register(); return true; } /** * Hooks the markers. Public for tests; normal code calls maybe_register(). */ public function register(): void { if ( ! defined( 'DONOTCACHEPAGE' ) ) { define( 'DONOTCACHEPAGE', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound -- Standard constant read by caching plugins. } add_filter( 'the_content', array( $this, 'post_content' ), PHP_INT_MAX ); add_filter( 'walker_nav_menu_start_el', array( $this, 'menu_item' ), PHP_INT_MAX, 2 ); add_filter( 'dynamic_sidebar_params', array( $this, 'widget' ), PHP_INT_MAX ); add_action( 'elementor/frontend/before_render', array( $this, 'elementor_open' ) ); add_action( 'elementor/frontend/after_render', array( $this, 'elementor_close' ) ); } /** * Wraps post content. * * @param string $content Rendered content. */ public function post_content( $content ): string { $id = get_the_ID(); return is_int( $id ) && $id > 0 ? Source::wrap( (string) $content, Source::POST_CONTENT, (string) $id ) : (string) $content; } /** * Wraps a menu item. * * @param string $output Item output. * @param object $item Menu item. */ public function menu_item( $output, $item ): string { $id = isset( $item->ID ) ? (int) $item->ID : 0; return $id > 0 ? Source::wrap( (string) $output, Source::MENU_ITEM, (string) $id ) : (string) $output; } /** * Adds markers to a widget's before/after HTML. * * @param mixed $params Widget display parameters. * @return array */ public function widget( $params ): array { if ( ! is_array( $params ) ) { return array(); } if ( ! isset( $params[0]['widget_id'] ) || ! is_array( $params[0] ) ) { return $params; } $id = (string) $params[0]['widget_id']; $params[0]['before_widget'] = Source::open( Source::WIDGET, $id ) . ( $params[0]['before_widget'] ?? '' ); $params[0]['after_widget'] = ( $params[0]['after_widget'] ?? '' ) . Source::close( Source::WIDGET, $id ); return $params; } /** * Opens an Elementor element. * * @param object $element Elementor element. */ public function elementor_open( $element ): void { echo Source::open( Source::ELEMENTOR, self::elementor_ref( $element ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Marker contains only [A-Za-z0-9_:.-]. } /** * Closes an Elementor element. * * @param object $element Elementor element. */ public function elementor_close( $element ): void { echo Source::close( Source::ELEMENTOR, self::elementor_ref( $element ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Marker contains only [A-Za-z0-9_:.-]. } /** * "document:element" for an Elementor element. The document is the post or template whose * Elementor data holds the element. * * @param object $element Elementor element. */ private static function elementor_ref( $element ): string { $element_id = method_exists( $element, 'get_id' ) ? (string) $element->get_id() : ''; $document = 0; if ( class_exists( '\Elementor\Plugin' ) && isset( \Elementor\Plugin::$instance->documents ) ) { $current = \Elementor\Plugin::$instance->documents->get_current(); if ( is_object( $current ) && method_exists( $current, 'get_main_id' ) ) { $document = (int) $current->get_main_id(); } } if ( 0 === $document ) { $id = get_the_ID(); $document = is_int( $id ) ? $id : 0; } return $document . ':' . $element_id; } }