PluginProbe
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management / 1.1.0
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management v1.1.0
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 +32 -268 1.4.0 → 1.1.0 View file →
@@ -6,15 +6,11 @@
6 6 */
7 7
8 8 namespace SureDonation\Inc\Blocks;
9 9
10 -use SureDonation\Inc\Assets\Register as Assets_Register;
11 -use SureDonation\Inc\Helper;
12 10 use SureDonation\Inc\Payments\Offline\Offline_Helper;
13 -use SureDonation\Inc\Payments\PayPal\PayPal_Helper;
14 11 use SureDonation\Inc\Payments\Payment_Helper;
15 12 use SureDonation\Inc\Payments\Stripe\Stripe_Helper;
16 -use SureDonation\Inc\Post_Types\Donation_Form;
17 13 use SureDonation\Inc\Traits\Get_Instance;
18 14
19 15 // Exit if accessed directly.
20 16 if ( ! defined( 'ABSPATH' ) ) {
@@ -40,125 +36,11 @@
40 36 add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_editor_assets' ] );
41 37 add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_campaign_editor_assets' ] );
42 38 add_filter( 'block_categories_all', [ $this, 'register_block_category' ], 10, 2 );
43 39 add_filter( 'block_editor_settings_all', [ $this, 'add_campaign_iframe_styles' ], 10, 2 );
44 - add_filter( 'block_editor_settings_all', [ $this, 'add_donation_form_iframe_styles' ], 10, 2 );
45 - add_filter( 'block_editor_settings_all', [ $this, 'add_phone_iframe_styles' ], 10, 2 );
46 - add_action( 'enqueue_block_assets', [ $this, 'enqueue_preview_field_scripts' ] );
47 40 }
48 41
49 42 /**
50 - * Load the dropdown and phone field libraries into the block editor canvas.
51 - *
52 - * The donation form embed block previews the real form through the block's PHP
53 - * render_callback (ServerSideRender), which returns markup only — a REST render
54 - * emits no wp_footer(), so nothing the render callback enqueues ever reaches the
55 - * page. Without their libraries the dropdown stays an unstyled native <select>
56 - * and the phone field renders with no country flag or dial code.
57 - *
58 - * `enqueue_block_assets` is the hook WordPress replays when it collects assets
59 - * for the iframed canvas: _wp_get_iframed_editor_assets() fires it and returns
60 - * both the printed styles AND scripts, which the canvas injects into its own
61 - * document. It is explicitly the hook for front-end assets that need to run
62 - * against editor content.
63 - *
64 - * Only the two field libraries are loaded. The payment gateways are excluded on
65 - * purpose: mounting Stripe Elements or the PayPal SDK would pull third-party
66 - * scripts into wp-admin on every editor load and open live gateway connections
67 - * for a preview the author cannot interact with. Those keep their static
68 - * placeholders (see _editor-preview.scss).
69 - *
70 - * Both initialisers are safe here — each is ready-state aware, guards against
71 - * double-initialising via a dataset flag, and exposes a re-init hook the editor
72 - * calls once ServerSideRender has injected the markup (see the block's edit
73 - * component).
74 - *
75 - * @return void
76 - * @since 1.4.0
77 - */
78 - public function enqueue_preview_field_scripts() {
79 - // Front end already enqueues these per-block from the field render; this is
80 - // the editor-only path.
81 - if ( ! is_admin() ) {
82 - return;
83 - }
84 -
85 - // The form builder mounts its own React controls for these fields.
86 - $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
87 - if ( $screen && 'suredonation_form' === $screen->post_type ) {
88 - return;
89 - }
90 -
91 - // The handles are registered on wp_enqueue_scripts, which never fires in
92 - // admin. Registration is side-effect free (wp_register_* only), so reuse it
93 - // rather than duplicating the definitions.
94 - Assets_Register::get_instance()->register_frontend_assets();
95 -
96 - // Each script handle already depends on its vendor library, so enqueuing the
97 - // initialiser pulls the library in, in the right order.
98 - wp_enqueue_style( 'suredonation-tom-select' );
99 - wp_enqueue_script( 'suredonation-dropdown' );
100 - wp_enqueue_style( 'suredonation-intl-tel-input' );
101 - wp_enqueue_script( 'suredonation-phone' );
102 -
103 - // The payment bundle mounts Stripe Elements and the PayPal buttons. Both are
104 - // client-only on mount: Stripe's elements()/mount() builds an iframe, and
105 - // PayPal's createOrder does not run until the button is clicked, so nothing
106 - // here reaches the server or creates a PaymentIntent.
107 - wp_enqueue_script( 'suredonation-form-frontend' );
108 -
109 - $this->enqueue_preview_gateway_assets();
110 - }
111 -
112 - /**
113 - * Enqueue gateway assets for each donation form embedded in the current post.
114 - *
115 - * The PayPal SDK is enqueued by gateway code hooked to
116 - * `suredonation_enqueue_form_frontend_scripts`, which the render callback fires
117 - * with the form's id and content — that hook is how a gateway decides whether it
118 - * is even used by the form. A REST render throws the enqueue away, so fire it
119 - * here instead, for the forms this post actually embeds.
120 - *
121 - * Resolving the forms (rather than loading every gateway unconditionally) keeps
122 - * the gateway's own `form_has_paypal()` style gating intact, so a post with no
123 - * PayPal-enabled form does not pull the SDK into wp-admin.
124 - *
125 - * Also localises the payment settings the bundle reads, per form.
126 - *
127 - * @return void
128 - * @since 1.4.0
129 - */
130 - private function enqueue_preview_gateway_assets() {
131 - $post = get_post();
132 -
133 - if ( ! $post instanceof \WP_Post || ! has_block( 'suredonation/donation-form', $post ) ) {
134 - return;
135 - }
136 -
137 - foreach ( parse_blocks( $post->post_content ) as $block ) {
138 - if ( 'suredonation/donation-form' !== ( $block['blockName'] ?? '' ) ) {
139 - continue;
140 - }
141 -
142 - $form_id = absint( $block['attrs']['formId'] ?? 0 );
143 - $form = $form_id ? get_post( $form_id ) : null;
144 -
145 - if ( ! $form instanceof \WP_Post || Donation_Form::POST_TYPE !== $form->post_type ) {
146 - continue;
147 - }
148 -
149 - /** This action is documented in inc/blocks/donation-form/block.php */
150 - do_action( 'suredonation_enqueue_form_frontend_scripts', $form_id, $form->post_content );
151 -
152 - wp_localize_script(
153 - 'suredonation-form-frontend',
154 - 'suredonationPayment',
155 - Helper::get_form_payment_settings( $form_id )
156 - );
157 - }
158 - }
159 -
160 - /**
161 43 * Register the donation form embed block editor script.
162 44 *
163 45 * Runs before register_blocks() so the handle exists when block.json is read.
164 46 * Not gated by post type — the embed block should work on all post types.
@@ -326,77 +208,15 @@
326 208 );
327 209 }
328 210
329 211 /**
330 - * Append an inline stylesheet to the block-editor iframe settings.
212 + * Inject the campaign block styles into the editor canvas iframe.
331 213 *
332 214 * Styles enqueued via enqueue_block_editor_assets load in the editor's outer
333 - * frame only; the block canvas is iframed, so server-side-rendered previews
334 - * would otherwise render unstyled. Adding CSS here makes WordPress inject it
335 - * inside the iframe, matching the frontend.
215 + * frame only; the block canvas is iframed, so the server-side-rendered campaign
216 + * block previews would otherwise render unstyled. Adding the CSS to the editor
217 + * settings makes WordPress inject it inside the iframe, matching the frontend.
336 218 *
337 - * @param array<string, mixed> $settings Block editor settings (by reference).
338 - * @param string $css Stylesheet contents to inline.
339 - * @return void
340 - * @since 1.4.0
341 - */
342 - private function append_iframe_style( &$settings, $css ) {
343 - if ( '' === $css ) {
344 - return;
345 - }
346 -
347 - if ( ! isset( $settings['styles'] ) || ! is_array( $settings['styles'] ) ) {
348 - $settings['styles'] = [];
349 - }
350 -
351 - $settings['styles'][] = [ 'css' => $css ];
352 - }
353 -
354 - /**
355 - * Read a stylesheet for iframe inlining, cached per request by file mtime so
356 - * the filter (which can run more than once per load) reads each file from disk
357 - * at most once until it changes.
358 - *
359 - * @param string $style_file Absolute path to the stylesheet.
360 - * @param array<string, string> $replacements Optional search => replace pairs
361 - * applied to the CSS, e.g. to rewrite
362 - * relative asset URLs to absolute
363 - * plugin URLs so they resolve inside
364 - * the iframe.
365 - * @return string The stylesheet contents, or '' when unavailable.
366 - * @since 1.4.0
367 - */
368 - private function read_iframe_css( $style_file, $replacements = [] ) {
369 - // Keyed by path so the aggregate + vendor stylesheets do not evict each
370 - // other's cache entry.
371 - static $cache = [];
372 -
373 - if ( ! file_exists( $style_file ) ) {
374 - return '';
375 - }
376 -
377 - $mtime = filemtime( $style_file );
378 - if ( ! isset( $cache[ $style_file ] ) || $cache[ $style_file ]['mtime'] !== $mtime ) {
379 - // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Reading the plugin's own/vendored stylesheet to inline into the editor iframe.
380 - $css = file_get_contents( $style_file );
381 - $css = false === $css ? '' : $css;
382 -
383 - if ( '' !== $css && ! empty( $replacements ) ) {
384 - $css = str_replace( array_keys( $replacements ), array_values( $replacements ), $css );
385 - }
386 -
387 - $cache[ $style_file ] = [
388 - 'mtime' => $mtime,
389 - 'css' => $css,
390 - ];
391 - }
392 -
393 - return $cache[ $style_file ]['css'];
394 - }
395 -
396 - /**
397 - * Inject the campaign block styles into the editor canvas iframe.
398 - *
399 219 * @param array<string, mixed> $settings Block editor settings.
400 220 * @param \WP_Block_Editor_Context $context Block editor context.
401 221 * @return array<string, mixed> Modified settings.
402 222 * @since 1.0.0
@@ -407,101 +227,48 @@
407 227 if ( ! isset( $context->post ) || 'suredonation_form' === $context->post->post_type ) {
408 228 return $settings;
409 229 }
410 230
411 - $this->append_iframe_style(
412 - $settings,
413 - $this->read_iframe_css( SUREDONATION_DIR . 'assets/build/blocks/campaign/style-style.css' )
414 - );
231 + $css = $this->get_campaign_iframe_css();
232 + if ( '' === $css ) {
233 + return $settings;
234 + }
415 235
416 - return $settings;
417 - }
418 -
419 - /**
420 - * Inject the donation form styles into the editor canvas iframe.
421 - *
422 - * The donation form embed block previews the real form via ServerSideRender,
423 - * and the canvas is iframed, so styles enqueued on the outer frame never reach
424 - * it. Three stylesheets are inlined:
425 - *
426 - * - the aggregate donation-form CSS, which also carries every field block's
427 - * styles and the editor-preview reconciliation (see _editor-preview.scss);
428 - * - the tom-select vendor CSS, which paints both the dropdown field's
429 - * server-rendered `.ts-wrapper` placeholder and the real control tom-select
430 - * mounts over it; and
431 - * - the intl-tel-input vendor CSS, for the `.iti` wrapper that library builds
432 - * around the phone input. Its flag sprites are referenced relative to the
433 - * stylesheet, so those paths are rewritten to absolute plugin URLs — inlining
434 - * drops the base they resolve against.
435 - *
436 - * Both libraries genuinely run in the canvas: they are enqueued on
437 - * enqueue_block_assets (see enqueue_preview_field_scripts) and re-initialised by
438 - * the block's edit component once ServerSideRender has injected the markup. The
439 - * payment gateways are not, so their placeholders stay static.
440 - *
441 - * @param array<string, mixed> $settings Block editor settings.
442 - * @param \WP_Block_Editor_Context $context Block editor context.
443 - * @return array<string, mixed> Modified settings.
444 - * @since 1.4.0
445 - */
446 - public function add_donation_form_iframe_styles( $settings, $context ) {
447 - // Inject wherever the embed block can be used, including the Site Editor and
448 - // widget contexts where $context->post is unset. Only the donation form
449 - // builder is excluded; it styles its own field blocks separately (see
450 - // add_phone_iframe_styles + form-editor).
451 - if ( isset( $context->post ) && 'suredonation_form' === $context->post->post_type ) {
452 - return $settings;
236 + if ( ! isset( $settings['styles'] ) || ! is_array( $settings['styles'] ) ) {
237 + $settings['styles'] = [];
453 238 }
454 239
455 - $this->append_iframe_style(
456 - $settings,
457 - $this->read_iframe_css( SUREDONATION_DIR . 'assets/build/blocks/donation-form/style-style.css' )
458 - );
459 - $this->append_iframe_style(
460 - $settings,
461 - $this->read_iframe_css( SUREDONATION_DIR . 'assets/css/vendor/tom-select.css' )
462 - );
463 - $this->append_iframe_style(
464 - $settings,
465 - $this->read_iframe_css(
466 - SUREDONATION_DIR . 'assets/css/vendor/intl/intlTelInput.min.css',
467 - [ '../intl/img/' => SUREDONATION_URL . 'assets/css/vendor/intl/img/' ]
468 - )
469 - );
240 + $settings['styles'][] = [ 'css' => $css ];
470 241
471 242 return $settings;
472 243 }
473 244
474 245 /**
475 - * Inject the intl-tel-input stylesheet into the editor canvas iframe.
246 + * Read the built campaign stylesheet, cached per request by file mtime so
247 + * the filter (which can run more than once per load) reads from disk at most
248 + * once until the asset changes.
476 249 *
477 - * The phone block renders the real intl-tel-input control in the form builder
478 - * editor so its preview (flag + dial code) matches the front end. The canvas
479 - * is iframed, so the library CSS is added to the editor settings rather than
480 - * enqueued on the outer frame. Gated to the donation form editor, where the
481 - * phone block lives. (The relative flag sprite paths are rewritten to absolute
482 - * plugin URLs so they resolve inside the iframe.)
483 - *
484 - * @param array<string, mixed> $settings Block editor settings.
485 - * @param \WP_Block_Editor_Context $context Block editor context.
486 - * @return array<string, mixed> Modified settings.
487 - * @since 1.1.1
250 + * @return string The stylesheet contents, or '' when unavailable.
251 + * @since 1.0.0
488 252 */
489 - public function add_phone_iframe_styles( $settings, $context ) {
490 - // Only the donation form editor uses the field blocks (incl. phone).
491 - if ( ! isset( $context->post ) || 'suredonation_form' !== $context->post->post_type ) {
492 - return $settings;
253 + private function get_campaign_iframe_css() {
254 + static $cached_css = null;
255 + static $cached_mtime = null;
256 +
257 + $style_file = SUREDONATION_DIR . 'assets/build/blocks/campaign/style-style.css';
258 + if ( ! file_exists( $style_file ) ) {
259 + return '';
493 260 }
494 261
495 - $this->append_iframe_style(
496 - $settings,
497 - $this->read_iframe_css(
498 - SUREDONATION_DIR . 'assets/css/vendor/intl/intlTelInput.min.css',
499 - [ '../intl/img/' => SUREDONATION_URL . 'assets/css/vendor/intl/img/' ]
500 - )
501 - );
262 + $mtime = filemtime( $style_file );
263 + if ( null === $cached_css || $cached_mtime !== $mtime ) {
264 + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Reading the plugin's own built stylesheet to inline into the editor iframe.
265 + $css = file_get_contents( $style_file );
266 + $cached_css = false === $css ? '' : $css;
267 + $cached_mtime = $mtime;
268 + }
502 269
503 - return $settings;
270 + return $cached_css;
504 271 }
505 272
506 273 /**
507 274 * Enqueue block editor assets.
@@ -550,13 +317,10 @@
550 317 'suredonation_admin',
551 318 [
552 319 'payments' => [
553 320 'stripe_connected' => Stripe_Helper::is_stripe_connected(),
554 - 'paypal_connected' => PayPal_Helper::is_paypal_connected(),
555 321 'stripe_connect_url' => Stripe_Helper::get_stripe_connect_url(),
556 - // Base payments-settings URL; the editor's "Configure Payment
557 - // Account" CTA appends the block's selected gateway subpage.
558 - 'settings_url' => Payment_Helper::get_settings_url(),
322 + 'settings_url' => admin_url( 'admin.php?page=suredonation#/settings?tab=payments' ),
559 323 'offline_enabled' => Offline_Helper::is_offline_enabled(),
560 324 'gateways' => apply_filters(
561 325 'suredonation_editor_payment_gateways',
562 326 [