Skip to content

Commit

Permalink
Feature: All donors are registered as users (only applies to v3 forms) (
Browse files Browse the repository at this point in the history
#7103)

Co-authored-by: Jon Waldstein <[email protected]>
  • Loading branch information
kjohnson and jonwaldstein authored Nov 21, 2023
1 parent 6bb1971 commit 21f163d
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 8 deletions.
12 changes: 12 additions & 0 deletions src/DonationForms/Controllers/DonateController.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class DonateController
/**
* First we create a donation and/or subscription, then move on to the gateway processing
*
* @unreleased Pass the form ID to match updated signature for getOrCreateDonor().
* @since 3.0.0
*
* @return void
Expand All @@ -28,6 +29,7 @@ class DonateController
public function donate(DonateControllerData $formData, PaymentGateway $gateway)
{
$donor = $this->getOrCreateDonor(
$formData->formId,
$formData->wpUserId,
$formData->email,
$formData->firstName,
Expand Down Expand Up @@ -76,8 +78,10 @@ public function donate(DonateControllerData $formData, PaymentGateway $gateway)
}

/**
* @unreleased Added $formId to the signature for passing to do_action hooks.
* @since 3.0.0
*
* @param int $formId
* @param int|null $userId
* @param string $donorEmail
* @param string $firstName
Expand All @@ -87,6 +91,7 @@ public function donate(DonateControllerData $formData, PaymentGateway $gateway)
* @throws Exception
*/
private function getOrCreateDonor(
int $formId,
int $userId,
string $donorEmail,
string $firstName,
Expand Down Expand Up @@ -115,6 +120,13 @@ private function getOrCreateDonor(
'email' => $donorEmail,
'userId' => $userId ?: null
]);

/**
* @unreleased Add a new do_action hook to differentiate when a v3 form creates a new donor.
* @param Donor $donor
* @param int $formId
*/
do_action('givewp_donate_controller_donor_created', $donor, $formId);
}

return $donor;
Expand Down
6 changes: 4 additions & 2 deletions src/DonationForms/Properties/FormSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,10 @@ class FormSettings implements Arrayable, Jsonable
*/
public $goalAmount;
/**
* @unreleased Added registrationNotification property.
* @var string
*/
public $registration;
public $registrationNotification;
/**
* @var string
*/
Expand Down Expand Up @@ -175,6 +176,7 @@ class FormSettings implements Arrayable, Jsonable
public $pdfSettings;

/**
* @unreleased Added registrationNotification
* @since 3.0.0
*/
public static function fromArray(array $array): self
Expand All @@ -200,7 +202,7 @@ public static function fromArray(array $array): self
$self->primaryColor = $array['primaryColor'] ?? '#69b86b';
$self->secondaryColor = $array['secondaryColor'] ?? '#f49420';
$self->goalAmount = $array['goalAmount'] ?? 0;
$self->registration = $array['registration'] ?? 'none';
$self->registrationNotification = $array['registrationNotification'] ?? false;
$self->customCss = $array['customCss'] ?? '';
$self->pageSlug = $array['pageSlug'] ?? '';
$self->goalAchievedMessage = $array['goalAchievedMessage'] ?? __(
Expand Down
44 changes: 44 additions & 0 deletions src/Donors/Actions/CreateUserFromDonor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace Give\Donors\Actions;

use Give\Donors\Exceptions\FailedDonorUserCreationException;
use Give\Donors\Models\Donor;

/**
* @unreleased
*/
class CreateUserFromDonor
{
public function __invoke(Donor $donor): Donor
{
$userIdOrError = wp_insert_user(apply_filters(
'givewp_create_donor_new_user',
[
'user_login' => $donor->email,
'user_pass' => wp_generate_password(),
'user_email' => $donor->email,
'first_name' => $donor->firstName,
'last_name' => $donor->lastName,
'role' => give_get_option( 'donor_default_user_role', 'give_donor' ),
],
$donor
));

if(!is_wp_error($userIdOrError)) {
$donor->userId = $userIdOrError;
} else {
throw new FailedDonorUserCreationException(
$donor,
0,
new \Exception($userIdOrError->get_error_message())
);
}

do_action('givewp_donor_user_created', $donor);

$donor->save();

return $donor;
}
}
34 changes: 34 additions & 0 deletions src/Donors/Actions/SendDonorUserRegistrationNotification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Give\Donors\Actions;

use Give\Donors\Models\Donor;
use Give_Donor_Register_Email;

/**
* @unreleased
*/
class SendDonorUserRegistrationNotification
{
/**
* @var Give_Donor_Register_Email
*/
protected $email;

public function __construct(Give_Donor_Register_Email $email)
{
$this->email = $email;
$this->email->init();
}

public function __invoke(Donor $donor)
{
// Enable the `donor-register` (legacy) email notification.
add_filter( "give_donor-register_is_email_notification_active", '__return_true' );

// For legacy email notifications `setup_email_notification()` calls `send_email_notification()`.
$this->email->setup_email_notification($donor->userId, [
'email' => $donor->email
]);
}
}
21 changes: 21 additions & 0 deletions src/Donors/Exceptions/FailedDonorUserCreationException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Give\Donors\Exceptions;

use Give\Donors\Models\Donor;
use Give\Framework\Exceptions\Primitives\Exception;

/**
* @unreleased
*/
class FailedDonorUserCreationException extends Exception
{
protected $donor;

public function __construct( Donor $donor = null, $code = 0, $previous = null ) {
parent::__construct('Failed creating a user for the donor.', $code, $previous);
$this->donor = $donor;
}
}
40 changes: 34 additions & 6 deletions src/Donors/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@

namespace Give\Donors;

use Give\DonationForms\Models\DonationForm;
use Give\Donors\Actions\CreateUserFromDonor;
use Give\Donors\Actions\SendDonorUserRegistrationNotification;
use Give\Donors\CustomFields\Controllers\DonorDetailsController;
use Give\Donors\Exceptions\FailedDonorUserCreationException;
use Give\Donors\ListTable\DonorsListTable;
use Give\Donors\Models\Donor;
use Give\Donors\Repositories\DonorRepositoryProxy;
use Give\Helpers\Hooks;
use Give\Log\Log;
use Give\ServiceProviders\ServiceProvider as ServiceProviderInterface;
use Give_Donor as LegacyDonor;

Expand All @@ -22,7 +27,7 @@ class ServiceProvider implements ServiceProviderInterface
public function register()
{
give()->singleton('donors', DonorRepositoryProxy::class);
give()->singleton(DonorsListTable::class, function() {
give()->singleton(DonorsListTable::class, function () {
$listTable = new DonorsListTable();
Hooks::doAction('givewp_donors_list_table', $listTable);

Expand All @@ -38,19 +43,18 @@ public function boot()
$userId = get_current_user_id();
$showLegacy = get_user_meta($userId, '_give_donors_archive_show_legacy', true);
// only register new admin page if user hasn't chosen to use the old one
if(empty($showLegacy)) {
if (empty($showLegacy)) {
Hooks::addAction('admin_menu', DonorsAdminPage::class, 'registerMenuItem', 30);

if (DonorsAdminPage::isShowing()) {
Hooks::addAction('admin_enqueue_scripts', DonorsAdminPage::class, 'loadScripts');
}
}
elseif(DonorsAdminPage::isShowing())
{
Hooks::addAction( 'admin_head', DonorsAdminPage::class, 'renderReactSwitch');
} elseif (DonorsAdminPage::isShowing()) {
Hooks::addAction('admin_head', DonorsAdminPage::class, 'renderReactSwitch');
}

$this->addCustomFieldsToDonorDetails();
$this->enforceDonorsAsUsers();
}

/**
Expand All @@ -65,4 +69,28 @@ private function addCustomFieldsToDonorDetails()
echo (new DonorDetailsController())->show($donor);
});
}

/**
* Hook into the donor creation process to ensure that donors are also users.
* @unreleased
*/
protected function enforceDonorsAsUsers()
{
add_action('givewp_donate_controller_donor_created', function (Donor $donor, $formId) {
if (!$donor->userId) {
try {
give(CreateUserFromDonor::class)->__invoke($donor);

if (DonationForm::find($formId)->settings->registrationNotification) {
give(SendDonorUserRegistrationNotification::class)->__invoke($donor);
}
} catch (FailedDonorUserCreationException $e) {
Log::error($e->getLogMessage(), [
'donor' => $donor,
'previous' => $e->getPrevious(),
]);
}
}
}, 10, 2);
}
}

0 comments on commit 21f163d

Please sign in to comment.