<?php
/**
 * Plugin Name:       AxcelersBlocks
 * Plugin URI:        https://axcelersblocks.com/
 * Description:       A Gutenberg Block Plugin to build different sections, pages and posts.
 * Version:           2.1.5
 * Requires at least: 6.8
 * Requires PHP:      7.4
 * Author:            Axcelers Hub Inc.
 * Author URI:        https://axcelershub.com/
 * License:           GPL-2.0-or-later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       axcelersblocks
 * Domain Path:       /languages
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

if ( ! defined( 'AXCELERSBLOCKS_VERSION' ) ) {
	define( 'AXCELERSBLOCKS_VERSION', '2.1.5' );
}

/**
 * Whether the PRO addon is active.
 *
 * @return bool
 */
function axcelersblocks_is_pro() {
	return (bool) apply_filters( 'axcelersblocks_is_pro', false );
}

/**
 * Editor globals for gating PRO-only UI.
 */
function axcelersblocks_editor_globals() {
	wp_add_inline_script(
		'wp-blocks',
		'window.axcelersblocks = window.axcelersblocks || {}; window.axcelersblocks.isPro = ' . ( axcelersblocks_is_pro() ? 'true' : 'false' ) . ';',
		'before'
	);
}
add_action( 'enqueue_block_editor_assets', 'axcelersblocks_editor_globals' );

/**
 * Stable hook point for addon editor assets.
 */
function axcelersblocks_enqueue_pro_editor_assets() {
	do_action( 'axcelersblocks_enqueue_editor_assets' );
}
add_action( 'enqueue_block_editor_assets', 'axcelersblocks_enqueue_pro_editor_assets', 20 );

/**
 * Override WordPress's native tablet/mobile preview widths with the values
 * from the AxcelersBlocks settings page.
 */
function axcelersblocks_enqueue_editor_preview_override() {
	$asset_file = plugin_dir_path( __FILE__ ) . 'build/editor/index.asset.php';
	if ( ! file_exists( $asset_file ) ) {
		return;
	}
	$asset = require $asset_file;
	wp_enqueue_script(
		'axcelersblocks-editor-preview',
		plugins_url( 'build/editor/index.js', __FILE__ ),
		$asset['dependencies'],
		$asset['version'],
		true
	);
}
add_action( 'enqueue_block_editor_assets', 'axcelersblocks_enqueue_editor_preview_override' );


/**
 * Stable hook point for addon frontend assets.
 */
function axcelersblocks_enqueue_pro_frontend_assets() {
	do_action( 'axcelersblocks_enqueue_frontend_assets' );
}
add_action( 'wp_enqueue_scripts', 'axcelersblocks_enqueue_pro_frontend_assets', 20 );

/**
 * Shared structural frontend CSS — loaded on frontend and editor canvas.
 * Visual styling comes from per-block inline CSS (render.php + attribute defaults).
 */
function axcelersblocks_enqueue_shared_frontend() {
	$css_file = plugin_dir_path( __FILE__ ) . 'build/css/shared-frontend.css';
	if ( ! file_exists( $css_file ) ) {
		return;
	}
	wp_enqueue_style(
		'axcelersblocks-shared',
		plugins_url( 'build/css/shared-frontend.css', __FILE__ ),
		[],
		AXCELERSBLOCKS_VERSION
	);
}
add_action( 'enqueue_block_assets', 'axcelersblocks_enqueue_shared_frontend' );

/**
 * Shared editor-only CSS — CodeMirror, dynamic tag chips, editor layout rules.
 */
function axcelersblocks_enqueue_shared_editor() {
	$css_file = plugin_dir_path( __FILE__ ) . 'build/css/shared-editor.css';
	if ( ! file_exists( $css_file ) ) {
		return;
	}
	wp_enqueue_style(
		'axcelersblocks-editor-shared',
		plugins_url( 'build/css/shared-editor.css', __FILE__ ),
		[],
		AXCELERSBLOCKS_VERSION
	);
}
add_action( 'enqueue_block_editor_assets', 'axcelersblocks_enqueue_shared_editor' );

/**
 * Registers blocks using a blocks-manifest.php file.
 *
 * @see https://make.wordpress.org/core/2025/03/13/more-efficient-block-type-registration-in-6-8/
 * @see https://make.wordpress.org/core/2024/10/17/new-block-type-registration-apis-to-improve-performance-in-wordpress-6-7/
 */
function axcelersblocks_block_init() {
	$manifest_file = __DIR__ . '/build/blocks-manifest.php';
	$blocks_dir    = __DIR__ . '/build/blocks/';

	if ( ! file_exists( $manifest_file ) ) {
		return;
	}

	// WP 6.8+.
	if ( function_exists( 'wp_register_block_types_from_metadata_collection' ) ) {
		wp_register_block_types_from_metadata_collection( $blocks_dir, $manifest_file );
		return;
	}

	// WP 6.7+.
	if ( function_exists( 'wp_register_block_metadata_collection' ) ) {
		wp_register_block_metadata_collection( $blocks_dir, $manifest_file );
	}

	$manifest_data = require $manifest_file;
	foreach ( array_keys( $manifest_data ) as $block_type ) {
		register_block_type( $blocks_dir . $block_type );
	}
}
add_action( 'init', 'axcelersblocks_block_init' );

/**
 * Register custom block category for AxcelersBlocks plugin.
 *
 * @param array $categories Existing block categories.
 * @return array Updated block categories.
 */
function axcelersblocks_register_block_category( $categories ) {
	$custom_category = array(
		'slug'  => 'axcelersblocks-blocks',
		'title' => __( 'AXB: Blocks', 'axcelersblocks' ),
		'icon'  => null,
	);

	array_unshift( $categories, $custom_category );
	return $categories;
}
add_filter( 'block_categories_all', 'axcelersblocks_register_block_category' );

/**
 * Print collected inline styles (if any).
 */
function axcelersblocks_sanitize_inline_css( $css ) {
	if ( ! is_string( $css ) ) {
		return '';
	}

	$css = trim( $css );

	if ( '' === $css ) {
		return '';
	}

	$css = preg_replace( '#</?style[^>]*>#i', '', $css );
	$css = str_replace( array( "\0", "\r" ), '', $css );
	$css = wp_strip_all_tags( $css );

	return trim( $css );
}

/**
 * Minify a CSS string for inline output.
 *
 * Safe for all CSS generated by AxcelersBlocks blocks:
 * - Collapses whitespace runs to a single space.
 * - Removes spaces around { } ; and : (property:value, media queries).
 * - Removes spaces after commas inside CSS functions (rgba, etc.).
 * - Removes trailing semicolons before closing braces.
 * Does NOT rewrite values, so calc(), var(), and quoted strings survive unchanged.
 *
 * @param string $css CSS string.
 * @return string
 */
function axcelersblocks_minify_css( $css ) {
	if ( ! is_string( $css ) || '' === $css ) {
		return $css;
	}

	// Strip CSS comments.
	$css = preg_replace( '/\/\*.*?\*\//s', '', $css );
	// Collapse whitespace (newlines, tabs, runs of spaces) to a single space.
	$css = preg_replace( '/\s+/', ' ', $css );
	// Remove spaces around braces and semicolons.
	$css = preg_replace( '/\s*\{\s*/', '{', $css );
	$css = preg_replace( '/\s*\}\s*/', '}', $css );
	$css = preg_replace( '/\s*;\s*/', ';', $css );
	// Remove trailing semicolon before closing brace.
	$css = str_replace( ';}', '}', $css );
	// Remove spaces around colons (property:value, @media conditions).
	$css = preg_replace( '/\s*:\s*/', ':', $css );
	// Remove spaces after commas inside function calls.
	$css = preg_replace( '/,\s*/', ',', $css );

	return trim( $css );
}

/**
 * Whether a block belongs to AxcelersBlocks.
 *
 * @param string $block_name Block name.
 * @return bool
 */
function axcelersblocks_is_plugin_block( $block_name ) {
	$is_plugin_block = is_string( $block_name ) && 0 === strpos( $block_name, 'axcelersblocks/' );

	/**
	 * Filter whether a block belongs to AxcelersBlocks (or an official addon).
	 *
	 * Addons can opt their namespace into the shared render pipeline (Custom CSS,
	 * Interactions, ARIA label extras) without hardcoding names into free/Pro.
	 *
	 * @param bool   $is_plugin_block Whether the block is treated as a plugin block.
	 * @param string $block_name      Block name.
	 */
	return (bool) apply_filters( 'axcelersblocks_is_plugin_block', $is_plugin_block, $block_name );
}

/**
 * Collect an inline CSS rule for later output.
 *
 * @param string $block_name Block name.
 * @param string $css_rule   CSS rule.
 * @return void
 */
function axcelersblocks_collect_inline_style_rule( $block_name, $css_rule ) {
	global $axcelersblocks_collected_styles;

	$block_name = is_string( $block_name ) ? $block_name : '';
	$css_rule   = axcelersblocks_sanitize_inline_css( $css_rule );

	if ( '' === $block_name || '' === $css_rule ) {
		return;
	}

	if ( ! isset( $axcelersblocks_collected_styles ) || ! is_array( $axcelersblocks_collected_styles ) ) {
		$axcelersblocks_collected_styles = array();
	}

	if ( ! isset( $axcelersblocks_collected_styles[ $block_name ] ) || ! is_array( $axcelersblocks_collected_styles[ $block_name ] ) ) {
		$axcelersblocks_collected_styles[ $block_name ] = array();
	}

	$axcelersblocks_collected_styles[ $block_name ][] = $css_rule;
}

/**
 * Apply extra attributes to the first HTML tag of a rendered block.
 *
 * @param string $html       Rendered block HTML.
 * @param array  $extra_attrs Extra attributes.
 * @return string
 */
function axcelersblocks_apply_render_extra_attrs( $html, $extra_attrs ) {
	if ( empty( $html ) || ! is_string( $html ) || empty( $extra_attrs ) || ! is_array( $extra_attrs ) ) {
		return $html;
	}

	if ( ! class_exists( 'WP_HTML_Tag_Processor' ) ) {
		return $html;
	}

	$processor = new WP_HTML_Tag_Processor( $html );

	if ( ! $processor->next_tag() ) {
		return $html;
	}

	foreach ( $extra_attrs as $attr_name => $attr_value ) {
		$attr_name = strtolower( trim( (string) $attr_name ) );

		if ( '' === $attr_name || null === $attr_value || '' === $attr_value ) {
			continue;
		}

		if ( 'class' === $attr_name ) {
			$classes = is_array( $attr_value ) ? $attr_value : preg_split( '/\s+/', (string) $attr_value );

			if ( empty( $classes ) || ! is_array( $classes ) ) {
				continue;
			}

			foreach ( $classes as $class_name ) {
				$class_name = sanitize_html_class( $class_name );

				if ( '' !== $class_name ) {
					$processor->add_class( $class_name );
				}
			}

			continue;
		}

		if ( is_array( $attr_value ) || is_object( $attr_value ) ) {
			$attr_value = wp_json_encode( $attr_value );
		} elseif ( is_bool( $attr_value ) ) {
			$attr_value = $attr_value ? 'true' : 'false';
		} else {
			$attr_value = (string) $attr_value;
		}

		$attr_value = trim( $attr_value );

		if ( '' === $attr_value ) {
			continue;
		}

		$processor->set_attribute( $attr_name, $attr_value );
	}

	return $processor->get_updated_html();
}

/**
 * Generic render extension layer for the PRO addon.
 *
 * @param string   $block_content Rendered block content.
 * @param array    $block         Parsed block data.
 * @param WP_Block $instance      Block instance.
 * @return string
 */
function axcelersblocks_filter_rendered_block( $block_content, $block, $instance ) {
	$block_name = isset( $block['blockName'] ) ? $block['blockName'] : '';

	if ( empty( $block_content ) || ! axcelersblocks_is_plugin_block( $block_name ) ) {
		return $block_content;
	}

	$override = apply_filters( 'axcelersblocks_render_block_override', null, $block_content, $block, $instance );

	if ( is_string( $override ) ) {
		$block_content = $override;
	}

	$extra_attrs = apply_filters( 'axcelersblocks_render_extra_attrs', array(), $block, $instance, $block_content );

	if ( ! empty( $extra_attrs ) && is_array( $extra_attrs ) ) {
		$block_content = axcelersblocks_apply_render_extra_attrs( $block_content, $extra_attrs );
	}

	$inline_css = apply_filters( 'axcelersblocks_render_inline_css', '', $block, $instance, $block_content );

	if ( is_array( $inline_css ) ) {
		foreach ( $inline_css as $css_rule ) {
			axcelersblocks_collect_inline_style_rule( $block_name, $css_rule );
		}
	} elseif ( is_string( $inline_css ) && '' !== trim( $inline_css ) ) {
		axcelersblocks_collect_inline_style_rule( $block_name, $inline_css );
	}

	return apply_filters( 'axcelersblocks_rendered_block_content', $block_content, $block, $instance );
}
add_filter( 'render_block', 'axcelersblocks_filter_rendered_block', 10, 3 );

function axcelersblocks_enqueue_collected_styles() {
	global $axcelersblocks_collected_styles;

	if ( ! is_array( $axcelersblocks_collected_styles ) || empty( $axcelersblocks_collected_styles ) ) {
		return;
	}

	// Separate plain rules from @media rules and group the latter by query string.
	// This collapses N per-block @media blocks into one per query, reducing output size.
	$plain_rules  = array();
	$media_groups = array(); // keyed by media query string, preserves insertion order
	$media_order  = array();

	foreach ( $axcelersblocks_collected_styles as $styles ) {
		if ( empty( $styles ) || ! is_array( $styles ) ) {
			continue;
		}
		foreach ( array_unique( $styles ) as $rule ) {
			if ( ! is_string( $rule ) ) {
				continue;
			}
			$rule = trim( $rule );
			if ( '' === $rule ) {
				continue;
			}

			if ( 0 === strpos( $rule, '@media ' ) ) {
				// Extract query and inner selector rule.
				// Format: @media QUERY { SELECTOR { props } }
				$brace = strpos( $rule, '{' );
				if ( false === $brace ) {
					$plain_rules[] = $rule;
					continue;
				}
				$query = trim( substr( $rule, 7, $brace - 7 ) ); // 7 = strlen('@media ')
				$inner = trim( substr( $rule, $brace + 1 ) );
				if ( '}' === substr( $inner, -1 ) ) {
					$inner = trim( substr( $inner, 0, -1 ) );
				}
				if ( '' !== $query && '' !== $inner ) {
					if ( ! isset( $media_groups[ $query ] ) ) {
						$media_groups[ $query ] = array();
						$media_order[ $query ]  = count( $media_order );
					}
					$media_groups[ $query ][] = $inner;
				}
			} else {
				$plain_rules[] = $rule;
			}
		}
	}

	if ( empty( $plain_rules ) && empty( $media_groups ) ) {
		return;
	}

	$parts = array();

	if ( ! empty( $plain_rules ) ) {
		$parts[] = implode( "\n", array_unique( $plain_rules ) );
	}

	if ( count( $media_groups ) > 1 ) {
		uksort(
			$media_groups,
			function ( $query_a, $query_b ) use ( $media_order ) {
				$min_a = null;
				$min_b = null;

				if ( preg_match( '/min-width\s*:\s*([0-9]+(?:\.[0-9]+)?)px/i', $query_a, $matches_a ) ) {
					$min_a = (float) $matches_a[1];
				}

				if ( preg_match( '/min-width\s*:\s*([0-9]+(?:\.[0-9]+)?)px/i', $query_b, $matches_b ) ) {
					$min_b = (float) $matches_b[1];
				}

				if ( null !== $min_a && null !== $min_b && $min_a !== $min_b ) {
					return ( $min_a < $min_b ) ? -1 : 1;
				}

				if ( null !== $min_a && null === $min_b ) {
					return -1;
				}

				if ( null === $min_a && null !== $min_b ) {
					return 1;
				}

				$order_a = isset( $media_order[ $query_a ] ) ? $media_order[ $query_a ] : 0;
				$order_b = isset( $media_order[ $query_b ] ) ? $media_order[ $query_b ] : 0;

				if ( $order_a === $order_b ) {
					return 0;
				}

				return ( $order_a < $order_b ) ? -1 : 1;
			}
		);
	}

	foreach ( $media_groups as $query => $inners ) {
		$parts[] = '@media ' . $query . " {\n" . implode( "\n", array_unique( $inners ) ) . "\n}";
	}

	$css = implode( "\n", $parts );
	$css = axcelersblocks_sanitize_inline_css( $css );
	$css = axcelersblocks_minify_css( $css );

	if ( '' === $css ) {
		return;
	}

	// Clear collected styles now to prevent a second output when this function
	// is also called on wp_footer (classic themes where blocks render late).
	$axcelersblocks_collected_styles = array();

	if ( 'wp_footer' === current_action() ) {
		// Classic themes: blocks render during the_content() after wp_head() has fired.
		// wp_add_inline_style() can no longer attach to the head, so echo directly.
		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSS is sanitized by axcelersblocks_sanitize_inline_css() and minified by axcelersblocks_minify_css().
		echo "<style id='axcelersblocks-inline-css'>\n" . $css . "\n</style>\n";
	} else {
		// FSE / block themes: get_the_block_template_html() pre-renders all blocks
		// before wp_head() fires, so the collection is already populated here.
		// Use the standard WP enqueueing mechanism so the CSS lands in <head>.
		wp_register_style( 'axcelersblocks-inline', false, array(), AXCELERSBLOCKS_VERSION );
		wp_enqueue_style( 'axcelersblocks-inline' );
		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSS is sanitized by axcelersblocks_sanitize_inline_css() and minified by axcelersblocks_minify_css().
		wp_add_inline_style( 'axcelersblocks-inline', $css );
	}
}
add_action( 'wp_enqueue_scripts', 'axcelersblocks_enqueue_collected_styles', 99 );
add_action( 'wp_footer',          'axcelersblocks_enqueue_collected_styles', 1  );

/**
 * Plugin bootstrap for settings/rest/custom fonts.
 */
function axcelersblocks_bootstrap() {
require_once plugin_dir_path( __FILE__ ) . 'includes/svg-support.php';
require_once plugin_dir_path( __FILE__ ) . 'includes/effect-style-helpers.php';
require_once plugin_dir_path( __FILE__ ) . 'includes/class-settings-page.php';
require_once plugin_dir_path( __FILE__ ) . 'includes/class-responsive-settings.php';
require_once plugin_dir_path( __FILE__ ) . 'includes/class-rest-api.php';

	$settings_page = new \AxcelersBlocks_Settings_Page();
	$settings_page->init();

	$responsive_settings = new \AxcelersBlocks_Responsive_Settings();
	$responsive_settings->init();

	$rest_api = new \AxcelersBlocks_Rest_API();
	$rest_api->init();
}
add_action( 'plugins_loaded', 'axcelersblocks_bootstrap' );


/**
 * Which post types should see the template in the editor dropdown.
 *
 * @return array
 */
function axcelersblocks_fullwidth_post_types() {
	return apply_filters( 'axcelersblocks_fullwidth_post_types', array( 'page', 'post' ) );
}

/**
 * Make the template appear in the "Template" dropdown for the chosen post types.
 *
 * Classic PHP templates are for classic themes only. Block themes use
 * register_block_template() entries (blank-page, full-width).
 */
function axcelersblocks_add_classic_template( $templates, $theme, $post, $post_type ) {
	if ( wp_is_block_theme() ) {
		return $templates;
	}

	if ( in_array( $post_type, axcelersblocks_fullwidth_post_types(), true ) ) {
		$templates['axcelersblocks-fullwidth.php'] = __( 'AxcelersBlocks — Full Width', 'axcelersblocks' );
		$templates['axcelersblocks-blank.php']     = __( 'AXB: Blank Page Template', 'axcelersblocks' );
	}
	return $templates;
}
add_filter( 'theme_templates', 'axcelersblocks_add_classic_template', 10, 4 );

/**
 * When a classic template is chosen, load our plugin file instead of a theme file.
 *
 * Block-theme slugs (blank-page, full-width) are handled by the FSE template system.
 */
function axcelersblocks_template_include( $template ) {
	if ( wp_is_block_theme() ) {
		return $template;
	}

	$slug = get_page_template_slug();
	$map  = array(
		'axcelersblocks-fullwidth.php' => 'templates/axcelersblocks-fullwidth.php',
		'axcelersblocks-blank.php'     => 'templates/axcelersblocks-blank.php',
	);
	if ( isset( $map[ $slug ] ) ) {
		$file = plugin_dir_path( __FILE__ ) . $map[ $slug ];
		if ( file_exists( $file ) ) {
			return $file;
		}
	}
	return $template;
}
add_filter( 'template_include', 'axcelersblocks_template_include' );

/**
 * Register block templates (block/FSE themes only).
 */
function axcelersblocks_register_block_template() {
	if ( ! wp_is_block_theme() || ! function_exists( 'register_block_template' ) ) {
		return;
	}

	register_block_template(
		'axcelersblocks//full-width',
		array(
			'title'       => __( 'AxcelersBlocks — Full Width', 'axcelersblocks' ),
			'description' => __( 'Edge-to-edge canvas without constrained wrappers.', 'axcelersblocks' ),
			'post_types'  => array( 'page', 'post' ),
			'content'     =>
				'<!-- wp:template-part {"slug":"header","area":"header","tagName":"header"} /-->' .
				'<!-- wp:post-content {"align":"full","layout":{"type":"default"}} /-->' .
				'<!-- wp:template-part {"slug":"footer","area":"footer","tagName":"footer"} /-->',
			'plugin'      => 'axcelersblocks',
		)
	);

	register_block_template(
		'axcelersblocks//blank-page',
		array(
			'title'       => __( 'AXB: Blank Page Template', 'axcelersblocks' ),
			'description' => __( 'A completely blank canvas with no WordPress layout wrappers. Build your header, content, and footer entirely with AXB blocks using Box (tagName: header/main/footer) and Columns.', 'axcelersblocks' ),
			'post_types'  => array( 'page', 'post' ),
			'content'     => '<!-- wp:post-content {"layout":{"type":"default","inherit":false}} /-->',
			'plugin'      => 'axcelersblocks',
		)
	);
}
add_action( 'init', 'axcelersblocks_register_block_template' );

/**
 * Re-index the get_block_templates() result so numeric key 0 always exists.
 *
 * Plugin-registered templates are stored with string keys in WP_Block_Templates_Registry.
 * After array_merge() those string keys are preserved, so $result[0] is undefined
 * even when ! empty( $result ) — triggering a PHP warning in block-editor.php:469.
 */
add_filter( 'get_block_templates', 'axcelersblocks_reindex_block_templates', 10, 3 );
function axcelersblocks_reindex_block_templates( $templates, $query, $template_type ) {
	if ( 'wp_template' !== $template_type || ! is_array( $templates ) ) {
		return $templates;
	}

	$templates = array_filter(
		$templates,
		static function ( $template ) {
			return $template instanceof WP_Block_Template && is_string( $template->content );
		}
	);

	return array_values( $templates );
}

/**
 * Whether the current request is rendering the AXB blank page template.
 *
 * @return bool
 */
function axcelersblocks_is_blank_page_template() {
	$slug = get_page_template_slug();

	if ( in_array( $slug, array( 'axcelersblocks-blank.php', 'blank-page' ), true ) ) {
		return true;
	}

	global $_wp_current_template_id;

	return is_string( $_wp_current_template_id ) && preg_match( '#//blank-page$#', $_wp_current_template_id );
}

/**
 * The block-theme post-content block adds entry-content/wp-block-post-content
 * wrappers. The AXB blank template needs only the user's block markup.
 *
 * @param string   $block_content Rendered block content.
 * @param array    $block         Parsed block data.
 * @param WP_Block $instance      Block instance.
 * @return string
 */
function axcelersblocks_render_blank_template_post_content( $block_content, $block, $instance ) {
	static $rendering = false;

	if ( $rendering || ! axcelersblocks_is_blank_page_template() || ! isset( $instance->context['postId'] ) ) {
		return $block_content;
	}

	$rendering = true;
	$content   = get_the_content();

	if ( has_block( 'core/nextpage', $instance->context['postId'] ) ) {
		$content .= wp_link_pages( array( 'echo' => 0 ) );
	}

	/** This filter is documented in wp-includes/post-template.php. */
	$content = apply_filters( 'the_content', str_replace( ']]>', ']]&gt;', $content ) ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Intentionally applying WordPress core's the_content filter, exactly as core does.
	$rendering = false;

	return $content;
}
add_filter( 'render_block_core/post-content', 'axcelersblocks_render_blank_template_post_content', 10, 3 );

/**
 * Register AxcelersBlocks pattern categories and patterns.
 */
function axcelersblocks_register_block_patterns() {
	// Categories.
	if ( function_exists( 'register_block_pattern_category' ) ) {

		// ✅ HERO category
		register_block_pattern_category(
			'axcelersblocks-hero',
			array(
				'label' => __( 'AXB: Hero', 'axcelersblocks' ),
			)
		);

		// ✅ CTA category
		register_block_pattern_category(
			'axcelersblocks-cta',
			array(
				'label' => __( 'AXB: CTA', 'axcelersblocks' ),
			)
		);

		// ✅ Media category
		register_block_pattern_category(
			'axcelersblocks-media',
			array( 'label' => __( 'AXB: Media', 'axcelersblocks' ) )
		);

		// ✅ Testimonial category
		register_block_pattern_category(
			'axcelersblocks-testimonials',
			array( 'label' => __( 'AXB: Testimonials', 'axcelersblocks' ) )
		);

		// ✅ Post category
		register_block_pattern_category(
			'axcelersblocks-posts',
			array(
				'label' => __( 'AXB: Posts', 'axcelersblocks' ),
			)
		);

		// ✅ List category
		register_block_pattern_category(
			'axcelersblocks-list',
			array( 'label' => __( 'AXB: List', 'axcelersblocks' ) )
		);

		// ✅ Table category
		register_block_pattern_category(
			'axcelersblocks-table',
			array( 'label' => __( 'AXB: Table', 'axcelersblocks' ) )
		);

	}

	// Patterns.
	$patterns = array(

		// ✅ HERO category
		'axcelersblocks/hero-centered-image-overlay'  => __DIR__ . '/patterns/hero-centered-image-overlay.php',
		'axcelersblocks/hero-split-text-image'       => __DIR__ . '/patterns/hero-split-text-image.php',
		'axcelersblocks/hero-dark-stats-row'         => __DIR__ . '/patterns/hero-dark-stats-row.php',

		// ✅ CTA pattern
		'axcelersblocks/cta-centered-banner'         => __DIR__ . '/patterns/cta-centered-banner.php',
		'axcelersblocks/cta-split-text-button'         => __DIR__ . '/patterns/cta-split-text-button.php',

		// ✅ Media category
		'axcelersblocks/media-with-text-image-left'         => __DIR__ . '/patterns/media-with-text-image-left.php',
		'axcelersblocks/media-with-text-text-left'         => __DIR__ . '/patterns/media-with-text-text-left.php',
		'axcelersblocks/media-with-text-stacked-centered'         => __DIR__ . '/patterns/media-with-text-stacked-centered.php',

		// ✅ Testimonial category
		'axcelersblocks/testimonials-3-col-grid'         => __DIR__ . '/patterns/testimonials-3-col-grid.php',
		'axcelersblocks/testimonials-featured-centered'         => __DIR__ . '/patterns/testimonials-featured-centered.php',

		// ✅ Featured Post category
		'axcelersblocks/featured-post-hero-card'         => __DIR__ . '/patterns/featured-post-hero-card.php',
		'axcelersblocks/featured-post-editorial-layout'         => __DIR__ . '/patterns/featured-post-editorial-layout.php',

		// ✅ List category
		'axcelersblocks/list-feature-checklist'          => __DIR__ . '/patterns/list-feature-checklist.php',
		'axcelersblocks/list-two-column-checklist'       => __DIR__ . '/patterns/list-two-column-checklist.php',
		'axcelersblocks/list-numbered-steps'             => __DIR__ . '/patterns/list-numbered-steps.php',

		// ✅ Table category
		'axcelersblocks/table-pricing-comparison'        => __DIR__ . '/patterns/table-pricing-comparison.php',
		'axcelersblocks/table-product-specs'             => __DIR__ . '/patterns/table-product-specs.php',
		'axcelersblocks/table-schedule'                  => __DIR__ . '/patterns/table-schedule.php',
	);

	if ( function_exists( 'register_block_pattern' ) ) {
		foreach ( $patterns as $pattern_name => $pattern_file ) {
			if ( ! file_exists( $pattern_file ) ) {
				continue;
			}

			$pattern = require $pattern_file;

			if ( is_array( $pattern ) && ! empty( $pattern['title'] ) && ! empty( $pattern['content'] ) ) {
				register_block_pattern( $pattern_name, $pattern );
			}
		}
	}
}
add_action( 'init', 'axcelersblocks_register_block_patterns' );
