?? GreyFile — Mystic File Browser

Current path: home/webdevt/www/wdp/wp-content/plugins/jetpack-boost/app/modules/optimizations/lcp/



?? Go up: /home/webdevt/www/wdp/wp-content/plugins/jetpack-boost/app/modules/optimizations

?? Viewing: class-lcp.php

<?php

namespace Automattic\Jetpack_Boost\Modules\Optimizations\Lcp;

use Automattic\Jetpack\Schema\Schema;
use Automattic\Jetpack\WP_JS_Data_Sync\Data_Sync;
use Automattic\Jetpack_Boost\Contracts\Changes_Output_After_Activation;
use Automattic\Jetpack_Boost\Contracts\Feature;
use Automattic\Jetpack_Boost\Contracts\Has_Activate;
use Automattic\Jetpack_Boost\Contracts\Has_Data_Sync;
use Automattic\Jetpack_Boost\Contracts\Needs_To_Be_Ready;
use Automattic\Jetpack_Boost\Contracts\Optimization;
use Automattic\Jetpack_Boost\Lib\Cornerstone\Cornerstone_Utils;
use Automattic\Jetpack_Boost\Lib\Output_Filter;
use Automattic\Jetpack_Boost\REST_API\Contracts\Has_Always_Available_Endpoints;
use Automattic\Jetpack_Boost\REST_API\Endpoints\Update_LCP;

class Lcp implements Feature, Changes_Output_After_Activation, Optimization, Has_Activate, Needs_To_Be_Ready, Has_Data_Sync, Has_Always_Available_Endpoints {
	/**
	 * Utility class that supports output filtering.
	 *
	 * @var Output_Filter
	 */
	private $output_filter = null;

	/**
	 * @since 3.13.1
	 */
	public function setup() {
		$this->output_filter = new Output_Filter();

		add_action( 'template_redirect', array( $this, 'start_output_filtering' ), -999999 );
	}

	/**
	 * @since 3.13.1
	 */
	public static function activate() {
		( new LCP_Analyzer() )->start();
	}

	/**
	 * @since 3.13.1
	 */
	public static function get_slug() {
		return 'lcp';
	}

	public function get_always_available_endpoints() {
		return array(
			new Update_LCP(),
		);
	}

	/**
	 * @since 3.13.1
	 */
	public static function is_available() {
		if ( defined( 'JETPACK_BOOST_ALPHA_FEATURES' ) && JETPACK_BOOST_ALPHA_FEATURES ) {
			return true;
		}

		return false;
	}

	/**
	 * Check if the module is ready and already serving optimized pages.
	 *
	 * @return bool
	 */
	public function is_ready() {
		return ( new LCP_State() )->is_analyzed();
	}

	/**
	 * Get the action names that will be triggered when the module is ready.
	 *
	 * @return string[]
	 */
	public static function get_change_output_action_names() {
		return array( 'jetpack_boost_lcp_analyzed' );
	}

	/**
	 * Register data sync actions.
	 *
	 * @param Data_Sync $instance The Data_Sync object.
	 */
	public function register_data_sync( $instance ) {
		$instance->register(
			'lcp_state',
			Schema::as_assoc_array(
				array(
					'pages'        => Schema::as_array(
						Schema::as_assoc_array(
							array(
								'key'    => Schema::as_string(),
								'url'    => Schema::as_string(),
								'status' => Schema::as_string(),
							)
						)
					),
					'status'       => Schema::enum( array( 'not_analyzed', 'analyzed', 'pending', 'error' ) )->fallback( 'not_analyzed' ),
					'created'      => Schema::as_float()->nullable(),
					'updated'      => Schema::as_float()->nullable(),
					'status_error' => Schema::as_string()->nullable(),
				)
			)->fallback(
				array(
					'pages'   => array(),
					'status'  => 'not_analyzed',
					'created' => null,
					'updated' => null,
				)
			)
		);
	}

	/**
	 * @since 3.13.1
	 */
	public function start_output_filtering() {
		/**
		 * Filter to disable LCP optimization
		 *
		 * @param bool $optimize return false to disable optimization
		 *
		 * @since   3.13.1
		 */
		if ( false === apply_filters( 'jetpack_boost_should_optimize_lcp', true ) ) {
			return;
		}

		if ( ! Cornerstone_Utils::is_current_page_cornerstone() ) {
			return;
		}

		if ( ! ( new LCP_State() )->is_analyzed() ) {
			return;
		}

		// Disable in robots.txt.
		if ( isset( $_SERVER['REQUEST_URI'] ) && strpos( home_url( wp_unslash( $_SERVER['REQUEST_URI'] ) ), 'robots.txt' ) !== false ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- This is validating.
			return;
		}

		// Disable in other possible AJAX requests setting cors related header.
		if ( isset( $_SERVER['HTTP_SEC_FETCH_MODE'] ) && 'cors' === strtolower( $_SERVER['HTTP_SEC_FETCH_MODE'] ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- This is validating.
			return;
		}

		// Disable in other possible AJAX requests setting XHR related header.
		if ( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && 'xmlhttprequest' === strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- This is validating.
			return;
		}

		// Disable in all XLS (see the WP_Sitemaps_Renderer class).
		if ( isset( $_SERVER['REQUEST_URI'] ) &&
			(
				// phpcs:disable WordPress.Security.ValidatedSanitizedInput -- This is validating.
				str_contains( $_SERVER['REQUEST_URI'], '.xsl' ) ||
				str_contains( $_SERVER['REQUEST_URI'], 'sitemap-stylesheet=index' ) ||
				str_contains( $_SERVER['REQUEST_URI'], 'sitemap-stylesheet=sitemap' )
				// phpcs:enable WordPress.Security.ValidatedSanitizedInput
			) ) {
			return;
		}

		// Disable in all POST Requests.
		// phpcs:disable WordPress.Security.NonceVerification.Missing
		if ( ! empty( $_POST ) ) {
			return;
		}

		// Disable in customizer previews
		if ( is_customize_preview() ) {
			return;
		}

		// Disable in feeds, AJAX, Cron, XML.
		if ( is_feed() || wp_doing_ajax() || wp_doing_cron() || wp_is_xml_request() ) {
			return;
		}

		// Disable in sitemaps.
		if ( ! empty( get_query_var( 'sitemap' ) ) ) {
			return;
		}

		// Disable in AMP pages.
		if ( function_exists( 'amp_is_request' ) && amp_is_request() ) {
			return;
		}

		$this->output_filter->add_callback( array( $this, 'optimize' ) );
	}

	/**
	 * Optimize the HTML content by finding the LCP image and adding required attributes.
	 *
	 * @param string $buffer_start First part of the buffer.
	 * @param string $buffer_end   Second part of the buffer.
	 *
	 * @return array Parts of the buffer.
	 *
	 * @since 3.13.1
	 */
	public function optimize( $buffer_start, $buffer_end ) {
		// Get the LCP image tag from WP option
		$storage = new LCP_Storage();

		$lcp_storage = $storage->get_current_request_lcp();
		// Early return if we don't have any LCP data
		if ( empty( $lcp_storage ) ) {
			return array( $buffer_start, $buffer_end );
		}

		// Combine the buffers for processing
		$combined_buffer = $buffer_start . $buffer_end;

		foreach ( $lcp_storage as $lcp_data ) {
			$combined_buffer = $this->optimize_viewport( $combined_buffer, $lcp_data );
		}

		// Split the modified buffer back into two parts
		$buffer_start_length = strlen( $buffer_start );
		$new_buffer_start    = substr( $combined_buffer, 0, $buffer_start_length );
		$new_buffer_end      = substr( $combined_buffer, $buffer_start_length );

		// Check for successful split
		if ( false === $new_buffer_start || false === $new_buffer_end ) {
			// If splitting failed, return the original buffers
			return array( $buffer_start, $buffer_end );
		}

		return array( $new_buffer_start, $new_buffer_end );
	}

	/**
	 * Optimize a viewport
	 *
	 * @param string $buffer The buffer/html to optimize.
	 * @param array  $lcp_data The LCP data returned from the Cloud.
	 * @return string The optimized buffer, or the original buffer if no optimization was needed
	 *
	 * @since 3.13.1
	 */
	private function optimize_viewport( $buffer, $lcp_data ) {
		if ( empty( $lcp_data ) || empty( $lcp_data['html'] ) ) {
			return $buffer;
		}

		// Defensive check to ensure the LCP HTML is not empty.
		if ( empty( $lcp_data['html'] ) ) {
			return $buffer;
		}

		// Remove the last (closing) character from the LCP HTML in case the buffer adds a closing forward slash to the img tag. Which is not found by the Cloud.
		$lcp_html = substr( $lcp_data['html'], 0, -1 );

		// If the LCP HTML is not found in the buffer, return early.
		if ( ! str_contains( $buffer, $lcp_html ) ) {
			return $buffer;
		}

		// Create the optimized tag with required attributes.
		$optimized_tag = $this->optimize_image_tag( $lcp_html );

		// If no optimization was needed, return early.
		if ( $optimized_tag === $lcp_html ) {
			return $buffer;
		}

		return str_replace( $lcp_html, $optimized_tag, $buffer );
	}

	/**
	 * Optimize an image tag by adding required attributes.
	 *
	 * @param string $tag The original image tag.
	 * @return string The optimized image tag.
	 *
	 * @since 3.13.1
	 */
	private function optimize_image_tag( $tag ) {
		// Add fetchpriority="high" if not present
		if ( ! preg_match( '/fetchpriority\s*=\s*["\']high["\']/i', $tag ) ) {
			$tag = preg_replace( '/<img\s/i', '<img fetchpriority="high" ', $tag );
		}

		// Add loading="eager" if not present
		if ( ! preg_match( '/loading\s*=\s*["\']eager["\']/i', $tag ) ) {
			$tag = preg_replace( '/<img\s/i', '<img loading="eager" ', $tag );
		}

		return $tag;
	}
}


??

??