PluginProbe
Extendify / 3.1.5
Extendify v3.1.5
3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 0.7.0 All 126 releases
extendify / app / Agent / TagBlocks.php

TagBlocks.php in Extendify 3.1.5, at app/Agent/TagBlocks.php

140 lines 4.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Extendify\Agent;
4
5 defined('ABSPATH') || die('No direct access.');
6
7 class TagBlocks
8 {
9 // Loop blocks render their inner tree once per item; counting children as
10 // separate seqs would produce N DOM ids for one parse_blocks() entry and
11 // break source-walks that resolve clicked ids back to block code.
12 // Public so SaveController + WPController can share the same list.
13 public static $ignored = [
14 'core/query',
15 'core/post-template',
16 'core/post-content',
17 'core/comments',
18 'core/comment-template',
19 'woocommerce/product-collection',
20 'woocommerce/product-template',
21 ];
22
23 public static function init()
24 {
25 \add_filter('the_content', [self::class, 'enterScope'], 0);
26 \add_filter('the_content', [self::class, 'leaveScope'], PHP_INT_MAX);
27
28 \add_filter('pre_render_block', [self::class, 'pre'], 10, 2);
29 \add_filter('render_block', [self::class, 'post'], 10, 2);
30 }
31
32 public static function enterScope($content)
33 {
34 if (is_admin()) {
35 return $content;
36 }
37
38 if (empty($GLOBALS['extendify_agent_scope'])) {
39 $GLOBALS['extendify_agent_scope'] = [
40 'depth' => 0,
41 'frames' => [],
42 ];
43 }
44 $GLOBALS['extendify_agent_scope']['depth']++;
45 // Each scope has: seq, id_stack, pushed_stack, skip_depth
46 $GLOBALS['extendify_agent_scope']['frames'][] = [
47 'seq' => 0,
48 'id_stack' => [],
49 'pushed_stack' => [],
50 'skip_depth' => 0, // >0 while inside an ignored subtree
51 ];
52 return $content;
53 }
54
55 public static function leaveScope($content)
56 {
57 if (is_admin()) {
58 return $content;
59 }
60 $S =& $GLOBALS['extendify_agent_scope'];
61 if (!empty($S['depth'])) {
62 $S['depth']--;
63 array_pop($S['frames']);
64 }
65 return $content;
66 }
67
68 public static function pre($pre, $parsed_block)
69 {
70 if (is_admin() || !is_array($parsed_block) || empty($parsed_block['blockName'])) {
71 return $pre;
72 }
73
74 $S = $GLOBALS['extendify_agent_scope'] ?? null;
75 if (!$S || ($S['depth'] ?? 0) !== 1 || empty($S['frames'])) {
76 return $pre;
77 } // only outer the_content
78
79 $i = count($S['frames']) - 1;
80 $frame = $S['frames'][$i];
81
82 $name = $parsed_block['blockName'];
83
84 // If this block starts an ignored subtree, enter skip mode
85 if (in_array($name, self::$ignored, true)) {
86 $frame['skip_depth']++;
87 $frame['pushed_stack'][] = false; // we didn't assign an id to this block
88 } elseif ($frame['skip_depth'] > 0) {
89 // Already skipping? (we're inside an ignored subtree)
90 $frame['pushed_stack'][] = false; // no id for anything under ignored
91 } else {
92 // Normal counting
93 $frame['seq']++;
94 $id = $frame['seq'];
95 $frame['id_stack'][] = $id;
96 $frame['pushed_stack'][] = true;
97 }
98
99 $GLOBALS['extendify_agent_scope']['frames'][$i] = $frame;
100 return $pre;
101 }
102
103 public static function post($content, $parsed_block)
104 {
105 $S = $GLOBALS['extendify_agent_scope'] ?? null;
106 if (!$S || empty($S['frames'])) {
107 return $content;
108 }
109
110 $i = count($S['frames']) - 1;
111 $frame = $S['frames'][$i];
112
113 $name = is_array($parsed_block) ? ($parsed_block['blockName'] ?? null) : null;
114
115 // Pop pushed flag & optional id (ALWAYS pop to stay balanced)
116 $pushed = !empty($frame['pushed_stack']) ? array_pop($frame['pushed_stack']) : false;
117 $id = ($pushed && !empty($frame['id_stack'])) ? array_pop($frame['id_stack']) : null;
118
119 // Inject only when: outer scope, we counted this block, html present, not admin
120 if (!is_admin() && ($S['depth'] ?? 0) === 1 && $pushed && $id && $content && $name) {
121 $tp = new \WP_HTML_Tag_Processor($content);
122 $value = (string) (int) $id;
123
124 // Move cursor to the first start tag in the fragment
125 if ($tp->next_tag()) {
126 $tp->set_attribute('data-extendify-agent-block-id', $value);
127 $content = $tp->get_updated_html();
128 }
129 }
130
131 // If this block ends an ignored subtree, exit skip mode
132 if ($name && in_array($name, self::$ignored, true) && $frame['skip_depth'] > 0) {
133 $frame['skip_depth']--;
134 }
135
136 $GLOBALS['extendify_agent_scope']['frames'][$i] = $frame;
137 return $content;
138 }
139 }
140