Changeset 1969996
- Timestamp:
- 11/06/2018 05:32:36 PM (7 years ago)
- Location:
- piio-image-optimization
- Files:
-
- 8 edited
- 1 copied
-
tags/0.9.8 (copied) (copied from piio-image-optimization/trunk)
-
tags/0.9.8/includes/class-piio-image-optimization.php (modified) (1 diff)
-
tags/0.9.8/piio-image-optimization.php (modified) (2 diffs)
-
tags/0.9.8/public/class-piio-image-optimization-public.php (modified) (1 diff)
-
tags/0.9.8/readme.txt (modified) (2 diffs)
-
trunk/includes/class-piio-image-optimization.php (modified) (1 diff)
-
trunk/piio-image-optimization.php (modified) (2 diffs)
-
trunk/public/class-piio-image-optimization-public.php (modified) (1 diff)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
piio-image-optimization/tags/0.9.8/includes/class-piio-image-optimization.php
r1921770 r1969996 29 29 */ 30 30 if ( !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 } 235 241 } -
piio-image-optimization/tags/0.9.8/piio-image-optimization.php
r1954139 r1969996 13 13 * Plugin URI: https://piio.co/wordpress 14 14 * Description: Generates responsive and optimized images, so you don't have to. 15 * Version: 0.9. 715 * Version: 0.9.8 16 16 * Author: Piio, Inc. 17 17 * Author URI: https://piio.co … … 30 30 * Currently plugin version. 31 31 */ 32 define( 'PIIO_IMAGE_OPTIMIZATION_VERSION', '0.9. 7' );32 define( 'PIIO_IMAGE_OPTIMIZATION_VERSION', '0.9.8' ); 33 33 34 34 /** -
piio-image-optimization/tags/0.9.8/public/class-piio-image-optimization-public.php
r1954139 r1969996 21 21 * @author Piio, Inc. <support@piio.co> 22 22 */ 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 } 23 if (!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 } 391 449 } 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 6 6 Requires PHP: 5.3.0 7 7 Tested up to: 4.9.8 8 Stable tag: 0.9. 78 Stable tag: 0.9.8 9 9 License: GPLv2 or later 10 10 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 121 121 122 122 == Changelog == 123 = 0.9.8 = 124 * W3 Total Cache v 0.9.7+ support added 125 * Standard optimization improved. 123 126 = 0.9.7 = 124 127 * Added older PHP versions support. -
piio-image-optimization/trunk/includes/class-piio-image-optimization.php
r1921770 r1969996 29 29 */ 30 30 if ( !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 } 235 241 } -
piio-image-optimization/trunk/piio-image-optimization.php
r1954139 r1969996 13 13 * Plugin URI: https://piio.co/wordpress 14 14 * Description: Generates responsive and optimized images, so you don't have to. 15 * Version: 0.9. 715 * Version: 0.9.8 16 16 * Author: Piio, Inc. 17 17 * Author URI: https://piio.co … … 30 30 * Currently plugin version. 31 31 */ 32 define( 'PIIO_IMAGE_OPTIMIZATION_VERSION', '0.9. 7' );32 define( 'PIIO_IMAGE_OPTIMIZATION_VERSION', '0.9.8' ); 33 33 34 34 /** -
piio-image-optimization/trunk/public/class-piio-image-optimization-public.php
r1954139 r1969996 21 21 * @author Piio, Inc. <support@piio.co> 22 22 */ 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 } 23 if (!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 } 391 449 } 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 6 6 Requires PHP: 5.3.0 7 7 Tested up to: 4.9.8 8 Stable tag: 0.9. 78 Stable tag: 0.9.8 9 9 License: GPLv2 or later 10 10 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 121 121 122 122 == Changelog == 123 = 0.9.8 = 124 * W3 Total Cache v 0.9.7+ support added 125 * Standard optimization improved 123 126 = 0.9.7 = 124 * Added older PHP versions support .127 * Added older PHP versions support 125 128 = 0.9.6 = 126 129 * Set advanced optimization as default
Note: See TracChangeset
for help on using the changeset viewer.