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()); + } +}