Create New Item
Item Type
File
Folder
Item Name
Search file in folder and subfolders...
Are you sure want to rename?
chromed
/
wp-content
/
plugins
/
extendify
/
app
/
Agent
:
TemplatePartBlockFinder.php
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
<?php namespace Extendify\Agent; defined('ABSPATH') || die('No direct access.'); // Resolves a block inside a template-part by the same preorder numbering // TagTemplateParts assigns at render time, so a client blockId (read off a // data-extendify-part-block-id attribute) maps back to the parsed block. // Shared by SaveController (write) and WPController::getBlockCode (read) so the // two halves can never resolve a different block for the same id. class TemplatePartBlockFinder { // Preorder walk matching TagTemplateParts numbering: nested // core/template-part blocks open a separate seq space (skipped), and the // shared $ignored dynamic blocks (mini-cart, loops, …) count as one leaf // each but are not descended into — the tagger skips their rendered subtree. // // Ref-based navigation blocks (`core/navigation` with a `ref` attr) resolve // their items at render time from a separate wp_navigation post. // TagTemplateParts fires for those rendered items inside the outer // template-part's frame, so each one increments the outer seq. parse_blocks // of the post we're walking only sees the navigation block (empty // innerBlocks for refs), so a naïve walk would under-count. Resolve the nav // ref here and add its block count to the running counter so blockIds // *after* the navigation (e.g. social-link in a sibling social-links block) // still line up. public static function find( array $blocks, int $targetId, int &$maxCounter = 0, array &$visited = [] ) { $counter = 0; $found = null; $walk = function (array &$list, array $pathSoFar) use (&$walk, &$counter, &$found, $targetId, &$visited) { foreach ($list as $i => &$block) { if ($found !== null) { return; } $name = $block['blockName'] ?? ''; if ($name === '') { if (!empty($block['innerBlocks'])) { $walk($block['innerBlocks'], array_merge($pathSoFar, [$i, 'innerBlocks'])); } continue; } if ($name === 'core/template-part') { continue; } $counter++; $visited[] = ['c' => $counter, 'n' => $name]; if ($counter === $targetId) { $found = ['block' => $block, 'path' => array_merge($pathSoFar, [$i])]; return; } // Dynamic self-rendering blocks (loops, woocommerce/mini-cart, …) // count as one leaf but are not descended into: TagTemplateParts // skips their render-injected subtree, so descending here would // drift every later id. Shares the one $ignored list. if (in_array($name, TagTemplateParts::$ignored, true)) { continue; } if ($name === 'core/navigation' && !empty($block['attrs']['ref'])) { $navPost = get_post((int) $block['attrs']['ref']); if ($navPost) { $navBlocks = parse_blocks($navPost->post_content); $before = $counter; self::countBlocksPreorder($navBlocks, $counter); for ($j = $before + 1; $j <= $counter; $j++) { $visited[] = ['c' => $j, 'n' => '(nav-ref-item)']; } } // Ref navs have no innerBlocks in the parsed tree — items // live in the wp_navigation post and can't be replaced from // here anyway (WPNavigationController owns that). continue; } if (!empty($block['innerBlocks'])) { $walk($block['innerBlocks'], array_merge($pathSoFar, [$i, 'innerBlocks'])); } } unset($block); }; $walk($blocks, []); $maxCounter = $counter; return $found; } private static function countBlocksPreorder(array $blocks, int &$counter) { foreach ($blocks as $block) { $name = $block['blockName'] ?? ''; if ($name === '') { if (!empty($block['innerBlocks'])) { self::countBlocksPreorder($block['innerBlocks'], $counter); } continue; } if ($name === 'core/template-part') { continue; } $counter++; if (in_array($name, TagTemplateParts::$ignored, true)) { continue; } if (!empty($block['innerBlocks'])) { self::countBlocksPreorder($block['innerBlocks'], $counter); } } } }