PluginProbe
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization / 2.5.5
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization v2.5.5
4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 2.5.5 2.5.6 2.5.7 3.0.0 3.0.1 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.11.0 3.11.1 3.11.2 3.11.3 3.12.0 3.12.1 All 134 releases
optimole-wp / inc / admin.php

admin.php in Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization 2.5.5, at inc/admin.php

860 lines 43.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Admin class.
4 *
5 * Author: Andrei Baicus <andrei@themeisle.com>
6 * Created on: 19/07/2018
7 *
8 * @soundtrack Somewhere Else - Marillion
9 * @package \Optimole\Inc
10 * @author Optimole <friends@optimole.com>
11 */
12
13 /**
14 * Class Optml_Admin
15 */
16 class Optml_Admin {
17
18 /**
19 * Hold the settings object.
20 *
21 * @var Optml_Settings Settings object.
22 */
23 public $settings;
24
25 /**
26 * Optml_Admin constructor.
27 */
28 public function __construct() {
29 $this->settings = new Optml_Settings();
30 add_action( 'plugin_action_links_' . plugin_basename( OPTML_BASEFILE ), array( $this, 'add_action_links' ) );
31 add_action( 'admin_menu', array( $this, 'add_dashboard_page' ) );
32 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ), PHP_INT_MIN );
33 add_action( 'admin_notices', array( $this, 'add_notice' ) );
34 add_action( 'admin_notices', array( $this, 'add_notice_upgrade' ) );
35 add_filter( 'admin_body_class', array( $this, 'add_body_class' ) );
36 add_action( 'optml_daily_sync', array( $this, 'daily_sync' ) );
37 add_action( 'admin_init', array( $this, 'maybe_redirect' ) );
38 if ( ! is_admin() && $this->settings->is_connected() && ! wp_next_scheduled( 'optml_daily_sync' ) ) {
39 wp_schedule_event( time() + 10, 'daily', 'optml_daily_sync', array() );
40 }
41 add_action( 'optml_after_setup', array( $this, 'register_public_actions' ), 999999 );
42
43 }
44
45 /**
46 * Adds Optimole tag to admin bar
47 */
48 public function add_report_menu() {
49 global $wp_admin_bar;
50
51 $wp_admin_bar->add_node(
52 array(
53 'id' => 'optml_report_script',
54 'href' => '#',
55 'title' => '<span class="ab-icon"></span>Optimole ' . __( 'debugger', 'optimole-wp' ),
56 )
57 );
58 $wp_admin_bar->add_menu(
59 array(
60 'id' => 'optml_status',
61 'title' => __( 'Troubleshoot this page', 'optimole-wp' ),
62 'parent' => 'optml_report_script',
63 )
64 );
65 }
66
67 /**
68 * Adds Optimole css to admin bar
69 */
70 public function print_report_css() {
71 ?>
72 <style type="text/css">
73 li#wp-admin-bar-optml_report_script > div :hover {
74 cursor: pointer;
75 color: #00b9eb !important;
76 text-decoration: underline;
77 }
78
79 #wpadminbar #wp-admin-bar-optml_report_script .ab-icon:before {
80 content: "\f227";
81 top: 3px;
82 }
83
84 /* The Modal (background) */
85 .optml-modal {
86 display: none; /* Hidden by default */
87 position: fixed; /* Stay in place */
88 z-index: 2147483641; /* Sit on top */
89 padding-top: 100px; /* Location of the box */
90 left: 0;
91 top: 0;
92 width: 100%; /* Full width */
93 height: 100%; /* Full height */
94 overflow: auto; /* Enable scroll if needed */
95 background-color: rgb(0, 0, 0); /* Fallback color */
96 background-color: rgba(0, 0, 0, 0.4); /* Black w/ opacity */
97 }
98
99 /* Modal Content */
100 .optml-modal-content {
101 background-color: #fefefe;
102 margin: auto;
103 padding: 20px;
104 border: 1px solid #888;
105 width: 80%;
106 }
107
108 /* The Close Button */
109 .optml-close {
110 color: #aaaaaa;
111 float: right;
112 font-size: 28px;
113 font-weight: bold;
114 }
115
116 .optml-modal-content ul {
117 list-style: none;
118 font-size: 80%;
119 margin-top: 50px;
120 }
121
122 .optml-close:hover,
123 .optml-close:focus {
124 color: #000;
125 text-decoration: none;
126 cursor: pointer;
127 }
128 </style>
129 <?php
130 }
131
132 /**
133 * Register public actions.
134 */
135 public function register_public_actions() {
136 add_action( 'wp_head', array( $this, 'generator' ) );
137 add_filter( 'wp_resource_hints', array( $this, 'add_dns_prefetch' ), 10, 2 );
138
139 if ( Optml_Manager::should_ignore_image_tags() ) {
140 return;
141 }
142 if ( ! is_admin() && $this->settings->get( 'report_script' ) === 'enabled' && current_user_can( 'manage_options' ) ) {
143
144 add_action( 'wp_head', array( $this, 'print_report_css' ) );
145 add_action( 'wp_before_admin_bar_render', array( $this, 'add_report_menu' ) );
146 add_action( 'wp_enqueue_scripts', array( $this, 'add_diagnosis_script' ) );
147 }
148 if ( ! $this->settings->use_lazyload() ) {
149 return;
150 }
151 add_action( 'wp_enqueue_scripts', array( $this, 'frontend_scripts' ) );
152 add_action( 'wp_head', array( $this, 'inline_bootstrap_script' ) );
153
154 }
155
156 /**
157 * Adds script for lazyload/js replacement.
158 */
159 public function inline_bootstrap_script() {
160
161 $domain = 'https://' . OPTML_JS_CDN;
162
163 $min = ! OPTML_DEBUG ? '.min' : '';
164 $bgclasses = Optml_Lazyload_Replacer::get_lazyload_bg_classes();
165 $watcher_classes = Optml_Lazyload_Replacer::get_watcher_lz_classes();
166 $lazyload_bg_selectors = Optml_Lazyload_Replacer::get_background_lazyload_selectors();
167 foreach ( $bgclasses as $key ) {
168 $lazyload_bg_selectors[] = '.' . $key;
169 }
170 $lazyload_bg_selectors = empty( $lazyload_bg_selectors ) ? '' : sprintf( '%s', implode( ', ', (array) $lazyload_bg_selectors ) );
171 $bgclasses = empty( $bgclasses ) ? '' : sprintf( '"%s"', implode( '","', (array) $bgclasses ) );
172 $watcher_classes = empty( $watcher_classes ) ? '' : sprintf( '"%s"', implode( '","', (array) $watcher_classes ) );
173 $default_network = ( $this->settings->get( 'network_optimization' ) === 'enabled' );
174 $retina_ready = ! ( $this->settings->get( 'retina_images' ) === 'enabled' );
175 $scale_is_disabled = ( $this->settings->get( 'scale' ) === 'enabled' );
176 $native_lazy_enabled = ( $this->settings->get( 'native_lazyload' ) === 'enabled' );
177 $output = sprintf(
178 '
179 <style type="text/css">
180 img[data-opt-src]:not([data-opt-lazy-loaded]) {
181 transition: .2s filter linear, .2s opacity linear, .2s border-radius linear;
182 -webkit-transition: .2s filter linear, .2s opacity linear, .2s border-radius linear;
183 -moz-transition: .2s filter linear, .2s opacity linear, .2s border-radius linear;
184 -o-transition: .2s filter linear, .2s opacity linear, .2s border-radius linear;
185 }
186 img[data-opt-src]:not([data-opt-lazy-loaded]) {
187 opacity: .75;
188 -webkit-filter: blur(8px);
189 -moz-filter: blur(8px);
190 -o-filter: blur(8px);
191 -ms-filter: blur(8px);
192 filter: blur(8px);
193 transform: scale(1.04);
194 animation: 0.1s ease-in;
195 -webkit-transform: translate3d(0, 0, 0);
196 }
197 iframe[data-opt-src]:not([data-opt-lazy-loaded]) {
198 background-color: #ffffff;
199 background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHdpZHRoPSI0MHB4IiBoZWlnaHQ9IjQwcHgiIHZpZXdCb3g9IjAgMCA0MCA0MCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWw6c3BhY2U9InByZXNlcnZlIiBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjEuNDE0MjE7IiB4PSIwcHgiIHk9IjBweCI+CiAgICA8ZGVmcz4KICAgICAgICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPjwhW0NEQVRBWwogICAgICAgICAgICBALXdlYmtpdC1rZXlmcmFtZXMgc3BpbiB7CiAgICAgICAgICAgICAgZnJvbSB7CiAgICAgICAgICAgICAgICAtd2Via2l0LXRyYW5zZm9ybTogcm90YXRlKDBkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRvIHsKICAgICAgICAgICAgICAgIC13ZWJraXQtdHJhbnNmb3JtOiByb3RhdGUoLTM1OWRlZykKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgQGtleWZyYW1lcyBzcGluIHsKICAgICAgICAgICAgICBmcm9tIHsKICAgICAgICAgICAgICAgIHRyYW5zZm9ybTogcm90YXRlKDBkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRvIHsKICAgICAgICAgICAgICAgIHRyYW5zZm9ybTogcm90YXRlKC0zNTlkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHN2ZyB7CiAgICAgICAgICAgICAgICAtd2Via2l0LXRyYW5zZm9ybS1vcmlnaW46IDUwJSA1MCU7CiAgICAgICAgICAgICAgICAtd2Via2l0LWFuaW1hdGlvbjogc3BpbiAxLjVzIGxpbmVhciBpbmZpbml0ZTsKICAgICAgICAgICAgICAgIC13ZWJraXQtYmFja2ZhY2UtdmlzaWJpbGl0eTogaGlkZGVuOwogICAgICAgICAgICAgICAgYW5pbWF0aW9uOiBzcGluIDEuNXMgbGluZWFyIGluZmluaXRlOwogICAgICAgICAgICB9CiAgICAgICAgXV0+PC9zdHlsZT4KICAgIDwvZGVmcz4KICAgIDxnIGlkPSJvdXRlciI+CiAgICAgICAgPGc+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMCwwQzIyLjIwNTgsMCAyMy45OTM5LDEuNzg4MTMgMjMuOTkzOSwzLjk5MzlDMjMuOTkzOSw2LjE5OTY4IDIyLjIwNTgsNy45ODc4MSAyMCw3Ljk4NzgxQzE3Ljc5NDIsNy45ODc4MSAxNi4wMDYxLDYuMTk5NjggMTYuMDA2MSwzLjk5MzlDMTYuMDA2MSwxLjc4ODEzIDE3Ljc5NDIsMCAyMCwwWiIgc3R5bGU9ImZpbGw6YmxhY2s7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNNS44NTc4Niw1Ljg1Nzg2QzcuNDE3NTgsNC4yOTgxNSA5Ljk0NjM4LDQuMjk4MTUgMTEuNTA2MSw1Ljg1Nzg2QzEzLjA2NTgsNy40MTc1OCAxMy4wNjU4LDkuOTQ2MzggMTEuNTA2MSwxMS41MDYxQzkuOTQ2MzgsMTMuMDY1OCA3LjQxNzU4LDEzLjA2NTggNS44NTc4NiwxMS41MDYxQzQuMjk4MTUsOS45NDYzOCA0LjI5ODE1LDcuNDE3NTggNS44NTc4Niw1Ljg1Nzg2WiIgc3R5bGU9ImZpbGw6cmdiKDIxMCwyMTAsMjEwKTsiLz4KICAgICAgICA8L2c+CiAgICAgICAgPGc+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMCwzMi4wMTIyQzIyLjIwNTgsMzIuMDEyMiAyMy45OTM5LDMzLjgwMDMgMjMuOTkzOSwzNi4wMDYxQzIzLjk5MzksMzguMjExOSAyMi4yMDU4LDQwIDIwLDQwQzE3Ljc5NDIsNDAgMTYuMDA2MSwzOC4yMTE5IDE2LjAwNjEsMzYuMDA2MUMxNi4wMDYxLDMzLjgwMDMgMTcuNzk0MiwzMi4wMTIyIDIwLDMyLjAxMjJaIiBzdHlsZT0iZmlsbDpyZ2IoMTMwLDEzMCwxMzApOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTI4LjQ5MzksMjguNDkzOUMzMC4wNTM2LDI2LjkzNDIgMzIuNTgyNCwyNi45MzQyIDM0LjE0MjEsMjguNDkzOUMzNS43MDE5LDMwLjA1MzYgMzUuNzAxOSwzMi41ODI0IDM0LjE0MjEsMzQuMTQyMUMzMi41ODI0LDM1LjcwMTkgMzAuMDUzNiwzNS43MDE5IDI4LjQ5MzksMzQuMTQyMUMyNi45MzQyLDMyLjU4MjQgMjYuOTM0MiwzMC4wNTM2IDI4LjQ5MzksMjguNDkzOVoiIHN0eWxlPSJmaWxsOnJnYigxMDEsMTAxLDEwMSk7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNMy45OTM5LDE2LjAwNjFDNi4xOTk2OCwxNi4wMDYxIDcuOTg3ODEsMTcuNzk0MiA3Ljk4NzgxLDIwQzcuOTg3ODEsMjIuMjA1OCA2LjE5OTY4LDIzLjk5MzkgMy45OTM5LDIzLjk5MzlDMS43ODgxMywyMy45OTM5IDAsMjIuMjA1OCAwLDIwQzAsMTcuNzk0MiAxLjc4ODEzLDE2LjAwNjEgMy45OTM5LDE2LjAwNjFaIiBzdHlsZT0iZmlsbDpyZ2IoMTg3LDE4NywxODcpOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTUuODU3ODYsMjguNDkzOUM3LjQxNzU4LDI2LjkzNDIgOS45NDYzOCwyNi45MzQyIDExLjUwNjEsMjguNDkzOUMxMy4wNjU4LDMwLjA1MzYgMTMuMDY1OCwzMi41ODI0IDExLjUwNjEsMzQuMTQyMUM5Ljk0NjM4LDM1LjcwMTkgNy40MTc1OCwzNS43MDE5IDUuODU3ODYsMzQuMTQyMUM0LjI5ODE1LDMyLjU4MjQgNC4yOTgxNSwzMC4wNTM2IDUuODU3ODYsMjguNDkzOVoiIHN0eWxlPSJmaWxsOnJnYigxNjQsMTY0LDE2NCk7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNMzYuMDA2MSwxNi4wMDYxQzM4LjIxMTksMTYuMDA2MSA0MCwxNy43OTQyIDQwLDIwQzQwLDIyLjIwNTggMzguMjExOSwyMy45OTM5IDM2LjAwNjEsMjMuOTkzOUMzMy44MDAzLDIzLjk5MzkgMzIuMDEyMiwyMi4yMDU4IDMyLjAxMjIsMjBDMzIuMDEyMiwxNy43OTQyIDMzLjgwMDMsMTYuMDA2MSAzNi4wMDYxLDE2LjAwNjFaIiBzdHlsZT0iZmlsbDpyZ2IoNzQsNzQsNzQpOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTI4LjQ5MzksNS44NTc4NkMzMC4wNTM2LDQuMjk4MTUgMzIuNTgyNCw0LjI5ODE1IDM0LjE0MjEsNS44NTc4NkMzNS43MDE5LDcuNDE3NTggMzUuNzAxOSw5Ljk0NjM4IDM0LjE0MjEsMTEuNTA2MUMzMi41ODI0LDEzLjA2NTggMzAuMDUzNiwxMy4wNjU4IDI4LjQ5MzksMTEuNTA2MUMyNi45MzQyLDkuOTQ2MzggMjYuOTM0Miw3LjQxNzU4IDI4LjQ5MzksNS44NTc4NloiIHN0eWxlPSJmaWxsOnJnYig1MCw1MCw1MCk7Ii8+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4K");
200 background-repeat: no-repeat;
201 background-position: 50%% 50%%;
202 }
203
204
205 </style>
206 <script type="application/javascript">
207 document.documentElement.className += " optimole_has_js";
208 (function(w, d){
209 var b = d.getElementsByTagName("head")[0];
210 var s = d.createElement("script");
211 var v = ("IntersectionObserver" in w && "isIntersecting" in w.IntersectionObserverEntry.prototype) ? "_no_poly" : "";
212 s.async = true;
213 s.src = "%s/v2/latest/optimole_lib" + v + "%s.js";
214 b.appendChild(s);
215 w.optimoleData = {
216 lazyloadOnly: "optimole-lazy-only",
217 backgroundReplaceClasses: [%s],
218 nativeLazyload : %s,
219 scalingDisabled: %s,
220 watchClasses: [%s],
221 backgroundLazySelectors: "%s",
222 network_optimizations: %s,
223 ignoreDpr: %s,
224 quality: %d
225 }
226 }(window, document));
227 document.addEventListener( "DOMContentLoaded", function() {
228
229 if ( "loading" in HTMLImageElement.prototype && Object.prototype.hasOwnProperty.call( optimoleData, "nativeLazyload" ) && optimoleData.nativeLazyload === true ) {
230 const images = document.querySelectorAll(\'img[loading="lazy"]\');
231 images.forEach( function (img) {
232 if ( !img.dataset.optSrc) {
233 return;
234 }
235 img.src = img.dataset.optSrc;
236 delete img.dataset.optSrc;
237 });
238 }
239 } );
240 </script>',
241 esc_url( $domain ),
242 $min,
243 $bgclasses,
244 $native_lazy_enabled ? 'true' : 'false',
245 $scale_is_disabled ? 'true' : 'false',
246 $watcher_classes,
247 addcslashes( $lazyload_bg_selectors, '"' ),
248 defined( 'OPTML_NETWORK_ON' ) && constant( 'OPTML_NETWORK_ON' ) ? ( OPTML_NETWORK_ON ? 'true' : 'false' ) : ( $default_network ? 'true' : 'false' ),
249 $retina_ready ? 'true' : 'false',
250 $this->settings->get_numeric_quality()
251 );
252 echo $output;
253 }
254
255 /**
256 * Adds script for lazyload/js replacement.
257 */
258 public function add_diagnosis_script() {
259
260 wp_enqueue_script( 'optml-report', OPTML_URL . 'assets/js/report_script.js' );
261 $ignoredDomains = [ 'gravatar.com', 'instagram.com', 'fbcdn' ];
262 $report_script = array(
263 'optmlCdn' => $this->settings->get_cdn_url(),
264 'restUrl' => untrailingslashit( rest_url( OPTML_NAMESPACE . '/v1' ) ) . '/check_redirects',
265 'nonce' => wp_create_nonce( 'wp_rest' ),
266 'ignoredDomains' => $ignoredDomains,
267 'wait' => __( 'We are checking the current page for any issues with optimized images ...', 'optimole-wp' ),
268 'description' => __( 'Optimole page analyzer', 'optimole-wp' ),
269 );
270 wp_localize_script( 'optml-report', 'reportScript', $report_script );
271 }
272
273 /**
274 * Add settings links in the plugin listing page.
275 *
276 * @param array $links Old plugin links.
277 *
278 * @return array Altered links.
279 */
280 function add_action_links( $links ) {
281 if ( ! is_array( $links ) ) {
282 return $links;
283 }
284
285 return array_merge(
286 $links,
287 array(
288 '<a href="' . admin_url( 'upload.php?page=optimole' ) . '">' . __( 'Settings', 'optimole-wp' ) . '</a>',
289 )
290 );
291 }
292
293 /**
294 * Adds optimole optin class.
295 *
296 * @return string Optimole class.
297 */
298 public function add_body_class( $classes ) {
299
300 if ( ! $this->should_show_notice() ) {
301 return $classes;
302 }
303
304 return $classes . ' optimole-optin-show ';
305 }
306
307 /**
308 * Check if we should show the notice.
309 *
310 * @return bool Should show?
311 */
312 public function should_show_notice() {
313
314 $current_screen = get_current_screen();
315 if ( ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ||
316 is_network_admin() ||
317 $this->settings->is_connected() ||
318 empty( $current_screen )
319 ) {
320 return false;
321 }
322
323 static $allowed_base = array(
324 'plugins' => true,
325 'upload' => true,
326 'media' => true,
327 'themes' => true,
328 'appearance_page_tgmpa-install-plugins' => true,
329 );
330
331 $screen_slug = '';
332 if ( isset( $current_screen->base ) ) {
333 $screen_slug = $current_screen->base;
334 }
335
336 if ( isset( $current_screen->parent_base ) ) {
337 $screen_slug = $current_screen->parent_base;
338 }
339
340 if ( empty( $screen_slug ) ||
341 ( ! isset( $allowed_base[ $screen_slug ] ) ) ||
342 ! current_user_can( 'manage_options' ) ||
343 ( get_option( 'optml_notice_optin', 'no' ) === 'yes' )
344 ) {
345 return false;
346 }
347
348 return true;
349 }
350
351 /**
352 * Show upgrade notice.
353 */
354 public function add_notice_upgrade() {
355 if ( ! $this->should_show_upgrade() ) {
356 return;
357 }
358 ?>
359 <div class="notice notice-warning optml-notice-optin">
360 <p> <?php printf( __( 'It seems your are close to the %1$s5.0000%2$s visits limit with %3$sOptiMole%4$s for this month. You might want to check the upgrade plans for a larger quota. %5$s %6$s What happens if i exceed the quota ?%7$s We will need to deliver back your original %8$sun-optimized%9$s images which might decrease your site speed perfomance.', 'optimole-wp' ), '<strong>', '</strong>', '<strong>', '</strong>', '<br/><br/>', '<i>', '</i >', '<strong>', '</strong>' ); ?></p>
361 <p>
362 <a href="https://optimole.com/pricing" target="_blank" class="button button-primary"><span
363 class="dashicons dashicons-external"></span><?php _e( 'Check upgrade plans', 'optimole-wp' ); ?>
364 </a>
365 <a class="button"
366 href="<?php echo wp_nonce_url( add_query_arg( array( 'optml_hide_upg' => 'yes' ) ), 'hide_nonce', 'optml_nonce' ); ?>"><?php _e( 'I\'ve done this', 'optimole-wp' ); ?></a>
367 </p>
368 </div>
369 <?php
370 }
371
372 /**
373 * Check if we should show the upgrade notice to users.
374 *
375 * @return bool Should we show it?
376 */
377 public function should_show_upgrade() {
378 $current_screen = get_current_screen();
379 if ( ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ||
380 is_network_admin() ||
381 ! current_user_can( 'manage_options' ) ||
382 ! $this->settings->is_connected() ||
383 empty( $current_screen )
384 ) {
385 return false;
386 }
387 if ( get_option( 'optml_notice_hide_upg', 'no' ) === 'yes' ) {
388 return false;
389 }
390 if ( isset( $current_screen->base ) && $current_screen->base !== 'upload' ) {
391 return false;
392 }
393 $service_data = $this->settings->get( 'service_data' );
394 if ( ! isset( $service_data['plan'] ) ) {
395 return false;
396 }
397 if ( $service_data['plan'] !== 'free' ) {
398 return false;
399 }
400 $visitors_limit = isset( $service_data['visitors_limit'] ) ? (int) $service_data['visitors_limit'] : 0;
401 $visitors_left = isset( $service_data['visitors_left'] ) ? (int) $service_data['visitors_left'] : 0;
402 if ( $visitors_limit === 0 ) {
403 return false;
404 }
405 if ( $visitors_left > 2000 ) {
406 return false;
407 }
408
409 return true;
410 }
411
412 /**
413 * Adds opt in notice.
414 */
415 public function add_notice() {
416 if ( ! $this->should_show_notice() ) {
417 return;
418 }
419 ?>
420 <div class="notice notice-success optml-notice-optin">
421 <p> <?php printf( __( 'Welcome to %1$sOptiMole%2$s, the easiest way to optimize your website images. Your users will enjoy a %3$sfaster%4$s website after you connect it with our service.', 'optimole-wp' ), '<strong>', '</strong>', '<strong>', '</strong>' ); ?></p>
422 <p>
423 <a href="<?php echo esc_url( admin_url( 'upload.php?page=optimole' ) ); ?>"
424 class="button button-primary"><?php _e( 'Connect to OptiMole', 'optimole-wp' ); ?></a>
425 <a class="button"
426 href="<?php echo wp_nonce_url( add_query_arg( array( 'optml_hide_optin' => 'yes' ) ), 'hide_nonce', 'optml_nonce' ); ?>"><?php _e( 'I will do it later', 'optimole-wp' ); ?></a>
427 </p>
428 </div>
429 <?php
430 }
431
432 /**
433 * Add style classes for lazy loading background images.
434 */
435 protected function get_background_lazy_css() {
436
437 $watchers = Optml_Lazyload_Replacer::get_background_lazyload_selectors();
438
439 $css = [];
440 foreach ( $watchers as $selector ) {
441 $css[] = 'html.optimole_has_js ' . $selector . ':not(.optml-bg-lazyloaded)';
442 }
443 if ( empty( $css ) ) {
444 return '';
445 }
446 $css = implode( ",\n", $css ) . ' { background-image: none !important; } ';
447
448 return strip_tags( $css );
449 }
450
451 /**
452 * Enqueue frontend scripts.
453 */
454 public function frontend_scripts() {
455
456 $bg_css = $this->get_background_lazy_css();
457
458 wp_register_style( 'optm_lazyload_noscript_style', false );
459 wp_enqueue_style( 'optm_lazyload_noscript_style' );
460 wp_add_inline_style( 'optm_lazyload_noscript_style', ":not(.optimole_has_js) img[data-opt-src] { display: none !important; } \n " . $bg_css );
461 }
462
463 /**
464 * Maybe redirect to dashboard page.
465 */
466 public function maybe_redirect() {
467
468 if ( isset( $_GET['optml_nonce'] ) && isset( $_GET['optml_hide_optin'] ) && $_GET['optml_hide_optin'] === 'yes' && wp_verify_nonce( $_GET['optml_nonce'], 'hide_nonce' ) ) {
469 update_option( 'optml_notice_optin', 'yes' );
470 }
471
472 if ( isset( $_GET['optml_nonce'] ) && isset( $_GET['optml_hide_upg'] ) && $_GET['optml_hide_upg'] === 'yes' && wp_verify_nonce( $_GET['optml_nonce'], 'hide_nonce' ) ) {
473 update_option( 'optml_notice_hide_upg', 'yes' );
474 }
475
476 if ( ! get_transient( 'optml_fresh_install' ) ) {
477 return;
478 }
479
480 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
481 return;
482 }
483
484 delete_transient( 'optml_fresh_install' );
485
486 if ( is_network_admin() || isset( $_GET['activate-multi'] ) ) {
487 return;
488 }
489
490 if ( $this->settings->is_connected() ) {
491 return;
492 }
493 wp_safe_redirect( admin_url( 'upload.php?page=optimole' ) );
494 exit;
495 }
496
497 /**
498 * Output Generator tag.
499 */
500 public function generator() {
501 if ( ! $this->settings->is_connected() ) {
502 return;
503 }
504 if ( ! $this->settings->is_enabled() ) {
505 return;
506 }
507 echo '<meta name="generator" content="Optimole ' . esc_attr( OPTML_VERSION ) . '">';
508 }
509
510 /**
511 * Update daily the quota routine.
512 */
513 function daily_sync() {
514
515 $api_key = $this->settings->get( 'api_key' );
516 if ( empty( $api_key ) ) {
517 return;
518 }
519
520 $request = new Optml_Api();
521 $data = $request->get_user_data( $api_key );
522 if ( $data === false || is_wp_error( $data ) ) {
523 return;
524 }
525
526 $this->settings->update( 'service_data', $data );
527
528 }
529
530 /**
531 * Adds cdn url for prefetch.
532 *
533 * @param array $hints Hints array.
534 * @param string $relation_type Type of relation.
535 *
536 * @return array Altered hints array.
537 */
538 public function add_dns_prefetch( $hints, $relation_type ) {
539 if ( 'dns-prefetch' !== $relation_type &&
540 'preconnect' !== $relation_type
541 ) {
542 return $hints;
543 }
544 if ( ! $this->settings->is_connected() ) {
545 return $hints;
546 }
547 if ( ! $this->settings->is_enabled() ) {
548 return $hints;
549 }
550 $hints[] = sprintf( 'https://%s', $this->settings->get_cdn_url() );
551
552 if ( ! $this->settings->use_lazyload() && ! Optml_Manager::should_ignore_image_tags() ) {
553 $hints[] = sprintf( 'https://%s', OPTML_JS_CDN );
554 }
555
556 return $hints;
557 }
558
559 /**
560 * Add the dashboard page.
561 */
562 public function add_dashboard_page() {
563 if ( defined( 'OPTIOMLE_HIDE_ADMIN_AREA' ) && OPTIOMLE_HIDE_ADMIN_AREA ) {
564 return;
565 }
566 add_media_page( 'Optimole', 'Optimole', 'manage_options', 'optimole', array( $this, 'render_dashboard_page' ) );
567 }
568
569 /**
570 * Render dashboard page.
571 */
572 public function render_dashboard_page() {
573 if ( get_option( 'optml_notice_optin', 'no' ) !== 'yes' ) {
574 update_option( 'optml_notice_optin', 'yes' );
575 }
576 ?>
577
578 <div id="optimole-app">
579 <app></app>
580 </div>
581 <?php
582 }
583
584 /**
585 * Enqueue scripts needed for admin functionality.
586 *
587 * @codeCoverageIgnore
588 */
589 public function enqueue() {
590
591 $current_screen = get_current_screen();
592 if ( ! isset( $current_screen->id ) ) {
593 return;
594 }
595 if ( $current_screen->id != 'media_page_optimole' ) {
596 return;
597 }
598 wp_register_script( OPTML_NAMESPACE . '-admin', OPTML_URL . 'assets/js/bundle' . ( ! OPTML_DEBUG ? '.min' : '' ) . '.js', array(), OPTML_VERSION );
599 wp_localize_script( OPTML_NAMESPACE . '-admin', 'optimoleDashboardApp', $this->localize_dashboard_app() );
600 wp_enqueue_script( OPTML_NAMESPACE . '-admin' );
601 }
602
603 /**
604 * Localize the dashboard app.
605 *
606 * @codeCoverageIgnore
607 * @return array
608 */
609 private function localize_dashboard_app() {
610 $api_key = $this->settings->get( 'api_key' );
611 $service_data = $this->settings->get( 'service_data' );
612 $user = get_userdata( get_current_user_id() );
613
614 return array(
615 'strings' => $this->get_dashboard_strings(),
616 'assets_url' => OPTML_URL . 'assets/',
617 'connection_status' => empty( $service_data ) ? 'no' : 'yes',
618 'user_status' => isset( $service_data['status'] ) && $service_data['status'] === 'inactive' ? 'inactive' : 'active',
619 'api_key' => $api_key,
620 'root' => untrailingslashit( rest_url( OPTML_NAMESPACE . '/v1' ) ),
621 'nonce' => wp_create_nonce( 'wp_rest' ),
622 'user_data' => $service_data,
623 'remove_latest_images' => defined( 'OPTML_REMOVE_LATEST_IMAGES' ) && constant( 'OPTML_REMOVE_LATEST_IMAGES' ) ? ( OPTML_REMOVE_LATEST_IMAGES ? 'yes' : 'no' ) : 'no',
624 'current_user' => array(
625 'email' => $user->user_email,
626 ),
627 'site_settings' => $this->settings->get_site_settings(),
628 'home_url' => home_url(),
629 );
630 }
631
632 /**
633 * Get all dashboard strings.
634 *
635 * @codeCoverageIgnore
636 * @return array
637 */
638 private function get_dashboard_strings() {
639 return array(
640 'optimole' => 'Optimole',
641 'version' => OPTML_VERSION,
642 'terms_menu' => __( 'Terms', 'optimole-wp' ),
643 'privacy_menu' => __( 'Privacy', 'optimole-wp' ),
644 'testdrive_menu' => __( 'Test Optimole', 'optimole-wp' ),
645 'service_details' => __( 'Image optimization service', 'optimole-wp' ),
646 'connect_btn' => __( 'Connect to OptiMole Service', 'optimole-wp' ),
647 'disconnect_btn' => __( 'Disconnect', 'optimole-wp' ),
648 'refresh_stats_cta' => __( 'Refresh stats', 'optimole-wp' ),
649 'updating_stats_cta' => __( 'Updating stats', 'optimole-wp' ),
650 'api_key_placeholder' => __( 'API Key', 'optimole-wp' ),
651 'account_needed_heading' => __( 'Sign-up for API key', 'optimole-wp' ),
652 'invalid_key' => __( 'Invalid API Key', 'optimole-wp' ),
653 'status' => __( 'Status', 'optimole-wp' ),
654 'email_address_label' => __( 'Your email address', 'optimole-wp' ),
655 'register_btn' => __( 'Register & Email API key', 'optimole-wp' ),
656 'step_one_api_title' => __( 'Enter your API key.', 'optimole-wp' ),
657 'step_one_api_desc' => sprintf( __( 'Copy the API key you have received via email or you can get it from %1$s Optimole dashboard%2$s. <br/>', 'optimole-wp' ), '<a href="https://dashboard.optimole.com/" target="_blank"> ', '</a>' ),
658 'step_two_api_title' => __( 'Connect to Optimole.', 'optimole-wp' ),
659 'step_two_api_desc' => __( ' Fill in the upper API key field and connect to Optimole service.', 'optimole-wp' ),
660 'api_exists' => __( 'I already have an API key.', 'optimole-wp' ),
661 'back_to_register' => __( 'Register account', 'optimole-wp' ),
662 'back_to_connect' => __( 'Connect account', 'optimole-wp' ),
663 'error_register' => sprintf( __( 'Error registering account. You can try again %1$shere%2$s ', 'optimole-wp' ), '<a href="https://dashboard.optimole.com/register" target="_blank"> ', '</a>' ),
664 'connected' => __( 'Connected', 'optimole-wp' ),
665 'not_connected' => __( 'Not connected', 'optimole-wp' ),
666 'usage' => __( 'Monthly Usage', 'optimole-wp' ),
667 'quota' => __( 'Monthly Quota', 'optimole-wp' ),
668 'logged_in_as' => __( 'Logged in as', 'optimole-wp' ),
669 'private_cdn_url' => __( 'Images domain', 'optimole-wp' ),
670 'notification_message_register' => __( 'We have sent you an email with the API key. Please copy and paste the key in the field below.', 'optimole-wp' ),
671 'account_needed_title' => sprintf(
672 __( 'In order to get access to free image optimization service you will need an API key from %s.', 'optimole-wp' ),
673 ' <a href="https://dashboard.optimole.com/register" target="_blank">optimole.com</a>'
674 ),
675 'account_needed_subtitle_1' => sprintf(
676 __( 'You will get access to our image optimization service for %1$sFREE%2$s in the limit of %3$s5k%4$s %5$svisitors%6$s per month. ', 'optimole-wp' ),
677 '<strong>',
678 '</strong>',
679 '<strong>',
680 '</strong>',
681 '<a href="https://docs.optimole.com/article/1134-how-optimole-counts-the-number-of-visitors" target="_blank">',
682 '</a>'
683 ),
684 'account_needed_subtitle_3' => sprintf(
685 __( 'Here’s %1$show%2$s to install Optimole on your WordPress site in 3 steps.', 'optimole-wp' ),
686 '<a target="_blank" href="https://docs.optimole.com/article/1173-how-to-get-started-with-optimole-in-just-3-steps">',
687 '</a>'
688 ),
689 'account_needed_subtitle_2' => sprintf(
690 __( 'Bonus, if you dont use a CDN, we got you covered, we will serve the images using CloudFront CD from 200 locations.', 'optimole-wp' )
691 ),
692 'notice_just_activated' => ! $this->settings->is_connected() ?
693 sprintf( __( '%1$sImage optimisation is currently running.%2$s <br/> Your visitors will now view the best image for their device automatically, all served from the Optimole Cloud Service on the fly. You might see for the very first image request being redirected to the original URL while we do the optimization in the background.<br/> You can relax, we\'ll take it from here.', 'optimole-wp' ), '<strong>', '</strong>' )
694 : '',
695 'notice_api_not_working' => __(
696 'It seems there is an issue with your WordPress configuration and the core REST API functionality is not available. This is crucial as Optimole relies on this functionality in order to work.<br/>
697 The root cause might be either a security plugin which blocks this feature or some faulty server configuration which constrain this WordPress feature.You can try to disable any of the security plugins that you use in order to see if the issue persists or ask the hosting company to further investigate.',
698 'optimole-wp'
699 ),
700 'notice_disabled_account' => sprintf( __( 'Your account has been disabled due to exceeding quota. All images are being redirected to the original unoptimized URL. Please %1$supgrade%2$s to re-activate the account.', 'optimole-wp' ), '<a href="https://optimole.com/pricing">', '</a>' ),
701 'dashboard_menu_item' => __( 'Dashboard', 'optimole-wp' ),
702 'settings_menu_item' => __( 'Settings', 'optimole-wp' ),
703 'settings_exclusions_menu_item' => __( 'Exclusions', 'optimole-wp' ),
704 'settings_resize_menu_item' => __( 'Resize', 'optimole-wp' ),
705 'settings_compression_menu_item' => __( 'Compression', 'optimole-wp' ),
706 'advanced_settings_menu_item' => __( 'Advanced', 'optimole-wp' ),
707 'general_settings_menu_item' => __( 'General', 'optimole-wp' ),
708 'lazyload_settings_menu_item' => __( 'Lazyload', 'optimole-wp' ),
709 'watermarks_menu_item' => __( 'Watermark', 'optimole-wp' ),
710 'conflicts_menu_item' => __( 'Possible issues', 'optimole-wp' ),
711 'conflicts' => array(
712 'title' => __( 'We might have some possible conflicts with the plugins that you use. In order to benefit from Optimole\'s full potential you will need to address this issues.', 'optimole-wp' ),
713 'message' => __( 'Details', 'optimole-wp' ),
714 'conflict_close' => __( 'I\'ve done this.', 'optimole-wp' ),
715 'no_conflicts_found' => __( 'No conflicts found. We are all peachy now. 🍑', 'optimole-wp' ),
716 ),
717 'upgrade' => array(
718 'title' => __( 'Upgrade to Pro', 'optimole-wp' ),
719 'reason_1' => __( 'Priority & Live Chat support', 'optimole-wp' ),
720 'reason_2' => __( 'Extend visits limit', 'optimole-wp' ),
721 'reason_3' => __( 'Custom domain', 'optimole-wp' ),
722 'reason_4' => __( 'Site audit', 'optimole-wp' ),
723 'cta' => __( 'View plans', 'optimole-wp' ),
724 ),
725 'options_strings' => array(
726 'add_filter' => __( 'Add filter', 'optimole-wp' ),
727 'admin_bar_desc' => __( 'Show in the WordPress admin bar the available quota from Optimole service.', 'optimole-wp' ),
728 'auto_q_title' => __( 'Auto', 'optimole-wp' ),
729 'cache_desc' => __( 'Clear all cached resources(images,js,css) by Optimole from this site. Useful if you updated them and Optimole shows the old version.', 'optimole-wp' ),
730 'cache_title' => __( 'Clear cached resources', 'optimole-wp' ),
731 'clear_cache' => __( 'Clear cached resources', 'optimole-wp' ),
732 'connect_step_0' => __( 'Connecting your site to the Optimole service.', 'optimole-wp' ),
733 'connect_step_1' => __( 'Checking for possible conflicts.', 'optimole-wp' ),
734 'connect_step_2' => __( 'Inspecting the images from your site.', 'optimole-wp' ),
735 'connect_step_3' => __( 'All done, Optimole is currently optimizing your site.', 'optimole-wp' ),
736 'disabled' => __( 'Disabled', 'optimole-wp' ),
737 'enable_bg_lazyload_desc' => __( 'Lazyload images used as CSS backgrounds.', 'optimole-wp' ),
738 'enable_bg_lazyload_title' => __( 'Enable lazyload for background images', 'optimole-wp' ),
739 'enable_video_lazyload_desc' => __( 'Lazyload iframes/videos', 'optimole-wp' ),
740 'enable_video_lazyload_title' => __( 'Enable lazyload for embedded videos and iframes.', 'optimole-wp' ),
741 'enable_gif_replace_title' => __( 'Enable Gif to Video conversion', 'optimole-wp' ),
742 'enable_report_title' => __( 'Enable error diagnosis tool' ),
743 'enable_report_desc' => __( 'Provides a troubleshooting mechanism which should help you identify any possible issues with your site using Optimole.' ),
744 'enable_image_replace' => __( 'Enable image replacement', 'optimole-wp' ),
745 'enable_lazyload_placeholder_desc' => __( 'Enabling this might affect the user experience in some cases, however it will reduce the number of total requests and page weight. Try it out and see how works best for you!', 'optimole-wp' ),
746 'enable_lazyload_placeholder_title' => __( 'Enable generic lazyload placeholder', 'optimole-wp' ),
747 'enable_network_opt_desc' => __( 'Optimole provides an option to automatically downgrade the image quality when it detects a slower network.', 'optimole-wp' ),
748 'enable_network_opt_title' => __( 'Enable network based optimizations', 'optimole-wp' ),
749 'enable_resize_smart_desc' => __( 'Detects the most interesting section of the image and considers it as the center of the resulting image.', 'optimole-wp' ),
750 'enable_resize_smart_title' => __( 'Enable Smart Cropping', 'optimole-wp' ),
751 'enable_retina_desc' => __( 'Deliver retina ready images to your visitors', 'optimole-wp' ),
752 'enable_retina_title' => __( 'Enable Retina images', 'optimole-wp' ),
753 'enabled' => __( 'Enabled', 'optimole-wp' ),
754 'exclude_class_desc' => __( 'Image tag contains class', 'optimole-wp' ),
755 'exclude_ext_desc' => __( 'Image extension is', 'optimole-wp' ),
756 'exclude_filename_desc' => __( 'Image filename contains', 'optimole-wp' ),
757 'exclude_title_lazyload' => __( 'Don\'t lazyload images if', 'optimole-wp' ),
758 'exclude_title_optimize' => __( 'Don\'t optimize images if', 'optimole-wp' ),
759 'exclude_url_desc' => __( 'Page url contains', 'optimole-wp' ),
760 'filter_class' => __( 'Image class', 'optimole-wp' ),
761 'filter_ext' => __( 'Image extension', 'optimole-wp' ),
762 'filter_filename' => __( 'Image filename', 'optimole-wp' ),
763 'filter_operator_contains' => __( 'contains', 'optimole-wp' ),
764 'filter_operator_is' => __( 'is', 'optimole-wp' ),
765 'filter_url' => __( 'Page URL', 'optimole-wp' ),
766 'gif_replacer_desc' => __( 'Automatically convert GIF images to Video files(MP4 and WebM)', 'optimole-wp' ),
767 'height_field' => __( 'Height', 'optimole-wp' ),
768 'hide' => __( 'Hide', 'optimole-wp' ),
769 'high_q_title' => __( 'High', 'optimole-wp' ),
770 'image_1_label' => __( 'Original', 'optimole-wp' ),
771 'image_2_label' => __( 'Optimized', 'optimole-wp' ),
772 'lazyload_desc' => __( 'We will generate images size based on your visitor\'s screen using javascript and render them without blocking the page execution via lazyload .', 'optimole-wp' ),
773 'scale_desc' => __( 'When this option is off, we disable the automatic scaling of images on lazyload.', 'optimole-wp' ),
774 'low_q_title' => __( 'Low', 'optimole-wp' ),
775 'medium_q_title' => __( 'Medium', 'optimole-wp' ),
776 'no_images_found' => __( 'You dont have any images in your Media Library. Add one and check how the Optimole will perform.', 'optimole-wp' ),
777 'native_desc' => __( 'Use browser native lazyload if supported, fallback to classic lazyload otherwise. When using browser native lazyload the auto scale feature is disabled', 'optimole-wp' ),
778 'option_saved' => __( 'Option saved.', 'optimole-wp' ),
779 'quality_desc' => __( 'Lower image quality might not always be perceived by users and would result in a boost of your loading speed by lowering the page size. Try experimenting with the setting, then click the View sample image link to see what option works best for you.', 'optimole-wp' ),
780 'quality_selected_value' => __( 'Selected value', 'optimole-wp' ),
781 'quality_slider_desc' => __( 'See one sample image which will help you choose the right quality of the compression.', 'optimole-wp' ),
782 'quality_title' => __( 'Image quality', 'optimole-wp' ),
783 'replacer_desc' => __( 'Replace all the image urls from your website with the ones optimized by Optimole.', 'optimole-wp' ),
784 'sample_image_loading' => __( 'Loading a sample image. ', 'optimole-wp' ),
785 'save_changes' => __( 'Save changes', 'optimole-wp' ),
786 'show' => __( 'Show', 'optimole-wp' ),
787 'size_desc' => __( 'We resize all images with sizes greater than the values defined here. Changing this option is not recommended unless large images are not being processed correctly. This does NOT affect the scaling of images on the frontend.', 'optimole-wp' ),
788 'size_title' => __( 'Resize large images original source.', 'optimole-wp' ),
789 'toggle_ab_item' => __( 'Admin bar status', 'optimole-wp' ),
790 'toggle_lazyload' => __( 'Scale images & Lazy load', 'optimole-wp' ),
791 'toggle_scale' => __( 'Scale Images', 'optimole-wp' ),
792 'toggle_native' => __( 'Use native lazyload', 'optimole-wp' ),
793 'on_toggle' => __( 'On', 'optimole-wp' ),
794 'off_toggle' => __( 'Off', 'optimole-wp' ),
795 'view_sample_image' => __( 'View sample image', 'optimole-wp' ),
796 'watch_desc_lazyload' => __( 'You can add each CSS selector on a new line or separated by comma(,).', 'optimole-wp' ),
797 'watch_title_lazyload' => __( 'Lazyload background images for selectors:', 'optimole-wp' ),
798 'width_field' => __( 'Width', 'optimole-wp' ),
799 'toggle_cdn' => __( 'Serve CSS & JS through Optimole', 'optimole-wp' ),
800 'cdn_desc' => __( 'Useful when you have images into CSS/JS files. Optimole wil optimize the images from them and serve the CSS/JS through the CDN.', 'optimole-wp' ),
801 'enable_css_minify_title' => __( 'Minify CSS files', 'optimole-wp' ),
802 'css_minify_desc' => __( 'Once Optimole will serve your CSS files, it will also minify the files and serve them via CDN.', 'optimole-wp' ),
803 'enable_js_minify_title' => __( 'Minify JS files', 'optimole-wp' ),
804 'js_minify_desc' => __( 'Once Optimole will serve your JS files, it will also minify the files and serve them via CDN.', 'optimole-wp' ),
805 ),
806 'watermarks' => array(
807 'image' => __( 'Image', 'optimole-wp' ),
808 'loading_remove_watermark' => __( 'Removing watermark resource ...', 'optimole-wp' ),
809 'max_allowed' => __( 'You are allowed to save maximum 5 images.', 'optimole-wp' ),
810 'list_header' => __( 'Possible watermarks', 'optimole-wp' ),
811 'settings_header' => __( 'Watermarks position settings', 'optimole-wp' ),
812 'no_images_found' => __( 'No images available for watermark. Please upload one.', 'optimole-wp' ),
813 'id' => __( 'ID', 'optimole-wp' ),
814 'name' => __( 'Name', 'optimole-wp' ),
815 'type' => __( 'Type', 'optimole-wp' ),
816 'action' => __( 'Action', 'optimole-wp' ),
817 'upload' => __( 'Upload', 'optimole-wp' ),
818 'add_desc' => __( 'Add new watermark', 'optimole-wp' ),
819 'wm_title' => __( 'Active watermark', 'optimole-wp' ),
820 'wm_desc' => __( 'The active watermark to use from the list of uploaded watermarks.', 'optimole-wp' ),
821 'opacity_field' => __( 'Opacity', 'optimole-wp' ),
822 'opacity_title' => __( 'Watermark opacity', 'optimole-wp' ),
823 'opacity_desc' => __( 'A value between 0 and 100 for the opacity level. If set to 0 it will disable the watermark.', 'optimole-wp' ),
824 'position_title' => __( 'Watermark position', 'optimole-wp' ),
825 'position_desc' => __( 'The place relative to the image where the watermark should be placed.', 'optimole-wp' ),
826 'pos_nowe_title' => __( 'North-West', 'optimole-wp' ),
827 'pos_no_title' => __( 'North', 'optimole-wp' ),
828 'pos_noea_title' => __( 'North-East', 'optimole-wp' ),
829 'pos_we_title' => __( 'West', 'optimole-wp' ),
830 'pos_ce_title' => __( 'Center', 'optimole-wp' ),
831 'pos_ea_title' => __( 'East', 'optimole-wp' ),
832 'pos_sowe_title' => __( 'South-West', 'optimole-wp' ),
833 'pos_so_title' => __( 'South', 'optimole-wp' ),
834 'pos_soea_title' => __( 'South-East', 'optimole-wp' ),
835 'offset_x_field' => __( 'Offset X', 'optimole-wp' ),
836 'offset_y_field' => __( 'Offset Y', 'optimole-wp' ),
837 'offset_title' => __( 'Watermark offset', 'optimole-wp' ),
838 'offset_desc' => __( 'Offset the watermark from set position on X and Y axis. Values can be positive or negative.', 'optimole-wp' ),
839 'scale_field' => __( 'Scale', 'optimole-wp' ),
840 'scale_title' => __( 'Watermark scale', 'optimole-wp' ),
841 'scale_desc' => __( 'A value between 0 and 300 for the scale of the watermark (100 is the original size and 300 is 3x the size) relative to the resulting image size. If set to 0 it will default to the original size.', 'optimole-wp' ),
842 'save_changes' => __( 'Save changes', 'optimole-wp' ),
843 ),
844 'latest_images' => array(
845 'image' => __( 'Image', 'optimole-wp' ),
846 'no_images_found' => sprintf( __( 'We are currently optimizing your images. Meanwhile you can visit your %1$shomepage%2$s and check how our plugin performs. ', 'optimole-wp' ), '<a href="' . esc_url( home_url() ) . '" target="_blank" >', '</a>' ),
847 'compression' => __( 'Optimization', 'optimole-wp' ),
848 'loading_latest_images' => __( 'Loading your optimized images...', 'optimole-wp' ),
849 'last' => __( 'Last', 'optimole-wp' ),
850 'optimized_images' => __( 'optimized images', 'optimole-wp' ),
851 'same_size' => __( '🙉 We couldn\'t do better, this image is already optimized at maximum. ', 'optimole-wp' ),
852 'small_optimization' => __( '😬 Not that much, just <strong>{ratio}</strong> smaller.', 'optimole-wp' ),
853 'medium_optimization' => __( '🤓 We are on the right track, <strong>{ratio}</strong> squeezed.', 'optimole-wp' ),
854 'big_optimization' => __( '❤️❤️❤️ Our moles just nailed it, this one is <strong>{ratio}</strong> smaller. ', 'optimole-wp' ),
855 ),
856 );
857 }
858
859 }
860