# ai-builder/2.7.8/includes/class-templates-assets-handler.php

AI Builder – Generate pages, blocks, images &amp; translate with AI, version 2.7.8. 302 lines.

- Page: https://pluginprobe.com/plugins/ai-builder/2.7.8/code/includes/class-templates-assets-handler.php
- Raw: https://pluginprobe.com/plugins/ai-builder/2.7.8/raw/includes/class-templates-assets-handler.php
- Modified: 2026-09-08T10:53:48+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/ai-builder/2.7.8/code/includes/class-templates-assets-handler.php#L10-L20`.

```php
<?php

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Injecte le CSS/JS associé aux block templates et template parts utilisés
 * sur le rendu d'une page côté frontend.
 *
 * Les données sont stockées via les AJAX endpoints aibui_save_template_{css,js}
 * dans les options :
 *   - ai_builder_templates_css
 *   - ai_builder_templates_js
 * keyées par "wp_template:{theme}//{slug}" ou "wp_template_part:{theme}//{slug}".
 */
class AIBUI_Templates_Assets_Handler
{
    public function __construct()
    {
        // Pré-collecter les template parts utilisés dans le template principal
        // pour pouvoir injecter leur CSS dans <head>.
        add_action('template_redirect', array($this, 'precompute_active_templates'), 100);

        // Collecter aussi les template parts rencontrés dynamiquement lors du rendu
        // (filets de sécurité si parse_blocks n'a pas suffi, cas rares).
        add_filter('render_block', array($this, 'collect_rendered_template_part'), 10, 2);

        add_action('wp_head', array($this, 'output_templates_css'), 999);
        add_action('wp_footer', array($this, 'output_templates_js'), 999);
    }

    /**
     * Renvoie la liste des clés de templates/parts actifs sur la requête courante.
     *
     * @return array<int, string>
     */
    private function get_active_template_keys()
    {
        $keys = array();

        if (!empty($GLOBALS['aibui_active_template_main_id'])) {
            $keys[] = 'wp_template:' . $GLOBALS['aibui_active_template_main_id'];
        }

        if (!empty($GLOBALS['aibui_active_template_parts']) && is_array($GLOBALS['aibui_active_template_parts'])) {
            foreach ($GLOBALS['aibui_active_template_parts'] as $part_id => $_) {
                $keys[] = 'wp_template_part:' . $part_id;
            }
        }

        return array_values(array_unique($keys));
    }

    /**
     * Résout l'ID (theme//slug) du block template principal utilisé pour la requête courante.
     */
    private function resolve_current_template_id()
    {
        if (!wp_is_block_theme()) {
            return null;
        }

        if (!empty($GLOBALS['_wp_current_template_id'])) {
            return (string) $GLOBALS['_wp_current_template_id'];
        }

        $slug = $this->resolve_template_slug_from_query();
        if (!$slug) {
            return null;
        }

        $theme = get_stylesheet();
        return $theme . '//' . $slug;
    }

    /**
     * Déduit le slug du template à utiliser en se basant sur la WP Query courante.
     * Ordre approximatif de la hiérarchie des templates block themes.
     */
    private function resolve_template_slug_from_query()
    {
        if (is_embed()) {
            return 'embed';
        }
        if (is_404()) {
            return '404';
        }
        if (is_search()) {
            return 'search';
        }
        if (is_front_page()) {
            return 'front-page';
        }
        if (is_home()) {
            return 'home';
        }

        if (is_singular()) {
            $obj = get_queried_object();
            if ($obj && isset($obj->ID)) {
                $assigned = get_page_template_slug($obj->ID);
                if ($assigned) {
                    return $assigned;
                }
            }

            if (is_page()) {
                return 'page';
            }
            if (is_attachment()) {
                return 'attachment';
            }
            if (is_single()) {
                return 'single';
            }
            return 'singular';
        }

        if (is_category()) {
            return 'category';
        }
        if (is_tag()) {
            return 'tag';
        }
        if (is_tax()) {
            return 'taxonomy';
        }
        if (is_author()) {
            return 'author';
        }
        if (is_date()) {
            return 'date';
        }
        if (is_archive()) {
            return 'archive';
        }

        return 'index';
    }

    /**
     * Parcourt récursivement les blocs pour détecter les core/template-part
     * et enregistrer leurs identifiants dans un global partagé.
     *
     * @param array<int, array> $blocks
     * @param int $depth
     */
    private function walk_blocks_for_template_parts($blocks, $depth = 0)
    {
        if ($depth > 10 || empty($blocks) || !is_array($blocks)) {
            return;
        }

        foreach ($blocks as $block) {
            if (!is_array($block)) {
                continue;
            }

            if (!empty($block['blockName']) && $block['blockName'] === 'core/template-part') {
                $slug = isset($block['attrs']['slug']) ? (string) $block['attrs']['slug'] : '';
                if ($slug !== '') {
                    $theme = !empty($block['attrs']['theme'])
                        ? (string) $block['attrs']['theme']
                        : get_stylesheet();
                    $part_id = $theme . '//' . $slug;

                    if (empty($GLOBALS['aibui_active_template_parts'][$part_id])) {
                        $GLOBALS['aibui_active_template_parts'][$part_id] = true;

                        // Descendre récursivement dans le contenu du template part
                        $part = function_exists('get_block_template')
                            ? get_block_template($part_id, 'wp_template_part')
                            : null;
                        if ($part && !empty($part->content)) {
                            $this->walk_blocks_for_template_parts(
                                parse_blocks($part->content),
                                $depth + 1
                            );
                        }
                    }
                }
            }

            if (!empty($block['innerBlocks']) && is_array($block['innerBlocks'])) {
                $this->walk_blocks_for_template_parts($block['innerBlocks'], $depth + 1);
            }
        }
    }

    public function precompute_active_templates()
    {
        if (is_admin() || !wp_is_block_theme()) {
            return;
        }

        $template_id = $this->resolve_current_template_id();
        if (!$template_id) {
            return;
        }

        $GLOBALS['aibui_active_template_main_id'] = $template_id;
        $GLOBALS['aibui_active_template_parts'] = isset($GLOBALS['aibui_active_template_parts'])
            && is_array($GLOBALS['aibui_active_template_parts'])
            ? $GLOBALS['aibui_active_template_parts']
            : array();

        if (!function_exists('get_block_template')) {
            return;
        }

        $template = get_block_template($template_id, 'wp_template');
        if (!$template || empty($template->content)) {
            return;
        }

        $this->walk_blocks_for_template_parts(parse_blocks($template->content));
    }

    /**
     * Filet de sécurité : détecter les core/template-part rendus dynamiquement
     * (via render_block) pour compléter la liste précalculée.
     */
    public function collect_rendered_template_part($block_content, $block)
    {
        if (empty($block['blockName']) || $block['blockName'] !== 'core/template-part') {
            return $block_content;
        }

        $slug = isset($block['attrs']['slug']) ? (string) $block['attrs']['slug'] : '';
        if ($slug === '') {
            return $block_content;
        }

        $theme = !empty($block['attrs']['theme'])
            ? (string) $block['attrs']['theme']
            : get_stylesheet();
        $id = $theme . '//' . $slug;

        if (!isset($GLOBALS['aibui_active_template_parts']) || !is_array($GLOBALS['aibui_active_template_parts'])) {
            $GLOBALS['aibui_active_template_parts'] = array();
        }
        $GLOBALS['aibui_active_template_parts'][$id] = true;

        return $block_content;
    }

    public function output_templates_css()
    {
        $keys = $this->get_active_template_keys();
        if (empty($keys)) {
            return;
        }

        $all = get_option('ai_builder_templates_css', array());
        if (!is_array($all)) {
            return;
        }

        $buffer = '';
        foreach ($keys as $key) {
            if (!empty($all[$key]['combined'])) {
                $buffer .= "\n" . $all[$key]['combined'];
            }
        }

        if (trim($buffer) === '') {
            return;
        }

        echo '<style id="ai-builder-templates-css" type="text/css">' . $buffer . '</style>';
    }

    public function output_templates_js()
    {
        $keys = $this->get_active_template_keys();
        if (empty($keys)) {
            return;
        }

        $all = get_option('ai_builder_templates_js', array());
        if (!is_array($all)) {
            return;
        }

        $buffer = '';
        foreach ($keys as $key) {
            if (!empty($all[$key]['combined'])) {
                $buffer .= "\n" . $all[$key]['combined'];
            }
        }

        if (trim($buffer) === '') {
            return;
        }

        echo '<script id="ai-builder-templates-js" type="text/javascript">' . $buffer . '</script>';
    }
}

new AIBUI_Templates_Assets_Handler();

```
