$label, 'slug' => $slug, '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(self::$frames)) { return $block; } // Inside a template part $frame = self::currentFrame(); // Any other block inside the part → number it if ($frame) { $frame['seq']++; self::$blockStack[] = [ 'id' => $frame['seq'], 'label' => $frame['label'], 'slug' => $frame['slug'] ?? '', ]; 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(self::$frames); return $html; } // If we’re not inside a template part, do nothing if (empty(self::$frames)) { return $html; } // Inject attributes for blocks we numbered $info = !empty(self::$blockStack) ? array_pop(self::$blockStack) : null; if ($info && $html) { $tp = new \WP_HTML_Tag_Processor($html); if ($tp->next_tag()) { $tp->set_attribute('data-extendify-part-block-id', (string) (int) $info['id']); $tp->set_attribute('data-extendify-part', $info['label']); if (!empty($info['slug'])) { $tp->set_attribute('data-extendify-part-slug', $info['slug']); } $html = $tp->get_updated_html(); } } return $html; } }