From 5972f7e0feb1a18ff2620d97c3c705aba17df5d2 Mon Sep 17 00:00:00 2001
From: Joshua Dinh <75056371+JoshuaHungDinh@users.noreply.github.com>
Date: Wed, 10 Apr 2024 22:17:06 +0900
Subject: [PATCH 1/6] Feature: add Constant Contact add-on to the form
migration process (#7145)
Co-authored-by: Jon Waldstein
Co-authored-by: Jon Waldstein
---
.../V2/DonationFormsAdminPage.php | 2 +-
src/FormMigration/FormMetaDecorator.php | 49 +++++++++-
src/FormMigration/ServiceProvider.php | 1 +
src/FormMigration/Steps/ConstantContact.php | 37 ++++++++
.../Steps/TestConstantContact.php | 95 +++++++++++++++++++
5 files changed, 182 insertions(+), 2 deletions(-)
create mode 100644 src/FormMigration/Steps/ConstantContact.php
create mode 100644 tests/Feature/FormMigration/Steps/TestConstantContact.php
diff --git a/src/DonationForms/V2/DonationFormsAdminPage.php b/src/DonationForms/V2/DonationFormsAdminPage.php
index 5154bcc277..06114ead38 100644
--- a/src/DonationForms/V2/DonationFormsAdminPage.php
+++ b/src/DonationForms/V2/DonationFormsAdminPage.php
@@ -334,6 +334,7 @@ public function getSupportedAddons(): array
'Zapier' => defined('GIVE_ZAPIER_VERSION'),
'Salesforce' => defined('GIVE_SALESFORCE_VERSION'),
'Donation Upsells for WooCommerce' => class_exists('Give_WooCommerce'),
+ 'Constant Contact' => class_exists('Give_Constant_Contact'),
'MailChimp' => class_exists('Give_MailChimp'),
// 'Manual Donations' => class_exists('Give_Manual_Donations'),
'Funds' => defined('GIVE_FUNDS_ADDON_NAME'),
@@ -349,7 +350,6 @@ public function getSupportedAddons(): array
// 'Per Form Confirmations' => class_exists('Per_Form_Confirmations_4_GIVEWP'),
// 'Form Countdown' => class_exists('Give_Form_Countdown'),
// 'ActiveCampaign' => class_exists('Give_ActiveCampaign'),
- // 'Constant Contact' => class_exists('Give_Constant_Contact'),
];
$output = [];
diff --git a/src/FormMigration/FormMetaDecorator.php b/src/FormMigration/FormMetaDecorator.php
index d6ecbc2fb2..78efb87ec9 100644
--- a/src/FormMigration/FormMetaDecorator.php
+++ b/src/FormMigration/FormMetaDecorator.php
@@ -510,6 +510,54 @@ public function getFeeRecoverySettings(): array
];
}
+ /**
+ * @unreleased
+ */
+ public function isConstantContactEnabled(): bool
+ {
+ $isFormEnabled = give_is_setting_enabled($this->getMeta('_give_constant_contact_enable'),'true');
+
+ $isFormDisabled = give_is_setting_enabled($this->getMeta('_give_constant_contact_disable'),'true');
+
+ $isGloballyEnabled = give_is_setting_enabled(give_get_option('give_constant_contact_show_checkout_signup'), 'on');
+
+ return !($isFormDisabled || ( !$isGloballyEnabled && !$isFormEnabled));
+ }
+
+ /**
+ * @unreleased
+ */
+ public function getConstantContactLabel(): string
+ {
+ $defaultMeta = give_get_option('give_constant_contact_label', __('Subscribe to our newsletter?'));
+
+ return $this->getMeta('_give_constant_contact_custom_label', $defaultMeta);
+ }
+
+ /**
+ * @unreleased
+ */
+ public function getConstantContactDefaultChecked(): bool
+ {
+ $defaultMeta = give_is_setting_enabled(
+ give_get_option('give_constant_contact_checked_default',
+ true),
+ 'on'
+ );
+
+ return $this->getMeta('_give_constant_contact_checked_default', $defaultMeta);
+ }
+
+ /**
+ * @unreleased
+ */
+ public function getConstantContactSelectedLists(): array
+ {
+ $defaultMeta = give_get_option('give_constant_contact_list', []);
+
+ return (array)$this->getMeta('_give_constant_contact', $defaultMeta);
+ }
+
/**
* @since 3.3.0
*/
@@ -542,7 +590,6 @@ public function getMailchimpDefaultChecked(): bool
give_get_option('give_mailchimp_checked_default', true)));
}
-
/**
* @unreleased add global setting as default.
* @since 3.3.0
diff --git a/src/FormMigration/ServiceProvider.php b/src/FormMigration/ServiceProvider.php
index 4911aa0f20..3af7de2f45 100644
--- a/src/FormMigration/ServiceProvider.php
+++ b/src/FormMigration/ServiceProvider.php
@@ -45,6 +45,7 @@ public function register()
Steps\FormMeta::class,
Steps\PdfSettings::class,
Steps\FeeRecovery::class,
+ Steps\ConstantContact::class,
Steps\PerFormGateways::class,
Steps\Mailchimp::class,
Steps\FundsAndDesignations::class,
diff --git a/src/FormMigration/Steps/ConstantContact.php b/src/FormMigration/Steps/ConstantContact.php
new file mode 100644
index 0000000000..561ad21555
--- /dev/null
+++ b/src/FormMigration/Steps/ConstantContact.php
@@ -0,0 +1,37 @@
+formV2->isConstantContactEnabled();
+ }
+
+ /**
+ * @unreleased
+ */
+ public function process(): void
+ {
+ $block = BlockModel::make([
+ 'name' => 'givewp/constantcontact',
+ 'attributes' =>[
+ 'label' => $this->formV2->getConstantContactLabel(),
+ 'checked' => $this->formV2->getConstantContactDefaultChecked(),
+ 'selectedEmailLists' => $this->formV2->getConstantContactSelectedLists(),
+ ],
+ ]);
+
+ $this->fieldBlocks->insertAfter('givewp/email', $block);
+ }
+}
diff --git a/tests/Feature/FormMigration/Steps/TestConstantContact.php b/tests/Feature/FormMigration/Steps/TestConstantContact.php
new file mode 100644
index 0000000000..2825d02d61
--- /dev/null
+++ b/tests/Feature/FormMigration/Steps/TestConstantContact.php
@@ -0,0 +1,95 @@
+ 'Subscribe to our newsletter?',
+ '_give_constant_contact_checked_default' => 'on',
+ '_give_constant_contact' => ['1928414891'],
+ ];
+
+ $formV2 = $this->createSimpleDonationForm(['meta' => $meta]);
+
+ $payload = FormMigrationPayload::fromFormV2($formV2);
+
+ $constantContact = new ConstantContact($payload);
+
+ $constantContact->process();
+
+ $block = $payload->formV3->blocks->findByName('givewp/constantcontact');
+
+ $this->assertTrue(true, $block->getAttribute('checked' === 'on'));
+ $this->assertSame($meta['_give_constant_contact_custom_label'], $block->getAttribute('label'));
+ $this->assertSame($meta['_give_constant_contact'], $block->getAttribute('selectedEmailLists'));
+ }
+
+ /**
+ * @unreleased
+ */
+ public function testProcessShouldUpdateConstantContactBlockAttributesWithGlobalSettings(): void
+ {
+ $meta = [
+ 'give_constant_contact_label' => 'Subscribe to our newsletter?',
+ 'give_constant_contact_checked_default' => 'on',
+ 'give_constant_contact_list' => ['1928414891'],
+ ];
+
+ $formV2 = $this->createSimpleDonationForm(['meta' => $meta]);
+
+ $payload = FormMigrationPayload::fromFormV2($formV2);
+
+ foreach ($meta as $key => $value) {
+ give_update_option($key, $value);
+ }
+
+ $constantContact = new ConstantContact($payload);
+
+ $constantContact->process();
+
+ $block = $payload->formV3->blocks->findByName('givewp/constantcontact');
+
+ $this->assertTrue(true, $block->getAttribute('checked' === 'on'));
+ $this->assertSame($meta['give_constant_contact_label'], $block->getAttribute('label'));
+ $this->assertSame($meta['give_constant_contact_list'], $block->getAttribute('selectedEmailLists'));
+ }
+
+ /**
+ * @unreleased
+ */
+ public function testProcessShouldUpdateConstantContactBlockAttributesWhenNoMeta(): void
+ {
+ $formV2 = $this->createSimpleDonationForm();
+
+ $payload = FormMigrationPayload::fromFormV2($formV2);
+
+ $constantContact = new ConstantContact($payload);
+
+ $constantContact->process();
+
+ $block = $payload->formV3->blocks->findByName('givewp/constantcontact');
+
+ $this->assertTrue(true, $block->getAttribute('checked' === 'on'));
+ $this->assertSame('Subscribe to our newsletter?', $block->getAttribute('label'));
+ $this->assertNull(null, $block->getAttribute('selectedEmailLists'));
+ }
+}
From f9672ea636990ced7e68e250c35f8230764f6152 Mon Sep 17 00:00:00 2001
From: Paulo Iankoski
Date: Wed, 10 Apr 2024 10:17:35 -0300
Subject: [PATCH 2/6] Fix: Update donation form excerpt on saving (#7348)
---
.../Repositories/DonationFormRepository.php | 5 +++-
src/FormBuilder/Actions/UpdateFormExcerpt.php | 24 -------------------
src/FormBuilder/ServiceProvider.php | 1 -
3 files changed, 4 insertions(+), 26 deletions(-)
delete mode 100644 src/FormBuilder/Actions/UpdateFormExcerpt.php
diff --git a/src/DonationForms/Repositories/DonationFormRepository.php b/src/DonationForms/Repositories/DonationFormRepository.php
index 4e2dc185d5..c9ad956ab3 100644
--- a/src/DonationForms/Repositories/DonationFormRepository.php
+++ b/src/DonationForms/Repositories/DonationFormRepository.php
@@ -69,7 +69,7 @@ public function getById(int $id)
}
/**
- *
+ * @unreleased Add post_excerpt to the list of fields being inserted
* @since 3.0.0
*
* @return void
@@ -103,6 +103,7 @@ public function insert(DonationForm $donationForm)
'post_modified_gmt' => get_gmt_from_date($dateCreatedFormatted),
'post_status' => $donationForm->status->getValue(),
'post_type' => 'give_forms',
+ 'post_excerpt' => $donationForm->settings->formExcerpt,
'post_parent' => 0,
'post_title' => $donationForm->title,
'post_content' => (new BlockCollection([]))->toJson(), // @todo Repurpose as form page.
@@ -146,6 +147,7 @@ public function insert(DonationForm $donationForm)
}
/**
+ * @unreleased Add post_excerpt to the list of fields being updated
* @since 3.0.0
*
* @param DonationForm $donationForm
@@ -179,6 +181,7 @@ public function update(DonationForm $donationForm)
'post_modified_gmt' => get_gmt_from_date($date),
'post_status' => $donationForm->status->getValue(),
'post_title' => $donationForm->title,
+ 'post_excerpt' => $donationForm->settings->formExcerpt,
'post_content' => (new BlockCollection([]))->toJson(), // @todo Repurpose as form page.
'post_name' => $donationForm->settings->pageSlug,
]);
diff --git a/src/FormBuilder/Actions/UpdateFormExcerpt.php b/src/FormBuilder/Actions/UpdateFormExcerpt.php
deleted file mode 100644
index 1325f4dbc3..0000000000
--- a/src/FormBuilder/Actions/UpdateFormExcerpt.php
+++ /dev/null
@@ -1,24 +0,0 @@
- $form->id,
- 'post_excerpt' => $form->settings->formExcerpt,
- ]);
- }
-}
diff --git a/src/FormBuilder/ServiceProvider.php b/src/FormBuilder/ServiceProvider.php
index fe7916c56b..51a66efbfa 100644
--- a/src/FormBuilder/ServiceProvider.php
+++ b/src/FormBuilder/ServiceProvider.php
@@ -63,7 +63,6 @@ public function boot()
give(UpdateEmailSettingsMeta::class)->__invoke($form);
give(UpdateEmailTemplateMeta::class)->__invoke($form);
give(UpdateDonorCommentsMeta::class)->__invoke($form);
- give(UpdateFormExcerpt::class)->__invoke($form);
});
Hooks::addAction('givewp_form_builder_new_form', ConvertGlobalDefaultOptionsToDefaultBlocks::class);
From 57ac936b6a45f7820cade460750b6759f0cc2f77 Mon Sep 17 00:00:00 2001
From: Paulo Iankoski
Date: Wed, 10 Apr 2024 10:17:57 -0300
Subject: [PATCH 3/6] Fix: Enhance Donation Form block to display up to 100
forms (#7347)
---
.../resources/editor/hooks/useFormOptions.ts | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/DonationForms/Blocks/DonationFormBlock/resources/editor/hooks/useFormOptions.ts b/src/DonationForms/Blocks/DonationFormBlock/resources/editor/hooks/useFormOptions.ts
index d9716d899a..bb6213ce70 100644
--- a/src/DonationForms/Blocks/DonationFormBlock/resources/editor/hooks/useFormOptions.ts
+++ b/src/DonationForms/Blocks/DonationFormBlock/resources/editor/hooks/useFormOptions.ts
@@ -12,6 +12,7 @@ export interface FormOption extends Form {
}
/**
+ * @unreleased Increase the per_page attribute to 100 to accommodate for more forms.
* @since 3.2.0 include isLegacyForm, isLegacyFormTemplate & link.
* @since 3.0.0
*/
@@ -22,11 +23,16 @@ export default function useFormOptions(): {
const formOptions = [];
const {forms, isResolving} = useSelect((select) => {
+ const query = {per_page: 100};
return {
// @ts-ignore
- forms: select('core').getEntityRecords('postType', 'give_forms'),
+ forms: select('core').getEntityRecords('postType', 'give_forms', query),
// @ts-ignore
- isResolving: select('core/data').getIsResolving('core', 'getEntityRecords', ['postType', 'give_forms']),
+ isResolving: select('core/data').getIsResolving('core', 'getEntityRecords', [
+ 'postType',
+ 'give_forms',
+ query,
+ ]),
};
}, []);
From cc3e4a6b2bf18886f1459b1e5e6265794d6d2419 Mon Sep 17 00:00:00 2001
From: Glauber Silva
Date: Wed, 10 Apr 2024 10:19:14 -0300
Subject: [PATCH 4/6] Enhancement: implements development good practices to
give form shortcode (#7338)
---
includes/class-notices.php | 11 ++++----
includes/donors/class-give-donor-wall.php | 2 ++
includes/login-register.php | 4 +--
includes/shortcodes.php | 28 +++++++++++++++----
.../MultiFormGoal/Shortcode.php | 3 ++
src/Views/IframeView.php | 8 ++++--
6 files changed, 41 insertions(+), 15 deletions(-)
diff --git a/includes/class-notices.php b/includes/class-notices.php
index 475febf295..be3e980879 100644
--- a/includes/class-notices.php
+++ b/includes/class-notices.php
@@ -638,6 +638,7 @@ public static function print_frontend_errors( $errors ) {
* Print frontend notice.
* Notice: notice type can be success/error/warning
*
+ * @unreleased Escape attributes
* @since 1.8.9
* @access public
*
@@ -691,11 +692,11 @@ public static function print_frontend_notice( $message, $echo = true, $notice_ty
%6$s
',
- $notice_type,
- give_clean( $notice_args['dismissible'] ),
- absint( $notice_args['dismiss_interval'] ),
- give_clean( $notice_args['dismiss_type'] ),
- $message,
+ esc_attr($notice_type),
+ esc_attr( $notice_args['dismissible'] ),
+ esc_attr( $notice_args['dismiss_interval'] ),
+ esc_attr( $notice_args['dismiss_type'] ),
+ esc_html($message),
$close_icon
);
diff --git a/includes/donors/class-give-donor-wall.php b/includes/donors/class-give-donor-wall.php
index b9f39a74ea..74637371ca 100644
--- a/includes/donors/class-give-donor-wall.php
+++ b/includes/donors/class-give-donor-wall.php
@@ -82,6 +82,7 @@ public function setup_actions() {
/**
* Displays donors in a grid layout.
*
+ * @unreleased Sanitize attributes
* @since 2.27.0 Moved AJAX nonce verification to ajax_handler method.
* @since 2.2.0
*
@@ -114,6 +115,7 @@ public function setup_actions() {
* @return string|bool The markup of the form grid or false.
*/
public function render_shortcode( $atts ) {
+ $atts = give_clean($atts);
$give_settings = give_get_settings();
diff --git a/includes/login-register.php b/includes/login-register.php
index 1b59fe274b..624870bfb1 100644
--- a/includes/login-register.php
+++ b/includes/login-register.php
@@ -51,8 +51,8 @@ function give_login_form( $login_redirect = '', $logout_redirect = '' ) {
give_get_template(
'shortcode-login',
array(
- 'give_login_redirect' => esc_url($login_redirect),
- 'give_logout_redirect' => esc_url($logout_redirect),
+ 'give_login_redirect' => $login_redirect,
+ 'give_logout_redirect' => $logout_redirect,
)
);
diff --git a/includes/shortcodes.php b/includes/shortcodes.php
index 8d73b11785..38045e86de 100644
--- a/includes/shortcodes.php
+++ b/includes/shortcodes.php
@@ -25,6 +25,7 @@
*
* Displays a user's donation history.
*
+ * @unreleased Sanitize attributes
* @since 3.1.0 pass form id by reference in give_totals shortcode.
* @since 1.0
*
@@ -34,7 +35,7 @@
* @return string|bool
*/
function give_donation_history( $atts, $content = false ) {
-
+ $atts = give_clean($atts);
$donation_history_args = shortcode_atts(
[
'id' => true,
@@ -132,6 +133,7 @@ function give_donation_history( $atts, $content = false ) {
*
* Show the Give donation form.
*
+ * @unreleased Sanitize attributes
* @since 3.4.0 Add additional validations to check if the form is valid and has the 'published' status.
* @since 2.30.0 Add short-circuit filter to allow for custom output.
* @since 1.0
@@ -142,6 +144,7 @@ function give_donation_history( $atts, $content = false ) {
* @return string
*/
function give_form_shortcode( $atts ) {
+ $atts = give_clean($atts);
$atts = shortcode_atts( give_get_default_form_shortcode_args(), $atts, 'give_form' );
if('fullForm' === $atts['display_style']) {
@@ -210,6 +213,7 @@ function give_form_shortcode( $atts ) {
*
* Show the Give donation form goals.
*
+ * @unreleased Sanitize attributes
* @since 3.4.0 Add additional validations to check if the form is valid and has the 'published' status.
* @since 1.0
*
@@ -218,6 +222,7 @@ function give_form_shortcode( $atts ) {
* @return string
*/
function give_goal_shortcode( $atts ) {
+ $atts = give_clean($atts);
$atts = shortcode_atts(
[
'id' => '',
@@ -266,6 +271,7 @@ function give_goal_shortcode( $atts ) {
* Shows a login form allowing users to users to log in. This function simply
* calls the give_login_form function to display the login form.
*
+ * @unreleased Sanitize attributes
* @since 1.0
*
* @param array $atts Shortcode attributes.
@@ -275,7 +281,7 @@ function give_goal_shortcode( $atts ) {
* @return string
*/
function give_login_form_shortcode( $atts ) {
-
+ $atts = give_clean($atts);
$atts = shortcode_atts(
[
// Add backward compatibility for redirect attribute.
@@ -300,6 +306,7 @@ function give_login_form_shortcode( $atts ) {
*
* Shows a registration form allowing users to users to register for the site.
*
+ * @unreleased Sanitize attributes
* @since 1.0
*
* @param array $atts Shortcode attributes.
@@ -309,6 +316,7 @@ function give_login_form_shortcode( $atts ) {
* @return string
*/
function give_register_form_shortcode( $atts ) {
+ $atts = give_clean($atts);
$atts = shortcode_atts(
[
'redirect' => '',
@@ -327,6 +335,7 @@ function give_register_form_shortcode( $atts ) {
*
* Shows a donation receipt.
*
+ * @unreleased Sanitize and escape attributes
* @since 1.0
*
* @param array $atts Shortcode attributes.
@@ -337,6 +346,8 @@ function give_receipt_shortcode( $atts ) {
global $give_receipt_args;
+ $atts = give_clean($atts);
+
$give_receipt_args = shortcode_atts(
[
'error' => __( 'You are missing the donation id to view this donation receipt.', 'give' ),
@@ -378,8 +389,8 @@ function give_receipt_shortcode( $atts ) {
return sprintf(
'%4$s
',
htmlspecialchars( wp_json_encode( $give_receipt_args ) ),
- $receipt_type,
- $donation_id,
+ esc_attr($receipt_type),
+ esc_attr($donation_id),
ob_get_clean()
);
}
@@ -400,6 +411,7 @@ function give_receipt_shortcode( $atts ) {
* folder. Please visit the Give Documentation for more information on how the
* templating system is used.
*
+ * @unreleased Sanitize attributes
* @since 1.0
*
* @param array $atts Shortcode attributes.
@@ -408,6 +420,8 @@ function give_receipt_shortcode( $atts ) {
*/
function give_profile_editor_shortcode( $atts ) {
+ $atts = give_clean($atts);
+
ob_start();
// Restrict access to donor profile, if donor and user are disconnected.
@@ -612,6 +626,7 @@ function give_process_profile_editor_updates( $data ) {
*
* Shows a donation total.
*
+ * @unreleased Sanitize attributes
* @since 2.1
*
* @param array $atts Shortcode attributes.
@@ -641,6 +656,8 @@ function give_totals_shortcode( $atts ) {
// Total Goal.
$total_goal = give_maybe_sanitize_amount( $atts['total_goal'] );
+ $atts = give_clean($atts);
+
/**
* Give Action fire before the shortcode is rendering is started.
*
@@ -818,6 +835,7 @@ static function ($id) {
/**
* Displays donation forms in a grid layout.
*
+ * @unreleased Sanitize attributes
* @since 2.1.0
*
* @since 3.1.0 Use static function on array_map callback to pass the id as reference for _give_redirect_form_id to prevent warnings on PHP 8.0.1 or plus
@@ -855,7 +873,7 @@ static function ($id) {
* @return string|bool The markup of the form grid or false.
*/
function give_form_grid_shortcode( $atts ) {
-
+ $atts = give_clean($atts);
$give_settings = give_get_settings();
$atts = shortcode_atts(
diff --git a/src/MultiFormGoals/MultiFormGoal/Shortcode.php b/src/MultiFormGoals/MultiFormGoal/Shortcode.php
index 9c1724d305..f28da58190 100644
--- a/src/MultiFormGoals/MultiFormGoal/Shortcode.php
+++ b/src/MultiFormGoals/MultiFormGoal/Shortcode.php
@@ -26,11 +26,14 @@ public function addShortcode()
/**
* Returns Shortcode markup
*
+ * @unreleased Sanitize attributes
* @since 3.0.3 Use static function on array_map callback to pass the id as reference for _give_redirect_form_id to prevent warnings on PHP 8.0.1 or plus
* @since 2.9.0
**/
public function renderCallback($attributes)
{
+ $attributes = give_clean($attributes);
+
$attributes = $this->parseAttributes(
[
'ids' => [],
diff --git a/src/Views/IframeView.php b/src/Views/IframeView.php
index 1c4d530df9..c524136059 100644
--- a/src/Views/IframeView.php
+++ b/src/Views/IframeView.php
@@ -261,6 +261,8 @@ private function getIframeHTML()
/**
* Get button HTML.
*
+ * @unreleased Escape attributes
+ *
* @return string
*/
private function getButtonHTML()
@@ -272,9 +274,9 @@ private function getButtonHTML()
class="js-give-embed-form-modal-opener"
data-form-id="%1$s"%3$s>%2$s
',
- $this->uniqueId,
- $this->buttonTitle,
- $this->buttonColor ? " style=\"background-color: {$this->buttonColor}\"" : ''
+ esc_attr($this->uniqueId),
+ esc_html($this->buttonTitle),
+ $this->buttonColor ? ' style="background-color: ' . esc_attr($this->buttonColor) . '"' : ''
);
}
From e8f6db6a4f7c4e083aa966c0baaa241f3dd6e02a Mon Sep 17 00:00:00 2001
From: Jon Waldstein
Date: Wed, 10 Apr 2024 09:47:37 -0400
Subject: [PATCH 5/6] chore: prepare for release 3.7.0
---
changelog.txt | 11 +++++++++++
give.php | 6 +++---
includes/admin/donors/donor-actions.php | 4 ++--
includes/admin/donors/donors.php | 2 +-
includes/class-notices.php | 2 +-
includes/donors/class-give-donor-wall.php | 2 +-
includes/misc-functions.php | 4 ++--
includes/shortcodes.php | 18 +++++++++---------
readme.txt | 14 +++++++++++---
.../resources/editor/hooks/useFormOptions.ts | 2 +-
src/DonationForms/Properties/FormSettings.php | 4 ++--
.../Repositories/DonationFormRepository.php | 4 ++--
src/Donors/Actions/UpdateAdminDonorDetails.php | 4 ++--
.../DataTransferObjects/DonorQueryData.php | 2 +-
src/Donors/Factories/DonorFactory.php | 2 +-
src/Donors/Migrations/AddPhoneColumn.php | 10 +++++-----
src/Donors/Models/Donor.php | 2 +-
src/Donors/Repositories/DonorRepository.php | 6 +++---
src/Donors/ServiceProvider.php | 2 +-
.../ViewModels/FormBuilderViewModel.php | 2 +-
.../form-builder/src/common/getWindowData.ts | 2 +-
.../group-general/form-summary/index.jsx | 2 +-
.../js/form-builder/src/types/formSettings.ts | 2 +-
src/FormMigration/FormMetaDecorator.php | 14 +++++++-------
src/FormMigration/Steps/ConstantContact.php | 6 +++---
src/FormMigration/Steps/FormExcerpt.php | 4 ++--
src/MultiFormGoals/MultiFormGoal/Shortcode.php | 2 +-
src/Views/IframeView.php | 2 +-
.../Steps/TestConstantContact.php | 8 ++++----
.../FormMigration/Steps/TestMailchimp.php | 6 +++---
tests/Unit/Donors/Models/TestDonor.php | 4 ++--
.../Repositories/TestDonorRepository.php | 6 +++---
.../ViewModels/FormBuilderViewModelTest.php | 2 +-
33 files changed, 91 insertions(+), 72 deletions(-)
diff --git a/changelog.txt b/changelog.txt
index 3c6d85a08a..bd8eb19d8b 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,4 +1,15 @@
== Changelog ==
+= 3.7.0: April 10th, 2024 =
+* New: Added pre-requisite form builder compatibility for upcoming constant contact add-on release
+* New: Added phone number field to the donor details page, more updates for this field will come in future releases!
+* Enhancement: Updated the form block option to select more available forms than the original limit of 10
+* Enhancement: Updated the form builder left-side menu to open automatically when entering the build screen
+* Security: Added sanitizing and escaping to shortcodes
+* Fix: Resolved a conflict with GiveWP and WordPress bulk actions functionality
+
+= 3.6.2: April 5th, 2024 =
+* Fix: Resolved an issue with WordPress 6.5 and the visual form builder that was making it difficult to interact with blocks
+
= 3.6.1: March 21st, 2024 =
* Fix: Resolved an issue with PayPal donations and currency switcher on donation forms using the visual form builder
diff --git a/give.php b/give.php
index 080903fbb7..373cd24036 100644
--- a/give.php
+++ b/give.php
@@ -6,8 +6,8 @@
* Description: The most robust, flexible, and intuitive way to accept donations on WordPress.
* Author: GiveWP
* Author URI: https://givewp.com/
- * Version: 3.6.2
- * Requires at least: 6.0
+ * Version: 3.7.0
+ * Requires at least: 6.3
* Requires PHP: 7.2
* Text Domain: give
* Domain Path: /languages
@@ -404,7 +404,7 @@ private function setup_constants()
{
// Plugin version.
if (!defined('GIVE_VERSION')) {
- define('GIVE_VERSION', '3.6.2');
+ define('GIVE_VERSION', '3.7.0');
}
// Plugin Root File.
diff --git a/includes/admin/donors/donor-actions.php b/includes/admin/donors/donor-actions.php
index 349abe6ee9..b15e767a07 100644
--- a/includes/admin/donors/donor-actions.php
+++ b/includes/admin/donors/donor-actions.php
@@ -17,7 +17,7 @@
/**
* Processes a donor edit.
*
- * @unreleased Add support to the "phone" field
+ * @since 3.7.0 Add support to the "phone" field
* @since 1.0
*
* @param array $args The $_POST array being passed.
@@ -132,7 +132,7 @@ function give_edit_donor( $args ) {
* @param array $args The sanitized data submitted.
* @param int $donor_id The donor ID.
*
- * @unreleased
+ * @since 3.7.0
*/
do_action('give_admin_donor_details_updating', $args, $donor->id);
diff --git a/includes/admin/donors/donors.php b/includes/admin/donors/donors.php
index 7d8981edb6..2fb9a67c7d 100644
--- a/includes/admin/donors/donors.php
+++ b/includes/admin/donors/donors.php
@@ -300,7 +300,7 @@ function give_render_donor_view( $view, $callbacks ) {
/**
* View a donor
*
- * @unreleased Add "phone" field
+ * @since 3.7.0 Add "phone" field
* @since 1.0
*
* @param Give_Donor $donor The Donor object being displayed.
diff --git a/includes/class-notices.php b/includes/class-notices.php
index be3e980879..d2cb992cf9 100644
--- a/includes/class-notices.php
+++ b/includes/class-notices.php
@@ -638,7 +638,7 @@ public static function print_frontend_errors( $errors ) {
* Print frontend notice.
* Notice: notice type can be success/error/warning
*
- * @unreleased Escape attributes
+ * @since 3.7.0 Escape attributes
* @since 1.8.9
* @access public
*
diff --git a/includes/donors/class-give-donor-wall.php b/includes/donors/class-give-donor-wall.php
index 74637371ca..26281edae5 100644
--- a/includes/donors/class-give-donor-wall.php
+++ b/includes/donors/class-give-donor-wall.php
@@ -82,7 +82,7 @@ public function setup_actions() {
/**
* Displays donors in a grid layout.
*
- * @unreleased Sanitize attributes
+ * @since 3.7.0 Sanitize attributes
* @since 2.27.0 Moved AJAX nonce verification to ajax_handler method.
* @since 2.2.0
*
diff --git a/includes/misc-functions.php b/includes/misc-functions.php
index 9248939c0b..519e67e408 100644
--- a/includes/misc-functions.php
+++ b/includes/misc-functions.php
@@ -2628,7 +2628,7 @@ function give_get_page_by_title(string $page_title, string $output = OBJECT, str
/**
* @see https://github.com/jackocnr/intl-tel-input
*
- * @unreleased
+ * @since 3.7.0
*/
function give_get_intl_tel_input(string $value, string $id, string $class = '', string $name = ''):string {
@@ -2719,7 +2719,7 @@ function readyHandler() {
}
/**
-* @unreleased
+* @since 3.7.0
*/
function give_get_intl_tel_input_i18n_json_object() {
diff --git a/includes/shortcodes.php b/includes/shortcodes.php
index 38045e86de..b297901a01 100644
--- a/includes/shortcodes.php
+++ b/includes/shortcodes.php
@@ -25,7 +25,7 @@
*
* Displays a user's donation history.
*
- * @unreleased Sanitize attributes
+ * @since 3.7.0 Sanitize attributes
* @since 3.1.0 pass form id by reference in give_totals shortcode.
* @since 1.0
*
@@ -133,7 +133,7 @@ function give_donation_history( $atts, $content = false ) {
*
* Show the Give donation form.
*
- * @unreleased Sanitize attributes
+ * @since 3.7.0 Sanitize attributes
* @since 3.4.0 Add additional validations to check if the form is valid and has the 'published' status.
* @since 2.30.0 Add short-circuit filter to allow for custom output.
* @since 1.0
@@ -213,7 +213,7 @@ function give_form_shortcode( $atts ) {
*
* Show the Give donation form goals.
*
- * @unreleased Sanitize attributes
+ * @since 3.7.0 Sanitize attributes
* @since 3.4.0 Add additional validations to check if the form is valid and has the 'published' status.
* @since 1.0
*
@@ -271,7 +271,7 @@ function give_goal_shortcode( $atts ) {
* Shows a login form allowing users to users to log in. This function simply
* calls the give_login_form function to display the login form.
*
- * @unreleased Sanitize attributes
+ * @since 3.7.0 Sanitize attributes
* @since 1.0
*
* @param array $atts Shortcode attributes.
@@ -306,7 +306,7 @@ function give_login_form_shortcode( $atts ) {
*
* Shows a registration form allowing users to users to register for the site.
*
- * @unreleased Sanitize attributes
+ * @since 3.7.0 Sanitize attributes
* @since 1.0
*
* @param array $atts Shortcode attributes.
@@ -335,7 +335,7 @@ function give_register_form_shortcode( $atts ) {
*
* Shows a donation receipt.
*
- * @unreleased Sanitize and escape attributes
+ * @since 3.7.0 Sanitize and escape attributes
* @since 1.0
*
* @param array $atts Shortcode attributes.
@@ -411,7 +411,7 @@ function give_receipt_shortcode( $atts ) {
* folder. Please visit the Give Documentation for more information on how the
* templating system is used.
*
- * @unreleased Sanitize attributes
+ * @since 3.7.0 Sanitize attributes
* @since 1.0
*
* @param array $atts Shortcode attributes.
@@ -626,7 +626,7 @@ function give_process_profile_editor_updates( $data ) {
*
* Shows a donation total.
*
- * @unreleased Sanitize attributes
+ * @since 3.7.0 Sanitize attributes
* @since 2.1
*
* @param array $atts Shortcode attributes.
@@ -835,7 +835,7 @@ static function ($id) {
/**
* Displays donation forms in a grid layout.
*
- * @unreleased Sanitize attributes
+ * @since 3.7.0 Sanitize attributes
* @since 2.1.0
*
* @since 3.1.0 Use static function on array_map callback to pass the id as reference for _give_redirect_form_id to prevent warnings on PHP 8.0.1 or plus
diff --git a/readme.txt b/readme.txt
index 4a160176ad..f003634bcb 100644
--- a/readme.txt
+++ b/readme.txt
@@ -2,10 +2,10 @@
Contributors: givewp, dlocc, webdevmattcrom, ravinderk, mehul0810, kevinwhoffman, jason_the_adams, henryholtgeerts, kbjohnson90, alaca, benmeredithgmailcom, jonwaldstein, joshuadinh, glaubersilvawp, pauloiankoski
Donate link: https://go.givewp.com/home
Tags: donation, donate, recurring donations, fundraising, crowdfunding
-Requires at least: 6.0
+Requires at least: 6.3
Tested up to: 6.5
Requires PHP: 7.2
-Stable tag: 3.6.2
+Stable tag: 3.7.0
License: GPLv3
License URI: http://www.gnu.org/licenses/gpl-3.0.html
@@ -167,7 +167,7 @@ Here’s a few ways you can contribute to GiveWP:
= Minimum Requirements =
-* WordPress 6.0 or greater
+* WordPress 6.3 or greater
* PHP version 7.2 or greater
* MySQL version 5.7 or greater
* MariaDB version 10 or later
@@ -262,6 +262,14 @@ The 2% fee on Stripe donations only applies to donations taken via our free Stri
10. Use almost any payment gateway integration with GiveWP through our add-ons or by creating your own add-on.
== Changelog ==
+= 3.7.0: April 10th, 2024 =
+* New: Added pre-requisite form builder compatibility for upcoming constant contact add-on release
+* New: Added phone number field to the donor details page, more updates for this field will come in future releases!
+* Enhancement: Updated the form block option to select more available forms than the original limit of 10
+* Enhancement: Updated the form builder left-side menu to open automatically when entering the build screen
+* Security: Added sanitizing and escaping to shortcodes
+* Fix: Resolved a conflict with GiveWP and WordPress bulk actions functionality
+
= 3.6.2: April 5th, 2024 =
* Fix: Resolved an issue with WordPress 6.5 and the visual form builder that was making it difficult to interact with blocks
diff --git a/src/DonationForms/Blocks/DonationFormBlock/resources/editor/hooks/useFormOptions.ts b/src/DonationForms/Blocks/DonationFormBlock/resources/editor/hooks/useFormOptions.ts
index bb6213ce70..dd88679e9b 100644
--- a/src/DonationForms/Blocks/DonationFormBlock/resources/editor/hooks/useFormOptions.ts
+++ b/src/DonationForms/Blocks/DonationFormBlock/resources/editor/hooks/useFormOptions.ts
@@ -12,7 +12,7 @@ export interface FormOption extends Form {
}
/**
- * @unreleased Increase the per_page attribute to 100 to accommodate for more forms.
+ * @since 3.7.0 Increase the per_page attribute to 100 to accommodate for more forms.
* @since 3.2.0 include isLegacyForm, isLegacyFormTemplate & link.
* @since 3.0.0
*/
diff --git a/src/DonationForms/Properties/FormSettings.php b/src/DonationForms/Properties/FormSettings.php
index fe7533dc5f..edff66ec27 100644
--- a/src/DonationForms/Properties/FormSettings.php
+++ b/src/DonationForms/Properties/FormSettings.php
@@ -230,13 +230,13 @@ class FormSettings implements Arrayable, Jsonable
*/
public $designSettingsImageOpacity;
- /* @unreleased
+ /* @since 3.7.0
* @var string
*/
public $formExcerpt;
/**
- * @unreleased Added formExcerpt
+ * @since 3.7.0 Added formExcerpt
/**
* @since 3.2.0 Added registrationNotification
diff --git a/src/DonationForms/Repositories/DonationFormRepository.php b/src/DonationForms/Repositories/DonationFormRepository.php
index c9ad956ab3..352cd0c17c 100644
--- a/src/DonationForms/Repositories/DonationFormRepository.php
+++ b/src/DonationForms/Repositories/DonationFormRepository.php
@@ -69,7 +69,7 @@ public function getById(int $id)
}
/**
- * @unreleased Add post_excerpt to the list of fields being inserted
+ * @since 3.7.0 Add post_excerpt to the list of fields being inserted
* @since 3.0.0
*
* @return void
@@ -147,7 +147,7 @@ public function insert(DonationForm $donationForm)
}
/**
- * @unreleased Add post_excerpt to the list of fields being updated
+ * @since 3.7.0 Add post_excerpt to the list of fields being updated
* @since 3.0.0
*
* @param DonationForm $donationForm
diff --git a/src/Donors/Actions/UpdateAdminDonorDetails.php b/src/Donors/Actions/UpdateAdminDonorDetails.php
index 66a3e1f7b1..23bcb1b909 100644
--- a/src/Donors/Actions/UpdateAdminDonorDetails.php
+++ b/src/Donors/Actions/UpdateAdminDonorDetails.php
@@ -8,12 +8,12 @@
/**
* This class allows us to use the Donor model to update data from the donor profile admin legacy page without adding new code directly to the legacy codebase.
*
- * @unreleased
+ * @since 3.7.0
*/
class UpdateAdminDonorDetails
{
/**
- * @unreleased
+ * @since 3.7.0
*
* @throws Exception
*/
diff --git a/src/Donors/DataTransferObjects/DonorQueryData.php b/src/Donors/DataTransferObjects/DonorQueryData.php
index ce25e46cae..0960cad79d 100644
--- a/src/Donors/DataTransferObjects/DonorQueryData.php
+++ b/src/Donors/DataTransferObjects/DonorQueryData.php
@@ -67,7 +67,7 @@ final class DonorQueryData
/**
* Convert data from donor object to Donor Model
*
- * @unreleased Add "phone" property
+ * @since 3.7.0 Add "phone" property
* @since 2.24.0 add $totalAmountDonated and $totalNumberOfDonations
* @since 2.20.0 add donor prefix property
* @since 2.19.6
diff --git a/src/Donors/Factories/DonorFactory.php b/src/Donors/Factories/DonorFactory.php
index ac79ee072e..7e0f3e04bf 100644
--- a/src/Donors/Factories/DonorFactory.php
+++ b/src/Donors/Factories/DonorFactory.php
@@ -8,7 +8,7 @@
class DonorFactory extends ModelFactory
{
/**
- * @unreleased Add "phone" property
+ * @since 3.7.0 Add "phone" property
* @since 2.19.6
*/
public function definition(): array
diff --git a/src/Donors/Migrations/AddPhoneColumn.php b/src/Donors/Migrations/AddPhoneColumn.php
index 05ab2518ed..4aa756bb9c 100644
--- a/src/Donors/Migrations/AddPhoneColumn.php
+++ b/src/Donors/Migrations/AddPhoneColumn.php
@@ -7,12 +7,12 @@
use Give\Framework\Migrations\Exceptions\DatabaseMigrationException;
/**
- * @unreleased
+ * @since 3.7.0
*/
class AddPhoneColumn extends Migration
{
/**
- * @unreleased
+ * @since 3.7.0
*
* @throws DatabaseMigrationException
*/
@@ -35,7 +35,7 @@ public function run()
}
/**
- * @unreleased
+ * @since 3.7.0
*/
public static function id(): string
{
@@ -43,7 +43,7 @@ public static function id(): string
}
/**
- * @unreleased
+ * @since 3.7.0
*/
public static function title(): string
{
@@ -51,7 +51,7 @@ public static function title(): string
}
/**
- * @unreleased
+ * @since 3.7.0
*/
public static function timestamp()
{
diff --git a/src/Donors/Models/Donor.php b/src/Donors/Models/Donor.php
index 1a8593370b..4f502469b6 100644
--- a/src/Donors/Models/Donor.php
+++ b/src/Donors/Models/Donor.php
@@ -20,7 +20,7 @@
/**
* Class Donor
*
- * @unreleased Add "phone" property
+ * @since 3.7.0 Add "phone" property
* @since 2.24.0 add new properties $totalAmountDonated and $totalNumberOfDonations
* @since 2.19.6
*
diff --git a/src/Donors/Repositories/DonorRepository.php b/src/Donors/Repositories/DonorRepository.php
index d3fb5cc9e6..ce19e9a9bb 100644
--- a/src/Donors/Repositories/DonorRepository.php
+++ b/src/Donors/Repositories/DonorRepository.php
@@ -97,7 +97,7 @@ public function getAdditionalEmails(int $donorId)
}
/**
- * @unreleased Add support to "phone" property
+ * @since 3.7.0 Add support to "phone" property
* @since 2.24.0 add support for $donor->totalAmountDonated and $donor->totalNumberOfDonation
* @since 2.21.0 add actions givewp_donor_creating and givewp_donor_created
* @since 2.20.0 mutate model and return void
@@ -177,7 +177,7 @@ public function insert(Donor $donor)
}
/**
- * @unreleased Add support to "phone" property
+ * @since 3.7.0 Add support to "phone" property
* @since 2.24.0 add support for $donor->totalAmountDonated and $donor->totalNumberOfDonation
* @since 2.23.1 use give()->donor_meta to update meta so data is upserted
* @since 2.21.0 add actions givewp_donor_updating and givewp_donor_updated
@@ -374,7 +374,7 @@ public function getByAdditionalEmail(string $email)
}
/**
- * @unreleased Add support to "phone" property
+ * @since 3.7.0 Add support to "phone" property
* @since 2.24.0 replace ModelQueryBuilder with DonorModelQueryBuilder
* @since 2.19.6
*
diff --git a/src/Donors/ServiceProvider.php b/src/Donors/ServiceProvider.php
index 5d9d61c6bd..74b6d938e5 100644
--- a/src/Donors/ServiceProvider.php
+++ b/src/Donors/ServiceProvider.php
@@ -41,7 +41,7 @@ public function register()
/**
* @inheritDoc
*
- * @unreleased Register "AddPhoneColumn" migration and add the "give_admin_donor_details_updating" action
+ * @since 3.7.0 Register "AddPhoneColumn" migration and add the "give_admin_donor_details_updating" action
*/
public function boot()
{
diff --git a/src/FormBuilder/ViewModels/FormBuilderViewModel.php b/src/FormBuilder/ViewModels/FormBuilderViewModel.php
index 82556b916c..7bb6d3a3a3 100644
--- a/src/FormBuilder/ViewModels/FormBuilderViewModel.php
+++ b/src/FormBuilder/ViewModels/FormBuilderViewModel.php
@@ -20,7 +20,7 @@
class FormBuilderViewModel
{
/**
- * @unreleased Add support to isExcerptEnabled key in the compared array
+ * @since 3.7.0 Add support to isExcerptEnabled key in the compared array
* @since 3.2.0 Add nameTitlePrefixes key to the returned array
* @since 3.0.0
*/
diff --git a/src/FormBuilder/resources/js/form-builder/src/common/getWindowData.ts b/src/FormBuilder/resources/js/form-builder/src/common/getWindowData.ts
index ebee54cdcd..4066530342 100644
--- a/src/FormBuilder/resources/js/form-builder/src/common/getWindowData.ts
+++ b/src/FormBuilder/resources/js/form-builder/src/common/getWindowData.ts
@@ -18,7 +18,7 @@ type GoalTypeOption = {
};
/**
- * @unreleased Added isExcerptEnabled
+ * @since 3.7.0 Added isExcerptEnabled
* @since 3.0.0
*/
interface FormBuilderWindowData {
diff --git a/src/FormBuilder/resources/js/form-builder/src/settings/group-general/form-summary/index.jsx b/src/FormBuilder/resources/js/form-builder/src/settings/group-general/form-summary/index.jsx
index 1d5c99e9bf..6a5bd56f85 100644
--- a/src/FormBuilder/resources/js/form-builder/src/settings/group-general/form-summary/index.jsx
+++ b/src/FormBuilder/resources/js/form-builder/src/settings/group-general/form-summary/index.jsx
@@ -8,7 +8,7 @@ import {getWindowData} from '@givewp/form-builder/common';
const {isExcerptEnabled} = getWindowData();
/**
- * @unreleased Added formExcerpt text area
+ * @since 3.7.0 Added formExcerpt text area
* @since 3.1.0 dispatch page slug from form title on initial publish.
*/
const FormSummarySettings = ({settings, setSettings}) => {
diff --git a/src/FormBuilder/resources/js/form-builder/src/types/formSettings.ts b/src/FormBuilder/resources/js/form-builder/src/types/formSettings.ts
index ddfd60c518..bf2c5375bf 100644
--- a/src/FormBuilder/resources/js/form-builder/src/types/formSettings.ts
+++ b/src/FormBuilder/resources/js/form-builder/src/types/formSettings.ts
@@ -2,7 +2,7 @@ import {FormStatus} from '@givewp/form-builder/types/formStatus';
import {EmailTemplateOption} from '@givewp/form-builder/types/emailTemplateOption';
/**
- * @unreleased Added formExcerpt
+ * @since 3.7.0 Added formExcerpt
* @since 3.0.0
*/
export type FormSettings = {
diff --git a/src/FormMigration/FormMetaDecorator.php b/src/FormMigration/FormMetaDecorator.php
index 78efb87ec9..b0a3d0eb71 100644
--- a/src/FormMigration/FormMetaDecorator.php
+++ b/src/FormMigration/FormMetaDecorator.php
@@ -511,7 +511,7 @@ public function getFeeRecoverySettings(): array
}
/**
- * @unreleased
+ * @since 3.7.0
*/
public function isConstantContactEnabled(): bool
{
@@ -525,7 +525,7 @@ public function isConstantContactEnabled(): bool
}
/**
- * @unreleased
+ * @since 3.7.0
*/
public function getConstantContactLabel(): string
{
@@ -535,7 +535,7 @@ public function getConstantContactLabel(): string
}
/**
- * @unreleased
+ * @since 3.7.0
*/
public function getConstantContactDefaultChecked(): bool
{
@@ -549,7 +549,7 @@ public function getConstantContactDefaultChecked(): bool
}
/**
- * @unreleased
+ * @since 3.7.0
*/
public function getConstantContactSelectedLists(): array
{
@@ -581,7 +581,7 @@ public function getMailchimpLabel(): string
}
/**
- * @unreleased add global setting as default.
+ * @since 3.7.0 add global setting as default.
* @since 3.3.0
*/
public function getMailchimpDefaultChecked(): bool
@@ -591,7 +591,7 @@ public function getMailchimpDefaultChecked(): bool
}
/**
- * @unreleased add global setting as default.
+ * @since 3.7.0 add global setting as default.
* @since 3.3.0
*/
public function getMailchimpSendDonationData(): bool
@@ -601,7 +601,7 @@ public function getMailchimpSendDonationData(): bool
}
/**
- * @unreleased add global setting as default.
+ * @since 3.7.0 add global setting as default.
* @since 3.3.0
*/
public function getMailchimpSendFFMData(): bool
diff --git a/src/FormMigration/Steps/ConstantContact.php b/src/FormMigration/Steps/ConstantContact.php
index 561ad21555..54aa22679d 100644
--- a/src/FormMigration/Steps/ConstantContact.php
+++ b/src/FormMigration/Steps/ConstantContact.php
@@ -6,12 +6,12 @@
use Give\Framework\Blocks\BlockModel;
/**
- * @unreleased
+ * @since 3.7.0
*/
class ConstantContact extends FormMigrationStep
{
/**
- * @unreleased
+ * @since 3.7.0
*/
public function canHandle(): bool
{
@@ -19,7 +19,7 @@ public function canHandle(): bool
}
/**
- * @unreleased
+ * @since 3.7.0
*/
public function process(): void
{
diff --git a/src/FormMigration/Steps/FormExcerpt.php b/src/FormMigration/Steps/FormExcerpt.php
index c5766e096d..40a5472397 100644
--- a/src/FormMigration/Steps/FormExcerpt.php
+++ b/src/FormMigration/Steps/FormExcerpt.php
@@ -5,12 +5,12 @@
use Give\FormMigration\Contracts\FormMigrationStep;
/**
- * @unreleased
+ * @since 3.7.0
*/
class FormExcerpt extends FormMigrationStep
{
/**
- * @unreleased
+ * @since 3.7.0
*/
public function process()
{
diff --git a/src/MultiFormGoals/MultiFormGoal/Shortcode.php b/src/MultiFormGoals/MultiFormGoal/Shortcode.php
index f28da58190..090b00156c 100644
--- a/src/MultiFormGoals/MultiFormGoal/Shortcode.php
+++ b/src/MultiFormGoals/MultiFormGoal/Shortcode.php
@@ -26,7 +26,7 @@ public function addShortcode()
/**
* Returns Shortcode markup
*
- * @unreleased Sanitize attributes
+ * @since 3.7.0 Sanitize attributes
* @since 3.0.3 Use static function on array_map callback to pass the id as reference for _give_redirect_form_id to prevent warnings on PHP 8.0.1 or plus
* @since 2.9.0
**/
diff --git a/src/Views/IframeView.php b/src/Views/IframeView.php
index c524136059..18139f8f43 100644
--- a/src/Views/IframeView.php
+++ b/src/Views/IframeView.php
@@ -261,7 +261,7 @@ private function getIframeHTML()
/**
* Get button HTML.
*
- * @unreleased Escape attributes
+ * @since 3.7.0 Escape attributes
*
* @return string
*/
diff --git a/tests/Feature/FormMigration/Steps/TestConstantContact.php b/tests/Feature/FormMigration/Steps/TestConstantContact.php
index 2825d02d61..52369f1d0c 100644
--- a/tests/Feature/FormMigration/Steps/TestConstantContact.php
+++ b/tests/Feature/FormMigration/Steps/TestConstantContact.php
@@ -9,7 +9,7 @@
use Give\Tests\Unit\DonationForms\TestTraits\LegacyDonationFormAdapter;
/**
- * @unreleased
+ * @since 3.7.0
*
* @covers \Give\FormMigration\Steps\DonationGoal
*/
@@ -18,7 +18,7 @@ class TestConstantContact extends TestCase
use RefreshDatabase, LegacyDonationFormAdapter;
/**
- * @unreleased
+ * @since 3.7.0
*/
public function testProcessShouldUpdateConstantContactBlockAttributesWithV2FormMeta(): void
{
@@ -44,7 +44,7 @@ public function testProcessShouldUpdateConstantContactBlockAttributesWithV2FormM
}
/**
- * @unreleased
+ * @since 3.7.0
*/
public function testProcessShouldUpdateConstantContactBlockAttributesWithGlobalSettings(): void
{
@@ -74,7 +74,7 @@ public function testProcessShouldUpdateConstantContactBlockAttributesWithGlobalS
}
/**
- * @unreleased
+ * @since 3.7.0
*/
public function testProcessShouldUpdateConstantContactBlockAttributesWhenNoMeta(): void
{
diff --git a/tests/Feature/FormMigration/Steps/TestMailchimp.php b/tests/Feature/FormMigration/Steps/TestMailchimp.php
index 23480788e1..7c9e9be78c 100644
--- a/tests/Feature/FormMigration/Steps/TestMailchimp.php
+++ b/tests/Feature/FormMigration/Steps/TestMailchimp.php
@@ -15,7 +15,7 @@ class TestMailchimp extends TestCase
use RefreshDatabase, LegacyDonationFormAdapter;
/**
- * @unreleased
+ * @since 3.7.0
*/
public function testProcessShouldUpdateMailchimpBlockAttributesFromV2FormMeta(): void
{
@@ -47,7 +47,7 @@ public function testProcessShouldUpdateMailchimpBlockAttributesFromV2FormMeta():
}
/**
- * @unreleased
+ * @since 3.7.0
*/
public function testProcessShouldUpdateMailchimpBlockAttributesFromGlobalSettings(): void
{
@@ -84,7 +84,7 @@ public function testProcessShouldUpdateMailchimpBlockAttributesFromGlobalSetting
}
/**
- * @unreleased
+ * @since 3.7.0
*/
public function testProcessShouldUpdateMailchimpBlockAttributesWhenNoMeta(): void
{
diff --git a/tests/Unit/Donors/Models/TestDonor.php b/tests/Unit/Donors/Models/TestDonor.php
index 145043d251..78242239e3 100644
--- a/tests/Unit/Donors/Models/TestDonor.php
+++ b/tests/Unit/Donors/Models/TestDonor.php
@@ -80,7 +80,7 @@ public function testShouldGetSubscriptions()
}
/**
- * @unreleased
+ * @since 3.7.0
*
* @throws Exception
*/
@@ -92,7 +92,7 @@ public function testCreateShouldDonorWithPhone()
}
/**
- * @unreleased
+ * @since 3.7.0
*
* @throws Exception
*/
diff --git a/tests/Unit/Donors/Repositories/TestDonorRepository.php b/tests/Unit/Donors/Repositories/TestDonorRepository.php
index e1181d5905..f4f30b8614 100644
--- a/tests/Unit/Donors/Repositories/TestDonorRepository.php
+++ b/tests/Unit/Donors/Repositories/TestDonorRepository.php
@@ -46,7 +46,7 @@ public function testGetByIdShouldReturnDonor()
}
/**
- * @unreleased Test "phone" property
+ * @since 3.7.0 Test "phone" property
* @since 2.19.6
*
* @return void
@@ -81,7 +81,7 @@ public function testInsertShouldAddDonorToDatabase()
}
/**
- * @unreleased
+ * @since 3.7.0
*
* @throws Exception
*/
@@ -129,7 +129,7 @@ public function testInsertShouldFailValidationAndThrowException()
}
/**
- * @unreleased Test "phone" property
+ * @since 3.7.0 Test "phone" property
* @since 2.19.6
*
* @return void
diff --git a/tests/Unit/ViewModels/FormBuilderViewModelTest.php b/tests/Unit/ViewModels/FormBuilderViewModelTest.php
index 080118d9e7..23c072c582 100644
--- a/tests/Unit/ViewModels/FormBuilderViewModelTest.php
+++ b/tests/Unit/ViewModels/FormBuilderViewModelTest.php
@@ -24,7 +24,7 @@ class FormBuilderViewModelTest extends TestCase
/**
*
- * @unreleased Add support to isExcerptEnabled key in the compared array
+ * @since 3.7.0 Add support to isExcerptEnabled key in the compared array
* @since 3.2.0 Add support to nameTitlePrefixes key in the compared array
* @since 3.0.0
*
From 2f2310d07de61c67109eddc3eedc85c43d34b35b Mon Sep 17 00:00:00 2001
From: Jon Waldstein
Date: Fri, 12 Apr 2024 17:52:32 -0400
Subject: [PATCH 6/6] Feature: GiveWP BlockTypes (#7195)
Co-authored-by: Jon Waldstein
Co-authored-by: Jon Waldstein
---
.../Concerns/HasDefaultFieldAttributes.php | 41 ++
.../BlockTypes/DonationAmountBlockType.php | 148 ++++++
src/FormBuilder/BlockTypes/TextBlockType.php | 22 +
src/Framework/Blocks/BlockType.php | 237 ++++++++++
.../Blocks/Contracts/BlockTypeInterface.php | 14 +
.../TestDonationAmountBlockType.php | 66 +++
.../BlockTypes/TestTextBlockType.php | 97 ++++
tests/Unit/Framework/Blocks/TestBlockType.php | 420 ++++++++++++++++++
8 files changed, 1045 insertions(+)
create mode 100644 src/FormBuilder/BlockTypes/Concerns/HasDefaultFieldAttributes.php
create mode 100644 src/FormBuilder/BlockTypes/DonationAmountBlockType.php
create mode 100644 src/FormBuilder/BlockTypes/TextBlockType.php
create mode 100644 src/Framework/Blocks/BlockType.php
create mode 100644 src/Framework/Blocks/Contracts/BlockTypeInterface.php
create mode 100644 tests/Unit/FormBuilder/BlockTypes/TestDonationAmountBlockType.php
create mode 100644 tests/Unit/FormBuilder/BlockTypes/TestTextBlockType.php
create mode 100644 tests/Unit/Framework/Blocks/TestBlockType.php
diff --git a/src/FormBuilder/BlockTypes/Concerns/HasDefaultFieldAttributes.php b/src/FormBuilder/BlockTypes/Concerns/HasDefaultFieldAttributes.php
new file mode 100644
index 0000000000..3d26c90fea
--- /dev/null
+++ b/src/FormBuilder/BlockTypes/Concerns/HasDefaultFieldAttributes.php
@@ -0,0 +1,41 @@
+ 'string',
+ 'description' => 'string',
+ 'placeholder' => 'string',
+ 'isRequired' => 'bool',
+ 'conditionalLogic' => 'array',
+ 'storeAsDonorMeta' => 'bool',
+ 'displayInAdmin' => 'bool',
+ 'displayInReceipt' => 'bool',
+ 'defaultValue' => 'string',
+ 'emailTag' => 'string',
+ 'fieldName' => 'string',
+ ];
+ }
+}
diff --git a/src/FormBuilder/BlockTypes/DonationAmountBlockType.php b/src/FormBuilder/BlockTypes/DonationAmountBlockType.php
new file mode 100644
index 0000000000..a7e869aace
--- /dev/null
+++ b/src/FormBuilder/BlockTypes/DonationAmountBlockType.php
@@ -0,0 +1,148 @@
+ 'string',
+ 'levels' => 'array',
+ 'defaultLevel' => 'float',
+ 'priceOption' => 'string',
+ 'setPrice' => 'int',
+ 'customAmount' => 'bool',
+ 'customAmountMin' => 'int',
+ 'customAmountMax' => 'int',
+ 'recurringEnabled' => 'bool',
+ 'recurringBillingInterval' => 'int',
+ 'recurringBillingPeriodOptions' => 'array',
+ 'recurringLengthOfTime' => 'int',
+ 'recurringEnableOneTimeDonations' => 'bool',
+ 'recurringOptInDefaultBillingPeriod' => 'string',
+ ];
+
+ /**
+ * @unreleased
+ *
+ * @return float[]
+ */
+ public function getLevels(): array
+ {
+ return array_map(static function ($level) {
+ return (float)filter_var($level, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
+ }, $this->levels);
+ }
+
+ /**
+ * @return bool
+ */
+ public function isRecurringFixed(): bool
+ {
+ return count($this->recurringBillingPeriodOptions) === 1 && $this->recurringEnableOneTimeDonations === false;
+ }
+
+ /**
+ * @unreleased
+ */
+ public function setRecurringEnabled(bool $enabled = true): self
+ {
+ $this->recurringEnabled = $enabled;
+
+ return $this;
+ }
+
+ /**
+ * @unreleased
+ */
+ public function setRecurringEnableOneTimeDonations(bool $enabled = true): self
+ {
+ $this->recurringEnableOneTimeDonations = $enabled;
+
+ return $this;
+ }
+
+ /**
+ * @unreleased
+ */
+ public function setRecurringBillingInterval(int $interval): self
+ {
+ $this->recurringBillingInterval = $interval;
+
+ return $this;
+ }
+
+ /**
+ * @unreleased
+ */
+ public function setRecurringLengthOfTime(int $lengthOfTime): self
+ {
+ $this->recurringLengthOfTime = $lengthOfTime;
+
+ return $this;
+ }
+
+ /**
+ * @unreleased
+ */
+ public function setRecurringBillingPeriodOptions(SubscriptionPeriod ...$options): self
+ {
+ $this->recurringBillingPeriodOptions =
+ array_values(
+ array_map(static function (SubscriptionPeriod $option) {
+ return $option->getValue();
+ }, $options)
+ );
+
+ return $this;
+ }
+
+ /**
+ * @unreleased
+ */
+ public function setRecurringOptInDefaultBillingPeriod(SubscriptionPeriod $period): self
+ {
+ $this->recurringOptInDefaultBillingPeriod = $period->getValue();
+
+ return $this;
+ }
+
+ /**
+ * @since 3.0.0
+ */
+ public function isCustomAmountEnabled(): bool
+ {
+ return $this->customAmount === true;
+ }
+}
diff --git a/src/FormBuilder/BlockTypes/TextBlockType.php b/src/FormBuilder/BlockTypes/TextBlockType.php
new file mode 100644
index 0000000000..0609ba67e5
--- /dev/null
+++ b/src/FormBuilder/BlockTypes/TextBlockType.php
@@ -0,0 +1,22 @@
+block = $block;
+
+ if ($this->block->name !== $this::name()) {
+ throw new RuntimeException(
+ sprintf(
+ 'BlockModel name "%s" does not match the BlockType name "%s".',
+ $this->block->name,
+ $this::name()
+ )
+ );
+ }
+
+ $this->fillDefaultProperties();
+ }
+
+ /**
+ * Dynamically retrieve attributes.
+ *
+ * @unreleased
+ *
+ * @return mixed
+ */
+ public function __get(string $key)
+ {
+ $value = $this->getAttribute($key);
+
+ return $this->castAttributeType($key, $value);
+ }
+
+ /**
+ * Dynamically set attributes.
+ *
+ * @unreleased
+ *
+ * @param mixed $value
+ *
+ * @return void
+ */
+ public function __set(string $key, $value)
+ {
+ $this->validateAttributeType($key, $value);
+
+ $this->setAttribute($key, $value);
+ }
+
+ /**
+ * Determine if an attribute exists.
+ *
+ * @unreleased
+ *
+ * @return bool
+ */
+ public function __isset(string $key)
+ {
+ return !is_null($this->getAttribute($key));
+ }
+
+ /**
+ * @unreleased
+ */
+ protected function getAttribute($name)
+ {
+ return $this->block->getAttribute($name);
+ }
+
+ /**
+ * @unreleased
+ */
+ protected function hasAttribute($name): bool
+ {
+ return $this->block->hasAttribute($name);
+ }
+
+ /**
+ * @unreleased
+ */
+ protected function setAttribute(string $name, $value): self
+ {
+ $this->block->setAttribute($name, $value);
+
+ return $this;
+ }
+
+ /**
+ * Validates that the given value is a valid type for the given attribute.
+ *
+ * @unreleased
+ *
+ * @throws InvalidArgumentException
+ */
+ protected function validateAttributeType(string $key, $value): void
+ {
+ if (!$this->isAttributeTypeValid($key, $value)) {
+ $type = $this->getPropertyType($key);
+
+ throw new InvalidArgumentException("Invalid attribute assignment. '$key' should be of type: '$type'");
+ }
+ }
+
+ /**
+ * Validate an attribute to a PHP type.
+ *
+ * @unreleased
+ */
+ public function isAttributeTypeValid(string $key, $value): bool
+ {
+ if (is_null($value)) {
+ return true;
+ }
+
+ $type = $this->getPropertyType($key);
+
+ switch ($type) {
+ case 'int':
+ return is_int($value);
+ case 'string':
+ return is_string($value);
+ case 'bool':
+ return is_bool($value);
+ case 'array':
+ return is_array($value);
+ case 'float':
+ return is_float($value);
+ default:
+ return $value instanceof $type;
+ }
+ }
+
+ /**
+ * @unreleased
+ */
+ public function castAttributeType(string $key, $value)
+ {
+ if (is_null($value)) {
+ return null;
+ }
+
+ $type = $this->getPropertyType($key);
+
+ switch ($type) {
+ case 'int':
+ return (int)($value);
+ case 'string':
+ return (string)($value);
+ case 'bool':
+ return filter_var($value, FILTER_VALIDATE_BOOLEAN);
+ case 'array':
+ return (array)($value);
+ case 'float':
+ return (float)filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT,FILTER_FLAG_ALLOW_FRACTION);
+ default:
+ return $value;
+ }
+ }
+
+ /**
+ * @unreleased
+ */
+ protected function getPropertyType(string $key): string
+ {
+ $type = is_array($this->properties[$key]) ? $this->properties[$key][0] : $this->properties[$key];
+
+ return strtolower(trim($type));
+ }
+
+ /**
+ * @unreleased
+ */
+ public function toArray(): array
+ {
+ $attributes = [];
+
+ foreach($this->properties as $key => $type) {
+ $attributes[$key] = $this->{$key};
+ }
+
+ return [
+ 'name' => $this::name(),
+ 'attributes' => $attributes
+ ];
+ }
+
+ /**
+ * @unreleased
+ */
+ protected function setDefaultProperties(): array
+ {
+ return [];
+ }
+
+ /**
+ * @unreleased
+ */
+ private function fillDefaultProperties(): void
+ {
+ foreach ($this->setDefaultProperties() as $key => $type) {
+ if ($this->hasAttribute($key)) {
+ $this->properties[$key] = $type;
+ }
+ }
+ }
+}
diff --git a/src/Framework/Blocks/Contracts/BlockTypeInterface.php b/src/Framework/Blocks/Contracts/BlockTypeInterface.php
new file mode 100644
index 0000000000..853fa390d5
--- /dev/null
+++ b/src/Framework/Blocks/Contracts/BlockTypeInterface.php
@@ -0,0 +1,14 @@
+getDefaultDonationAmountBlockModel();
+ $block = new \Give\FormBuilder\BlockTypes\DonationAmountBlockType($blockModel);
+
+ $this->assertSame('givewp/donation-amount', $block::name());
+ }
+
+ /**
+ * @unreleased
+ * @throws Exception
+ */
+ public function testDefaultBlockModelAttributesMatchBlockTypeProperties(): void
+ {
+ $blockModel = $this->getDefaultDonationAmountBlockModel();
+ $block = new \Give\FormBuilder\BlockTypes\DonationAmountBlockType($blockModel);
+
+ $this->assertSame(__("Donation Amount", 'give'), $block->label);
+ $this->assertSame([
+ 10,
+ 25,
+ 50,
+ 100,
+ 250,
+ 500
+ ], $block->levels);
+ $this->assertSame(10.00, $block->defaultLevel);
+ $this->assertSame("multi", $block->priceOption);
+ $this->assertSame(25, $block->setPrice);
+ $this->assertTrue($block->customAmount);
+ $this->assertSame(1, $block->customAmountMin);
+ $this->assertNull($block->customAmountMax);
+ $this->assertFalse($block->recurringEnabled);
+ $this->assertSame(1, $block->recurringBillingInterval);
+ $this->assertSame(["month"], $block->recurringBillingPeriodOptions);
+ $this->assertSame(0, $block->recurringLengthOfTime);
+ $this->assertTrue($block->recurringEnableOneTimeDonations);
+ $this->assertSame('month', $block->recurringOptInDefaultBillingPeriod);
+ }
+
+ /**
+ * @unreleased
+ */
+ public function getDefaultDonationAmountBlockModel(): BlockModel
+ {
+ return (new GenerateDefaultDonationFormBlockCollection())()->findByName('givewp/donation-amount');
+ }
+}
diff --git a/tests/Unit/FormBuilder/BlockTypes/TestTextBlockType.php b/tests/Unit/FormBuilder/BlockTypes/TestTextBlockType.php
new file mode 100644
index 0000000000..c1e6a19f23
--- /dev/null
+++ b/tests/Unit/FormBuilder/BlockTypes/TestTextBlockType.php
@@ -0,0 +1,97 @@
+ 'givewp/text',
+ 'attributes' => [
+ 'label' => 'Test Label',
+ 'description' => 'Test Description',
+ ]
+ ]
+ );
+
+ $blockType = new \Give\FormBuilder\BlockTypes\TextBlockType($blockModel);
+
+ $this->assertSame('givewp/text', $blockType::name());
+ }
+
+ /**
+ * @unreleased
+ *
+ * @throws Exception
+ */
+ public function testAttributesShouldMatchProperties(): void
+ {
+ $blockModel = BlockModel::make(
+ [
+ 'name' => 'givewp/text',
+ 'attributes' => [
+ 'label' => 'Test Label',
+ 'description' => 'Test Description',
+ 'placeholder' => 'Test Placeholder',
+ 'isRequired' => true,
+ 'displayInAdmin' => true,
+ 'displayInReceipt' => true,
+ 'defaultValue' => 'Test Default Value',
+ 'emailTag' => 'test@givewp.com',
+ 'fieldName' => 'test_field_name',
+ 'conditionalLogic' => [
+ 'enabled' => true,
+ 'action' => 'show',
+ 'boolean' => 'and',
+ 'rules' => [
+ [
+ 'field' => 'Test Field ID',
+ 'operator' => '=',
+ 'value' => '100'
+ ]
+ ]
+ ],
+ ]
+ ]
+ );
+
+ $blockType = new \Give\FormBuilder\BlockTypes\TextBlockType($blockModel);
+
+ $this->assertSame('Test Label', $blockType->label);
+ $this->assertSame('Test Description', $blockType->description);
+ $this->assertSame('Test Placeholder', $blockType->placeholder);
+ $this->assertTrue($blockType->isRequired);
+ $this->assertTrue($blockType->displayInAdmin);
+ $this->assertTrue($blockType->displayInReceipt);
+ $this->assertSame('Test Default Value', $blockType->defaultValue);
+ $this->assertSame('test@givewp.com', $blockType->emailTag);
+ $this->assertSame('test_field_name', $blockType->fieldName);
+ $this->assertSame(
+ [
+ 'enabled' => true,
+ 'action' => 'show',
+ 'boolean' => 'and',
+ 'rules' => [
+ [
+ 'field' => 'Test Field ID',
+ 'operator' => '=',
+ 'value' => '100'
+ ]
+ ]
+ ],
+ $blockType->conditionalLogic
+ );
+ }
+}
diff --git a/tests/Unit/Framework/Blocks/TestBlockType.php b/tests/Unit/Framework/Blocks/TestBlockType.php
new file mode 100644
index 0000000000..6d2b231d7e
--- /dev/null
+++ b/tests/Unit/Framework/Blocks/TestBlockType.php
@@ -0,0 +1,420 @@
+expectException(RuntimeException::class);
+
+ $blockModel = new BlockModel('givewp/not-donation-amount');
+
+ new class ($blockModel) extends BlockType {
+ public static function name(): string
+ {
+ return 'givewp/donation-amount';
+ }
+ };
+ }
+
+ /**
+ * @unreleased
+ *
+ * @throws Exception
+ */
+ public function testBlockModelAndBlockTypeShouldHaveMatchingNames(): void
+ {
+ $blockModel = new BlockModel('givewp/donation-amount');
+
+ $blockType = new class ($blockModel) extends BlockType {
+ public static function name(): string
+ {
+ return 'givewp/donation-amount';
+ }
+ };
+
+ $this->assertSame('givewp/donation-amount', $blockType::name());
+ }
+
+ /**
+ * @unreleased
+ *
+ * @throws Exception
+ */
+ public function testShouldHavePropertiesThatMatchBlockModelAttributes(): void
+ {
+ $blockModel = BlockModel::make([
+ 'name' => 'givewp/donation-amount',
+ 'attributes' => [
+ 'label' => 'Donation Amount',
+ 'recurringEnabled' => false,
+ ]
+ ]);
+
+ $blockType = new class ($blockModel) extends BlockType {
+ protected $properties = [
+ 'label' => 'string',
+ 'recurringEnabled' => 'bool',
+ ];
+
+ public static function name(): string
+ {
+ return 'givewp/donation-amount';
+ }
+ };
+
+ $this->assertSame('Donation Amount', $blockType->label);
+ $this->assertSame(false, $blockType->recurringEnabled);
+ }
+
+ /**
+ * @unreleased
+ *
+ * @throws Exception
+ */
+ public function testShouldCastBoolPropertyValues(): void
+ {
+ $blockModel = BlockModel::make([
+ 'name' => 'givewp/donation-amount',
+ 'attributes' => [
+ 'falsyAttribute' => false,
+ 'falsyStringAttribute' => 'false',
+ 'falsyIntAttribute' => 0,
+ 'truthyAttribute' => true,
+ 'truthyStringAttribute' => 'true',
+ 'truthyIntAttribute' => 1,
+ ]
+ ]);
+
+ $blockType = new class ($blockModel) extends BlockType {
+ protected $properties = [
+ 'falsyAttribute' => 'bool',
+ 'falsyStringAttribute' => 'bool',
+ 'falsyIntAttribute' => 'bool',
+ 'truthyAttribute' => 'bool',
+ 'truthyStringAttribute' => 'bool',
+ 'truthyIntAttribute' => 'bool',
+ ];
+
+ public static function name(): string
+ {
+ return 'givewp/donation-amount';
+ }
+ };
+
+ $this->assertFalse($blockType->falsyAttribute);
+ $this->assertFalse($blockType->falsyStringAttribute);
+ $this->assertFalse($blockType->falsyIntAttribute);
+ $this->assertTrue($blockType->truthyAttribute);
+ $this->assertTrue($blockType->truthyStringAttribute);
+ $this->assertTrue($blockType->truthyIntAttribute);
+ }
+
+ /**
+ * @unreleased
+ *
+ * @throws Exception
+ */
+ public function testShouldCastStringPropertyValues(): void
+ {
+ $blockModel = BlockModel::make([
+ 'name' => 'givewp/donation-amount',
+ 'attributes' => [
+ 'stringAttribute' => '123',
+ 'intStringAttribute' => 123,
+ 'floatStringAttribute' => 123.00,
+ ]
+ ]);
+
+ $blockType = new class ($blockModel) extends BlockType {
+ protected $properties = [
+ 'stringAttribute' => 'string',
+ 'intStringAttribute' => 'string',
+ 'floatStringAttribute' => 'string',
+ ];
+
+ public static function name(): string
+ {
+ return 'givewp/donation-amount';
+ }
+ };
+
+ $this->assertSame('123', $blockType->stringAttribute);
+ $this->assertSame('123', $blockType->intStringAttribute);
+ $this->assertSame('123', $blockType->floatStringAttribute);
+ }
+
+ /**
+ * @unreleased
+ *
+ * @throws Exception
+ */
+ public function testShouldCastIntPropertyValues(): void
+ {
+ $blockModel = BlockModel::make([
+ 'name' => 'givewp/donation-amount',
+ 'attributes' => [
+ 'intAttribute' => 123,
+ 'stringIntAttribute' => '123',
+ 'floatIntAttribute' => 123.00,
+ ]
+ ]);
+
+ $blockType = new class ($blockModel) extends BlockType {
+ protected $properties = [
+ 'intAttribute' => 'int',
+ 'stringIntAttribute' => 'int',
+ 'floatIntAttribute' => 'int',
+ ];
+
+ public static function name(): string
+ {
+ return 'givewp/donation-amount';
+ }
+ };
+
+ $this->assertSame(123, $blockType->intAttribute);
+ $this->assertSame(123, $blockType->stringIntAttribute);
+ $this->assertSame(123, $blockType->floatIntAttribute);
+ }
+
+ /**
+ * @unreleased
+ *
+ * @throws Exception
+ */
+ public function testShouldCastArrayPropertyValues(): void
+ {
+ $blockModel = BlockModel::make([
+ 'name' => 'givewp/donation-amount',
+ 'attributes' => [
+ 'arrayAttribute' => ['green', 'eggs', 'and', 'ham'],
+ 'intArrayAttribute' => 123,
+ 'stringArrayAttribute' => 'green'
+ ]
+ ]);
+
+ $blockType = new class ($blockModel) extends BlockType {
+ protected $properties = [
+ 'arrayAttribute' => 'array',
+ 'intArrayAttribute' => 'array',
+ 'stringArrayAttribute' => 'array',
+ ];
+
+ public static function name(): string
+ {
+ return 'givewp/donation-amount';
+ }
+ };
+
+ $this->assertSame(['green', 'eggs', 'and', 'ham'], $blockType->arrayAttribute);
+ $this->assertSame([123], $blockType->intArrayAttribute);
+ $this->assertSame(['green'], $blockType->stringArrayAttribute);
+ }
+
+ /**
+ * @unreleased
+ */
+ public function testShouldCastFloatPropertyValues(): void
+ {
+ $blockModel = BlockModel::make([
+ 'name' => 'givewp/donation-amount',
+ 'attributes' => [
+ 'floatAttribute' => 123.00,
+ 'stringFloatAttribute' => '123.00',
+ 'intFloatAttribute' => 123,
+ ]
+ ]);
+
+ $blockType = new class ($blockModel) extends BlockType {
+ protected $properties = [
+ 'floatAttribute' => 'float',
+ 'stringFloatAttribute' => 'float',
+ 'intFloatAttribute' => 'float',
+ ];
+
+ public static function name(): string
+ {
+ return 'givewp/donation-amount';
+ }
+ };
+
+ $this->assertSame(123.00, $blockType->floatAttribute);
+ $this->assertIsFloat($blockType->floatAttribute);
+ $this->assertSame(123.00, $blockType->stringFloatAttribute);
+ $this->assertIsFloat($blockType->stringFloatAttribute);
+ $this->assertSame(123.00, $blockType->intFloatAttribute);
+ $this->assertIsFloat($blockType->intFloatAttribute);
+ }
+
+ /**
+ * @unreleased
+ *
+ * @throws Exception
+ */
+ public function testShouldThrowExceptionWhenSettingInvalidPropertyType(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+
+ $blockModel = BlockModel::make([
+ 'name' => 'givewp/donation-amount',
+ 'attributes' => [
+ 'arrayAttribute' => ['green', 'eggs', 'and', 'ham'],
+ ]
+ ]);
+
+ $blockType = new class ($blockModel) extends BlockType {
+ protected $properties = [
+ 'arrayAttribute' => 'array',
+ ];
+
+ public static function name(): string
+ {
+ return 'givewp/donation-amount';
+ }
+ };
+
+ $blockType->arrayAttribute = 'not an array';
+ }
+
+ /**
+ * @unreleased
+ *
+ * @throws Exception
+ */
+ public function testShouldUpdateExistingPropertyValue(): void
+ {
+ $blockModel = BlockModel::make([
+ 'name' => 'givewp/donation-amount',
+ 'attributes' => [
+ 'arrayAttribute' => ['green', 'eggs', 'and', 'ham'],
+ ]
+ ]);
+
+ $blockType = new class ($blockModel) extends BlockType {
+ protected $properties = [
+ 'arrayAttribute' => 'array',
+ ];
+
+ public static function name(): string
+ {
+ return 'givewp/donation-amount';
+ }
+ };
+
+ $blockType->arrayAttribute = array_merge($blockType->arrayAttribute,['sam', 'i', 'am']);
+
+ $this->assertSame(['green', 'eggs', 'and', 'ham', 'sam', 'i', 'am'], $blockType->arrayAttribute);
+ }
+
+ /**
+ * @unreleased
+ */
+ public function testShouldSetNewProperty(): void
+ {
+ $blockModel = BlockModel::make([
+ 'name' => 'givewp/donation-amount',
+ 'attributes' => []
+ ]);
+
+ $blockType = new class ($blockModel) extends BlockType {
+ protected $properties = [
+ 'arrayAttribute' => 'array',
+ ];
+
+ public static function name(): string
+ {
+ return 'givewp/donation-amount';
+ }
+ };
+
+ $blockType->arrayAttribute = ['green', 'eggs', 'and', 'ham', 'sam', 'i', 'am'];
+
+ $this->assertSame(['green', 'eggs', 'and', 'ham', 'sam', 'i', 'am'], $blockType->arrayAttribute);
+ }
+
+ /**
+ * @unreleased
+ *
+ * @return void
+ */
+ public function testIssetProperty(): void
+ {
+ $blockModel = BlockModel::make([
+ 'name' => 'givewp/donation-amount',
+ 'attributes' => [
+ 'arrayAttribute' => ['green', 'eggs', 'and', 'ham'],
+ ]
+ ]);
+
+ $blockType = new class ($blockModel) extends BlockType {
+ protected $properties = [
+ 'arrayAttribute' => 'array',
+ ];
+
+ public static function name(): string
+ {
+ return 'givewp/donation-amount';
+ }
+ };
+
+ $this->assertTrue(isset($blockType->arrayAttribute));
+ $this->assertFalse(isset($blockType->notAnAttribute));
+ }
+
+ /**
+ * @unreleased
+ */
+ public function testBlockTypeToArray(): void
+ {
+ $blockModel = BlockModel::make([
+ 'name' => 'givewp/donation-amount',
+ 'attributes' => [
+ 'arrayAttribute' => ['green', 'eggs', 'and', 'ham'],
+ 'stringAttribute' => 'hello',
+ 'intAttribute' => 123,
+ 'boolAttribute' => true,
+ ]
+ ]);
+
+ $blockType = new class ($blockModel) extends BlockType {
+ protected $properties = [
+ 'arrayAttribute' => 'array',
+ 'stringAttribute' => 'string',
+ 'intAttribute' => 'int',
+ 'boolAttribute' => 'bool',
+ ];
+
+ public static function name(): string
+ {
+ return 'givewp/donation-amount';
+ }
+ };
+
+ $this->assertSame([
+ 'name' => 'givewp/donation-amount',
+ 'attributes' => [
+ 'arrayAttribute' => ['green', 'eggs', 'and', 'ham'],
+ 'stringAttribute' => 'hello',
+ 'intAttribute' => 123,
+ 'boolAttribute' => true,
+ ]
+ ], $blockType->toArray());
+ }
+}