<?php
/**
 * Auto-tag NESTED Kadence Row Layouts with a `bw-inside-row` class.
 *
 * When a Row Layout (kadence/rowlayout) sits inside another Row Layout — e.g. a
 * complex layout of Row → Column → Row — the INNER row's wrapper
 * (.kb-row-layout-wrap) gets an extra class `bw-inside-row`. There is NO
 * editor/admin option: nesting is detected automatically on render.
 *
 * Why: a Customizer CSS rule targets `.bw-inside-row` (e.g. to drop the inner
 * row's left/right padding). This hook's ONLY job is to add the class — the
 * styling lives in the Customizer, not here.
 *
 * How: after the page content's blocks are rendered (the_content), we walk the
 * final HTML once with WP_HTML_Tag_Processor (HTML5-aware, lossless) and track
 * real <div> nesting. Any `.kb-row-layout-wrap` that has a `.kb-row-layout-wrap`
 * ancestor is a nested row → we add `bw-inside-row` to it. This is DOM-accurate
 * regardless of how the inner row got rendered (columns, custom blocks, popups),
 * unlike a positional render_block pass. Scope is the page content, which is
 * where authors build complex nested layouts (header/footer nav elements are
 * intentionally left alone).
 *
 * @package Kadence-Child
 */

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

/**
 * @param string $content Rendered post content (after do_blocks).
 * @return string
 */
function bw_inside_row_tag_nested( $content ) {
	// Main singular content only (mirrors the hero filter's guard); skip admin,
	// feeds, widgets, secondary queries.
	if ( is_admin() || ! in_the_loop() || ! is_main_query() ) {
		return $content;
	}
	// Cheap bail-outs: need at least two row wrappers to have any nesting, and
	// the tag processor to be available (WP 6.2+).
	if ( substr_count( $content, 'kb-row-layout-wrap' ) < 2 || ! class_exists( 'WP_HTML_Tag_Processor' ) ) {
		return $content;
	}

	$p         = new WP_HTML_Tag_Processor( $content );
	$depth     = 0;          // current <div> nesting depth
	$row_depths = array();   // depths at which a row wrapper is currently open
	$changed   = false;

	while ( $p->next_tag( array( 'tag_name' => 'DIV', 'tag_closers' => 'visit' ) ) ) {
		if ( $p->is_tag_closer() ) {
			if ( ! empty( $row_depths ) && (int) end( $row_depths ) === $depth ) {
				array_pop( $row_depths );
			}
			$depth--;
			continue;
		}

		$depth++;
		$class = $p->get_attribute( 'class' );
		if ( is_string( $class ) && preg_match( '/\bkb-row-layout-wrap\b/', $class ) ) {
			// A row wrapper that already sits inside another row wrapper → nested.
			if ( ! empty( $row_depths ) && false === strpos( $class, 'bw-inside-row' ) ) {
				$p->add_class( 'bw-inside-row' );
				$changed = true;
			}
			$row_depths[] = $depth;
		}
	}

	return $changed ? $p->get_updated_html() : $content;
}
// Priority 99: after do_blocks (9) and the hero prepend (20), so we see the
// fully rendered content.
add_filter( 'the_content', 'bw_inside_row_tag_nested', 99 );
