PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.4
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.4
1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 trunk 1.2.0 All 47 releases
fluent-cart / app / Services / Renderer / RenderContext.php

RenderContext.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.4, at app/Services/Renderer/RenderContext.php

127 lines 3.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Services\Renderer;
4
5 use FluentCart\Framework\Support\Arr;
6
7 /**
8 * Which surface asked for the current product render.
9 *
10 * RenderGate's `scope` answers "which region of the page" (product_card |
11 * single_product). This answers "which builder is drawing it", so a listener
12 * can gate a region on the shop grid without touching the same region in a
13 * Divi module.
14 *
15 * Gutenberg needs no wiring at all: WordPress already tracks the block being
16 * rendered in WP_Block_Supports::$block_to_render, which is the same signal
17 * RenderHelper::getBlockWrapperAttributes() reads. Shortcodes declare
18 * themselves in the one closure they all register through. Everything else —
19 * Bricks, Divi, page builders we have never heard of — reports `unknown` until
20 * it opts in with a single filter:
21 *
22 * add_filter('fluent_cart/product/render_source', function ($source) {
23 * return bricks_is_rendering()
24 * ? ['source' => 'bricks', 'name' => 'fct-products']
25 * : $source;
26 * });
27 *
28 * An honest `unknown` beats a guess. Nothing here inspects the call stack.
29 */
30 class RenderContext
31 {
32 const SOURCE_GUTENBERG = 'gutenberg';
33 const SOURCE_SHORTCODE = 'shortcode';
34 const SOURCE_BRICKS = 'bricks';
35 const SOURCE_DIVI = 'divi';
36 const SOURCE_UNKNOWN = 'unknown';
37
38 /**
39 * Set only by callers that WordPress gives us no way to detect.
40 *
41 * @var array{source: string, name: string}|null
42 */
43 protected static $declared = null;
44
45 /**
46 * Run $callback with the caller declared, restoring whatever was in force
47 * before — including when the callback throws. A leaked declaration would
48 * mislabel every later render in the request.
49 *
50 * @param string $source
51 * @param string $name
52 * @param callable $callback
53 * @return mixed
54 */
55 public static function declaring($source, $name, callable $callback)
56 {
57 $previous = self::$declared;
58 self::$declared = ['source' => (string) $source, 'name' => (string) $name];
59
60 try {
61 return $callback();
62 } finally {
63 self::$declared = $previous;
64 }
65 }
66
67 /**
68 * @return array{source: string, name: string}
69 */
70 public static function current()
71 {
72 // A declaration wins over block detection: a shortcode rendering inside
73 // a block leaves $block_to_render pointing at the outer block, and the
74 // shortcode is the more useful answer.
75 if (self::$declared !== null) {
76 return self::$declared;
77 }
78
79 $block = \WP_Block_Supports::$block_to_render;
80
81 if (is_array($block) && !empty($block['blockName'])) {
82 return [
83 'source' => self::SOURCE_GUTENBERG,
84 'name' => (string) $block['blockName'],
85 ];
86 }
87
88 $fallback = ['source' => self::SOURCE_UNKNOWN, 'name' => ''];
89 $filtered = apply_filters('fluent_cart/product/render_source', $fallback);
90
91 if (!is_array($filtered) || empty($filtered['source'])) {
92 return $fallback;
93 }
94
95 return [
96 'source' => (string) $filtered['source'],
97 'name' => (string) Arr::get($filtered, 'name', ''),
98 ];
99 }
100
101 /**
102 * Add `source` and `source_name` to a hook payload. Existing keys win.
103 *
104 * @param array $payload
105 * @return array
106 */
107 public static function decorate(array $payload)
108 {
109 $current = self::current();
110
111 return $payload + [
112 'source' => $current['source'],
113 'source_name' => $current['name'],
114 ];
115 }
116
117 /**
118 * Test seam — a declaration left standing would mislabel the next test.
119 *
120 * @return void
121 */
122 public static function reset()
123 {
124 self::$declared = null;
125 }
126 }
127