PluginProbe
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management / 1.0.0
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management v1.0.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
suredonation / inc / blocks / register.php

register.php in SureDonation – Donation Forms, Fundraising Campaigns & Donor Management 1.0.0, at inc/blocks/register.php

414 lines 12.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Blocks Register
4 *
5 * @package SureDonation
6 */
7
8 namespace SureDonation\Inc\Blocks;
9
10 use SureDonation\Inc\Payments\Offline\Offline_Helper;
11 use SureDonation\Inc\Payments\Payment_Helper;
12 use SureDonation\Inc\Payments\Stripe\Stripe_Helper;
13 use SureDonation\Inc\Traits\Get_Instance;
14
15 // Exit if accessed directly.
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit;
18 }
19
20 /**
21 * Register class for blocks.
22 *
23 * @since 0.0.1
24 */
25 class Register {
26 use Get_Instance;
27
28 /**
29 * Constructor.
30 *
31 * @since 0.0.1
32 */
33 public function __construct() {
34 add_action( 'init', [ $this, 'register_embed_block_script' ], 5 );
35 add_action( 'init', [ $this, 'register_blocks' ] );
36 add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_editor_assets' ] );
37 add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_campaign_editor_assets' ] );
38 add_filter( 'block_categories_all', [ $this, 'register_block_category' ], 10, 2 );
39 add_filter( 'block_editor_settings_all', [ $this, 'add_campaign_iframe_styles' ], 10, 2 );
40 }
41
42 /**
43 * Register the donation form embed block editor script.
44 *
45 * Runs before register_blocks() so the handle exists when block.json is read.
46 * Not gated by post type — the embed block should work on all post types.
47 *
48 * @return void
49 * @since 1.0.0
50 */
51 public function register_embed_block_script() {
52 $asset_file = SUREDONATION_DIR . 'assets/build/blocks/donation-form/editor.asset.php';
53 $asset = file_exists( $asset_file )
54 ? require $asset_file
55 : [
56 'dependencies' => [],
57 'version' => SUREDONATION_VER,
58 ];
59
60 wp_register_script(
61 'suredonation-donation-form-editor',
62 SUREDONATION_URL . 'assets/build/blocks/donation-form/editor.js',
63 $asset['dependencies'],
64 $asset['version'],
65 true
66 );
67
68 // Data for the block editor placeholder (logo). The campaign blocks
69 // bundle defines the same global elsewhere; localizing it here keeps the
70 // logo available wherever the donation form block is inserted.
71 wp_localize_script(
72 'suredonation-donation-form-editor',
73 'suredonationCampaignBlocks',
74 $this->get_campaign_blocks_data()
75 );
76
77 wp_register_style(
78 'suredonation-donation-form-editor',
79 SUREDONATION_URL . 'assets/build/blocks/donation-form/editor.css',
80 [],
81 $asset['version']
82 );
83 }
84
85 /**
86 * Data localized for the block editor placeholders (logo).
87 *
88 * Shared by the donation form embed block and the campaign display blocks,
89 * both of which expose it on the `suredonationCampaignBlocks` JS global.
90 *
91 * @return array<string, string>
92 * @since 1.0.0
93 */
94 public function get_campaign_blocks_data() {
95 return [
96 'logoUrl' => esc_url_raw( SUREDONATION_URL . 'images/suredonation-logo.svg' ),
97 ];
98 }
99
100 /**
101 * Register custom block category for SureDonation blocks.
102 *
103 * The field-block category is limited to the donation form editor; the
104 * campaign display-block category is registered everywhere else.
105 *
106 * @param array<int, array<string, mixed>> $categories Existing block categories.
107 * @param \WP_Block_Editor_Context $context Block editor context.
108 * @return array<int, array<string, mixed>> Modified block categories.
109 * @since 0.0.1
110 */
111 public function register_block_category( $categories, $context ) {
112 // Field-block category on the donation form editor.
113 if ( isset( $context->post ) && 'suredonation_form' === $context->post->post_type ) {
114 return array_merge(
115 [
116 [
117 'slug' => 'suredonation',
118 'title' => __( 'General Fields', 'suredonation' ),
119 'icon' => null,
120 ],
121 ],
122 $categories
123 );
124 }
125
126 // Campaign display-block category on every other editor — including the
127 // Site Editor and widget contexts where $context->post is unset — so the
128 // campaign blocks always group under SureDonation in the inserter. Only
129 // the donation form editor (handled above) is excluded.
130 return array_merge(
131 [
132 [
133 'slug' => 'suredonation-campaign',
134 'title' => __( 'SureDonation', 'suredonation' ),
135 'icon' => null,
136 ],
137 ],
138 $categories
139 );
140 }
141
142 /**
143 * Enqueue the campaign display blocks editor bundle.
144 *
145 * Loads on every block editor so the campaign blocks can be added to any
146 * page/post/CPT — except the donation form editor, which has its own field
147 * blocks. On a campaign post the blocks auto-bind to that campaign; elsewhere
148 * the block inspector exposes a campaign selector.
149 *
150 * @return void
151 * @since 1.0.0
152 */
153 public function enqueue_campaign_editor_assets() {
154 $screen = get_current_screen();
155
156 // Load everywhere except the donation form editor.
157 if ( ! $screen || 'suredonation_form' === $screen->post_type ) {
158 return;
159 }
160
161 $asset_file = SUREDONATION_DIR . 'assets/build/campaign-blocks.asset.php';
162 $asset = file_exists( $asset_file )
163 ? require $asset_file
164 : [
165 'dependencies' => [ 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n', 'wp-block-editor', 'wp-data', 'wp-server-side-render' ],
166 'version' => SUREDONATION_VER,
167 ];
168
169 wp_enqueue_script(
170 'suredonation-campaign-blocks',
171 SUREDONATION_URL . 'assets/build/campaign-blocks.js',
172 $asset['dependencies'],
173 $asset['version'],
174 true
175 );
176
177 wp_set_script_translations( 'suredonation-campaign-blocks', 'suredonation' );
178
179 // Data for the campaign block editor placeholder (logo).
180 wp_localize_script(
181 'suredonation-campaign-blocks',
182 'suredonationCampaignBlocks',
183 $this->get_campaign_blocks_data()
184 );
185
186 // Style the server-side-rendered block previews in the editor.
187 $style_file = SUREDONATION_DIR . 'assets/build/blocks/campaign/style-style.css';
188 $style_version = file_exists( $style_file )
189 ? (string) filemtime( $style_file )
190 : SUREDONATION_VER;
191
192 wp_enqueue_style(
193 'suredonation-campaign-blocks',
194 SUREDONATION_URL . 'assets/build/blocks/campaign/style-style.css',
195 [],
196 $style_version
197 );
198 }
199
200 /**
201 * Inject the campaign block styles into the editor canvas iframe.
202 *
203 * Styles enqueued via enqueue_block_editor_assets load in the editor's outer
204 * frame only; the block canvas is iframed, so the server-side-rendered campaign
205 * block previews would otherwise render unstyled. Adding the CSS to the editor
206 * settings makes WordPress inject it inside the iframe, matching the frontend.
207 *
208 * @param array<string, mixed> $settings Block editor settings.
209 * @param \WP_Block_Editor_Context $context Block editor context.
210 * @return array<string, mixed> Modified settings.
211 * @since 1.0.0
212 */
213 public function add_campaign_iframe_styles( $settings, $context ) {
214 // Inject wherever the campaign blocks can be used (everywhere except the
215 // donation form editor), so their editor previews match the frontend.
216 if ( ! isset( $context->post ) || 'suredonation_form' === $context->post->post_type ) {
217 return $settings;
218 }
219
220 $css = $this->get_campaign_iframe_css();
221 if ( '' === $css ) {
222 return $settings;
223 }
224
225 if ( ! isset( $settings['styles'] ) || ! is_array( $settings['styles'] ) ) {
226 $settings['styles'] = [];
227 }
228
229 $settings['styles'][] = [ 'css' => $css ];
230
231 return $settings;
232 }
233
234 /**
235 * Read the built campaign stylesheet, cached per request by file mtime so
236 * the filter (which can run more than once per load) reads from disk at most
237 * once until the asset changes.
238 *
239 * @return string The stylesheet contents, or '' when unavailable.
240 * @since 1.0.0
241 */
242 private function get_campaign_iframe_css() {
243 static $cached_css = null;
244 static $cached_mtime = null;
245
246 $style_file = SUREDONATION_DIR . 'assets/build/blocks/campaign/style-style.css';
247 if ( ! file_exists( $style_file ) ) {
248 return '';
249 }
250
251 $mtime = filemtime( $style_file );
252 if ( null === $cached_css || $cached_mtime !== $mtime ) {
253 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Reading the plugin's own built stylesheet to inline into the editor iframe.
254 $css = file_get_contents( $style_file );
255 $cached_css = false === $css ? '' : $css;
256 $cached_mtime = $mtime;
257 }
258
259 return $cached_css;
260 }
261
262 /**
263 * Enqueue block editor assets.
264 *
265 * Only loads on the donation form editor.
266 *
267 * @return void
268 * @since 0.0.1
269 */
270 public function enqueue_editor_assets() {
271 $screen = get_current_screen();
272
273 // Only load on donation form editor.
274 if ( ! $screen || 'suredonation_form' !== $screen->post_type ) {
275 return;
276 }
277
278 // Use the asset.php content hash as the version so rebuilds bust the
279 // browser cache. Falls back to SUREDONATION_VER if the asset file
280 // is missing.
281 $blocks_asset_file = SUREDONATION_DIR . 'assets/build/blocks.asset.php';
282 $blocks_asset = file_exists( $blocks_asset_file )
283 ? require $blocks_asset_file
284 : [
285 'dependencies' => [ 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n', 'wp-block-editor', 'wp-data' ],
286 'version' => SUREDONATION_VER,
287 ];
288
289 // Enqueue the blocks script.
290 wp_enqueue_script(
291 'suredonation-blocks',
292 SUREDONATION_URL . 'assets/build/blocks.js',
293 $blocks_asset['dependencies'],
294 $blocks_asset['version'],
295 true
296 );
297
298 // Load JS translations for blocks.
299 wp_set_script_translations( 'suredonation-blocks', 'suredonation' );
300
301 // Localize script with admin data for blocks.
302 $global_currency = Payment_Helper::get_currency();
303
304 wp_localize_script(
305 'suredonation-blocks',
306 'suredonation_admin',
307 [
308 'payments' => [
309 'stripe_connected' => Stripe_Helper::is_stripe_connected(),
310 'stripe_connect_url' => Stripe_Helper::get_stripe_connect_url(),
311 'offline_enabled' => Offline_Helper::is_offline_enabled(),
312 'gateways' => apply_filters(
313 'suredonation_editor_payment_gateways',
314 [
315 [
316 'value' => 'stripe',
317 'label' => __( 'Stripe', 'suredonation' ),
318 'supports_recurring' => true,
319 ],
320 [
321 'value' => 'offline',
322 'label' => __( 'Offline Donations', 'suredonation' ),
323 'supports_recurring' => false,
324 ],
325 ]
326 ),
327 ],
328 'fee_recovery' => Payment_Helper::get_fee_recovery_settings(),
329 'currency' => $global_currency,
330 'currencySymbol' => Payment_Helper::get_currency_symbol( $global_currency ),
331 ]
332 );
333 }
334
335 /**
336 * Register all blocks.
337 *
338 * @return void
339 * @since 0.0.1
340 */
341 public function register_blocks() {
342 $blocks = [
343 [
344 'dir' => SUREDONATION_DIR . 'inc/blocks/**/*.php',
345 'namespace' => 'SureDonation\\Inc\\Blocks',
346 ],
347 ];
348
349 /**
350 * Filter to add and register additional blocks.
351 *
352 * @param array<int, array<string, string>> $additional_blocks Additional blocks to register.
353 */
354 $additional_blocks = apply_filters( 'suredonation_register_additional_blocks', [] );
355
356 if ( ! empty( $additional_blocks ) && is_array( $additional_blocks ) && count( $additional_blocks ) > 0 ) {
357 $blocks = [ ...$blocks, ...$additional_blocks ];
358 }
359
360 foreach ( $blocks as $block ) {
361 if ( ! is_array( $block ) || ! isset( $block['dir'] ) || ! isset( $block['namespace'] ) ) {
362 continue;
363 }
364 $block_files = glob( $block['dir'] );
365 if ( is_array( $block_files ) ) {
366 $this->register_block( $block_files, $block['namespace'], 'Block' );
367 }
368 }
369 }
370
371 /**
372 * Register blocks from directory.
373 *
374 * @param array<int, string> $blocks_dir Array of block file paths.
375 * @param string $block_namespace Block namespace.
376 * @param string $base Base class name.
377 * @return void
378 * @since 0.0.1
379 */
380 public function register_block( $blocks_dir, $block_namespace, $base ) {
381 if ( empty( $blocks_dir ) ) {
382 return;
383 }
384
385 foreach ( $blocks_dir as $filename ) {
386 // Skip base.php and register.php.
387 $basename = basename( $filename );
388 if ( 'base.php' === $basename || 'register.php' === $basename ) {
389 continue;
390 }
391
392 require_once $filename;
393
394 // Replace hyphens with underscores in directory name.
395 $classname = str_replace( '-', '_', basename( dirname( $filename ) ) );
396
397 // Convert to title case.
398 $classname = ucwords( $classname, '_' );
399
400 $full_class_name = $block_namespace . '\\' . $classname . '\\' . $base;
401
402 // Check if the class exists.
403 if ( class_exists( $full_class_name ) ) {
404 $block = new $full_class_name();
405
406 // Call register on the block object.
407 if ( method_exists( $block, 'register' ) ) {
408 $block->register();
409 }
410 }
411 }
412 }
413 }
414