Version Description
- Feature: Image Service API extension: WebP conversion options
Download this release
Release Info
Developer | joemoto |
Plugin | W3 Total Cache |
Version | 2.2.0 |
Comparing to | |
See all releases |
Code changes from version 2.1.9 to 2.2.0
- BrowserCache_Environment_Nginx.php +42 -27
- ConfigCompiler.php +0 -1
- ConfigKeys.php +10 -3
- Extension_ImageService_Api.php +390 -0
- Extension_ImageService_Cron.php +210 -0
- Extension_ImageService_Environment.php +202 -0
- Extension_ImageService_Page_View.php +210 -0
- Extension_ImageService_Plugin.php +95 -0
- Extension_ImageService_Plugin_Admin.css +131 -0
- Extension_ImageService_Plugin_Admin.js +661 -0
- Extension_ImageService_Plugin_Admin.php +1327 -0
- Extensions_Plugin_Admin.php +139 -109
- Extensions_Util.php +82 -41
- FeatureShowcase_Plugin_Admin.php +86 -15
- Generic_Page_Dashboard_View.css +0 -3
- Generic_Plugin_Admin.php +1 -1
- Root_AdminActivation.php +4 -0
- Root_Environment.php +2 -1
- Root_Loader.php +47 -1
- Util_Ui.php +3 -1
- inc/options/extensions/list.php +13 -3
- pub/css/feature-counter.css +10 -0
- pub/js/feature-counter.js +3 -13
- readme.txt +25 -12
- w3-total-cache-api.php +5 -6
- w3-total-cache.php +1 -1
BrowserCache_Environment_Nginx.php
CHANGED
@@ -264,55 +264,70 @@ class BrowserCache_Environment_Nginx {
|
|
264 |
return $rules;
|
265 |
}
|
266 |
|
267 |
-
|
268 |
-
|
269 |
/**
|
270 |
-
* Adds cache rules for type to &$rules
|
271 |
*
|
272 |
-
* @param string
|
273 |
-
* @param array
|
274 |
-
* @param string
|
275 |
* @return void
|
276 |
*/
|
277 |
private function generate_section( &$rules, $mime_types, $section ) {
|
278 |
-
$expires
|
279 |
-
$etag
|
280 |
$cache_control = $this->c->get_boolean( 'browsercache.' . $section . '.cache.control' );
|
281 |
-
$w3tc
|
282 |
$last_modified = $this->c->get_boolean( 'browsercache.' . $section . '.last_modified' );
|
283 |
|
284 |
-
if ( $etag || $expires || $cache_control || $w3tc ||
|
285 |
-
$
|
286 |
-
|
287 |
-
|
288 |
-
$
|
289 |
-
|
|
|
|
|
290 |
|
291 |
-
// Remove ext from filesmatch if its the same as permalink extension
|
292 |
$pext = strtolower( pathinfo( get_option( 'permalink_structure' ), PATHINFO_EXTENSION ) );
|
|
|
293 |
if ( $pext ) {
|
294 |
$extensions = Util_Rule::remove_extension_from_list( $extensions, $pext );
|
295 |
}
|
296 |
|
297 |
-
$rules .=
|
|
|
|
|
|
|
298 |
|
299 |
-
|
300 |
-
|
301 |
-
|
|
|
|
|
|
|
|
|
|
|
302 |
|
303 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
304 |
$wp_uri = network_home_url( '', 'relative' );
|
305 |
$wp_uri = rtrim( $wp_uri, '/' );
|
306 |
-
|
307 |
-
$rules .= ' try_files $uri $uri/ ' . $wp_uri .
|
308 |
-
'/index.php?$args;' . "\n";
|
309 |
}
|
310 |
-
|
|
|
311 |
}
|
312 |
}
|
313 |
|
314 |
-
|
315 |
-
|
316 |
/**
|
317 |
* Returns directives plugin applies to files of specific section
|
318 |
* Without location
|
264 |
return $rules;
|
265 |
}
|
266 |
|
|
|
|
|
267 |
/**
|
268 |
+
* Adds cache rules for type to &$rules.
|
269 |
*
|
270 |
+
* @param string $rules Rules.
|
271 |
+
* @param array $mime_types MIME types.
|
272 |
+
* @param string $section Section.
|
273 |
* @return void
|
274 |
*/
|
275 |
private function generate_section( &$rules, $mime_types, $section ) {
|
276 |
+
$expires = $this->c->get_boolean( 'browsercache.' . $section . '.expires' );
|
277 |
+
$etag = $this->c->get_boolean( 'browsercache.' . $section . '.etag' );
|
278 |
$cache_control = $this->c->get_boolean( 'browsercache.' . $section . '.cache.control' );
|
279 |
+
$w3tc = $this->c->get_boolean( 'browsercache.' . $section . '.w3tc' );
|
280 |
$last_modified = $this->c->get_boolean( 'browsercache.' . $section . '.last_modified' );
|
281 |
|
282 |
+
if ( $etag || $expires || $cache_control || $w3tc || ! $last_modified ) {
|
283 |
+
$mime_types2 = apply_filters(
|
284 |
+
'w3tc_browsercache_rules_section_extensions',
|
285 |
+
$mime_types,
|
286 |
+
$this->c,
|
287 |
+
$section
|
288 |
+
);
|
289 |
+
$extensions = array_keys( $mime_types2 );
|
290 |
|
291 |
+
// Remove ext from filesmatch if its the same as permalink extension.
|
292 |
$pext = strtolower( pathinfo( get_option( 'permalink_structure' ), PATHINFO_EXTENSION ) );
|
293 |
+
|
294 |
if ( $pext ) {
|
295 |
$extensions = Util_Rule::remove_extension_from_list( $extensions, $pext );
|
296 |
}
|
297 |
|
298 |
+
$rules .= 'location ~ \\.(' . implode( '|', $extensions ) . ')$ {' . "\n";
|
299 |
+
|
300 |
+
$subrules = Dispatcher::nginx_rules_for_browsercache_section( $this->c, $section );
|
301 |
+
$rules .= ' ' . implode( "\n ", $subrules ) . "\n";
|
302 |
|
303 |
+
// Add rules for the Image Service extension, if active.
|
304 |
+
if ( 'other' === $section && array_key_exists( 'imageservice', $this->c->get_array( 'extensions.active' ) ) ) {
|
305 |
+
$rules .= "\n" . ' location ~* ^(?<path>.+)\.(jpe?g|png|gif)$ {' . "\n" .
|
306 |
+
' if ( $http_accept !~* "webp|\*/\*" ) {' . "\n" .
|
307 |
+
' break;' . "\n" .
|
308 |
+
' }' . "\n\n" .
|
309 |
+
' ' . implode( "\n ", Dispatcher::nginx_rules_for_browsercache_section( $this->c, $section, true ) ) . "\n" .
|
310 |
+
' add_header Vary Accept;' . "\n";
|
311 |
|
312 |
+
if ( $this->c->get_boolean( 'browsercache.no404wp' ) ) {
|
313 |
+
$rules .= ' try_files ${path}.webp $uri =404;';
|
314 |
+
} else {
|
315 |
+
$rules .= ' try_files ${path}.webp $uri /index.php?$args;';
|
316 |
+
}
|
317 |
+
|
318 |
+
$rules .= "\n" . ' }' . "\n\n";
|
319 |
+
}
|
320 |
+
|
321 |
+
if ( ! $this->c->get_boolean( 'browsercache.no404wp' ) ) {
|
322 |
$wp_uri = network_home_url( '', 'relative' );
|
323 |
$wp_uri = rtrim( $wp_uri, '/' );
|
324 |
+
$rules .= ' try_files $uri $uri/ ' . $wp_uri . '/index.php?$args;' . "\n";
|
|
|
|
|
325 |
}
|
326 |
+
|
327 |
+
$rules .= '}' . "\n";
|
328 |
}
|
329 |
}
|
330 |
|
|
|
|
|
331 |
/**
|
332 |
* Returns directives plugin applies to files of specific section
|
333 |
* Without location
|
ConfigCompiler.php
CHANGED
@@ -348,7 +348,6 @@ class ConfigCompiler {
|
|
348 |
'w3-total-cache/Extension_NewRelic_Plugin.php';
|
349 |
$file_data['extensions.active']['fragmentcache'] =
|
350 |
'w3-total-cache/Extension_FragmentCache_Plugin.php';
|
351 |
-
|
352 |
}
|
353 |
|
354 |
// newrelic settings - migrate to extension
|
348 |
'w3-total-cache/Extension_NewRelic_Plugin.php';
|
349 |
$file_data['extensions.active']['fragmentcache'] =
|
350 |
'w3-total-cache/Extension_FragmentCache_Plugin.php';
|
|
|
351 |
}
|
352 |
|
353 |
// newrelic settings - migrate to extension
|
ConfigKeys.php
CHANGED
@@ -2421,12 +2421,12 @@ $keys = array(
|
|
2421 |
'extensions.active' => array(
|
2422 |
'type' => 'array',
|
2423 |
'default' => array(
|
2424 |
-
'fragmentcache' => 'w3-total-cache/Extension_FragmentCache_Plugin.php'
|
2425 |
-
)
|
2426 |
),
|
2427 |
'extensions.active_frontend' => array(
|
2428 |
'type' => 'array',
|
2429 |
-
'default' => array()
|
2430 |
),
|
2431 |
'extensions.active_dropin' => array(
|
2432 |
'type' => 'array',
|
@@ -2446,6 +2446,13 @@ $keys = array(
|
|
2446 |
'type' => 'boolean',
|
2447 |
'default' => false,
|
2448 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2449 |
|
2450 |
// extensions keys:
|
2451 |
//
|
2421 |
'extensions.active' => array(
|
2422 |
'type' => 'array',
|
2423 |
'default' => array(
|
2424 |
+
'fragmentcache' => 'w3-total-cache/Extension_FragmentCache_Plugin.php',
|
2425 |
+
),
|
2426 |
),
|
2427 |
'extensions.active_frontend' => array(
|
2428 |
'type' => 'array',
|
2429 |
+
'default' => array(),
|
2430 |
),
|
2431 |
'extensions.active_dropin' => array(
|
2432 |
'type' => 'array',
|
2446 |
'type' => 'boolean',
|
2447 |
'default' => false,
|
2448 |
),
|
2449 |
+
'imageservice' => array(
|
2450 |
+
'type' => 'array',
|
2451 |
+
'default' => array(
|
2452 |
+
'compression' => 'lossy',
|
2453 |
+
'auto' => 'enabled',
|
2454 |
+
),
|
2455 |
+
),
|
2456 |
|
2457 |
// extensions keys:
|
2458 |
//
|
Extension_ImageService_Api.php
ADDED
@@ -0,0 +1,390 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* File: Extension_ImageService_Api.php
|
4 |
+
*
|
5 |
+
* @since 2.2.0
|
6 |
+
*
|
7 |
+
* @package W3TC
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace W3TC;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Class: Extension_ImageService_Api
|
14 |
+
*
|
15 |
+
* @since 2.2.0
|
16 |
+
*/
|
17 |
+
class Extension_ImageService_Api {
|
18 |
+
/**
|
19 |
+
* API Base URL.
|
20 |
+
*
|
21 |
+
* @since 2.2.0
|
22 |
+
* @access private
|
23 |
+
*
|
24 |
+
* @var string
|
25 |
+
*/
|
26 |
+
private $base_url = 'https://api2.w3-edge.com';
|
27 |
+
|
28 |
+
/**
|
29 |
+
* W3TC Pro license key.
|
30 |
+
*
|
31 |
+
* @since 2.2.0
|
32 |
+
* @access private
|
33 |
+
*
|
34 |
+
* @var string
|
35 |
+
*/
|
36 |
+
private $license_key = '0';
|
37 |
+
|
38 |
+
/**
|
39 |
+
* W3TC Pro licensed home URL.
|
40 |
+
*
|
41 |
+
* @since 2.2.0
|
42 |
+
* @access private
|
43 |
+
*
|
44 |
+
* @var string
|
45 |
+
*/
|
46 |
+
private $home_url;
|
47 |
+
|
48 |
+
/**
|
49 |
+
* W3TC Pro licensed product item name.
|
50 |
+
*
|
51 |
+
* @since 2.2.0
|
52 |
+
* @access private
|
53 |
+
*
|
54 |
+
* @var string
|
55 |
+
*/
|
56 |
+
private $item_name = '0';
|
57 |
+
|
58 |
+
/**
|
59 |
+
* API endpoints.
|
60 |
+
*
|
61 |
+
* @since 2.2.0
|
62 |
+
* @access private
|
63 |
+
*
|
64 |
+
* @var array
|
65 |
+
*/
|
66 |
+
private $endpoints = array(
|
67 |
+
'convert' => array(
|
68 |
+
'method' => 'POST',
|
69 |
+
'uri' => '/image/convert',
|
70 |
+
),
|
71 |
+
'status' => array(
|
72 |
+
'method' => 'GET',
|
73 |
+
'uri' => '/job/status',
|
74 |
+
),
|
75 |
+
'download' => array(
|
76 |
+
'method' => 'GET',
|
77 |
+
'uri' => '/image/download',
|
78 |
+
),
|
79 |
+
'usage' => array(
|
80 |
+
'method' => 'GET',
|
81 |
+
'uri' => '/image/usage',
|
82 |
+
),
|
83 |
+
);
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Constructor.
|
87 |
+
*
|
88 |
+
* @since 2.2.0
|
89 |
+
*/
|
90 |
+
public function __construct() {
|
91 |
+
$config = Dispatcher::config();
|
92 |
+
|
93 |
+
if ( Util_Environment::is_w3tc_pro( $config ) ) {
|
94 |
+
$this->license_key = $config->get_string( 'plugin.license_key' );
|
95 |
+
$this->home_url = network_home_url();
|
96 |
+
$this->item_name = W3TC_PURCHASE_PRODUCT_NAME;
|
97 |
+
} else {
|
98 |
+
$this->home_url = md5( network_home_url() );
|
99 |
+
}
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Convert an image; submit a job request.
|
104 |
+
*
|
105 |
+
* @since 2.2.0
|
106 |
+
*
|
107 |
+
* @param string $filepath Image file path.
|
108 |
+
* @param array $options Optional array of options. Overrides settings.
|
109 |
+
* @return array
|
110 |
+
*/
|
111 |
+
public function convert( $filepath, array $options = array() ) {
|
112 |
+
$config = Dispatcher::config();
|
113 |
+
$settings = $config->get_array( 'imageservice' );
|
114 |
+
$options = array_merge(
|
115 |
+
array(
|
116 |
+
'optimize' => 'lossy' === $settings['compression'] ? '1' : '0',
|
117 |
+
),
|
118 |
+
$options
|
119 |
+
);
|
120 |
+
$boundary = wp_generate_password( 24 );
|
121 |
+
$body = '';
|
122 |
+
|
123 |
+
$post_fields = array(
|
124 |
+
'license_key' => $this->license_key,
|
125 |
+
'home_url' => $this->home_url,
|
126 |
+
'item_name' => $this->item_name,
|
127 |
+
'optimize' => $options['optimize'],
|
128 |
+
);
|
129 |
+
|
130 |
+
foreach ( $post_fields as $k => $v ) {
|
131 |
+
$body .= '--' . $boundary . "\r\n";
|
132 |
+
$body .= 'Content-Disposition: form-data; name="' . $k . '"' . "\r\n\r\n";
|
133 |
+
$body .= $v . "\r\n";
|
134 |
+
}
|
135 |
+
|
136 |
+
$body .= '--' . $boundary . "\r\n";
|
137 |
+
$body .= 'Content-Disposition: form-data; name="image"; filename="' . basename( $filepath ) . '"' . "\r\n\r\n";
|
138 |
+
$body .= file_get_contents( $filepath ) . "\r\n" . '--' . $boundary . '--'; // phpcs:ignore WordPress.WP.AlternativeFunctions
|
139 |
+
|
140 |
+
$response = wp_remote_request(
|
141 |
+
$this->get_base_url() . $this->endpoints['convert']['uri'],
|
142 |
+
array(
|
143 |
+
'method' => $this->endpoints['convert']['method'],
|
144 |
+
'sslverify' => false,
|
145 |
+
'timeout' => 30,
|
146 |
+
'headers' => array(
|
147 |
+
'Accept' => 'application/json',
|
148 |
+
'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
|
149 |
+
),
|
150 |
+
'body' => $body,
|
151 |
+
)
|
152 |
+
);
|
153 |
+
|
154 |
+
if ( is_wp_error( $response ) ) {
|
155 |
+
return array(
|
156 |
+
'error' => __( 'WP Error: ', 'w3-total-cache' ) . $response->get_error_message(),
|
157 |
+
);
|
158 |
+
}
|
159 |
+
|
160 |
+
// Convert response body to an array.
|
161 |
+
$response_body = json_decode( wp_remote_retrieve_body( $response ), true );
|
162 |
+
|
163 |
+
// Update usage.
|
164 |
+
if ( isset( $response_body['usage_hourly'] ) ) {
|
165 |
+
set_transient(
|
166 |
+
'w3tc_imageservice_usage',
|
167 |
+
array(
|
168 |
+
'updated_at' => time(),
|
169 |
+
'usage_hourly' => $response_body['usage_hourly'],
|
170 |
+
'usage_monthly' => isset( $response_body['usage_monthly'] ) ? $response_body['usage_monthly'] : null,
|
171 |
+
'limit_hourly' => isset( $response_body['limit_hourly'] ) ? $response_body['limit_hourly'] : null,
|
172 |
+
'limit_monthly' => isset( $response_body['limit_monthly'] ) ? $response_body['limit_monthly'] : null,
|
173 |
+
),
|
174 |
+
DAY_IN_SECONDS
|
175 |
+
);
|
176 |
+
}
|
177 |
+
|
178 |
+
// Handle non-200 response codes.
|
179 |
+
if ( 200 !== $response['response']['code'] ) {
|
180 |
+
$result = array(
|
181 |
+
'code' => $response['response']['code'],
|
182 |
+
'error' => esc_html__( 'Error: Received a non-200 response code: ', 'w3-total-cache' ) . $response['response']['code'],
|
183 |
+
);
|
184 |
+
|
185 |
+
if ( isset( $response_body['error']['id'] ) && 'exceeded-hourly' === $response_body['error']['id'] ) {
|
186 |
+
$result['message'] = sprintf(
|
187 |
+
// translators: 1: Hourly request limit.
|
188 |
+
esc_html__( 'You reached your hourly limit of %1$d; try again later%2$s.', 'w3-total-cache' ),
|
189 |
+
esc_attr( $response_body['limit_hourly'] ),
|
190 |
+
isset( $response_body['licensed'] ) && $response_body['licensed'] ? '' :
|
191 |
+
sprintf(
|
192 |
+
// translators: 1: Hourly request limit, 2: HTML anchor open tag, 3: HTML anchor close tag.
|
193 |
+
esc_html__( ' or %1$supgrade to Pro%2$s for higher limits', 'w3-total-cache' ),
|
194 |
+
'<a href="#" class="button-buy-plugin" data-src="imageservice_api_limit">',
|
195 |
+
'</a>'
|
196 |
+
)
|
197 |
+
);
|
198 |
+
} elseif ( isset( $response_body['error']['id'] ) && 'exceeded-monthly' === $response_body['error']['id'] ) {
|
199 |
+
$result['message'] = sprintf(
|
200 |
+
// translators: 1: Monthly request limit, 2: HTML anchor open tag, 3: HTML anchor close tag.
|
201 |
+
esc_html__( 'You reached your monthly limit of %1$d; try again later or %2$supgrade to Pro%3$s for unlimited.', 'w3-total-cache' ),
|
202 |
+
esc_attr( $response_body['limit_monthly'] ),
|
203 |
+
'<a href="#" class="button-buy-plugin" data-src="imageservice_api_limit">',
|
204 |
+
'</a>'
|
205 |
+
);
|
206 |
+
} elseif ( isset( $response_body['error']['id'] ) && 'invalid-output-mime' === $response_body['error']['id'] ) {
|
207 |
+
$result['message'] = esc_html__( 'Invalid output image MIME type.', 'w3-total-cache' );
|
208 |
+
} elseif ( isset( $response_body['error']['id'] ) && 'missing-image' === $response_body['error']['id'] ) {
|
209 |
+
$result['message'] = esc_html__( 'An image file is required.', 'w3-total-cache' );
|
210 |
+
} elseif ( isset( $response_body['error']['id'] ) && 'invalid-image' === $response_body['error']['id'] ) {
|
211 |
+
$result['message'] = esc_html__( 'Valid image data is required.', 'w3-total-cache' );
|
212 |
+
} elseif ( isset( $response_body['error']['id'] ) && 'invalid-input-mime' === $response_body['error']['id'] ) {
|
213 |
+
$result['message'] = esc_html__( 'Invalid input image MIME type.', 'w3-total-cache' );
|
214 |
+
} elseif ( 403 === $response['response']['code'] ) {
|
215 |
+
$result['message'] = sprintf(
|
216 |
+
// translators: 1: HTML anchor open tag, 2: HTML anchor close tag.
|
217 |
+
esc_html__( 'Please verify your license key in %1$sGeneral Settings%2$s.', 'w3-total-cache' ),
|
218 |
+
'<a href="' . esc_url( Util_Ui::admin_url( 'admin.php?page=w3tc_general#licensing' ) ) . '">',
|
219 |
+
'</a>'
|
220 |
+
);
|
221 |
+
} elseif ( isset( $response_body['error']['message'] ) ) {
|
222 |
+
// Unknown error message id; forward the error message.
|
223 |
+
$result['message'] = esc_html( $response_body['error']['message'] );
|
224 |
+
}
|
225 |
+
|
226 |
+
return $result;
|
227 |
+
}
|
228 |
+
|
229 |
+
return $response_body;
|
230 |
+
}
|
231 |
+
|
232 |
+
/**
|
233 |
+
* Get job status.
|
234 |
+
*
|
235 |
+
* @since 2.2.0
|
236 |
+
*
|
237 |
+
* @param int $job_id Job id.
|
238 |
+
* @param string $signature Signature.
|
239 |
+
* @return array
|
240 |
+
*/
|
241 |
+
public function get_status( $job_id, $signature ) {
|
242 |
+
$response = wp_remote_request(
|
243 |
+
$this->get_base_url() . $this->endpoints['status']['uri'] . '/' . $job_id . '/' . $signature,
|
244 |
+
array(
|
245 |
+
'method' => $this->endpoints['status']['method'],
|
246 |
+
'sslverify' => false,
|
247 |
+
'timeout' => 10,
|
248 |
+
'headers' => array(
|
249 |
+
'Accept' => 'application/json',
|
250 |
+
),
|
251 |
+
)
|
252 |
+
);
|
253 |
+
|
254 |
+
if ( is_wp_error( $response ) ) {
|
255 |
+
return array(
|
256 |
+
'error' => __( 'WP Error: ', 'w3-total-cache' ) . $response->get_error_message(),
|
257 |
+
);
|
258 |
+
}
|
259 |
+
|
260 |
+
// Convert response body to an array.
|
261 |
+
$response = json_decode( wp_remote_retrieve_body( $response ), true );
|
262 |
+
|
263 |
+
// Pass error message.
|
264 |
+
if ( isset( $response['error'] ) ) {
|
265 |
+
return array(
|
266 |
+
'error' => $response['error'],
|
267 |
+
);
|
268 |
+
}
|
269 |
+
|
270 |
+
return $response;
|
271 |
+
}
|
272 |
+
|
273 |
+
/**
|
274 |
+
* Download a processed image.
|
275 |
+
*
|
276 |
+
* @since 2.2.0
|
277 |
+
*
|
278 |
+
* @param int $job_id Job id.
|
279 |
+
* @param string $signature Signature.
|
280 |
+
* @return array WP response array.
|
281 |
+
*/
|
282 |
+
public function download( $job_id, $signature ) {
|
283 |
+
$response = wp_remote_request(
|
284 |
+
$this->get_base_url() . $this->endpoints['download']['uri'] . '/' . $job_id . '/' . $signature,
|
285 |
+
array(
|
286 |
+
'method' => $this->endpoints['download']['method'],
|
287 |
+
'sslverify' => false,
|
288 |
+
'timeout' => 10,
|
289 |
+
)
|
290 |
+
);
|
291 |
+
|
292 |
+
if ( is_wp_error( $response ) ) {
|
293 |
+
return array(
|
294 |
+
'error' => __( 'WP Error: ', 'w3-total-cache' ) . $response->get_error_message(),
|
295 |
+
);
|
296 |
+
}
|
297 |
+
|
298 |
+
// Get the response body.
|
299 |
+
$body = wp_remote_retrieve_body( $response );
|
300 |
+
|
301 |
+
// Convert response body to an array. A successful image results in a JSON decode false return.
|
302 |
+
$json = json_decode( $body, true );
|
303 |
+
|
304 |
+
// Pass error message.
|
305 |
+
if ( isset( $json['error'] ) ) {
|
306 |
+
return array(
|
307 |
+
'error' => $json['error'],
|
308 |
+
);
|
309 |
+
}
|
310 |
+
|
311 |
+
return $response;
|
312 |
+
}
|
313 |
+
|
314 |
+
/**
|
315 |
+
* Get usage statistics.
|
316 |
+
*
|
317 |
+
* @since 2.2.0
|
318 |
+
*
|
319 |
+
* @return array
|
320 |
+
*/
|
321 |
+
public function get_usage() {
|
322 |
+
$error_message = __( 'Unknown', 'w3-total-cache' );
|
323 |
+
$error_response = array(
|
324 |
+
'usage_hourly' => $error_message,
|
325 |
+
'usage_monthly' => $error_message,
|
326 |
+
'limit_hourly' => $error_message,
|
327 |
+
'limit_monthly' => $error_message,
|
328 |
+
);
|
329 |
+
|
330 |
+
$response = wp_remote_request(
|
331 |
+
esc_url(
|
332 |
+
$this->get_base_url() . $this->endpoints['usage']['uri'] .
|
333 |
+
'/' . rawurlencode( $this->license_key ) .
|
334 |
+
'/' . urlencode( $this->item_name ) . // phpcs:ignore
|
335 |
+
'/' . rawurlencode( $this->home_url )
|
336 |
+
),
|
337 |
+
array(
|
338 |
+
'method' => $this->endpoints['usage']['method'],
|
339 |
+
'sslverify' => false,
|
340 |
+
'timeout' => 10,
|
341 |
+
'headers' => array(
|
342 |
+
'Accept' => 'application/json',
|
343 |
+
),
|
344 |
+
)
|
345 |
+
);
|
346 |
+
|
347 |
+
if ( is_wp_error( $response ) ) {
|
348 |
+
return $error_response;
|
349 |
+
}
|
350 |
+
|
351 |
+
// Convert response body to an array.
|
352 |
+
$response = json_decode( wp_remote_retrieve_body( $response ), true );
|
353 |
+
|
354 |
+
// If usage is not obtained, then return error response.
|
355 |
+
if ( ! isset( $response['usage_hourly'] ) ) {
|
356 |
+
return $error_response;
|
357 |
+
} else {
|
358 |
+
// Update usage.
|
359 |
+
set_transient(
|
360 |
+
'w3tc_imageservice_usage',
|
361 |
+
array(
|
362 |
+
'updated_at' => time(),
|
363 |
+
'usage_hourly' => $response['usage_hourly'],
|
364 |
+
'usage_monthly' => isset( $response['usage_monthly'] ) ? $response['usage_monthly'] : null,
|
365 |
+
'limit_hourly' => isset( $response['limit_hourly'] ) ? $response['limit_hourly'] : null,
|
366 |
+
'limit_monthly' => isset( $response['limit_monthly'] ) ? $response['limit_monthly'] : null,
|
367 |
+
),
|
368 |
+
DAY_IN_SECONDS
|
369 |
+
);
|
370 |
+
|
371 |
+
// Ensure that the monthly limit is represented correctly.
|
372 |
+
$response['limit_monthly'] = $response['limit_monthly'] ? $response['limit_monthly'] : __( 'Unlimited', 'w3-total-cache' );
|
373 |
+
|
374 |
+
return $response;
|
375 |
+
}
|
376 |
+
}
|
377 |
+
|
378 |
+
/**
|
379 |
+
* Get base URL.
|
380 |
+
*
|
381 |
+
* @since 2.2.0
|
382 |
+
* @access private
|
383 |
+
*
|
384 |
+
* @returns string
|
385 |
+
*/
|
386 |
+
private function get_base_url() {
|
387 |
+
return defined( 'W3TC_API2_URL' ) && W3TC_API2_URL ?
|
388 |
+
esc_url( W3TC_API2_URL, 'https', '' ) : $this->base_url;
|
389 |
+
}
|
390 |
+
}
|
Extension_ImageService_Cron.php
ADDED
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* File: Extension_ImageService_Cron.php
|
4 |
+
*
|
5 |
+
* @since 2.2.0
|
6 |
+
*
|
7 |
+
* @package W3TC
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace W3TC;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Class: Extension_ImageService_Cron
|
14 |
+
*
|
15 |
+
* @since 2.2.0
|
16 |
+
*/
|
17 |
+
class Extension_ImageService_Cron {
|
18 |
+
/**
|
19 |
+
* Add cron job/event.
|
20 |
+
*
|
21 |
+
* @since 2.2.0
|
22 |
+
* @static
|
23 |
+
*/
|
24 |
+
public static function add_cron() {
|
25 |
+
if ( ! wp_next_scheduled( 'w3tc_imageservice_cron' ) ) {
|
26 |
+
wp_schedule_event( time(), 'ten_seconds', 'w3tc_imageservice_cron' );
|
27 |
+
}
|
28 |
+
}
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Add cron schedule.
|
32 |
+
*
|
33 |
+
* @since 2.2.0
|
34 |
+
* @static
|
35 |
+
*
|
36 |
+
* @param array $schedules Schedules.
|
37 |
+
*/
|
38 |
+
public static function add_schedule( array $schedules = array() ) {
|
39 |
+
$schedules['ten_seconds'] = array(
|
40 |
+
'interval' => 10,
|
41 |
+
'display' => esc_html__( 'Every Ten Seconds', 'w3-total-cache' ),
|
42 |
+
);
|
43 |
+
return $schedules;
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Remove cron job/event.
|
48 |
+
*
|
49 |
+
* @since 2.2.0
|
50 |
+
* @static
|
51 |
+
*/
|
52 |
+
public static function delete_cron() {
|
53 |
+
$timestamp = wp_next_scheduled( 'w3tc_imageservice_cron' );
|
54 |
+
|
55 |
+
if ( $timestamp ) {
|
56 |
+
wp_unschedule_event( $timestamp, 'w3tc_imageservice_cron' );
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Run the cron event.
|
62 |
+
*
|
63 |
+
* @since 2.2.0
|
64 |
+
*
|
65 |
+
* @see Extension_ImageService_Plugin_Admin::get_imageservice_attachments()
|
66 |
+
* @see Extension_ImageService_Plugin::get_api()
|
67 |
+
*
|
68 |
+
* @global $wp_filesystem WP_Filesystem.
|
69 |
+
*/
|
70 |
+
public static function run() {
|
71 |
+
// Get all images with postmeta key "w3tc_imageservice".
|
72 |
+
$results = Extension_ImageService_Plugin_Admin::get_imageservice_attachments();
|
73 |
+
|
74 |
+
// If there are matches, then load dependencies before use.
|
75 |
+
if ( $results->have_posts() ) {
|
76 |
+
require_once __DIR__ . '/Extension_ImageService_Plugin_Admin.php';
|
77 |
+
|
78 |
+
$wp_upload_dir = wp_upload_dir();
|
79 |
+
|
80 |
+
global $wp_filesystem;
|
81 |
+
|
82 |
+
// Make sure that this file is included, as wp_generate_attachment_metadata() depends on it.
|
83 |
+
require_once ABSPATH . 'wp-admin/includes/image.php';
|
84 |
+
}
|
85 |
+
|
86 |
+
foreach ( $results->posts as $post ) {
|
87 |
+
$postmeta = get_post_meta( $post->ID, 'w3tc_imageservice', true );
|
88 |
+
$status = isset( $postmeta['status'] ) ? $postmeta['status'] : null;
|
89 |
+
|
90 |
+
// Handle items with the "processing" status.
|
91 |
+
if ( 'processing' === $status && isset( $postmeta['processing']['job_id'] ) && isset( $postmeta['processing']['signature'] ) ) {
|
92 |
+
// Get the Image Service API object (singlton).
|
93 |
+
$api = Extension_ImageService_Plugin::get_api();
|
94 |
+
|
95 |
+
// Check the status of the request.
|
96 |
+
$response = $api->get_status( $postmeta['processing']['job_id'], $postmeta['processing']['signature'] );
|
97 |
+
|
98 |
+
// Save the status response.
|
99 |
+
Extension_ImageService_Plugin_Admin::update_postmeta(
|
100 |
+
$post->ID,
|
101 |
+
array( 'job_status' => $response )
|
102 |
+
);
|
103 |
+
|
104 |
+
// Check if image is ready for pickup/download.
|
105 |
+
if ( isset( $response['status'] ) && 'pickup' === $response['status'] ) {
|
106 |
+
// Download image.
|
107 |
+
$response = $api->download( $postmeta['processing']['job_id'], $postmeta['processing']['signature'] );
|
108 |
+
$headers = wp_remote_retrieve_headers( $response );
|
109 |
+
$is_error = isset( $response['error'] );
|
110 |
+
$is_reduced = ! $is_error && isset( $headers['x-filesize-reduced'] ) &&
|
111 |
+
rtrim( $headers['x-filesize-reduced'], '%' ) > 0;
|
112 |
+
|
113 |
+
switch ( true ) {
|
114 |
+
case $is_error:
|
115 |
+
$status = 'error';
|
116 |
+
break;
|
117 |
+
case $is_reduced:
|
118 |
+
$status = 'converted';
|
119 |
+
break;
|
120 |
+
default:
|
121 |
+
$status = 'notconverted';
|
122 |
+
break;
|
123 |
+
}
|
124 |
+
|
125 |
+
// Save the download headers or error.
|
126 |
+
Extension_ImageService_Plugin_Admin::update_postmeta(
|
127 |
+
$post->ID,
|
128 |
+
array(
|
129 |
+
'download' => $is_error ? $response['error'] : (array) $headers,
|
130 |
+
'status' => $status,
|
131 |
+
)
|
132 |
+
);
|
133 |
+
|
134 |
+
// Skip error responses or if converted image is larger.
|
135 |
+
if ( $is_error || ! $is_reduced ) {
|
136 |
+
continue;
|
137 |
+
}
|
138 |
+
|
139 |
+
// If an converted file already exists, then delete it before saving the new file.
|
140 |
+
if ( isset( $postmeta['post_child'] ) ) {
|
141 |
+
wp_delete_attachment( $postmeta['post_child'], true );
|
142 |
+
}
|
143 |
+
|
144 |
+
// Save the file.
|
145 |
+
$original_filepath = get_attached_file( $post->ID );
|
146 |
+
$original_size = wp_getimagesize( $original_filepath );
|
147 |
+
$original_filename = basename( get_attached_file( $post->ID ) );
|
148 |
+
$original_filedir = str_replace( '/' . $original_filename, '', $original_filepath );
|
149 |
+
$extension = isset( $headers['X-Mime-Type-Out'] ) ?
|
150 |
+
str_replace( 'image/', '', $headers['X-Mime-Type-Out'] ) : 'webp';
|
151 |
+
$new_filename = preg_replace( '/\.[^.]+$/', '', $original_filename ) . '.' . $extension;
|
152 |
+
$new_filepath = $original_filedir . '/' . $new_filename;
|
153 |
+
|
154 |
+
if ( is_a( $wp_filesystem, 'WP_Filesystem_Base' ) ) {
|
155 |
+
$wp_filesystem->put_contents( $new_filepath, wp_remote_retrieve_body( $response ) );
|
156 |
+
} else {
|
157 |
+
Util_File::file_put_contents_atomic( $new_filepath, wp_remote_retrieve_body( $response ) );
|
158 |
+
}
|
159 |
+
|
160 |
+
// Insert as attachment post.
|
161 |
+
$post_id = wp_insert_attachment(
|
162 |
+
array(
|
163 |
+
'guid' => $new_filepath,
|
164 |
+
'post_mime_type' => $headers['x-mime-type-out'],
|
165 |
+
'post_title' => preg_replace( '/\.[^.]+$/', '', $new_filename ),
|
166 |
+
'post_content' => '',
|
167 |
+
'post_status' => 'inherit',
|
168 |
+
'post_parent' => $post->ID,
|
169 |
+
'comment_status' => 'closed',
|
170 |
+
),
|
171 |
+
$new_filepath,
|
172 |
+
$post->ID,
|
173 |
+
false,
|
174 |
+
false
|
175 |
+
);
|
176 |
+
|
177 |
+
// Copy postmeta data to the new attachment.
|
178 |
+
Extension_ImageService_Plugin_Admin::copy_postmeta( $post->ID, $post_id );
|
179 |
+
|
180 |
+
// Save the new post id.
|
181 |
+
Extension_ImageService_Plugin_Admin::update_postmeta(
|
182 |
+
$post->ID,
|
183 |
+
array( 'post_child' => $post_id )
|
184 |
+
);
|
185 |
+
|
186 |
+
// Mark the downloaded file as the converted one.
|
187 |
+
Extension_ImageService_Plugin_Admin::update_postmeta(
|
188 |
+
$post_id,
|
189 |
+
array( 'is_converted_file' => true )
|
190 |
+
);
|
191 |
+
|
192 |
+
// In order to filter/hide converted files in the media list, add a meta key.
|
193 |
+
update_post_meta( $post_id, 'w3tc_imageservice_file', $extension );
|
194 |
+
|
195 |
+
// Generate the metadata for the attachment, and update the database record.
|
196 |
+
$attach_data = wp_generate_attachment_metadata( $post_id, $new_filepath );
|
197 |
+
$attach_data['width'] = isset( $attach_data['width'] ) ? $attach_data['width'] : $original_size[0];
|
198 |
+
$attach_data['height'] = isset( $attach_data['height'] ) ? $attach_data['height'] : $original_size[1];
|
199 |
+
wp_update_attachment_metadata( $post_id, $attach_data );
|
200 |
+
} elseif ( isset( $response['status'] ) && 'complete' === $response['status'] ) {
|
201 |
+
// Update the status to "error".
|
202 |
+
Extension_ImageService_Plugin_Admin::update_postmeta(
|
203 |
+
$post->ID,
|
204 |
+
array( 'status' => 'error' )
|
205 |
+
);
|
206 |
+
}
|
207 |
+
}
|
208 |
+
}
|
209 |
+
}
|
210 |
+
}
|
Extension_ImageService_Environment.php
ADDED
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* File: Extension_ImageService_Environment.php
|
4 |
+
*
|
5 |
+
* @since 2.2.0
|
6 |
+
*
|
7 |
+
* @package W3TC
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace W3TC;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Class: Extension_ImageService_Environment
|
14 |
+
*/
|
15 |
+
class Extension_ImageService_Environment {
|
16 |
+
/**
|
17 |
+
* Fixes environment in each wp-admin request.
|
18 |
+
*
|
19 |
+
* @since 2.2.0
|
20 |
+
*
|
21 |
+
* @param Config $config Configuration.
|
22 |
+
* @param bool $force_all_checks Force all checks.
|
23 |
+
* @throws Util_Environment_Exceptions Exceptions.
|
24 |
+
*/
|
25 |
+
public function fix_on_wpadmin_request( $config, $force_all_checks ) {
|
26 |
+
$exs = new Util_Environment_Exceptions();
|
27 |
+
|
28 |
+
if ( $config->get_boolean( 'config.check' ) || $force_all_checks ) {
|
29 |
+
$extensions_active = $config->get_array( 'extensions.active' );
|
30 |
+
|
31 |
+
if ( array_key_exists( 'imageservice', $extensions_active ) ) {
|
32 |
+
$this->rules_add( $config, $exs );
|
33 |
+
} else {
|
34 |
+
$this->rules_remove( $exs );
|
35 |
+
}
|
36 |
+
}
|
37 |
+
|
38 |
+
if ( count( $exs->exceptions() ) > 0 ) {
|
39 |
+
throw $exs;
|
40 |
+
}
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Fixes environment once event occurs.
|
45 |
+
*
|
46 |
+
* @since 2.2.0
|
47 |
+
*
|
48 |
+
* @param Config $config Config object.
|
49 |
+
* @param mixed $event Event.
|
50 |
+
* @param Config $old_config Old config object.
|
51 |
+
*/
|
52 |
+
public function fix_on_event( $config, $event, $old_config = null ) {
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Fixes environment after plugin deactivation
|
57 |
+
*
|
58 |
+
* @since 2.2.0
|
59 |
+
*
|
60 |
+
* @throws Util_Environment_Exceptions Exceptions.
|
61 |
+
*/
|
62 |
+
public function fix_after_deactivation() {
|
63 |
+
$exs = new Util_Environment_Exceptions();
|
64 |
+
|
65 |
+
$this->rules_remove( $exs );
|
66 |
+
|
67 |
+
if ( count( $exs->exceptions() ) > 0 ) {
|
68 |
+
throw $exs;
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Returns required rules for module.
|
74 |
+
*
|
75 |
+
* @since 2.2.0
|
76 |
+
*
|
77 |
+
* @param Config $config Configuration object.
|
78 |
+
* @return array
|
79 |
+
*/
|
80 |
+
public function get_required_rules( $config ) {
|
81 |
+
return array(
|
82 |
+
array(
|
83 |
+
'filename' => Util_Rule::get_browsercache_rules_cache_path(),
|
84 |
+
'content' => $this->rules_generate(),
|
85 |
+
),
|
86 |
+
);
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Write rewrite rules.
|
91 |
+
*
|
92 |
+
* @since 2.2.0
|
93 |
+
*
|
94 |
+
* @param Config $config Configuration.
|
95 |
+
* @param Util_Environment_Exceptions $exs Exceptions.
|
96 |
+
*
|
97 |
+
* @throws Util_WpFile_FilesystemOperationException S/FTP form if it can't get the required filesystem credentials.
|
98 |
+
*/
|
99 |
+
private function rules_add( $config, $exs ) {
|
100 |
+
Util_Rule::add_rules(
|
101 |
+
$exs,
|
102 |
+
Util_Rule::get_browsercache_rules_cache_path(),
|
103 |
+
$this->rules_generate(),
|
104 |
+
W3TC_MARKER_BEGIN_WEBP,
|
105 |
+
W3TC_MARKER_END_WEBP,
|
106 |
+
array(
|
107 |
+
W3TC_MARKER_BEGIN_BROWSERCACHE_CACHE => 0,
|
108 |
+
W3TC_MARKER_BEGIN_WORDPRESS => 0,
|
109 |
+
)
|
110 |
+
);
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Generate rewrite rules.
|
115 |
+
*
|
116 |
+
* @since 2.2.0
|
117 |
+
*
|
118 |
+
* @see Dispatcher::nginx_rules_for_browsercache_section()
|
119 |
+
*
|
120 |
+
* @return string
|
121 |
+
*/
|
122 |
+
private function rules_generate() {
|
123 |
+
switch ( true ) {
|
124 |
+
case Util_Environment::is_apache():
|
125 |
+
case Util_Environment::is_litespeed():
|
126 |
+
return '
|
127 |
+
# BEGIN W3TC WEBP
|
128 |
+
<IfModule mod_rewrite.c>
|
129 |
+
RewriteEngine On
|
130 |
+
RewriteCond %{HTTP_ACCEPT} image/webp
|
131 |
+
RewriteCond %{REQUEST_FILENAME} (.+)\.(jpe?g|png|gif)$
|
132 |
+
RewriteCond %1\.webp -f
|
133 |
+
RewriteCond %{QUERY_STRING} !type=original
|
134 |
+
RewriteRule (.+)\.(jpe?g|png|gif)$ $1.webp [NC,T=image/webp,E=webp,L]
|
135 |
+
</IfModule>
|
136 |
+
<IfModule mod_headers.c>
|
137 |
+
<FilesMatch "\.(jpe?g|png|gif)$">
|
138 |
+
Header append Vary Accept
|
139 |
+
</FilesMatch>
|
140 |
+
</IfModule>
|
141 |
+
AddType image/webp .webp
|
142 |
+
# END W3TC WEBP
|
143 |
+
|
144 |
+
';
|
145 |
+
|
146 |
+
case Util_Environment::is_nginx():
|
147 |
+
$config = Dispatcher::config();
|
148 |
+
|
149 |
+
/*
|
150 |
+
* Add Nginx rules only if Browser Cache is disabled.
|
151 |
+
* Otherwise, the rules are added in "BrowserCache_Environment_Nginx.php".
|
152 |
+
* @see BrowserCache_Environment_Nginx::generate_section()
|
153 |
+
*/
|
154 |
+
if ( ! $config->get_boolean( 'browsercache.enabled' ) ) {
|
155 |
+
if ( $config->get_boolean( 'browsercache.no404wp' ) ) {
|
156 |
+
$fallback = '=404';
|
157 |
+
} else {
|
158 |
+
$fallback = '/index.php?$args';
|
159 |
+
}
|
160 |
+
|
161 |
+
return '
|
162 |
+
# BEGIN W3TC WEBP
|
163 |
+
location ~* ^(?<path>.+)\.(jpe?g|png|gif)$ {
|
164 |
+
if ( $http_accept !~* "webp|\*/\*" ) {
|
165 |
+
break;
|
166 |
+
}
|
167 |
+
|
168 |
+
' . implode( "\n ", Dispatcher::nginx_rules_for_browsercache_section( $config, 'other' ) ) . '
|
169 |
+
|
170 |
+
add_header Vary Accept;
|
171 |
+
try_files ${path}.webp $uri ' . $fallback . ';
|
172 |
+
}
|
173 |
+
# END W3TC WEBP
|
174 |
+
|
175 |
+
';
|
176 |
+
} else {
|
177 |
+
return '';
|
178 |
+
}
|
179 |
+
|
180 |
+
default:
|
181 |
+
return '';
|
182 |
+
}
|
183 |
+
}
|
184 |
+
|
185 |
+
/**
|
186 |
+
* Removes cache directives
|
187 |
+
*
|
188 |
+
* @since 2.2.0
|
189 |
+
*
|
190 |
+
* @param Util_Environment_Exceptions $exs Exceptions.
|
191 |
+
*
|
192 |
+
* @throws Util_WpFile_FilesystemOperationException S/FTP form if it can't get the required filesystem credentials.
|
193 |
+
*/
|
194 |
+
private function rules_remove( $exs ) {
|
195 |
+
Util_Rule::remove_rules(
|
196 |
+
$exs,
|
197 |
+
Util_Rule::get_pgcache_rules_core_path(),
|
198 |
+
W3TC_MARKER_BEGIN_WEBP,
|
199 |
+
W3TC_MARKER_END_WEBP
|
200 |
+
);
|
201 |
+
}
|
202 |
+
}
|
Extension_ImageService_Page_View.php
ADDED
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* File: Extension_ImageService_Page_View.php
|
4 |
+
*
|
5 |
+
* View for the Image Service extension settings, tools, and statistics page.
|
6 |
+
*
|
7 |
+
* @since 2.2.0
|
8 |
+
*
|
9 |
+
* @package W3TC
|
10 |
+
*
|
11 |
+
* @uses Config $c Configuration object.
|
12 |
+
* @uses array $counts Image Service media counts.
|
13 |
+
* @uses array|false $usage API usage statistics.
|
14 |
+
*/
|
15 |
+
|
16 |
+
namespace W3TC;
|
17 |
+
|
18 |
+
if ( ! defined( 'W3TC' ) ) {
|
19 |
+
die();
|
20 |
+
}
|
21 |
+
|
22 |
+
?>
|
23 |
+
<div class="wrap" id="w3tc">
|
24 |
+
|
25 |
+
<?php
|
26 |
+
// Upgrade banner.
|
27 |
+
if ( ! Util_Environment::is_w3tc_pro( $c ) ) {
|
28 |
+
require W3TC_INC_DIR . '/options/parts/dashboard_banner.php';
|
29 |
+
}
|
30 |
+
?>
|
31 |
+
|
32 |
+
<p>
|
33 |
+
Total Cache Image Service is currently
|
34 |
+
<?php
|
35 |
+
if ( $c->is_extension_active( 'imageservice' ) ) {
|
36 |
+
?>
|
37 |
+
<span class="w3tc-enabled">enabled</span>
|
38 |
+
<?php
|
39 |
+
} else {
|
40 |
+
?>
|
41 |
+
<span class="w3tc-disabled">disabled</span>
|
42 |
+
<?php
|
43 |
+
}
|
44 |
+
?>
|
45 |
+
.
|
46 |
+
</p>
|
47 |
+
|
48 |
+
<form id="w3tc-imageservice-settings" action="upload.php?page=w3tc_extension_page_imageservice" method="post">
|
49 |
+
<div class="metabox-holder">
|
50 |
+
|
51 |
+
<?php Util_Ui::postbox_header( esc_html__( 'Configuration', 'w3-total-cache' ), '', '' ); ?>
|
52 |
+
|
53 |
+
<table class="form-table" id="w3tc-imageservice-config">
|
54 |
+
<?php
|
55 |
+
Util_Ui::config_item(
|
56 |
+
array(
|
57 |
+
'key' => array(
|
58 |
+
'imageservice',
|
59 |
+
'compression',
|
60 |
+
),
|
61 |
+
'label' => esc_html__( 'Compression type:', 'w3-total-cache' ),
|
62 |
+
'control' => 'radiogroup',
|
63 |
+
'radiogroup_values' => array(
|
64 |
+
'lossy' => 'Lossy',
|
65 |
+
'lossless' => 'Lossless',
|
66 |
+
),
|
67 |
+
'description' => esc_html__( 'Image compression type.', 'w3-total-cache' ),
|
68 |
+
)
|
69 |
+
);
|
70 |
+
|
71 |
+
Util_Ui::config_item(
|
72 |
+
array(
|
73 |
+
'key' => array(
|
74 |
+
'imageservice',
|
75 |
+
'auto',
|
76 |
+
),
|
77 |
+
'label' => esc_html__( 'Auto-convert:', 'w3-total-cache' ),
|
78 |
+
'control' => 'radiogroup',
|
79 |
+
'radiogroup_values' => array(
|
80 |
+
'enabled' => 'Enabled',
|
81 |
+
'disabled' => 'Disabled',
|
82 |
+
),
|
83 |
+
'description' => esc_html__( 'Auto-convert images on upload.', 'w3-total-cache' ),
|
84 |
+
)
|
85 |
+
);
|
86 |
+
?>
|
87 |
+
</table>
|
88 |
+
|
89 |
+
<?php
|
90 |
+
Util_Ui::button_config_save( 'extension_imageservice_configuration' );
|
91 |
+
Util_Ui::postbox_footer();
|
92 |
+
|
93 |
+
Util_Ui::postbox_header( esc_html__( 'Tools', 'w3-total-cache' ), '', '' );
|
94 |
+
?>
|
95 |
+
|
96 |
+
<table class="form-table" id="w3tc-imageservice-tools">
|
97 |
+
<?php
|
98 |
+
Util_Ui::config_item(
|
99 |
+
array(
|
100 |
+
'key' => null,
|
101 |
+
'label' => esc_html__( 'Convert all images:', 'w3-total-cache' ),
|
102 |
+
'label_class' => 'w3tc-imageservice-all',
|
103 |
+
'control' => 'button',
|
104 |
+
'none_label' => 'Convert All',
|
105 |
+
'description' => esc_html__( 'Convert all images in the media library.', 'w3-total-cache' ),
|
106 |
+
)
|
107 |
+
);
|
108 |
+
|
109 |
+
Util_Ui::config_item(
|
110 |
+
array(
|
111 |
+
'key' => null,
|
112 |
+
'label' => esc_html__( 'Revert all images:', 'w3-total-cache' ),
|
113 |
+
'label_class' => 'w3tc-imageservice-revertall',
|
114 |
+
'control' => 'button',
|
115 |
+
'none_label' => 'Revert All',
|
116 |
+
'description' => esc_html__( 'Revert all converted images in the media library.', 'w3-total-cache' ),
|
117 |
+
)
|
118 |
+
);
|
119 |
+
?>
|
120 |
+
</table>
|
121 |
+
|
122 |
+
<?php
|
123 |
+
|
124 |
+
Util_Ui::postbox_footer();
|
125 |
+
|
126 |
+
Util_Ui::postbox_header(
|
127 |
+
esc_html__( 'Statistics', 'w3-total-cache' ),
|
128 |
+
'',
|
129 |
+
'w3tc-imageservice-statistics'
|
130 |
+
);
|
131 |
+
|
132 |
+
?>
|
133 |
+
|
134 |
+
<table class="form-table" id="w3tc-imageservice-stats">
|
135 |
+
<tr>
|
136 |
+
<th><?php esc_html_e( 'Counts and filesizes by status:', 'w3-total-cache' ); ?></th>
|
137 |
+
<td>
|
138 |
+
<table id="w3tc-imageservice-counts">
|
139 |
+
<tr>
|
140 |
+
<td><?php esc_html_e( 'Total:', 'w3-total-cache' ); ?></td>
|
141 |
+
<td id="w3tc-imageservice-total"><?php echo esc_html( $counts['total'] ); ?></td>
|
142 |
+
<td id="w3tc-imageservice-totalbytes"><?php echo esc_html( size_format( $counts['totalbytes'], 2 ) ); ?></td>
|
143 |
+
</tr>
|
144 |
+
<tr>
|
145 |
+
<td><?php esc_html_e( 'Converted:', 'w3-total-cache' ); ?></td>
|
146 |
+
<td id="w3tc-imageservice-converted"><?php echo esc_html( $counts['converted'] ); ?></td>
|
147 |
+
<td id="w3tc-imageservice-convertedbytes"><?php echo esc_html( size_format( $counts['convertedbytes'], 2 ) ); ?></td>
|
148 |
+
</tr>
|
149 |
+
<tr>
|
150 |
+
<td><?php esc_html_e( 'Sending:', 'w3-total-cache' ); ?></td>
|
151 |
+
<td id="w3tc-imageservice-sending"><?php echo esc_html( $counts['sending'] ); ?></td>
|
152 |
+
<td id="w3tc-imageservice-sendingbytes"><?php echo esc_html( size_format( $counts['sendingbytes'], 2 ) ); ?></td>
|
153 |
+
</tr>
|
154 |
+
<tr>
|
155 |
+
<td><?php esc_html_e( 'Processing:', 'w3-total-cache' ); ?></td>
|
156 |
+
<td id="w3tc-imageservice-processing"><?php echo esc_html( $counts['processing'] ); ?></td>
|
157 |
+
<td id="w3tc-imageservice-processingbytes"><?php echo esc_html( size_format( $counts['processingbytes'], 2 ) ); ?></td>
|
158 |
+
</tr>
|
159 |
+
<tr>
|
160 |
+
<td><?php esc_html_e( 'Not converted:', 'w3-total-cache' ); ?></td>
|
161 |
+
<td id="w3tc-imageservice-notconverted"><?php echo esc_html( $counts['notconverted'] ); ?></td>
|
162 |
+
<td id="w3tc-imageservice-notconvertedbytes"><?php echo esc_html( size_format( $counts['notconvertedbytes'], 2 ) ); ?></td>
|
163 |
+
</tr>
|
164 |
+
<tr>
|
165 |
+
<td><?php esc_html_e( 'Unconverted:', 'w3-total-cache' ); ?></td>
|
166 |
+
<td id="w3tc-imageservice-unconverted"><?php echo esc_html( $counts['unconverted'] ); ?></td>
|
167 |
+
<td id="w3tc-imageservice-unconvertedbytes"><?php echo esc_html( size_format( $counts['unconvertedbytes'], 2 ) ); ?></td>
|
168 |
+
</tr>
|
169 |
+
<tr><td height="10"></td></tr>
|
170 |
+
<tr>
|
171 |
+
<td colspan="3"><input id="w3tc-imageservice-refresh-counts" class="button" type="button" value="<?php esc_attr_e( 'Refresh', 'w3-total-cache' ); ?>" /></td>
|
172 |
+
</tr>
|
173 |
+
</table>
|
174 |
+
</td>
|
175 |
+
</tr>
|
176 |
+
<tr>
|
177 |
+
<th><?php esc_html_e( 'Image Service API usage:', 'w3-total-cache' ); ?></th>
|
178 |
+
<td>
|
179 |
+
<table id="w3tc-imageservice-usage">
|
180 |
+
<tr>
|
181 |
+
<td><?php esc_html_e( 'Hourly requests:', 'w3-total-cache' ); ?></td>
|
182 |
+
<td id="w3tc-imageservice-usage-hourly"><?php echo esc_html( $usage['usage_hourly'] ); ?></td>
|
183 |
+
</tr>
|
184 |
+
<tr>
|
185 |
+
<td><?php esc_html_e( 'Hourly limit:', 'w3-total-cache' ); ?></td>
|
186 |
+
<td id="w3tc-imageservice-limit-hourly"><?php echo esc_html( $usage['limit_hourly'] ); ?></td>
|
187 |
+
</tr>
|
188 |
+
<tr>
|
189 |
+
<td><?php esc_html_e( 'Monthly requests:', 'w3-total-cache' ); ?></td>
|
190 |
+
<td id="w3tc-imageservice-usage-monthly"><?php echo esc_html( $usage['usage_monthly'] ); ?></td>
|
191 |
+
</tr>
|
192 |
+
<tr>
|
193 |
+
<td><?php esc_html_e( 'Monthly limit:', 'w3-total-cache' ); ?></td>
|
194 |
+
<td id="w3tc-imageservice-limit-monthly"><?php echo esc_html( $usage['limit_monthly'] ); ?></td>
|
195 |
+
</tr>
|
196 |
+
<tr><td height="10"></td></tr>
|
197 |
+
<tr>
|
198 |
+
<td colspan="3"><input id="w3tc-imageservice-refresh-usage" class="button" type="button" value="<?php esc_attr_e( 'Refresh', 'w3-total-cache' ); ?>" /></td>
|
199 |
+
</tr>
|
200 |
+
</table>
|
201 |
+
</td>
|
202 |
+
</tr>
|
203 |
+
</table>
|
204 |
+
|
205 |
+
<?php Util_Ui::postbox_footer(); ?>
|
206 |
+
|
207 |
+
</div>
|
208 |
+
</form>
|
209 |
+
|
210 |
+
</div>
|
Extension_ImageService_Plugin.php
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* File: Extension_ImageService_Plugin.php
|
4 |
+
*
|
5 |
+
* @since 2.2.0
|
6 |
+
*
|
7 |
+
* @package W3TC
|
8 |
+
*
|
9 |
+
* phpcs:disable WordPress.WP.CronInterval
|
10 |
+
*/
|
11 |
+
|
12 |
+
namespace W3TC;
|
13 |
+
|
14 |
+
if ( ! defined( 'W3TC' ) ) {
|
15 |
+
die();
|
16 |
+
}
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Extension_ImageService_Plugin
|
20 |
+
*
|
21 |
+
* @since 2.2.0
|
22 |
+
*/
|
23 |
+
class Extension_ImageService_Plugin {
|
24 |
+
/**
|
25 |
+
* Image Service API object.
|
26 |
+
*
|
27 |
+
* @since 2.2.0
|
28 |
+
*
|
29 |
+
* @static
|
30 |
+
*
|
31 |
+
* @var Extension_ImageService_Api
|
32 |
+
*/
|
33 |
+
public static $api;
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Add hooks.
|
37 |
+
*
|
38 |
+
* @since 2.2.0
|
39 |
+
* @static
|
40 |
+
*/
|
41 |
+
public static function wp_loaded() {
|
42 |
+
add_action(
|
43 |
+
'w3tc_extension_load_admin',
|
44 |
+
array(
|
45 |
+
'\W3TC\Extension_ImageService_Plugin_Admin',
|
46 |
+
'w3tc_extension_load_admin',
|
47 |
+
)
|
48 |
+
);
|
49 |
+
|
50 |
+
// Cron event handling.
|
51 |
+
require_once __DIR__ . '/Extension_ImageService_Cron.php';
|
52 |
+
|
53 |
+
add_action(
|
54 |
+
'w3tc_imageservice_cron',
|
55 |
+
array(
|
56 |
+
'\W3TC\Extension_ImageService_Cron',
|
57 |
+
'run',
|
58 |
+
)
|
59 |
+
);
|
60 |
+
|
61 |
+
add_filter(
|
62 |
+
'cron_schedules',
|
63 |
+
array(
|
64 |
+
'\W3TC\Extension_ImageService_Cron',
|
65 |
+
'add_schedule',
|
66 |
+
)
|
67 |
+
);
|
68 |
+
|
69 |
+
Extension_ImageService_Cron::add_cron();
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Get the Image Service API object.
|
74 |
+
*
|
75 |
+
* @since 2.2.0
|
76 |
+
*
|
77 |
+
* @return Extension_ImageService_Api
|
78 |
+
*/
|
79 |
+
public static function get_api() {
|
80 |
+
if ( is_null( self::$api ) ) {
|
81 |
+
require_once __DIR__ . '/Extension_ImageService_Api.php';
|
82 |
+
self::$api = new Extension_ImageService_Api();
|
83 |
+
}
|
84 |
+
|
85 |
+
return self::$api;
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
+
w3tc_add_action(
|
90 |
+
'wp_loaded',
|
91 |
+
array(
|
92 |
+
'\W3TC\Extension_ImageService_Plugin',
|
93 |
+
'wp_loaded',
|
94 |
+
)
|
95 |
+
);
|
Extension_ImageService_Plugin_Admin.css
ADDED
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
span.w3tc-convert:before {
|
2 |
+
content:'\0041';
|
3 |
+
display: inline-block;
|
4 |
+
font-family: 'w3tc';
|
5 |
+
font-size: x-large;
|
6 |
+
}
|
7 |
+
|
8 |
+
th span.w3tc-convert:before,
|
9 |
+
th #w3tc-imageservice-settings {
|
10 |
+
vertical-align: text-bottom;
|
11 |
+
}
|
12 |
+
|
13 |
+
p span.w3tc-convert:before {
|
14 |
+
vertical-align: middle;
|
15 |
+
}
|
16 |
+
|
17 |
+
.w3tc-converted-reduced {
|
18 |
+
color: green;
|
19 |
+
}
|
20 |
+
|
21 |
+
.w3tc-disabled {
|
22 |
+
cursor: not-allowed;
|
23 |
+
opacity: 0.7;
|
24 |
+
}
|
25 |
+
|
26 |
+
.w3tc-disabled > a {
|
27 |
+
color: currentColor;
|
28 |
+
display: inline-block; /* For IE11 / Ms Edge bug */
|
29 |
+
pointer-events: none;
|
30 |
+
text-decoration: none;
|
31 |
+
}
|
32 |
+
|
33 |
+
/* Statistics section on the extension settings, tools, and statistics page. */
|
34 |
+
|
35 |
+
#w3tc-imageservice-counts td,
|
36 |
+
#w3tc-imageservice-usage td {
|
37 |
+
padding: 1px 10px;
|
38 |
+
}
|
39 |
+
|
40 |
+
#w3tc_default_save_and_flush_extension_imageservice_configuration {
|
41 |
+
display: none;
|
42 |
+
}
|
43 |
+
|
44 |
+
@-webkit-keyframes w3tc-animation-rotating {
|
45 |
+
from {
|
46 |
+
-webkit-transform: rotate(0deg);
|
47 |
+
-o-transform: rotate(0deg);
|
48 |
+
transform: rotate(0deg);
|
49 |
+
}
|
50 |
+
|
51 |
+
to {
|
52 |
+
-webkit-transform: rotate(360deg);
|
53 |
+
-o-transform: rotate(360deg);
|
54 |
+
transform: rotate(360deg);
|
55 |
+
}
|
56 |
+
}
|
57 |
+
|
58 |
+
@keyframes w3tc-animation-rotating {
|
59 |
+
from {
|
60 |
+
-ms-transform: rotate(0deg);
|
61 |
+
-moz-transform: rotate(0deg);
|
62 |
+
-webkit-transform: rotate(0deg);
|
63 |
+
-o-transform: rotate(0deg);
|
64 |
+
transform: rotate(0deg);
|
65 |
+
}
|
66 |
+
|
67 |
+
to {
|
68 |
+
-ms-transform: rotate(360deg);
|
69 |
+
-moz-transform: rotate(360deg);
|
70 |
+
-webkit-transform: rotate(360deg);
|
71 |
+
-o-transform: rotate(360deg);
|
72 |
+
transform: rotate(360deg);
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
.w3tc-rotating {
|
77 |
+
-webkit-animation: w3tc-animation-rotating 2s linear infinite;
|
78 |
+
-moz-animation: w3tc-animation-rotating 2s linear infinite;
|
79 |
+
-ms-animation: w3tc-animation-rotating 2s linear infinite;
|
80 |
+
-o-animation: w3tc-animation-rotating 2s linear infinite;
|
81 |
+
animation: w3tc-animation-rotating 2s linear infinite;
|
82 |
+
}
|
83 |
+
|
84 |
+
@-webkit-keyframes w3tc-highlight {
|
85 |
+
0% {
|
86 |
+
background: #fefefe;
|
87 |
+
}
|
88 |
+
|
89 |
+
50% {
|
90 |
+
background: gray;
|
91 |
+
}
|
92 |
+
|
93 |
+
to {
|
94 |
+
background: #fefefe;
|
95 |
+
}
|
96 |
+
}
|
97 |
+
|
98 |
+
@keyframes w3tc-highlight {
|
99 |
+
0% {
|
100 |
+
background: #fefefe;
|
101 |
+
}
|
102 |
+
|
103 |
+
50% {
|
104 |
+
background: gray;
|
105 |
+
}
|
106 |
+
|
107 |
+
to {
|
108 |
+
background: #fefefe;
|
109 |
+
}
|
110 |
+
}
|
111 |
+
|
112 |
+
.w3tc-highlight {
|
113 |
+
-webkit-animation: w3tc-highlight 1s linear;
|
114 |
+
-o-animation: w3tc-highlight 1s linear;
|
115 |
+
animation: w3tc-highlight 1s linear;
|
116 |
+
-webkit-animation-iteration-count: 1;
|
117 |
+
-o-animation-iteration-count: 1;
|
118 |
+
animation-iteration-count: 1;
|
119 |
+
}
|
120 |
+
|
121 |
+
#w3tc_dashboard_banner {
|
122 |
+
width: 100%;
|
123 |
+
}
|
124 |
+
|
125 |
+
a:hover {
|
126 |
+
cursor: pointer;
|
127 |
+
}
|
128 |
+
|
129 |
+
.media_page_w3tc_extension_page_imageservice #licensing_terms {
|
130 |
+
display:none;
|
131 |
+
}
|
Extension_ImageService_Plugin_Admin.js
ADDED
@@ -0,0 +1,661 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* File: Extension_ImageService_Plugin_Admin.js
|
3 |
+
*
|
4 |
+
* JavaScript for the Media Library list page.
|
5 |
+
*
|
6 |
+
* @since 2.2.0
|
7 |
+
*
|
8 |
+
* @global w3tcData Localized data.
|
9 |
+
*/
|
10 |
+
|
11 |
+
(function( $ ) {
|
12 |
+
var isCheckingItems = false,
|
13 |
+
$convertLinks = $( 'a.w3tc-convert' ),
|
14 |
+
$unconvertLinks = $( '.w3tc-revert > a' ),
|
15 |
+
$convertAllButton = $( 'th.w3tc-imageservice-all' ).parent().find( 'td button' ),
|
16 |
+
$revertAllButton = $( 'th.w3tc-imageservice-revertall' ).parent().find( 'td button' ),
|
17 |
+
$refreshStatsButton = $( 'input#w3tc-imageservice-refresh-counts.button' ),
|
18 |
+
$refreshUsageButton = $( 'input#w3tc-imageservice-refresh-usage.button' );
|
19 |
+
|
20 |
+
/* On page load. */
|
21 |
+
|
22 |
+
// Start checking items that are in the processing status.
|
23 |
+
startCheckItems();
|
24 |
+
|
25 |
+
// Disable ineligible buttons.
|
26 |
+
toggleButtons();
|
27 |
+
|
28 |
+
/* Events. */
|
29 |
+
|
30 |
+
// Clicked convert link.
|
31 |
+
$convertLinks.on( 'click', convertItem );
|
32 |
+
|
33 |
+
// Clicked revert link.
|
34 |
+
$unconvertLinks.on( 'click', revertItem );
|
35 |
+
|
36 |
+
// Clicked convert all images button.
|
37 |
+
$convertAllButton.on( 'click', convertItems );
|
38 |
+
|
39 |
+
// Clicked revert all converted images button.
|
40 |
+
$revertAllButton.on( 'click', revertItems );
|
41 |
+
|
42 |
+
// Clicked the refresh icon for statistics counts.
|
43 |
+
$refreshStatsButton.on( 'click', refreshStats );
|
44 |
+
|
45 |
+
// Clicked the refresh icon for API usage statistics.
|
46 |
+
$refreshUsageButton.on( 'click', refreshUsage );
|
47 |
+
|
48 |
+
/* Functions. */
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Toggle buttons based on eligibility.
|
52 |
+
*
|
53 |
+
* @since 2.2.0
|
54 |
+
*/
|
55 |
+
function toggleButtons() {
|
56 |
+
if ( $convertAllButton.length && $( '#w3tc-imageservice-unconverted' ).text() < 1 ) {
|
57 |
+
$convertAllButton.prop( 'disabled', true ).prop( 'aria-disabled', 'true' ); // Disable button.
|
58 |
+
}
|
59 |
+
|
60 |
+
if ( $revertAllButton.length && $( '#w3tc-imageservice-converted' ).text() < 1 ) {
|
61 |
+
$revertAllButton.prop( 'disabled', true ).prop( 'aria-disabled', 'true' ); // Disable button.
|
62 |
+
}
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Start checking items that are in the processing status.
|
67 |
+
*
|
68 |
+
* @since 2.2.0
|
69 |
+
*
|
70 |
+
* @see checkItemsProcessing()
|
71 |
+
*/
|
72 |
+
function startCheckItems() {
|
73 |
+
if ( isCheckingItems ) {
|
74 |
+
return;
|
75 |
+
}
|
76 |
+
|
77 |
+
isCheckingItems= true;
|
78 |
+
|
79 |
+
// Check status and update every 5 seconds.
|
80 |
+
checkitemsInterval = setInterval( checkItemsProcessing, 5000 );
|
81 |
+
|
82 |
+
// Stop checking after 5 minutes.
|
83 |
+
setTimeout(
|
84 |
+
function() {
|
85 |
+
clearInterval( checkitemsInterval );
|
86 |
+
isCheckingItems = false;
|
87 |
+
},
|
88 |
+
60 * 5 * 1000
|
89 |
+
);
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Check processing items.
|
94 |
+
*
|
95 |
+
* @since 2.2.0
|
96 |
+
*
|
97 |
+
* @see checkItemProcessing()
|
98 |
+
*/
|
99 |
+
function checkItemsProcessing() {
|
100 |
+
$convertLinks.each( checkItemProcessing );
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Callback: Check processing item.
|
105 |
+
*
|
106 |
+
* @since 2.2.0
|
107 |
+
*/
|
108 |
+
function checkItemProcessing() {
|
109 |
+
var $this = $( this ),
|
110 |
+
$itemTd = $this.closest( 'td' );
|
111 |
+
|
112 |
+
// If marked as processing, then check for status change an update status on screen.
|
113 |
+
if ( 'processing' === $this.data( 'status' ) ) {
|
114 |
+
$.ajax({
|
115 |
+
method: 'POST',
|
116 |
+
url: ajaxurl,
|
117 |
+
data: {
|
118 |
+
_wpnonce: w3tcData.nonces.postmeta,
|
119 |
+
action: 'w3tc_imageservice_postmeta',
|
120 |
+
post_id: $this.data( 'post-id' )
|
121 |
+
}
|
122 |
+
})
|
123 |
+
.done( function( response ) {
|
124 |
+
var infoClass;
|
125 |
+
|
126 |
+
// Remove any previous optimization information and the revert link.
|
127 |
+
$itemTd.find(
|
128 |
+
'.w3tc-converted-reduced, .w3tc-converted-increased, .w3tc-notconverted, .w3tc-revert'
|
129 |
+
).remove();
|
130 |
+
|
131 |
+
// Add optimization information.
|
132 |
+
if ( 'notconverted' !== response.data.status && response.data.download && response.data.download["\u0000*\u0000data"] ) {
|
133 |
+
infoClass = response.data.download["\u0000*\u0000data"]['x-filesize-reduced'] > 0 ?
|
134 |
+
'w3tc-converted-increased' : 'w3tc-converted-reduced';
|
135 |
+
|
136 |
+
$itemTd.prepend(
|
137 |
+
'<div class="' +
|
138 |
+
infoClass +
|
139 |
+
'">' +
|
140 |
+
sizeFormat( response.data.download["\u0000*\u0000data"]['x-filesize-in'] ) +
|
141 |
+
' → ' +
|
142 |
+
sizeFormat( response.data.download["\u0000*\u0000data"]['x-filesize-out'] ) +
|
143 |
+
' (' +
|
144 |
+
response.data.download["\u0000*\u0000data"]['x-filesize-reduced'] +
|
145 |
+
')</div>'
|
146 |
+
);
|
147 |
+
}
|
148 |
+
|
149 |
+
if ( 'converted' === response.data.status ) {
|
150 |
+
$this
|
151 |
+
.text( w3tcData.lang.converted )
|
152 |
+
.data( 'status', 'converted' );
|
153 |
+
|
154 |
+
// Add revert link, if not already present.
|
155 |
+
if ( ! $itemTd.find( '.w3tc-revert' ).length ) {
|
156 |
+
$itemTd.append(
|
157 |
+
'<span class="w3tc-revert"> | <a>' +
|
158 |
+
w3tcData.lang.revert +
|
159 |
+
'</a></span>'
|
160 |
+
);
|
161 |
+
|
162 |
+
// Update global revert link.
|
163 |
+
$( '.w3tc-revert > a' ).unbind().on( 'click', revertItem );
|
164 |
+
}
|
165 |
+
} else if ( 'notconverted' === response.data.status ) {
|
166 |
+
$this.data( 'status', 'notconverted' );
|
167 |
+
|
168 |
+
$itemTd.prepend(
|
169 |
+
'<div class="w3tc-notconverted">' +
|
170 |
+
w3tcData.lang.notConvertedDesc +
|
171 |
+
'</div>'
|
172 |
+
);
|
173 |
+
|
174 |
+
if ( 'lossless' === w3tcData.settings.compression ) {
|
175 |
+
$this
|
176 |
+
.text( w3tcData.lang.settings )
|
177 |
+
.prop( 'aria-disabled' , 'false')
|
178 |
+
.closest( 'span' ).removeClass( 'w3tc-disabled' );
|
179 |
+
} else {
|
180 |
+
$this.text( w3tcData.lang.notConverted );
|
181 |
+
}
|
182 |
+
}
|
183 |
+
})
|
184 |
+
.fail( function() {
|
185 |
+
$this
|
186 |
+
.text( w3tcData.lang.error )
|
187 |
+
.data( 'status', null );
|
188 |
+
$itemTd.find( '.w3tc-imageservice-error' ).remove();
|
189 |
+
$itemTd.append(
|
190 |
+
'<div class="notice notice-error inline w3tc-imageservice-error">' +
|
191 |
+
w3tcData.lang.ajaxFail +
|
192 |
+
'</div>'
|
193 |
+
);
|
194 |
+
});
|
195 |
+
}
|
196 |
+
}
|
197 |
+
|
198 |
+
/**
|
199 |
+
* Refresh statistics/counts.
|
200 |
+
*
|
201 |
+
* @since 2.2.0
|
202 |
+
*/
|
203 |
+
function refreshStats() {
|
204 |
+
var $countsTable = $( 'table#w3tc-imageservice-counts' );
|
205 |
+
|
206 |
+
// Update the refresh button text.
|
207 |
+
$refreshStatsButton
|
208 |
+
.val( w3tcData.lang.refreshing )
|
209 |
+
.prop( 'disabled', true )
|
210 |
+
.prop( 'aria-disabled', 'true' );
|
211 |
+
|
212 |
+
// Remove any error notices.
|
213 |
+
$countsTable.find( '.w3tc-imageservice-error' ).remove();
|
214 |
+
|
215 |
+
$.ajax({
|
216 |
+
method: 'POST',
|
217 |
+
url: ajaxurl,
|
218 |
+
data: {
|
219 |
+
_wpnonce: w3tcData.nonces.submit,
|
220 |
+
action: 'w3tc_imageservice_counts'
|
221 |
+
}
|
222 |
+
})
|
223 |
+
.done( function( response ) {
|
224 |
+
if ( response.data && response.data.hasOwnProperty( 'total' ) ) {
|
225 |
+
[ 'total', 'converted', 'sending', 'processing', 'notconverted', 'unconverted' ].forEach( function( className ) {
|
226 |
+
var size,
|
227 |
+
$size,
|
228 |
+
$count = $countsTable.find( '#w3tc-imageservice-' + className );
|
229 |
+
if ( parseInt( $count.text() ) !== response.data[ className ] ) {
|
230 |
+
$count.text( response.data[ className ] ).closest( 'tr' ).addClass( 'w3tc-highlight' );
|
231 |
+
|
232 |
+
className += 'bytes';
|
233 |
+
$size = $countsTable.find( '#w3tc-imageservice-' + className );
|
234 |
+
size = sizeFormat( response.data[ className ], 2 );
|
235 |
+
$size.text( size );
|
236 |
+
}
|
237 |
+
} );
|
238 |
+
}
|
239 |
+
|
240 |
+
// Update the refresh button text.
|
241 |
+
$refreshStatsButton
|
242 |
+
.val( w3tcData.lang.refresh )
|
243 |
+
.prop( 'disabled', false )
|
244 |
+
.prop( 'aria-disabled', 'false' );
|
245 |
+
|
246 |
+
// Remove highlights.
|
247 |
+
setTimeout(
|
248 |
+
function() {
|
249 |
+
$countsTable.find( '.w3tc-highlight' ).removeClass( 'w3tc-highlight' );
|
250 |
+
},
|
251 |
+
1000
|
252 |
+
);
|
253 |
+
})
|
254 |
+
.fail( function() {
|
255 |
+
$countsTable.append(
|
256 |
+
'<div class="notice notice-error inline w3tc-imageservice-error">' +
|
257 |
+
w3tcData.lang.ajaxFail +
|
258 |
+
'</div>'
|
259 |
+
);
|
260 |
+
|
261 |
+
// Update the refresh button text.
|
262 |
+
$refreshStatsButton
|
263 |
+
.val( w3tcData.lang.error )
|
264 |
+
.prop( 'disabled', false )
|
265 |
+
.prop( 'aria-disabled', 'false' );
|
266 |
+
});
|
267 |
+
}
|
268 |
+
|
269 |
+
/**
|
270 |
+
* Refresh API usage statistics.
|
271 |
+
*
|
272 |
+
* @since 2.2.0
|
273 |
+
*/
|
274 |
+
function refreshUsage() {
|
275 |
+
var $usageTable = $( 'table#w3tc-imageservice-usage' );
|
276 |
+
|
277 |
+
// Update the refresh button text.
|
278 |
+
$refreshUsageButton
|
279 |
+
.val( w3tcData.lang.refreshing )
|
280 |
+
.prop( 'disabled', true )
|
281 |
+
.prop( 'aria-disabled', 'true' );
|
282 |
+
|
283 |
+
// Remove any error notices.
|
284 |
+
$usageTable.find( '.w3tc-imageservice-error' ).remove();
|
285 |
+
|
286 |
+
$.ajax({
|
287 |
+
method: 'POST',
|
288 |
+
url: ajaxurl,
|
289 |
+
data: {
|
290 |
+
_wpnonce: w3tcData.nonces.submit,
|
291 |
+
action: 'w3tc_imageservice_usage'
|
292 |
+
}
|
293 |
+
})
|
294 |
+
.done( function( response ) {
|
295 |
+
if ( response.data && response.data.hasOwnProperty( 'usage_hourly' ) ) {
|
296 |
+
[ 'usage_hourly', 'usage_monthly', 'limit_hourly', 'limit_monthly' ].forEach( function( keyName ) {
|
297 |
+
var className = keyName.replace( '_', '-' ),
|
298 |
+
$count = $usageTable.find( '#w3tc-imageservice-' + className );
|
299 |
+
if ( $count.text() != response.data[ keyName ] ) {
|
300 |
+
$count.text( response.data[ keyName ] ).closest( 'tr' ).addClass( 'w3tc-highlight' );
|
301 |
+
}
|
302 |
+
});
|
303 |
+
}
|
304 |
+
|
305 |
+
// Update the refresh button text.
|
306 |
+
$refreshUsageButton
|
307 |
+
.val( w3tcData.lang.refresh )
|
308 |
+
.prop( 'disabled', false )
|
309 |
+
.prop( 'aria-disabled', 'false' );
|
310 |
+
|
311 |
+
// Remove highlights.
|
312 |
+
setTimeout(
|
313 |
+
function() {
|
314 |
+
$usageTable.find( '.w3tc-highlight' ).removeClass( 'w3tc-highlight' );
|
315 |
+
},
|
316 |
+
1000
|
317 |
+
);
|
318 |
+
})
|
319 |
+
.fail( function() {
|
320 |
+
$usageTable.append(
|
321 |
+
'<div class="notice notice-error inline w3tc-imageservice-error">' +
|
322 |
+
w3tcData.lang.ajaxFail +
|
323 |
+
'</div>'
|
324 |
+
);
|
325 |
+
|
326 |
+
// Update the refresh button text.
|
327 |
+
$refreshUsageButton
|
328 |
+
.val( w3tcData.lang.error )
|
329 |
+
.prop( 'disabled', false )
|
330 |
+
.prop( 'aria-disabled', 'false' );
|
331 |
+
});
|
332 |
+
}
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Convert number of bytes largest unit bytes will fit into.
|
336 |
+
*
|
337 |
+
* Similar to size_format(), but in JavaScript.
|
338 |
+
*
|
339 |
+
* @since 2.2.0
|
340 |
+
*
|
341 |
+
* @param int size Size in bytes.
|
342 |
+
* @param int decimals Number of decimal places.
|
343 |
+
* @return string
|
344 |
+
*/
|
345 |
+
function sizeFormat( size, decimals = 0 ) {
|
346 |
+
var units = [ 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' ],
|
347 |
+
i = 0;
|
348 |
+
|
349 |
+
while ( size >= 1024 ) {
|
350 |
+
size /= 1024;
|
351 |
+
++i;
|
352 |
+
}
|
353 |
+
|
354 |
+
return size.toFixed( decimals ) + ' ' + units[ i ];
|
355 |
+
}
|
356 |
+
|
357 |
+
/* Event callback functions */
|
358 |
+
|
359 |
+
/**
|
360 |
+
* Event callback: Convert an item.
|
361 |
+
*
|
362 |
+
* @since 2.2.0
|
363 |
+
*
|
364 |
+
* @param event e Event object.
|
365 |
+
*/
|
366 |
+
function convertItem() {
|
367 |
+
var $this = $( this ),
|
368 |
+
$itemTd = $this.closest( 'td' );
|
369 |
+
|
370 |
+
// If the conversion was canceled and the compression setting is "lossless", then go to the settings page.
|
371 |
+
if ( 'notconverted' === $this.data( 'status' ) && 'lossless' === w3tcData.settings.compression ) {
|
372 |
+
window.location.href = w3tcData.settingsUrl;
|
373 |
+
return;
|
374 |
+
}
|
375 |
+
|
376 |
+
$this
|
377 |
+
.text( w3tcData.lang.sending )
|
378 |
+
.prop( 'aria-disabled' , 'true')
|
379 |
+
.closest( 'span' ).addClass( 'w3tc-disabled' );
|
380 |
+
|
381 |
+
// Remove any previous optimization information, revert link, and error notices.
|
382 |
+
$itemTd.find( '.w3tc-converted-reduced, .w3tc-converted-increased, .w3tc-revert, .w3tc-imageservice-error' ).remove();
|
383 |
+
|
384 |
+
$.ajax({
|
385 |
+
method: 'POST',
|
386 |
+
url: ajaxurl,
|
387 |
+
data: {
|
388 |
+
_wpnonce: w3tcData.nonces.submit,
|
389 |
+
action: 'w3tc_imageservice_submit',
|
390 |
+
post_id: $this.data( 'post-id' )
|
391 |
+
}
|
392 |
+
})
|
393 |
+
.done( function( response ) {
|
394 |
+
if ( response.success ) {
|
395 |
+
$this
|
396 |
+
.text( w3tcData.lang.processing )
|
397 |
+
.data( 'status', 'processing' );
|
398 |
+
|
399 |
+
startCheckItems();
|
400 |
+
} else if ( response.data && response.data.hasOwnProperty( 'error' ) ) {
|
401 |
+
$this
|
402 |
+
.text( w3tcData.lang.error )
|
403 |
+
.data( 'status', 'error' );
|
404 |
+
|
405 |
+
$itemTd.append(
|
406 |
+
'<div class="notice notice-error inline">' +
|
407 |
+
response.data.error +
|
408 |
+
'</div>'
|
409 |
+
);
|
410 |
+
} else {
|
411 |
+
$this
|
412 |
+
.text( w3tcData.lang.error )
|
413 |
+
.data( 'status', 'error' );
|
414 |
+
|
415 |
+
$itemTd.append(
|
416 |
+
'<div class="notice notice-error inline w3tc-imageservice-error">' +
|
417 |
+
w3tcData.lang.apiError +
|
418 |
+
'</div>'
|
419 |
+
);
|
420 |
+
}
|
421 |
+
})
|
422 |
+
.fail( function( response ) {
|
423 |
+
var message,
|
424 |
+
rebindBuyClick = false,
|
425 |
+
$wrap = $( '.wrap' );
|
426 |
+
|
427 |
+
$this
|
428 |
+
.val( w3tcData.lang.error )
|
429 |
+
.data( 'status', 'error' );
|
430 |
+
|
431 |
+
if (
|
432 |
+
response && response.hasOwnProperty( 'responseJSON' ) &&
|
433 |
+
response.responseJSON.hasOwnProperty( 'data' ) &&
|
434 |
+
response.responseJSON.data.hasOwnProperty( 'message' )
|
435 |
+
) {
|
436 |
+
message = response.responseJSON.data.message;
|
437 |
+
rebindBuyClick = true;
|
438 |
+
} else {
|
439 |
+
message = w3tcData.lang.ajaxFail;
|
440 |
+
}
|
441 |
+
|
442 |
+
$itemTd.append(
|
443 |
+
'<div class="notice notice-error inline w3tc-imageservice-error">' +
|
444 |
+
message +
|
445 |
+
'</div>'
|
446 |
+
);
|
447 |
+
|
448 |
+
// Rebind click event handler after adding a new link that may need it.
|
449 |
+
if ( rebindBuyClick ) {
|
450 |
+
// Ensure overlay.
|
451 |
+
if ( 'w3tc' !== $wrap.attr( 'id' ) ) {
|
452 |
+
$wrap.attr( 'id', 'w3tc' );
|
453 |
+
}
|
454 |
+
|
455 |
+
// Rebind click event.
|
456 |
+
$( '.button-buy-plugin' )
|
457 |
+
.off( 'click' )
|
458 |
+
.on( 'click', function() {
|
459 |
+
if ( ! $( '.w3tc-overlay' ).length ) {
|
460 |
+
w3tc_lightbox_upgrade( w3tc_nonce, $( this ).data('src'), null );
|
461 |
+
}
|
462 |
+
} );
|
463 |
+
}
|
464 |
+
});
|
465 |
+
}
|
466 |
+
|
467 |
+
/**
|
468 |
+
* Event callback: Revert item.
|
469 |
+
*
|
470 |
+
* @since 2.2.0
|
471 |
+
*
|
472 |
+
* @param event e Event object.
|
473 |
+
*/
|
474 |
+
function revertItem() {
|
475 |
+
var $this = $( this ),
|
476 |
+
$itemTd = $this.closest( 'td' ),
|
477 |
+
$convertLink = $itemTd.find( 'a.w3tc-convert' );
|
478 |
+
|
479 |
+
$this
|
480 |
+
.text( w3tcData.lang.reverting )
|
481 |
+
.prop( 'aria-disabled', 'true' )
|
482 |
+
.closest( 'span' ).addClass( 'w3tc-disabled' );
|
483 |
+
|
484 |
+
$convertLink
|
485 |
+
.prop( 'aria-disabled', 'true' )
|
486 |
+
.closest( 'span' ).addClass( 'w3tc-disabled' );
|
487 |
+
|
488 |
+
// Remove error notices.
|
489 |
+
$itemTd.find( '.w3tc-imageservice-error' ).remove();
|
490 |
+
|
491 |
+
$.ajax({
|
492 |
+
method: 'POST',
|
493 |
+
url: ajaxurl,
|
494 |
+
data: {
|
495 |
+
_wpnonce: w3tcData.nonces.revert,
|
496 |
+
action: 'w3tc_imageservice_revert',
|
497 |
+
post_id: $convertLink.data( 'post-id' )
|
498 |
+
}
|
499 |
+
})
|
500 |
+
.done( function( response ) {
|
501 |
+
if ( response.success ) {
|
502 |
+
$this.closest( 'span' ).remove(); // Remove the revert link.
|
503 |
+
$itemTd.find( 'div' ).remove(); // Remove optimization info.
|
504 |
+
|
505 |
+
$convertLink
|
506 |
+
.text( w3tcData.lang.convert )
|
507 |
+
.prop( 'aria-disabled', false )
|
508 |
+
.data( 'status', null )
|
509 |
+
.closest( 'span' ).removeClass( 'w3tc-disabled' );
|
510 |
+
} else if ( response.data && response.data.hasOwnProperty( 'error' ) ) {
|
511 |
+
$this
|
512 |
+
.text( w3tcData.lang.error )
|
513 |
+
.data( 'status', 'error' );
|
514 |
+
|
515 |
+
$itemTd.parent().append(
|
516 |
+
'<div class="notice notice-error inline">' +
|
517 |
+
response.data.error +
|
518 |
+
'</div>'
|
519 |
+
);
|
520 |
+
} else {
|
521 |
+
$this
|
522 |
+
.text( w3tcData.lang.error )
|
523 |
+
.data( 'status', 'error' );
|
524 |
+
|
525 |
+
$itemTd.append(
|
526 |
+
'<div class="notice notice-error inline w3tc-imageservice-error">' +
|
527 |
+
w3tcData.lang.apiError +
|
528 |
+
'</div>'
|
529 |
+
);
|
530 |
+
}
|
531 |
+
})
|
532 |
+
.fail( function() {
|
533 |
+
$this
|
534 |
+
.text( w3tcData.lang.error )
|
535 |
+
.data( 'status', 'error' );
|
536 |
+
|
537 |
+
$itemTd.append(
|
538 |
+
'<div class="notice notice-error inline w3tc-imageservice-error">' +
|
539 |
+
w3tcData.lang.ajaxFail +
|
540 |
+
'</div>'
|
541 |
+
);
|
542 |
+
});
|
543 |
+
}
|
544 |
+
|
545 |
+
/**
|
546 |
+
* Event callback: Convert all items.
|
547 |
+
*
|
548 |
+
* @since 2.2.0
|
549 |
+
*
|
550 |
+
* @see refreshStats()
|
551 |
+
* @see refreshUsage()
|
552 |
+
*/
|
553 |
+
function convertItems() {
|
554 |
+
var $this = $( this ),
|
555 |
+
$parent = $this.parent();
|
556 |
+
|
557 |
+
$this
|
558 |
+
.text( w3tcData.lang.sending )
|
559 |
+
.prop( 'disabled', true )
|
560 |
+
.prop( 'aria-disabled', 'true' );
|
561 |
+
|
562 |
+
// Remove error notices.
|
563 |
+
$parent.find( '.w3tc-imageservice-error' ).remove();
|
564 |
+
|
565 |
+
$.ajax({
|
566 |
+
method: 'POST',
|
567 |
+
url: ajaxurl,
|
568 |
+
data: {
|
569 |
+
_wpnonce: w3tcData.nonces.submit,
|
570 |
+
action: 'w3tc_imageservice_all'
|
571 |
+
}
|
572 |
+
})
|
573 |
+
.done( function( response ) {
|
574 |
+
if ( response.success ) {
|
575 |
+
$this.text( w3tcData.lang.processing );
|
576 |
+
refreshStats();
|
577 |
+
refreshUsage();
|
578 |
+
} else if ( response.data && response.data.hasOwnProperty( 'error' ) ) {
|
579 |
+
$this.text( w3tcData.lang.error );
|
580 |
+
$parent.append(
|
581 |
+
'<div class="notice notice-error inline">' +
|
582 |
+
response.data.error +
|
583 |
+
'</div>'
|
584 |
+
);
|
585 |
+
} else {
|
586 |
+
$this.text( w3tcData.lang.error );
|
587 |
+
$parent.append(
|
588 |
+
'<div class="notice notice-error inline w3tc-imageservice-error">' +
|
589 |
+
w3tcData.lang.apiError +
|
590 |
+
'</div>'
|
591 |
+
);
|
592 |
+
}
|
593 |
+
})
|
594 |
+
.fail( function() {
|
595 |
+
$this.text( w3tcData.lang.error );
|
596 |
+
$parent.append(
|
597 |
+
'<div class="notice notice-error inline w3tc-imageservice-error">' +
|
598 |
+
w3tcData.lang.ajaxFail +
|
599 |
+
'</div>'
|
600 |
+
);
|
601 |
+
});
|
602 |
+
}
|
603 |
+
|
604 |
+
/**
|
605 |
+
* Event callback: Revert all items.
|
606 |
+
*
|
607 |
+
* @since 2.2.0
|
608 |
+
*
|
609 |
+
* @see refreshStats()
|
610 |
+
*/
|
611 |
+
function revertItems() {
|
612 |
+
var $this = $( this );
|
613 |
+
|
614 |
+
$this.text( w3tcData.lang.reverting )
|
615 |
+
.prop( 'disabled', true )
|
616 |
+
.prop( 'aria-disabled', 'true' );
|
617 |
+
|
618 |
+
$.ajax({
|
619 |
+
method: 'POST',
|
620 |
+
url: ajaxurl,
|
621 |
+
data: {
|
622 |
+
_wpnonce: w3tcData.nonces.submit,
|
623 |
+
action: 'w3tc_imageservice_revertall'
|
624 |
+
}
|
625 |
+
})
|
626 |
+
.done( function( response ) {
|
627 |
+
if ( response.success ) {
|
628 |
+
$this.text( w3tcData.lang.reverted );
|
629 |
+
$convertAllButton
|
630 |
+
.prop( 'disabled', false )
|
631 |
+
.prop( 'aria-disabled', 'false' );
|
632 |
+
refreshStats();
|
633 |
+
} else if ( response.data && response.data.hasOwnProperty( 'error' ) ) {
|
634 |
+
$this
|
635 |
+
.text( w3tcData.lang.error )
|
636 |
+
.parent().append(
|
637 |
+
'<div class="notice notice-error inline">' +
|
638 |
+
response.data.error +
|
639 |
+
'</div>'
|
640 |
+
);
|
641 |
+
} else {
|
642 |
+
$this
|
643 |
+
.text( w3tcData.lang.error )
|
644 |
+
.parent().append(
|
645 |
+
'<div class="notice notice-error inline w3tc-imageservice-error">' +
|
646 |
+
w3tcData.lang.apiError +
|
647 |
+
'</div>'
|
648 |
+
);
|
649 |
+
}
|
650 |
+
})
|
651 |
+
.fail( function() {
|
652 |
+
$this
|
653 |
+
.text( w3tcData.lang.error )
|
654 |
+
.parent().append(
|
655 |
+
'<div class="notice notice-error inline w3tc-imageservice-error">' +
|
656 |
+
w3tcData.lang.ajaxFail +
|
657 |
+
'</div>'
|
658 |
+
);
|
659 |
+
});
|
660 |
+
}
|
661 |
+
})( jQuery );
|
Extension_ImageService_Plugin_Admin.php
ADDED
@@ -0,0 +1,1327 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* File: Extension_ImageService_Plugin_Admin.php
|
4 |
+
*
|
5 |
+
* @since 2.2.0
|
6 |
+
*
|
7 |
+
* @package W3TC
|
8 |
+
*
|
9 |
+
* phpcs:disable Squiz.PHP.EmbeddedPhp.ContentBeforeOpen, Squiz.PHP.EmbeddedPhp.ContentAfterEnd
|
10 |
+
*/
|
11 |
+
|
12 |
+
namespace W3TC;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Class: Extension_ImageService_Plugin_Admin
|
16 |
+
*
|
17 |
+
* @since 2.2.0
|
18 |
+
*/
|
19 |
+
class Extension_ImageService_Plugin_Admin {
|
20 |
+
/**
|
21 |
+
* Image MIME types available for optimization.
|
22 |
+
*
|
23 |
+
* @since 2.2.0
|
24 |
+
* @static
|
25 |
+
*
|
26 |
+
* @var array
|
27 |
+
*/
|
28 |
+
public static $mime_types = array(
|
29 |
+
'gif' => 'image/gif',
|
30 |
+
'jpeg' => 'image/jpeg',
|
31 |
+
'jpg' => 'image/jpg',
|
32 |
+
'png' => 'image/png',
|
33 |
+
);
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Configuration.
|
37 |
+
*
|
38 |
+
* @since 2.2.0
|
39 |
+
* @access private
|
40 |
+
*
|
41 |
+
* @var Config
|
42 |
+
*/
|
43 |
+
private $config;
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Image Service API class object.
|
47 |
+
*
|
48 |
+
* @since 2.2.0
|
49 |
+
* @access private
|
50 |
+
*
|
51 |
+
* @var Extension_ImageService_API
|
52 |
+
*/
|
53 |
+
private $api;
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Constructor.
|
57 |
+
*
|
58 |
+
* @since 2.2.0
|
59 |
+
*/
|
60 |
+
public function __construct() {
|
61 |
+
$this->config = Dispatcher::config();
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Get extension information.
|
66 |
+
*
|
67 |
+
* @since 2.2.0
|
68 |
+
* @static
|
69 |
+
*
|
70 |
+
* @global $wp_version WordPress core version.
|
71 |
+
*
|
72 |
+
* @param array $extensions Extensions.
|
73 |
+
* @param array $config Configuration.
|
74 |
+
* @return array
|
75 |
+
*/
|
76 |
+
public static function w3tc_extensions( $extensions, $config ) {
|
77 |
+
global $wp_version;
|
78 |
+
|
79 |
+
$description = __(
|
80 |
+
'Adds the ability to convert images in the Media Library to the modern WebP format for better performance.',
|
81 |
+
'w3-total-cache'
|
82 |
+
);
|
83 |
+
|
84 |
+
if ( version_compare( $wp_version, '5.8', '<' ) ) {
|
85 |
+
$description .= sprintf(
|
86 |
+
// translators: 1: HTML break, 2: WordPress version string, 3: HTML archor open tag, 4: HTML archor close tag.
|
87 |
+
__(
|
88 |
+
'%1$sThis extension works best in WordPress version 5.8 and higher. You are running WordPress version %2$s. Please %3$supdate now%4$s to benefit from this feature.',
|
89 |
+
'w3-total-cache'
|
90 |
+
),
|
91 |
+
'<br />',
|
92 |
+
$wp_version,
|
93 |
+
'<a href="' . esc_url( admin_url( 'update-core.php' ) ) . '">',
|
94 |
+
'</a>'
|
95 |
+
);
|
96 |
+
}
|
97 |
+
|
98 |
+
$settings_url = esc_url( Util_Ui::admin_url( 'upload.php?page=w3tc_extension_page_imageservice&w3tc_imageservice_action=dismiss_activation_notice' ) );
|
99 |
+
$library_url = esc_url( Util_Ui::admin_url( 'upload.php?mode=list' ) );
|
100 |
+
|
101 |
+
$extensions['imageservice'] = array(
|
102 |
+
'name' => 'Image Service',
|
103 |
+
'author' => 'BoldGrid',
|
104 |
+
'description' => esc_html( $description ),
|
105 |
+
'author_uri' => 'https://www.boldgrid.com/',
|
106 |
+
'extension_uri' => 'https://www.boldgrid.com/w3-total-cache/',
|
107 |
+
'extension_id' => 'imageservice',
|
108 |
+
'settings_exists' => false,
|
109 |
+
'version' => '1.0',
|
110 |
+
'enabled' => true,
|
111 |
+
'disabled_message' => '',
|
112 |
+
'requirements' => '',
|
113 |
+
'path' => 'w3-total-cache/Extension_ImageService_Plugin.php',
|
114 |
+
'extra_links' => array(
|
115 |
+
'<a class="edit" href="' . $settings_url . '">' . esc_html__( 'Settings', 'w3-total-cache' ) . '</a>',
|
116 |
+
'<a class="edit" href="' . $library_url . '">' . esc_html__( 'Media Library', 'w3-total-cache' ) . '</a>',
|
117 |
+
),
|
118 |
+
'notice' => sprintf(
|
119 |
+
// translators: 1: HTML anchor open tag, 2: HTML anchor close tag, 3: HTML anchor open tag, 4: HTML anchor open tag.
|
120 |
+
__(
|
121 |
+
'Total Cache Image Service has been activated. Now, you can %1$sadjust the settings%2$s or go to the %3$sMedia Library%2$s to convert images to WebP. %4$sLearn more%2$s.',
|
122 |
+
'w3-total-cache'
|
123 |
+
),
|
124 |
+
'<a class="edit" href="' . $settings_url . '">',
|
125 |
+
'</a>',
|
126 |
+
'<a class="edit" href="' . $library_url . '">',
|
127 |
+
'<a target="_blank" href="' . esc_url(
|
128 |
+
'https://www.boldgrid.com/support/w3-total-cache/image-service/?utm_source=w3tc&utm_medium=activation_notice&utm_campaign=imageservice'
|
129 |
+
) . '">'
|
130 |
+
),
|
131 |
+
);
|
132 |
+
|
133 |
+
return $extensions;
|
134 |
+
}
|
135 |
+
|
136 |
+
/**
|
137 |
+
* Load the admin extension.
|
138 |
+
*
|
139 |
+
* Runs on the "wp_loaded" action.
|
140 |
+
*
|
141 |
+
* @since 2.2.0
|
142 |
+
* @static
|
143 |
+
*/
|
144 |
+
public static function w3tc_extension_load_admin() {
|
145 |
+
$o = new Extension_ImageService_Plugin_Admin();
|
146 |
+
|
147 |
+
// Enqueue scripts.
|
148 |
+
add_action( 'admin_enqueue_scripts', array( $o, 'admin_enqueue_scripts' ) );
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Filters the Media list table columns.
|
152 |
+
*
|
153 |
+
* @since 2.5.0
|
154 |
+
*
|
155 |
+
* @param string[] $posts_columns An array of columns displayed in the Media list table.
|
156 |
+
* @param bool $detached Whether the list table contains media not attached
|
157 |
+
* to any posts. Default true.
|
158 |
+
*/
|
159 |
+
add_filter( 'manage_media_columns', array( $o, 'add_media_column' ) );
|
160 |
+
|
161 |
+
/**
|
162 |
+
* Fires for each custom column in the Media list table.
|
163 |
+
*
|
164 |
+
* Custom columns are registered using the {@see 'manage_media_columns'} filter.
|
165 |
+
*
|
166 |
+
* @since 2.5.0
|
167 |
+
*
|
168 |
+
* @param string $column_name Name of the custom column.
|
169 |
+
* @param int $post_id Attachment ID.
|
170 |
+
*/
|
171 |
+
add_action( 'manage_media_custom_column', array( $o, 'media_column_row' ), 10, 2 );
|
172 |
+
|
173 |
+
// AJAX hooks.
|
174 |
+
add_action( 'wp_ajax_w3tc_imageservice_submit', array( $o, 'ajax_submit' ) );
|
175 |
+
add_action( 'wp_ajax_w3tc_imageservice_postmeta', array( $o, 'ajax_get_postmeta' ) );
|
176 |
+
add_action( 'wp_ajax_w3tc_imageservice_revert', array( $o, 'ajax_revert' ) );
|
177 |
+
add_action( 'wp_ajax_w3tc_imageservice_all', array( $o, 'ajax_convert_all' ) );
|
178 |
+
add_action( 'wp_ajax_w3tc_imageservice_revertall', array( $o, 'ajax_revert_all' ) );
|
179 |
+
add_action( 'wp_ajax_w3tc_imageservice_counts', array( $o, 'ajax_get_counts' ) );
|
180 |
+
add_action( 'wp_ajax_w3tc_imageservice_usage', array( $o, 'ajax_get_usage' ) );
|
181 |
+
|
182 |
+
// Admin notices.
|
183 |
+
add_action( 'admin_notices', array( $o, 'display_notices' ) );
|
184 |
+
|
185 |
+
/**
|
186 |
+
* Ensure all network sites include WebP support.
|
187 |
+
*
|
188 |
+
* @link https://make.wordpress.org/core/2021/06/07/wordpress-5-8-adds-webp-support/
|
189 |
+
*/
|
190 |
+
add_filter(
|
191 |
+
'site_option_upload_filetypes',
|
192 |
+
function ( $filetypes ) {
|
193 |
+
$filetypes = explode( ' ', $filetypes );
|
194 |
+
if ( ! in_array( 'webp', $filetypes, true ) ) {
|
195 |
+
$filetypes[] = 'webp';
|
196 |
+
}
|
197 |
+
|
198 |
+
return implode( ' ', $filetypes );
|
199 |
+
}
|
200 |
+
);
|
201 |
+
|
202 |
+
// Add bulk actions.
|
203 |
+
add_filter( 'bulk_actions-upload', array( $o, 'add_bulk_actions' ) );
|
204 |
+
|
205 |
+
/**
|
206 |
+
* Fires when a custom bulk action should be handled.
|
207 |
+
*
|
208 |
+
* The redirect link should be modified with success or failure feedback
|
209 |
+
* from the action to be used to display feedback to the user.
|
210 |
+
*
|
211 |
+
* The dynamic portion of the hook name, `$screen`, refers to the current screen ID.
|
212 |
+
*
|
213 |
+
* @since 4.7.0
|
214 |
+
*
|
215 |
+
* @link https://core.trac.wordpress.org/browser/tags/5.8/src/wp-admin/upload.php#L206
|
216 |
+
*
|
217 |
+
* @param string $sendback The redirect URL.
|
218 |
+
* @param string $doaction The action being taken.
|
219 |
+
* @param array $items The items to take the action on. Accepts an array of IDs of posts,
|
220 |
+
* comments, terms, links, plugins, attachments, or users.
|
221 |
+
*/
|
222 |
+
add_filter( 'handle_bulk_actions-upload', array( $o, 'handle_bulk_actions' ), 10, 3 );
|
223 |
+
|
224 |
+
/**
|
225 |
+
* Handle auto-optimization on upload.
|
226 |
+
*
|
227 |
+
* @link https://core.trac.wordpress.org/browser/tags/5.8/src/wp-includes/post.php#L4401
|
228 |
+
* @link https://developer.wordpress.org/reference/hooks/add_attachment/
|
229 |
+
*
|
230 |
+
* Fires once an attachment has been added.
|
231 |
+
*
|
232 |
+
* @since 2.0.0
|
233 |
+
*
|
234 |
+
* @param int $post_ID Attachment ID.
|
235 |
+
*/
|
236 |
+
add_action( 'add_attachment', array( $o, 'auto_convert' ) );
|
237 |
+
|
238 |
+
/**
|
239 |
+
* Delete optimizations on parent image delation.
|
240 |
+
*
|
241 |
+
* @link https://core.trac.wordpress.org/browser/tags/5.8/src/wp-includes/post.php#L6134
|
242 |
+
* @link https://developer.wordpress.org/reference/hooks/pre_delete_attachment/
|
243 |
+
*
|
244 |
+
* Filters whether an attachment deletion should take place.
|
245 |
+
*
|
246 |
+
* @since 5.5.0
|
247 |
+
*
|
248 |
+
* @param bool|null $delete Whether to go forward with deletion.
|
249 |
+
* @param WP_Post $post Post object.
|
250 |
+
* @param bool $force_delete Whether to bypass the Trash.
|
251 |
+
*/
|
252 |
+
add_filter( 'pre_delete_attachment', array( $o, 'cleanup_optimizations' ), 10, 3 );
|
253 |
+
|
254 |
+
// Add admin menu items.
|
255 |
+
add_action( 'admin_menu', array( $o, 'admin_menu' ) );
|
256 |
+
}
|
257 |
+
|
258 |
+
/**
|
259 |
+
* Get all images with postmeta key "w3tc_imageservice".
|
260 |
+
*
|
261 |
+
* @since 2.2.0
|
262 |
+
* @static
|
263 |
+
*
|
264 |
+
* @link https://developer.wordpress.org/reference/classes/wp_query/
|
265 |
+
*
|
266 |
+
* @return WP_Query
|
267 |
+
*/
|
268 |
+
public static function get_imageservice_attachments() {
|
269 |
+
return new \WP_Query(
|
270 |
+
array(
|
271 |
+
'post_type' => 'attachment',
|
272 |
+
'post_status' => 'inherit',
|
273 |
+
'post_mime_type' => self::$mime_types,
|
274 |
+
'posts_per_page' => -1,
|
275 |
+
'ignore_sticky_posts' => true,
|
276 |
+
'suppress_filters' => true,
|
277 |
+
'meta_key' => 'w3tc_imageservice', // phpcs:ignore WordPress.DB.SlowDBQuery
|
278 |
+
)
|
279 |
+
);
|
280 |
+
}
|
281 |
+
|
282 |
+
/**
|
283 |
+
* Get all images without postmeta key "w3tc_imageservice".
|
284 |
+
*
|
285 |
+
* @since 2.2.0
|
286 |
+
* @static
|
287 |
+
*
|
288 |
+
* @link https://developer.wordpress.org/reference/classes/wp_query/
|
289 |
+
*
|
290 |
+
* @return WP_Query
|
291 |
+
*/
|
292 |
+
public static function get_eligible_attachments() {
|
293 |
+
return new \WP_Query(
|
294 |
+
array(
|
295 |
+
'post_type' => 'attachment',
|
296 |
+
'post_status' => 'inherit',
|
297 |
+
'post_mime_type' => self::$mime_types,
|
298 |
+
'posts_per_page' => -1,
|
299 |
+
'ignore_sticky_posts' => true,
|
300 |
+
'suppress_filters' => true,
|
301 |
+
'meta_key' => 'w3tc_imageservice', // phpcs:ignore WordPress.DB.SlowDBQuery
|
302 |
+
'meta_compare' => 'NOT EXISTS',
|
303 |
+
)
|
304 |
+
);
|
305 |
+
}
|
306 |
+
|
307 |
+
/**
|
308 |
+
* Get an attachment filesize.
|
309 |
+
*
|
310 |
+
* @since 2.2.0
|
311 |
+
*
|
312 |
+
* @global $wp_filesystem
|
313 |
+
*
|
314 |
+
* @param int $post_id Post id.
|
315 |
+
* @return int
|
316 |
+
*/
|
317 |
+
public function get_attachment_filesize( $post_id ) {
|
318 |
+
WP_Filesystem();
|
319 |
+
global $wp_filesystem;
|
320 |
+
|
321 |
+
$size = 0;
|
322 |
+
$filepath = get_attached_file( $post_id );
|
323 |
+
|
324 |
+
if ( $wp_filesystem->exists( $filepath ) ) {
|
325 |
+
$size = $wp_filesystem->size( $filepath );
|
326 |
+
}
|
327 |
+
|
328 |
+
return $size;
|
329 |
+
}
|
330 |
+
|
331 |
+
/**
|
332 |
+
* Get image counts by status.
|
333 |
+
*
|
334 |
+
* @since 2.2.0
|
335 |
+
*
|
336 |
+
* @see self::get_imageservice_attachments()
|
337 |
+
* @see self::get_eligible_attachments()
|
338 |
+
*
|
339 |
+
* @return array
|
340 |
+
*/
|
341 |
+
public function get_counts() {
|
342 |
+
$unconverted_posts = self::get_eligible_attachments();
|
343 |
+
$counts = array(
|
344 |
+
'sending' => 0,
|
345 |
+
'processing' => 0,
|
346 |
+
'converted' => 0,
|
347 |
+
'notconverted' => 0,
|
348 |
+
'unconverted' => $unconverted_posts->post_count,
|
349 |
+
'total' => 0,
|
350 |
+
);
|
351 |
+
$bytes = array(
|
352 |
+
'sending' => 0,
|
353 |
+
'processing' => 0,
|
354 |
+
'converted' => 0,
|
355 |
+
'notconverted' => 0,
|
356 |
+
'unconverted' => 0,
|
357 |
+
'total' => 0,
|
358 |
+
);
|
359 |
+
$imageservice_posts = self::get_imageservice_attachments()->posts;
|
360 |
+
|
361 |
+
foreach ( $imageservice_posts as $post ) {
|
362 |
+
$imageservice_data = get_post_meta( $post->ID, 'w3tc_imageservice', true );
|
363 |
+
$status = isset( $imageservice_data['status'] ) ? $imageservice_data['status'] : null;
|
364 |
+
$filesize_in = isset( $imageservice_data['download']["\0*\0data"]['x-filesize-in'] ) ?
|
365 |
+
$imageservice_data['download']["\0*\0data"]['x-filesize-in'] : 0;
|
366 |
+
$filesize_out = isset( $imageservice_data['download']["\0*\0data"]['x-filesize-out'] ) ?
|
367 |
+
$imageservice_data['download']["\0*\0data"]['x-filesize-out'] : 0;
|
368 |
+
|
369 |
+
switch ( $status ) {
|
370 |
+
case 'sending':
|
371 |
+
$size = $this->get_attachment_filesize( $post->ID );
|
372 |
+
$counts['sending']++;
|
373 |
+
$bytes['sending'] += $size;
|
374 |
+
$bytes['total'] += $size;
|
375 |
+
break;
|
376 |
+
case 'processing':
|
377 |
+
$size = $this->get_attachment_filesize( $post->ID );
|
378 |
+
$counts['processing']++;
|
379 |
+
$bytes['processing'] += $size;
|
380 |
+
$bytes['total'] += $size;
|
381 |
+
break;
|
382 |
+
case 'converted':
|
383 |
+
$counts['converted']++;
|
384 |
+
$bytes['converted'] += $filesize_in - $filesize_out;
|
385 |
+
$bytes['total'] += $filesize_in - $filesize_out;
|
386 |
+
break;
|
387 |
+
case 'notconverted':
|
388 |
+
$size = $this->get_attachment_filesize( $post->ID );
|
389 |
+
$counts['notconverted']++;
|
390 |
+
$bytes['notconverted'] += $size;
|
391 |
+
$bytes['total'] += $size;
|
392 |
+
break;
|
393 |
+
case 'unconverted':
|
394 |
+
$size = $this->get_attachment_filesize( $post->ID );
|
395 |
+
$counts['unconverted']++;
|
396 |
+
$bytes['unconverted'] += $size;
|
397 |
+
$bytes['total'] += $size;
|
398 |
+
break;
|
399 |
+
default:
|
400 |
+
break;
|
401 |
+
}
|
402 |
+
}
|
403 |
+
|
404 |
+
foreach ( $unconverted_posts->posts as $post ) {
|
405 |
+
$size = $this->get_attachment_filesize( $post->ID );
|
406 |
+
|
407 |
+
if ( $size ) {
|
408 |
+
$bytes['unconverted'] += $size;
|
409 |
+
$bytes['total'] += $size;
|
410 |
+
}
|
411 |
+
}
|
412 |
+
|
413 |
+
$counts['total'] = array_sum( $counts );
|
414 |
+
$counts['totalbytes'] = $bytes['total'];
|
415 |
+
$counts['sendingbytes'] = $bytes['sending'];
|
416 |
+
$counts['processingbytes'] = $bytes['processing'];
|
417 |
+
$counts['convertedbytes'] = $bytes['converted'];
|
418 |
+
$counts['notconvertedbytes'] = $bytes['notconverted'];
|
419 |
+
$counts['unconvertedbytes'] = $bytes['unconverted'];
|
420 |
+
|
421 |
+
return $counts;
|
422 |
+
}
|
423 |
+
|
424 |
+
/**
|
425 |
+
* Load the extension settings page view.
|
426 |
+
*
|
427 |
+
* @since 2.2.0
|
428 |
+
*
|
429 |
+
* @see Extension_ImageService_Plugin::get_api()
|
430 |
+
* @see Extension_ImageService_Api::get_usage()
|
431 |
+
*/
|
432 |
+
public function settings_page() {
|
433 |
+
$c = $this->config;
|
434 |
+
$counts = $this->get_counts();
|
435 |
+
$usage = get_transient( 'w3tc_imageservice_usage' );
|
436 |
+
|
437 |
+
// Delete transient for displaying activation notice.
|
438 |
+
delete_transient( 'w3tc_activation_imageservice' );
|
439 |
+
|
440 |
+
// Save submitted settings.
|
441 |
+
if ( isset( $_POST['_wpnonce'], $_POST['imageservice___compression'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'w3tc' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
|
442 |
+
$settings = $c->get_array( 'imageservice' );
|
443 |
+
|
444 |
+
if ( isset( $_POST['imageservice___compression'] ) ) {
|
445 |
+
$settings['compression'] = sanitize_key( $_POST['imageservice___compression'] );
|
446 |
+
}
|
447 |
+
|
448 |
+
if ( isset( $_POST['imageservice___auto'] ) ) {
|
449 |
+
$settings['auto'] = sanitize_key( $_POST['imageservice___auto'] );
|
450 |
+
}
|
451 |
+
|
452 |
+
$c->set( 'imageservice', $settings );
|
453 |
+
$c->save();
|
454 |
+
|
455 |
+
// Display notice when saving settings.
|
456 |
+
?>
|
457 |
+
<div class="notice notice-success is-dismissible">
|
458 |
+
<p><?php esc_html_e( 'Settings saved.', 'w3-total-cache' ); ?></p>
|
459 |
+
</div>
|
460 |
+
<?php
|
461 |
+
}
|
462 |
+
|
463 |
+
// If usage is not stored, then retrieve it from the API.
|
464 |
+
if ( empty( $usage ) ) {
|
465 |
+
$usage = Extension_ImageService_Plugin::get_api()->get_usage();
|
466 |
+
}
|
467 |
+
|
468 |
+
// Ensure that the monthly limit is represented correctly.
|
469 |
+
$usage['limit_monthly'] = $usage['limit_monthly'] ? $usage['limit_monthly'] : __( 'Unlimited', 'w3-total-cache' );
|
470 |
+
|
471 |
+
require W3TC_DIR . '/Extension_ImageService_Page_View.php';
|
472 |
+
}
|
473 |
+
|
474 |
+
/**
|
475 |
+
* Add admin menu items.
|
476 |
+
*
|
477 |
+
* @since 2.2.0
|
478 |
+
*/
|
479 |
+
public function admin_menu() {
|
480 |
+
// Add settings submenu to Media top-level menu.
|
481 |
+
add_submenu_page(
|
482 |
+
'upload.php',
|
483 |
+
esc_html__( 'Total Cache Image Service', 'w3-total-cache' ),
|
484 |
+
esc_html__( 'Total Cache Image Service', 'w3-total-cache' ),
|
485 |
+
'edit_posts',
|
486 |
+
'w3tc_extension_page_imageservice',
|
487 |
+
array( $this, 'settings_page' )
|
488 |
+
);
|
489 |
+
}
|
490 |
+
|
491 |
+
/**
|
492 |
+
* Enqueue scripts and styles for admin pages.
|
493 |
+
*
|
494 |
+
* Runs on the "admin_enqueue_scripts" action.
|
495 |
+
*
|
496 |
+
* @since 2.2.0
|
497 |
+
*/
|
498 |
+
public function admin_enqueue_scripts() {
|
499 |
+
// Enqueue JavaScript for the Media Library (upload) and extension settings admin pages.
|
500 |
+
$is_settings_page = isset( $_GET['page'] ) && 'w3tc_extension_page_imageservice' === $_GET['page']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
501 |
+
$is_media_page = 'upload' === get_current_screen()->id;
|
502 |
+
|
503 |
+
if ( $is_settings_page ) {
|
504 |
+
wp_enqueue_style( 'w3tc-options' );
|
505 |
+
}
|
506 |
+
|
507 |
+
if ( $is_settings_page || $is_media_page ) {
|
508 |
+
wp_localize_script( 'w3tc-lightbox', 'w3tc_nonce', array( wp_create_nonce( 'w3tc' ) ) );
|
509 |
+
wp_enqueue_script( 'w3tc-lightbox' );
|
510 |
+
wp_enqueue_style( 'w3tc-lightbox' );
|
511 |
+
|
512 |
+
wp_register_script(
|
513 |
+
'w3tc-imageservice',
|
514 |
+
esc_url( plugin_dir_url( __FILE__ ) . 'Extension_ImageService_Plugin_Admin.js' ),
|
515 |
+
array( 'jquery' ),
|
516 |
+
W3TC_VERSION,
|
517 |
+
true
|
518 |
+
);
|
519 |
+
|
520 |
+
wp_localize_script(
|
521 |
+
'w3tc-imageservice',
|
522 |
+
'w3tcData',
|
523 |
+
array(
|
524 |
+
'nonces' => array(
|
525 |
+
'submit' => wp_create_nonce( 'w3tc_imageservice_submit' ),
|
526 |
+
'postmeta' => wp_create_nonce( 'w3tc_imageservice_postmeta' ),
|
527 |
+
'revert' => wp_create_nonce( 'w3tc_imageservice_revert' ),
|
528 |
+
),
|
529 |
+
'lang' => array(
|
530 |
+
'convert' => __( 'Convert', 'w3-total_cache' ),
|
531 |
+
'sending' => __( 'Sending...', 'w3-total_cache' ),
|
532 |
+
'processing' => __( 'Processing...', 'w3-total_cache' ),
|
533 |
+
'converted' => __( 'Converted', 'w3-total_cache' ),
|
534 |
+
'notConverted' => __( 'Not converted', 'w3-total_cache' ),
|
535 |
+
'reverting' => __( 'Reverting...', 'w3-total_cache' ),
|
536 |
+
'reverted' => __( 'Reverted', 'w3-total_cache' ),
|
537 |
+
'revert' => __( 'Revert', 'w3-total_cache' ),
|
538 |
+
'error' => __( 'Error', 'w3-total_cache' ),
|
539 |
+
'ajaxFail' => __( 'Failed to retrieve a response. Please reload the page to try again.', 'w3-total_cache' ),
|
540 |
+
'apiError' => __( 'API error. Please reload the page to try again,', 'w3-total_cache' ),
|
541 |
+
'refresh' => __( 'Refresh', 'w3-total_cache' ),
|
542 |
+
'refreshing' => __( 'Refreshing...', 'w3-total_cache' ),
|
543 |
+
'settings' => __( 'Settings', 'w3-total_cache' ),
|
544 |
+
'notConvertedDesc' => sprintf(
|
545 |
+
// translators: 1: HTML anchor open tag, 2: HTML anchor close tag.
|
546 |
+
__( 'The converted image would be larger than the original; conversion canceled. %1$sLearn more%2$s.', 'w3-total_cache' ),
|
547 |
+
'<a target="_blank" href="' . esc_url(
|
548 |
+
'https://www.boldgrid.com/support/w3-total-cache/image-service#conversion-canceled/?utm_source=w3tc&utm_medium=conversion_canceled&utm_campaign=imageservice'
|
549 |
+
) . '">',
|
550 |
+
'</a>'
|
551 |
+
),
|
552 |
+
),
|
553 |
+
'settings' => $this->config->get_array( 'imageservice' ),
|
554 |
+
'settingsUrl' => esc_url( Util_Ui::admin_url( 'upload.php?page=w3tc_extension_page_imageservice' ) ),
|
555 |
+
)
|
556 |
+
);
|
557 |
+
|
558 |
+
wp_enqueue_script( 'w3tc-imageservice' );
|
559 |
+
|
560 |
+
wp_enqueue_style(
|
561 |
+
'w3tc-imageservice',
|
562 |
+
esc_url( plugin_dir_url( __FILE__ ) . 'Extension_ImageService_Plugin_Admin.css' ),
|
563 |
+
array(),
|
564 |
+
W3TC_VERSION,
|
565 |
+
'all'
|
566 |
+
);
|
567 |
+
}
|
568 |
+
}
|
569 |
+
|
570 |
+
/**
|
571 |
+
* Add image service controls to the Media Library table in list view.
|
572 |
+
*
|
573 |
+
* Runs on the "manage_media_columns" filter.
|
574 |
+
*
|
575 |
+
* @since 2.2.0
|
576 |
+
*
|
577 |
+
* @param string[] $posts_columns An array of columns displayed in the Media list table.
|
578 |
+
* @param bool $detached Whether the list table contains media not attached
|
579 |
+
* to any posts. Default true.
|
580 |
+
*/
|
581 |
+
public function add_media_column( $posts_columns, $detached = true ) {
|
582 |
+
// Delete transient for displaying activation notice.
|
583 |
+
delete_transient( 'w3tc_activation_imageservice' );
|
584 |
+
|
585 |
+
$posts_columns['imageservice'] = '<span class="w3tc-convert"></span> ' . esc_html__( 'Image Service', 'w3-total-cache' );
|
586 |
+
|
587 |
+
return $posts_columns;
|
588 |
+
}
|
589 |
+
|
590 |
+
/**
|
591 |
+
* Fires for each custom column in the Media list table.
|
592 |
+
*
|
593 |
+
* Custom columns are registered using the {@see 'manage_media_columns'} filter.
|
594 |
+
* Runs on the "manage_media_custom_column" action.
|
595 |
+
*
|
596 |
+
* @since 2.5.0
|
597 |
+
*
|
598 |
+
* @see self::remove_optimizations()
|
599 |
+
*
|
600 |
+
* @link https://developer.wordpress.org/reference/functions/size_format/
|
601 |
+
*
|
602 |
+
* @param string $column_name Name of the custom column.
|
603 |
+
* @param int $post_id Attachment ID.
|
604 |
+
*/
|
605 |
+
public function media_column_row( $column_name, $post_id ) {
|
606 |
+
static $settings;
|
607 |
+
|
608 |
+
if ( 'imageservice' === $column_name ) {
|
609 |
+
$post = get_post( $post_id );
|
610 |
+
$imageservice_data = get_post_meta( $post_id, 'w3tc_imageservice', true );
|
611 |
+
|
612 |
+
$settings = isset( $settings ) ? $settings : $this->config->get_array( 'imageservice' );
|
613 |
+
|
614 |
+
// Display controls and info for eligible images.
|
615 |
+
if ( in_array( $post->post_mime_type, self::$mime_types, true ) ) {
|
616 |
+
$filepath = get_attached_file( $post_id );
|
617 |
+
$status = isset( $imageservice_data['status'] ) ? $imageservice_data['status'] : null;
|
618 |
+
|
619 |
+
// Check if image still has the converted file. It could have been deleted.
|
620 |
+
if ( 'converted' === $status && isset( $imageservice_data['post_child'] ) ) {
|
621 |
+
$child_data = get_post_meta( $imageservice_data['post_child'], 'w3tc_imageservice', true );
|
622 |
+
|
623 |
+
if ( empty( $child_data['is_converted_file'] ) ) {
|
624 |
+
$status = null;
|
625 |
+
$this->remove_optimizations( $post_id );
|
626 |
+
}
|
627 |
+
}
|
628 |
+
|
629 |
+
// If processed, then show information.
|
630 |
+
if ( 'converted' === $status ) {
|
631 |
+
$converted_percent = isset( $imageservice_data['download']["\0*\0data"]['x-filesize-out-percent'] ) ?
|
632 |
+
$imageservice_data['download']["\0*\0data"]['x-filesize-out-percent'] : null;
|
633 |
+
$reduced_percent = isset( $imageservice_data['download']["\0*\0data"]['x-filesize-reduced'] ) ?
|
634 |
+
$imageservice_data['download']["\0*\0data"]['x-filesize-reduced'] : null;
|
635 |
+
$filesize_in = isset( $imageservice_data['download']["\0*\0data"]['x-filesize-in'] ) ?
|
636 |
+
$imageservice_data['download']["\0*\0data"]['x-filesize-in'] : null;
|
637 |
+
$filesize_out = isset( $imageservice_data['download']["\0*\0data"]['x-filesize-out'] ) ?
|
638 |
+
$imageservice_data['download']["\0*\0data"]['x-filesize-out'] : null;
|
639 |
+
|
640 |
+
if ( $converted_percent ) {
|
641 |
+
$converted_class = rtrim( $converted_percent, '%' ) > 100 ? 'w3tc-converted-increased' : 'w3tc-converted-reduced';
|
642 |
+
?>
|
643 |
+
<div class="<?php echo esc_attr( $converted_class ); ?>">
|
644 |
+
<?php
|
645 |
+
printf(
|
646 |
+
'%1$s → %2$s (%3$s)',
|
647 |
+
esc_html( size_format( $filesize_in ) ),
|
648 |
+
esc_html( size_format( $filesize_out ) ),
|
649 |
+
esc_html( $reduced_percent )
|
650 |
+
);
|
651 |
+
?>
|
652 |
+
</div>
|
653 |
+
<?php
|
654 |
+
}
|
655 |
+
} elseif ( 'notconverted' === $status ) {
|
656 |
+
?>
|
657 |
+
<div class="w3tc-notconverted">
|
658 |
+
<?php
|
659 |
+
printf(
|
660 |
+
// translators: 1: HTML anchor open tag, 2: HTML anchor close tag.
|
661 |
+
esc_html__( 'The converted image would be larger than the original; conversion canceled. %1$sLearn more%2$s.', 'w3-total_cache' ),
|
662 |
+
'<a target="_blank" href="' . esc_url(
|
663 |
+
'https://www.boldgrid.com/support/w3-total-cache/image-service#conversion-canceled/?utm_source=w3tc&utm_medium=conversion_canceled&utm_campaign=imageservice'
|
664 |
+
) . '">',
|
665 |
+
'</a>'
|
666 |
+
);
|
667 |
+
?>
|
668 |
+
</div>
|
669 |
+
<?php
|
670 |
+
}
|
671 |
+
|
672 |
+
// Determine classes.
|
673 |
+
$link_classes = 'w3tc-convert';
|
674 |
+
|
675 |
+
switch ( $status ) {
|
676 |
+
case 'processing':
|
677 |
+
$link_classes .= ' w3tc-convert-processing';
|
678 |
+
$disabled_class = 'w3tc-disabled';
|
679 |
+
$aria_attr = 'true';
|
680 |
+
break;
|
681 |
+
case 'converted':
|
682 |
+
$disabled_class = 'w3tc-disabled';
|
683 |
+
$aria_attr = 'true';
|
684 |
+
break;
|
685 |
+
default:
|
686 |
+
$disabled_class = '';
|
687 |
+
$aria_attr = 'false';
|
688 |
+
break;
|
689 |
+
}
|
690 |
+
|
691 |
+
// Print action links.
|
692 |
+
?>
|
693 |
+
<span class="<?php echo esc_attr( $disabled_class ); ?>">
|
694 |
+
<a class="<?php echo esc_attr( $link_classes ); ?>" data-post-id="<?php echo esc_attr( $post_id ); ?>"
|
695 |
+
data-status="<?php echo esc_attr( $status ); ?>" aria-disabled="<?php echo esc_attr( $aria_attr ); ?>">
|
696 |
+
<?php
|
697 |
+
// phpcs:disable Generic.WhiteSpace.ScopeIndent.IncorrectExact
|
698 |
+
switch ( $status ) {
|
699 |
+
case 'sending':
|
700 |
+
esc_html_e( 'Sending...', 'w3-total-cache' );
|
701 |
+
break;
|
702 |
+
case 'processing':
|
703 |
+
esc_html_e( 'Processing...', 'w3-total-cache' );
|
704 |
+
break;
|
705 |
+
case 'converted':
|
706 |
+
esc_html_e( 'Converted', 'w3-total-cache' );
|
707 |
+
break;
|
708 |
+
case 'notconverted':
|
709 |
+
if ( isset( $settings['compression'] ) && 'lossless' === $settings['compression'] ) {
|
710 |
+
esc_html_e( 'Settings', 'w3-total-cache' );
|
711 |
+
} else {
|
712 |
+
esc_html_e( 'Convert', 'w3-total-cache' );
|
713 |
+
}
|
714 |
+
break;
|
715 |
+
default:
|
716 |
+
esc_html_e( 'Convert', 'w3-total-cache' );
|
717 |
+
break;
|
718 |
+
}
|
719 |
+
// phpcs:enable Generic.WhiteSpace.ScopeIndent.IncorrectExact
|
720 |
+
?>
|
721 |
+
</a>
|
722 |
+
</span>
|
723 |
+
<?php
|
724 |
+
|
725 |
+
// If converted, then show revert link.
|
726 |
+
if ( 'converted' === $status ) {
|
727 |
+
?>
|
728 |
+
<span class="w3tc-revert"> | <a><?php esc_attr_e( 'Revert', 'w3-total-cache' ); ?></a></span>
|
729 |
+
<?php
|
730 |
+
}
|
731 |
+
} elseif ( isset( $imageservice_data['is_converted_file'] ) && $imageservice_data['is_converted_file'] ) {
|
732 |
+
// W3TC converted image.
|
733 |
+
echo esc_html__( 'Attachment id: ', 'w3-total-cache' ) . esc_html( $post->post_parent );
|
734 |
+
}
|
735 |
+
}
|
736 |
+
}
|
737 |
+
|
738 |
+
/**
|
739 |
+
* Add bulk actions.
|
740 |
+
*
|
741 |
+
* @since 2.2.0
|
742 |
+
*
|
743 |
+
* @param array $actions Bulk actions.
|
744 |
+
* @return array
|
745 |
+
*/
|
746 |
+
public function add_bulk_actions( array $actions ) {
|
747 |
+
$actions['w3tc_imageservice_convert'] = 'W3 Total Convert';
|
748 |
+
$actions['w3tc_imageservice_revert'] = 'W3 Total Convert Revert';
|
749 |
+
|
750 |
+
return $actions;
|
751 |
+
}
|
752 |
+
|
753 |
+
/**
|
754 |
+
* Handle bulk actions.
|
755 |
+
*
|
756 |
+
* @since 2.2.0
|
757 |
+
*
|
758 |
+
* @see self::submit_images()
|
759 |
+
* @see self::revert_optimizations()
|
760 |
+
*
|
761 |
+
* @link https://developer.wordpress.org/reference/hooks/handle_bulk_actions-screen/
|
762 |
+
* @link https://make.wordpress.org/core/2016/10/04/custom-bulk-actions/
|
763 |
+
* @link https://core.trac.wordpress.org/browser/tags/5.8/src/wp-admin/upload.php#L206
|
764 |
+
*
|
765 |
+
* @since WordPress 4.7.0
|
766 |
+
*
|
767 |
+
* @param string $location The redirect URL.
|
768 |
+
* @param string $doaction The action being taken.
|
769 |
+
* @param array $post_ids The items to take the action on. Accepts an array of IDs of attachments.
|
770 |
+
* @return string
|
771 |
+
*/
|
772 |
+
public function handle_bulk_actions( $location, $doaction, array $post_ids ) {
|
773 |
+
// Remove custom query args.
|
774 |
+
$location = remove_query_arg( array( 'w3tc_imageservice_submitted', 'w3tc_imageservice_reverted' ), $location );
|
775 |
+
|
776 |
+
switch ( $doaction ) {
|
777 |
+
case 'w3tc_imageservice_convert':
|
778 |
+
$stats = $this->submit_images( $post_ids );
|
779 |
+
|
780 |
+
$location = add_query_arg(
|
781 |
+
array(
|
782 |
+
'w3tc_imageservice_submitted' => $stats['submitted'],
|
783 |
+
'w3tc_imageservice_successful' => $stats['successful'],
|
784 |
+
'w3tc_imageservice_skipped' => $stats['skipped'],
|
785 |
+
'w3tc_imageservice_errored' => $stats['errored'],
|
786 |
+
'w3tc_imageservice_invalid' => $stats['invalid'],
|
787 |
+
),
|
788 |
+
$location
|
789 |
+
);
|
790 |
+
|
791 |
+
break;
|
792 |
+
case 'w3tc_imageservice_revert':
|
793 |
+
$this->revert_optimizations( $post_ids );
|
794 |
+
|
795 |
+
$location = add_query_arg( 'w3tc_imageservice_reverted', 1, $location );
|
796 |
+
|
797 |
+
break;
|
798 |
+
default:
|
799 |
+
break;
|
800 |
+
}
|
801 |
+
|
802 |
+
return $location;
|
803 |
+
}
|
804 |
+
|
805 |
+
/**
|
806 |
+
* Display bulk action results admin notice.
|
807 |
+
*
|
808 |
+
* @since 2.2.0
|
809 |
+
*
|
810 |
+
* @uses $_GET['w3tc_imageservice_submitted'] Number of submittions.
|
811 |
+
* @uses $_GET['w3tc_imageservice_successful'] Number of successful submissions.
|
812 |
+
* @uses $_GET['w3tc_imageservice_skipped'] Number of skipped submissions.
|
813 |
+
* @uses $_GET['w3tc_imageservice_errored'] Number of errored submissions.
|
814 |
+
* @uses $_GET['w3tc_imageservice_invalid'] Number of invalid submissions.
|
815 |
+
*/
|
816 |
+
public function display_notices() {
|
817 |
+
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
818 |
+
if ( isset( $_GET['w3tc_imageservice_submitted'] ) ) {
|
819 |
+
$submitted = intval( $_GET['w3tc_imageservice_submitted'] );
|
820 |
+
$successful = isset( $_GET['w3tc_imageservice_successful'] ) ? intval( $_GET['w3tc_imageservice_successful'] ) : 0;
|
821 |
+
$skipped = isset( $_GET['w3tc_imageservice_skipped'] ) ? intval( $_GET['w3tc_imageservice_skipped'] ) : 0;
|
822 |
+
$errored = isset( $_GET['w3tc_imageservice_errored'] ) ? intval( $_GET['w3tc_imageservice_errored'] ) : 0;
|
823 |
+
$invalid = isset( $_GET['w3tc_imageservice_invalid'] ) ? intval( $_GET['w3tc_imageservice_invalid'] ) : 0;
|
824 |
+
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
825 |
+
|
826 |
+
?>
|
827 |
+
<script>history.pushState( null, '', location.href.split( '?' )[0] );</script>
|
828 |
+
|
829 |
+
<div class="updated notice notice-success is-dismissible">
|
830 |
+
<p>Total Cache Image Service</p>
|
831 |
+
<p>
|
832 |
+
<?php
|
833 |
+
|
834 |
+
printf(
|
835 |
+
esc_html(
|
836 |
+
// translators: 1: Submissions.
|
837 |
+
_n(
|
838 |
+
'Submitted %1$u image for processing.',
|
839 |
+
'Submitted %1$u images for processing.',
|
840 |
+
$submitted,
|
841 |
+
'w3-total-cache'
|
842 |
+
)
|
843 |
+
) . '</p>',
|
844 |
+
esc_attr( $submitted )
|
845 |
+
);
|
846 |
+
|
847 |
+
// Print extra stats if debug is on.
|
848 |
+
if ( defined( 'W3TC_DEBUG' ) && W3TC_DEBUG ) {
|
849 |
+
?>
|
850 |
+
<p>
|
851 |
+
<?php
|
852 |
+
|
853 |
+
printf(
|
854 |
+
// translators: 1: Successes, 2: Skipped, 3: Errored, 4: Invalid.
|
855 |
+
esc_html__(
|
856 |
+
'Successful: %1$u | Skipped: %2$u | Errored: %3$u | Invalid: %4$u',
|
857 |
+
'w3-total-cache'
|
858 |
+
),
|
859 |
+
esc_attr( $successful ),
|
860 |
+
esc_attr( $skipped ),
|
861 |
+
esc_attr( $errored ),
|
862 |
+
esc_attr( $invalid )
|
863 |
+
);
|
864 |
+
}
|
865 |
+
|
866 |
+
?>
|
867 |
+
</p>
|
868 |
+
</div>
|
869 |
+
<?php
|
870 |
+
|
871 |
+
} elseif ( isset( $_GET['w3tc_imageservice_reverted'] ) ) { // phpcs:ignore
|
872 |
+
?>
|
873 |
+
<script>history.pushState( null, '', location.href.split( '?' )[0] );</script>
|
874 |
+
|
875 |
+
<div class="updated notice notice-success is-dismissible"><p>Total Cache Image Service</p>
|
876 |
+
<p><?php esc_html_e( 'All selected optimizations have been reverted.', 'w3-total-cache' ); ?></p>
|
877 |
+
</div>
|
878 |
+
<?php
|
879 |
+
} elseif ( 'upload' === get_current_screen()->id ) {
|
880 |
+
// Media Library: Get the display mode.
|
881 |
+
$mode = get_user_option( 'media_library_mode', get_current_user_id() ) ?
|
882 |
+
get_user_option( 'media_library_mode', get_current_user_id() ) : 'grid';
|
883 |
+
|
884 |
+
// If not in list mode, then print a notice to switch to it.
|
885 |
+
if ( 'list' !== $mode ) {
|
886 |
+
?>
|
887 |
+
<div class="notice notice-warning is-dismissible"><p>Total Cache Image Service -
|
888 |
+
<?php
|
889 |
+
printf(
|
890 |
+
// translators: 1: HTML anchor open tag, 2: HTML anchor close tag.
|
891 |
+
esc_html__( 'Switch to %1$slist mode%2$s for WebP conversions.', 'w3-total-cache' ),
|
892 |
+
'<a href="' . esc_attr( Util_Ui::admin_url( 'upload.php?mode=list' ) ) . '">',
|
893 |
+
'</a>'
|
894 |
+
);
|
895 |
+
?>
|
896 |
+
</p>
|
897 |
+
</div>
|
898 |
+
<?php
|
899 |
+
}
|
900 |
+
}
|
901 |
+
}
|
902 |
+
|
903 |
+
/**
|
904 |
+
* Submit images to the API for processing.
|
905 |
+
*
|
906 |
+
* @since 2.2.0
|
907 |
+
*
|
908 |
+
* @global $wp_filesystem
|
909 |
+
*
|
910 |
+
* @see Extension_ImageService_Plugin::get_api()
|
911 |
+
*
|
912 |
+
* @param array $post_ids Post ids.
|
913 |
+
* @return array
|
914 |
+
*/
|
915 |
+
public function submit_images( array $post_ids ) {
|
916 |
+
WP_Filesystem();
|
917 |
+
global $wp_filesystem;
|
918 |
+
|
919 |
+
$stats = array(
|
920 |
+
'skipped' => 0,
|
921 |
+
'submitted' => 0,
|
922 |
+
'successful' => 0,
|
923 |
+
'errored' => 0,
|
924 |
+
'invalid' => 0,
|
925 |
+
);
|
926 |
+
|
927 |
+
foreach ( $post_ids as $post_id ) {
|
928 |
+
// Skip silently (do not count) if not an allowed MIME type.
|
929 |
+
if ( ! in_array( get_post_mime_type( $post_id ), self::$mime_types, true ) ) {
|
930 |
+
continue;
|
931 |
+
}
|
932 |
+
|
933 |
+
$filepath = get_attached_file( $post_id );
|
934 |
+
|
935 |
+
// Skip if attachment file does not exist.
|
936 |
+
if ( ! $wp_filesystem->exists( $filepath ) ) {
|
937 |
+
$stats['skipped']++;
|
938 |
+
continue;
|
939 |
+
}
|
940 |
+
|
941 |
+
// Submit current image.
|
942 |
+
$response = Extension_ImageService_Plugin::get_api()->convert( $filepath );
|
943 |
+
$stats['submitted']++;
|
944 |
+
|
945 |
+
if ( isset( $response['error'] ) ) {
|
946 |
+
$stats['errored']++;
|
947 |
+
continue;
|
948 |
+
}
|
949 |
+
|
950 |
+
if ( empty( $response['job_id'] ) || empty( $response['signature'] ) ) {
|
951 |
+
$stats['invalid']++;
|
952 |
+
continue;
|
953 |
+
}
|
954 |
+
|
955 |
+
// Remove old optimizations.
|
956 |
+
$this->remove_optimizations( $post_id );
|
957 |
+
|
958 |
+
// Save the job info.
|
959 |
+
self::update_postmeta(
|
960 |
+
$post_id,
|
961 |
+
array(
|
962 |
+
'status' => 'processing',
|
963 |
+
'processing' => $response,
|
964 |
+
)
|
965 |
+
);
|
966 |
+
|
967 |
+
$stats['successful']++;
|
968 |
+
}
|
969 |
+
|
970 |
+
return $stats;
|
971 |
+
}
|
972 |
+
|
973 |
+
/**
|
974 |
+
* Revert optimizations of images.
|
975 |
+
*
|
976 |
+
* @since 2.2.0
|
977 |
+
*
|
978 |
+
* @param array $post_ids Attachment post ids.
|
979 |
+
*/
|
980 |
+
public function revert_optimizations( array $post_ids ) {
|
981 |
+
foreach ( $post_ids as $post_id ) {
|
982 |
+
// Skip if not an allowed MIME type.
|
983 |
+
if ( ! in_array( get_post_mime_type( $post_id ), self::$mime_types, true ) ) {
|
984 |
+
continue;
|
985 |
+
}
|
986 |
+
|
987 |
+
$this->remove_optimizations( $post_id );
|
988 |
+
}
|
989 |
+
}
|
990 |
+
|
991 |
+
/**
|
992 |
+
* Update postmeta.
|
993 |
+
*
|
994 |
+
* @since 2.2.0
|
995 |
+
* @static
|
996 |
+
*
|
997 |
+
* @link https://developer.wordpress.org/reference/functions/update_post_meta/
|
998 |
+
*
|
999 |
+
* @param int $post_id Post id.
|
1000 |
+
* @param array $data Postmeta data.
|
1001 |
+
* @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure or if the value
|
1002 |
+
* passed to the function is the same as the one that is already in the database.
|
1003 |
+
*/
|
1004 |
+
public static function update_postmeta( $post_id, array $data ) {
|
1005 |
+
$postmeta = (array) get_post_meta( $post_id, 'w3tc_imageservice', true );
|
1006 |
+
$postmeta = array_merge( $postmeta, $data );
|
1007 |
+
|
1008 |
+
return update_post_meta( $post_id, 'w3tc_imageservice', $postmeta );
|
1009 |
+
}
|
1010 |
+
|
1011 |
+
/**
|
1012 |
+
* Copy postmeta from one post to another.
|
1013 |
+
*
|
1014 |
+
* @since 2.2.0
|
1015 |
+
* @static
|
1016 |
+
*
|
1017 |
+
* @link https://developer.wordpress.org/reference/functions/update_post_meta/
|
1018 |
+
*
|
1019 |
+
* @param int $post_id_1 Post id 1.
|
1020 |
+
* @param int $post_id_2 Post id 2.
|
1021 |
+
* @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure or if the value
|
1022 |
+
* passed to the function is the same as the one that is already in the database.
|
1023 |
+
*/
|
1024 |
+
public static function copy_postmeta( $post_id_1, $post_id_2 ) {
|
1025 |
+
$postmeta = (array) get_post_meta( $post_id_1, 'w3tc_imageservice', true );
|
1026 |
+
|
1027 |
+
// Do not copy "post_child".
|
1028 |
+
unset( $postmeta['post_child'] );
|
1029 |
+
|
1030 |
+
return update_post_meta( $post_id_2, 'w3tc_imageservice', $postmeta );
|
1031 |
+
}
|
1032 |
+
|
1033 |
+
/**
|
1034 |
+
* Remove optimizations.
|
1035 |
+
*
|
1036 |
+
* @since 2.2.0
|
1037 |
+
*
|
1038 |
+
* @link https://developer.wordpress.org/reference/functions/wp_delete_attachment/
|
1039 |
+
*
|
1040 |
+
* @param int $post_id Parent post id.
|
1041 |
+
* @return WP_Post|false|null Post data on success, false or null on failure.
|
1042 |
+
*/
|
1043 |
+
public function remove_optimizations( $post_id ) {
|
1044 |
+
$result = null;
|
1045 |
+
|
1046 |
+
// Get child post id.
|
1047 |
+
$postmeta = (array) get_post_meta( $post_id, 'w3tc_imageservice', true );
|
1048 |
+
$child_id = isset( $postmeta['post_child'] ) ? $postmeta['post_child'] : null;
|
1049 |
+
|
1050 |
+
if ( $child_id ) {
|
1051 |
+
// Delete optimization.
|
1052 |
+
$result = wp_delete_attachment( $child_id, true );
|
1053 |
+
}
|
1054 |
+
|
1055 |
+
// Delete postmeta.
|
1056 |
+
delete_post_meta( $post_id, 'w3tc_imageservice' );
|
1057 |
+
|
1058 |
+
return $result;
|
1059 |
+
}
|
1060 |
+
|
1061 |
+
/**
|
1062 |
+
* Handle auto-optimization on image upload.
|
1063 |
+
*
|
1064 |
+
* @since 2.2.0
|
1065 |
+
*
|
1066 |
+
* @param int $post_id Post id.
|
1067 |
+
*/
|
1068 |
+
public function auto_convert( $post_id ) {
|
1069 |
+
$settings = $this->config->get_array( 'imageservice' );
|
1070 |
+
$enabled = isset( $settings['auto'] ) && 'enabled' === $settings['auto'];
|
1071 |
+
|
1072 |
+
if ( $enabled && in_array( get_post_mime_type( $post_id ), self::$mime_types, true ) ) {
|
1073 |
+
$this->submit_images( array( $post_id ) );
|
1074 |
+
}
|
1075 |
+
}
|
1076 |
+
|
1077 |
+
/**
|
1078 |
+
* Delete optimizations on parent image delation.
|
1079 |
+
*
|
1080 |
+
* Does not filter the WordPress operation. We use this as an action trigger.
|
1081 |
+
*
|
1082 |
+
* @since 2.2.0
|
1083 |
+
*
|
1084 |
+
* @param bool|null $delete Whether to go forward with deletion.
|
1085 |
+
* @param WP_Post $post Post object.
|
1086 |
+
* @param bool $force_delete Whether to bypass the Trash.
|
1087 |
+
* @return null
|
1088 |
+
*/
|
1089 |
+
public function cleanup_optimizations( $delete, $post, $force_delete ) {
|
1090 |
+
if ( $force_delete ) {
|
1091 |
+
$this->remove_optimizations( $post->ID );
|
1092 |
+
}
|
1093 |
+
|
1094 |
+
return null;
|
1095 |
+
}
|
1096 |
+
|
1097 |
+
/**
|
1098 |
+
* AJAX: Submit an image for processing.
|
1099 |
+
*
|
1100 |
+
* @since 2.2.0
|
1101 |
+
*
|
1102 |
+
* @global $wp_filesystem
|
1103 |
+
*
|
1104 |
+
* @see Extension_ImageService_Plugin::get_api()
|
1105 |
+
*
|
1106 |
+
* @uses $_POST['post_id'] Post id.
|
1107 |
+
*/
|
1108 |
+
public function ajax_submit() {
|
1109 |
+
check_ajax_referer( 'w3tc_imageservice_submit' );
|
1110 |
+
|
1111 |
+
WP_Filesystem();
|
1112 |
+
global $wp_filesystem;
|
1113 |
+
|
1114 |
+
// Check for post id.
|
1115 |
+
$post_id = isset( $_POST['post_id'] ) ? (int) sanitize_key( $_POST['post_id'] ) : null;
|
1116 |
+
|
1117 |
+
if ( ! $post_id ) {
|
1118 |
+
wp_send_json_error(
|
1119 |
+
array(
|
1120 |
+
'error' => __( 'Missing input post id.', 'w3-total-cache' ),
|
1121 |
+
),
|
1122 |
+
400
|
1123 |
+
);
|
1124 |
+
}
|
1125 |
+
|
1126 |
+
// Verify the image file exists.
|
1127 |
+
$filepath = get_attached_file( $post_id );
|
1128 |
+
|
1129 |
+
if ( ! $wp_filesystem->exists( $filepath ) ) {
|
1130 |
+
wp_send_json_error(
|
1131 |
+
array(
|
1132 |
+
'error' => sprintf(
|
1133 |
+
// translators: 1: Image filepath.
|
1134 |
+
__( 'File "%1$s" does not exist.', 'w3-total-cache' ),
|
1135 |
+
$filepath
|
1136 |
+
),
|
1137 |
+
),
|
1138 |
+
412
|
1139 |
+
);
|
1140 |
+
}
|
1141 |
+
|
1142 |
+
// Submit the job request.
|
1143 |
+
$response = Extension_ImageService_Plugin::get_api()->convert( $filepath );
|
1144 |
+
|
1145 |
+
// Check for non-200 status code.
|
1146 |
+
if ( isset( $response['code'] ) && 200 !== $response['code'] ) {
|
1147 |
+
wp_send_json_error(
|
1148 |
+
$response,
|
1149 |
+
$response['code']
|
1150 |
+
);
|
1151 |
+
}
|
1152 |
+
|
1153 |
+
// Check for error.
|
1154 |
+
if ( isset( $response['error'] ) ) {
|
1155 |
+
wp_send_json_error(
|
1156 |
+
$response,
|
1157 |
+
417
|
1158 |
+
);
|
1159 |
+
}
|
1160 |
+
|
1161 |
+
// Check for valid response data.
|
1162 |
+
if ( empty( $response['job_id'] ) || empty( $response['signature'] ) ) {
|
1163 |
+
wp_send_json_error(
|
1164 |
+
array(
|
1165 |
+
'error' => __( 'Invalid API response.', 'w3-total-cache' ),
|
1166 |
+
),
|
1167 |
+
417
|
1168 |
+
);
|
1169 |
+
}
|
1170 |
+
|
1171 |
+
// Remove old optimizations.
|
1172 |
+
$this->remove_optimizations( $post_id );
|
1173 |
+
|
1174 |
+
// Save the job info.
|
1175 |
+
self::update_postmeta(
|
1176 |
+
$post_id,
|
1177 |
+
array(
|
1178 |
+
'status' => 'processing',
|
1179 |
+
'processing' => $response,
|
1180 |
+
)
|
1181 |
+
);
|
1182 |
+
|
1183 |
+
wp_send_json_success( $response );
|
1184 |
+
}
|
1185 |
+
|
1186 |
+
/**
|
1187 |
+
* AJAX: Get the status of an image, from postmeta.
|
1188 |
+
*
|
1189 |
+
* @since 2.2.0
|
1190 |
+
*
|
1191 |
+
* @uses $_POST['post_id'] Post id.
|
1192 |
+
*/
|
1193 |
+
public function ajax_get_postmeta() {
|
1194 |
+
check_ajax_referer( 'w3tc_imageservice_postmeta' );
|
1195 |
+
|
1196 |
+
$post_id = isset( $_POST['post_id'] ) ? (int) sanitize_key( $_POST['post_id'] ) : null;
|
1197 |
+
|
1198 |
+
if ( $post_id ) {
|
1199 |
+
wp_send_json_success( (array) get_post_meta( $post_id, 'w3tc_imageservice', true ) );
|
1200 |
+
} else {
|
1201 |
+
wp_send_json_error(
|
1202 |
+
array(
|
1203 |
+
'error' => __( 'Missing input post id.', 'w3-total-cache' ),
|
1204 |
+
),
|
1205 |
+
400
|
1206 |
+
);
|
1207 |
+
}
|
1208 |
+
}
|
1209 |
+
|
1210 |
+
/**
|
1211 |
+
* AJAX: Revert an optimization.
|
1212 |
+
*
|
1213 |
+
* @since 2.2.0
|
1214 |
+
*
|
1215 |
+
* @uses $_POST['post_id'] Parent post id.
|
1216 |
+
*/
|
1217 |
+
public function ajax_revert() {
|
1218 |
+
check_ajax_referer( 'w3tc_imageservice_revert' );
|
1219 |
+
|
1220 |
+
$post_id = isset( $_POST['post_id'] ) ? (int) sanitize_key( $_POST['post_id'] ) : null;
|
1221 |
+
|
1222 |
+
if ( $post_id ) {
|
1223 |
+
$result = $this->remove_optimizations( $post_id );
|
1224 |
+
|
1225 |
+
if ( $result ) {
|
1226 |
+
wp_send_json_success( $result );
|
1227 |
+
} else {
|
1228 |
+
wp_send_json_error(
|
1229 |
+
array(
|
1230 |
+
'error' => __( 'Missing converted attachment id.', 'w3-total-cache' ),
|
1231 |
+
),
|
1232 |
+
410
|
1233 |
+
);
|
1234 |
+
}
|
1235 |
+
} else {
|
1236 |
+
wp_send_json_error(
|
1237 |
+
array(
|
1238 |
+
'error' => __( 'Missing input post id.', 'w3-total-cache' ),
|
1239 |
+
),
|
1240 |
+
400
|
1241 |
+
);
|
1242 |
+
}
|
1243 |
+
}
|
1244 |
+
|
1245 |
+
/**
|
1246 |
+
* AJAX: Convert all images.
|
1247 |
+
*
|
1248 |
+
* @since 2.2.0
|
1249 |
+
*
|
1250 |
+
* @see self::get_eligible_attachments()
|
1251 |
+
* @see self::submit_images()
|
1252 |
+
*/
|
1253 |
+
public function ajax_convert_all() {
|
1254 |
+
check_ajax_referer( 'w3tc_imageservice_submit' );
|
1255 |
+
|
1256 |
+
$results = $this->get_eligible_attachments();
|
1257 |
+
|
1258 |
+
$post_ids = array();
|
1259 |
+
|
1260 |
+
// Allow plenty of time to complete.
|
1261 |
+
ignore_user_abort( true );
|
1262 |
+
set_time_limit( 0 );
|
1263 |
+
|
1264 |
+
foreach ( $results->posts as $post ) {
|
1265 |
+
$post_ids[] = $post->ID;
|
1266 |
+
}
|
1267 |
+
|
1268 |
+
$stats = $this->submit_images( $post_ids );
|
1269 |
+
|
1270 |
+
wp_send_json_success( $stats );
|
1271 |
+
}
|
1272 |
+
|
1273 |
+
/**
|
1274 |
+
* AJAX: Revert all converted images.
|
1275 |
+
*
|
1276 |
+
* @since 2.2.0
|
1277 |
+
*
|
1278 |
+
* @see self::get_imageservice_attachments()
|
1279 |
+
* @see self::remove_optimizations()
|
1280 |
+
*/
|
1281 |
+
public function ajax_revert_all() {
|
1282 |
+
check_ajax_referer( 'w3tc_imageservice_submit' );
|
1283 |
+
|
1284 |
+
$results = $this->get_imageservice_attachments();
|
1285 |
+
|
1286 |
+
$revert_count = 0;
|
1287 |
+
|
1288 |
+
// Allow plenty of time to complete.
|
1289 |
+
ignore_user_abort( true );
|
1290 |
+
set_time_limit( 0 );
|
1291 |
+
|
1292 |
+
foreach ( $results->posts as $post ) {
|
1293 |
+
if ( $this->remove_optimizations( $post->ID ) ) {
|
1294 |
+
$revert_count++;
|
1295 |
+
}
|
1296 |
+
}
|
1297 |
+
|
1298 |
+
wp_send_json_success( array( 'revert_count' => $revert_count ) );
|
1299 |
+
}
|
1300 |
+
|
1301 |
+
/**
|
1302 |
+
* AJAX: Get image counts by status.
|
1303 |
+
*
|
1304 |
+
* @since 2.2.0
|
1305 |
+
*
|
1306 |
+
* @see get_counts()
|
1307 |
+
*/
|
1308 |
+
public function ajax_get_counts() {
|
1309 |
+
check_ajax_referer( 'w3tc_imageservice_submit' );
|
1310 |
+
|
1311 |
+
wp_send_json_success( $this->get_counts() );
|
1312 |
+
}
|
1313 |
+
|
1314 |
+
/**
|
1315 |
+
* AJAX: Get image API usage.
|
1316 |
+
*
|
1317 |
+
* @since 2.2.0
|
1318 |
+
*
|
1319 |
+
* @see Extension_ImageService_Plugin::get_api()
|
1320 |
+
* @see Extension_ImageService_Api::get_usage()
|
1321 |
+
*/
|
1322 |
+
public function ajax_get_usage() {
|
1323 |
+
check_ajax_referer( 'w3tc_imageservice_submit' );
|
1324 |
+
|
1325 |
+
wp_send_json_success( Extension_ImageService_Plugin::get_api()->get_usage() );
|
1326 |
+
}
|
1327 |
+
}
|
Extensions_Plugin_Admin.php
CHANGED
@@ -1,150 +1,138 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
namespace W3TC;
|
3 |
|
4 |
/**
|
5 |
-
*
|
6 |
*/
|
7 |
class Extensions_Plugin_Admin {
|
8 |
/**
|
9 |
-
* Config
|
|
|
|
|
10 |
*/
|
11 |
-
private $_config = null;
|
12 |
|
13 |
-
|
|
|
|
|
|
|
14 |
$this->_config = Dispatcher::config();
|
15 |
}
|
16 |
|
17 |
/**
|
18 |
-
* Runs plugin
|
19 |
*/
|
20 |
-
function run() {
|
21 |
-
//
|
22 |
-
add_filter( 'w3tc_extensions', array(
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
add_filter( '
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
add_filter( 'w3tc_extensions', array(
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
add_filter( 'w3tc_extensions', array(
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
add_filter( 'w3tc_extensions_hooks', array(
|
39 |
-
'\W3TC\Extension_Genesis_Plugin_Admin',
|
40 |
-
'w3tc_extensions_hooks' ) );
|
41 |
-
add_filter( 'w3tc_notes_genesis_theme', array(
|
42 |
-
'\W3TC\Extension_Genesis_Plugin_Admin',
|
43 |
-
'w3tc_notes_genesis_theme' ) );
|
44 |
-
add_filter( 'w3tc_extensions', array(
|
45 |
-
'\W3TC\Extension_NewRelic_Plugin_Admin',
|
46 |
-
'w3tc_extensions' ),
|
47 |
-
10, 2 );
|
48 |
-
add_filter( 'w3tc_extensions', array(
|
49 |
-
'\W3TC\Extension_Swarmify_Plugin_Admin',
|
50 |
-
'w3tc_extensions' ),
|
51 |
-
10, 2 );
|
52 |
-
add_filter( 'w3tc_extensions', array(
|
53 |
-
'\W3TC\Extension_WordPressSeo_Plugin_Admin',
|
54 |
-
'w3tc_extensions' ),
|
55 |
-
10, 2 );
|
56 |
-
add_filter( 'w3tc_extensions_hooks', array(
|
57 |
-
'\W3TC\Extension_WordPressSeo_Plugin_Admin',
|
58 |
-
'w3tc_extensions_hooks' ) );
|
59 |
-
add_action( 'w3tc_notes_wordpress_seo', array(
|
60 |
-
'\W3TC\Extension_WordPressSeo_Plugin_Admin',
|
61 |
-
'w3tc_notes_wordpress_seo' ) );
|
62 |
-
add_filter( 'w3tc_extensions', array(
|
63 |
-
'\W3TC\Extension_Wpml_Plugin_Admin',
|
64 |
-
'w3tc_extensions' ),
|
65 |
-
10, 2 );
|
66 |
-
add_filter( 'w3tc_extensions', array(
|
67 |
-
'\W3TC\Extension_Amp_Plugin_Admin',
|
68 |
-
'w3tc_extensions' ),
|
69 |
-
10, 2 );
|
70 |
-
add_filter( 'w3tc_extensions_hooks', array(
|
71 |
-
'\W3TC\Extension_Wpml_Plugin_Admin',
|
72 |
-
'w3tc_extensions_hooks' ) );
|
73 |
-
add_action( 'w3tc_notes_wpml', array(
|
74 |
-
'\W3TC\Extension_Wpml_Plugin_Admin',
|
75 |
-
'w3tc_notes_wpml' ) );
|
76 |
-
|
77 |
add_action( 'admin_init', array( $this, 'admin_init' ), 1 );
|
78 |
-
add_filter( 'pre_update_option_active_plugins', array(
|
79 |
-
$this, 'pre_update_option_active_plugins' ) );
|
80 |
add_filter( 'w3tc_admin_menu', array( $this, 'w3tc_admin_menu' ), 10000 );
|
81 |
-
add_action( 'w3tc_settings_page-w3tc_extensions',
|
82 |
-
array( $this, 'w3tc_settings_page_w3tc_extensions' ) );
|
83 |
|
84 |
if ( Util_Admin::is_w3tc_admin_page() ) {
|
85 |
-
|
86 |
-
|
|
|
|
|
87 |
add_action( 'init', array( $this, 'change_extension_status' ) );
|
88 |
}
|
89 |
-
} elseif ( isset( $_POST['checked'] ) ) {
|
90 |
add_action( 'admin_init', array( $this, 'change_extensions_status' ) );
|
91 |
}
|
92 |
}
|
93 |
}
|
94 |
|
95 |
/**
|
96 |
-
* Adds menu
|
97 |
*
|
98 |
-
* @param
|
99 |
* @return array
|
100 |
*/
|
101 |
public function w3tc_admin_menu( $menu ) {
|
102 |
$menu['w3tc_extensions'] = array(
|
103 |
-
'page_title'
|
104 |
-
'menu_text'
|
105 |
'visible_always' => false,
|
106 |
-
'order'
|
107 |
);
|
108 |
|
109 |
return $menu;
|
110 |
}
|
111 |
|
112 |
/**
|
113 |
-
* Loads options page and corresponding view
|
114 |
*/
|
115 |
public function w3tc_settings_page_w3tc_extensions() {
|
116 |
$o = new Extensions_Page();
|
117 |
$o->render_content();
|
118 |
}
|
119 |
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
public function pre_update_option_active_plugins( $o ) {
|
121 |
delete_option( 'w3tc_extensions_hooks' );
|
122 |
|
123 |
return $o;
|
124 |
}
|
125 |
|
|
|
|
|
|
|
126 |
public function admin_init() {
|
127 |
-
//
|
128 |
-
$s
|
129 |
-
$hooks = @json_decode( $s, true );
|
130 |
-
|
|
|
131 |
$hooks['next_check_date'] < time() ) {
|
132 |
$hooks = array(
|
133 |
-
'actions'
|
134 |
-
'filters'
|
135 |
-
'next_check_date' => time() + 24 * 60 * 60
|
136 |
);
|
|
|
137 |
$hooks = apply_filters( 'w3tc_extensions_hooks', $hooks );
|
138 |
-
|
|
|
139 |
}
|
140 |
|
141 |
if ( isset( $hooks['actions'] ) ) {
|
142 |
foreach ( $hooks['actions'] as $hook => $actions_to_call ) {
|
143 |
if ( is_array( $actions_to_call ) ) {
|
144 |
-
add_action(
|
145 |
-
|
146 |
-
|
147 |
-
|
|
|
|
|
|
|
|
|
148 |
}
|
149 |
}
|
150 |
}
|
@@ -152,58 +140,100 @@ class Extensions_Plugin_Admin {
|
|
152 |
if ( isset( $hooks['filters'] ) ) {
|
153 |
foreach ( $hooks['filters'] as $hook => $filters_to_call ) {
|
154 |
if ( is_array( $filters_to_call ) ) {
|
155 |
-
add_filter(
|
156 |
-
|
157 |
-
|
|
|
|
|
|
|
158 |
|
159 |
return $v;
|
160 |
-
}
|
|
|
161 |
}
|
162 |
}
|
163 |
}
|
164 |
}
|
165 |
|
166 |
/**
|
167 |
-
* Alters the active state of multiple extensions
|
168 |
*/
|
169 |
public function change_extensions_status() {
|
|
|
170 |
$extensions = Util_Request::get_array( 'checked' );
|
171 |
-
$action
|
172 |
-
if ( '-1' == $action )
|
173 |
-
$action = Util_Request::get( 'action2' ); // dropdown at bottom
|
174 |
|
175 |
-
|
176 |
-
|
|
|
|
|
|
|
177 |
foreach ( $extensions as $extension ) {
|
178 |
-
if ( Extensions_Util::activate_extension( $extension, $this->_config ) )
|
179 |
$message .= '&activated=' . $extension;
|
|
|
180 |
}
|
181 |
-
|
182 |
-
|
|
|
183 |
foreach ( $extensions as $extension ) {
|
184 |
-
if ( Extensions_Util::deactivate_extension( $extension, $this->_config ) )
|
185 |
$message .= '&deactivated=' . $extension;
|
|
|
186 |
}
|
187 |
-
|
|
|
188 |
} else {
|
189 |
-
|
|
|
190 |
}
|
191 |
}
|
192 |
|
193 |
/**
|
194 |
-
* Alters the active state of an extension
|
195 |
*/
|
196 |
public function change_extension_status() {
|
197 |
$action = Util_Request::get_string( 'action' );
|
198 |
|
199 |
-
if ( in_array( $action, array( 'activate', 'deactivate' ) ) ) {
|
200 |
$extension = Util_Request::get_string( 'extension' );
|
201 |
-
|
|
|
202 |
Extensions_Util::activate_extension( $extension, $this->_config );
|
203 |
-
|
204 |
-
|
|
|
205 |
Extensions_Util::deactivate_extension( $extension, $this->_config );
|
206 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
207 |
}
|
208 |
}
|
209 |
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* File: Extensions_Plugin_Admin.php
|
4 |
+
*
|
5 |
+
* @package W3TC
|
6 |
+
*/
|
7 |
+
|
8 |
namespace W3TC;
|
9 |
|
10 |
/**
|
11 |
+
* Class: Extensions_Plugin_Admin
|
12 |
*/
|
13 |
class Extensions_Plugin_Admin {
|
14 |
/**
|
15 |
+
* Config.
|
16 |
+
*
|
17 |
+
* @var Config
|
18 |
*/
|
19 |
+
private $_config = null; // phpcs:ignore
|
20 |
|
21 |
+
/**
|
22 |
+
* Constructor.
|
23 |
+
*/
|
24 |
+
public function __construct() {
|
25 |
$this->_config = Dispatcher::config();
|
26 |
}
|
27 |
|
28 |
/**
|
29 |
+
* Runs plugin.
|
30 |
*/
|
31 |
+
public function run() {
|
32 |
+
// Attach w3tc-bundled extensions.
|
33 |
+
add_filter( 'w3tc_extensions', array( '\W3TC\Extension_CloudFlare_Plugin_Admin', 'w3tc_extensions' ), 10, 2 );
|
34 |
+
add_filter( 'w3tc_extensions', array( '\W3TC\Extension_FeedBurner_Plugin_Admin', 'w3tc_extensions' ), 10, 2 );
|
35 |
+
add_filter( 'w3tc_extensions', array( '\W3TC\Extension_FragmentCache_Plugin_Admin', 'w3tc_extensions' ), 10, 2 );
|
36 |
+
add_filter( 'w3tc_extensions', array( '\W3TC\Extension_Genesis_Plugin_Admin', 'w3tc_extensions' ), 10, 2 );
|
37 |
+
add_filter( 'w3tc_extensions_hooks', array( '\W3TC\Extension_Genesis_Plugin_Admin', 'w3tc_extensions_hooks' ) );
|
38 |
+
add_filter( 'w3tc_notes_genesis_theme', array( '\W3TC\Extension_Genesis_Plugin_Admin', 'w3tc_notes_genesis_theme' ) );
|
39 |
+
add_filter( 'w3tc_extensions', array( '\W3TC\Extension_NewRelic_Plugin_Admin', 'w3tc_extensions' ), 10, 2 );
|
40 |
+
add_filter( 'w3tc_extensions', array( '\W3TC\Extension_Swarmify_Plugin_Admin', 'w3tc_extensions' ), 10, 2 );
|
41 |
+
add_filter( 'w3tc_extensions', array( '\W3TC\Extension_WordPressSeo_Plugin_Admin', 'w3tc_extensions' ), 10, 2 );
|
42 |
+
add_filter( 'w3tc_extensions_hooks', array( '\W3TC\Extension_WordPressSeo_Plugin_Admin', 'w3tc_extensions_hooks' ) );
|
43 |
+
add_action( 'w3tc_notes_wordpress_seo', array( '\W3TC\Extension_WordPressSeo_Plugin_Admin', 'w3tc_notes_wordpress_seo' ) );
|
44 |
+
add_filter( 'w3tc_extensions', array( '\W3TC\Extension_Wpml_Plugin_Admin', 'w3tc_extensions' ), 10, 2 );
|
45 |
+
add_filter( 'w3tc_extensions', array( '\W3TC\Extension_Amp_Plugin_Admin', 'w3tc_extensions' ), 10, 2 );
|
46 |
+
add_filter( 'w3tc_extensions_hooks', array( '\W3TC\Extension_Wpml_Plugin_Admin', 'w3tc_extensions_hooks' ) );
|
47 |
+
add_action( 'w3tc_notes_wpml', array( '\W3TC\Extension_Wpml_Plugin_Admin', 'w3tc_notes_wpml' ) );
|
48 |
+
add_filter( 'w3tc_extensions', array( '\W3TC\Extension_ImageService_Plugin_Admin', 'w3tc_extensions' ), 10, 2 );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
add_action( 'admin_init', array( $this, 'admin_init' ), 1 );
|
50 |
+
add_filter( 'pre_update_option_active_plugins', array( $this, 'pre_update_option_active_plugins' ) );
|
|
|
51 |
add_filter( 'w3tc_admin_menu', array( $this, 'w3tc_admin_menu' ), 10000 );
|
52 |
+
add_action( 'w3tc_settings_page-w3tc_extensions', array( $this, 'w3tc_settings_page_w3tc_extensions' ) );
|
|
|
53 |
|
54 |
if ( Util_Admin::is_w3tc_admin_page() ) {
|
55 |
+
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
|
56 |
+
|
57 |
+
if ( isset( $_GET['extension'] ) && isset( $_GET['action'] ) ) { // phpcs:ignore
|
58 |
+
if ( in_array( $_GET['action'], array( 'activate', 'deactivate' ), true ) ) { // phpcs:ignore
|
59 |
add_action( 'init', array( $this, 'change_extension_status' ) );
|
60 |
}
|
61 |
+
} elseif ( isset( $_POST['checked'] ) ) { // phpcs:ignore
|
62 |
add_action( 'admin_init', array( $this, 'change_extensions_status' ) );
|
63 |
}
|
64 |
}
|
65 |
}
|
66 |
|
67 |
/**
|
68 |
+
* Adds menu.
|
69 |
*
|
70 |
+
* @param array $menu Menu.
|
71 |
* @return array
|
72 |
*/
|
73 |
public function w3tc_admin_menu( $menu ) {
|
74 |
$menu['w3tc_extensions'] = array(
|
75 |
+
'page_title' => __( 'Extensions', 'w3-total-cache' ),
|
76 |
+
'menu_text' => __( 'Extensions', 'w3-total-cache' ),
|
77 |
'visible_always' => false,
|
78 |
+
'order' => 1900,
|
79 |
);
|
80 |
|
81 |
return $menu;
|
82 |
}
|
83 |
|
84 |
/**
|
85 |
+
* Loads options page and corresponding view.
|
86 |
*/
|
87 |
public function w3tc_settings_page_w3tc_extensions() {
|
88 |
$o = new Extensions_Page();
|
89 |
$o->render_content();
|
90 |
}
|
91 |
|
92 |
+
/**
|
93 |
+
* Delete hooks option before updating active plugins option.
|
94 |
+
*
|
95 |
+
* @param mixed $o Option value.
|
96 |
+
* @return mixed
|
97 |
+
*/
|
98 |
public function pre_update_option_active_plugins( $o ) {
|
99 |
delete_option( 'w3tc_extensions_hooks' );
|
100 |
|
101 |
return $o;
|
102 |
}
|
103 |
|
104 |
+
/**
|
105 |
+
* Admin init.
|
106 |
+
*/
|
107 |
public function admin_init() {
|
108 |
+
// Used to load even inactive extensions if they want to.
|
109 |
+
$s = get_option( 'w3tc_extensions_hooks' );
|
110 |
+
$hooks = @json_decode( $s, true ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
|
111 |
+
|
112 |
+
if ( ! isset( $hooks['next_check_date'] ) ||
|
113 |
$hooks['next_check_date'] < time() ) {
|
114 |
$hooks = array(
|
115 |
+
'actions' => array(),
|
116 |
+
'filters' => array(),
|
117 |
+
'next_check_date' => time() + 24 * 60 * 60,
|
118 |
);
|
119 |
+
|
120 |
$hooks = apply_filters( 'w3tc_extensions_hooks', $hooks );
|
121 |
+
|
122 |
+
update_option( 'w3tc_extensions_hooks', wp_json_encode( $hooks ) );
|
123 |
}
|
124 |
|
125 |
if ( isset( $hooks['actions'] ) ) {
|
126 |
foreach ( $hooks['actions'] as $hook => $actions_to_call ) {
|
127 |
if ( is_array( $actions_to_call ) ) {
|
128 |
+
add_action(
|
129 |
+
$hook,
|
130 |
+
function() use ( $actions_to_call ) {
|
131 |
+
foreach ( $actions_to_call as $action ) {
|
132 |
+
do_action( $action );
|
133 |
+
}
|
134 |
+
}
|
135 |
+
);
|
136 |
}
|
137 |
}
|
138 |
}
|
140 |
if ( isset( $hooks['filters'] ) ) {
|
141 |
foreach ( $hooks['filters'] as $hook => $filters_to_call ) {
|
142 |
if ( is_array( $filters_to_call ) ) {
|
143 |
+
add_filter(
|
144 |
+
$hook,
|
145 |
+
function( $v ) use ( $filters_to_call ) {
|
146 |
+
foreach ( $filters_to_call as $filter ) {
|
147 |
+
$v = apply_filters( $filter, $v );
|
148 |
+
}
|
149 |
|
150 |
return $v;
|
151 |
+
}
|
152 |
+
);
|
153 |
}
|
154 |
}
|
155 |
}
|
156 |
}
|
157 |
|
158 |
/**
|
159 |
+
* Alters the active state of multiple extensions.
|
160 |
*/
|
161 |
public function change_extensions_status() {
|
162 |
+
$message = '';
|
163 |
$extensions = Util_Request::get_array( 'checked' );
|
164 |
+
$action = Util_Request::get( 'action' );
|
|
|
|
|
165 |
|
166 |
+
if ( '-1' === $action ) {
|
167 |
+
$action = Util_Request::get( 'action2' ); // Dropdown at bottom.
|
168 |
+
}
|
169 |
+
|
170 |
+
if ( 'activate-selected' === $action ) {
|
171 |
foreach ( $extensions as $extension ) {
|
172 |
+
if ( Extensions_Util::activate_extension( $extension, $this->_config ) ) {
|
173 |
$message .= '&activated=' . $extension;
|
174 |
+
}
|
175 |
}
|
176 |
+
wp_safe_redirect( Util_Ui::admin_url( sprintf( 'admin.php?page=w3tc_extensions%s', $message ) ) );
|
177 |
+
exit;
|
178 |
+
} elseif ( 'deactivate-selected' === $action ) {
|
179 |
foreach ( $extensions as $extension ) {
|
180 |
+
if ( Extensions_Util::deactivate_extension( $extension, $this->_config ) ) {
|
181 |
$message .= '&deactivated=' . $extension;
|
182 |
+
}
|
183 |
}
|
184 |
+
wp_safe_redirect( Util_Ui::admin_url( sprintf( 'admin.php?page=w3tc_extensions%s', $message ) ) );
|
185 |
+
exit;
|
186 |
} else {
|
187 |
+
wp_safe_redirect( Util_Ui::admin_url( 'admin.php?page=w3tc_extensions' ) );
|
188 |
+
exit;
|
189 |
}
|
190 |
}
|
191 |
|
192 |
/**
|
193 |
+
* Alters the active state of an extension.
|
194 |
*/
|
195 |
public function change_extension_status() {
|
196 |
$action = Util_Request::get_string( 'action' );
|
197 |
|
198 |
+
if ( in_array( $action, array( 'activate', 'deactivate' ), true ) ) {
|
199 |
$extension = Util_Request::get_string( 'extension' );
|
200 |
+
|
201 |
+
if ( 'activate' === $action ) {
|
202 |
Extensions_Util::activate_extension( $extension, $this->_config );
|
203 |
+
wp_safe_redirect( Util_Ui::admin_url( sprintf( 'admin.php?page=w3tc_extensions&activated=%s', $extension ) ) );
|
204 |
+
exit;
|
205 |
+
} elseif ( 'deactivate' === $action ) {
|
206 |
Extensions_Util::deactivate_extension( $extension, $this->_config );
|
207 |
+
wp_safe_redirect( Util_Ui::admin_url( sprintf( 'admin.php?page=w3tc_extensions&deactivated=%s', $extension ) ) );
|
208 |
+
exit;
|
209 |
+
}
|
210 |
+
}
|
211 |
+
}
|
212 |
+
|
213 |
+
/**
|
214 |
+
* Display admin notices.
|
215 |
+
*
|
216 |
+
* @since 2.2.0
|
217 |
+
*
|
218 |
+
* @see Extensions_Util::get_active_extensions()
|
219 |
+
*/
|
220 |
+
public function admin_notices() {
|
221 |
+
$extensions_active = Extensions_Util::get_active_extensions( $this->_config );
|
222 |
+
|
223 |
+
foreach ( $extensions_active as $id => $info ) {
|
224 |
+
$transient_name = 'w3tc_activation_' . $id;
|
225 |
+
$action_name = 'w3tc_' . $id . '_action';
|
226 |
+
|
227 |
+
if ( isset( $_GET[ $action_name ] ) && 'dismiss_activation_notice' === $_GET[ $action_name ] ) { // phpcs:ignore
|
228 |
+
delete_transient( $transient_name );
|
229 |
+
}
|
230 |
+
|
231 |
+
if ( isset( $info['notice'] ) && get_transient( $transient_name ) ) {
|
232 |
+
?>
|
233 |
+
<div class="notice notice-warning is-dismissible">
|
234 |
+
<p><?php echo $info['notice']; //phpcs:ignore ?></p>
|
235 |
+
</div>
|
236 |
+
<?php
|
237 |
}
|
238 |
}
|
239 |
}
|
Extensions_Util.php
CHANGED
@@ -1,97 +1,127 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
namespace W3TC;
|
3 |
|
|
|
|
|
|
|
4 |
class Extensions_Util {
|
5 |
/**
|
6 |
* Get registered extensions
|
7 |
*
|
8 |
-
* @
|
|
|
|
|
9 |
* @return array
|
10 |
*/
|
11 |
-
static
|
12 |
-
return apply_filters(
|
13 |
}
|
14 |
|
15 |
/**
|
16 |
* Get registered extension
|
17 |
*
|
18 |
-
* @
|
19 |
-
*
|
|
|
|
|
20 |
* @return array
|
21 |
*/
|
22 |
-
static
|
23 |
$exts = self::get_extensions( $config );
|
24 |
-
|
|
|
25 |
return null;
|
|
|
26 |
|
27 |
-
return $exts[$extension];
|
28 |
}
|
29 |
|
30 |
/**
|
31 |
* Returns the inactive extensions
|
32 |
*
|
33 |
-
* @
|
|
|
|
|
34 |
* @return array
|
35 |
*/
|
36 |
-
static
|
37 |
-
$extensions
|
38 |
-
$config
|
39 |
$active_extensions = $config->get_array( 'extensions.active' );
|
|
|
40 |
return array_diff_key( $extensions, $active_extensions );
|
41 |
}
|
42 |
|
43 |
/**
|
44 |
-
* Returns the active extensions
|
|
|
|
|
45 |
*
|
46 |
-
* @param
|
47 |
* @return array
|
48 |
*/
|
49 |
-
static
|
50 |
-
$extensions
|
51 |
-
$extensions_keys
|
52 |
-
$config
|
53 |
$active_extensions = $config->get_array( 'extensions.active' );
|
|
|
54 |
return array_intersect_key( $extensions, $active_extensions );
|
55 |
}
|
56 |
|
57 |
/**
|
|
|
58 |
*
|
|
|
59 |
*
|
60 |
-
* @param
|
61 |
-
* @param Config
|
|
|
62 |
* @return bool
|
63 |
*/
|
64 |
-
static
|
65 |
-
$all_extensions =
|
66 |
-
$extensions
|
67 |
|
68 |
-
if (
|
69 |
-
$meta = $all_extensions[$extension];
|
70 |
|
71 |
$filename = W3TC_EXTENSION_DIR . '/' . trim( $meta['path'], '/' );
|
72 |
-
|
|
|
73 |
return false;
|
|
|
74 |
|
75 |
include $filename;
|
76 |
|
77 |
-
$extensions[$extension] = $meta['path'];
|
|
|
78 |
ksort( $extensions, SORT_STRING );
|
|
|
79 |
$w3_config->set( 'extensions.active', $extensions );
|
80 |
|
81 |
-
// if extensions doesnt want to control frontend activity -
|
82 |
-
|
83 |
-
if ( !isset( $meta['active_frontend_own_control'] ) ||
|
84 |
-
!$meta['active_frontend_own_control'] ) {
|
85 |
$w3_config->set_extension_active_frontend( $extension, true );
|
86 |
}
|
87 |
|
88 |
-
|
89 |
try {
|
90 |
-
if (
|
91 |
$w3_config->save();
|
92 |
}
|
|
|
|
|
|
|
|
|
93 |
return true;
|
94 |
} catch ( \Exception $ex ) {
|
|
|
95 |
}
|
96 |
}
|
97 |
|
@@ -100,17 +130,20 @@ class Extensions_Util {
|
|
100 |
|
101 |
|
102 |
/**
|
|
|
103 |
*
|
|
|
104 |
*
|
105 |
-
* @param
|
106 |
-
* @param Config
|
107 |
-
* @param bool
|
108 |
* @return bool
|
109 |
*/
|
110 |
-
static
|
111 |
$extensions = $config->get_array( 'extensions.active' );
|
|
|
112 |
if ( array_key_exists( $extension, $extensions ) ) {
|
113 |
-
unset( $extensions[$extension] );
|
114 |
ksort( $extensions, SORT_STRING );
|
115 |
$config->set( 'extensions.active', $extensions );
|
116 |
}
|
@@ -118,11 +151,19 @@ class Extensions_Util {
|
|
118 |
$config->set_extension_active_frontend( $extension, false );
|
119 |
|
120 |
try {
|
121 |
-
if (
|
122 |
$config->save();
|
123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
return true;
|
125 |
-
} catch ( \Exception $ex ) {
|
|
|
|
|
126 |
|
127 |
return false;
|
128 |
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* File: Extensions_Util.php
|
4 |
+
*
|
5 |
+
* @package W3TC
|
6 |
+
*/
|
7 |
+
|
8 |
namespace W3TC;
|
9 |
|
10 |
+
/**
|
11 |
+
* Class: Extensions_Util
|
12 |
+
*/
|
13 |
class Extensions_Util {
|
14 |
/**
|
15 |
* Get registered extensions
|
16 |
*
|
17 |
+
* @static
|
18 |
+
*
|
19 |
+
* @param Config $config Configuration object.
|
20 |
* @return array
|
21 |
*/
|
22 |
+
public static function get_extensions( $config ) {
|
23 |
+
return apply_filters( 'w3tc_extensions', __return_empty_array(), $config );
|
24 |
}
|
25 |
|
26 |
/**
|
27 |
* Get registered extension
|
28 |
*
|
29 |
+
* @static
|
30 |
+
*
|
31 |
+
* @param Config $config Configuration object.
|
32 |
+
* @param string $extension Extension.
|
33 |
* @return array
|
34 |
*/
|
35 |
+
public static function get_extension( $config, $extension ) {
|
36 |
$exts = self::get_extensions( $config );
|
37 |
+
|
38 |
+
if ( ! isset( $exts[ $extension ] ) ) {
|
39 |
return null;
|
40 |
+
}
|
41 |
|
42 |
+
return $exts[ $extension ];
|
43 |
}
|
44 |
|
45 |
/**
|
46 |
* Returns the inactive extensions
|
47 |
*
|
48 |
+
* @static
|
49 |
+
*
|
50 |
+
* @param Config $config Configuration object.
|
51 |
* @return array
|
52 |
*/
|
53 |
+
public static function get_inactive_extensions( $config ) {
|
54 |
+
$extensions = self::get_extensions( $config );
|
55 |
+
$config = Dispatcher::config();
|
56 |
$active_extensions = $config->get_array( 'extensions.active' );
|
57 |
+
|
58 |
return array_diff_key( $extensions, $active_extensions );
|
59 |
}
|
60 |
|
61 |
/**
|
62 |
+
* Returns the active extensions.
|
63 |
+
*
|
64 |
+
* @static
|
65 |
*
|
66 |
+
* @param Config $config Configuration object.
|
67 |
* @return array
|
68 |
*/
|
69 |
+
public static function get_active_extensions( $config ) {
|
70 |
+
$extensions = self::get_extensions( $config );
|
71 |
+
$extensions_keys = array_keys( $extensions );
|
72 |
+
$config = Dispatcher::config();
|
73 |
$active_extensions = $config->get_array( 'extensions.active' );
|
74 |
+
|
75 |
return array_intersect_key( $extensions, $active_extensions );
|
76 |
}
|
77 |
|
78 |
/**
|
79 |
+
* Activate extension.
|
80 |
*
|
81 |
+
* @static
|
82 |
*
|
83 |
+
* @param string $extension Extension.
|
84 |
+
* @param Config $w3_config Configuration object.
|
85 |
+
* @param bool $dont_save_config Whether or not to save configuration. Default: false.
|
86 |
* @return bool
|
87 |
*/
|
88 |
+
public static function activate_extension( $extension, $w3_config, $dont_save_config = false ) {
|
89 |
+
$all_extensions = self::get_extensions( $w3_config );
|
90 |
+
$extensions = $w3_config->get_array( 'extensions.active' );
|
91 |
|
92 |
+
if ( ! $w3_config->is_extension_active( $extension ) ) {
|
93 |
+
$meta = $all_extensions[ $extension ];
|
94 |
|
95 |
$filename = W3TC_EXTENSION_DIR . '/' . trim( $meta['path'], '/' );
|
96 |
+
|
97 |
+
if ( ! file_exists( $filename ) ) {
|
98 |
return false;
|
99 |
+
}
|
100 |
|
101 |
include $filename;
|
102 |
|
103 |
+
$extensions[ $extension ] = $meta['path'];
|
104 |
+
|
105 |
ksort( $extensions, SORT_STRING );
|
106 |
+
|
107 |
$w3_config->set( 'extensions.active', $extensions );
|
108 |
|
109 |
+
// if extensions doesnt want to control frontend activity - activate it there too.
|
110 |
+
if ( ! isset( $meta['active_frontend_own_control'] ) || ! $meta['active_frontend_own_control'] ) {
|
|
|
|
|
111 |
$w3_config->set_extension_active_frontend( $extension, true );
|
112 |
}
|
113 |
|
|
|
114 |
try {
|
115 |
+
if ( ! $dont_save_config ) {
|
116 |
$w3_config->save();
|
117 |
}
|
118 |
+
|
119 |
+
// Set transient for displaying activation notice.
|
120 |
+
set_transient( 'w3tc_activation_' . $extension, true, DAY_IN_SECONDS );
|
121 |
+
|
122 |
return true;
|
123 |
} catch ( \Exception $ex ) {
|
124 |
+
return false;
|
125 |
}
|
126 |
}
|
127 |
|
130 |
|
131 |
|
132 |
/**
|
133 |
+
* Deactivate extension.
|
134 |
*
|
135 |
+
* @static
|
136 |
*
|
137 |
+
* @param string $extension Extension.
|
138 |
+
* @param Config $config Configuration object.
|
139 |
+
* @param bool $dont_save_config Whether or not to save configuration. Default: false.
|
140 |
* @return bool
|
141 |
*/
|
142 |
+
public static function deactivate_extension( $extension, $config, $dont_save_config = false ) {
|
143 |
$extensions = $config->get_array( 'extensions.active' );
|
144 |
+
|
145 |
if ( array_key_exists( $extension, $extensions ) ) {
|
146 |
+
unset( $extensions[ $extension ] );
|
147 |
ksort( $extensions, SORT_STRING );
|
148 |
$config->set( 'extensions.active', $extensions );
|
149 |
}
|
151 |
$config->set_extension_active_frontend( $extension, false );
|
152 |
|
153 |
try {
|
154 |
+
if ( ! $dont_save_config ) {
|
155 |
$config->save();
|
156 |
+
}
|
157 |
+
|
158 |
+
// Delete transient for displaying activation notice.
|
159 |
+
delete_transient( 'w3tc_activation_' . $extension );
|
160 |
+
|
161 |
+
do_action( 'w3tc_deactivate_extension_' . $extension );
|
162 |
+
|
163 |
return true;
|
164 |
+
} catch ( \Exception $ex ) {
|
165 |
+
return false;
|
166 |
+
}
|
167 |
|
168 |
return false;
|
169 |
}
|
FeatureShowcase_Plugin_Admin.php
CHANGED
@@ -25,6 +25,17 @@ class FeatureShowcase_Plugin_Admin {
|
|
25 |
*/
|
26 |
private $_page = 'w3tc_feature_showcase'; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
|
27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
/**
|
29 |
* Constructor.
|
30 |
*
|
@@ -35,17 +46,22 @@ class FeatureShowcase_Plugin_Admin {
|
|
35 |
* @see self::set_config()
|
36 |
*/
|
37 |
public function __construct() {
|
38 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
}
|
49 |
}
|
50 |
|
51 |
/**
|
@@ -72,8 +88,10 @@ class FeatureShowcase_Plugin_Admin {
|
|
72 |
|
73 |
require W3TC_DIR . '/FeatureShowcase_Plugin_Admin_View.php';
|
74 |
|
75 |
-
// Mark unseen new features as seen.
|
76 |
-
|
|
|
|
|
77 |
}
|
78 |
|
79 |
/**
|
@@ -82,12 +100,23 @@ class FeatureShowcase_Plugin_Admin {
|
|
82 |
* @since 2.1.0
|
83 |
*/
|
84 |
public function enqueue_styles() {
|
|
|
|
|
85 |
wp_enqueue_style(
|
86 |
-
'
|
87 |
-
esc_url( plugin_dir_url( __FILE__ ) . 'pub/css/feature-
|
88 |
array(),
|
89 |
W3TC_VERSION
|
90 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
}
|
92 |
|
93 |
/**
|
@@ -168,10 +197,52 @@ class FeatureShowcase_Plugin_Admin {
|
|
168 |
* @access private
|
169 |
* @static
|
170 |
*
|
|
|
|
|
171 |
* @return array
|
172 |
*/
|
173 |
private static function get_cards() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
return array(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
175 |
'setup_guide' => array(
|
176 |
'title' => esc_html__( 'Setup Guide Wizard', 'w3-total-cache' ),
|
177 |
'icon' => 'dashicons-superhero',
|
@@ -194,7 +265,7 @@ class FeatureShowcase_Plugin_Admin {
|
|
194 |
'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/lazy-load-google-maps/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=pro_lazyload_googlemaps' ) .
|
195 |
'">' . __( 'More info', 'w3-total-cache' ) . '<span class="dashicons dashicons-external"></span></a>',
|
196 |
'is_premium' => true,
|
197 |
-
'is_new' =>
|
198 |
),
|
199 |
'cdn_fsd' => array(
|
200 |
'title' => esc_html__( 'Full Site Delivery via CDN', 'w3-total-cache' ),
|
25 |
*/
|
26 |
private $_page = 'w3tc_feature_showcase'; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
|
27 |
|
28 |
+
/**
|
29 |
+
* Location of any wp_redirect.
|
30 |
+
*
|
31 |
+
* @since 2.2.0
|
32 |
+
* @access private
|
33 |
+
* @static
|
34 |
+
*
|
35 |
+
* @var string
|
36 |
+
*/
|
37 |
+
private static $wp_redirect_location;
|
38 |
+
|
39 |
/**
|
40 |
* Constructor.
|
41 |
*
|
46 |
* @see self::set_config()
|
47 |
*/
|
48 |
public function __construct() {
|
49 |
+
add_action(
|
50 |
+
'admin_enqueue_scripts',
|
51 |
+
array(
|
52 |
+
$this,
|
53 |
+
'enqueue_styles',
|
54 |
+
)
|
55 |
+
);
|
56 |
|
57 |
+
// Check if being redirected.
|
58 |
+
add_filter(
|
59 |
+
'wp_redirect',
|
60 |
+
function( $location ) {
|
61 |
+
FeatureShowcase_Plugin_Admin::$wp_redirect_location = $location;
|
62 |
+
return $location;
|
63 |
+
}
|
64 |
+
);
|
|
|
65 |
}
|
66 |
|
67 |
/**
|
88 |
|
89 |
require W3TC_DIR . '/FeatureShowcase_Plugin_Admin_View.php';
|
90 |
|
91 |
+
// Mark unseen new features as seen, if not redirecting to the Setup Guide wizard.
|
92 |
+
if ( ! self::$wp_redirect_location ) {
|
93 |
+
$this->mark_seen();
|
94 |
+
}
|
95 |
}
|
96 |
|
97 |
/**
|
100 |
* @since 2.1.0
|
101 |
*/
|
102 |
public function enqueue_styles() {
|
103 |
+
$page = Util_Request::get_string( 'page' );
|
104 |
+
|
105 |
wp_enqueue_style(
|
106 |
+
'w3tc_feature_counter',
|
107 |
+
esc_url( plugin_dir_url( __FILE__ ) . 'pub/css/feature-counter.css' ),
|
108 |
array(),
|
109 |
W3TC_VERSION
|
110 |
);
|
111 |
+
|
112 |
+
if ( 'w3tc_feature_showcase' === $page ) {
|
113 |
+
wp_enqueue_style(
|
114 |
+
'w3tc_feature_showcase',
|
115 |
+
esc_url( plugin_dir_url( __FILE__ ) . 'pub/css/feature-showcase.css' ),
|
116 |
+
array(),
|
117 |
+
W3TC_VERSION
|
118 |
+
);
|
119 |
+
}
|
120 |
}
|
121 |
|
122 |
/**
|
197 |
* @access private
|
198 |
* @static
|
199 |
*
|
200 |
+
* @global $wp_version WordPress core version.
|
201 |
+
*
|
202 |
* @return array
|
203 |
*/
|
204 |
private static function get_cards() {
|
205 |
+
$c = Dispatcher::config();
|
206 |
+
$extensions = $c->get_array( 'extensions.active' );
|
207 |
+
$is_imageservice_active = isset( $extensions['imageservice'] );
|
208 |
+
$imageservice_button_text = $is_imageservice_active ? __( 'Settings', 'w3-total-cache' ) : __( 'Activate', 'w3-total-cache' );
|
209 |
+
$imageservice_button_link = $is_imageservice_active ?
|
210 |
+
'upload.php?page=w3tc_extension_page_imageservice' : 'admin.php?page=w3tc_extensions&action=activate&extension=imageservice';
|
211 |
+
|
212 |
+
global $wp_version;
|
213 |
+
|
214 |
+
$imageservice_description = __(
|
215 |
+
'Adds the ability to convert images into the modern WebP format for better performance using our remote API service.',
|
216 |
+
'w3-total-cache'
|
217 |
+
);
|
218 |
+
|
219 |
+
if ( version_compare( $wp_version, '5.8', '<' ) ) {
|
220 |
+
$imageservice_description .= sprintf(
|
221 |
+
// translators: 1: HTML p open tag, 2: WordPress version string, 3: HTML anchor open tag, 4: HTML anchor close tag, 5: HTML p close tag.
|
222 |
+
__(
|
223 |
+
'%1$sThis feature works best in WordPress version 5.8 and higher. You are running WordPress version %2$s. Please %3$supdate now%4$s to benefit from this feature.%5$s',
|
224 |
+
'w3-total-cache'
|
225 |
+
),
|
226 |
+
'<p>',
|
227 |
+
$wp_version,
|
228 |
+
'<a href="' . esc_url( admin_url( 'update-core.php' ) ) . '">',
|
229 |
+
'</a>',
|
230 |
+
'</p>'
|
231 |
+
);
|
232 |
+
}
|
233 |
+
|
234 |
return array(
|
235 |
+
'imageservice' => array(
|
236 |
+
'title' => esc_html__( 'Image Service', 'w3-total-cache' ),
|
237 |
+
'icon' => 'dashicons-embed-photo',
|
238 |
+
'text' => esc_html( $imageservice_description ),
|
239 |
+
'button' => '<button class="button" onclick="window.location=\'' .
|
240 |
+
esc_url( Util_Ui::admin_url( $imageservice_button_link ) ) . '\'">' . esc_html( $imageservice_button_text ) . '</button>',
|
241 |
+
'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/image-service/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=imageservice' ) .
|
242 |
+
'">' . __( 'More info', 'w3-total-cache' ) . '<span class="dashicons dashicons-external"></span></a>',
|
243 |
+
'is_premium' => false,
|
244 |
+
'is_new' => true,
|
245 |
+
),
|
246 |
'setup_guide' => array(
|
247 |
'title' => esc_html__( 'Setup Guide Wizard', 'w3-total-cache' ),
|
248 |
'icon' => 'dashicons-superhero',
|
265 |
'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/lazy-load-google-maps/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=pro_lazyload_googlemaps' ) .
|
266 |
'">' . __( 'More info', 'w3-total-cache' ) . '<span class="dashicons dashicons-external"></span></a>',
|
267 |
'is_premium' => true,
|
268 |
+
'is_new' => false,
|
269 |
),
|
270 |
'cdn_fsd' => array(
|
271 |
'title' => esc_html__( 'Full Site Delivery via CDN', 'w3-total-cache' ),
|
Generic_Page_Dashboard_View.css
CHANGED
@@ -14,9 +14,6 @@
|
|
14 |
-webkit-box-shadow: none;
|
15 |
box-shadow: none;
|
16 |
}
|
17 |
-
#w3tc-dashboard-widgets h1 {
|
18 |
-
margin-top: 5px;
|
19 |
-
}
|
20 |
#w3tc-dashboard-widgets #postbox-container-left {
|
21 |
padding: 10px;
|
22 |
margin-right: 200px;
|
14 |
-webkit-box-shadow: none;
|
15 |
box-shadow: none;
|
16 |
}
|
|
|
|
|
|
|
17 |
#w3tc-dashboard-widgets #postbox-container-left {
|
18 |
padding: 10px;
|
19 |
margin-right: 200px;
|
Generic_Plugin_Admin.php
CHANGED
@@ -266,7 +266,7 @@ class Generic_Plugin_Admin {
|
|
266 |
|
267 |
// Define icon styles for the custom post type
|
268 |
function admin_head() {
|
269 |
-
$page =
|
270 |
|
271 |
if ( ( ! is_multisite() || is_super_admin() ) && false !== strpos( $page, 'w3tc' ) && 'w3tc_setup_guide' !== $page && ! get_site_option( 'w3tc_setupguide_completed' ) ) {
|
272 |
$config = new Config();
|
266 |
|
267 |
// Define icon styles for the custom post type
|
268 |
function admin_head() {
|
269 |
+
$page = Util_Request::get_string( 'page', null );
|
270 |
|
271 |
if ( ( ! is_multisite() || is_super_admin() ) && false !== strpos( $page, 'w3tc' ) && 'w3tc_setup_guide' !== $page && ! get_site_option( 'w3tc_setupguide_completed' ) ) {
|
272 |
$config = new Config();
|
Root_AdminActivation.php
CHANGED
@@ -100,5 +100,9 @@ class Root_AdminActivation {
|
|
100 |
Util_Activation::disable_maintenance_mode();
|
101 |
} catch ( \Exception $ex ) {
|
102 |
}
|
|
|
|
|
|
|
|
|
103 |
}
|
104 |
}
|
100 |
Util_Activation::disable_maintenance_mode();
|
101 |
} catch ( \Exception $ex ) {
|
102 |
}
|
103 |
+
|
104 |
+
// Delete cron events.
|
105 |
+
require_once __DIR__ . '/Extension_ImageService_Cron.php';
|
106 |
+
Extension_ImageService_Cron::delete_cron();
|
107 |
}
|
108 |
}
|
Root_Environment.php
CHANGED
@@ -172,7 +172,8 @@ class Root_Environment {
|
|
172 |
new BrowserCache_Environment(),
|
173 |
new ObjectCache_Environment(),
|
174 |
new DbCache_Environment(),
|
175 |
-
new Cdn_Environment()
|
|
|
176 |
);
|
177 |
|
178 |
return $a;
|
172 |
new BrowserCache_Environment(),
|
173 |
new ObjectCache_Environment(),
|
174 |
new DbCache_Environment(),
|
175 |
+
new Cdn_Environment(),
|
176 |
+
new Extension_ImageService_Environment(),
|
177 |
);
|
178 |
|
179 |
return $a;
|
Root_Loader.php
CHANGED
@@ -147,7 +147,6 @@ class Root_Loader {
|
|
147 |
}
|
148 |
|
149 |
if ( is_admin() ) {
|
150 |
-
$extensions = $c->get_array( 'extensions.active' );
|
151 |
foreach ( $extensions as $extension => $path ) {
|
152 |
$filename = W3TC_EXTENSION_DIR . '/' .
|
153 |
str_replace( '..', '', trim( $path, '/' ) );
|
@@ -163,6 +162,53 @@ class Root_Loader {
|
|
163 |
if ( is_admin() ) {
|
164 |
do_action( 'w3tc_extension_load_admin' );
|
165 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
166 |
}
|
167 |
}
|
168 |
|
147 |
}
|
148 |
|
149 |
if ( is_admin() ) {
|
|
|
150 |
foreach ( $extensions as $extension => $path ) {
|
151 |
$filename = W3TC_EXTENSION_DIR . '/' .
|
152 |
str_replace( '..', '', trim( $path, '/' ) );
|
162 |
if ( is_admin() ) {
|
163 |
do_action( 'w3tc_extension_load_admin' );
|
164 |
}
|
165 |
+
|
166 |
+
// Hide Image Service media.
|
167 |
+
add_action(
|
168 |
+
'pre_get_posts',
|
169 |
+
function( $query ) {
|
170 |
+
if ( ! is_admin() || ! $query->is_main_query() ) {
|
171 |
+
return;
|
172 |
+
}
|
173 |
+
|
174 |
+
$screen = get_current_screen();
|
175 |
+
|
176 |
+
if ( ! $screen || 'upload' !== $screen->id || 'attachment' !== $screen->post_type ) {
|
177 |
+
return;
|
178 |
+
}
|
179 |
+
|
180 |
+
$query->set(
|
181 |
+
'meta_query',
|
182 |
+
array(
|
183 |
+
array(
|
184 |
+
'key' => 'w3tc_imageservice_file',
|
185 |
+
'compare' => 'NOT EXISTS',
|
186 |
+
),
|
187 |
+
)
|
188 |
+
);
|
189 |
+
|
190 |
+
return;
|
191 |
+
}
|
192 |
+
);
|
193 |
+
|
194 |
+
add_filter(
|
195 |
+
'ajax_query_attachments_args',
|
196 |
+
function( $args ) {
|
197 |
+
if ( ! is_admin() ) {
|
198 |
+
return;
|
199 |
+
}
|
200 |
+
|
201 |
+
// Modify the query.
|
202 |
+
$args['meta_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
|
203 |
+
array(
|
204 |
+
'key' => 'w3tc_imageservice_file',
|
205 |
+
'compare' => 'NOT EXISTS',
|
206 |
+
),
|
207 |
+
);
|
208 |
+
|
209 |
+
return $args;
|
210 |
+
}
|
211 |
+
);
|
212 |
}
|
213 |
}
|
214 |
|
Util_Ui.php
CHANGED
@@ -648,7 +648,9 @@ class Util_Ui {
|
|
648 |
'disabled' => $a['disabled']
|
649 |
) );
|
650 |
} elseif ( 'none' === $a['control'] ) {
|
651 |
-
esc_html_e( $a['none_label'] );
|
|
|
|
|
652 |
}
|
653 |
}
|
654 |
|
648 |
'disabled' => $a['disabled']
|
649 |
) );
|
650 |
} elseif ( 'none' === $a['control'] ) {
|
651 |
+
esc_html_e( $a['none_label'], 'w3-total-cache' );
|
652 |
+
} elseif ( 'button' === $a['control'] ) {
|
653 |
+
echo '<button type="button" class="button">' . __( $a['none_label'], 'w3-total-cache' ) . '</button>';
|
654 |
}
|
655 |
}
|
656 |
|
inc/options/extensions/list.php
CHANGED
@@ -73,11 +73,21 @@ $cb_id++;
|
|
73 |
<strong><?php esc_html_e( $meta['name'] ) ?></strong>
|
74 |
<div class="row-actions-visible">
|
75 |
<?php if ( $config->is_extension_active( $extension ) ):
|
76 |
-
|
77 |
-
|
78 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
$extra_links = apply_filters( "w3tc_extension_plugin_links_{$extension}", $extra_links );
|
80 |
$links = implode( ' | ', $extra_links );
|
|
|
81 |
if ( $links ) {
|
82 |
echo $links;
|
83 |
}
|
73 |
<strong><?php esc_html_e( $meta['name'] ) ?></strong>
|
74 |
<div class="row-actions-visible">
|
75 |
<?php if ( $config->is_extension_active( $extension ) ):
|
76 |
+
$extra_links = array();
|
77 |
+
|
78 |
+
if ( isset( $meta['settings_exists'] ) && $meta['settings_exists'] ) {
|
79 |
+
$extra_links[] = '<a class="edit" href="' .
|
80 |
+
esc_attr( Util_Ui::admin_url( sprintf( 'admin.php?page=w3tc_extensions&extension=%s&action=view', $extension ) ) ) . '">' .
|
81 |
+
esc_html__( 'Settings', 'w3-total-cache' ) . '</a>';
|
82 |
+
}
|
83 |
+
|
84 |
+
if ( isset( $meta['extra_links'] ) && is_Array( $meta['extra_links'] ) ) {
|
85 |
+
$extra_links = array_merge( $extra_links, $meta['extra_links'] );
|
86 |
+
}
|
87 |
+
|
88 |
$extra_links = apply_filters( "w3tc_extension_plugin_links_{$extension}", $extra_links );
|
89 |
$links = implode( ' | ', $extra_links );
|
90 |
+
|
91 |
if ( $links ) {
|
92 |
echo $links;
|
93 |
}
|
pub/css/feature-counter.css
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#wp-admin-bar-w3tc > a .awaiting-mod,
|
2 |
+
#wp-admin-bar-w3tc_feature_showcase a .awaiting-mod {
|
3 |
+
background-color: #d63638;
|
4 |
+
border-radius: 9px;
|
5 |
+
color: #fff;
|
6 |
+
font-size: 11px;
|
7 |
+
height: 18px;
|
8 |
+
min-width: 18px;
|
9 |
+
padding: 0 5px;
|
10 |
+
}
|
pub/js/feature-counter.js
CHANGED
@@ -9,7 +9,8 @@
|
|
9 |
*/
|
10 |
|
11 |
jQuery(function() {
|
12 |
-
var $
|
|
|
13 |
$menuItem = jQuery( '#toplevel_page_w3tc_dashboard.wp-not-current-submenu a[href="admin.php?page=w3tc_dashboard"] .wp-menu-name' ),
|
14 |
$submenuItem = jQuery( '#toplevel_page_w3tc_dashboard a[href="admin.php?page=w3tc_feature_showcase"]' ),
|
15 |
markup = ' <span class="awaiting-mod count-' +
|
@@ -20,19 +21,8 @@ jQuery(function() {
|
|
20 |
|
21 |
if ( W3TCFeatureShowcaseData.unseenCount > 0 ) {
|
22 |
if ( $adminmenuItem.length ) {
|
|
|
23 |
$adminmenuItem.append( markup );
|
24 |
-
|
25 |
-
$adminmenuItem.find( '.awaiting-mod' ).css(
|
26 |
-
{
|
27 |
-
padding: "0 5px",
|
28 |
-
"min-width": "18px",
|
29 |
-
height: "18px",
|
30 |
-
"border-radius": "9px",
|
31 |
-
"background-color": "#ca4a1f",
|
32 |
-
color: "#fff",
|
33 |
-
"font-size": "11px"
|
34 |
-
}
|
35 |
-
);
|
36 |
}
|
37 |
|
38 |
if ( $menuItem.length ) {
|
9 |
*/
|
10 |
|
11 |
jQuery(function() {
|
12 |
+
var $adminmenuTopItem = jQuery( '#wp-admin-bar-w3tc > a' ),
|
13 |
+
$adminmenuItem = jQuery ( '#wp-admin-bar-w3tc_feature_showcase a' ),
|
14 |
$menuItem = jQuery( '#toplevel_page_w3tc_dashboard.wp-not-current-submenu a[href="admin.php?page=w3tc_dashboard"] .wp-menu-name' ),
|
15 |
$submenuItem = jQuery( '#toplevel_page_w3tc_dashboard a[href="admin.php?page=w3tc_feature_showcase"]' ),
|
16 |
markup = ' <span class="awaiting-mod count-' +
|
21 |
|
22 |
if ( W3TCFeatureShowcaseData.unseenCount > 0 ) {
|
23 |
if ( $adminmenuItem.length ) {
|
24 |
+
$adminmenuTopItem.append( markup );
|
25 |
$adminmenuItem.append( markup );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
}
|
27 |
|
28 |
if ( $menuItem.length ) {
|
readme.txt
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
=== Plugin Name ===
|
2 |
Contributors: boldgrid, fredericktownes, maxicusc, gidomanders, bwmarkle, harryjackson1221, joemoto, vmarko, jacobd91
|
3 |
-
Tags: seo, cache,
|
4 |
Requires at least: 3.8
|
5 |
Tested up to: 5.8
|
6 |
-
Stable tag: 2.
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
@@ -11,9 +11,9 @@ Search Engine (SEO) & Performance Optimization (WPO) via caching. Integrated
|
|
11 |
|
12 |
== Description ==
|
13 |
|
14 |
-
W3 Total Cache (W3TC) improves the SEO and user experience of your site by increasing website performance and reducing load times by leveraging features like content delivery network (CDN) integration and the latest best practices.
|
15 |
|
16 |
-
W3TC is the **only** web host agnostic Web Performance Optimization (WPO) framework for WordPress trusted by millions of publishers, web developers, and web hosts worldwide for more than a decade. It is the total performance solution for optimizing
|
17 |
|
18 |
An inside look:
|
19 |
|
@@ -36,7 +36,7 @@ https://youtu.be/7AsNSSrZq4Y
|
|
36 |
* Transparent content delivery network (CDN) management with Media Library, theme files and WordPress itself
|
37 |
* Mobile support: respective caching of pages by referrer or groups of user agents including theme switching for groups of referrers or user agents
|
38 |
* Accelerated Mobile Pages (AMP) support
|
39 |
-
* Secure Socket Layer (SSL) support
|
40 |
* Caching of (minified and compressed) pages and posts in memory or on disk or on (FSD) CDN (by user agent group)
|
41 |
* Caching of (minified and compressed) CSS and JavaScript in memory, on disk or on CDN
|
42 |
* Caching of feeds (site, categories, tags, comments, search results) in memory or on disk or on CDN
|
@@ -61,8 +61,9 @@ https://youtu.be/7AsNSSrZq4Y
|
|
61 |
* Caching statistics for performance insights of any enabled feature
|
62 |
* Extension framework for customization or extensibility for Cloudflare, WPML and much more
|
63 |
* Reverse proxy integration via Nginx or Varnish
|
|
|
64 |
|
65 |
-
Speed up your site tremendously, and
|
66 |
|
67 |
== Frequently Asked Questions ==
|
68 |
|
@@ -76,7 +77,7 @@ Speed is among the most significant success factors web sites face. In fact, you
|
|
76 |
* Yahoo.com: **+400 ms** (speed decrease) -> **-5-9% full-page traffic loss** (visitor left before the page finished loading) [[2](http://www.slideshare.net/stoyan/yslow-20-presentation)]
|
77 |
* Amazon.com: **+100 ms** (speed decrease) -> **-1% sales loss** [[1](http://home.blarg.net/~glinden/StanfordDataMining.2006-11-29.ppt)]
|
78 |
|
79 |
-
A thousandth of a second is not a long time, yet the impact is quite significant. Even if you're not a large company (or just hope to become one), a loss is still a loss.
|
80 |
|
81 |
Many of the other consequences of poor performance were discovered more than a decade ago:
|
82 |
|
@@ -94,7 +95,7 @@ There are a number of [resources](http://www.websiteoptimization.com/speed/tweak
|
|
94 |
|
95 |
= Why is W3 Total Cache better than other caching solutions? =
|
96 |
|
97 |
-
**It's a complete framework.** Most cache plugins available do a great job at achieving a couple of performance
|
98 |
|
99 |
= I've never heard of any of this stuff; my site is fine, no one complains about the speed. Why should I install this? =
|
100 |
|
@@ -156,7 +157,7 @@ Use the "Help" button available on the Minify settings tab. Once open, the tool
|
|
156 |
|
157 |
= I don't understand what a CDN has to do with caching, that's completely different, no? =
|
158 |
|
159 |
-
Technically no, a CDN is a high performance cache that stores static assets (your theme files, media library etc) in various locations throughout the world in order to provide low latency access to them by readers in those regions.
|
160 |
|
161 |
= How do I use an Origin Pull (Mirror) CDN? =
|
162 |
Login to your CDN providers control panel or account management area. Following any set up steps they provide, create a new "pull zone" or "bucket" for your site's domain name. If there's a set up wizard or any troubleshooting tips your provider offers, be sure to review them. In the CDN tab of the plugin, enter the hostname your CDN provider provided in the "replace site's hostname with" field. You should always do a quick check by opening a test file from the CDN hostname, e.g. http://cdn.domain.com/favicon.ico. Troubleshoot with your CDN provider until this test is successful.
|
@@ -215,20 +216,29 @@ First, make sure the plugin is not active (disabled) network-wide. Then make sur
|
|
215 |
|
216 |
= A notification about file owner appears along with an FTP form, how can I resolve this? =
|
217 |
|
218 |
-
The plugin uses WordPress FileSystem functionality to write to files. It checks if the file owner, file owner group of created files match process owner. If this is not the case it cannot write or modify files.
|
219 |
|
220 |
Typically, you should tell your web host about the permission issue and they should be able to resolve it.
|
221 |
|
222 |
You can however try adding <em>define('FS_METHOD', 'direct');</em> to wp-config.php to circumvent the file and folder checks.
|
223 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
224 |
= This is too good to be true, how can I test the results? =
|
225 |
|
226 |
-
You will be able to see
|
227 |
|
228 |
* [Google Page Speed](https://developers.google.com/speed/pagespeed/)
|
|
|
229 |
* [WebPagetest](https://www.webpagetest.org/test)
|
230 |
* [Pingdom](https://tools.pingdom.com/)
|
231 |
-
* [
|
232 |
|
233 |
= I don't have time to deal with this, but I know I need it. Will you help me? =
|
234 |
|
@@ -275,6 +285,9 @@ Please reach out to all of these people and support their projects if you're so
|
|
275 |
|
276 |
== Changelog ==
|
277 |
|
|
|
|
|
|
|
278 |
= 2.1.9 =
|
279 |
* Fix: Cloudflare Dashboard Widget: Updated to use GraphQL
|
280 |
* Fix: Cloudflare Dashboard Widget: Use WordPress timezone
|
1 |
=== Plugin Name ===
|
2 |
Contributors: boldgrid, fredericktownes, maxicusc, gidomanders, bwmarkle, harryjackson1221, joemoto, vmarko, jacobd91
|
3 |
+
Tags: seo, cache, CDN, pagespeed, caching, performance, compression, optimize, cloudflare, nginx, apache, varnish, redis, aws, amazon web services, s3, cloudfront, azure
|
4 |
Requires at least: 3.8
|
5 |
Tested up to: 5.8
|
6 |
+
Stable tag: 2.2.0
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
11 |
|
12 |
== Description ==
|
13 |
|
14 |
+
W3 Total Cache (W3TC) improves the SEO, Core Web Vitals and overall user experience of your site by increasing website performance and reducing load times by leveraging features like content delivery network (CDN) integration and the latest best practices.
|
15 |
|
16 |
+
W3TC is the **only** web host agnostic Web Performance Optimization (WPO) framework for WordPress trusted by millions of publishers, web developers, and web hosts worldwide for more than a decade. It is the total performance solution for optimizing WordPress Websites.
|
17 |
|
18 |
An inside look:
|
19 |
|
36 |
* Transparent content delivery network (CDN) management with Media Library, theme files and WordPress itself
|
37 |
* Mobile support: respective caching of pages by referrer or groups of user agents including theme switching for groups of referrers or user agents
|
38 |
* Accelerated Mobile Pages (AMP) support
|
39 |
+
* Secure Socket Layer (SSL/TLS) support
|
40 |
* Caching of (minified and compressed) pages and posts in memory or on disk or on (FSD) CDN (by user agent group)
|
41 |
* Caching of (minified and compressed) CSS and JavaScript in memory, on disk or on CDN
|
42 |
* Caching of feeds (site, categories, tags, comments, search results) in memory or on disk or on CDN
|
61 |
* Caching statistics for performance insights of any enabled feature
|
62 |
* Extension framework for customization or extensibility for Cloudflare, WPML and much more
|
63 |
* Reverse proxy integration via Nginx or Varnish
|
64 |
+
* Image Service API extension provides WebP image format conversion from common image formats (on upload and on demand)
|
65 |
|
66 |
+
Speed up your site tremendously, improve core web vitals and the overall user experience for your visitors without having to change your WordPress host, theme, plugins or your content production workflow.
|
67 |
|
68 |
== Frequently Asked Questions ==
|
69 |
|
77 |
* Yahoo.com: **+400 ms** (speed decrease) -> **-5-9% full-page traffic loss** (visitor left before the page finished loading) [[2](http://www.slideshare.net/stoyan/yslow-20-presentation)]
|
78 |
* Amazon.com: **+100 ms** (speed decrease) -> **-1% sales loss** [[1](http://home.blarg.net/~glinden/StanfordDataMining.2006-11-29.ppt)]
|
79 |
|
80 |
+
A thousandth of a second is not a long time, yet the impact is quite significant. Even if you're not a large company (or just hope to become one), a loss is still a loss. W3 Total Cache is your solution for faster websites, happier visitors and better results.
|
81 |
|
82 |
Many of the other consequences of poor performance were discovered more than a decade ago:
|
83 |
|
95 |
|
96 |
= Why is W3 Total Cache better than other caching solutions? =
|
97 |
|
98 |
+
**It's a complete framework.** Most cache plugins available do a great job at achieving a couple of performance gains. Total Cache is different because it remedies numerous performance reducing aspects of any web site. It goes farther than the basics, beyond merely reducing CPU usage (load) or bandwidth consumption for HTML pages. Equally important, the plugin requires no theme modifications, modifications to your .htaccess (mod_rewrite rules) or programming compromises to get started. Most importantly, it's the only plugin designed to optimize all practical hosting environments small or large. The options are many and setup is easy.
|
99 |
|
100 |
= I've never heard of any of this stuff; my site is fine, no one complains about the speed. Why should I install this? =
|
101 |
|
157 |
|
158 |
= I don't understand what a CDN has to do with caching, that's completely different, no? =
|
159 |
|
160 |
+
Technically no, a CDN is a high performance cache that stores static assets (your theme files, media library etc) in various locations throughout the world in order to provide low latency access to them by readers in those regions. Use Total Cache to accelerate your site by putting your content closer to your users with our many CDN integrations including Cloudflare, StackPath, AWS and more.
|
161 |
|
162 |
= How do I use an Origin Pull (Mirror) CDN? =
|
163 |
Login to your CDN providers control panel or account management area. Following any set up steps they provide, create a new "pull zone" or "bucket" for your site's domain name. If there's a set up wizard or any troubleshooting tips your provider offers, be sure to review them. In the CDN tab of the plugin, enter the hostname your CDN provider provided in the "replace site's hostname with" field. You should always do a quick check by opening a test file from the CDN hostname, e.g. http://cdn.domain.com/favicon.ico. Troubleshoot with your CDN provider until this test is successful.
|
216 |
|
217 |
= A notification about file owner appears along with an FTP form, how can I resolve this? =
|
218 |
|
219 |
+
The plugin uses WordPress FileSystem functionality to write to files. It checks if the file owner, file owner group of created files match process owner. If this is not the case it cannot write or modify files.
|
220 |
|
221 |
Typically, you should tell your web host about the permission issue and they should be able to resolve it.
|
222 |
|
223 |
You can however try adding <em>define('FS_METHOD', 'direct');</em> to wp-config.php to circumvent the file and folder checks.
|
224 |
|
225 |
+
= Does the Image Service extension use a lot of resources to convert images to WebP? =
|
226 |
+
|
227 |
+
No. The Image Service extension converts common image file formats to the modern WebP format using our API services. The conversions occur on our API service, so that resource usage does not impact your website server.
|
228 |
+
|
229 |
+
= Is image data retained by the Total Cache Image Service API? =
|
230 |
+
|
231 |
+
Image data received by our API is destroyed after a converted image is generated. The converted iamges are destroyed once picked-up/downloaded to your website by the Total Cache plugin.
|
232 |
+
|
233 |
= This is too good to be true, how can I test the results? =
|
234 |
|
235 |
+
You will be able to see the results instantly on each page load, but for tangible metrics, you should consider using the following tools:
|
236 |
|
237 |
* [Google Page Speed](https://developers.google.com/speed/pagespeed/)
|
238 |
+
* [Google Search Console Core Web Vitals Report](https://search.google.com/search-console/core-web-vitals/)
|
239 |
* [WebPagetest](https://www.webpagetest.org/test)
|
240 |
* [Pingdom](https://tools.pingdom.com/)
|
241 |
+
* [GTmetrix](https://gtmetrix.com/)
|
242 |
|
243 |
= I don't have time to deal with this, but I know I need it. Will you help me? =
|
244 |
|
285 |
|
286 |
== Changelog ==
|
287 |
|
288 |
+
= 2.2.0 =
|
289 |
+
* Feature: Image Service API extension: WebP conversion options
|
290 |
+
|
291 |
= 2.1.9 =
|
292 |
* Fix: Cloudflare Dashboard Widget: Updated to use GraphQL
|
293 |
* Fix: Cloudflare Dashboard Widget: Use WordPress timezone
|
w3-total-cache-api.php
CHANGED
@@ -5,7 +5,7 @@ if ( !defined( 'ABSPATH' ) ) {
|
|
5 |
}
|
6 |
|
7 |
define( 'W3TC', true );
|
8 |
-
define( 'W3TC_VERSION', '2.
|
9 |
define( 'W3TC_POWERED_BY', 'W3 Total Cache' );
|
10 |
define( 'W3TC_EMAIL', 'w3tc@w3-edge.com' );
|
11 |
define( 'W3TC_TEXT_DOMAIN', 'w3-total-cache' );
|
@@ -104,7 +104,7 @@ define( 'W3TC_MARKER_BEGIN_MINIFY_CORE', '# BEGIN W3TC Minify core' );
|
|
104 |
define( 'W3TC_MARKER_BEGIN_MINIFY_CACHE', '# BEGIN W3TC Minify cache' );
|
105 |
define( 'W3TC_MARKER_BEGIN_MINIFY_LEGACY', '# BEGIN W3TC Minify' );
|
106 |
define( 'W3TC_MARKER_BEGIN_CDN', '# BEGIN W3TC CDN' );
|
107 |
-
|
108 |
|
109 |
define( 'W3TC_MARKER_END_WORDPRESS', '# END WordPress' );
|
110 |
define( 'W3TC_MARKER_END_PGCACHE_CORE', '# END W3TC Page Cache core' );
|
@@ -118,7 +118,7 @@ define( 'W3TC_MARKER_END_MINIFY_CACHE', '# END W3TC Minify cache' );
|
|
118 |
define( 'W3TC_MARKER_END_MINIFY_LEGACY', '# END W3TC Minify' );
|
119 |
define( 'W3TC_MARKER_END_CDN', '# END W3TC CDN' );
|
120 |
define( 'W3TC_MARKER_END_NEW_RELIC_CORE', '# END W3TC New Relic core' );
|
121 |
-
|
122 |
|
123 |
if ( !defined( 'W3TC_EXTENSION_DIR' ) ) {
|
124 |
define( 'W3TC_EXTENSION_DIR', ( defined( 'WP_PLUGIN_DIR' ) ? WP_PLUGIN_DIR : WP_CONTENT_DIR . '/plugins' ) );
|
@@ -131,7 +131,6 @@ if ( !defined( 'W3TC_FEED_REGEXP' ) ) {
|
|
131 |
define( 'W3TC_FEED_REGEXP', '~/feed(/|$)~' );
|
132 |
}
|
133 |
|
134 |
-
|
135 |
@ini_set( 'pcre.backtrack_limit', 4194304 );
|
136 |
@ini_set( 'pcre.recursion_limit', 4194304 );
|
137 |
|
@@ -567,8 +566,8 @@ class W3_ConfigWriter {
|
|
567 |
}
|
568 |
|
569 |
/**
|
570 |
-
Deprecated. Retained for 3rd parties that use it. see w3tc_config()
|
571 |
-
*/
|
572 |
function w3_instance( $class ) {
|
573 |
$legacy_class_name = null;
|
574 |
|
5 |
}
|
6 |
|
7 |
define( 'W3TC', true );
|
8 |
+
define( 'W3TC_VERSION', '2.2.0' );
|
9 |
define( 'W3TC_POWERED_BY', 'W3 Total Cache' );
|
10 |
define( 'W3TC_EMAIL', 'w3tc@w3-edge.com' );
|
11 |
define( 'W3TC_TEXT_DOMAIN', 'w3-total-cache' );
|
104 |
define( 'W3TC_MARKER_BEGIN_MINIFY_CACHE', '# BEGIN W3TC Minify cache' );
|
105 |
define( 'W3TC_MARKER_BEGIN_MINIFY_LEGACY', '# BEGIN W3TC Minify' );
|
106 |
define( 'W3TC_MARKER_BEGIN_CDN', '# BEGIN W3TC CDN' );
|
107 |
+
define( 'W3TC_MARKER_BEGIN_WEBP', '# BEGIN W3TC WEBP' );
|
108 |
|
109 |
define( 'W3TC_MARKER_END_WORDPRESS', '# END WordPress' );
|
110 |
define( 'W3TC_MARKER_END_PGCACHE_CORE', '# END W3TC Page Cache core' );
|
118 |
define( 'W3TC_MARKER_END_MINIFY_LEGACY', '# END W3TC Minify' );
|
119 |
define( 'W3TC_MARKER_END_CDN', '# END W3TC CDN' );
|
120 |
define( 'W3TC_MARKER_END_NEW_RELIC_CORE', '# END W3TC New Relic core' );
|
121 |
+
define( 'W3TC_MARKER_END_WEBP', '# END W3TC WEBP' );
|
122 |
|
123 |
if ( !defined( 'W3TC_EXTENSION_DIR' ) ) {
|
124 |
define( 'W3TC_EXTENSION_DIR', ( defined( 'WP_PLUGIN_DIR' ) ? WP_PLUGIN_DIR : WP_CONTENT_DIR . '/plugins' ) );
|
131 |
define( 'W3TC_FEED_REGEXP', '~/feed(/|$)~' );
|
132 |
}
|
133 |
|
|
|
134 |
@ini_set( 'pcre.backtrack_limit', 4194304 );
|
135 |
@ini_set( 'pcre.recursion_limit', 4194304 );
|
136 |
|
566 |
}
|
567 |
|
568 |
/**
|
569 |
+
* Deprecated. Retained for 3rd parties that use it. see w3tc_config().
|
570 |
+
*/
|
571 |
function w3_instance( $class ) {
|
572 |
$legacy_class_name = null;
|
573 |
|
w3-total-cache.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
* Plugin Name: W3 Total Cache
|
4 |
* Plugin URI: https://www.boldgrid.com/totalcache/
|
5 |
* Description: The highest rated and most complete WordPress performance plugin. Dramatically improve the speed and user experience of your site. Add browser, page, object and database caching as well as minify and content delivery network (CDN) to WordPress.
|
6 |
-
* Version: 2.
|
7 |
* Requires at least: 3.8
|
8 |
* Requires PHP: 5.6
|
9 |
* Author: BoldGrid
|
3 |
* Plugin Name: W3 Total Cache
|
4 |
* Plugin URI: https://www.boldgrid.com/totalcache/
|
5 |
* Description: The highest rated and most complete WordPress performance plugin. Dramatically improve the speed and user experience of your site. Add browser, page, object and database caching as well as minify and content delivery network (CDN) to WordPress.
|
6 |
+
* Version: 2.2.0
|
7 |
* Requires at least: 3.8
|
8 |
* Requires PHP: 5.6
|
9 |
* Author: BoldGrid
|