PluginProbe
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management / 1.6.1
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management v1.6.1
1.6.1 1.6.0 1.5.1 1.5.0 1.4.0 1.3.0 trunk 0.0.1 1.0.0 1.1.0 1.1.1 1.1.2 1.2.0
← All changes | inc/blocks/register.php +187 -13 1.4.0 → 1.6.1 View file →
@@ -29,8 +29,20 @@
29 29 class Register {
30 30 use Get_Instance;
31 31
32 32 /**
33 + * Memoized block-inserter preview map (block key => image URL).
34 + *
35 + * Built once per request in get_field_preview_images() so every localized
36 + * copy is identical and the `suredonation_block_preview_images` filter runs
37 + * once.
38 + *
39 + * @var array<string,string>|null
40 + * @since 1.5.0
41 + */
42 + private $preview_images = null;
43 +
44 + /**
33 45 * Constructor.
34 46 *
35 47 * @since 0.0.1
36 48 */
@@ -38,8 +50,9 @@
38 50 add_action( 'init', [ $this, 'register_embed_block_script' ], 5 );
39 51 add_action( 'init', [ $this, 'register_blocks' ] );
40 52 add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_editor_assets' ] );
41 53 add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_campaign_editor_assets' ] );
54 + add_action( 'enqueue_block_editor_assets', [ $this, 'localize_embed_preview_images' ] );
42 55 add_filter( 'block_categories_all', [ $this, 'register_block_category' ], 10, 2 );
43 56 add_filter( 'block_editor_settings_all', [ $this, 'add_campaign_iframe_styles' ], 10, 2 );
44 57 add_filter( 'block_editor_settings_all', [ $this, 'add_donation_form_iframe_styles' ], 10, 2 );
45 58 add_filter( 'block_editor_settings_all', [ $this, 'add_phone_iframe_styles' ], 10, 2 );
@@ -191,8 +204,16 @@
191 204 'suredonationCampaignBlocks',
192 205 $this->get_campaign_blocks_data()
193 206 );
194 207
208 + // Note: the inserter preview map is localized on this handle later, in
209 + // localize_embed_preview_images() on enqueue_block_editor_assets, not here
210 + // on init:5 — see that method for why.
211 +
212 + // Load JS translations for the embed editor bundle so the "Field preview"
213 + // string and the block's own UI strings can be translated.
214 + wp_set_script_translations( 'suredonation-donation-form-editor', 'suredonation' );
215 +
195 216 wp_register_style(
196 217 'suredonation-donation-form-editor',
197 218 SUREDONATION_URL . 'assets/build/blocks/donation-form/editor.css',
198 219 [],
@@ -200,8 +221,34 @@
200 221 );
201 222 }
202 223
203 224 /**
225 + * Localize the inserter preview map onto the donation-form embed script.
226 + *
227 + * The embed block is insertable on any post type, so this runs on every
228 + * editor screen (no post-type guard, unlike enqueue_editor_assets()).
229 + *
230 + * It runs on `enqueue_block_editor_assets` rather than at `init` — where the
231 + * handle is registered — deliberately: get_field_preview_images() memoizes on
232 + * its first call, so the first localizer to run fixes the map for the request.
233 + * Building it here (after `init`) lets consumers of the
234 + * `suredonation_block_preview_images` filter register on the default `init`
235 + * priority — the obvious thing to do, and what SureDonation Pro does on
236 + * `plugins_loaded` — and still be captured. The handle is registered by
237 + * register_embed_block_script() on init:5, so wp_localize_script attaches here.
238 + *
239 + * @return void
240 + * @since 1.5.0
241 + */
242 + public function localize_embed_preview_images() {
243 + wp_localize_script(
244 + 'suredonation-donation-form-editor',
245 + 'suredonation_fields_preview',
246 + $this->get_field_preview_images()
247 + );
248 + }
249 +
250 + /**
204 251 * Data localized for the block editor placeholders (logo).
205 252 *
206 253 * Shared by the donation form embed block and the campaign display blocks,
207 254 * both of which expose it on the `suredonationCampaignBlocks` JS global.
@@ -311,20 +358,23 @@
311 358 'suredonationCampaignBlocks',
312 359 $this->get_campaign_blocks_data()
313 360 );
314 361
315 - // Style the server-side-rendered block previews in the editor.
316 - $style_file = SUREDONATION_DIR . 'assets/build/blocks/campaign/style-style.css';
317 - $style_version = file_exists( $style_file )
318 - ? (string) filemtime( $style_file )
319 - : SUREDONATION_VER;
320 -
321 - wp_enqueue_style(
362 + // Block-inserter preview images (see withFieldPreview / get_field_preview_images()).
363 + wp_localize_script(
322 364 'suredonation-campaign-blocks',
323 - SUREDONATION_URL . 'assets/build/blocks/campaign/style-style.css',
324 - [],
325 - $style_version
365 + 'suredonation_fields_preview',
366 + $this->get_field_preview_images()
326 367 );
368 +
369 + // No stylesheet is enqueued here. The campaign blocks only ever render in
370 + // the canvas, and add_campaign_iframe_styles() inlines this exact CSS into
371 + // it through the editor settings, where it carries no element id and so is
372 + // invisible to the compatibility pass. Enqueueing it on the outer frame as
373 + // well put its one `.editor-styles-wrapper` rule in the admin document,
374 + // which is all it takes for WordPress to clone the whole sheet into the
375 + // canvas and log "suredonation-campaign-blocks-css was added to the iframe
376 + // incorrectly" on every campaign editor load.
327 377 }
328 378
329 379 /**
330 380 * Append an inline stylesheet to the block-editor iframe settings.
@@ -401,11 +451,20 @@
401 451 * @return array<string, mixed> Modified settings.
402 452 * @since 1.0.0
403 453 */
404 454 public function add_campaign_iframe_styles( $settings, $context ) {
405 - // Inject wherever the campaign blocks can be used (everywhere except the
406 - // donation form editor), so their editor previews match the frontend.
407 - if ( ! isset( $context->post ) || 'suredonation_form' === $context->post->post_type ) {
455 + // Inject wherever the campaign blocks can be used, which is every editor
456 + // except the donation form builder — matching the blocks' own registration
457 + // and add_donation_form_iframe_styles() below.
458 + //
459 + // The post is checked only when there is one. Requiring it excluded exactly
460 + // the contexts that have none: the widget editor never sets it
461 + // (wp-admin/widgets-form-blocks.php), and the Site Editor only sets it for a
462 + // numeric postId, so editing any template or template part
463 + // (postId=theme//slug) has none either. The campaign blocks are insertable in
464 + // both, and this stylesheet also carries the placeholder rules the donation
465 + // form embed block reuses, so bailing there left both unstyled.
466 + if ( isset( $context->post ) && 'suredonation_form' === $context->post->post_type ) {
408 467 return $settings;
409 468 }
410 469
411 470 $this->append_iframe_style(
@@ -580,8 +639,123 @@
580 639 // them as placeholders on each field's Error Message control.
581 640 'validationMessages' => \SureDonation\Inc\Field_Validation::get_resolved_validation_messages(),
582 641 ]
583 642 );
643 +
644 + // Field-preview images shown in the block inserter's preview pane (mirrors
645 + // SureForms). Blocks whose block.json sets example.attributes.preview render
646 + // this image via the withFieldPreview HOC; unmapped blocks fall back to the
647 + // shared placeholder key on the JS side.
648 + wp_localize_script(
649 + 'suredonation-blocks',
650 + 'suredonation_fields_preview',
651 + $this->get_field_preview_images()
652 + );
653 + }
654 +
655 + /**
656 + * Block-inserter preview images, keyed by block name (slug, hyphens as
657 + * underscores) to mirror the JS lookup in withFieldPreview.
658 + *
659 + * Shared by every editor bundle (field blocks, campaign blocks, donation-form
660 + * embed) so the same map is localized wherever a SureDonation block can be
661 + * inserted. Field-type blocks reuse the SureForms field-preview art; campaign
662 + * and donation-form display blocks use SureDonation's own mockups; anything not
663 + * listed falls back to the shared placeholder on the JS side.
664 + *
665 + * Pro-only field blocks (date/time picker) register their own art through the
666 + * `suredonation_block_preview_images` filter — Pro owns those assets, so they
667 + * are not listed here.
668 + *
669 + * Memoized so the map is built once per request: every localized copy is then
670 + * identical regardless of which editor hook fires first, and the filter runs
671 + * exactly once.
672 + *
673 + * @return array<string,string> Map of block key => image URL.
674 + * @since 1.5.0
675 + */
676 + public function get_field_preview_images() {
677 + if ( null !== $this->preview_images ) {
678 + return $this->preview_images;
679 + }
680 +
681 + $base = SUREDONATION_URL . 'images/field-previews/';
682 +
683 + /**
684 + * Filters the block-inserter preview image map.
685 + *
686 + * Keys are block slugs with hyphens replaced by underscores
687 + * (`suredonation/date-picker` => `date_picker`) to match the JS lookup in
688 + * withFieldPreview; values are absolute image URLs.
689 + *
690 + * Register no later than `init` — SureDonation Pro adds its date/time
691 + * picker art on `plugins_loaded`. The map is first built on
692 + * `enqueue_block_editor_assets` and then memoized, so a filter added after
693 + * that first build is silently ignored.
694 + *
695 + * @since 1.5.0
696 + *
697 + * @param array<string,string> $images Map of block key => image URL.
698 + */
699 + $images = apply_filters(
700 + 'suredonation_block_preview_images',
701 + [
702 + // Field blocks.
703 + 'input' => $base . 'input.svg',
704 + 'email' => $base . 'email.svg',
705 + 'number' => $base . 'number.svg',
706 + 'checkbox' => $base . 'checkbox.svg',
707 + // A multi-line message field — the textarea art, not the text input's.
708 + 'donor_comment' => $base . 'donor-comment.svg',
709 + // Anonymous-donation and cover-fees both render a single checkbox.
710 + 'anonymous_donation' => $base . 'checkbox.svg',
711 + 'cover_fees' => $base . 'checkbox.svg',
712 + 'dropdown' => $base . 'dropdown.svg',
713 + // Donation-amount is a grid of selectable amounts (radio options).
714 + 'donation_amount' => $base . 'multi-choice.svg',
715 + 'address' => $base . 'address.svg',
716 + 'phone' => $base . 'phone.svg',
717 + 'url' => $base . 'url.svg',
718 + 'heading' => $base . 'heading.svg',
719 + 'html' => $base . 'html.svg',
720 + 'image' => $base . 'image.svg',
721 + 'payment' => $base . 'payment.svg',
722 + 'donate_button' => $base . 'button.svg',
723 + // Campaign + donation-form display blocks.
724 + 'donation_form' => $base . 'donation-form.svg',
725 + 'campaign_goal' => $base . 'campaign-goal.svg',
726 + 'campaign_stats' => $base . 'campaign-stats.svg',
727 + 'campaign_donations' => $base . 'campaign-donations.svg',
728 + 'campaign_donors' => $base . 'campaign-donors.svg',
729 + 'campaign_donor_comments' => $base . 'campaign-donor-comments.svg',
730 + 'campaign_social_sharing' => $base . 'campaign-social-sharing.svg',
731 + 'campaign_donate_button' => $base . 'button.svg',
732 + // Fallback for any block without its own image.
733 + 'placeholder' => $base . 'placeholder.svg',
734 + ]
735 + );
736 +
737 + // Coerce defensively: a filter returning a non-array or non-string values
738 + // must not poison the map (mirrors the JS-side guard).
739 + if ( ! is_array( $images ) ) {
740 + $this->preview_images = [];
741 + return $this->preview_images;
742 + }
743 +
744 + $result = [];
745 + foreach ( $images as $key => $value ) {
746 + if ( is_string( $key ) && is_string( $value ) ) {
747 + // esc_url_raw for consistency with get_campaign_blocks_data(); the
748 + // value is consumed by JS as an <img src>, not printed as HTML. The
749 + // plugin version busts the browser cache when redesigned art ships
750 + // in a release (filemtime is avoided: filter-supplied Pro URLs do
751 + // not resolve to a local path).
752 + $result[ $key ] = esc_url_raw( add_query_arg( 'ver', SUREDONATION_VER, $value ) );
753 + }
754 + }
755 +
756 + $this->preview_images = $result;
757 + return $this->preview_images;
584 758 }
585 759
586 760 /**
587 761 * Register all blocks.