PluginProbe
AI Builder – Generate pages, blocks, images & translate with AI / trunk
AI Builder – Generate pages, blocks, images & translate with AI vtrunk
2.7.10 2.7.9 2.7.8 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.3.10 All 122 releases
ai-builder / includes / class-templates-assets-handler.php

class-templates-assets-handler.php in AI Builder – Generate pages, blocks, images & translate with AI trunk, at includes/class-templates-assets-handler.php

302 lines 9.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) {
4 exit;
5 }
6
7 /**
8 * Injecte le CSS/JS associé aux block templates et template parts utilisés
9 * sur le rendu d'une page côté frontend.
10 *
11 * Les données sont stockées via les AJAX endpoints aibui_save_template_{css,js}
12 * dans les options :
13 * - ai_builder_templates_css
14 * - ai_builder_templates_js
15 * keyées par "wp_template:{theme}//{slug}" ou "wp_template_part:{theme}//{slug}".
16 */
17 class AIBUI_Templates_Assets_Handler
18 {
19 public function __construct()
20 {
21 // Pré-collecter les template parts utilisés dans le template principal
22 // pour pouvoir injecter leur CSS dans <head>.
23 add_action('template_redirect', array($this, 'precompute_active_templates'), 100);
24
25 // Collecter aussi les template parts rencontrés dynamiquement lors du rendu
26 // (filets de sécurité si parse_blocks n'a pas suffi, cas rares).
27 add_filter('render_block', array($this, 'collect_rendered_template_part'), 10, 2);
28
29 add_action('wp_head', array($this, 'output_templates_css'), 999);
30 add_action('wp_footer', array($this, 'output_templates_js'), 999);
31 }
32
33 /**
34 * Renvoie la liste des clés de templates/parts actifs sur la requête courante.
35 *
36 * @return array<int, string>
37 */
38 private function get_active_template_keys()
39 {
40 $keys = array();
41
42 if (!empty($GLOBALS['aibui_active_template_main_id'])) {
43 $keys[] = 'wp_template:' . $GLOBALS['aibui_active_template_main_id'];
44 }
45
46 if (!empty($GLOBALS['aibui_active_template_parts']) && is_array($GLOBALS['aibui_active_template_parts'])) {
47 foreach ($GLOBALS['aibui_active_template_parts'] as $part_id => $_) {
48 $keys[] = 'wp_template_part:' . $part_id;
49 }
50 }
51
52 return array_values(array_unique($keys));
53 }
54
55 /**
56 * Résout l'ID (theme//slug) du block template principal utilisé pour la requête courante.
57 */
58 private function resolve_current_template_id()
59 {
60 if (!wp_is_block_theme()) {
61 return null;
62 }
63
64 if (!empty($GLOBALS['_wp_current_template_id'])) {
65 return (string) $GLOBALS['_wp_current_template_id'];
66 }
67
68 $slug = $this->resolve_template_slug_from_query();
69 if (!$slug) {
70 return null;
71 }
72
73 $theme = get_stylesheet();
74 return $theme . '//' . $slug;
75 }
76
77 /**
78 * Déduit le slug du template à utiliser en se basant sur la WP Query courante.
79 * Ordre approximatif de la hiérarchie des templates block themes.
80 */
81 private function resolve_template_slug_from_query()
82 {
83 if (is_embed()) {
84 return 'embed';
85 }
86 if (is_404()) {
87 return '404';
88 }
89 if (is_search()) {
90 return 'search';
91 }
92 if (is_front_page()) {
93 return 'front-page';
94 }
95 if (is_home()) {
96 return 'home';
97 }
98
99 if (is_singular()) {
100 $obj = get_queried_object();
101 if ($obj && isset($obj->ID)) {
102 $assigned = get_page_template_slug($obj->ID);
103 if ($assigned) {
104 return $assigned;
105 }
106 }
107
108 if (is_page()) {
109 return 'page';
110 }
111 if (is_attachment()) {
112 return 'attachment';
113 }
114 if (is_single()) {
115 return 'single';
116 }
117 return 'singular';
118 }
119
120 if (is_category()) {
121 return 'category';
122 }
123 if (is_tag()) {
124 return 'tag';
125 }
126 if (is_tax()) {
127 return 'taxonomy';
128 }
129 if (is_author()) {
130 return 'author';
131 }
132 if (is_date()) {
133 return 'date';
134 }
135 if (is_archive()) {
136 return 'archive';
137 }
138
139 return 'index';
140 }
141
142 /**
143 * Parcourt récursivement les blocs pour détecter les core/template-part
144 * et enregistrer leurs identifiants dans un global partagé.
145 *
146 * @param array<int, array> $blocks
147 * @param int $depth
148 */
149 private function walk_blocks_for_template_parts($blocks, $depth = 0)
150 {
151 if ($depth > 10 || empty($blocks) || !is_array($blocks)) {
152 return;
153 }
154
155 foreach ($blocks as $block) {
156 if (!is_array($block)) {
157 continue;
158 }
159
160 if (!empty($block['blockName']) && $block['blockName'] === 'core/template-part') {
161 $slug = isset($block['attrs']['slug']) ? (string) $block['attrs']['slug'] : '';
162 if ($slug !== '') {
163 $theme = !empty($block['attrs']['theme'])
164 ? (string) $block['attrs']['theme']
165 : get_stylesheet();
166 $part_id = $theme . '//' . $slug;
167
168 if (empty($GLOBALS['aibui_active_template_parts'][$part_id])) {
169 $GLOBALS['aibui_active_template_parts'][$part_id] = true;
170
171 // Descendre récursivement dans le contenu du template part
172 $part = function_exists('get_block_template')
173 ? get_block_template($part_id, 'wp_template_part')
174 : null;
175 if ($part && !empty($part->content)) {
176 $this->walk_blocks_for_template_parts(
177 parse_blocks($part->content),
178 $depth + 1
179 );
180 }
181 }
182 }
183 }
184
185 if (!empty($block['innerBlocks']) && is_array($block['innerBlocks'])) {
186 $this->walk_blocks_for_template_parts($block['innerBlocks'], $depth + 1);
187 }
188 }
189 }
190
191 public function precompute_active_templates()
192 {
193 if (is_admin() || !wp_is_block_theme()) {
194 return;
195 }
196
197 $template_id = $this->resolve_current_template_id();
198 if (!$template_id) {
199 return;
200 }
201
202 $GLOBALS['aibui_active_template_main_id'] = $template_id;
203 $GLOBALS['aibui_active_template_parts'] = isset($GLOBALS['aibui_active_template_parts'])
204 && is_array($GLOBALS['aibui_active_template_parts'])
205 ? $GLOBALS['aibui_active_template_parts']
206 : array();
207
208 if (!function_exists('get_block_template')) {
209 return;
210 }
211
212 $template = get_block_template($template_id, 'wp_template');
213 if (!$template || empty($template->content)) {
214 return;
215 }
216
217 $this->walk_blocks_for_template_parts(parse_blocks($template->content));
218 }
219
220 /**
221 * Filet de sécurité : détecter les core/template-part rendus dynamiquement
222 * (via render_block) pour compléter la liste précalculée.
223 */
224 public function collect_rendered_template_part($block_content, $block)
225 {
226 if (empty($block['blockName']) || $block['blockName'] !== 'core/template-part') {
227 return $block_content;
228 }
229
230 $slug = isset($block['attrs']['slug']) ? (string) $block['attrs']['slug'] : '';
231 if ($slug === '') {
232 return $block_content;
233 }
234
235 $theme = !empty($block['attrs']['theme'])
236 ? (string) $block['attrs']['theme']
237 : get_stylesheet();
238 $id = $theme . '//' . $slug;
239
240 if (!isset($GLOBALS['aibui_active_template_parts']) || !is_array($GLOBALS['aibui_active_template_parts'])) {
241 $GLOBALS['aibui_active_template_parts'] = array();
242 }
243 $GLOBALS['aibui_active_template_parts'][$id] = true;
244
245 return $block_content;
246 }
247
248 public function output_templates_css()
249 {
250 $keys = $this->get_active_template_keys();
251 if (empty($keys)) {
252 return;
253 }
254
255 $all = get_option('ai_builder_templates_css', array());
256 if (!is_array($all)) {
257 return;
258 }
259
260 $buffer = '';
261 foreach ($keys as $key) {
262 if (!empty($all[$key]['combined'])) {
263 $buffer .= "\n" . $all[$key]['combined'];
264 }
265 }
266
267 if (trim($buffer) === '') {
268 return;
269 }
270
271 echo '<style id="ai-builder-templates-css" type="text/css">' . $buffer . '</style>';
272 }
273
274 public function output_templates_js()
275 {
276 $keys = $this->get_active_template_keys();
277 if (empty($keys)) {
278 return;
279 }
280
281 $all = get_option('ai_builder_templates_js', array());
282 if (!is_array($all)) {
283 return;
284 }
285
286 $buffer = '';
287 foreach ($keys as $key) {
288 if (!empty($all[$key]['combined'])) {
289 $buffer .= "\n" . $all[$key]['combined'];
290 }
291 }
292
293 if (trim($buffer) === '') {
294 return;
295 }
296
297 echo '<script id="ai-builder-templates-js" type="text/javascript">' . $buffer . '</script>';
298 }
299 }
300
301 new AIBUI_Templates_Assets_Handler();
302