add wp-rocket
This commit is contained in:
@@ -0,0 +1,245 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Addon\GoogleTracking;
|
||||
|
||||
use WP_Rocket\Addon\Busting\FileBustingTrait;
|
||||
use WP_Rocket\Busting\Abstract_Busting;
|
||||
use WP_Rocket\Logger\Logger;
|
||||
|
||||
/**
|
||||
* Manages the cache busting of the Google Analytics file.
|
||||
*
|
||||
* @since 3.1
|
||||
*/
|
||||
class GoogleAnalytics extends Abstract_Busting {
|
||||
use FileBustingTrait;
|
||||
|
||||
/**
|
||||
* Context used for the logger.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.4
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
const LOGGER_CONTEXT = 'gg analytics';
|
||||
|
||||
/**
|
||||
* Google Analytics URL.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.1
|
||||
* @access protected
|
||||
* @author Remy Perona
|
||||
*/
|
||||
protected $url = 'https://www.google-analytics.com/analytics.js';
|
||||
|
||||
/**
|
||||
* File name (local).
|
||||
* %s is a "version": a md5 hash of the file contents.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.4
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
protected $filename_pattern = 'ga-%s.js';
|
||||
|
||||
/**
|
||||
* Current file version (local): a md5 hash of the file contents.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.4
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
protected $file_version;
|
||||
|
||||
/**
|
||||
* Flag to track the replacement.
|
||||
*
|
||||
* @var bool
|
||||
* @since 3.1
|
||||
* @access protected
|
||||
* @author Remy Perona
|
||||
*/
|
||||
protected $is_replaced = false;
|
||||
|
||||
/**
|
||||
* Filesystem object.
|
||||
*
|
||||
* @var object
|
||||
* @since 3.2.4
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
protected $filesystem = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 3.1
|
||||
* @access public
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @param string $busting_path Path to the busting directory.
|
||||
* @param string $busting_url URL of the busting directory.
|
||||
*/
|
||||
public function __construct( $busting_path, $busting_url ) {
|
||||
$this->busting_path = $busting_path . 'google-tracking/';
|
||||
$this->busting_url = $busting_url . 'google-tracking/';
|
||||
$this->filesystem = rocket_direct_filesystem();
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** PUBLIC METHODS ========================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Performs the replacement process.
|
||||
*
|
||||
* @since 3.1
|
||||
* @access public
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @param string $html HTML content.
|
||||
* @return string
|
||||
*/
|
||||
public function replace_url( $html ) {
|
||||
$this->is_replaced = false;
|
||||
|
||||
$tag = $this->find( '<script\s*(?<attr>[^>]*)?>(?<content>.*)?<\/script>', $html );
|
||||
|
||||
if ( ! $tag ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
Logger::info(
|
||||
'GOOGLE ANALYTICS CACHING PROCESS STARTED.',
|
||||
[
|
||||
self::LOGGER_CONTEXT,
|
||||
'tag' => $tag,
|
||||
]
|
||||
);
|
||||
|
||||
if ( ! $this->save( $this->url ) ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
$replace_tag = preg_replace( '/(?:https?:)?\/\/www\.google-analytics\.com\/analytics\.js/i', $this->get_busting_url(), $tag );
|
||||
$html = str_replace( $tag, $replace_tag, $html );
|
||||
|
||||
$this->is_replaced = true;
|
||||
|
||||
Logger::info(
|
||||
'Google Analytics caching process succeeded.',
|
||||
[
|
||||
self::LOGGER_CONTEXT,
|
||||
'file' => $this->get_busting_path(),
|
||||
]
|
||||
);
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the replacement was sucessful or not.
|
||||
*
|
||||
* @since 3.1
|
||||
* @access public
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_replaced() {
|
||||
return $this->is_replaced;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the content of the URL to cache to the busting file.
|
||||
*
|
||||
* @since 3.2.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $url URL to get the content from.
|
||||
* @return bool
|
||||
*/
|
||||
public function refresh_save( $url ) {
|
||||
// Before doing anything, make sure the busting file can be created.
|
||||
if ( ! $this->is_busting_dir_writable() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get remote content.
|
||||
$content = $this->get_remote_contents( $url );
|
||||
|
||||
if ( ! $content ) {
|
||||
// Could not get the remote contents.
|
||||
return false;
|
||||
}
|
||||
|
||||
$version = md5( $content );
|
||||
$path = $this->get_busting_file_path( $version );
|
||||
|
||||
return $this->update_file_contents( $path, $content );
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** REMOTE FILE ============================================================================= */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the Google Analytics URL.
|
||||
*
|
||||
* @since 3.1
|
||||
* @access public
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_url() {
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** VARIOUS INTERNAL TOOLS ================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Searches for element(s) in the DOM.
|
||||
*
|
||||
* @since 3.1
|
||||
* @access public
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @param string $pattern Pattern to match.
|
||||
* @param string $html HTML content.
|
||||
* @return string
|
||||
*/
|
||||
protected function find( $pattern, $html ) {
|
||||
preg_match_all( '/' . $pattern . '/si', $html, $all_matches, PREG_SET_ORDER );
|
||||
|
||||
$matches = array_map(
|
||||
function( $match ) {
|
||||
|
||||
if (
|
||||
! preg_match( '/src\s*=\s*[\'"]\s*(?:https?:)?\/\/www\.google-analytics\.com\/analytics\.js\s*[\'"]/i', $match['attr'] . $match['content'] )
|
||||
&&
|
||||
false === strpos( $match['content'], 'GoogleAnalyticsObject' )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $match[0];
|
||||
},
|
||||
$all_matches
|
||||
);
|
||||
|
||||
$matches = array_values( array_filter( $matches ) );
|
||||
|
||||
if ( ! $matches ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $matches[0];
|
||||
}
|
||||
}
|
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Addon\GoogleTracking;
|
||||
|
||||
use WP_Rocket\Addon\Busting\FileBustingTrait;
|
||||
use WP_Rocket\Logger\Logger;
|
||||
use WP_Rocket\Busting\Abstract_Busting;
|
||||
use WP_Filesystem_Direct;
|
||||
|
||||
/**
|
||||
* Manages the cache busting of the Google Tag Manager file
|
||||
*
|
||||
* @since 3.1
|
||||
*/
|
||||
class GoogleTagManager extends Abstract_Busting {
|
||||
use FileBustingTrait;
|
||||
|
||||
/**
|
||||
* Context used for the logger.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.4
|
||||
*/
|
||||
const LOGGER_CONTEXT = 'gg tag manager';
|
||||
|
||||
/**
|
||||
* File name (local).
|
||||
* %s is a "version": a md5 hash of the file contents.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.4
|
||||
* @access protected
|
||||
*/
|
||||
protected $filename_pattern = 'gtm-%s.js';
|
||||
|
||||
/**
|
||||
* Current file version (local): a md5 hash of the file contents.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.4
|
||||
* @access protected
|
||||
*/
|
||||
protected $file_version;
|
||||
|
||||
/**
|
||||
* Filesystem object.
|
||||
*
|
||||
* @var object
|
||||
* @since 3.2.4
|
||||
* @access protected
|
||||
*/
|
||||
protected $filesystem = false;
|
||||
|
||||
/**
|
||||
* Google Analytics object.
|
||||
*
|
||||
* @var object
|
||||
* @since 3.2.4
|
||||
* @access protected
|
||||
*/
|
||||
protected $ga_busting = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 3.1
|
||||
* @access public
|
||||
*
|
||||
* @param string $busting_path Path to the busting directory.
|
||||
* @param string $busting_url URL of the busting directory.
|
||||
* @param GoogleAnalytics $ga_busting A GoogleAnalytics instance.
|
||||
* @param WP_Filesystem_Direct $filesystem Instance of the filesystem handler.
|
||||
*/
|
||||
public function __construct( $busting_path, $busting_url, GoogleAnalytics $ga_busting, $filesystem = null ) {
|
||||
$blog_id = get_current_blog_id();
|
||||
$this->busting_path = $busting_path . $blog_id . '/';
|
||||
$this->busting_url = $busting_url . $blog_id . '/';
|
||||
$this->ga_busting = $ga_busting;
|
||||
$this->filesystem = is_null( $filesystem ) ? rocket_direct_filesystem() : $filesystem;
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** PUBLIC METHODS ========================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Performs the replacement process.
|
||||
*
|
||||
* @since 3.1
|
||||
* @access public
|
||||
*
|
||||
* @param string $html HTML content.
|
||||
* @return string
|
||||
*/
|
||||
public function replace_url( $html ) {
|
||||
$script = $this->find( '<script(\s+[^>]+)?\s+src\s*=\s*[\'"]\s*?((?:https?:)?\/\/www\.googletagmanager\.com(?:.+)?)\s*?[\'"]([^>]+)?\/?>', $html );
|
||||
|
||||
if ( ! $script ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
// replace relative protocol // with full https://.
|
||||
$gtm_url = preg_replace( '/^\/\//', 'https://', $script[2] );
|
||||
|
||||
Logger::info(
|
||||
'GOOGLE TAG MANAGER CACHING PROCESS STARTED.',
|
||||
[
|
||||
self::LOGGER_CONTEXT,
|
||||
'tag' => $script,
|
||||
]
|
||||
);
|
||||
|
||||
if ( ! $this->save( $gtm_url ) ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
$replace_script = str_replace( $script[2], $this->get_busting_url(), $script[0] );
|
||||
$replace_script = str_replace( '<script', '<script data-no-minify="1"', $replace_script );
|
||||
$html = str_replace( $script[0], $replace_script, $html );
|
||||
|
||||
Logger::info(
|
||||
'Google Tag Manager caching process succeeded.',
|
||||
[
|
||||
self::LOGGER_CONTEXT,
|
||||
'file' => $this->get_busting_path(),
|
||||
]
|
||||
);
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the content of the URL to cache to the busting file.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
*
|
||||
* @param string $url URL to get the content from.
|
||||
* @return bool
|
||||
*/
|
||||
public function refresh_save( $url ) {
|
||||
// Before doing anything, make sure the busting file can be created.
|
||||
if ( ! $this->is_busting_dir_writable() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get remote content.
|
||||
$content = $this->get_remote_contents( $url );
|
||||
|
||||
if ( ! $content ) {
|
||||
// Could not get the remote contents.
|
||||
return false;
|
||||
}
|
||||
|
||||
$version = md5( $content );
|
||||
$path = $this->get_busting_file_path( $version );
|
||||
$content = $this->replace_ga_url( $content );
|
||||
|
||||
return $this->update_file_contents( $path, $content );
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** VARIOUS INTERNAL TOOLS ================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Searches for element(s) in the DOM.
|
||||
*
|
||||
* @since 3.1
|
||||
* @access public
|
||||
*
|
||||
* @param string $pattern Pattern to match.
|
||||
* @param string $html HTML content.
|
||||
* @return string
|
||||
*/
|
||||
protected function find( $pattern, $html ) {
|
||||
preg_match_all( '/' . $pattern . '/Umsi', $html, $matches, PREG_SET_ORDER );
|
||||
|
||||
if ( empty( $matches ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the Google Analytics URL by the local copy inside the gtm-local.js file content
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* @param string $content JavaScript content.
|
||||
* @return string
|
||||
*/
|
||||
protected function replace_ga_url( $content ) {
|
||||
if ( ! $this->ga_busting->save( $this->ga_busting->get_url() ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
return str_replace( $this->ga_busting->get_url(), $this->ga_busting->get_busting_url(), $content );
|
||||
}
|
||||
}
|
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Addon\GoogleTracking;
|
||||
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
use WP_Rocket\Addon\Busting\BustingFactory;
|
||||
use WP_Rocket\Admin\Options_Data as Options;
|
||||
|
||||
/**
|
||||
* Event subscriber for Google tracking cache busting
|
||||
*
|
||||
* @since 3.1
|
||||
*/
|
||||
class Subscriber implements Subscriber_Interface {
|
||||
|
||||
/**
|
||||
* Instance of the Busting Factory class
|
||||
*
|
||||
* @var BustingFactory
|
||||
*/
|
||||
private $busting_factory;
|
||||
|
||||
/**
|
||||
* Instance of the Option_Data class
|
||||
*
|
||||
* @var Options
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param BustingFactory $busting_factory Instance of the Busting Factory class.
|
||||
* @param Options $options Instance of the Option_Data class.
|
||||
*/
|
||||
public function __construct( BustingFactory $busting_factory, Options $options ) {
|
||||
$this->busting_factory = $busting_factory;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
$events = [
|
||||
'cron_schedules' => 'add_schedule',
|
||||
'init' => 'schedule_tracking_cache_update',
|
||||
'rocket_google_tracking_cache_update' => 'update_tracking_cache',
|
||||
'rocket_purge_cache' => 'delete_tracking_cache',
|
||||
'rocket_buffer' => 'cache_busting_google_tracking',
|
||||
];
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the cache busting on the HTML content
|
||||
*
|
||||
* Google Analytics replacement is performed first, and if no replacement occured, Google Tag Manager replacement is performed.
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* @param string $html HTML content.
|
||||
* @return string
|
||||
*/
|
||||
public function cache_busting_google_tracking( $html ) {
|
||||
if ( ! $this->is_allowed() ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
$processor = $this->busting_factory->type( 'ga' );
|
||||
$html = $processor->replace_url( $html );
|
||||
|
||||
$processor = $this->busting_factory->type( 'gtm' );
|
||||
$html = $processor->replace_url( $html );
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules the auto-update of Google Analytics cache busting file
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function schedule_tracking_cache_update() {
|
||||
if ( ! $this->is_busting_active() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! wp_next_scheduled( 'rocket_google_tracking_cache_update' ) ) {
|
||||
wp_schedule_event( time(), 'weekly', 'rocket_google_tracking_cache_update' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates Google Analytics cache busting file
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update_tracking_cache() {
|
||||
if ( ! $this->is_busting_active() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$processor = $this->busting_factory->type( 'ga' );
|
||||
|
||||
return $processor->refresh_save( $processor->get_url() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds weekly interval to cron schedules
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* @param Array $schedules An array of intervals used by cron jobs.
|
||||
* @return Array
|
||||
*/
|
||||
public function add_schedule( $schedules ) {
|
||||
if ( ! $this->is_busting_active() ) {
|
||||
return $schedules;
|
||||
}
|
||||
|
||||
$schedules['weekly'] = [
|
||||
'interval' => 604800,
|
||||
'display' => __( 'weekly', 'rocket' ),
|
||||
];
|
||||
|
||||
return $schedules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the GA busting file.
|
||||
*
|
||||
* @since 3.1
|
||||
* @since 3.6 Argument replacement.
|
||||
*
|
||||
* @param string $type Type of cache clearance: 'all', 'post', 'term', 'user', 'url'.
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_tracking_cache( $type ) {
|
||||
if ( 'all' !== $type || ! $this->is_busting_active() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->busting_factory->type( 'gtm' )->delete();
|
||||
|
||||
return $this->busting_factory->type( 'ga' )->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the cache busting should happen
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function is_allowed() {
|
||||
if ( rocket_get_constant( 'DONOTROCKETOPTIMIZE' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->is_busting_active();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the cache busting option is active.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_busting_active() {
|
||||
return (bool) $this->options->get( 'google_analytics_cache', 0 );
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user