HEX
Server: LiteSpeed
System: Linux server318.web-hosting.com 4.18.0-513.18.1.lve.el8.x86_64 #1 SMP Thu Feb 22 12:55:50 UTC 2024 x86_64
User: joyfejor (3859)
PHP: 8.1.33
Disabled: NONE
Upload Files
File: /home/joyfejor/www/wp-content/plugins/extendify/app/Agent/TagTemplateParts.php
<?php

namespace Extendify\Agent;

defined('ABSPATH') || die('No direct access.');

/**
 * Tag blocks inside template parts (header/footer/etc.) with deterministic IDs.
 * - Only runs inside core/template-part scopes.
 * - Preorder numbering per template-part.
 */
class TagTemplateParts
{
    public static function init()
    {
        // Reset per-request state
        add_action('template_redirect', function () {
            $GLOBALS['extendify_part_frames'] = []; // stack of frames
        });

        // Assign IDs at the block-data layer (pre-order, stable)
        add_filter('render_block_data', [self::class, 'onRenderBlockData'], 10, 2);

        // Turn those IDs into DOM attributes & manage scope lifecycle
        add_filter('render_block', [self::class, 'onRenderBlock'], 10, 2);
    }

    private static function isTemplatePart(array $b): bool
    {
        return (($b['blockName'] ?? '') === 'core/template-part');
    }

    private static function currentFrame()
    {
        $stack = $GLOBALS['extendify_part_frames'] ?? [];
        return $stack ? $stack[count($stack) - 1] : null;
    }

    private static function setCurrentFrame(array $frame)
    {
        $GLOBALS['extendify_part_frames'][count($GLOBALS['extendify_part_frames']) - 1] = $frame;
    }

    private static function labelForPart(array $b): string
    {
        if (!empty($b['attrs']['area'])) {
            return (string) $b['attrs']['area'];
        }
        if (!empty($b['attrs']['slug'])) {
            return (string) $b['attrs']['slug'];
        }
        return 'template-part';
    }

    /** Assign IDs/labels into attrs before render (pre-order) */
    public static function onRenderBlockData(array $block, array $source): array
    {
        $name = $block['blockName'] ?? '';
        if ($name === '') {
            return $block;
        }

        // OPEN a template-part scope (do not number the wrapper itself)
        if (self::isTemplatePart($block)) {
            $label = self::labelForPart($block);
            $GLOBALS['extendify_part_frames'][] = [
                'label' => $label,
                'seq' => 0, // per-part counter
            ];
            // mark so we know to pop when this wrapper finishes rendering
            $block['attrs']['__extendify_scope_open'] = 1;
            return $block;
        }

        // Not inside a template-part? Ignore (prevents tagging post content).
        if (empty($GLOBALS['extendify_part_frames'])) {
            return $block;
        }

        // Inside a template part
        $frame = self::currentFrame();
        // Any other block inside the part → number it
        if ($frame) {
            $frame['seq']++;
            $block['attrs']['extendifyAgentBlockId'] = $frame['seq'];
            $block['attrs']['extendifyAgentPart'] = $frame['label'];
            self::setCurrentFrame($frame);
        }

        return $block;
    }

    /** Inject DOM attributes and close scopes after render */
    public static function onRenderBlock(string $html, array $block): string
    {
        $name = $block['blockName'] ?? '';
        if ($name === '') {
            return $html;
        }

        // When the template-part wrapper finishes rendering, POP the frame
        if (self::isTemplatePart($block) && !empty($block['attrs']['__extendify_scope_open'])) {
            // wrapper itself isn’t tagged; just close the scope
            array_pop($GLOBALS['extendify_part_frames']);
            return $html;
        }

        // If we’re not inside a template part, do nothing
        if (empty($GLOBALS['extendify_part_frames'])) {
            return $html;
        }

        // Inject attributes for blocks we numbered
        $id   = $block['attrs']['extendifyAgentBlockId'] ?? null;
        $part = $block['attrs']['extendifyAgentPart'] ?? null;

        if ($id && $html) {
            $tp = new \WP_HTML_Tag_Processor($html);
            if ($tp->next_tag()) {
                $tp->set_attribute('data-extendify-part-block-id', (string) (int) $id);
                if ($part) {
                    $tp->set_attribute('data-extendify-part', $part);
                }
                $html = $tp->get_updated_html();
            }
        }
        return $html;
    }
}