PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.17.0
GiveWP – Donation Plugin and Fundraising Platform v4.17.0
4.17.0 4.16.9 4.16.8.1 4.16.8 4.16.7.2 4.16.7.1 4.16.7 4.16.6.1 4.16.6 4.16.5.1 4.16.5 4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 All 256 releases
← All changes | src/DonationForms/ViewModels/DonationFormViewModel.php +59 -4 4.15.1 → 4.17.0 View file →
@@ -6,9 +6,13 @@
6 6 use Give\Campaigns\ValueObjects\CampaignGoalType;
7 7 use Give\DonationForms\Actions\GenerateAuthUrl;
8 8 use Give\DonationForms\Actions\GenerateDonateRouteUrl;
9 9 use Give\DonationForms\Actions\GenerateDonationFormValidationRouteUrl;
10 +use Give\DonationForms\Actions\GetFormSkeletonData;
11 +use Give\DonationForms\Actions\IsolateEnqueuedFormViewAssets;
12 +use Give\DonationForms\Actions\RenderFormSkeleton;
10 13 use Give\DonationForms\DataTransferObjects\DonationFormGoalData;
14 +use Give\DonationForms\Models\DonationForm;
11 15 use Give\DonationForms\Properties\FormSettings;
12 16 use Give\DonationForms\Repositories\DonationFormRepository;
13 17 use Give\DonationForms\ValueObjects\GoalType;
14 18 use Give\Framework\Blocks\BlockCollection;
@@ -46,9 +50,18 @@
46 50 /**
47 51 * @var bool
48 52 */
49 53 private $previewMode;
54 +
50 55 /**
56 + * The skeleton markup for this render, or empty when there is none to show.
57 + *
58 + * @since 4.17.0
59 + *
60 + * @var string
61 + */
62 + private $skeleton = '';
63 + /**
51 64 * @since 4.1.0
52 65 */
53 66 private DonationFormGoalData $donationFormGoalData;
54 67
@@ -144,8 +157,15 @@
144 157 wp_strip_all_tags(give_get_option('custom_form_styles', ''))
145 158 );
146 159
147 160 wp_enqueue_style('givewp-base-form-styles');
161 +
162 + // The skeleton prints in the body before the app bundles load, so its styles go in the head with the rest.
163 + if ($this->skeleton) {
164 + wp_register_style('givewp-form-skeleton-styles', false);
165 + wp_add_inline_style('givewp-form-skeleton-styles', (new RenderFormSkeleton())->css());
166 + wp_enqueue_style('givewp-form-skeleton-styles');
167 + }
148 168 }
149 169
150 170 /**
151 171 * @since 3.0.0
@@ -274,19 +294,24 @@
274 294 ];
275 295 }
276 296
277 297 /**
298 + * @since 4.17.0 print the form's skeleton inside the root and announce the shell to the embedding page.
278 299 * This is the order of loading:
279 300 * 1. Enqueue global styles from WP.
280 301 * - This ensures template compatability with global WP css variables as needed. Loads before our templates, so they can use things like global font-family, etc.
281 302 * 2. Enqueue our donation form specific scripts & styles.
282 303 * - We will let WP handle the actual printing depending on how they were enqueued.
283 - * 3. Call the specific WP functions wp_print_styles() and wp_print_head_scripts()
304 + * 3. Pin the script and style queues to what we enqueued.
305 + * - The print functions below fire actions that other plugins enqueue from, so the queues
306 + * have to be constrained before printing rather than trusted.
307 + * 4. Call the specific WP functions wp_print_styles() and wp_print_head_scripts()
284 308 * - This will only print the styles and scripts that are enqueued within our route - so we don't have to dequeue a bunch of stuff.
285 - * 4. Manually echo our window data and root div for our React app to consume
286 - * 5. Finally, call the specific WP function wp_print_footer_scripts()
309 + * 5. Manually echo our window data and root div for our React app to consume
310 + * 6. Finally, call the specific WP function wp_print_footer_scripts()
287 311 * - This will only print the footer scripts that are enqueued within our route.
288 312 *
313 + * @since 4.16.7 Isolate the printed assets from anything enqueued after the form has been prepared
289 314 * @since 4.14.3 Escape HTML attributes for classNames property
290 315 * @since 3.20.0 Adds class for form design
291 316 * @since 3.11.0 Sanitize customCSS property
292 317 * @since 3.0.0
@@ -292,8 +317,10 @@
292 317 * @since 3.0.0
293 318 */
294 319 public function render(): string
295 320 {
321 + $this->skeleton = $this->previewMode ? '' : $this->renderSkeleton();
322 +
296 323 $this->enqueueGlobalStyles();
297 324
298 325 $this->enqueueFormScripts(
299 326 $this->donationFormId,
@@ -299,8 +326,10 @@
299 326 $this->donationFormId,
300 327 $this->designId()
301 328 );
302 329
330 + (new IsolateEnqueuedFormViewAssets())();
331 +
303 332 ob_start();
304 333 wp_print_styles();
305 334 wp_print_head_scripts();
306 335 ?>
@@ -321,10 +350,14 @@
321 350 ?>
322 351
323 352 <div data-theme="light" id="root-givewp-donation-form"
324 353 data-iframe-height
325 - class="<?= esc_attr(implode(' ', $classNames)) ?>"></div>
354 + class="<?= esc_attr(implode(' ', $classNames)) ?>"><?= $this->skeleton ?></div>
326 355
356 + <?php if ($this->skeleton): ?>
357 + <script>parent.postMessage({type: 'givewp-embed-shell', height: document.documentElement.scrollHeight}, '*');</script>
358 + <?php endif; ?>
359 +
327 360 <?php
328 361 wp_print_footer_scripts();
329 362
330 363 echo ob_get_clean();
@@ -329,8 +362,30 @@
329 362
330 363 echo ob_get_clean();
331 364
332 365 exit();
366 + }
367 +
368 + /**
369 + * The skeleton RenderFormSkeleton draws, printed inside the root so the iframe shows the form's
370 + * shape as soon as its HTML and head styles arrive, before the app bundles load. createRoot()
371 + * replaces it with the form. The inline script that follows the root tells the embedding page
372 + * the shell has painted and how tall it is; the payload is that height and nothing else, so it
373 + * is addressed to any origin and the embed authenticates the message by its origin and source
374 + * instead. Both are skipped for an unknown design, where there is nothing to show, and in the
375 + * builder preview.
376 + *
377 + * @since 4.17.0
378 + */
379 + private function renderSkeleton(): string
380 + {
381 + $form = DonationForm::find($this->donationFormId);
382 +
383 + if (!$form) {
384 + return '';
385 + }
386 +
387 + return (new RenderFormSkeleton())((new GetFormSkeletonData())($form));
333 388 }
334 389
335 390 /**
336 391 * Loads scripts in order: [Registrars, Designs, Gateways, Block]