Plugin Directory

Changeset 1969996


Ignore:
Timestamp:
11/06/2018 05:32:36 PM (7 years ago)
Author:
piio
Message:

tagging version 0.9.8

Location:
piio-image-optimization
Files:
8 edited
1 copied

Legend:

Unmodified
Added
Removed
  • piio-image-optimization/tags/0.9.8/includes/class-piio-image-optimization.php

    r1921770 r1969996  
    2929*/
    3030if ( !class_exists( 'Piio_Image_Optimization' ) ) {
    31     class Piio_Image_Optimization {
    32 
    33         /**
    34         * The loader that's responsible for maintaining and registering all hooks that power
    35         * the plugin.
    36         *
    37         * @since    0.9.0
    38         * @access   protected
    39         * @var      Piio_Image_Optimization_Loader    $loader    Maintains and registers all hooks for the plugin.
    40         */
    41         protected $loader;
    42 
    43         /**
    44         * The unique identifier of this plugin.
    45         *
    46         * @since    0.9.0
    47         * @access   protected
    48         * @var      string    $plugin_name    The string used to uniquely identify this plugin.
    49         */
    50         protected $plugin_name;
    51 
    52         /**
    53         * The current version of the plugin.
    54         *
    55         * @since    0.9.0
    56         * @access   protected
    57         * @var      string    $version    The current version of the plugin.
    58         */
    59         protected $version;
    60 
    61         /**
    62         * Define the core functionality of the plugin.
    63         *
    64         * Set the plugin name and the plugin version that can be used throughout the plugin.
    65         * Load the dependencies, define the locale, and set the hooks for the admin area and
    66         * the public-facing side of the site.
    67         *
    68         * @since    0.9.0
    69         */
    70         public function __construct() {
    71             if ( defined( 'PIIO_IMAGE_OPTIMIZATION_VERSION' ) ) {
    72                 $this->version = PIIO_IMAGE_OPTIMIZATION_VERSION;
    73             } else {
    74                 $this->version = '0.9.0';
    75             }
    76             $this->plugin_name = 'piio-image-optimization';
    77 
    78             $this->load_dependencies();
    79             $this->set_locale();
    80             if ( is_admin() ) {
    81                 $this->define_admin_hooks();
    82             }
    83             $this->define_public_hooks();
    84 
    85         }
    86 
    87         /**
    88         * Load the required dependencies for this plugin.
    89         *
    90         * Include the following files that make up the plugin:
    91         *
    92         * - Piio_Image_Optimization_Loader. Orchestrates the hooks of the plugin.
    93         * - Piio_Image_Optimization_i18n. Defines internationalization functionality.
    94         * - Piio_Image_Optimization_Admin. Defines all hooks for the admin area.
    95         * - Piio_Image_Optimization_Public. Defines all hooks for the public side of the site.
    96         *
    97         * Create an instance of the loader which will be used to register the hooks
    98         * with WordPress.
    99         *
    100         * @since    0.9.0
    101         * @access   private
    102         */
    103         private function load_dependencies() {
    104 
    105             /**
    106             * The class responsible for orchestrating the actions and filters of the
    107             * core plugin.
    108             */
    109             require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-piio-image-optimization-loader.php';
    110 
    111             /**
    112             * The class responsible for defining internationalization functionality
    113             * of the plugin.
    114             */
    115             require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-piio-image-optimization-i18n.php';
    116 
    117             /**
    118             * The class responsible for defining all actions that occur in the admin area.
    119             */
    120             require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-piio-image-optimization-admin.php';
    121 
    122             /**
    123             * The class responsible for defining all actions that occur in the public-facing
    124             * side of the site.
    125             */
    126             require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-piio-image-optimization-public.php';
    127 
    128             $this->loader = new Piio_Image_Optimization_Loader();
    129 
    130         }
    131 
    132         /**
    133         * Define the locale for this plugin for internationalization.
    134         *
    135         * Uses the Piio_Image_Optimization_i18n class in order to set the domain and to register the hook
    136         * with WordPress.
    137         *
    138         * @since    0.9.0
    139         * @access   private
    140         */
    141         private function set_locale() {
    142 
    143             $plugin_i18n = new Piio_Image_Optimization_i18n();
    144 
    145             $this->loader->add_action( 'plugins_loaded', $plugin_i18n, 'load_plugin_textdomain' );
    146 
    147         }
    148 
    149         /**
    150         * Register all of the hooks related to the admin area functionality
    151         * of the plugin.
    152         *
    153         * @since    0.9.0
    154         * @access   private
    155         */
    156         private function define_admin_hooks() {
    157 
    158             $plugin_admin = new Piio_Image_Optimization_Admin( $this->get_plugin_name(), $this->get_version() );
    159             $this->loader->add_action( 'admin_menu', $plugin_admin, 'display_admin_page');
    160             $this->loader->add_action( 'admin_init', $plugin_admin, 'setup_sections');
    161             $this->loader->add_action( 'admin_init', $plugin_admin, 'setup_fields');
    162             $this->loader->add_action( 'admin_init', $plugin_admin, 'check_piio_incompatibility');
    163             $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
    164             $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
    165 
    166         }
    167 
    168         /**
    169         * Register all of the hooks related to the public-facing functionality
    170         * of the plugin.
    171         *
    172         * @since    0.9.0
    173         * @access   private
    174         */
    175         private function define_public_hooks() {
    176 
    177             $plugin_public = new Piio_Image_Optimization_Public( $this->get_plugin_name(), $this->get_version() );
    178             $piio_enabled_option = get_option('piio_imageopt_enabled');
    179             $is_piio_enabled = (isset($piio_enabled_option[0])) ? ($piio_enabled_option[0] === "1") : false;
    180 
    181             if ($is_piio_enabled && !is_admin()){
    182                 ob_start();
    183                 $this->loader->add_action( 'shutdown', $plugin_public, 'create_final_output_filter', -100 );
    184 
    185                 $this->loader->add_filter( 'piio_final_output', $plugin_public, 'filter_images' );
    186                 // If site is using WPSupercache, we just hook it
    187                 $this->loader->add_filter( 'wpsupercache_buffer', $plugin_public, 'filter_images' );
    188             }
    189 
    190             $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' );
    191 
    192         }
    193 
    194         /**
    195         * Run the loader to execute all of the hooks with WordPress.
    196         *
    197         * @since    0.9.0
    198         */
    199         public function run() {
    200             $this->loader->run();
    201         }
    202 
    203         /**
    204         * The name of the plugin used to uniquely identify it within the context of
    205         * WordPress and to define internationalization functionality.
    206         *
    207         * @since     0.9.0
    208         * @return    string    The name of the plugin.
    209         */
    210         public function get_plugin_name() {
    211             return $this->plugin_name;
    212         }
    213 
    214         /**
    215         * The reference to the class that orchestrates the hooks with the plugin.
    216         *
    217         * @since     0.9.0
    218         * @return    Piio_Image_Optimization_Loader    Orchestrates the hooks of the plugin.
    219         */
    220         public function get_loader() {
    221             return $this->loader;
    222         }
    223 
    224         /**
    225         * Retrieve the version number of the plugin.
    226         *
    227         * @since     0.9.0
    228         * @return    string    The version number of the plugin.
    229         */
    230         public function get_version() {
    231             return $this->version;
    232         }
    233 
    234     }
     31    class Piio_Image_Optimization {
     32
     33        /**
     34        * The loader that's responsible for maintaining and registering all hooks that power
     35        * the plugin.
     36        *
     37        * @since    0.9.0
     38        * @access   protected
     39        * @var      Piio_Image_Optimization_Loader    $loader    Maintains and registers all hooks for the plugin.
     40        */
     41        protected $loader;
     42
     43        /**
     44        * The unique identifier of this plugin.
     45        *
     46        * @since    0.9.0
     47        * @access   protected
     48        * @var      string    $plugin_name    The string used to uniquely identify this plugin.
     49        */
     50        protected $plugin_name;
     51
     52        /**
     53        * The current version of the plugin.
     54        *
     55        * @since    0.9.0
     56        * @access   protected
     57        * @var      string    $version    The current version of the plugin.
     58        */
     59        protected $version;
     60
     61        /**
     62        * Define the core functionality of the plugin.
     63        *
     64        * Set the plugin name and the plugin version that can be used throughout the plugin.
     65        * Load the dependencies, define the locale, and set the hooks for the admin area and
     66        * the public-facing side of the site.
     67        *
     68        * @since    0.9.0
     69        */
     70        public function __construct() {
     71            if ( defined( 'PIIO_IMAGE_OPTIMIZATION_VERSION' ) ) {
     72                $this->version = PIIO_IMAGE_OPTIMIZATION_VERSION;
     73            } else {
     74                $this->version = '0.9.0';
     75            }
     76            $this->plugin_name = 'piio-image-optimization';
     77
     78            $this->load_dependencies();
     79            $this->set_locale();
     80            if ( is_admin() ) {
     81                $this->define_admin_hooks();
     82            }
     83            $this->define_public_hooks();
     84
     85        }
     86
     87        /**
     88        * Load the required dependencies for this plugin.
     89        *
     90        * Include the following files that make up the plugin:
     91        *
     92        * - Piio_Image_Optimization_Loader. Orchestrates the hooks of the plugin.
     93        * - Piio_Image_Optimization_i18n. Defines internationalization functionality.
     94        * - Piio_Image_Optimization_Admin. Defines all hooks for the admin area.
     95        * - Piio_Image_Optimization_Public. Defines all hooks for the public side of the site.
     96        *
     97        * Create an instance of the loader which will be used to register the hooks
     98        * with WordPress.
     99        *
     100        * @since    0.9.0
     101        * @access   private
     102        */
     103        private function load_dependencies() {
     104
     105            /**
     106            * The class responsible for orchestrating the actions and filters of the
     107            * core plugin.
     108            */
     109            require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-piio-image-optimization-loader.php';
     110
     111            /**
     112            * The class responsible for defining internationalization functionality
     113            * of the plugin.
     114            */
     115            require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-piio-image-optimization-i18n.php';
     116
     117            /**
     118            * The class responsible for defining all actions that occur in the admin area.
     119            */
     120            require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-piio-image-optimization-admin.php';
     121
     122            /**
     123            * The class responsible for defining all actions that occur in the public-facing
     124            * side of the site.
     125            */
     126            require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-piio-image-optimization-public.php';
     127
     128            $this->loader = new Piio_Image_Optimization_Loader();
     129
     130        }
     131
     132        /**
     133        * Define the locale for this plugin for internationalization.
     134        *
     135        * Uses the Piio_Image_Optimization_i18n class in order to set the domain and to register the hook
     136        * with WordPress.
     137        *
     138        * @since    0.9.0
     139        * @access   private
     140        */
     141        private function set_locale() {
     142
     143            $plugin_i18n = new Piio_Image_Optimization_i18n();
     144
     145            $this->loader->add_action( 'plugins_loaded', $plugin_i18n, 'load_plugin_textdomain' );
     146
     147        }
     148
     149        /**
     150        * Register all of the hooks related to the admin area functionality
     151        * of the plugin.
     152        *
     153        * @since    0.9.0
     154        * @access   private
     155        */
     156        private function define_admin_hooks() {
     157
     158            $plugin_admin = new Piio_Image_Optimization_Admin( $this->get_plugin_name(), $this->get_version() );
     159            $this->loader->add_action( 'admin_menu', $plugin_admin, 'display_admin_page');
     160            $this->loader->add_action( 'admin_init', $plugin_admin, 'setup_sections');
     161            $this->loader->add_action( 'admin_init', $plugin_admin, 'setup_fields');
     162            $this->loader->add_action( 'admin_init', $plugin_admin, 'check_piio_incompatibility');
     163            $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
     164            $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
     165
     166        }
     167
     168        /**
     169        * Register all of the hooks related to the public-facing functionality
     170        * of the plugin.
     171        *
     172        * @since    0.9.0
     173        * @access   private
     174        */
     175        private function define_public_hooks() {
     176
     177            $plugin_public = new Piio_Image_Optimization_Public( $this->get_plugin_name(), $this->get_version() );
     178            $piio_enabled_option = get_option('piio_imageopt_enabled');
     179            $is_piio_enabled = (isset($piio_enabled_option[0])) ? ($piio_enabled_option[0] === "1") : false;
     180
     181            if ($is_piio_enabled && !is_admin()){
     182                ob_start();
     183                $this->loader->add_action( 'shutdown', $plugin_public, 'create_final_output_filter', -100 );
     184
     185                $this->loader->add_filter( 'piio_final_output', $plugin_public, 'filter_images' );
     186
     187                /* Cache plugins compatibility */
     188
     189                // WP Super Cache
     190                $this->loader->add_filter( 'wpsupercache_buffer', $plugin_public, 'filter_images' );
     191
     192                // W3 Total Cache 0.9.7+
     193                $this->loader->add_filter( 'w3tc_process_content', $plugin_public, 'filter_images' );
     194            }
     195
     196            $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' );
     197
     198        }
     199
     200        /**
     201        * Run the loader to execute all of the hooks with WordPress.
     202        *
     203        * @since    0.9.0
     204        */
     205        public function run() {
     206            $this->loader->run();
     207        }
     208
     209        /**
     210        * The name of the plugin used to uniquely identify it within the context of
     211        * WordPress and to define internationalization functionality.
     212        *
     213        * @since     0.9.0
     214        * @return    string    The name of the plugin.
     215        */
     216        public function get_plugin_name() {
     217            return $this->plugin_name;
     218        }
     219
     220        /**
     221        * The reference to the class that orchestrates the hooks with the plugin.
     222        *
     223        * @since     0.9.0
     224        * @return    Piio_Image_Optimization_Loader    Orchestrates the hooks of the plugin.
     225        */
     226        public function get_loader() {
     227            return $this->loader;
     228        }
     229
     230        /**
     231        * Retrieve the version number of the plugin.
     232        *
     233        * @since     0.9.0
     234        * @return    string    The version number of the plugin.
     235        */
     236        public function get_version() {
     237            return $this->version;
     238        }
     239
     240    }
    235241}
  • piio-image-optimization/tags/0.9.8/piio-image-optimization.php

    r1954139 r1969996  
    1313* Plugin URI:        https://piio.co/wordpress
    1414* Description:       Generates responsive and optimized images, so you don't have to.
    15 * Version:           0.9.7
     15* Version:           0.9.8
    1616* Author:            Piio, Inc.
    1717* Author URI:        https://piio.co
     
    3030* Currently plugin version.
    3131*/
    32 define( 'PIIO_IMAGE_OPTIMIZATION_VERSION', '0.9.7' );
     32define( 'PIIO_IMAGE_OPTIMIZATION_VERSION', '0.9.8' );
    3333
    3434/**
  • piio-image-optimization/tags/0.9.8/public/class-piio-image-optimization-public.php

    r1954139 r1969996  
    2121* @author     Piio, Inc. <support@piio.co>
    2222*/
    23 if ( !class_exists( 'Piio_Image_Optimization_Public' ) ) {
    24     class Piio_Image_Optimization_Public {
    25 
    26         /**
    27         * The ID of this plugin.
    28         *
    29         * @since    0.9.0
    30         * @access   private
    31         * @var      string    $plugin_name    The ID of this plugin.
    32         */
    33         private $plugin_name;
    34 
    35         /**
    36         * The version of this plugin.
    37         *
    38         * @since    0.9.0
    39         * @access   private
    40         * @var      string    $version    The current version of this plugin.
    41         */
    42         private $version;
    43 
    44         /**
    45         * Initialize the class and set its properties.
    46         *
    47         * @since    0.9.0
    48         * @param      string    $plugin_name       The name of the plugin.
    49         * @param      string    $version    The version of this plugin.
    50         */
    51         public function __construct( $plugin_name, $version ) {
    52 
    53             $this->plugin_name = $plugin_name;
    54             $this->version = $version;
    55 
    56         }
    57 
    58         public function create_final_output_filter(){
    59             $final = '';
    60             $levels = ob_get_level();
    61             for ($i = 0; $i < $levels; $i++) {
    62                 $final .= ob_get_clean();
    63             }
    64             echo apply_filters('piio_final_output', $final);
    65         }
    66 
    67         public function getLargestImageSrc($imgTag){
    68             //If tag contains srcset
    69             if (strpos($imgTag, 'srcset') !== FALSE){
    70                 preg_match('/\bsrcset\W*=\W*[\'"](.*)?[\'"]/Uxis', $imgTag, $matches);
    71                 //Get all sources
    72                 $sources = array_map('trim', explode(',', $matches[1]));
    73                 $size = 0;
    74                 foreach ($sources as $source){
    75                     //Extract url and size
    76                     $attr = array_map('trim', explode(' ', $source));
    77                     //url = $attr[0], size with unit = $attr[1]
    78                     //remove unit (w or x)
    79                     $attr[1] = intval(substr($attr[1], 0, strlen($attr[1]) - 1));
    80                     if ($attr[1] > $size){
    81                         $retSrc = $attr[0];
    82                         $size = $attr[1];
    83                     }
    84                 }
    85                 return $this->_url_to_absolute($retSrc);
    86             } else {
    87                 //Else just return src
    88                 preg_match('/\bsrc\W*=\W*[\'"](.*)?[\'"]/Uxis', $imgTag, $matches);
    89                 return (isset($matches[1])) ? $this->_url_to_absolute($matches[1]) : null;
    90             }
    91         }
    92 
    93         public function filter_images($HTMLContent){
    94             //Get optimization option and api key
    95             $optimization = get_option('piio_imageopt_optimization');
    96             $use_data_piio = isset($optimization[0]) ? ($optimization[0] === "1") : true;
    97             $api_key = get_option('piio_imageopt_api_key');
    98 
    99             $HTMLContent = $this->_replace_img_tags($HTMLContent, $use_data_piio, $api_key);
    100 
    101             $optimize_bck = get_option('piio_imageopt_optimize_bck');
    102             $optimize_bck = isset($optimize_bck[0]) ? ($optimize_bck[0] === "1") : true;
    103 
    104             if ($optimize_bck){
    105                 $HTMLContent = $this->_replace_bck_styles($HTMLContent, $use_data_piio, $api_key);
    106             }
    107 
    108             return $HTMLContent;
    109         }
    110 
    111         /**
    112         * Register the JavaScript for the public-facing side of the site.
    113         *
    114         * @since    0.9.0
    115         */
    116         public function enqueue_scripts() {
    117 
    118             $api_key        = get_option('piio_imageopt_api_key');
    119             $position       = get_option('piio_imageopt_script_position');
    120             $lazy_mode      = (get_option('piio_imageopt_lazy') === "1") ? 'strict' : 'friendly';
    121 
    122             $lazy_mode      = get_option('piio_imageopt_lazy');
    123             $lazy_mode      = (isset($lazy_mode[0]) && ($lazy_mode[0] === "1")) ? 'strict' : 'friendly';
    124 
    125             $enable_webp    = get_option('piio_imageopt_enable_webp');
    126             $enable_webp    = isset($enable_webp[0]) ? ($enable_webp[0] === "1")  : false;
    127 
    128             $domain         = get_site_url();
    129 
    130             $in_footer = isset($position[0]) ? ($position[0] === "0") : false;
    131 
    132             $jsVars = array(
    133                 'appKey' => $api_key,
    134                 'domain' => $domain,
    135                 'lazyLoadingMode' => $lazy_mode,
    136                 'disableWebP' => !$enable_webp
    137             );
    138 
    139             $piio_vars = "var piioData = " . json_encode($jsVars);
    140 
    141             wp_register_script('piio.js', '//js.piio.co/' . $api_key . '/piio.min.js', array(), false, $in_footer);
    142             wp_add_inline_script('piio.js', $piio_vars, 'before');
    143             wp_enqueue_script('piio.js');
    144         }
    145 
    146 
    147         private function _replace_img_tags($HTMLContent, $use_data_piio, $api_key){
    148             $placeholder_url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8+f9vPQAJZAN2rlRQVAAAAABJRU5ErkJggg==";
    149             $matches = array();
    150             preg_match_all('/<img[\s\r\n]+.*?>/is', $HTMLContent, $matches);
    151 
    152             $search = array();
    153             $replace = array();
    154 
    155             $i = 0;
    156             foreach ($matches[0] as $imgHTML) {
    157 
    158                 // don't to the replacement if the image is a data-uri or has class piio-skip
    159                 if (!preg_match("/src=['\"]data:image/is", $imgHTML) && !preg_match("/class=(['\"]|(['\"][^'\"]*)\s)piio-skip(\"|\s([^'\"]*)['\"])/is", $imgHTML)) {
    160                     $i++;
    161 
    162                     // get largest image src
    163                     $src = $this->getLargestImageSrc($imgHTML);
    164 
    165                     $replaceHTML = '';
    166 
    167                     if ($use_data_piio){
    168                         // replace the src and add the data-piio attribute
    169                         $replaceHTML = preg_replace('/<img(.*?)src=(["\'])(.*?)["\']/is', '<img$1src=$2' . $placeholder_url . '$2 data-piio=$2' . $src . "$2", $imgHTML);
    170                         // remove srcset and sizes attributes
    171                         $replaceHTML = preg_replace('/<img(.*?)srcset=["\'].*?["\']/is', '<img$1', $replaceHTML);
    172                         $replaceHTML = preg_replace('/<img(.*?)sizes=["\'].*?["\']/is', '<img$1', $replaceHTML);
    173 
    174                     } else {
    175                         $enable_webp = get_option('piio_imageopt_enable_webp');
    176                         $enable_webp = isset($enable_webp[0]) ? ($enable_webp[0] === "1") : true;
    177 
    178                         $params = '';
    179                         //Check if client is using Chrome
    180                         if($enable_webp && preg_match('/(Chrome)\//i',$_SERVER['HTTP_USER_AGENT']) && !preg_match('/(Aviator|ChromePlus|coc_|Dragon|Edge|Flock|Iron|Kinza|Maxthon|MxNitro|Nichrome|OPR|Perk|Rockmelt|Seznam|Sleipnir|Spark|UBrowser|Vivaldi|WebExplorer|YaBrowser)/i',$_SERVER['HTTP_USER_AGENT'])){
    181                             $params .= 'wp,1';
    182                         }
    183 
    184                         // remove srcset and sizes attributes as we are adding our own
    185                         $replaceHTML = preg_replace('/<img(.*?)srcset=["\'].*?["\']/is', '<img$1', $imgHTML);
    186                         $replaceHTML = preg_replace('/<img(.*?)sizes=["\'].*?["\']/is', '<img$1', $replaceHTML);
    187 
    188                         $srcAttr = urlencode($src);
    189 
    190                         $breakpoints = array("576", "768", "992", "1200");
    191                         $srcset_values = array();
    192                         foreach ($breakpoints as $width) {
    193                             $local_params = 'vw,' . $width . (($params != '') ? ',' . $params : '');
    194                             array_push($srcset_values, 'https://pcdn.piiojs.com/i/' . $api_key . '/' . $local_params . '/' . $srcAttr . ' ' . $width . 'w');
    195                         }
    196                         // replace src with largest image and add srcset
    197                         $replaceHTML = preg_replace('/<img(.*?)src=(["\'])(.*?)["\']/is', '<img$1src=$2' . 'https://pcdn.piiojs.com/i/' . $api_key . (($params != '') ? '/' . $params : '') . '/' . $srcAttr . '$2 srcset=$2' . implode(', ', $srcset_values) . '$2', $replaceHTML);
    198                     }
    199 
    200                     array_push($search, $imgHTML);
    201                     array_push($replace, $replaceHTML);
    202                 }
    203             }
    204 
    205             $search = array_unique($search);
    206             $replace = array_unique($replace);
    207 
    208             return str_replace($search, $replace, $HTMLContent);
    209         }
    210 
    211         private function _replace_bck_styles($HTMLContent, $use_data_piio, $api_key){
    212             $matches = array();
    213             preg_match_all("/<.*?\sstyle=['\"][^>]*?background(-image)?:.*?url\(\s*.*?\s*\);?.*?['\"].*?>/is", $HTMLContent, $matches);
    214 
    215             $search = array();
    216             $replace = array();
    217 
    218             $i = 0;
    219             foreach ($matches[0] as $bckHTML) {
    220                 // don't to the replacement if the image is a data-uri or has class piio-skip
    221                 if (!preg_match("/url\(['\"]data:image/is", $bckHTML) && !preg_match("/class=(['\"]|(['\"][^'\"]*)\s)piio-skip(\"|\s([^'\"]*)['\"])/is", $bckHTML)) {
    222                     $i++;
    223 
    224                     $replaceHTML = '';
    225 
    226                     if ($use_data_piio){
    227                         // replace the background-image attribute from style and add the data-piio-bck attribute
    228                         $replaceHTML = preg_replace("/(\sstyle=['\"][^>]*?)(background-image:.*?url\((\s*.*?\s*)\));?(.*?['\"])/is", '$1$4 data-piio-bck=' . "$3", $bckHTML);
    229                         $replaceHTML = preg_replace("/(\sstyle=['\"][^>]*?background:.*?)(url\((\s*.*?\s*)\));?(.*?['\"])/is", '$1$4 data-piio-bck=' . "$3", $replaceHTML);
    230 
    231                     } else {
    232                         $enable_webp = get_option('piio_imageopt_enable_webp');
    233                         $enable_webp = isset($enable_webp[0]) ? ($enable_webp[0] === "1") : true;
    234 
    235                         $params = "";
    236                         //Check if client is using Chrome
    237                         if($enable_webp && preg_match('/(Chrome)\//i',$_SERVER['HTTP_USER_AGENT']) && !preg_match('/(Aviator|ChromePlus|coc_|Dragon|Edge|Flock|Iron|Kinza|Maxthon|MxNitro|Nichrome|OPR|Perk|Rockmelt|Seznam|Sleipnir|Spark|UBrowser|Vivaldi|WebExplorer|YaBrowser)/i',$_SERVER['HTTP_USER_AGENT'])){
    238                             $params .= "wp,1";
    239                         }
    240 
    241                         $callback = new Piio_Image_Callback($api_key, $params);
    242 
    243                         $replaceHTML = preg_replace_callback("/(\sstyle=['\"][^>]*?)(background-image:.*?url\(['\"](\s*.*?\s*)['\"]\));?(.*?['\"])/is", array($callback, 'callback_background_image'), $bckHTML);
    244 
    245                         $replaceHTML = preg_replace_callback("/(\sstyle=['\"][^>]*?background:.*?url\(['\"])(\s*.*?\s*)(['\"]\);?.*?['\"])/is", array($callback, 'callback_background'), $replaceHTML);
    246                     }
    247 
    248                     array_push($search, $bckHTML);
    249                     array_push($replace, $replaceHTML);
    250                 }
    251             }
    252 
    253             $search = array_unique($search);
    254             $replace = array_unique($replace);
    255 
    256             return str_replace($search, $replace, $HTMLContent);
    257         }
    258 
    259         private function _url_to_absolute($relativeUrl){
    260             $baseUrl = get_site_url();
    261             // If relative URL has a scheme, clean path and return.
    262             $r = parse_url( $relativeUrl );
    263             if ( $r === FALSE )
    264             return FALSE;
    265             if ( !empty( $r['scheme'] ) )
    266             {
    267                 if ( !empty( $r['path'] ) && $r['path'][0] == '/' )
    268                 $r['path'] = $this->_url_remove_dot_segments($r['path']);
    269                 return $this->_join_url( $r );
    270             }
    271 
    272             // Make sure the base URL is absolute.
    273             $b = parse_url( $baseUrl );
    274             if ( $b === FALSE || empty( $b['scheme'] ) || empty( $b['host'] ) )
    275             return FALSE;
    276             $r['scheme'] = $b['scheme'];
    277 
    278             // If relative URL has an authority, clean path and return.
    279             if ( isset( $r['host'] ) )
    280             {
    281                 if ( !empty( $r['path'] ) )
    282                 $r['path'] = $this->_url_remove_dot_segments($r['path']);
    283                 return $this->_join_url( $r );
    284             }
    285             unset( $r['port'] );
    286             unset( $r['user'] );
    287             unset( $r['pass'] );
    288 
    289             // Copy base authority.
    290             $r['host'] = $b['host'];
    291             if ( isset( $b['port'] ) ) $r['port'] = $b['port'];
    292             if ( isset( $b['user'] ) ) $r['user'] = $b['user'];
    293             if ( isset( $b['pass'] ) ) $r['pass'] = $b['pass'];
    294 
    295             // If relative URL has no path, use base path
    296             if ( empty( $r['path'] ) )
    297             {
    298                 if ( !empty( $b['path'] ) )
    299                 $r['path'] = $b['path'];
    300                 if ( !isset( $r['query'] ) && isset( $b['query'] ) )
    301                 $r['query'] = $b['query'];
    302                 return $this->_join_url( $r );
    303             }
    304 
    305             // If relative URL path doesn't start with /, merge with base path
    306             if ( $r['path'][0] != '/' )
    307             {
    308                 $base = mb_strrchr( $b['path'], '/', TRUE, 'UTF-8' );
    309                 if ( $base === FALSE ) $base = '';
    310                 $r['path'] = $base . '/' . $r['path'];
    311             }
    312             $r['path'] = $this->_url_remove_dot_segments($r['path']);
    313             return $this->_join_url($r);
    314         }
    315 
    316         private function _join_url($parts, $encode=TRUE){
    317             if ( $encode )
    318             {
    319                 if ( isset( $parts['user'] ) )
    320                 $parts['user']     = rawurlencode( $parts['user'] );
    321                 if ( isset( $parts['pass'] ) )
    322                 $parts['pass']     = rawurlencode( $parts['pass'] );
    323                 if ( isset( $parts['host'] ) &&
    324                 !preg_match( '!^(\[[\da-f.:]+\]])|([\da-f.:]+)$!ui', $parts['host'] ) )
    325                 $parts['host']     = rawurlencode( $parts['host'] );
    326                 if ( !empty( $parts['path'] ) )
    327                 $parts['path']     = preg_replace( '!%2F!ui', '/',
    328                 rawurlencode( $parts['path'] ) );
    329                 if ( isset( $parts['query'] ) )
    330                 $parts['query']    = rawurlencode( $parts['query'] );
    331                 if ( isset( $parts['fragment'] ) )
    332                 $parts['fragment'] = rawurlencode( $parts['fragment'] );
    333             }
    334 
    335             $url = '';
    336             if ( !empty( $parts['scheme'] ) )
    337             {
    338                 $url .= $parts['scheme'] . ':';
    339             }
    340             if ( isset( $parts['host'] ) )
    341             {
    342                 $url .= '//';
    343                 if ( isset( $parts['user'] ) )
    344                 {
    345                     $url .= $parts['user'];
    346                     if ( isset( $parts['pass'] ) )
    347                     $url .= ':' . $parts['pass'];
    348                     $url .= '@';
    349                 }
    350                 if ( preg_match( '!^[\da-f]*:[\da-f.:]+$!ui', $parts['host'] ) )
    351                 $url .= '[' . $parts['host'] . ']'; // IPv6
    352                 else
    353                 $url .= $parts['host'];             // IPv4 or name
    354                 if ( isset( $parts['port'] ) )
    355                 $url .= ':' . $parts['port'];
    356                 if ( !empty( $parts['path'] ) && $parts['path'][0] != '/' )
    357                 $url .= '/';
    358             }
    359             if ( !empty( $parts['path'] ) )
    360             $url .= $parts['path'];
    361             if ( isset( $parts['query'] ) )
    362             $url .= '?' . $parts['query'];
    363             if ( isset( $parts['fragment'] ) )
    364             $url .= '#' . $parts['fragment'];
    365             return $url;
    366         }
    367 
    368         private function _url_remove_dot_segments($path){
    369             // multi-byte character explode
    370             $inSegs  = preg_split( '!/!u', $path );
    371             $outSegs = array( );
    372             foreach ( $inSegs as $seg )
    373             {
    374                 if ( $seg == '' || $seg == '.')
    375                 continue;
    376                 if ( $seg == '..' )
    377                 array_pop( $outSegs );
    378                 else
    379                 array_push( $outSegs, $seg );
    380             }
    381             $outPath = implode( '/', $outSegs );
    382             if ( $path[0] == '/' )
    383             $outPath = '/' . $outPath;
    384             // compare last multi-byte character against '/'
    385             if ( $outPath != '/' &&
    386             (mb_strlen($path)-1) == mb_strrpos( $path, '/', 'UTF-8' ) )
    387             $outPath .= '/';
    388             return $outPath;
    389         }
    390     }
     23if (!class_exists('Piio_Image_Optimization_Public')) {
     24    class Piio_Image_Optimization_Public
     25    {
     26
     27        /**
     28        * The ID of this plugin.
     29        *
     30        * @since    0.9.0
     31        * @access   private
     32        * @var      string    $plugin_name    The ID of this plugin.
     33        */
     34        private $plugin_name;
     35
     36        /**
     37        * The version of this plugin.
     38        *
     39        * @since    0.9.0
     40        * @access   private
     41        * @var      string    $version    The current version of this plugin.
     42        */
     43        private $version;
     44
     45        /**
     46        * Initialize the class and set its properties.
     47        *
     48        * @since    0.9.0
     49        * @param      string    $plugin_name       The name of the plugin.
     50        * @param      string    $version    The version of this plugin.
     51        */
     52        public function __construct($plugin_name, $version)
     53        {
     54            $this->plugin_name = $plugin_name;
     55            $this->version = $version;
     56
     57            /**
     58            * The class responsible for defining callbacks for replacing
     59            * of the plugin.
     60            */
     61            require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-piio-image-optimization-callbacks.php';
     62        }
     63
     64        public function create_final_output_filter()
     65        {
     66            $final = '';
     67            $levels = ob_get_level();
     68            for ($i = 0; $i < $levels; $i++) {
     69                $final .= ob_get_clean();
     70            }
     71            echo apply_filters('piio_final_output', $final);
     72        }
     73
     74        public function get_largest_image_src($imgTag)
     75        {
     76            //If tag contains srcset
     77            if (strpos($imgTag, 'srcset') !== false) {
     78                preg_match('/\bsrcset\W*=\W*[\'"](.*)?[\'"]/Uxis', $imgTag, $matches);
     79                //Get all sources
     80                $sources = array_map('trim', explode(',', $matches[1]));
     81                $size = 0;
     82                foreach ($sources as $source) {
     83                    //Extract url and size
     84                    $attr = array_map('trim', explode(' ', $source));
     85                    //Check if we have size with unit
     86                    if ($attr[1]) {
     87                        //url = $attr[0], size with unit = $attr[1]
     88                        //remove unit (w or x)
     89                        $attr[1] = intval(substr($attr[1], 0, strlen($attr[1]) - 1));
     90                        if ($attr[1] > $size) {
     91                            $retSrc = $attr[0];
     92                            $size = $attr[1];
     93                        }
     94                    }
     95                }
     96                if (isset($retSrc)) {
     97                    return $this->_url_to_absolute($retSrc);
     98                }
     99            }
     100            //Else just return src
     101            preg_match('/\bsrc\W*=\W*[\'"](.*)?[\'"]/Uxis', $imgTag, $matches);
     102            return (isset($matches[1])) ? $this->_url_to_absolute($matches[1]) : null;
     103        }
     104
     105        public function filter_images($HTMLContent)
     106        {
     107            //Get optimization option and api key
     108            $optimization = get_option('piio_imageopt_optimization');
     109            $use_data_piio = isset($optimization[0]) ? ($optimization[0] === "1") : true;
     110            $api_key = get_option('piio_imageopt_api_key');
     111
     112            $HTMLContent = $this->_replace_img_tags($HTMLContent, $use_data_piio, $api_key);
     113
     114            $optimize_bck = get_option('piio_imageopt_optimize_bck');
     115            $optimize_bck = isset($optimize_bck[0]) ? ($optimize_bck[0] === "1") : true;
     116
     117            if ($optimize_bck) {
     118                $HTMLContent = $this->_replace_bck_styles($HTMLContent, $use_data_piio, $api_key);
     119            }
     120
     121            return $HTMLContent;
     122        }
     123
     124        /**
     125        * Register the JavaScript for the public-facing side of the site.
     126        *
     127        * @since    0.9.0
     128        */
     129        public function enqueue_scripts()
     130        {
     131
     132            $api_key = get_option('piio_imageopt_api_key');
     133            $position = get_option('piio_imageopt_script_position');
     134            $lazy_mode = (get_option('piio_imageopt_lazy') === "1") ? 'strict' : 'friendly';
     135
     136            $lazy_mode = get_option('piio_imageopt_lazy');
     137            $lazy_mode = (isset($lazy_mode[0]) && ($lazy_mode[0] === "1")) ? 'strict' : 'friendly';
     138
     139            $enable_webp = get_option('piio_imageopt_enable_webp');
     140            $enable_webp = isset($enable_webp[0]) ? ($enable_webp[0] === "1")  : false;
     141
     142            $domain = get_site_url();
     143
     144            $in_footer = isset($position[0]) ? ($position[0] === "0") : false;
     145
     146            $jsVars = array(
     147                'appKey' => $api_key,
     148                'domain' => $domain,
     149                'lazyLoadingMode' => $lazy_mode,
     150                'disableWebP' => !$enable_webp
     151            );
     152
     153            $piio_vars = "var piioData = " . json_encode($jsVars);
     154
     155            wp_register_script('piio.js', '//js.piio.co/' . $api_key . '/piio.min.js', array(), false, $in_footer);
     156            wp_add_inline_script('piio.js', $piio_vars, 'before');
     157            wp_enqueue_script('piio.js');
     158        }
     159
     160
     161        private function _replace_img_tags($HTMLContent, $use_data_piio, $api_key)
     162        {
     163            $placeholder_url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8+f9vPQAJZAN2rlRQVAAAAABJRU5ErkJggg==";
     164            $matches = array();
     165            preg_match_all('/<img[\s\r\n]+.*?>/is', $HTMLContent, $matches);
     166
     167            $search = array();
     168            $replace = array();
     169
     170            $std_opt_img_added = false;
     171
     172            $i = 0;
     173            foreach ($matches[0] as $imgHTML) {
     174                // don't to the replacement if the image is a data-uri or has class piio-skip
     175                if (!preg_match("/src=['\"]data:image/is", $imgHTML) && !preg_match("/class=(['\"]|(['\"][^'\"]*)\s)piio-skip(['\"]|\s([^'\"]*)['\"])/is", $imgHTML)) {
     176                    $i++;
     177
     178                    // get largest image src
     179                    $src = $this->get_largest_image_src($imgHTML);
     180
     181                    $replaceHTML = '';
     182
     183                    if ($use_data_piio) {
     184                        // advanced optimization enabled
     185
     186                        // replace the src and add the data-piio attribute
     187                        $replaceHTML = preg_replace('/<img(.*?)src=(["\'])(.*?)["\']/is', '<img$1src=$2' . $placeholder_url . '$2 data-piio=$2' . urldecode($src) . "$2", $imgHTML);
     188                        // remove srcset and sizes attributes
     189                        $replaceHTML = preg_replace('/<img(.*?)srcset=["\'].*?["\']/is', '<img$1', $replaceHTML);
     190                        $replaceHTML = preg_replace('/<img(.*?)sizes=["\'].*?["\']/is', '<img$1', $replaceHTML);
     191                    } else {
     192                        // standard optimization enabled
     193
     194                        $enable_webp = get_option('piio_imageopt_enable_webp');
     195                        $enable_webp = isset($enable_webp[0]) ? ($enable_webp[0] === "1") : true;
     196
     197                        $params = '';
     198                        //Check if client is using Chrome
     199                        if ($enable_webp && preg_match('/(Chrome)\//i', $_SERVER['HTTP_USER_AGENT']) && !preg_match('/(Aviator|ChromePlus|coc_|Dragon|Edge|Flock|Iron|Kinza|Maxthon|MxNitro|Nichrome|OPR|Perk|Rockmelt|Seznam|Sleipnir|Spark|UBrowser|Vivaldi|WebExplorer|YaBrowser)/i', $_SERVER['HTTP_USER_AGENT'])) {
     200                            $params .= 'wp,1';
     201                        }
     202
     203                        // remove srcset and sizes attributes as we are adding our own
     204                        $replaceHTML = preg_replace('/<img(.*?)srcset=["\'].*?["\']/is', '<img$1', $imgHTML);
     205                        $replaceHTML = preg_replace('/<img(.*?)sizes=["\'].*?["\']/is', '<img$1', $replaceHTML);
     206
     207                        $srcAttr = urlencode($src);
     208
     209                        $breakpoints = array("576", "768", "992", "1200");
     210                        $srcset_values = array();
     211                        foreach ($breakpoints as $width) {
     212                            $local_params = 'vw,' . $width . (($params != '') ? ',' . $params : '');
     213                            array_push($srcset_values, 'https://pcdn.piiojs.com/i/' . $api_key . '/' . $local_params . '/' . $srcAttr . ' ' . $width . 'w');
     214                        }
     215                        // replace src with largest image and add srcset
     216                        $replaceHTML = preg_replace('/<img(.*?)src=(["\'])(.*?)["\']/is', '<img$1src=$2' . 'https://pcdn.piiojs.com/i/' . $api_key . (($params != '') ? '/' . $params : '') . '/' . $srcAttr . '$2 srcset=$2' . implode(', ', $srcset_values) . '$2', $replaceHTML);
     217
     218                        // add img with data-piio to log user data for consumption
     219                        if (!$std_opt_img_added) {
     220                            $body_matches = array();
     221                            if (preg_match('/<body.*?>/is', $HTMLContent, $body_matches, PREG_OFFSET_CAPTURE) > 0) {
     222                                // get <body start position
     223                                // body_matches[0][0] contains string, body_matches[0][1] contains string index
     224                                $body_end_pos = $body_matches[0][1] + strlen($body_matches[0][0]);
     225                                $HTMLContent = substr_replace($HTMLContent, $this->_get_transparent_svg_with_piio(), $body_end_pos, 0);
     226                            };
     227                            $std_opt_img_added = true;
     228                        }
     229                    }
     230
     231                    array_push($search, $imgHTML);
     232                    array_push($replace, $replaceHTML);
     233                }
     234            }
     235
     236            $search = array_unique($search);
     237            $replace = array_unique($replace);
     238
     239            return str_replace($search, $replace, $HTMLContent);
     240        }
     241
     242        private function _replace_bck_styles($HTMLContent, $use_data_piio, $api_key)
     243        {
     244            $matches = array();
     245            preg_match_all("/<[^>]*?\sstyle=['\"][^>]*?background(-image)?:.*?url\(\s*.*?\s*\);?.*?['\"].*?>/is", $HTMLContent, $matches);
     246
     247            $search = array();
     248            $replace = array();
     249
     250            $i = 0;
     251            foreach ($matches[0] as $bckHTML) {
     252                // don't to the replacement if the image is a data-uri or has class piio-skip
     253                if (!preg_match("/url\(['\"]data:image/is", $bckHTML) && !preg_match("/class=(['\"]|(['\"][^'\"]*)\s)piio-skip(['\"]|\s([^'\"]*)['\"])/is", $bckHTML)) {
     254                    $i++;
     255
     256                    $replaceHTML = '';
     257
     258                    if ($use_data_piio) {
     259                        // replace the background-image attribute from style and add the data-piio-bck attribute
     260                        $replaceHTML = preg_replace("/(\sstyle=['\"][^>]*?)(background-image:.*?url\((\s*.*?\s*)\));?(.*?['\"])/is", '$1$4 data-piio-bck=' . urldecode("$3"), $bckHTML);
     261                        $replaceHTML = preg_replace("/(\sstyle=['\"][^>]*?background:.*?)(url\((\s*.*?\s*)\));?(.*?['\"])/is", '$1$4 data-piio-bck=' . urldecode("$3"), $replaceHTML);
     262                    } else {
     263                        $enable_webp = get_option('piio_imageopt_enable_webp');
     264                        $enable_webp = isset($enable_webp[0]) ? ($enable_webp[0] === "1") : true;
     265
     266                        $params = "";
     267                        //Check if client is using Chrome
     268                        if ($enable_webp && preg_match('/(Chrome)\//i', $_SERVER['HTTP_USER_AGENT']) && !preg_match('/(Aviator|ChromePlus|coc_|Dragon|Edge|Flock|Iron|Kinza|Maxthon|MxNitro|Nichrome|OPR|Perk|Rockmelt|Seznam|Sleipnir|Spark|UBrowser|Vivaldi|WebExplorer|YaBrowser)/i', $_SERVER['HTTP_USER_AGENT'])) {
     269                            $params .= "wp,1";
     270                        }
     271
     272                        $callback = new Piio_Image_Optimization_Callbacks($api_key, $params);
     273
     274                        $replaceHTML = preg_replace_callback("/(\sstyle=['\"][^>]*?)(background-image:.*?url\(['\"](\s*.*?\s*)['\"]\));?(.*?['\"])/is", array($callback, 'callback_background_image'), $bckHTML);
     275
     276                        $replaceHTML = preg_replace_callback("/(\sstyle=['\"][^>]*?background:.*?url\(['\"])(\s*.*?\s*)(['\"]\);?.*?['\"])/is", array($callback, 'callback_background'), $replaceHTML);
     277                    }
     278
     279                    array_push($search, $bckHTML);
     280                    array_push($replace, $replaceHTML);
     281                }
     282            }
     283
     284            $search = array_unique($search);
     285            $replace = array_unique($replace);
     286
     287            return str_replace($search, $replace, $HTMLContent);
     288        }
     289
     290        private function _get_transparent_svg_with_piio()
     291        {
     292            return "<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8+f9vPQAJZAN2rlRQVAAAAABJRU5ErkJggg==' data-piio='" . plugin_dir_url(__FILE__) . 'images/transparent.svg' . "' style='width:1px !important;height:1px !important;position:absolute !important;top:0 !important;left:-1px !important'>";
     293        }
     294
     295        private function _url_to_absolute($relativeUrl)
     296        {
     297            $baseUrl = get_site_url();
     298            // If relative URL has a scheme, clean path and return.
     299            $r = parse_url($relativeUrl);
     300            if ($r === false) {
     301                return false;
     302            }
     303            if (!empty($r['scheme'])) {
     304                if (!empty($r['path']) && $r['path'][0] == '/') {
     305                    $r['path'] = $this->_url_remove_dot_segments($r['path']);
     306                }
     307                return $this->_join_url($r);
     308            }
     309
     310            // Make sure the base URL is absolute.
     311            $b = parse_url($baseUrl);
     312            if ($b === false || empty($b['scheme']) || empty($b['host'])) {
     313                return false;
     314            }
     315            $r['scheme'] = $b['scheme'];
     316
     317            // If relative URL has an authority, clean path and return.
     318            if (isset($r['host'])) {
     319                if (!empty($r['path'])) {
     320                    $r['path'] = $this->_url_remove_dot_segments($r['path']);
     321                }
     322                return $this->_join_url($r);
     323            }
     324            unset($r['port']);
     325            unset($r['user']);
     326            unset($r['pass']);
     327
     328            // Copy base authority.
     329            $r['host'] = $b['host'];
     330            if (isset($b['port'])) {
     331                $r['port'] = $b['port'];
     332            }
     333            if (isset($b['user'])) {
     334                $r['user'] = $b['user'];
     335            }
     336            if (isset($b['pass'])) {
     337                $r['pass'] = $b['pass'];
     338            }
     339
     340            // If relative URL has no path, use base path
     341            if (empty($r['path'])) {
     342                if (!empty($b['path'])) {
     343                    $r['path'] = $b['path'];
     344                }
     345                if (!isset($r['query']) && isset($b['query'])) {
     346                    $r['query'] = $b['query'];
     347                }
     348                return $this->_join_url($r);
     349            }
     350
     351            // If relative URL path doesn't start with /, merge with base path
     352            if ($r['path'][0] != '/') {
     353                $base = mb_strrchr($b['path'], '/', true, 'UTF-8');
     354                if ($base === false) {
     355                    $base = '';
     356                }
     357                $r['path'] = $base . '/' . $r['path'];
     358            }
     359            $r['path'] = $this->_url_remove_dot_segments($r['path']);
     360            return $this->_join_url($r);
     361        }
     362
     363        private function _join_url($parts, $encode = true)
     364        {
     365            if ($encode) {
     366                if (isset($parts['user'])) {
     367                    $parts['user'] = rawurlencode($parts['user']);
     368                }
     369                if (isset($parts['pass'])) {
     370                    $parts['pass'] = rawurlencode($parts['pass']);
     371                }
     372                if (isset($parts['host']) && !preg_match('!^(\[[\da-f.:]+\]])|([\da-f.:]+)$!ui', $parts['host'])) {
     373                    $parts['host'] = rawurlencode($parts['host']);
     374                }
     375                if (!empty($parts['path'])) {
     376                    $parts['path'] = preg_replace('!%2F!ui', '/', rawurlencode($parts['path']));
     377                }
     378                if (isset($parts['query'])) {
     379                    $parts['query'] = rawurlencode($parts['query']);
     380                }
     381                if (isset($parts['fragment'])) {
     382                    $parts['fragment'] = rawurlencode($parts['fragment']);
     383                }
     384            }
     385
     386            $url = '';
     387            if (!empty($parts['scheme'])) {
     388                $url .= $parts['scheme'] . ':';
     389            }
     390            if (isset($parts['host'])) {
     391                $url .= '//';
     392                if (isset($parts['user'])) {
     393                    $url .= $parts['user'];
     394                    if (isset($parts['pass'])) {
     395                        $url .= ':' . $parts['pass'];
     396                    }
     397                    $url .= '@';
     398                }
     399                if (preg_match('!^[\da-f]*:[\da-f.:]+$!ui', $parts['host'])) {
     400                    $url .= '[' . $parts['host'] . ']'; // IPv6
     401                } else {
     402                    $url .= $parts['host'];             // IPv4 or name
     403                }
     404                if (isset($parts['port'])) {
     405                    $url .= ':' . $parts['port'];
     406                }
     407                if (!empty($parts['path']) && $parts['path'][0] != '/') {
     408                    $url .= '/';
     409                }
     410            }
     411            if (!empty($parts['path'])) {
     412                $url .= $parts['path'];
     413            }
     414            if (isset($parts['query'])) {
     415                $url .= '?' . $parts['query'];
     416            }
     417            if (isset($parts['fragment'])) {
     418                $url .= '#' . $parts['fragment'];
     419            }
     420            return $url;
     421        }
     422
     423        private function _url_remove_dot_segments($path)
     424        {
     425            // multi-byte character explode
     426            $inSegs = preg_split('!/!u', $path);
     427            $outSegs = array( );
     428            foreach ($inSegs as $seg) {
     429                if ($seg == '' || $seg == '.') {
     430                    continue;
     431                }
     432                if ($seg == '..') {
     433                    array_pop($outSegs);
     434                } else {
     435                    array_push($outSegs, $seg);
     436                }
     437            }
     438            $outPath = implode('/', $outSegs);
     439            if ($path[0] == '/') {
     440                $outPath = '/' . $outPath;
     441            }
     442            // compare last multi-byte character against '/'
     443            if ($outPath != '/' && (mb_strlen($path)-1) == mb_strrpos($path, '/', 'UTF-8')) {
     444                $outPath .= '/';
     445            }
     446            return $outPath;
     447        }
     448    }
    391449}
    392 if ( !class_exists( 'Piio_Image_Callback' ) ) {
    393     class Piio_Image_Callback {
    394         private $api_key;
    395         private $params;
    396 
    397         function __construct($api_key, $params) {
    398             $this->$api_key = $api_key;
    399             $this->$params = $params;
    400         }
    401 
    402         public function callback_background_image($matches) {
    403             $srcAttr = urlencode($matches[3]);
    404             return $matches[1] . "background-image:url('https://pcdn.piiojs.com/i/" . $this->api_key . (($this->params != '') ? '/' . $this->params : '') . "/" . $srcAttr . "');" . $matches[4];
    405         }
    406 
    407         public function callback_background($matches) {
    408             $srcAttr = urlencode($matches[2]);
    409             return $matches[1] . "https://pcdn.piiojs.com/i/" . $this->api_key . (($this->params != '') ? '/' . $this->params : '') . "/" . $srcAttr . $matches[3];
    410         }
    411     }
    412 }
  • piio-image-optimization/tags/0.9.8/readme.txt

    r1954139 r1969996  
    66Requires PHP: 5.3.0
    77Tested up to: 4.9.8
    8 Stable tag: 0.9.7
     8Stable tag: 0.9.8
    99License: GPLv2 or later
    1010License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    121121
    122122== Changelog ==
     123= 0.9.8 =
     124* W3 Total Cache v 0.9.7+ support added
     125* Standard optimization improved.
    123126= 0.9.7 =
    124127* Added older PHP versions support.
  • piio-image-optimization/trunk/includes/class-piio-image-optimization.php

    r1921770 r1969996  
    2929*/
    3030if ( !class_exists( 'Piio_Image_Optimization' ) ) {
    31     class Piio_Image_Optimization {
    32 
    33         /**
    34         * The loader that's responsible for maintaining and registering all hooks that power
    35         * the plugin.
    36         *
    37         * @since    0.9.0
    38         * @access   protected
    39         * @var      Piio_Image_Optimization_Loader    $loader    Maintains and registers all hooks for the plugin.
    40         */
    41         protected $loader;
    42 
    43         /**
    44         * The unique identifier of this plugin.
    45         *
    46         * @since    0.9.0
    47         * @access   protected
    48         * @var      string    $plugin_name    The string used to uniquely identify this plugin.
    49         */
    50         protected $plugin_name;
    51 
    52         /**
    53         * The current version of the plugin.
    54         *
    55         * @since    0.9.0
    56         * @access   protected
    57         * @var      string    $version    The current version of the plugin.
    58         */
    59         protected $version;
    60 
    61         /**
    62         * Define the core functionality of the plugin.
    63         *
    64         * Set the plugin name and the plugin version that can be used throughout the plugin.
    65         * Load the dependencies, define the locale, and set the hooks for the admin area and
    66         * the public-facing side of the site.
    67         *
    68         * @since    0.9.0
    69         */
    70         public function __construct() {
    71             if ( defined( 'PIIO_IMAGE_OPTIMIZATION_VERSION' ) ) {
    72                 $this->version = PIIO_IMAGE_OPTIMIZATION_VERSION;
    73             } else {
    74                 $this->version = '0.9.0';
    75             }
    76             $this->plugin_name = 'piio-image-optimization';
    77 
    78             $this->load_dependencies();
    79             $this->set_locale();
    80             if ( is_admin() ) {
    81                 $this->define_admin_hooks();
    82             }
    83             $this->define_public_hooks();
    84 
    85         }
    86 
    87         /**
    88         * Load the required dependencies for this plugin.
    89         *
    90         * Include the following files that make up the plugin:
    91         *
    92         * - Piio_Image_Optimization_Loader. Orchestrates the hooks of the plugin.
    93         * - Piio_Image_Optimization_i18n. Defines internationalization functionality.
    94         * - Piio_Image_Optimization_Admin. Defines all hooks for the admin area.
    95         * - Piio_Image_Optimization_Public. Defines all hooks for the public side of the site.
    96         *
    97         * Create an instance of the loader which will be used to register the hooks
    98         * with WordPress.
    99         *
    100         * @since    0.9.0
    101         * @access   private
    102         */
    103         private function load_dependencies() {
    104 
    105             /**
    106             * The class responsible for orchestrating the actions and filters of the
    107             * core plugin.
    108             */
    109             require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-piio-image-optimization-loader.php';
    110 
    111             /**
    112             * The class responsible for defining internationalization functionality
    113             * of the plugin.
    114             */
    115             require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-piio-image-optimization-i18n.php';
    116 
    117             /**
    118             * The class responsible for defining all actions that occur in the admin area.
    119             */
    120             require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-piio-image-optimization-admin.php';
    121 
    122             /**
    123             * The class responsible for defining all actions that occur in the public-facing
    124             * side of the site.
    125             */
    126             require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-piio-image-optimization-public.php';
    127 
    128             $this->loader = new Piio_Image_Optimization_Loader();
    129 
    130         }
    131 
    132         /**
    133         * Define the locale for this plugin for internationalization.
    134         *
    135         * Uses the Piio_Image_Optimization_i18n class in order to set the domain and to register the hook
    136         * with WordPress.
    137         *
    138         * @since    0.9.0
    139         * @access   private
    140         */
    141         private function set_locale() {
    142 
    143             $plugin_i18n = new Piio_Image_Optimization_i18n();
    144 
    145             $this->loader->add_action( 'plugins_loaded', $plugin_i18n, 'load_plugin_textdomain' );
    146 
    147         }
    148 
    149         /**
    150         * Register all of the hooks related to the admin area functionality
    151         * of the plugin.
    152         *
    153         * @since    0.9.0
    154         * @access   private
    155         */
    156         private function define_admin_hooks() {
    157 
    158             $plugin_admin = new Piio_Image_Optimization_Admin( $this->get_plugin_name(), $this->get_version() );
    159             $this->loader->add_action( 'admin_menu', $plugin_admin, 'display_admin_page');
    160             $this->loader->add_action( 'admin_init', $plugin_admin, 'setup_sections');
    161             $this->loader->add_action( 'admin_init', $plugin_admin, 'setup_fields');
    162             $this->loader->add_action( 'admin_init', $plugin_admin, 'check_piio_incompatibility');
    163             $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
    164             $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
    165 
    166         }
    167 
    168         /**
    169         * Register all of the hooks related to the public-facing functionality
    170         * of the plugin.
    171         *
    172         * @since    0.9.0
    173         * @access   private
    174         */
    175         private function define_public_hooks() {
    176 
    177             $plugin_public = new Piio_Image_Optimization_Public( $this->get_plugin_name(), $this->get_version() );
    178             $piio_enabled_option = get_option('piio_imageopt_enabled');
    179             $is_piio_enabled = (isset($piio_enabled_option[0])) ? ($piio_enabled_option[0] === "1") : false;
    180 
    181             if ($is_piio_enabled && !is_admin()){
    182                 ob_start();
    183                 $this->loader->add_action( 'shutdown', $plugin_public, 'create_final_output_filter', -100 );
    184 
    185                 $this->loader->add_filter( 'piio_final_output', $plugin_public, 'filter_images' );
    186                 // If site is using WPSupercache, we just hook it
    187                 $this->loader->add_filter( 'wpsupercache_buffer', $plugin_public, 'filter_images' );
    188             }
    189 
    190             $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' );
    191 
    192         }
    193 
    194         /**
    195         * Run the loader to execute all of the hooks with WordPress.
    196         *
    197         * @since    0.9.0
    198         */
    199         public function run() {
    200             $this->loader->run();
    201         }
    202 
    203         /**
    204         * The name of the plugin used to uniquely identify it within the context of
    205         * WordPress and to define internationalization functionality.
    206         *
    207         * @since     0.9.0
    208         * @return    string    The name of the plugin.
    209         */
    210         public function get_plugin_name() {
    211             return $this->plugin_name;
    212         }
    213 
    214         /**
    215         * The reference to the class that orchestrates the hooks with the plugin.
    216         *
    217         * @since     0.9.0
    218         * @return    Piio_Image_Optimization_Loader    Orchestrates the hooks of the plugin.
    219         */
    220         public function get_loader() {
    221             return $this->loader;
    222         }
    223 
    224         /**
    225         * Retrieve the version number of the plugin.
    226         *
    227         * @since     0.9.0
    228         * @return    string    The version number of the plugin.
    229         */
    230         public function get_version() {
    231             return $this->version;
    232         }
    233 
    234     }
     31    class Piio_Image_Optimization {
     32
     33        /**
     34        * The loader that's responsible for maintaining and registering all hooks that power
     35        * the plugin.
     36        *
     37        * @since    0.9.0
     38        * @access   protected
     39        * @var      Piio_Image_Optimization_Loader    $loader    Maintains and registers all hooks for the plugin.
     40        */
     41        protected $loader;
     42
     43        /**
     44        * The unique identifier of this plugin.
     45        *
     46        * @since    0.9.0
     47        * @access   protected
     48        * @var      string    $plugin_name    The string used to uniquely identify this plugin.
     49        */
     50        protected $plugin_name;
     51
     52        /**
     53        * The current version of the plugin.
     54        *
     55        * @since    0.9.0
     56        * @access   protected
     57        * @var      string    $version    The current version of the plugin.
     58        */
     59        protected $version;
     60
     61        /**
     62        * Define the core functionality of the plugin.
     63        *
     64        * Set the plugin name and the plugin version that can be used throughout the plugin.
     65        * Load the dependencies, define the locale, and set the hooks for the admin area and
     66        * the public-facing side of the site.
     67        *
     68        * @since    0.9.0
     69        */
     70        public function __construct() {
     71            if ( defined( 'PIIO_IMAGE_OPTIMIZATION_VERSION' ) ) {
     72                $this->version = PIIO_IMAGE_OPTIMIZATION_VERSION;
     73            } else {
     74                $this->version = '0.9.0';
     75            }
     76            $this->plugin_name = 'piio-image-optimization';
     77
     78            $this->load_dependencies();
     79            $this->set_locale();
     80            if ( is_admin() ) {
     81                $this->define_admin_hooks();
     82            }
     83            $this->define_public_hooks();
     84
     85        }
     86
     87        /**
     88        * Load the required dependencies for this plugin.
     89        *
     90        * Include the following files that make up the plugin:
     91        *
     92        * - Piio_Image_Optimization_Loader. Orchestrates the hooks of the plugin.
     93        * - Piio_Image_Optimization_i18n. Defines internationalization functionality.
     94        * - Piio_Image_Optimization_Admin. Defines all hooks for the admin area.
     95        * - Piio_Image_Optimization_Public. Defines all hooks for the public side of the site.
     96        *
     97        * Create an instance of the loader which will be used to register the hooks
     98        * with WordPress.
     99        *
     100        * @since    0.9.0
     101        * @access   private
     102        */
     103        private function load_dependencies() {
     104
     105            /**
     106            * The class responsible for orchestrating the actions and filters of the
     107            * core plugin.
     108            */
     109            require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-piio-image-optimization-loader.php';
     110
     111            /**
     112            * The class responsible for defining internationalization functionality
     113            * of the plugin.
     114            */
     115            require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-piio-image-optimization-i18n.php';
     116
     117            /**
     118            * The class responsible for defining all actions that occur in the admin area.
     119            */
     120            require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-piio-image-optimization-admin.php';
     121
     122            /**
     123            * The class responsible for defining all actions that occur in the public-facing
     124            * side of the site.
     125            */
     126            require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-piio-image-optimization-public.php';
     127
     128            $this->loader = new Piio_Image_Optimization_Loader();
     129
     130        }
     131
     132        /**
     133        * Define the locale for this plugin for internationalization.
     134        *
     135        * Uses the Piio_Image_Optimization_i18n class in order to set the domain and to register the hook
     136        * with WordPress.
     137        *
     138        * @since    0.9.0
     139        * @access   private
     140        */
     141        private function set_locale() {
     142
     143            $plugin_i18n = new Piio_Image_Optimization_i18n();
     144
     145            $this->loader->add_action( 'plugins_loaded', $plugin_i18n, 'load_plugin_textdomain' );
     146
     147        }
     148
     149        /**
     150        * Register all of the hooks related to the admin area functionality
     151        * of the plugin.
     152        *
     153        * @since    0.9.0
     154        * @access   private
     155        */
     156        private function define_admin_hooks() {
     157
     158            $plugin_admin = new Piio_Image_Optimization_Admin( $this->get_plugin_name(), $this->get_version() );
     159            $this->loader->add_action( 'admin_menu', $plugin_admin, 'display_admin_page');
     160            $this->loader->add_action( 'admin_init', $plugin_admin, 'setup_sections');
     161            $this->loader->add_action( 'admin_init', $plugin_admin, 'setup_fields');
     162            $this->loader->add_action( 'admin_init', $plugin_admin, 'check_piio_incompatibility');
     163            $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
     164            $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
     165
     166        }
     167
     168        /**
     169        * Register all of the hooks related to the public-facing functionality
     170        * of the plugin.
     171        *
     172        * @since    0.9.0
     173        * @access   private
     174        */
     175        private function define_public_hooks() {
     176
     177            $plugin_public = new Piio_Image_Optimization_Public( $this->get_plugin_name(), $this->get_version() );
     178            $piio_enabled_option = get_option('piio_imageopt_enabled');
     179            $is_piio_enabled = (isset($piio_enabled_option[0])) ? ($piio_enabled_option[0] === "1") : false;
     180
     181            if ($is_piio_enabled && !is_admin()){
     182                ob_start();
     183                $this->loader->add_action( 'shutdown', $plugin_public, 'create_final_output_filter', -100 );
     184
     185                $this->loader->add_filter( 'piio_final_output', $plugin_public, 'filter_images' );
     186
     187                /* Cache plugins compatibility */
     188
     189                // WP Super Cache
     190                $this->loader->add_filter( 'wpsupercache_buffer', $plugin_public, 'filter_images' );
     191
     192                // W3 Total Cache 0.9.7+
     193                $this->loader->add_filter( 'w3tc_process_content', $plugin_public, 'filter_images' );
     194            }
     195
     196            $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' );
     197
     198        }
     199
     200        /**
     201        * Run the loader to execute all of the hooks with WordPress.
     202        *
     203        * @since    0.9.0
     204        */
     205        public function run() {
     206            $this->loader->run();
     207        }
     208
     209        /**
     210        * The name of the plugin used to uniquely identify it within the context of
     211        * WordPress and to define internationalization functionality.
     212        *
     213        * @since     0.9.0
     214        * @return    string    The name of the plugin.
     215        */
     216        public function get_plugin_name() {
     217            return $this->plugin_name;
     218        }
     219
     220        /**
     221        * The reference to the class that orchestrates the hooks with the plugin.
     222        *
     223        * @since     0.9.0
     224        * @return    Piio_Image_Optimization_Loader    Orchestrates the hooks of the plugin.
     225        */
     226        public function get_loader() {
     227            return $this->loader;
     228        }
     229
     230        /**
     231        * Retrieve the version number of the plugin.
     232        *
     233        * @since     0.9.0
     234        * @return    string    The version number of the plugin.
     235        */
     236        public function get_version() {
     237            return $this->version;
     238        }
     239
     240    }
    235241}
  • piio-image-optimization/trunk/piio-image-optimization.php

    r1954139 r1969996  
    1313* Plugin URI:        https://piio.co/wordpress
    1414* Description:       Generates responsive and optimized images, so you don't have to.
    15 * Version:           0.9.7
     15* Version:           0.9.8
    1616* Author:            Piio, Inc.
    1717* Author URI:        https://piio.co
     
    3030* Currently plugin version.
    3131*/
    32 define( 'PIIO_IMAGE_OPTIMIZATION_VERSION', '0.9.7' );
     32define( 'PIIO_IMAGE_OPTIMIZATION_VERSION', '0.9.8' );
    3333
    3434/**
  • piio-image-optimization/trunk/public/class-piio-image-optimization-public.php

    r1954139 r1969996  
    2121* @author     Piio, Inc. <support@piio.co>
    2222*/
    23 if ( !class_exists( 'Piio_Image_Optimization_Public' ) ) {
    24     class Piio_Image_Optimization_Public {
    25 
    26         /**
    27         * The ID of this plugin.
    28         *
    29         * @since    0.9.0
    30         * @access   private
    31         * @var      string    $plugin_name    The ID of this plugin.
    32         */
    33         private $plugin_name;
    34 
    35         /**
    36         * The version of this plugin.
    37         *
    38         * @since    0.9.0
    39         * @access   private
    40         * @var      string    $version    The current version of this plugin.
    41         */
    42         private $version;
    43 
    44         /**
    45         * Initialize the class and set its properties.
    46         *
    47         * @since    0.9.0
    48         * @param      string    $plugin_name       The name of the plugin.
    49         * @param      string    $version    The version of this plugin.
    50         */
    51         public function __construct( $plugin_name, $version ) {
    52 
    53             $this->plugin_name = $plugin_name;
    54             $this->version = $version;
    55 
    56         }
    57 
    58         public function create_final_output_filter(){
    59             $final = '';
    60             $levels = ob_get_level();
    61             for ($i = 0; $i < $levels; $i++) {
    62                 $final .= ob_get_clean();
    63             }
    64             echo apply_filters('piio_final_output', $final);
    65         }
    66 
    67         public function getLargestImageSrc($imgTag){
    68             //If tag contains srcset
    69             if (strpos($imgTag, 'srcset') !== FALSE){
    70                 preg_match('/\bsrcset\W*=\W*[\'"](.*)?[\'"]/Uxis', $imgTag, $matches);
    71                 //Get all sources
    72                 $sources = array_map('trim', explode(',', $matches[1]));
    73                 $size = 0;
    74                 foreach ($sources as $source){
    75                     //Extract url and size
    76                     $attr = array_map('trim', explode(' ', $source));
    77                     //url = $attr[0], size with unit = $attr[1]
    78                     //remove unit (w or x)
    79                     $attr[1] = intval(substr($attr[1], 0, strlen($attr[1]) - 1));
    80                     if ($attr[1] > $size){
    81                         $retSrc = $attr[0];
    82                         $size = $attr[1];
    83                     }
    84                 }
    85                 return $this->_url_to_absolute($retSrc);
    86             } else {
    87                 //Else just return src
    88                 preg_match('/\bsrc\W*=\W*[\'"](.*)?[\'"]/Uxis', $imgTag, $matches);
    89                 return (isset($matches[1])) ? $this->_url_to_absolute($matches[1]) : null;
    90             }
    91         }
    92 
    93         public function filter_images($HTMLContent){
    94             //Get optimization option and api key
    95             $optimization = get_option('piio_imageopt_optimization');
    96             $use_data_piio = isset($optimization[0]) ? ($optimization[0] === "1") : true;
    97             $api_key = get_option('piio_imageopt_api_key');
    98 
    99             $HTMLContent = $this->_replace_img_tags($HTMLContent, $use_data_piio, $api_key);
    100 
    101             $optimize_bck = get_option('piio_imageopt_optimize_bck');
    102             $optimize_bck = isset($optimize_bck[0]) ? ($optimize_bck[0] === "1") : true;
    103 
    104             if ($optimize_bck){
    105                 $HTMLContent = $this->_replace_bck_styles($HTMLContent, $use_data_piio, $api_key);
    106             }
    107 
    108             return $HTMLContent;
    109         }
    110 
    111         /**
    112         * Register the JavaScript for the public-facing side of the site.
    113         *
    114         * @since    0.9.0
    115         */
    116         public function enqueue_scripts() {
    117 
    118             $api_key        = get_option('piio_imageopt_api_key');
    119             $position       = get_option('piio_imageopt_script_position');
    120             $lazy_mode      = (get_option('piio_imageopt_lazy') === "1") ? 'strict' : 'friendly';
    121 
    122             $lazy_mode      = get_option('piio_imageopt_lazy');
    123             $lazy_mode      = (isset($lazy_mode[0]) && ($lazy_mode[0] === "1")) ? 'strict' : 'friendly';
    124 
    125             $enable_webp    = get_option('piio_imageopt_enable_webp');
    126             $enable_webp    = isset($enable_webp[0]) ? ($enable_webp[0] === "1")  : false;
    127 
    128             $domain         = get_site_url();
    129 
    130             $in_footer = isset($position[0]) ? ($position[0] === "0") : false;
    131 
    132             $jsVars = array(
    133                 'appKey' => $api_key,
    134                 'domain' => $domain,
    135                 'lazyLoadingMode' => $lazy_mode,
    136                 'disableWebP' => !$enable_webp
    137             );
    138 
    139             $piio_vars = "var piioData = " . json_encode($jsVars);
    140 
    141             wp_register_script('piio.js', '//js.piio.co/' . $api_key . '/piio.min.js', array(), false, $in_footer);
    142             wp_add_inline_script('piio.js', $piio_vars, 'before');
    143             wp_enqueue_script('piio.js');
    144         }
    145 
    146 
    147         private function _replace_img_tags($HTMLContent, $use_data_piio, $api_key){
    148             $placeholder_url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8+f9vPQAJZAN2rlRQVAAAAABJRU5ErkJggg==";
    149             $matches = array();
    150             preg_match_all('/<img[\s\r\n]+.*?>/is', $HTMLContent, $matches);
    151 
    152             $search = array();
    153             $replace = array();
    154 
    155             $i = 0;
    156             foreach ($matches[0] as $imgHTML) {
    157 
    158                 // don't to the replacement if the image is a data-uri or has class piio-skip
    159                 if (!preg_match("/src=['\"]data:image/is", $imgHTML) && !preg_match("/class=(['\"]|(['\"][^'\"]*)\s)piio-skip(\"|\s([^'\"]*)['\"])/is", $imgHTML)) {
    160                     $i++;
    161 
    162                     // get largest image src
    163                     $src = $this->getLargestImageSrc($imgHTML);
    164 
    165                     $replaceHTML = '';
    166 
    167                     if ($use_data_piio){
    168                         // replace the src and add the data-piio attribute
    169                         $replaceHTML = preg_replace('/<img(.*?)src=(["\'])(.*?)["\']/is', '<img$1src=$2' . $placeholder_url . '$2 data-piio=$2' . $src . "$2", $imgHTML);
    170                         // remove srcset and sizes attributes
    171                         $replaceHTML = preg_replace('/<img(.*?)srcset=["\'].*?["\']/is', '<img$1', $replaceHTML);
    172                         $replaceHTML = preg_replace('/<img(.*?)sizes=["\'].*?["\']/is', '<img$1', $replaceHTML);
    173 
    174                     } else {
    175                         $enable_webp = get_option('piio_imageopt_enable_webp');
    176                         $enable_webp = isset($enable_webp[0]) ? ($enable_webp[0] === "1") : true;
    177 
    178                         $params = '';
    179                         //Check if client is using Chrome
    180                         if($enable_webp && preg_match('/(Chrome)\//i',$_SERVER['HTTP_USER_AGENT']) && !preg_match('/(Aviator|ChromePlus|coc_|Dragon|Edge|Flock|Iron|Kinza|Maxthon|MxNitro|Nichrome|OPR|Perk|Rockmelt|Seznam|Sleipnir|Spark|UBrowser|Vivaldi|WebExplorer|YaBrowser)/i',$_SERVER['HTTP_USER_AGENT'])){
    181                             $params .= 'wp,1';
    182                         }
    183 
    184                         // remove srcset and sizes attributes as we are adding our own
    185                         $replaceHTML = preg_replace('/<img(.*?)srcset=["\'].*?["\']/is', '<img$1', $imgHTML);
    186                         $replaceHTML = preg_replace('/<img(.*?)sizes=["\'].*?["\']/is', '<img$1', $replaceHTML);
    187 
    188                         $srcAttr = urlencode($src);
    189 
    190                         $breakpoints = array("576", "768", "992", "1200");
    191                         $srcset_values = array();
    192                         foreach ($breakpoints as $width) {
    193                             $local_params = 'vw,' . $width . (($params != '') ? ',' . $params : '');
    194                             array_push($srcset_values, 'https://pcdn.piiojs.com/i/' . $api_key . '/' . $local_params . '/' . $srcAttr . ' ' . $width . 'w');
    195                         }
    196                         // replace src with largest image and add srcset
    197                         $replaceHTML = preg_replace('/<img(.*?)src=(["\'])(.*?)["\']/is', '<img$1src=$2' . 'https://pcdn.piiojs.com/i/' . $api_key . (($params != '') ? '/' . $params : '') . '/' . $srcAttr . '$2 srcset=$2' . implode(', ', $srcset_values) . '$2', $replaceHTML);
    198                     }
    199 
    200                     array_push($search, $imgHTML);
    201                     array_push($replace, $replaceHTML);
    202                 }
    203             }
    204 
    205             $search = array_unique($search);
    206             $replace = array_unique($replace);
    207 
    208             return str_replace($search, $replace, $HTMLContent);
    209         }
    210 
    211         private function _replace_bck_styles($HTMLContent, $use_data_piio, $api_key){
    212             $matches = array();
    213             preg_match_all("/<.*?\sstyle=['\"][^>]*?background(-image)?:.*?url\(\s*.*?\s*\);?.*?['\"].*?>/is", $HTMLContent, $matches);
    214 
    215             $search = array();
    216             $replace = array();
    217 
    218             $i = 0;
    219             foreach ($matches[0] as $bckHTML) {
    220                 // don't to the replacement if the image is a data-uri or has class piio-skip
    221                 if (!preg_match("/url\(['\"]data:image/is", $bckHTML) && !preg_match("/class=(['\"]|(['\"][^'\"]*)\s)piio-skip(\"|\s([^'\"]*)['\"])/is", $bckHTML)) {
    222                     $i++;
    223 
    224                     $replaceHTML = '';
    225 
    226                     if ($use_data_piio){
    227                         // replace the background-image attribute from style and add the data-piio-bck attribute
    228                         $replaceHTML = preg_replace("/(\sstyle=['\"][^>]*?)(background-image:.*?url\((\s*.*?\s*)\));?(.*?['\"])/is", '$1$4 data-piio-bck=' . "$3", $bckHTML);
    229                         $replaceHTML = preg_replace("/(\sstyle=['\"][^>]*?background:.*?)(url\((\s*.*?\s*)\));?(.*?['\"])/is", '$1$4 data-piio-bck=' . "$3", $replaceHTML);
    230 
    231                     } else {
    232                         $enable_webp = get_option('piio_imageopt_enable_webp');
    233                         $enable_webp = isset($enable_webp[0]) ? ($enable_webp[0] === "1") : true;
    234 
    235                         $params = "";
    236                         //Check if client is using Chrome
    237                         if($enable_webp && preg_match('/(Chrome)\//i',$_SERVER['HTTP_USER_AGENT']) && !preg_match('/(Aviator|ChromePlus|coc_|Dragon|Edge|Flock|Iron|Kinza|Maxthon|MxNitro|Nichrome|OPR|Perk|Rockmelt|Seznam|Sleipnir|Spark|UBrowser|Vivaldi|WebExplorer|YaBrowser)/i',$_SERVER['HTTP_USER_AGENT'])){
    238                             $params .= "wp,1";
    239                         }
    240 
    241                         $callback = new Piio_Image_Callback($api_key, $params);
    242 
    243                         $replaceHTML = preg_replace_callback("/(\sstyle=['\"][^>]*?)(background-image:.*?url\(['\"](\s*.*?\s*)['\"]\));?(.*?['\"])/is", array($callback, 'callback_background_image'), $bckHTML);
    244 
    245                         $replaceHTML = preg_replace_callback("/(\sstyle=['\"][^>]*?background:.*?url\(['\"])(\s*.*?\s*)(['\"]\);?.*?['\"])/is", array($callback, 'callback_background'), $replaceHTML);
    246                     }
    247 
    248                     array_push($search, $bckHTML);
    249                     array_push($replace, $replaceHTML);
    250                 }
    251             }
    252 
    253             $search = array_unique($search);
    254             $replace = array_unique($replace);
    255 
    256             return str_replace($search, $replace, $HTMLContent);
    257         }
    258 
    259         private function _url_to_absolute($relativeUrl){
    260             $baseUrl = get_site_url();
    261             // If relative URL has a scheme, clean path and return.
    262             $r = parse_url( $relativeUrl );
    263             if ( $r === FALSE )
    264             return FALSE;
    265             if ( !empty( $r['scheme'] ) )
    266             {
    267                 if ( !empty( $r['path'] ) && $r['path'][0] == '/' )
    268                 $r['path'] = $this->_url_remove_dot_segments($r['path']);
    269                 return $this->_join_url( $r );
    270             }
    271 
    272             // Make sure the base URL is absolute.
    273             $b = parse_url( $baseUrl );
    274             if ( $b === FALSE || empty( $b['scheme'] ) || empty( $b['host'] ) )
    275             return FALSE;
    276             $r['scheme'] = $b['scheme'];
    277 
    278             // If relative URL has an authority, clean path and return.
    279             if ( isset( $r['host'] ) )
    280             {
    281                 if ( !empty( $r['path'] ) )
    282                 $r['path'] = $this->_url_remove_dot_segments($r['path']);
    283                 return $this->_join_url( $r );
    284             }
    285             unset( $r['port'] );
    286             unset( $r['user'] );
    287             unset( $r['pass'] );
    288 
    289             // Copy base authority.
    290             $r['host'] = $b['host'];
    291             if ( isset( $b['port'] ) ) $r['port'] = $b['port'];
    292             if ( isset( $b['user'] ) ) $r['user'] = $b['user'];
    293             if ( isset( $b['pass'] ) ) $r['pass'] = $b['pass'];
    294 
    295             // If relative URL has no path, use base path
    296             if ( empty( $r['path'] ) )
    297             {
    298                 if ( !empty( $b['path'] ) )
    299                 $r['path'] = $b['path'];
    300                 if ( !isset( $r['query'] ) && isset( $b['query'] ) )
    301                 $r['query'] = $b['query'];
    302                 return $this->_join_url( $r );
    303             }
    304 
    305             // If relative URL path doesn't start with /, merge with base path
    306             if ( $r['path'][0] != '/' )
    307             {
    308                 $base = mb_strrchr( $b['path'], '/', TRUE, 'UTF-8' );
    309                 if ( $base === FALSE ) $base = '';
    310                 $r['path'] = $base . '/' . $r['path'];
    311             }
    312             $r['path'] = $this->_url_remove_dot_segments($r['path']);
    313             return $this->_join_url($r);
    314         }
    315 
    316         private function _join_url($parts, $encode=TRUE){
    317             if ( $encode )
    318             {
    319                 if ( isset( $parts['user'] ) )
    320                 $parts['user']     = rawurlencode( $parts['user'] );
    321                 if ( isset( $parts['pass'] ) )
    322                 $parts['pass']     = rawurlencode( $parts['pass'] );
    323                 if ( isset( $parts['host'] ) &&
    324                 !preg_match( '!^(\[[\da-f.:]+\]])|([\da-f.:]+)$!ui', $parts['host'] ) )
    325                 $parts['host']     = rawurlencode( $parts['host'] );
    326                 if ( !empty( $parts['path'] ) )
    327                 $parts['path']     = preg_replace( '!%2F!ui', '/',
    328                 rawurlencode( $parts['path'] ) );
    329                 if ( isset( $parts['query'] ) )
    330                 $parts['query']    = rawurlencode( $parts['query'] );
    331                 if ( isset( $parts['fragment'] ) )
    332                 $parts['fragment'] = rawurlencode( $parts['fragment'] );
    333             }
    334 
    335             $url = '';
    336             if ( !empty( $parts['scheme'] ) )
    337             {
    338                 $url .= $parts['scheme'] . ':';
    339             }
    340             if ( isset( $parts['host'] ) )
    341             {
    342                 $url .= '//';
    343                 if ( isset( $parts['user'] ) )
    344                 {
    345                     $url .= $parts['user'];
    346                     if ( isset( $parts['pass'] ) )
    347                     $url .= ':' . $parts['pass'];
    348                     $url .= '@';
    349                 }
    350                 if ( preg_match( '!^[\da-f]*:[\da-f.:]+$!ui', $parts['host'] ) )
    351                 $url .= '[' . $parts['host'] . ']'; // IPv6
    352                 else
    353                 $url .= $parts['host'];             // IPv4 or name
    354                 if ( isset( $parts['port'] ) )
    355                 $url .= ':' . $parts['port'];
    356                 if ( !empty( $parts['path'] ) && $parts['path'][0] != '/' )
    357                 $url .= '/';
    358             }
    359             if ( !empty( $parts['path'] ) )
    360             $url .= $parts['path'];
    361             if ( isset( $parts['query'] ) )
    362             $url .= '?' . $parts['query'];
    363             if ( isset( $parts['fragment'] ) )
    364             $url .= '#' . $parts['fragment'];
    365             return $url;
    366         }
    367 
    368         private function _url_remove_dot_segments($path){
    369             // multi-byte character explode
    370             $inSegs  = preg_split( '!/!u', $path );
    371             $outSegs = array( );
    372             foreach ( $inSegs as $seg )
    373             {
    374                 if ( $seg == '' || $seg == '.')
    375                 continue;
    376                 if ( $seg == '..' )
    377                 array_pop( $outSegs );
    378                 else
    379                 array_push( $outSegs, $seg );
    380             }
    381             $outPath = implode( '/', $outSegs );
    382             if ( $path[0] == '/' )
    383             $outPath = '/' . $outPath;
    384             // compare last multi-byte character against '/'
    385             if ( $outPath != '/' &&
    386             (mb_strlen($path)-1) == mb_strrpos( $path, '/', 'UTF-8' ) )
    387             $outPath .= '/';
    388             return $outPath;
    389         }
    390     }
     23if (!class_exists('Piio_Image_Optimization_Public')) {
     24    class Piio_Image_Optimization_Public
     25    {
     26
     27        /**
     28        * The ID of this plugin.
     29        *
     30        * @since    0.9.0
     31        * @access   private
     32        * @var      string    $plugin_name    The ID of this plugin.
     33        */
     34        private $plugin_name;
     35
     36        /**
     37        * The version of this plugin.
     38        *
     39        * @since    0.9.0
     40        * @access   private
     41        * @var      string    $version    The current version of this plugin.
     42        */
     43        private $version;
     44
     45        /**
     46        * Initialize the class and set its properties.
     47        *
     48        * @since    0.9.0
     49        * @param      string    $plugin_name       The name of the plugin.
     50        * @param      string    $version    The version of this plugin.
     51        */
     52        public function __construct($plugin_name, $version)
     53        {
     54            $this->plugin_name = $plugin_name;
     55            $this->version = $version;
     56
     57            /**
     58            * The class responsible for defining callbacks for replacing
     59            * of the plugin.
     60            */
     61            require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-piio-image-optimization-callbacks.php';
     62        }
     63
     64        public function create_final_output_filter()
     65        {
     66            $final = '';
     67            $levels = ob_get_level();
     68            for ($i = 0; $i < $levels; $i++) {
     69                $final .= ob_get_clean();
     70            }
     71            echo apply_filters('piio_final_output', $final);
     72        }
     73
     74        public function get_largest_image_src($imgTag)
     75        {
     76            //If tag contains srcset
     77            if (strpos($imgTag, 'srcset') !== false) {
     78                preg_match('/\bsrcset\W*=\W*[\'"](.*)?[\'"]/Uxis', $imgTag, $matches);
     79                //Get all sources
     80                $sources = array_map('trim', explode(',', $matches[1]));
     81                $size = 0;
     82                foreach ($sources as $source) {
     83                    //Extract url and size
     84                    $attr = array_map('trim', explode(' ', $source));
     85                    //Check if we have size with unit
     86                    if ($attr[1]) {
     87                        //url = $attr[0], size with unit = $attr[1]
     88                        //remove unit (w or x)
     89                        $attr[1] = intval(substr($attr[1], 0, strlen($attr[1]) - 1));
     90                        if ($attr[1] > $size) {
     91                            $retSrc = $attr[0];
     92                            $size = $attr[1];
     93                        }
     94                    }
     95                }
     96                if (isset($retSrc)) {
     97                    return $this->_url_to_absolute($retSrc);
     98                }
     99            }
     100            //Else just return src
     101            preg_match('/\bsrc\W*=\W*[\'"](.*)?[\'"]/Uxis', $imgTag, $matches);
     102            return (isset($matches[1])) ? $this->_url_to_absolute($matches[1]) : null;
     103        }
     104
     105        public function filter_images($HTMLContent)
     106        {
     107            //Get optimization option and api key
     108            $optimization = get_option('piio_imageopt_optimization');
     109            $use_data_piio = isset($optimization[0]) ? ($optimization[0] === "1") : true;
     110            $api_key = get_option('piio_imageopt_api_key');
     111
     112            $HTMLContent = $this->_replace_img_tags($HTMLContent, $use_data_piio, $api_key);
     113
     114            $optimize_bck = get_option('piio_imageopt_optimize_bck');
     115            $optimize_bck = isset($optimize_bck[0]) ? ($optimize_bck[0] === "1") : true;
     116
     117            if ($optimize_bck) {
     118                $HTMLContent = $this->_replace_bck_styles($HTMLContent, $use_data_piio, $api_key);
     119            }
     120
     121            return $HTMLContent;
     122        }
     123
     124        /**
     125        * Register the JavaScript for the public-facing side of the site.
     126        *
     127        * @since    0.9.0
     128        */
     129        public function enqueue_scripts()
     130        {
     131
     132            $api_key = get_option('piio_imageopt_api_key');
     133            $position = get_option('piio_imageopt_script_position');
     134            $lazy_mode = (get_option('piio_imageopt_lazy') === "1") ? 'strict' : 'friendly';
     135
     136            $lazy_mode = get_option('piio_imageopt_lazy');
     137            $lazy_mode = (isset($lazy_mode[0]) && ($lazy_mode[0] === "1")) ? 'strict' : 'friendly';
     138
     139            $enable_webp = get_option('piio_imageopt_enable_webp');
     140            $enable_webp = isset($enable_webp[0]) ? ($enable_webp[0] === "1")  : false;
     141
     142            $domain = get_site_url();
     143
     144            $in_footer = isset($position[0]) ? ($position[0] === "0") : false;
     145
     146            $jsVars = array(
     147                'appKey' => $api_key,
     148                'domain' => $domain,
     149                'lazyLoadingMode' => $lazy_mode,
     150                'disableWebP' => !$enable_webp
     151            );
     152
     153            $piio_vars = "var piioData = " . json_encode($jsVars);
     154
     155            wp_register_script('piio.js', '//js.piio.co/' . $api_key . '/piio.min.js', array(), false, $in_footer);
     156            wp_add_inline_script('piio.js', $piio_vars, 'before');
     157            wp_enqueue_script('piio.js');
     158        }
     159
     160
     161        private function _replace_img_tags($HTMLContent, $use_data_piio, $api_key)
     162        {
     163            $placeholder_url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8+f9vPQAJZAN2rlRQVAAAAABJRU5ErkJggg==";
     164            $matches = array();
     165            preg_match_all('/<img[\s\r\n]+.*?>/is', $HTMLContent, $matches);
     166
     167            $search = array();
     168            $replace = array();
     169
     170            $std_opt_img_added = false;
     171
     172            $i = 0;
     173            foreach ($matches[0] as $imgHTML) {
     174                // don't to the replacement if the image is a data-uri or has class piio-skip
     175                if (!preg_match("/src=['\"]data:image/is", $imgHTML) && !preg_match("/class=(['\"]|(['\"][^'\"]*)\s)piio-skip(['\"]|\s([^'\"]*)['\"])/is", $imgHTML)) {
     176                    $i++;
     177
     178                    // get largest image src
     179                    $src = $this->get_largest_image_src($imgHTML);
     180
     181                    $replaceHTML = '';
     182
     183                    if ($use_data_piio) {
     184                        // advanced optimization enabled
     185
     186                        // replace the src and add the data-piio attribute
     187                        $replaceHTML = preg_replace('/<img(.*?)src=(["\'])(.*?)["\']/is', '<img$1src=$2' . $placeholder_url . '$2 data-piio=$2' . urldecode($src) . "$2", $imgHTML);
     188                        // remove srcset and sizes attributes
     189                        $replaceHTML = preg_replace('/<img(.*?)srcset=["\'].*?["\']/is', '<img$1', $replaceHTML);
     190                        $replaceHTML = preg_replace('/<img(.*?)sizes=["\'].*?["\']/is', '<img$1', $replaceHTML);
     191                    } else {
     192                        // standard optimization enabled
     193
     194                        $enable_webp = get_option('piio_imageopt_enable_webp');
     195                        $enable_webp = isset($enable_webp[0]) ? ($enable_webp[0] === "1") : true;
     196
     197                        $params = '';
     198                        //Check if client is using Chrome
     199                        if ($enable_webp && preg_match('/(Chrome)\//i', $_SERVER['HTTP_USER_AGENT']) && !preg_match('/(Aviator|ChromePlus|coc_|Dragon|Edge|Flock|Iron|Kinza|Maxthon|MxNitro|Nichrome|OPR|Perk|Rockmelt|Seznam|Sleipnir|Spark|UBrowser|Vivaldi|WebExplorer|YaBrowser)/i', $_SERVER['HTTP_USER_AGENT'])) {
     200                            $params .= 'wp,1';
     201                        }
     202
     203                        // remove srcset and sizes attributes as we are adding our own
     204                        $replaceHTML = preg_replace('/<img(.*?)srcset=["\'].*?["\']/is', '<img$1', $imgHTML);
     205                        $replaceHTML = preg_replace('/<img(.*?)sizes=["\'].*?["\']/is', '<img$1', $replaceHTML);
     206
     207                        $srcAttr = urlencode($src);
     208
     209                        $breakpoints = array("576", "768", "992", "1200");
     210                        $srcset_values = array();
     211                        foreach ($breakpoints as $width) {
     212                            $local_params = 'vw,' . $width . (($params != '') ? ',' . $params : '');
     213                            array_push($srcset_values, 'https://pcdn.piiojs.com/i/' . $api_key . '/' . $local_params . '/' . $srcAttr . ' ' . $width . 'w');
     214                        }
     215                        // replace src with largest image and add srcset
     216                        $replaceHTML = preg_replace('/<img(.*?)src=(["\'])(.*?)["\']/is', '<img$1src=$2' . 'https://pcdn.piiojs.com/i/' . $api_key . (($params != '') ? '/' . $params : '') . '/' . $srcAttr . '$2 srcset=$2' . implode(', ', $srcset_values) . '$2', $replaceHTML);
     217
     218                        // add img with data-piio to log user data for consumption
     219                        if (!$std_opt_img_added) {
     220                            $body_matches = array();
     221                            if (preg_match('/<body.*?>/is', $HTMLContent, $body_matches, PREG_OFFSET_CAPTURE) > 0) {
     222                                // get <body start position
     223                                // body_matches[0][0] contains string, body_matches[0][1] contains string index
     224                                $body_end_pos = $body_matches[0][1] + strlen($body_matches[0][0]);
     225                                $HTMLContent = substr_replace($HTMLContent, $this->_get_transparent_svg_with_piio(), $body_end_pos, 0);
     226                            };
     227                            $std_opt_img_added = true;
     228                        }
     229                    }
     230
     231                    array_push($search, $imgHTML);
     232                    array_push($replace, $replaceHTML);
     233                }
     234            }
     235
     236            $search = array_unique($search);
     237            $replace = array_unique($replace);
     238
     239            return str_replace($search, $replace, $HTMLContent);
     240        }
     241
     242        private function _replace_bck_styles($HTMLContent, $use_data_piio, $api_key)
     243        {
     244            $matches = array();
     245            preg_match_all("/<[^>]*?\sstyle=['\"][^>]*?background(-image)?:.*?url\(\s*.*?\s*\);?.*?['\"].*?>/is", $HTMLContent, $matches);
     246
     247            $search = array();
     248            $replace = array();
     249
     250            $i = 0;
     251            foreach ($matches[0] as $bckHTML) {
     252                // don't to the replacement if the image is a data-uri or has class piio-skip
     253                if (!preg_match("/url\(['\"]data:image/is", $bckHTML) && !preg_match("/class=(['\"]|(['\"][^'\"]*)\s)piio-skip(['\"]|\s([^'\"]*)['\"])/is", $bckHTML)) {
     254                    $i++;
     255
     256                    $replaceHTML = '';
     257
     258                    if ($use_data_piio) {
     259                        // replace the background-image attribute from style and add the data-piio-bck attribute
     260                        $replaceHTML = preg_replace("/(\sstyle=['\"][^>]*?)(background-image:.*?url\((\s*.*?\s*)\));?(.*?['\"])/is", '$1$4 data-piio-bck=' . urldecode("$3"), $bckHTML);
     261                        $replaceHTML = preg_replace("/(\sstyle=['\"][^>]*?background:.*?)(url\((\s*.*?\s*)\));?(.*?['\"])/is", '$1$4 data-piio-bck=' . urldecode("$3"), $replaceHTML);
     262                    } else {
     263                        $enable_webp = get_option('piio_imageopt_enable_webp');
     264                        $enable_webp = isset($enable_webp[0]) ? ($enable_webp[0] === "1") : true;
     265
     266                        $params = "";
     267                        //Check if client is using Chrome
     268                        if ($enable_webp && preg_match('/(Chrome)\//i', $_SERVER['HTTP_USER_AGENT']) && !preg_match('/(Aviator|ChromePlus|coc_|Dragon|Edge|Flock|Iron|Kinza|Maxthon|MxNitro|Nichrome|OPR|Perk|Rockmelt|Seznam|Sleipnir|Spark|UBrowser|Vivaldi|WebExplorer|YaBrowser)/i', $_SERVER['HTTP_USER_AGENT'])) {
     269                            $params .= "wp,1";
     270                        }
     271
     272                        $callback = new Piio_Image_Optimization_Callbacks($api_key, $params);
     273
     274                        $replaceHTML = preg_replace_callback("/(\sstyle=['\"][^>]*?)(background-image:.*?url\(['\"](\s*.*?\s*)['\"]\));?(.*?['\"])/is", array($callback, 'callback_background_image'), $bckHTML);
     275
     276                        $replaceHTML = preg_replace_callback("/(\sstyle=['\"][^>]*?background:.*?url\(['\"])(\s*.*?\s*)(['\"]\);?.*?['\"])/is", array($callback, 'callback_background'), $replaceHTML);
     277                    }
     278
     279                    array_push($search, $bckHTML);
     280                    array_push($replace, $replaceHTML);
     281                }
     282            }
     283
     284            $search = array_unique($search);
     285            $replace = array_unique($replace);
     286
     287            return str_replace($search, $replace, $HTMLContent);
     288        }
     289
     290        private function _get_transparent_svg_with_piio()
     291        {
     292            return "<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8+f9vPQAJZAN2rlRQVAAAAABJRU5ErkJggg==' data-piio='" . plugin_dir_url(__FILE__) . 'images/transparent.svg' . "' style='width:1px !important;height:1px !important;position:absolute !important;top:0 !important;left:-1px !important'>";
     293        }
     294
     295        private function _url_to_absolute($relativeUrl)
     296        {
     297            $baseUrl = get_site_url();
     298            // If relative URL has a scheme, clean path and return.
     299            $r = parse_url($relativeUrl);
     300            if ($r === false) {
     301                return false;
     302            }
     303            if (!empty($r['scheme'])) {
     304                if (!empty($r['path']) && $r['path'][0] == '/') {
     305                    $r['path'] = $this->_url_remove_dot_segments($r['path']);
     306                }
     307                return $this->_join_url($r);
     308            }
     309
     310            // Make sure the base URL is absolute.
     311            $b = parse_url($baseUrl);
     312            if ($b === false || empty($b['scheme']) || empty($b['host'])) {
     313                return false;
     314            }
     315            $r['scheme'] = $b['scheme'];
     316
     317            // If relative URL has an authority, clean path and return.
     318            if (isset($r['host'])) {
     319                if (!empty($r['path'])) {
     320                    $r['path'] = $this->_url_remove_dot_segments($r['path']);
     321                }
     322                return $this->_join_url($r);
     323            }
     324            unset($r['port']);
     325            unset($r['user']);
     326            unset($r['pass']);
     327
     328            // Copy base authority.
     329            $r['host'] = $b['host'];
     330            if (isset($b['port'])) {
     331                $r['port'] = $b['port'];
     332            }
     333            if (isset($b['user'])) {
     334                $r['user'] = $b['user'];
     335            }
     336            if (isset($b['pass'])) {
     337                $r['pass'] = $b['pass'];
     338            }
     339
     340            // If relative URL has no path, use base path
     341            if (empty($r['path'])) {
     342                if (!empty($b['path'])) {
     343                    $r['path'] = $b['path'];
     344                }
     345                if (!isset($r['query']) && isset($b['query'])) {
     346                    $r['query'] = $b['query'];
     347                }
     348                return $this->_join_url($r);
     349            }
     350
     351            // If relative URL path doesn't start with /, merge with base path
     352            if ($r['path'][0] != '/') {
     353                $base = mb_strrchr($b['path'], '/', true, 'UTF-8');
     354                if ($base === false) {
     355                    $base = '';
     356                }
     357                $r['path'] = $base . '/' . $r['path'];
     358            }
     359            $r['path'] = $this->_url_remove_dot_segments($r['path']);
     360            return $this->_join_url($r);
     361        }
     362
     363        private function _join_url($parts, $encode = true)
     364        {
     365            if ($encode) {
     366                if (isset($parts['user'])) {
     367                    $parts['user'] = rawurlencode($parts['user']);
     368                }
     369                if (isset($parts['pass'])) {
     370                    $parts['pass'] = rawurlencode($parts['pass']);
     371                }
     372                if (isset($parts['host']) && !preg_match('!^(\[[\da-f.:]+\]])|([\da-f.:]+)$!ui', $parts['host'])) {
     373                    $parts['host'] = rawurlencode($parts['host']);
     374                }
     375                if (!empty($parts['path'])) {
     376                    $parts['path'] = preg_replace('!%2F!ui', '/', rawurlencode($parts['path']));
     377                }
     378                if (isset($parts['query'])) {
     379                    $parts['query'] = rawurlencode($parts['query']);
     380                }
     381                if (isset($parts['fragment'])) {
     382                    $parts['fragment'] = rawurlencode($parts['fragment']);
     383                }
     384            }
     385
     386            $url = '';
     387            if (!empty($parts['scheme'])) {
     388                $url .= $parts['scheme'] . ':';
     389            }
     390            if (isset($parts['host'])) {
     391                $url .= '//';
     392                if (isset($parts['user'])) {
     393                    $url .= $parts['user'];
     394                    if (isset($parts['pass'])) {
     395                        $url .= ':' . $parts['pass'];
     396                    }
     397                    $url .= '@';
     398                }
     399                if (preg_match('!^[\da-f]*:[\da-f.:]+$!ui', $parts['host'])) {
     400                    $url .= '[' . $parts['host'] . ']'; // IPv6
     401                } else {
     402                    $url .= $parts['host'];             // IPv4 or name
     403                }
     404                if (isset($parts['port'])) {
     405                    $url .= ':' . $parts['port'];
     406                }
     407                if (!empty($parts['path']) && $parts['path'][0] != '/') {
     408                    $url .= '/';
     409                }
     410            }
     411            if (!empty($parts['path'])) {
     412                $url .= $parts['path'];
     413            }
     414            if (isset($parts['query'])) {
     415                $url .= '?' . $parts['query'];
     416            }
     417            if (isset($parts['fragment'])) {
     418                $url .= '#' . $parts['fragment'];
     419            }
     420            return $url;
     421        }
     422
     423        private function _url_remove_dot_segments($path)
     424        {
     425            // multi-byte character explode
     426            $inSegs = preg_split('!/!u', $path);
     427            $outSegs = array( );
     428            foreach ($inSegs as $seg) {
     429                if ($seg == '' || $seg == '.') {
     430                    continue;
     431                }
     432                if ($seg == '..') {
     433                    array_pop($outSegs);
     434                } else {
     435                    array_push($outSegs, $seg);
     436                }
     437            }
     438            $outPath = implode('/', $outSegs);
     439            if ($path[0] == '/') {
     440                $outPath = '/' . $outPath;
     441            }
     442            // compare last multi-byte character against '/'
     443            if ($outPath != '/' && (mb_strlen($path)-1) == mb_strrpos($path, '/', 'UTF-8')) {
     444                $outPath .= '/';
     445            }
     446            return $outPath;
     447        }
     448    }
    391449}
    392 if ( !class_exists( 'Piio_Image_Callback' ) ) {
    393     class Piio_Image_Callback {
    394         private $api_key;
    395         private $params;
    396 
    397         function __construct($api_key, $params) {
    398             $this->$api_key = $api_key;
    399             $this->$params = $params;
    400         }
    401 
    402         public function callback_background_image($matches) {
    403             $srcAttr = urlencode($matches[3]);
    404             return $matches[1] . "background-image:url('https://pcdn.piiojs.com/i/" . $this->api_key . (($this->params != '') ? '/' . $this->params : '') . "/" . $srcAttr . "');" . $matches[4];
    405         }
    406 
    407         public function callback_background($matches) {
    408             $srcAttr = urlencode($matches[2]);
    409             return $matches[1] . "https://pcdn.piiojs.com/i/" . $this->api_key . (($this->params != '') ? '/' . $this->params : '') . "/" . $srcAttr . $matches[3];
    410         }
    411     }
    412 }
  • piio-image-optimization/trunk/readme.txt

    r1954139 r1969996  
    66Requires PHP: 5.3.0
    77Tested up to: 4.9.8
    8 Stable tag: 0.9.7
     8Stable tag: 0.9.8
    99License: GPLv2 or later
    1010License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    121121
    122122== Changelog ==
     123= 0.9.8 =
     124* W3 Total Cache v 0.9.7+ support added
     125* Standard optimization improved
    123126= 0.9.7 =
    124 * Added older PHP versions support.
     127* Added older PHP versions support
    125128= 0.9.6 =
    126129* Set advanced optimization as default
Note: See TracChangeset for help on using the changeset viewer.