*
* @copyright (c) 2018, Incsub (http://incsub.com)
*/
if ( ! class_exists( 'WpSmushCDN' ) ) {
class WpSmushCDN {
/**
* Smush CDN base url.
*
* @var null|string
*/
var $cdn_base = null;
/**
* Flag to check if CDN is active.
*
* @var bool
*/
var $cdn_active = false;
/**
* WPMUDEV API key for the member.
*
* @var null
*/
var $api_key = null;
/**
* WpSmushCDN constructor.
*/
public function __construct() {
// Set auto resize flag.
add_action( 'wp', array( $this, 'init_flags' ) );
// Set Smush API config.
add_action( 'init', array( $this, 'set_cdn_url' ) );
// Start an output buffer before any output starts.
add_action( 'template_redirect', array( $this, 'process_buffer' ), 1 );
// Hook into CDN settings section.
add_action( 'smush_cdn_settings_ui', array( $this, 'ui' ) );
// Add cdn url to dns prefetch.
add_filter( 'wp_resource_hints', array( $this, 'dns_prefetch' ), 99, 2 );
}
/**
* Set the API base for the member.
*
* @return void
*/
public function set_cdn_url() {
// Get the user id of current member.
// @todo handle this.
$user_id = 0;
// Site id to help mapping multisite installations.
$site_id = get_current_blog_id();
// This is member's custom cdn path.
$this->cdn_base = trailingslashit( "https://{$user_id}.smushcdn.com/{$site_id}" );
// $this->cdn_base = trailingslashit( "http://localhost" );
}
/**
* Initialize required flags.
*
* @return void
*/
public function init_flags() {
global $wp_smush;
// @todo handle this after implementing CDN settings.
$this->cdn_active = false;
// All these are members only feature.
if ( ! $wp_smush->validate_install() ) {
return;
}
}
/**
* Admin UI section for the CDN settings.
*
* @return void
*/
public function ui() {
global $wpsmush_bulkui;
echo '
';
// Container header.
$wpsmush_bulkui->container_header( esc_html__( 'CDN', 'wp-smushit' ) );
echo '
';
echo '
';
}
/**
* Generate CDN url from given image url.
*
* @param string $src Image url.
* @param array $args Query parameters.
*
* @return string
*/
public function generate_cdn_url( $src, $args = array() ) {
global $wp_smush;
// Do not continue incase we try this when cdn is disabled.
if ( ! $this->cdn_active ) {
return $src;
}
// Parse url to get all parts.
$url_parts = parse_url( $src );
// If path not found, do not continue.
if ( empty( $url_parts['path'] ) ) {
return $src;
}
// Arguments for CDN.
$pro_args = array(
'lossy' => $wp_smush->lossy_enabled ? 1 : 0,
'strip' => $wp_smush->keep_exif ? 0 : 1,
'webp' => 0,
);
$args = wp_parse_args( $pro_args, $args );
// Replace base url with cdn base.
$url = $this->cdn_base . ltrim( $url_parts['path'], '/' );
// Now we need to add our CDN parameters for resizing.
$url = add_query_arg( $args, $url );
return $url;
}
/**
* Starts an output buffer and register the callback function.
*
* Register callback function that adds attachment ids of images
* those are from media library and has an attachment id.
*
* @uses ob_start()
*
* @return void
*/
public function process_buffer() {
ob_start( array( $this, 'process_img_tags' ) );
}
/**
* Process images from current buffer content.
*
* Use DOMDocument class to find all available images
* in current HTML content and set attachmet id attribute.
*
* @param string $content Current buffer content.
*
* @return string
*/
public function process_img_tags( $content ) {
$content = mb_convert_encoding( $content, 'HTML-ENTITIES', 'UTF-8' );
$document = new DOMDocument();
libxml_use_internal_errors( true );
$document->loadHTML( utf8_decode( $content ) );
// Get images from current DOM elements.
$images = $document->getElementsByTagName( 'img' );
// If images found, set attachment ids.
if ( ! empty( $images ) ) {
/**
* Action hook to modify DOM images.
*
* Images are saved at the end of this function. So no need
* to return anything in this hook.
*/
do_action( 'smush_images_from_content', $images );
$this->process_images( $images );
}
return $document->saveHTML();
}
/**
* Set attachment IDs of images as data.
*
* Get attachment ids from urls and set new data
* property to img.
* We can use WP_Query to find attachment ids of
* all images on current page content.
*
* @param array $images Current page images.
*
* @return void
*/
public function process_images( $images ) {
$dir = wp_upload_dir();
// Loop through each image.
foreach ( $images as $key => $image ) {
// Get the src value.
$src = $image->getAttribute( 'src' );
// Make sure this image is inside upload directory.
if ( false === strpos( $src, $dir['baseurl'] . '/' ) ) {
continue;
}
/**
* Filter to skip a single image from cdn.
*
* @param bool false Should skip?
* @param string $img_url Image url.
* @param array|bool $image Image object or false.
*/
if ( apply_filters( 'smush_skip_image_from_cdn', false, $src, $image ) ) {
continue;
}
/**
* Filter hook to alter image src arguments before going through cdn.
*
* @param array $args Arguments.
* @param string $src Image src.
* @param object $image Image tag object.
*/
$args = apply_filters( 'smush_image_cdn_args', array(), $image );
/**
* Filter hook to alter image src before going through cdn.
*
* @param string $src Image src.
* @param object $image Image tag object.
*/
$src = apply_filters( 'smush_image_src_before_cdn', $src, $image );
// Do not continue if CDN is not active.
if ( $this->cdn_active ) {
// Generate cdn url from local url.
$src = $this->generate_cdn_url( $src, $args );
/**
* Filter hook to alter image src after replacing with CDN base.
*
* @param string $src Image src.
* @param object $image Image tag object.
*/
$src = apply_filters( 'smush_image_src_after_cdn', $src, $image );
}
// Update src with cdn url.
$image->setAttribute( 'src', $src );
}
}
/**
* Add CDN url to header for better speed.
*
* @param array $urls URLs to print for resource hints.
* @param string $relation_type The relation type the URLs are printed.
*
* @return array
*/
public function dns_prefetch( $urls, $relation_type ) {
// Add only if CDN active.
if ( 'dns-prefetch' === $relation_type && $this->cdn_active && ! empty( $this->cdn_base ) ) {
$urls[] = $this->cdn_base;
}
return $urls;
}
}
global $wpsmush_cdn;
$wpsmush_cdn = new WpSmushCDN();
}