PluginProbe ʕ •ᴥ•ʔ
Asset CleanUp: Page Speed Booster / trunk
Asset CleanUp: Page Speed Booster vtrunk
trunk 1.1.4.6 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.4.1 1.2.4.2 1.2.4.3 1.2.4.4 1.2.5 1.2.5.1 1.2.5.2 1.2.5.3 1.2.6 1.2.6.1 1.2.6.2 1.2.6.3 1.2.6.4 1.2.6.5 1.2.6.6 1.2.6.7 1.2.6.8 1.2.6.9 1.2.7 1.2.7.1 1.2.7.2 1.2.7.3 1.2.7.4 1.2.7.5 1.2.7.6 1.2.7.7 1.2.7.8 1.2.7.9 1.2.8 1.2.8.1 1.2.8.2 1.2.8.3 1.2.8.4 1.2.8.5 1.2.8.6 1.2.8.7 1.2.8.8 1.2.8.9 1.2.9 1.2.9.1 1.2.9.2 1.2.9.3 1.2.9.4 1.2.9.5 1.2.9.6 1.2.9.7 1.2.9.8 1.2.9.9 1.3 1.3.1 1.3.2 1.3.2.1 1.3.2.2 1.3.2.3 1.3.2.4 1.3.2.5 1.3.2.6 1.3.2.7 1.3.2.8 1.3.2.9 1.3.3.0 1.3.3.1 1.3.3.2 1.3.3.3 1.3.3.4 1.3.3.5 1.3.3.6 1.3.3.7 1.3.3.8 1.3.3.9 1.3.4.0 1.3.4.1 1.3.4.2 1.3.4.3 1.3.4.4 1.3.4.5 1.3.4.6 1.3.4.7 1.3.4.8 1.3.4.9 1.3.5.0 1.3.5.1 1.3.5.2 1.3.5.3 1.3.5.4 1.3.5.5 1.3.5.6 1.3.5.7 1.3.5.8 1.3.5.9 1.3.6.0 1.3.6.1 1.3.6.2 1.3.6.3 1.3.6.4 1.3.6.5 1.3.6.6 1.3.6.7 1.3.6.8 1.3.6.9 1.3.7.0 1.3.7.1 1.3.7.2 1.3.7.3 1.3.7.4 1.3.7.5 1.3.7.6 1.3.7.7 1.3.7.8 1.3.7.9 1.3.8.0 1.3.8.1 1.3.8.2 1.3.8.2.1 1.3.8.3 1.3.8.4 1.3.8.5 1.3.8.6 1.3.8.7 1.3.8.8 1.3.8.9 1.3.9.0 1.3.9.1 1.3.9.2 1.3.9.3 1.3.9.4 1.3.9.5 1.3.9.6 1.3.9.7 1.3.9.8 1.3.9.9 1.4 1.4.0.1 1.4.0.2 1.4.0.3 1.4.0.4
wp-asset-clean-up / classes / Update.php
wp-asset-clean-up / classes Last commit date
Admin 1 month ago OptimiseAssets 1 month ago ThirdParty 1 year ago AdminBar.php 1 year ago AssetsManager.php 1 month ago BulkChanges.php 1 year ago CleanUp.php 1 month ago Debug.php 1 month ago FileSystem.php 1 year ago HardcodedAssets.php 1 month ago Lite.php 3 years ago Main.php 1 month ago MainFront.php 1 month ago Maintenance.php 1 month ago Menu.php 1 month ago MetaBoxes.php 1 month ago Misc.php 1 month ago ObjectCache.php 1 month ago OwnAssets.php 1 month ago PluginNotifications.php 1 year ago PluginTracking.php 1 month ago Preloads.php 1 month ago Settings.php 1 month ago Tips.php 1 year ago Update.php 1 month ago
Update.php
1637 lines
1 <?php
2 /** @noinspection MultipleReturnStatementsInspection */
3
4 namespace WpAssetCleanUp;
5
6 use WpAssetCleanUp\Admin\SettingsAdmin;
7 use WpAssetCleanUp\OptimiseAssets\OptimizeCommon;
8
9 /**
10 * Class Update
11 * @package WpAssetCleanUp
12 */
13 class Update
14 {
15 /**
16 *
17 */
18 const NONCE_ACTION_NAME = 'wpacu_data_update';
19 /**
20 *
21 */
22 const NONCE_FIELD_NAME = 'wpacu_data_nonce';
23
24 /**
25 * @var bool
26 */
27 public $frontEndUpdateTriggered = false;
28
29 /**
30 * @var array
31 */
32 public $frontEndUpdateFor = array(
33 'homepage' => false,
34 'page' => false
35 );
36
37 /**
38 * @var array
39 */
40 public $afterSubmitMsg = array();
41
42 /**
43 * Update constructor.
44 */
45 public function __construct()
46 {
47 $homePageSettingsUpdatedText = esc_html__('The homepage\'s settings were updated. Please make sure the homepage\'s cache is cleared (if you\'re using a caching plugin or a server-side caching solution) to immediately have the changes applied for every visitor.', 'wp-asset-clean-up');
48 $this->afterSubmitMsg['homepage'] = <<<HTML
49 <span class="dashicons dashicons-yes"></span> {$homePageSettingsUpdatedText}
50 HTML;
51
52 $pageSettingsUpdatedText = esc_html__('This page\'s settings were updated. Please make sure the page\'s cache is cleared (if you\'re using a caching plugin or a server-side caching solution) to immediately have the changes applied for every visitor.', 'wp-asset-clean-up');
53 $this->afterSubmitMsg['page'] = <<<HTML
54 <span class="dashicons dashicons-yes"></span> {$pageSettingsUpdatedText}
55 HTML;
56
57 $invalidNonceText = sprintf(
58 __('The changes were not saved because the security nonce has expired (it took over 24 hours since you loaded this page) or it was not sent for verification in the first place because the form was partially submitted due to the input fields being stripped.', 'wp-asset-clean-up'),
59 ini_get('max_input_vars')
60 );
61
62 $maxInputVarsValue = (int)@ini_get('max_input_vars');
63
64 if ($maxInputVarsValue === 1000) {
65 $invalidNonceText .= ' '. sprintf(__('The value of <strong>max_input_vars</strong> is <strong>1000</strong> which is the default one in many hosting accounts. Increase it to a higher number, ideally over %d.'), 4000);
66 } elseif ($maxInputVarsValue < 1000) {
67 $invalidNonceText .= ' '. sprintf(__('The value of <strong>max_input_vars</strong> is <strong>%d</strong>. That\'s below <strong>1000</strong> (the default one in many hosting accounts). Increase it to a higher number, ideally over %d.'), $maxInputVarsValue, 4000);
68 } else {
69 $invalidNonceText .= ' '. sprintf(__('The value of <strong>max_input_vars</strong> is <strong>%d</strong>. You might need to increase it to a higher number.'), $maxInputVarsValue);
70 }
71
72 $invalidNonceText .= ' <a target="_blank" href="https://www.assetcleanup.com/docs/?p=1346">'.esc_html__('How to fix it?', 'wp-asset-clean-up').'</a>';
73
74 $this->afterSubmitMsg['invalid_nonce_error'] = <<<HTML
75 <span style="color: #cc0000;" class="dashicons dashicons-dismiss"></span> {$invalidNonceText}
76 HTML;
77 }
78
79 /**
80 *
81 */
82 public function init()
83 {
84 // Triggers on front-end view
85 add_action('init', array($this, 'triggersAfterInit'), 11);
86
87 // After post/page is saved - update your styles/scripts lists
88 // This triggers ONLY in the Dashboard after "Update" button is clicked (on Edit mode)
89 add_action('save_post', array($this, 'savePosts'));
90
91 // Are there any plugins such as "WPML Multilingual CMS" that have the same page translated in several languages
92 // each having its own ID in the "posts" table? Make sure to sync all of them whenever a specific page setting is applied
93 add_filter('wpacu_get_all_assoc_post_ids', array($this, 'getAllAssocPostIds'));
94
95 // Clear cache (via AJAX) only if the user is logged-in (with the right privileges)
96 add_action('wp_ajax_' . WPACU_PLUGIN_ID . '_clear_cache', array($this, 'ajaxClearCache'), PHP_INT_MAX);
97
98 // After an update, preload the page for the guest view; the preload for the admin is done within /assets/script.min.js
99 add_action('wp_ajax_' . WPACU_PLUGIN_ID . '_preload', array($this, 'ajaxPreloadGuest'), PHP_INT_MAX);
100
101 // Clear cache (via AJAX) for other plugins after post/page update
102 add_action('wp_ajax_' . WPACU_PLUGIN_ID . '_cache_enabler_clear_cache', array($this, 'ajaxCacheEnablerClearCache'), PHP_INT_MAX);
103
104 // e.g. when "+" or "-" is used within an asset's row (CSS/JS manager), the state is updated in the background to be remembered
105 add_action( 'wp_ajax_' . WPACU_PLUGIN_ID . '_update_asset_row_state', array($this, 'ajaxUpdateAssetRowState') );
106 add_action( 'wp_ajax_nopriv_' . WPACU_PLUGIN_ID . '_update_asset_row_state', array($this, 'ajaxUpdateAssetRowState') );
107
108 add_action( 'wp_ajax_' . WPACU_PLUGIN_ID . '_area_update_assets_row_state', array($this, 'ajaxAreaUpdateAssetsRowState') );
109 add_action( 'wp_ajax_nopriv_' . WPACU_PLUGIN_ID . '_area_update_assets_row_state', array($this, 'ajaxAreaUpdateAssetsRowState') );
110 }
111
112 /**
113 *
114 */
115 public function triggersAfterInit()
116 {
117 if (! is_admin() && AssetsManager::instance()->frontendShow()) {
118 if (! empty($_POST)) {
119 $wpacuAction = Misc::isElementorMaintenanceModeOn() ? 'template_redirect' : 'wp';
120
121 if ($wpacuAction === 'wp') {
122 add_action( 'wp', array( $this, 'frontendUpdate' ), 9 );
123 } else {
124 add_action( 'template_redirect', array( $this, 'frontendUpdate' ), 15 );
125 }
126 }
127
128 add_action('template_redirect', array($this, 'redirectAfterFrontEndUpdate'), 16);
129 }
130 }
131
132 /**
133 *
134 */
135 public function frontendUpdate()
136 {
137 $postId = 0;
138
139 if (Main::instance()->currentPostId > 0) {
140 $postId = Main::instance()->currentPostId;
141 }
142
143 // Check nonce
144 $nonceName = self::NONCE_FIELD_NAME;
145 $nonceAction = self::NONCE_ACTION_NAME;
146
147 $updateAction = Misc::getVar('post', 'wpacu_update_asset_frontend');
148
149 if ($updateAction != 1 || ! AssetsManager::instance()->frontendShow()) {
150 return;
151 }
152
153 // only for admins
154 if (! Menu::userCanAccessPlugin()) {
155 return;
156 }
157
158 if ( ! wp_verify_nonce($_POST[$nonceName], $nonceAction) ) {
159 wp_die(
160 $this->afterSubmitMsg['invalid_nonce_error'],
161 __('Nonce is missing or has expired', 'wp-asset-clean-up')
162 );
163 }
164
165 $this->frontEndUpdateTriggered = true;
166
167 // Was the Assets List Layout changed?
168 self::updateSettingsChangedOutsideTheMainArea();
169
170 // Form submitted from the homepage
171 // e.g. from a page such as latest blog posts, not a static page that was selected as home page
172 if (MainFront::isHomePage() && Misc::getShowOnFront() !== 'page') {
173 $wpacuNoLoadAssets = Misc::getVar('post', WPACU_PLUGIN_ID, array());
174
175 $this->updateFrontPage($wpacuNoLoadAssets);
176 return;
177 }
178
179 // Form submitted from a Singular Page
180 // e.g. post, page, custom post type such as 'product' page from WooCommerce, home page (static page selected as front page)
181
182 // Sometimes, there's a singular page set as 404 page (e.g. via "404page – your smart custom 404 error page" plugin)
183 if (is_404() && Misc::getVar('post', 'wpacu_is_singular_page')) {
184 $postId = (int)$_POST['wpacu_is_singular_page'];
185 }
186
187 if ($postId > 0) {
188 $this->savePosts($postId);
189 return;
190 }
191
192 // Any preloads
193 self::updatePreloads();
194
195 // Any handle notes?
196 self::updateHandleNotes();
197
198 // Any always load it if a user is logged in?
199 self::saveGlobalLoadExceptions();
200
201 // Any ignore deps
202 self::updateIgnoreChild();
203
204 self::clearTransients();
205 }
206
207 /**
208 * Specific changes can be applied to "Settings" outside its main area
209 * e.g. "Assets List Layout" can be updated within a CSS/JS manager; Its location is in "Settings" -- "Plugin Usage Preferences" -- "Assets List Layout")
210 */
211 public static function updateSettingsChangedOutsideTheMainArea()
212 {
213 // Was the Assets' List Layout changed?
214 if ($assetsListLayout = Misc::getVar('post', 'wpacu_assets_list_layout')) {
215 $settingsAdminClass = new SettingsAdmin();
216 $settingsAdminClass->updateOption('assets_list_layout', $assetsListLayout);
217 }
218
219 // Was the retrieval way changed for the CSS/JS list?
220 if ($domGetType = Misc::getVar('post', 'wpacu_dom_get_type')) {
221 $settingsAdminClass = new SettingsAdmin();
222 $settingsAdminClass->updateOption('dom_get_type', $domGetType);
223 }
224 }
225
226 /**
227 *
228 */
229 public function redirectAfterFrontEndUpdate()
230 {
231 // It triggers ONLY on front-end view, when a valid POST request is made
232 if (! $this->frontEndUpdateTriggered || is_admin() || ! Misc::getVar('post', 'wpacu_unload_assets_area_loaded')) {
233 return;
234 }
235
236 $parseUrl = parse_url($_SERVER['REQUEST_URI']);
237
238 $location = $parseUrl['path'];
239
240 $paramsToAdd = array(
241 'wpacu_time' => time(),
242 'nocache' => 'true',
243 'wpacu_updated' => 'true',
244 'wpacu_ignore_no_load_option' => 1
245 );
246
247 $extraParamsSign = '?';
248
249 if (isset($parseUrl['query']) && $parseUrl['query']) {
250 parse_str($parseUrl['query'], $existingQueryParams);
251
252 foreach (array_keys($paramsToAdd) as $paramKey) {
253 if ( isset( $existingQueryParams[$paramKey] ) ) {
254 unset( $existingQueryParams[$paramKey] );
255 }
256 }
257
258 if (! empty($existingQueryParams)) {
259 $location .= '?'.http_build_query($existingQueryParams);
260 $extraParamsSign = '&';
261 }
262 }
263
264 $location .= $extraParamsSign . http_build_query($paramsToAdd) . '#wpacu_wrap_assets';
265
266 set_transient(WPACU_PLUGIN_ID . '_frontend_assets_manager_just_updated', 1, 30);
267
268 wp_safe_redirect($location);
269 exit();
270 }
271
272 /**
273 * This could save the existent post and its associated posts if a plugin such as "WPML - The WordPress Multilingual Plugin" is used
274 * and there are languages associated with this post
275 *
276 * @param $postId
277 *
278 * @return void
279 */
280 public function savePosts($postId)
281 {
282 $allPostIdsToUpdate = apply_filters('wpacu_get_all_assoc_post_ids', $postId);
283
284 foreach ($allPostIdsToUpdate as $postIdToUpdate) {
285 $postObj = get_post( $postIdToUpdate );
286 $this->savePost( $postIdToUpdate, $postObj );
287 }
288 }
289
290 /**
291 * @param $postId
292 *
293 * @return array
294 */
295 public function getAllAssocPostIds($postId)
296 {
297 $allPostIds = array($postId); // default (original post ID)
298
299 // "WPML Multilingual CMS" compatibility: Syncing post changes on all its associated translated posts
300 // e.g. if a page in Spanish is having a CSS unloaded, then that unload will also apply for the German version of the page
301 // If, for any reason, one wants to stop syncing on translated pages, the following snippet could be used in functions.php (Child Theme)
302 // add_filter('wpacu_manage_assets_update_sync_wpml_translated_posts', '__return_false');
303 if ( wpacuIsPluginActive('sitepress-multilingual-cms/sitepress.php')
304 && apply_filters('wpacu_manage_assets_update_sync_wpml_translated_posts', true) ) {
305 $translations = self::getAnyAssocTranslationsForWpml($postId);
306
307 if ( ! empty($translations) ) {
308 foreach ( $translations as $translation ) {
309 if (isset($translation->element_id) && $translation->element_id) {
310 $allPostIds[] = (int) $translation->element_id;
311 }
312 }
313 }
314 }
315
316 return array_unique($allPostIds);
317 }
318
319 /**
320 * @param $elementId
321 * @param string $elementRefType
322 *
323 * @return mixed|null
324 */
325 public static function getAnyAssocTranslationsForWpml($elementId, $elementRefType = 'post')
326 {
327 global $wpdb;
328
329 // This may or might not be the main post which has the default language (usually English)
330 // and all other posts were created as an association with this language
331 // We'll need to check that
332 // Source: https://techoverflow.net/2017/03/08/get-the-original-language-post-id-for-wpml-translated-posts/
333 $elementRefTypeLengthForMySql = strlen($elementRefType) + 1;
334
335 $sqlQuery = <<<SQL
336 SELECT trans2.element_id, trans2.element_type
337 FROM `{$wpdb->prefix}icl_translations` AS trans1
338 INNER JOIN `{$wpdb->prefix}icl_translations` AS trans2 ON (trans2.trid = trans1.trid)
339 WHERE trans1.element_id = '%d'
340 AND SUBSTR(trans1.element_type, 1, {$elementRefTypeLengthForMySql}) = '%s'
341 AND trans2.source_language_code IS NULL
342 SQL;
343 $sqlQueryPrepared = $wpdb->prepare($sqlQuery, array($elementId, $elementRefType . '_'));
344
345 $result = $wpdb->get_row($sqlQueryPrepared, ARRAY_A);
346
347 if ( ! isset($result['element_type']) ) {
348 return array();
349 }
350
351 $type = apply_filters( 'wpml_element_type', $result['element_type'] );
352 $trId = apply_filters( 'wpml_element_trid', false, $elementId, $type );
353
354 return apply_filters( 'wpml_get_element_translations', array(), $trId, $type );
355 }
356
357 /**
358 * Save post metadata when a post is saved (not for the "Latest Blog Posts" home page type)
359 * Only for post type
360 *
361 * Dashboard view: triggered via hook
362 * Front-end view: triggered by direct call
363 *
364 * @param $postId
365 * @param mixed $post
366 */
367 public function savePost($postId, $post = '')
368 {
369 if (empty($post) || $post === '') {
370 global $post;
371 }
372
373 if ( ! isset( $post->ID, $post->post_type ) ) {
374 return;
375 }
376
377 // Has to be a public post type
378 $obj = get_post_type_object($post->post_type);
379
380 if ( ! isset($obj->public) || $obj->public < 1 ) {
381 return;
382 }
383
384 // only for admins
385 if (! Menu::userCanAccessPlugin()) {
386 return;
387 }
388
389 // Any page options set? From the Side Meta Box "Asset CleanUp: Options"
390 // Could be just these fields available in the form (e.g. unavailable CSS/JS manager due to the page set to not load the plugin at all)
391 $this->updatePageOptions($post->ID);
392
393 // This is triggered only if the "Asset CleanUp" meta box was loaded with the list of assets (either in edit post/page or in "CSS & JS Manager" -> "Manage CSS/JS")
394 // Otherwise, $_POST[WPACU_PLUGIN_ID] will be taken as empty which might be not if there are values in the database
395 if (! Misc::getVar('post', 'wpacu_unload_assets_area_loaded')) {
396 return;
397 }
398
399 $wpacuNoLoadAssets = Misc::getVar('post', WPACU_PLUGIN_ID, array());
400
401 if (is_array($wpacuNoLoadAssets)) {
402 global $wpdb;
403
404 $noUpdate = false;
405
406 // Is the list empty?
407 if (empty($wpacuNoLoadAssets)) {
408 // Remove any row with no results
409 $wpdb->delete(
410 $wpdb->postmeta,
411 array('post_id' => $postId, 'meta_key' => '_' . WPACU_PLUGIN_ID . '_no_load')
412 );
413 $noUpdate = true;
414 }
415
416 if (! $noUpdate) {
417 $jsonNoAssetsLoadList = wp_json_encode($wpacuNoLoadAssets);
418
419 if (! add_post_meta($postId, '_' . WPACU_PLUGIN_ID . '_no_load', $jsonNoAssetsLoadList, true)) {
420 update_post_meta($postId, '_' . WPACU_PLUGIN_ID . '_no_load', $jsonNoAssetsLoadList);
421 }
422 }
423 }
424
425 // Was the Assets' List Layout changed?
426 self::updateSettingsChangedOutsideTheMainArea();
427
428 // If globally disabled, make an exception to load for submitted assets
429 $this->saveLoadExceptions('post', $postId);
430 $this->saveLoadExceptionsPostType($post->post_type);
431
432 // Add / Remove Site-wide Unloads
433 $this->updateEverywhereUnloads();
434
435 // Any bulk unloads or removed? (e.g. all pages of a certain post type)
436 $this->saveToBulkUnloads($post);
437 $this->removeBulkUnloads($post->post_type);
438
439 // Any preloads
440 self::updatePreloads();
441
442 // Any handle notes
443 self::updateHandleNotes();
444
445 // Any always load it if user is logged in?
446 self::saveGlobalLoadExceptions();
447
448 // Any ignore deps
449 self::updateIgnoreChild();
450
451 add_action('wpacu_admin_notices', array($this, 'pageUpdated'));
452
453 self::clearTransients();
454
455 // In case Combine CSS/JS was enabled and there are traces of JSON files in the caching directory
456 // Clear them if the caching timing expired as they are not relevant anymore and reduce the disk's space
457 OptimizeCommon::clearItemStorageForPost($postId, true);
458
459 self::afterPostUpdate($postId);
460
461 // Note: Cache is cleared (except the JSON files related to CSS/JS combine option) after the post/page is updated via a separate AJAX call
462 // To avoid the usage of too much memory (good for shared environments) and avoid any memory related errors showing up to the user which could be confusing
463 }
464
465 /**
466 * This is to update the permalink for the post in "Page Options" if the following option was ever used for the post: "Do not load Asset CleanUp Pro on this page (this will disable any functionality of the plugin)"
467 * This takes action when the CSS/JS manager is updated for a specific post (e.g. post, page, attachment, custom post type)
468 *
469 * @param $postId
470 */
471 public static function afterPostUpdate($postId)
472 {
473 global $wpdb;
474
475 // The post might have the following page option: "Do not load Asset CleanUp Pro on this page (this will disable any functionality of the plugin)"
476 // If the admin changed the slug, we need to update the page URI as well that is used very early in the triggering of the plugin
477 // when get_permalink() is not available (e.g. outside any action hook or in the MU plugin)
478 $pageOptionJson = $wpdb->get_var( 'SELECT meta_value FROM `' . $wpdb->prefix . 'postmeta` WHERE post_id=\''.$postId.'\' && meta_key=\'_'.WPACU_PLUGIN_ID.'_page_options\' && meta_value LIKE \'%no_wpacu_load%\'' );
479
480 $postPageOptions = @json_decode($pageOptionJson, ARRAY_A);
481
482 if ( ! isset($postPageOptions['no_wpacu_load']) ) {
483 return;
484 }
485
486 $postPageOptions['_page_uri'] = Misc::getPageUri($postId);
487 update_post_meta($postId, '_' . WPACU_PLUGIN_ID . '_page_options', wp_json_encode(Misc::filterList($postPageOptions)));
488 }
489
490 /**
491 * @param $wpacuNoLoadAssets
492 */
493 public function updateFrontPage($wpacuNoLoadAssets)
494 {
495 // Any page options set? From the Side Meta Box "Asset CleanUp: Options"
496 // Could be just these fields available in the form (e.g. unavailable CSS/JS manager due to the page set to not load the plugin at all)
497 $this->updatePageOptions(0, 'front_page');
498
499 // Needed in case the user clicks "Update" on a page without assets retrieved
500 // Avoid resetting the existing values
501 if (! Misc::getVar('post', 'wpacu_unload_assets_area_loaded')) {
502 return;
503 }
504
505 if (! is_array($wpacuNoLoadAssets)) {
506 return; // only arrays (empty or not) should be used
507 }
508
509 // Was the Assets List Layout changed?
510 self::updateSettingsChangedOutsideTheMainArea();
511
512 $jsonNoAssetsLoadList = wp_json_encode( $wpacuNoLoadAssets );
513 Misc::addUpdateOption( WPACU_PLUGIN_ID . '_front_page_no_load', $jsonNoAssetsLoadList );
514
515 // If globally disabled, make an exception to load for submitted assets
516 $this->saveLoadExceptions('front_page');
517
518 // Add / Remove Site-wide Unloads
519 $this->updateEverywhereUnloads();
520
521 // Any preloads
522 self::updatePreloads();
523
524 // Any handle notes
525 self::updateHandleNotes();
526
527 // Any always load it if user is logged in?
528 self::saveGlobalLoadExceptions();
529
530 // Any ignore deps
531 self::updateIgnoreChild();
532
533 add_action('wpacu_admin_notices', array($this, 'homePageUpdated'));
534
535 $this->frontEndUpdateFor['homepage'] = true;
536
537 self::clearTransients();
538
539 // Clear all cache
540 // Note: The cache is cleared after the page is saved
541 }
542
543 /**
544 *
545 */
546 public function homePageUpdated()
547 {
548 ?>
549 <div class="updated notice wpacu-notice is-dismissible">
550 <p><?php echo wp_kses(
551 $this->afterSubmitMsg['homepage'],
552 array(
553 'style' => array(),
554 'class' => array(),
555 'strong' => array(),
556 'a' => array(
557 'target' => array(),
558 'href' => array()
559 )
560 )
561 ); ?></p>
562 </div>
563 <?php
564 }
565
566 /**
567 *
568 */
569 public function pageUpdated()
570 {
571 ?>
572 <div class="updated notice wpacu-notice is-dismissible">
573 <p><?php echo wp_kses(
574 $this->afterSubmitMsg['page'],
575 array(
576 'style' => array(),
577 'class' => array(),
578 'strong' => array(),
579 'a' => array(
580 'target' => array(),
581 'href' => array()
582 )
583 )
584 ); ?></p>
585 </div>
586 <?php
587 }
588
589 /**
590 *
591 */
592 public function changesNotMadeInvalidNonce()
593 {
594 ?>
595 <div class="notice wpacu-error is-dismissible">
596 <p><?php echo wp_kses(
597 $this->afterSubmitMsg['invalid_nonce_error'],
598 array(
599 'style' => array(),
600 'class' => array(),
601 'strong' => array(),
602 'a' => array(
603 'target' => array(),
604 'href' => array()
605 )
606 )
607 ); ?></p>
608 </div>
609 <?php
610 }
611
612 /**
613 * Lite: For Singular Page (Post, Page, Custom Post Type), Front Page (Home Page), On All Pages of a specific post type (post, page or custom)
614 * Pro: 'for_pro' would trigger the actions from the premium extension (if available)
615 * UPDATE: Since v1.2.9.5, no fallback for both the lite and pro version activated at the same time would work anymore
616 * Users need to only keep the PRO version since it's standalone since v1.0.3
617 *
618 * This is the function that clears and updates the load exceptions for any of the requested pages
619 *
620 * This method SHOULD NOT be triggered within an AJAX call
621 *
622 * @param string $type
623 * @param string $postId
624 */
625 public function saveLoadExceptions($type = 'post', $postId = '')
626 {
627 if ( $type === 'post' && ! $postId ) {
628 // $postId needs to have a value if $type is a 'post' type
629 return;
630 }
631
632 $loadExceptions = array('styles' => array(), 'scripts' => array());
633
634 // [Start] Clear existing list first
635 if ($type === 'post') {
636 delete_post_meta($postId, '_' . WPACU_PLUGIN_ID . '_load_exceptions');
637 } elseif ($type === 'front_page') {
638 delete_option( WPACU_PLUGIN_ID . '_front_page_load_exceptions');
639 }
640 // [End] Clear existing list first
641
642 // Load Exception
643 // On this page or page type such as 404, search, etc.
644 foreach (array('styles', 'scripts') as $assetType) {
645 $postKey = ($assetType === 'styles') ? 'wpacu_styles_load_it' : 'wpacu_scripts_load_it';
646 $optionsKey = ($assetType === 'styles') ? 'wpacu_options_styles' : 'wpacu_options_scripts';
647
648 if ( ! empty( $_POST[$postKey] ) ) {
649 foreach ( $_POST[$postKey] as $wpacuHandle ) {
650 // Do not append it if the global unload is removed
651 if ( isset( $_POST[$optionsKey][ $wpacuHandle ] )
652 && $_POST[$optionsKey][ $wpacuHandle ] === 'remove' ) {
653 continue;
654 }
655 $loadExceptions[$assetType][] = $wpacuHandle;
656 }
657 }
658 }
659
660 if (! empty($loadExceptions['styles']) || ! empty($loadExceptions['scripts'])) {
661 // Default
662 $list = array('styles' => array(), 'scripts' => array());
663
664 // Build list
665 foreach ( array('styles', 'scripts') as $assetType ) {
666 if ( ! empty( $loadExceptions[$assetType] ) ) {
667 foreach ( $loadExceptions[$assetType] as $postHandle ) {
668 $list[$assetType][] = $postHandle;
669 }
670 }
671
672 if (is_array($list[$assetType])) {
673 $list[$assetType] = array_unique($list[$assetType]);
674 }
675 }
676
677 $jsonLoadExceptions = wp_json_encode(Misc::filterList($list));
678
679 if ( $type === 'post' && (! add_post_meta($postId, '_' . WPACU_PLUGIN_ID . '_load_exceptions', $jsonLoadExceptions, true)) ) {
680 update_post_meta( $postId, '_' . WPACU_PLUGIN_ID . '_load_exceptions', $jsonLoadExceptions );
681 } elseif ($type === 'front_page') {
682 Misc::addUpdateOption( WPACU_PLUGIN_ID . '_front_page_load_exceptions', $jsonLoadExceptions );
683 }
684 }
685 }
686
687 /**
688 *
689 */
690 public function saveLoadExceptionsPostType($wpacuPostType)
691 {
692 // On all pages belonging to a (custom) post type (e.g. WooCommerce product page)
693 $referenceKey = WPACU_FORM_ASSETS_POST_KEY;
694
695 $loadExceptions = array('styles' => array(), 'scripts' => array());
696
697 // From v1.2.0.5
698 if (isset($_POST[$referenceKey]['styles']) || isset($_POST[$referenceKey]['scripts'])) {
699 foreach (array('styles', 'scripts') as $assetType) {
700 if ( ! empty( $_POST[ $referenceKey ][$assetType] ) ) {
701 foreach ( $_POST[ $referenceKey ][$assetType] as $assetHandle => $values ) {
702 $assetValue = isset( $values['load_it_post_type'] ) && $values['load_it_post_type'] ? $values['load_it_post_type'] : ''; // '1' or ''
703 $loadExceptions[$assetType][ $assetHandle ] = $assetValue;
704 }
705 }
706 }
707 } else {
708 // Prior to v1.2.0.5
709 foreach (array('styles', 'scripts') as $assetType) {
710 $indexKey = 'wpacu_'.$assetType.'_load_it_post_type';
711 if ( ! empty( $_POST[$indexKey] ) ) {
712 $wpacuPostType = key( $_POST[$indexKey] );
713 $loadExceptions[$assetType] = $_POST[$indexKey][ $wpacuPostType ];
714 }
715 }
716 }
717
718 if ((! empty($loadExceptions['styles']) || ! empty($loadExceptions['scripts'])) && (isset($wpacuPostType) && $wpacuPostType)) {
719 // Default
720 $listToSave = array( 'styles' => array(), 'scripts' => array() );
721
722 // Build list
723 foreach (array('styles', 'scripts') as $assetType) {
724 $listToSave[$assetType] = ( ! empty( $loadExceptions[$assetType] ) ) ? $loadExceptions[$assetType] : array();
725 }
726
727 $jsonLoadExceptionsToAdd = wp_json_encode(array($wpacuPostType => $listToSave));
728
729 $optionToUpdate = WPACU_PLUGIN_ID . '_post_type_load_exceptions';
730
731 $existingListEmpty = array( $wpacuPostType => array( 'styles' => array(), 'scripts' => array() ) );
732 $existingListJson = get_option($optionToUpdate);
733
734 $existingListData = Main::instance()->existingList($existingListJson, $existingListEmpty);
735 $existingList = $existingListData['list'];
736
737 if ( $existingListJson && is_array($existingList) && ! empty($existingList) ) {
738 if (isset($existingList[$wpacuPostType])) {
739 foreach ($listToSave as $assetType => $assetValues) {
740 foreach ($assetValues as $assetHandle => $assetValue) {
741 $existingList[ $wpacuPostType ][ $assetType ][ $assetHandle ] = $assetValue;
742 }
743 }
744 } else {
745 $existingList[$wpacuPostType] = $listToSave;
746 }
747
748 // Clear empty (redundant) values
749 foreach ($existingList as $wpacuPostTypeDb => $assetTypes) {
750 foreach ($assetTypes as $assetType => $assetValues) {
751 if (empty($assetValues)) {
752 unset($existingList[$wpacuPostTypeDb][$assetType]);
753 }
754
755 foreach ($assetValues as $assetHandle => $assetValue) {
756 if ( $assetValue === '' ) {
757 unset( $existingList[ $wpacuPostTypeDb ][ $assetType ][ $assetHandle ] );
758 }
759
760 if (empty($existingList[ $wpacuPostTypeDb ][ $assetType ])) {
761 unset( $existingList[$wpacuPostTypeDb][$assetType] );
762 }
763
764 if (empty($existingList[$wpacuPostTypeDb])) {
765 unset($existingList[$wpacuPostTypeDb]);
766 }
767 }
768 }
769 }
770
771 Misc::addUpdateOption( $optionToUpdate, wp_json_encode($existingList) );
772 } else {
773 Misc::addUpdateOption( $optionToUpdate, $jsonLoadExceptionsToAdd );
774 }
775 }
776 }
777
778 /**
779 * e.g. Always load the handle (if unloaded by any rule) if the user is logged-in (applies site-wide)
780 */
781 public static function saveGlobalLoadExceptions()
782 {
783 $optionToUpdate = WPACU_PLUGIN_ID . '_global_data';
784 $formTargetKey = 'wpacu_load_it_logged_in';
785 $targetGlobalKey = 'load_it_logged_in';
786
787 $referenceKey = WPACU_FORM_ASSETS_POST_KEY;
788
789 if (! Misc::isValidRequest('post', $referenceKey)) {
790 return;
791 }
792
793 if (! isset($_POST[$referenceKey]['styles']) && ! isset($_POST[$referenceKey]['scripts'])) {
794 return;
795 }
796
797 $existingListEmpty = array('styles' => array($targetGlobalKey => array()), 'scripts' => array($targetGlobalKey => array()));
798 $existingListJson = get_option($optionToUpdate);
799
800 $existingListData = Main::instance()->existingList($existingListJson, $existingListEmpty);
801 $existingList = $existingListData['list'];
802
803 foreach (array('styles', 'scripts') as $assetType) {
804 if ( ! empty( $_POST[ $referenceKey ][$assetType] ) ) {
805 foreach ( array_keys( $_POST[ $referenceKey ][$assetType] ) as $assetHandle ) {
806 // The checkbox was ticked (it's not empty)
807 $isSelected = isset( $_POST[$formTargetKey][$assetType][ $assetHandle ] ) && $_POST[$formTargetKey][$assetType][ $assetHandle ];
808
809 if ( $isSelected ) {
810 $existingList[$assetType][ $targetGlobalKey ][ $assetHandle ] = 1;
811 } else {
812 unset( $existingList[$assetType][ $targetGlobalKey ][ $assetHandle ] );
813
814 // Are there no values left? Remove the empty array (free space)
815 if (empty($existingList[$assetType][ $targetGlobalKey ])) {
816 unset($existingList[$assetType][ $targetGlobalKey ]);
817 }
818 }
819 }
820 }
821 }
822
823 Misc::addUpdateOption($optionToUpdate, wp_json_encode(Misc::filterList($existingList)));
824 }
825
826 /**
827 * This method should ONLY be triggered when the "Asset CleanUp: Options" area is visible
828 *
829 * @param $postId
830 * @param string $type
831 */
832 public function updatePageOptions($postId, $type = 'post')
833 {
834 // Is the "Asset CleanUp: Page Options" meta box not loaded?
835 // Then do not perform any update below
836 if ( ! Misc::getVar( 'post', 'wpacu_page_options_area_loaded', false ) ) {
837 return;
838 }
839
840 $pageOptions = Misc::getVar( 'post', WPACU_PLUGIN_ID . '_page_options', array() );
841
842 if ($type === 'post' || $postId > 0) {
843 /*
844 * For posts, pages, custom post types
845 */
846 // No page options? Delete any entry from the database to free up space
847 // instead of updating it as an empty entry
848 if ( empty( $pageOptions ) ) {
849 delete_post_meta( $postId, '_' . WPACU_PLUGIN_ID . '_page_options' );
850 return;
851 }
852
853 // Save the page URI as it's needed instead of get_permalink() that can't be called too early (e.g. outside an action hook or in a MU plugin)
854 $pageOptions['_page_uri'] = Misc::getPageUri($postId);
855
856 $pageOptionsJson = wp_json_encode( Misc::filterList($pageOptions) );
857
858 if ( ! add_post_meta( $postId, '_' . WPACU_PLUGIN_ID . '_page_options', $pageOptionsJson, true ) ) {
859 update_post_meta( $postId, '_' . WPACU_PLUGIN_ID . '_page_options', $pageOptionsJson );
860 }
861 } elseif ($type === 'front_page') {
862 /*
863 * For the homepage (e.g. the latest posts), but not a page set as homepage
864 */
865 $existingListJson = get_option(WPACU_PLUGIN_ID . '_global_data');
866 $existingListData = Main::instance()->existingList($existingListJson, array());
867 $existingList = $existingListData['list'];
868
869 $existingList['page_options']['homepage'] = $pageOptions;
870
871 Misc::addUpdateOption(WPACU_PLUGIN_ID . '_global_data', wp_json_encode(Misc::filterList($existingList)));
872 }
873 }
874
875 /**
876 * Triggers either "saveToEverywhereUnloads" or "removeEverywhereUnloads" methods
877 */
878 public function updateEverywhereUnloads()
879 {
880 /*
881 * Any global (all pages / everywhere) UNLOADS?
882 * Coming from a POST request
883 */
884 $reqStyles = Misc::getVar('post', 'wpacu_global_unload_styles', array());
885 $reqScripts = Misc::getVar('post', 'wpacu_global_unload_scripts', array());
886
887 $this->saveToEverywhereUnloads($reqStyles, $reqScripts);
888
889 /*
890 * Any global (all pages / everywhere) REMOVED?
891 * Coming from a POST request
892 */
893 $this->removeEverywhereUnloads(array(), array(), 'post');
894 }
895
896 /**
897 * @param array $reqStyles
898 * @param array $reqScripts
899 */
900 public function saveToEverywhereUnloads($reqStyles = array(), $reqScripts = array())
901 {
902 // Is there any entry already in JSON format?
903 $existingListJson = get_option(WPACU_PLUGIN_ID . '_global_unload');
904
905 // Default list as array
906 $existingListEmpty = array('styles' => array(), 'scripts' => array());
907
908 $existingListData = Main::instance()->existingList($existingListJson, $existingListEmpty);
909 $existingList = $existingListData['list'];
910
911 // Append to the list anything from the POST (if any)
912 if (! empty($reqStyles)) {
913 foreach ($reqStyles as $reqStyleHandle) {
914 $existingList['styles'][] = $reqStyleHandle;
915 }
916 }
917
918 if (! empty($reqScripts)) {
919 foreach ($reqScripts as $reqScriptHandle) {
920 $existingList['scripts'][] = $reqScriptHandle;
921 }
922 }
923
924 // Make sure all entries are unique (no handle duplicates)
925 foreach (array('styles', 'scripts') as $assetType) {
926 if ( isset( $existingList[$assetType] ) && is_array( $existingList[$assetType] ) ) {
927 $existingList[$assetType] = array_unique( $existingList[$assetType] );
928 }
929 }
930
931 Misc::addUpdateOption(WPACU_PLUGIN_ID . '_global_unload', wp_json_encode(Misc::filterList($existingList)));
932 }
933
934 /**
935 * @param array $stylesList
936 * @param array $scriptsList
937 * @param string $checkType
938 *
939 * @return bool
940 *
941 * @noinspection NestedAssignmentsUsageInspection
942 */
943 public function removeEverywhereUnloads($stylesList = array(), $scriptsList = array(), $checkType = '')
944 {
945 if ($checkType === 'post') {
946 $stylesList = Misc::getVar('post', 'wpacu_options_styles', array());
947 $scriptsList = Misc::getVar('post', 'wpacu_options_scripts', array());
948 }
949
950 $removeStylesList = $removeScriptsList = array();
951
952 $isUpdated = false;
953
954 if (! empty($stylesList)) {
955 foreach ($stylesList as $handle => $action) {
956 if ($action === 'remove') {
957 $removeStylesList[] = $handle;
958 }
959 }
960 }
961
962 if (! empty($scriptsList)) {
963 foreach ($scriptsList as $handle => $action) {
964 if ($action === 'remove') {
965 $removeScriptsList[] = $handle;
966 }
967 }
968 }
969
970 $existingListJson = get_option(WPACU_PLUGIN_ID . '_global_unload');
971
972 if (! $existingListJson) {
973 return false;
974 }
975
976 $existingList = json_decode($existingListJson, true);
977
978 if (wpacuJsonLastError() === JSON_ERROR_NONE) {
979 foreach (array('styles', 'scripts') as $assetType) {
980 if ($assetType === 'styles') {
981 $list = $removeStylesList;
982 } elseif ($assetType === 'scripts') {
983 $list = $removeScriptsList;
984 }
985
986 if (empty($list)) {
987 continue;
988 }
989
990 foreach ($list as $handle) {
991 $handleKey = isset($existingList[$assetType]) ? array_search($handle, $existingList[$assetType]) : false;
992
993 if ($handleKey !== false) {
994 unset($existingList[$assetType][$handleKey]);
995 $isUpdated = true;
996 }
997 }
998 }
999
1000 if ($isUpdated) {
1001 Misc::addUpdateOption(WPACU_PLUGIN_ID . '_global_unload', wp_json_encode(Misc::filterList($existingList)));
1002 }
1003 }
1004
1005 return $isUpdated;
1006 }
1007
1008 /**
1009 * @param string $post
1010 */
1011 public function saveToBulkUnloads($post = '')
1012 {
1013 if ($post === '') {
1014 global $post;
1015 }
1016
1017 $postType = isset( $post->post_type ) ? $post->post_type : false;
1018
1019 // Free Version: It only deals with 'post_type' bulk unloads
1020 if ( ! $postType ) {
1021 return;
1022 }
1023
1024 $postStyles = Misc::getVar('post', 'wpacu_bulk_unload_styles', array());
1025 $postScripts = Misc::getVar('post', 'wpacu_bulk_unload_scripts', array());
1026
1027 // Is there any entry already in JSON format?
1028 $existingListJson = get_option( WPACU_PLUGIN_ID . '_bulk_unload');
1029
1030 // Default list as array
1031 $existingListEmpty = array(
1032 'styles' => array('post_type' => array($postType => array())),
1033 'scripts' => array('post_type' => array($postType => array()))
1034 );
1035
1036 $existingListData = Main::instance()->existingList($existingListJson, $existingListEmpty);
1037 $existingList = $existingListData['list'];
1038
1039 // Append to the list anything from the POST (if any)
1040 // Make sure all entries are unique (no handle duplicates)
1041 $list = array();
1042
1043 foreach (array('styles', 'scripts') as $assetType) {
1044 if ($assetType === 'styles') {
1045 $list = $postStyles;
1046 } elseif ($assetType === 'scripts') {
1047 $list = $postScripts;
1048 }
1049
1050 if (empty($list)) {
1051 continue;
1052 }
1053
1054 foreach ($list as $bulkType => $values) {
1055 if (empty($values)) {
1056 continue;
1057 }
1058
1059 if ($bulkType === 'post_type') {
1060 foreach ($values as $postType => $handles) {
1061 if (empty($handles)) {
1062 continue;
1063 }
1064
1065 foreach (array_unique($handles) as $handle) {
1066 $existingList[ $assetType ]['post_type'][ $postType ][] = $handle;
1067 }
1068
1069 $existingList[ $assetType ]['post_type'][ $postType ] = array_unique($existingList[ $assetType ]['post_type'][ $postType ]);
1070 }
1071 }
1072 }
1073 }
1074
1075 Misc::addUpdateOption( WPACU_PLUGIN_ID . '_bulk_unload', wp_json_encode(Misc::filterList($existingList)));
1076 }
1077
1078 /**
1079 * Lite Version: For post, pages, custom post types
1080 *
1081 * @param mixed $value
1082 *
1083 * @return bool
1084 * @noinspection NestedAssignmentsUsageInspection
1085 */
1086 public function removeBulkUnloads($value = '')
1087 {
1088 if ( ! $value ) {
1089 global $post;
1090
1091 // In the LITE version, post type unload is the only option for bulk unloads
1092 // $postType could be 'post', 'page' or a custom post type such as 'product' (WooCommerce), 'download' (Easy Digital Downloads), etc.
1093 $value = isset($post->post_type) ? $post->post_type : false;
1094
1095 if ( ! $value ) {
1096 return false;
1097 }
1098 }
1099
1100 $bulkType = 'post_type';
1101
1102 $stylesList = Misc::getVar('post', 'wpacu_options_'.$bulkType.'_styles', array());
1103 $scriptsList = Misc::getVar('post', 'wpacu_options_'.$bulkType.'_scripts', array());
1104
1105 if (empty($stylesList) && empty($scriptsList)) {
1106 return false;
1107 }
1108
1109 $removeStylesList = $removeScriptsList = array();
1110
1111 $isUpdated = false;
1112
1113 if (! empty($stylesList)) {
1114 foreach ($stylesList as $handle => $action) {
1115 if ($action === 'remove') {
1116 $removeStylesList[] = $handle;
1117 }
1118 }
1119 }
1120
1121 if (! empty($scriptsList)) {
1122 foreach ($scriptsList as $handle => $action) {
1123 if ($action === 'remove') {
1124 $removeScriptsList[] = $handle;
1125 }
1126 }
1127 }
1128
1129 $existingListJson = get_option( WPACU_PLUGIN_ID . '_bulk_unload');
1130
1131 if (! $existingListJson) {
1132 return false;
1133 }
1134
1135 $existingList = json_decode($existingListJson, true);
1136
1137 if (wpacuJsonLastError() === JSON_ERROR_NONE) {
1138 $list = array();
1139
1140 foreach (array('styles', 'scripts') as $assetType) {
1141 if ($assetType === 'styles') {
1142 $list = $removeStylesList;
1143 } elseif ($assetType === 'scripts') {
1144 $list = $removeScriptsList;
1145 }
1146
1147 if (empty($list)) {
1148 continue;
1149 }
1150
1151 foreach ($existingList[$assetType][$bulkType][$value] as $handleKey => $handle) {
1152 if (in_array($handle, $list)) {
1153 unset($existingList[$assetType][$bulkType][$value][$handleKey]);
1154 $isUpdated = true;
1155 }
1156 }
1157 }
1158
1159 Misc::addUpdateOption(WPACU_PLUGIN_ID . '_bulk_unload', wp_json_encode(Misc::filterList($existingList)));
1160 }
1161
1162 return $isUpdated;
1163 }
1164
1165 /**
1166 *
1167 */
1168 public static function updatePreloads()
1169 {
1170 $useGlobalPost = false;
1171
1172 if ( ( ! empty($_POST[WPACU_FORM_ASSETS_POST_KEY]['styles']) ) || ( ! empty($_POST[WPACU_FORM_ASSETS_POST_KEY]['scripts']) ) ) {
1173 $mainVarToUse = self::updatePreloadsAdapt($_POST[WPACU_FORM_ASSETS_POST_KEY]); // New form fields (starting from v1.1.9.9)
1174 } elseif (Misc::isValidRequest('post', 'wpacu_preloads')) {
1175 $useGlobalPost = true;
1176 } else {
1177 return;
1178 }
1179
1180 if (! $useGlobalPost && isset($mainVarToUse['wpacu_preloads'])) {
1181 $bucketToUse = $mainVarToUse['wpacu_preloads'];
1182 } elseif (isset($_POST['wpacu_preloads'])) {
1183 $bucketToUse = $_POST['wpacu_preloads'];
1184 }
1185
1186 if (! isset($bucketToUse['styles']) && ! isset($bucketToUse['scripts'])) {
1187 return;
1188 }
1189
1190 $optionToUpdate = WPACU_PLUGIN_ID . '_global_data';
1191 $globalKey = 'preloads';
1192
1193 $existingListEmpty = array('styles' => array($globalKey => array()), 'scripts' => array($globalKey => array()));
1194 $existingListJson = get_option($optionToUpdate);
1195
1196 $existingListData = Main::instance()->existingList($existingListJson, $existingListEmpty);
1197 $existingList = $existingListData['list'];
1198
1199 foreach (array('styles', 'scripts') as $assetType) {
1200 if ( ! empty( $bucketToUse[$assetType] ) ) {
1201 foreach ( $bucketToUse[$assetType] as $assetHandle => $assetPreload ) {
1202 $assetPreload = trim( $assetPreload );
1203
1204 if ( $assetPreload === '' && isset( $existingList[$assetType][ $globalKey ][ $assetHandle ] ) ) {
1205 unset( $existingList[$assetType][ $globalKey ][ $assetHandle ] );
1206 } elseif ( $assetPreload !== '' ) {
1207 $existingList[$assetType][ $globalKey ][ $assetHandle ] = $assetPreload;
1208 }
1209 }
1210 }
1211 }
1212
1213 Misc::addUpdateOption($optionToUpdate, wp_json_encode(Misc::filterList($existingList)));
1214 }
1215
1216 /**
1217 * @param $mainFormArray
1218 *
1219 * @return array
1220 */
1221 public static function updatePreloadsAdapt($mainFormArray)
1222 {
1223 $wpacuPreloadsList = array();
1224
1225 foreach (array('styles', 'scripts') as $assetKey) {
1226 if ( ! empty($mainFormArray[$assetKey]) ) {
1227 foreach ($mainFormArray[$assetKey] as $assetHandle => $assetData) {
1228 $wpacuPreloadsList['wpacu_preloads'][$assetKey][$assetHandle] = ''; // default
1229
1230 if (isset($assetData['preload']) && $assetData['preload']) {
1231 $wpacuPreloadsList['wpacu_preloads'][ $assetKey ][ $assetHandle ] = $assetData['preload']; // 'basic' or 'async'
1232 }
1233 }
1234 }
1235 }
1236
1237 return $wpacuPreloadsList;
1238 }
1239
1240 /**
1241 *
1242 */
1243 public static function updateHandleNotes()
1244 {
1245 if (! Misc::isValidRequest('post', 'wpacu_handle_notes')) {
1246 return;
1247 }
1248
1249 if (! isset($_POST['wpacu_handle_notes']['styles']) && ! isset($_POST['wpacu_handle_notes']['scripts'])) {
1250 return;
1251 }
1252
1253 $optionToUpdate = WPACU_PLUGIN_ID . '_global_data';
1254 $globalKey = 'notes';
1255
1256 $existingListEmpty = array('styles' => array($globalKey => array()), 'scripts' => array($globalKey => array()));
1257 $existingListJson = get_option($optionToUpdate);
1258
1259 $existingListData = Main::instance()->existingList($existingListJson, $existingListEmpty);
1260 $existingList = $existingListData['list'];
1261
1262 foreach (array('styles', 'scripts') as $assetType) {
1263 if ( ! empty( $_POST['wpacu_handle_notes'][$assetType] ) ) {
1264 foreach ( $_POST['wpacu_handle_notes'][$assetType] as $assetHandle => $assetNote ) {
1265 $assetNote = stripslashes( $assetNote );
1266
1267 if ( $assetNote === '' && isset( $existingList[$assetType][ $globalKey ][ $assetHandle ] ) ) {
1268 unset( $existingList[$assetType][ $globalKey ][ $assetHandle ] );
1269 } elseif ( $assetNote !== '' ) {
1270 $existingList[$assetType][ $globalKey ][ $assetHandle ] = $assetNote;
1271 }
1272 }
1273 }
1274 }
1275
1276 Misc::addUpdateOption($optionToUpdate, wp_json_encode(Misc::filterList($existingList)));
1277 }
1278
1279 /**
1280 * @param array $mainVarToUse
1281 */
1282 public static function updateIgnoreChild($mainVarToUse = array())
1283 {
1284 // No $mainVarToUse passed? Then it's a $_POST
1285 // Check if $_POST is empty via Misc::isValidRequest()
1286 $useGlobalPost = false;
1287
1288 if (empty($mainVarToUse)) {
1289 if ( ( ! empty($_POST[WPACU_FORM_ASSETS_POST_KEY]['styles']) ) || ( ! empty($_POST[WPACU_FORM_ASSETS_POST_KEY]['scripts']) ) ) {
1290 $mainVarToUse = self::updateIgnoreChildAdapt($_POST[WPACU_FORM_ASSETS_POST_KEY]); // New form fields (starting from v1.1.9.9)
1291 } elseif (Misc::isValidRequest('post', 'wpacu_ignore_child')) {
1292 $useGlobalPost = true;
1293 } else {
1294 return;
1295 }
1296 }
1297
1298 if (! $useGlobalPost && isset($mainVarToUse['wpacu_ignore_child'])) {
1299 $bucketToUse = $mainVarToUse['wpacu_ignore_child'];
1300 } elseif (isset($_POST['wpacu_ignore_child'])) {
1301 $bucketToUse = $_POST['wpacu_ignore_child'];
1302 }
1303
1304 if (! isset($bucketToUse['styles']) && ! isset($bucketToUse['scripts'])) {
1305 return;
1306 }
1307
1308 $optionToUpdate = WPACU_PLUGIN_ID . '_global_data';
1309 $globalKey = 'ignore_child';
1310
1311 $existingListEmpty = array('styles' => array($globalKey => array()), 'scripts' => array($globalKey => array()));
1312 $existingListJson = get_option($optionToUpdate);
1313
1314 $existingListData = Main::instance()->existingList($existingListJson, $existingListEmpty);
1315 $existingList = $existingListData['list'];
1316
1317 foreach (array('styles','scripts') as $assetType) {
1318 if ( ! empty( $bucketToUse[$assetType] ) ) {
1319 foreach ( $bucketToUse[$assetType] as $assetHandle => $assetVal ) {
1320 $assetVal = trim( $assetVal );
1321
1322 if ( $assetVal === '' && isset( $existingList[$assetType][ $globalKey ][ $assetHandle ] ) ) {
1323 unset( $existingList[$assetType][ $globalKey ][ $assetHandle ] );
1324 } elseif ( $assetVal !== '' ) {
1325 $existingList[$assetType][ $globalKey ][ $assetHandle ] = $assetVal;
1326 }
1327 }
1328 }
1329 }
1330
1331 Misc::addUpdateOption($optionToUpdate, wp_json_encode(Misc::filterList($existingList)));
1332 }
1333
1334 /**
1335 * @param $mainFormArray
1336 *
1337 * @return array
1338 */
1339 public static function updateIgnoreChildAdapt($mainFormArray)
1340 {
1341 $wpacuIgnoreChildList = array();
1342
1343 foreach (array('styles', 'scripts') as $assetKey) {
1344 if ( ! empty($mainFormArray[$assetKey]) ) {
1345 foreach ($mainFormArray[$assetKey] as $assetHandle => $assetData) {
1346 $wpacuIgnoreChildList['wpacu_ignore_child'][$assetKey][$assetHandle] = ''; // default
1347
1348 if (isset($assetData['ignore_child']) && $assetData['ignore_child']) {
1349 $wpacuIgnoreChildList['wpacu_ignore_child'][ $assetKey ][ $assetHandle ] = 1;
1350 }
1351 }
1352 }
1353 }
1354
1355 return $wpacuIgnoreChildList;
1356 }
1357
1358 /**
1359 * This function is called via AJAX whenever "+" or "-" is used on an asset's row
1360 *
1361 * @param $newState
1362 * @param $handle
1363 * @param $handleFor
1364 *
1365 * @return array|false
1366 */
1367 public static function updateHandleRowStatus($newState, $handle, $handleFor)
1368 {
1369 $optionToUpdate = WPACU_PLUGIN_ID . '_global_data';
1370 $globalKey = 'handle_row_contracted'; // Contracted or Expanded (default)
1371
1372 $existingListEmpty = array('styles' => array($globalKey => array()), 'scripts' => array($globalKey => array()));
1373 $existingListJson = get_option($optionToUpdate);
1374
1375 $existingListData = Main::instance()->existingList($existingListJson, $existingListEmpty);
1376 $existingList = $existingListData['list'];
1377
1378 if ($handleFor === 'style') {
1379 $keyList = 'styles';
1380 } elseif ($handleFor === 'script') {
1381 $keyList = 'scripts';
1382 } else {
1383 return false;
1384 }
1385
1386 // The database value should be equal with '1' suggesting it's contracted (no value means it's expanded by default)
1387 if ( $newState === 'expanded' && isset( $existingList[$keyList][ $globalKey ][ $handle ] ) ) {
1388 unset( $existingList[$keyList][ $globalKey ][ $handle ] ); // "expanded" (default)
1389 } elseif ( $newState === 'contracted' ) {
1390 $existingList[$keyList][ $globalKey ][ $handle ] = 1; // "contracted"
1391 }
1392
1393 Misc::addUpdateOption($optionToUpdate, wp_json_encode(Misc::filterList($existingList)));
1394
1395 $toReturn = array();
1396
1397 if (isset($existingList['styles'][$globalKey])) {
1398 $toReturn['styles'] = $existingList['styles'][$globalKey];
1399 }
1400
1401 if (isset($existingList['scripts'][$globalKey])) {
1402 $toReturn['scripts'] = $existingList['scripts'][$globalKey];
1403 }
1404
1405 return $toReturn;
1406 }
1407
1408 /**
1409 * This is triggered automatically and sets a transient with the handles info
1410 * It doesn't require any manual action from the user
1411 *
1412 * @param $assetList
1413 */
1414 public static function updateHandlesInfo($assetList)
1415 {
1416 $optionToUpdate = WPACU_PLUGIN_ID . '_global_data';
1417 $globalKey = 'assets_info';
1418
1419 $existingListEmpty = array('styles' => array($globalKey => array()), 'scripts' => array($globalKey => array()));
1420 $existingListJson = get_option($optionToUpdate);
1421
1422 $existingListData = Main::instance()->existingList($existingListJson, $existingListEmpty);
1423 $existingList = $existingListData['list'];
1424
1425 // $assetKey could be 'styles' or 'scripts'
1426 foreach ($assetList as $assetType => $assetDataHandleList) {
1427 if (empty($assetDataHandleList) || ! in_array($assetType, array('styles', 'scripts'))) {
1428 continue;
1429 }
1430
1431 foreach ($assetDataHandleList as $assetObj) {
1432 $assetArray = (array)$assetObj;
1433
1434 $handleMaybeAliases = Main::maybeAssignUniqueHandleName($assetArray['handle'], 'scripts');
1435 $assetHandle = $handleMaybeAliases['handle_ref'];
1436
1437 // Strip other unused information including the 'handle' (no need to have it twice as it's already in one of the array's keys)
1438 unset( $assetArray['handle'], $assetArray['textdomain'], $assetArray['translations_path'] );
1439
1440 // Some handles don't have a "src" value such as "woocommerce-inline"
1441 if (isset($assetArray['src']) && $assetArray['src']) {
1442 $assetArray['src'] = Misc::assetFromHrefToRelativeUri( $assetArray['src'], $assetType );
1443 }
1444
1445 $existingList[$assetType][$globalKey][$assetHandle] = $assetArray;
1446 }
1447 }
1448
1449 update_option($optionToUpdate, wp_json_encode(Misc::filterList($existingList)));
1450 }
1451
1452 /**
1453 *
1454 */
1455 public static function clearTransients()
1456 {
1457 delete_transient(WPACU_PLUGIN_ID. '_total_unloaded_assets_all');
1458 delete_transient(WPACU_PLUGIN_ID. '_total_unloaded_assets_per_page');
1459 }
1460
1461 /**
1462 * This is triggered when /admin/admin-ajax.php is called (default WordPress AJAX handler)
1463 */
1464 public function ajaxClearCache()
1465 {
1466 if ( ! isset($_REQUEST['wpacu_nonce']) ) {
1467 echo 'Error: The security nonce was not sent for verification. Location: '.__METHOD__;
1468 return;
1469 }
1470
1471 if ( ! wp_verify_nonce($_REQUEST['wpacu_nonce'], 'wpacu_ajax_clear_cache_nonce') ) {
1472 echo 'Error: The security check has failed. Location: '.__METHOD__;
1473 exit();
1474 }
1475
1476 if (! Menu::userCanAccessPlugin()) {
1477 echo 'Error: Not enough privileges to clear the cache.';
1478 exit();
1479 }
1480
1481 OptimizeCommon::clearCache();
1482
1483 exit();
1484 }
1485
1486 /**
1487 * @return void
1488 */
1489 public function ajaxCacheEnablerClearCache()
1490 {
1491 if ( ! isset($_REQUEST['wpacu_nonce']) ) {
1492 echo 'Error: The security nonce was not sent for verification. Location: '.__METHOD__;
1493 return;
1494 }
1495
1496 if ( ! wp_verify_nonce($_REQUEST['wpacu_nonce'], 'wpacu_ajax_clear_cache_enabler_cache_nonce') ) {
1497 echo 'Error: The security check has failed. Location: '.__METHOD__;
1498 exit();
1499 }
1500
1501 if (! Menu::userCanAccessPlugin()) {
1502 echo 'Error: Not enough privileges to clear the cache.';
1503 exit();
1504 }
1505
1506 OptimizeCommon::clearCacheEnablerCache('ajax_call');
1507 }
1508
1509 /**
1510 * This is triggered when /admin/admin-ajax.php is called (default WordPress AJAX handler)
1511 */
1512 public function ajaxPreloadGuest()
1513 {
1514 // Check nonce
1515 if ( ! isset( $_POST['wpacu_nonce'] ) || ! wp_verify_nonce( $_POST['wpacu_nonce'], 'wpacu_ajax_preload_url_nonce' ) ) {
1516 echo 'Error: The security nonce is not valid.';
1517 exit();
1518 }
1519
1520 $pageUrl = isset($_POST['page_url']) ? $_POST['page_url'] : false;
1521 $pageUrlDomain = parse_url($pageUrl, PHP_URL_HOST);
1522 $pageUrlPreload = add_query_arg( array( 'wpacu_preload' => 1 ), $pageUrl );
1523
1524 // Check if the URL is valid
1525 if (! filter_var($pageUrlPreload, FILTER_VALIDATE_URL)) {
1526 echo 'The URL `'.$pageUrlPreload.'` is not valid.';
1527 exit();
1528 }
1529
1530 // Check the domain from "page_url" parameter
1531 if (strpos(site_url(), $pageUrlDomain) === false) {
1532 echo 'Error: Possible hacking attempt! The host name of the requested URL is not the same as the one of "Site Address (URL)" from "Settings" - "General".';
1533 exit();
1534 }
1535
1536 // Check privileges
1537 if (! Menu::userCanAccessPlugin()) {
1538 echo 'Error: Not enough privileges to perform this action.';
1539 exit();
1540 }
1541
1542 $response = wp_remote_get($pageUrlPreload);
1543
1544 if (is_wp_error($response)) {
1545 // Any error generated during the fetch? Print it
1546 echo 'Error: '.$response->get_error_code();
1547 } else {
1548 // No errors
1549 echo 'Status Code: '.wp_remote_retrieve_response_code($response).' / Page URL (preload): ' . $pageUrlPreload . "\n\n";
1550 echo isset($response['body']) ? $response['body'] : 'No "body" key found from wp_remote_get(), the preload might not have triggered';
1551 }
1552
1553 exit();
1554 }
1555
1556 /**
1557 *
1558 */
1559 public function ajaxUpdateAssetRowState()
1560 {
1561 // Option: "On Assets List Layout Load, keep the groups:"
1562 if (isset($_POST['wpacu_update_asset_row_state'])) {
1563 if ( ! isset( $_POST['action'], $_POST['wpacu_asset_row_state'], $_POST['wpacu_handle'], $_POST['wpacu_handle_for'] )
1564 || ! Menu::userCanAccessPlugin() ) {
1565 return;
1566 }
1567
1568 if ( $_POST['wpacu_update_asset_row_state'] !== 'yes' ) {
1569 return;
1570 }
1571
1572 if ( ! isset($_POST['wpacu_nonce']) ) {
1573 echo 'Error: The security nonce was not sent for verification. Location: '.__METHOD__;
1574 return;
1575 }
1576
1577 if ( ! wp_verify_nonce($_POST['wpacu_nonce'], 'wpacu_update_asset_row_state_nonce') ) {
1578 echo 'Error: The security check has failed. Location: '.__METHOD__;
1579 return;
1580 }
1581
1582 $assetRowState = $_POST['wpacu_asset_row_state'];
1583
1584 $newContractedList = self::updateHandleRowStatus($assetRowState, $_POST['wpacu_handle'], $_POST['wpacu_handle_for']);
1585
1586 echo "<pre>" . print_r($newContractedList, true);
1587 }
1588
1589 exit();
1590 }
1591
1592 /**
1593 * Update state for all assets within a plugin
1594 *
1595 * @return void
1596 */
1597 public function ajaxAreaUpdateAssetsRowState()
1598 {
1599 if (isset($_POST['wpacu_area_update_assets_row_state'])) {
1600 if ( ! isset( $_POST['action'], $_POST['wpacu_area_assets_row_state'], $_POST['wpacu_area_handles'], $_POST['wpacu_nonce'] )
1601 || ! Menu::userCanAccessPlugin() ) {
1602 return;
1603 }
1604
1605 if ( $_POST['wpacu_area_update_assets_row_state'] !== 'yes' ) {
1606 return;
1607 }
1608
1609 if ( ! isset($_POST['wpacu_nonce']) ) {
1610 echo 'Error: The security nonce was not sent for verification. Location: '.__METHOD__;
1611 return;
1612 }
1613
1614 if ( ! wp_verify_nonce($_POST['wpacu_nonce'], 'wpacu_area_update_assets_row_state_nonce') ) {
1615 echo 'Error: The security check has failed. Location: '.__METHOD__;
1616 return;
1617 }
1618
1619 $areaAllAssetsRowState = $_POST['wpacu_area_assets_row_state'];
1620
1621 if ( ! empty($_POST['wpacu_area_handles']) && is_array($_POST['wpacu_area_handles']) ) {
1622 foreach ($_POST['wpacu_area_handles'] as $areaAssetHandleFormat) {
1623 $areaAssetHandleFor = substr(strrchr($areaAssetHandleFormat, '_'), 1);
1624 $areaAssetHandle = substr($areaAssetHandleFormat, 0, -(strlen($areaAssetHandleFor) + 1));
1625
1626 echo 'New State: '.$areaAllAssetsRowState.' / Handle: '.$areaAssetHandle . ' / For: '.$areaAssetHandleFor."\n";
1627
1628 $newContractedList = self::updateHandleRowStatus( $areaAllAssetsRowState, $areaAssetHandle, $areaAssetHandleFor );
1629 echo "<pre>" . print_r( $newContractedList, true );
1630 }
1631 }
1632
1633 exit();
1634 }
1635 }
1636 }
1637