editor ) && method_exists( $plugin->editor, 'is_edit_mode' ) && $plugin->editor->is_edit_mode(); $is_preview = isset( $plugin->preview ) && method_exists( $plugin->preview, 'is_preview_mode' ) && $plugin->preview->is_preview_mode(); return $is_edit || $is_preview; } /** * Gets an inline script element that re-fires Elementor's frontend "element_ready" * hooks, needed because content rendered via AJAX/shortcode inside the * Elementor editor doesn't trigger Elementor's own initialization events. * * @return string The script element's markup, or an empty string outside the Elementor editor. */ public static function get_elementor_init_script(): string { if ( ! self::is_elementor_editor() ) { return ''; } return <<<'JS' JS; } /** * Recursively collects the generated per-breakpoint CSS for a block and its children. * * @param array $block A single parsed block (with optional 'innerBlocks'). * @return string Concatenated CSS for this block and all descendants. */ public static function collect_block_css( array $block ): string { $css = self::build_css_from_attrs( $block['attrs'] ?? array() ); foreach ( $block['innerBlocks'] ?? array() as $inner_block ) { $css .= self::collect_block_css( $inner_block ); } return $css; } /** * Builds a single block's responsive CSS from its stored "blocksCSS" attribute, * wrapping per-device rules in the appropriate min/max-width media query. * * @param array $attrs Block attributes, expected to contain a "blocksCSS" map keyed by device slug. * @return string The generated CSS, or an empty string if there's nothing to output. */ public static function build_css_from_attrs( array $attrs ): string { static $device_list = null; $device_list ??= Utils::get_device_list(); $blocks_css = $attrs['blocksCSS'] ?? null; if ( empty( $blocks_css ) || ! is_array( $blocks_css ) ) { return ''; } $css_map = array_filter( $blocks_css, static fn( $value ) => is_string( $value ) && '' !== trim( $value ) ); if ( empty( $css_map ) ) { return ''; } $output = ''; foreach ( $device_list as $device ) { $slug = strtolower( $device['slug'] ?? '' ); $css = trim( $css_map[ $slug ] ?? '' ); if ( '' === $css ) { continue; } $css = self::sanitize_css( $css ); if ( 'base' === ( $device['value'] ?? '' ) ) { $output .= $css; } else { $output .= "@media ({$device['direction']}-width:{$device['value']}px){{$css}}"; } } if ( ! empty( $css_map['customStyles'] ) ) { $output .= self::sanitize_css( $css_map['customStyles'] ); } return $output; } /** * Strips any HTML-tag-like sequences from a stored CSS string before it's * @param string $css Raw CSS string from a block attribute. * @return string Sanitized CSS string. */ private static function sanitize_css( string $css ): string { return preg_replace( '/<[^>]*>?/', '', $css ); } }