| @@ -6,8 +6,9 @@ | ||
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | namespace PoweredCache\Utils; |
| 9 | 9 | |
| 10 | +use PoweredCache\Encryption; | |
| 10 | 11 | use const PoweredCache\Constants\SETTING_OPTION; |
| 11 | 12 | use RecursiveDirectoryIterator; |
| 12 | 13 | use RecursiveIteratorIterator; |
| 13 | 14 | |
| @@ -42,92 +43,126 @@ | ||
| 42 | 43 | * @return array |
| 43 | 44 | * @since 2.0 |
| 44 | 45 | */ |
| 45 | 46 | function get_settings( $force_network_wide = false ) { |
| 47 | + global $is_apache; | |
| 48 | + | |
| 46 | 49 | $settings = [ |
| 47 | 50 | // basic options |
| 48 | - 'enable_page_cache' => true, | |
| 49 | - 'object_cache' => 'off', | |
| 50 | - 'cache_mobile' => true, | |
| 51 | - 'cache_mobile_separate_file' => false, | |
| 52 | - 'loggedin_user_cache' => false, | |
| 53 | - 'ssl_cache' => true, // deprecated | |
| 54 | - 'gzip_compression' => false, | |
| 55 | - 'cache_timeout' => 1440, | |
| 51 | + 'enable_page_cache' => true, | |
| 52 | + 'object_cache' => 'off', | |
| 53 | + 'cache_mobile' => true, | |
| 54 | + 'cache_mobile_separate_file' => false, | |
| 55 | + 'loggedin_user_cache' => false, | |
| 56 | + 'ssl_cache' => true, // deprecated | |
| 57 | + 'gzip_compression' => false, | |
| 58 | + 'cache_timeout' => 1440, | |
| 56 | 59 | // advanced options |
| 57 | - 'auto_configure_htaccess' => true, | |
| 58 | - 'rejected_user_agents' => '', | |
| 59 | - 'rejected_cookies' => '', | |
| 60 | - 'vary_cookies' => '', | |
| 61 | - 'rejected_uri' => '', | |
| 62 | - 'accepted_query_strings' => '', | |
| 63 | - 'purge_additional_pages' => '', | |
| 60 | + 'auto_configure_htaccess' => $is_apache, | |
| 61 | + 'rejected_user_agents' => '', | |
| 62 | + 'rejected_cookies' => '', | |
| 63 | + 'rejected_referrers' => '', | |
| 64 | + 'vary_cookies' => '', | |
| 65 | + 'rejected_uri' => '', | |
| 66 | + 'ignored_query_strings' => '', | |
| 67 | + 'cache_query_strings' => '', | |
| 68 | + 'purge_additional_pages' => '', | |
| 64 | 69 | // file optimization |
| 65 | - 'minify_html' => false, | |
| 66 | - 'combine_google_fonts' => false, | |
| 67 | - 'minify_css' => false, | |
| 68 | - 'combine_css' => false, | |
| 69 | - 'excluded_css_files' => '', | |
| 70 | - 'minify_js' => false, | |
| 71 | - 'combine_js' => false, | |
| 72 | - 'excluded_js_files' => '', | |
| 73 | - 'js_execution_method' => 'blocking', | |
| 74 | - 'js_execution_optimized_only' => true, | |
| 70 | + 'minify_html' => false, | |
| 71 | + 'minify_html_dom_optimization' => false, | |
| 72 | + 'combine_google_fonts' => false, | |
| 73 | + 'swap_google_fonts_display' => true, | |
| 74 | + 'use_bunny_fonts' => false, | |
| 75 | + 'minify_css' => false, | |
| 76 | + 'combine_css' => false, | |
| 77 | + 'critical_css' => false, | |
| 78 | + 'critical_css_additional_files' => '', | |
| 79 | + 'critical_css_excluded_files' => '', | |
| 80 | + 'critical_css_appended_content' => '', | |
| 81 | + 'critical_css_fallback' => '', | |
| 82 | + 'excluded_css_files' => '', | |
| 83 | + 'remove_unused_css' => false, | |
| 84 | + 'ucss_safelist' => '', | |
| 85 | + 'ucss_excluded_files' => '', | |
| 86 | + 'minify_js' => false, | |
| 87 | + 'combine_js' => false, | |
| 88 | + 'excluded_js_files' => '', | |
| 89 | + 'js_execution_method' => 'blocking', // deprecated @since 3.2 | |
| 90 | + 'js_defer' => false, | |
| 91 | + 'js_defer_exclusions' => '', | |
| 92 | + 'js_delay' => false, | |
| 93 | + 'js_delay_exclusions' => '', | |
| 94 | + 'js_delay_timeout' => 0, | |
| 95 | + 'js_execution_optimized_only' => true, // deprecated @since 3.2 | |
| 96 | + 'rewrite_file_optimizer' => $is_apache, | |
| 75 | 97 | // media optimization |
| 98 | + 'enable_image_optimization' => false, | |
| 99 | + 'image_optimizer_preferred_format' => '', | |
| 100 | + 'add_missing_image_dimensions' => false, | |
| 76 | 101 | // lazyload |
| 77 | - 'enable_lazy_load' => false, | |
| 78 | - 'lazy_load_post_content' => true, | |
| 79 | - 'lazy_load_images' => true, | |
| 80 | - 'lazy_load_iframes' => true, | |
| 81 | - 'lazy_load_widgets' => true, | |
| 82 | - 'lazy_load_post_thumbnail' => true, | |
| 83 | - 'lazy_load_avatars' => true, | |
| 84 | - 'disable_wp_lazy_load' => false, | |
| 85 | - 'disable_wp_embeds' => false, | |
| 86 | - 'disable_emoji_scripts' => false, | |
| 102 | + 'enable_lazy_load' => false, | |
| 103 | + 'lazy_load_post_content' => true, | |
| 104 | + 'lazy_load_images' => true, | |
| 105 | + 'lazy_load_iframes' => true, | |
| 106 | + 'lazy_load_widgets' => true, | |
| 107 | + 'lazy_load_post_thumbnail' => true, | |
| 108 | + 'lazy_load_avatars' => true, | |
| 109 | + 'lazy_load_youtube' => false, | |
| 110 | + 'lazy_load_skip_first_nth_img' => 3, | |
| 111 | + 'lazy_load_exclusions' => '', | |
| 112 | + 'disable_wp_lazy_load' => false, | |
| 113 | + 'disable_wp_embeds' => false, | |
| 114 | + 'disable_emoji_scripts' => false, | |
| 87 | 115 | // cdn |
| 88 | - 'enable_cdn' => false, | |
| 89 | - 'cdn_hostname' => array( '' ), | |
| 90 | - 'cdn_zone' => array( '' ), | |
| 91 | - 'cdn_rejected_files' => '', | |
| 116 | + 'enable_cdn' => false, | |
| 117 | + 'cdn_hostname' => array( '' ), | |
| 118 | + 'cdn_zone' => array( '' ), | |
| 119 | + 'cdn_rejected_files' => '', | |
| 92 | 120 | // preload |
| 93 | - 'enable_cache_preload' => false, | |
| 94 | - 'preload_homepage' => true, | |
| 95 | - 'preload_public_posts' => true, | |
| 96 | - 'preload_public_tax' => true, | |
| 97 | - 'enable_sitemap_preload' => false, | |
| 98 | - 'preload_sitemap' => '', | |
| 99 | - 'prefetch_dns' => '', | |
| 121 | + 'enable_cache_preload' => false, | |
| 122 | + 'preload_homepage' => true, | |
| 123 | + 'preload_public_posts' => true, | |
| 124 | + 'preload_public_tax' => true, | |
| 125 | + 'enable_sitemap_preload' => false, | |
| 126 | + 'preload_request_interval' => 2, // in seconds | |
| 127 | + 'preload_sitemap' => '', | |
| 128 | + 'prefetch_dns' => '', | |
| 129 | + 'preconnect_resource' => '', | |
| 130 | + 'prefetch_links' => true, | |
| 131 | + 'enable_lcp_optimization' => false, | |
| 100 | 132 | // db options |
| 101 | - 'db_cleanup_post_revisions' => false, | |
| 102 | - 'db_cleanup_auto_drafts' => false, | |
| 103 | - 'db_cleanup_trashed_posts' => false, | |
| 104 | - 'db_cleanup_spam_comments' => false, | |
| 105 | - 'db_cleanup_trashed_comments' => false, | |
| 106 | - 'db_cleanup_expired_transients' => false, | |
| 107 | - 'db_cleanup_all_transients' => false, | |
| 108 | - 'db_cleanup_optimize_tables' => false, | |
| 109 | - 'enable_scheduled_db_cleanup' => false, | |
| 110 | - 'scheduled_db_cleanup_frequency' => 'daily', | |
| 133 | + 'db_cleanup_post_revisions' => false, | |
| 134 | + 'db_cleanup_auto_drafts' => false, | |
| 135 | + 'db_cleanup_trashed_posts' => false, | |
| 136 | + 'db_cleanup_spam_comments' => false, | |
| 137 | + 'db_cleanup_trashed_comments' => false, | |
| 138 | + 'db_cleanup_expired_transients' => false, | |
| 139 | + 'db_cleanup_all_transients' => false, | |
| 140 | + 'db_cleanup_optimize_tables' => false, | |
| 141 | + 'enable_scheduled_db_cleanup' => false, | |
| 142 | + 'scheduled_db_cleanup_frequency' => 'daily', | |
| 111 | 143 | // add-ons |
| 112 | - 'enable_cloudflare' => false, | |
| 113 | - 'cloudflare_email' => '', | |
| 114 | - 'cloudflare_api_key' => '', | |
| 115 | - 'cloudflare_zone' => '', | |
| 116 | - 'enable_heartbeat' => false, // extention status | |
| 117 | - 'heartbeat_dashboard_status' => 'enable', // enable,disable,modify | |
| 118 | - 'heartbeat_dashboard_interval' => 60, // default interval in seconds | |
| 119 | - 'heartbeat_editor_status' => 'enable', // enable,disable,modify | |
| 120 | - 'heartbeat_editor_interval' => 15, // default interval in seconds | |
| 121 | - 'heartbeat_frontend_status' => 'enable', // enable,disable,modify | |
| 122 | - 'heartbeat_frontend_interval' => 60, // default interval in seconds | |
| 123 | - 'enable_varnish' => false, | |
| 124 | - 'varnish_ip' => '', | |
| 144 | + 'enable_cloudflare' => false, | |
| 145 | + 'cloudflare_api_token' => '', | |
| 146 | + 'cloudflare_email' => '', | |
| 147 | + 'cloudflare_api_key' => '', | |
| 148 | + 'cloudflare_zone' => '', | |
| 149 | + 'enable_heartbeat' => false, // extension status | |
| 150 | + 'heartbeat_dashboard_status' => 'enable', // enable,disable,modify | |
| 151 | + 'heartbeat_dashboard_interval' => 60, // default interval in seconds | |
| 152 | + 'heartbeat_editor_status' => 'enable', // enable,disable,modify | |
| 153 | + 'heartbeat_editor_interval' => 15, // default interval in seconds | |
| 154 | + 'heartbeat_frontend_status' => 'enable', // enable,disable,modify | |
| 155 | + 'heartbeat_frontend_interval' => 60, // default interval in seconds | |
| 156 | + 'enable_varnish' => false, | |
| 157 | + 'varnish_ip' => '', | |
| 125 | 158 | // misc |
| 126 | - 'cache_footprint' => true, | |
| 159 | + 'cache_footprint' => true, | |
| 160 | + 'async_cache_cleaning' => false, | |
| 161 | + 'dev_mode' => false, | |
| 127 | 162 | // new options needs to migrate from extensions |
| 128 | - 'enable_google_tracking' => false, | |
| 129 | - 'enable_fb_tracking' => false, | |
| 163 | + 'enable_google_tracking' => false, | |
| 164 | + 'enable_fb_tracking' => false, | |
| 130 | 165 | ]; |
| 131 | 166 | |
| 132 | 167 | /** |
| 133 | 168 | * Filter default settings. |
| @@ -173,9 +208,8 @@ | ||
| 173 | 208 | * Object cache methods keys will use as option |
| 174 | 209 | * |
| 175 | 210 | * @return array $object_caches |
| 176 | 211 | * @since 1.2 apcu added |
| 177 | - * | |
| 178 | 212 | * @since 1.0 |
| 179 | 213 | */ |
| 180 | 214 | function get_object_cache_dropins() { |
| 181 | 215 | |
| @@ -335,8 +369,10 @@ | ||
| 335 | 369 | |
| 336 | 370 | /** |
| 337 | 371 | * Supported js execution methods |
| 338 | 372 | * |
| 373 | + * @depreacated since 3.2 | |
| 374 | + * | |
| 339 | 375 | * @return mixed|void |
| 340 | 376 | */ |
| 341 | 377 | function js_execution_methods() { |
| 342 | 378 | $methods = [ |
| @@ -342,8 +378,9 @@ | ||
| 342 | 378 | $methods = [ |
| 343 | 379 | 'blocking' => esc_html__( 'Blocking – (default)', 'powered-cache' ), |
| 344 | 380 | 'async' => esc_html__( 'Non-blocking using async', 'powered-cache' ), |
| 345 | 381 | 'defer' => esc_html__( 'Non-blocking using defer', 'powered-cache' ), |
| 382 | + 'delayed' => esc_html__( 'Delayed for user interaction', 'powered-cache' ), | |
| 346 | 383 | ]; |
| 347 | 384 | |
| 348 | 385 | /** |
| 349 | 386 | * Filter supported JS execution methods. |
| @@ -386,26 +423,8 @@ | ||
| 386 | 423 | return apply_filters( 'powered_cache_cdn_zones', $zones ); |
| 387 | 424 | } |
| 388 | 425 | |
| 389 | 426 | /** |
| 390 | - * Get counts for db entities | |
| 391 | - * | |
| 392 | - * @return array | |
| 393 | - */ | |
| 394 | -function get_db_cleanup_counts() { | |
| 395 | - return [ | |
| 396 | - 'post_revision' => 0, | |
| 397 | - 'post_auto_draft' => 1, | |
| 398 | - 'post_trashed' => 4, | |
| 399 | - 'comment_spam' => 4, | |
| 400 | - 'comment_trashed' => 4, | |
| 401 | - 'transient_expired' => 4, | |
| 402 | - 'transient_all' => 4, | |
| 403 | - 'table_count' => 0, | |
| 404 | - ]; | |
| 405 | -} | |
| 406 | - | |
| 407 | -/** | |
| 408 | 427 | * Which version of plugin running |
| 409 | 428 | * |
| 410 | 429 | * @return bool |
| 411 | 430 | */ |
| @@ -495,9 +514,8 @@ | ||
| 495 | 514 | } |
| 496 | 515 | |
| 497 | 516 | /** |
| 498 | 517 | * remove directories recursively |
| 499 | - * | |
| 500 | 518 | * Adopted from W3TC Utility |
| 501 | 519 | * |
| 502 | 520 | * @param string $path The target path |
| 503 | 521 | * @param array $exclude list of the files that will excluded |
| @@ -701,80 +719,172 @@ | ||
| 701 | 719 | * @since 1.0 |
| 702 | 720 | * @since 1.1 powered_cache_post_related_urls filter added |
| 703 | 721 | */ |
| 704 | 722 | function get_post_related_urls( $post_id ) { |
| 723 | + // Valid post statuses that require cache purging. | |
| 724 | + $valid_post_statuses = [ 'publish', 'private', 'trash', 'pending', 'draft' ]; | |
| 725 | + $post_status = get_post_status( $post_id ); | |
| 726 | + $post = get_post( $post_id ); | |
| 705 | 727 | |
| 706 | - $current_post_status = get_post_status( $post_id ); | |
| 728 | + // Post types that should not have their cache purged. | |
| 729 | + $excluded_post_types = [ 'nav_menu_item', 'revision' ]; | |
| 730 | + $post_type = get_post_type( $post_id ); | |
| 731 | + $rest_api_route = 'wp/v2'; | |
| 707 | 732 | |
| 708 | - // array to collect all our URLs | |
| 709 | - $related_urls = array(); | |
| 733 | + $related_urls = []; | |
| 710 | 734 | |
| 711 | - if ( get_permalink( $post_id ) ) { | |
| 712 | - // we're going to add a ton of things to flush. | |
| 735 | + if ( false !== get_permalink( $post_id ) && in_array( $post_status, $valid_post_statuses, true ) && ! in_array( $post_type, $excluded_post_types, true ) ) { | |
| 736 | + // Add the post URL. | |
| 737 | + $related_urls[] = get_permalink( $post_id ); | |
| 713 | 738 | |
| 714 | - // related category urls | |
| 715 | - $categories = get_the_category( $post_id ); | |
| 716 | - if ( $categories ) { | |
| 717 | - foreach ( $categories as $cat ) { | |
| 718 | - array_push( $related_urls, get_category_link( $cat->term_id ) ); | |
| 739 | + // Add REST API URL if applicable. | |
| 740 | + if ( $rest_api_route ) { | |
| 741 | + $post_type_object = get_post_type_object( $post_type ); | |
| 742 | + if ( ! empty( $post_type_object->show_in_rest ) ) { | |
| 743 | + $post_type_base = $post_type_object->rest_base ? $post_type_object->rest_base : $post_type_object->name; | |
| 744 | + $related_urls[] = get_rest_url() . $rest_api_route . '/' . $post_type_base . '/' . $post_id . '/'; | |
| 745 | + } elseif ( in_array( $post_type, [ 'post', 'page' ], true ) ) { | |
| 746 | + $related_urls[] = get_rest_url() . $rest_api_route . '/' . $post_type . 's/' . $post_id . '/'; | |
| 719 | 747 | } |
| 720 | 748 | } |
| 721 | 749 | |
| 722 | - // related tags url | |
| 723 | - $tags = get_the_tags( $post_id ); | |
| 724 | - if ( $tags ) { | |
| 725 | - foreach ( $tags as $tag ) { | |
| 726 | - array_push( $related_urls, get_tag_link( $tag->term_id ) ); | |
| 750 | + // Add AMP URL if AMP plugin is active. | |
| 751 | + if ( function_exists( 'amp_get_permalink' ) ) { | |
| 752 | + $related_urls[] = amp_get_permalink( $post_id ); | |
| 753 | + } | |
| 754 | + | |
| 755 | + // Regular AMP url for posts if ant of the following are active: | |
| 756 | + // https://wordpress.org/plugins/accelerated-mobile-pages/ | |
| 757 | + if ( defined( 'AMPFORWP_AMP_QUERY_VAR' ) ) { | |
| 758 | + $related_urls[] = get_permalink( $post_id ) . 'amp/'; | |
| 759 | + } | |
| 760 | + | |
| 761 | + // Handle trashed post URLs. | |
| 762 | + if ( 'trash' === $post_status ) { | |
| 763 | + $trash_permalink = str_replace( '__trashed', '', get_permalink( $post_id ) ); | |
| 764 | + $related_urls[] = $trash_permalink; | |
| 765 | + $related_urls[] = $trash_permalink . 'feed/'; | |
| 766 | + } | |
| 767 | + | |
| 768 | + $taxonomies = get_object_taxonomies( get_post_type( $post_id ), 'objects' ); | |
| 769 | + | |
| 770 | + // Purge terms associated with the post. | |
| 771 | + foreach ( $taxonomies as $taxonomy ) { | |
| 772 | + // Skip non-public taxonomies. | |
| 773 | + if ( ! $taxonomy->public ) { | |
| 774 | + continue; | |
| 727 | 775 | } |
| 728 | - } | |
| 729 | 776 | |
| 730 | - // Author URL | |
| 731 | - array_push( $related_urls, get_author_posts_url( get_post_field( 'post_author', $post_id ) ), get_author_feed_link( get_post_field( 'post_author', $post_id ) ) ); | |
| 777 | + $terms = get_the_terms( $post_id, $taxonomy->name ); | |
| 732 | 778 | |
| 733 | - // Archives and their feeds | |
| 734 | - if ( get_post_type_archive_link( get_post_type( $post_id ) ) === true ) { | |
| 735 | - array_push( $related_urls, get_post_type_archive_link( get_post_type( $post_id ) ), get_post_type_archive_feed_link( get_post_type( $post_id ) ) ); | |
| 779 | + if ( empty( $terms ) || is_wp_error( $terms ) ) { | |
| 780 | + continue; | |
| 781 | + } | |
| 782 | + | |
| 783 | + foreach ( $terms as $term ) { | |
| 784 | + $term_url = get_term_link( $term->slug, $taxonomy->name ); | |
| 785 | + if ( ! is_wp_error( $term_url ) ) { | |
| 786 | + $related_urls[] = $term_url; | |
| 787 | + if ( $taxonomy->show_in_rest ) { | |
| 788 | + $taxonomy_base = $taxonomy->rest_base ? $taxonomy->rest_base : $taxonomy->name; | |
| 789 | + $related_urls[] = rest_url( "{$taxonomy->rest_namespace}/{$taxonomy_base}/{$term->term_id}/" ); // REST API URL for the term | |
| 790 | + } | |
| 791 | + } | |
| 792 | + | |
| 793 | + if ( ! is_taxonomy_hierarchical( $taxonomy->name ) ) { | |
| 794 | + continue; | |
| 795 | + } | |
| 796 | + | |
| 797 | + $ancestors = (array) get_ancestors( $term->term_id, $taxonomy->name ); | |
| 798 | + foreach ( $ancestors as $ancestor ) { | |
| 799 | + $ancestor_object = get_term( $ancestor, $taxonomy->name ); | |
| 800 | + if ( ! is_a( $ancestor, '\WP_Term' ) ) { | |
| 801 | + continue; | |
| 802 | + } | |
| 803 | + | |
| 804 | + $ancestor_term_url = get_term_link( $ancestor_object->slug, $taxonomy->name ); | |
| 805 | + if ( ! is_wp_error( $ancestor_term_url ) ) { | |
| 806 | + $related_urls[] = $ancestor_term_url; | |
| 807 | + if ( $taxonomy->show_in_rest ) { | |
| 808 | + $taxonomy_base = $taxonomy->rest_base ? $taxonomy->rest_base : $taxonomy->name; | |
| 809 | + $related_urls[] = rest_url( "{$taxonomy->rest_namespace}/{$taxonomy_base}/{$ancestor_object->term_id}/" ); // REST API URL for the ancestor term | |
| 810 | + } | |
| 811 | + } | |
| 812 | + } | |
| 813 | + } | |
| 736 | 814 | } |
| 737 | 815 | |
| 738 | - // Post URL | |
| 739 | - array_push( $related_urls, get_permalink( $post_id ) ); | |
| 816 | + // Purge author and feed URLs for posts. | |
| 817 | + if ( 'post' === $post_type ) { | |
| 818 | + $author_id = get_post_field( 'post_author', $post_id ); | |
| 819 | + $related_urls[] = get_author_posts_url( $author_id ); | |
| 820 | + $related_urls[] = get_author_feed_link( $author_id ); | |
| 821 | + if ( $rest_api_route ) { | |
| 822 | + $related_urls[] = get_rest_url() . $rest_api_route . '/users/' . $author_id . '/'; | |
| 823 | + } | |
| 740 | 824 | |
| 741 | - // Also clean URL for trashed post. | |
| 742 | - if ( 'trash' === $current_post_status ) { | |
| 743 | - $trashpost = get_permalink( $post_id ); | |
| 744 | - $trashpost = str_replace( '__trashed', '', $trashpost ); | |
| 745 | - array_push( $related_urls, $trashpost, $trashpost . 'feed/' ); | |
| 825 | + // Include various feed URLs. | |
| 826 | + $feed_urls = [ | |
| 827 | + get_bloginfo_rss( 'rdf_url' ), | |
| 828 | + get_bloginfo_rss( 'rss_url' ), | |
| 829 | + get_bloginfo_rss( 'rss2_url' ), | |
| 830 | + get_bloginfo_rss( 'atom_url' ), | |
| 831 | + get_bloginfo_rss( 'comments_rss2_url' ), | |
| 832 | + get_post_comments_feed_link( $post_id ), | |
| 833 | + ]; | |
| 834 | + $related_urls = array_merge( $related_urls, $feed_urls ); | |
| 746 | 835 | } |
| 747 | 836 | |
| 748 | - // Add in AMP permalink if Automattic's AMP is installed | |
| 749 | - if ( function_exists( 'amp_get_permalink' ) ) { | |
| 750 | - array_push( $related_urls, amp_get_permalink( $post_id ) ); | |
| 837 | + // Purge archive pages if not excluded. | |
| 838 | + if ( ! in_array( $post_type, [ 'post', 'page' ], true ) ) { | |
| 839 | + $related_urls[] = get_post_type_archive_link( $post_type ); | |
| 840 | + $related_urls[] = get_post_type_archive_feed_link( $post_type ); | |
| 751 | 841 | } |
| 752 | 842 | |
| 753 | - // Regular AMP url for posts | |
| 754 | - array_push( $related_urls, get_permalink( $post_id ) . 'amp/' ); | |
| 843 | + $post_date = strtotime( $post->post_date ); | |
| 755 | 844 | |
| 756 | - // Feeds | |
| 757 | - array_push( $related_urls, get_bloginfo_rss( 'rdf_url' ), get_bloginfo_rss( 'rss_url' ), get_bloginfo_rss( 'rss2_url' ), get_bloginfo_rss( 'atom_url' ), get_bloginfo_rss( 'comments_rss2_url' ), get_post_comments_feed_link( $post_id ) ); | |
| 845 | + if ( $post_date ) { | |
| 846 | + // Generate the date archive URLs | |
| 847 | + $year = gmdate( 'Y', $post_date ); | |
| 848 | + $month = gmdate( 'm', $post_date ); | |
| 849 | + $day = gmdate( 'd', $post_date ); | |
| 758 | 850 | |
| 759 | - // Home Page and (if used) posts page | |
| 760 | - array_push( $related_urls, trailingslashit( home_url() ) ); | |
| 761 | - if ( get_option( 'show_on_front' ) === 'page' ) { | |
| 762 | - // Ensure we have a page_for_posts setting to avoid empty URL | |
| 763 | - if ( get_option( 'page_for_posts' ) ) { | |
| 764 | - array_push( $related_urls, get_permalink( get_option( 'page_for_posts' ) ) ); | |
| 851 | + $related_urls[] = get_year_link( $year ); | |
| 852 | + $related_urls[] = get_month_link( $year, $month ); | |
| 853 | + $related_urls[] = get_day_link( $year, $month, $day ); | |
| 854 | + } | |
| 855 | + | |
| 856 | + // Always purge the home page. | |
| 857 | + $related_urls[] = home_url( '/' ); | |
| 858 | + | |
| 859 | + // Purge the posts page if it's set to a static page. | |
| 860 | + if ( 'page' === get_option( 'show_on_front' ) ) { | |
| 861 | + $posts_page_id = get_option( 'page_for_posts' ); | |
| 862 | + if ( $posts_page_id ) { | |
| 863 | + $related_urls[] = get_permalink( $posts_page_id ); | |
| 765 | 864 | } |
| 766 | 865 | } |
| 767 | 866 | } |
| 768 | 867 | |
| 868 | + // Remove query strings and ensure unique URLs before purging. | |
| 869 | + $related_urls = array_unique( | |
| 870 | + array_map( | |
| 871 | + function ( $url ) { | |
| 872 | + return strtok( $url, '?' ); | |
| 873 | + }, | |
| 874 | + $related_urls | |
| 875 | + ) | |
| 876 | + ); | |
| 877 | + | |
| 769 | 878 | /** |
| 770 | 879 | * Filters post related urls. |
| 771 | 880 | * |
| 772 | - * @hook powered_cache_post_related_urls | |
| 881 | + * @hook powered_cache_post_related_urls | |
| 773 | 882 | * |
| 774 | - * @param {array} $related_urls The list of the URLs that related with the post. | |
| 883 | + * @param {array} $related_urls The list of the URLs that related with the post. | |
| 775 | 884 | * |
| 776 | - * @since 1.0 | |
| 885 | + * @return {array} New value. | |
| 886 | + * @since 1.0 | |
| 777 | 887 | */ |
| 778 | 888 | $related_urls = apply_filters( 'powered_cache_post_related_urls', $related_urls ); |
| 779 | 889 | |
| 780 | 890 | return $related_urls; |
| @@ -783,17 +893,17 @@ | ||
| 783 | 893 | |
| 784 | 894 | /** |
| 785 | 895 | * Delete cache file |
| 786 | 896 | * |
| 787 | - * @param string $url Target URL | |
| 897 | + * @param string $url Target URL | |
| 898 | + * @param bool $delete_subdirectories Whether delete subdirectories or not | |
| 788 | 899 | * |
| 789 | 900 | * @return bool true when found cache dir, otherwise false |
| 790 | 901 | * @since 1.0 |
| 791 | 902 | */ |
| 792 | -function delete_page_cache( $url ) { | |
| 903 | +function delete_page_cache( $url, $delete_subdirectories = false ) { | |
| 904 | + $dir = get_url_dir( trim( $url ) ); | |
| 793 | 905 | |
| 794 | - $dir = trailingslashit( get_url_dir( trim( $url ) ) ); | |
| 795 | - | |
| 796 | 906 | if ( is_dir( $dir ) ) { |
| 797 | 907 | $files = scandir( $dir ); |
| 798 | 908 | foreach ( $files as $file ) { |
| 799 | 909 | /** |
| @@ -799,15 +909,15 @@ | ||
| 799 | 909 | /** |
| 800 | 910 | * Don't need to lookup for index-https, index-https-mobile etc.. |
| 801 | 911 | * Just clean that directory's files only. |
| 802 | 912 | */ |
| 803 | - if ( ! is_dir( $dir . $file ) && ! in_array( $file, array( '.', '..' ), true ) ) { | |
| 913 | + if ( ! is_dir( $dir . $file ) && file_exists( $dir . $file ) && ! in_array( $file, array( '.', '..' ), true ) ) { | |
| 804 | 914 | unlink( $dir . $file ); |
| 805 | 915 | } |
| 916 | + } | |
| 806 | 917 | |
| 807 | - if ( file_exists( $dir ) && is_dir_empty( $dir ) ) { | |
| 808 | - remove_dir( $dir ); | |
| 809 | - } | |
| 918 | + if ( file_exists( $dir ) && ( $delete_subdirectories || is_dir_empty( $dir ) ) ) { | |
| 919 | + remove_dir( $dir ); | |
| 810 | 920 | } |
| 811 | 921 | |
| 812 | 922 | return true; |
| 813 | 923 | } |
| @@ -825,9 +935,9 @@ | ||
| 825 | 935 | * @since 1.1 |
| 826 | 936 | */ |
| 827 | 937 | function get_url_dir( $url ) { |
| 828 | 938 | $url_info = wp_parse_url( $url ); |
| 829 | - $sub_dir = $url_info['host']; | |
| 939 | + $sub_dir = isset( $url_info['host'] ) ? $url_info['host'] : ''; | |
| 830 | 940 | |
| 831 | 941 | if ( ! empty( $url_info['path'] ) ) { |
| 832 | 942 | $sub_dir .= $url_info['path']; |
| 833 | 943 | } |
| @@ -832,8 +942,9 @@ | ||
| 832 | 942 | $sub_dir .= $url_info['path']; |
| 833 | 943 | } |
| 834 | 944 | |
| 835 | 945 | $path = trailingslashit( get_page_cache_dir() ) . ltrim( $sub_dir, '/' ); |
| 946 | + $path = trailingslashit( $path ); | |
| 836 | 947 | |
| 837 | 948 | /** |
| 838 | 949 | * Filters the path of the given url in the cache directory. |
| 839 | 950 | * |
| @@ -859,8 +970,12 @@ | ||
| 859 | 970 | $zones = $settings['cdn_zone']; |
| 860 | 971 | |
| 861 | 972 | $cdn_addresses = array(); |
| 862 | 973 | foreach ( $hostnames as $host_key => $host ) { |
| 974 | + if ( filter_var( $host, FILTER_VALIDATE_URL ) ) { | |
| 975 | + $host = wp_parse_url( $host, PHP_URL_HOST ); | |
| 976 | + } | |
| 977 | + | |
| 863 | 978 | if ( ! empty( $host ) ) { |
| 864 | 979 | $cdn_addresses[ $zones[ $host_key ] ][] = $host; |
| 865 | 980 | } |
| 866 | 981 | } |
| @@ -869,12 +984,11 @@ | ||
| 869 | 984 | * Filters CDN Addresses. |
| 870 | 985 | * |
| 871 | 986 | * @hook powered_cache_cdn_addresses |
| 872 | 987 | * |
| 873 | - * @param {array} $cdn_addresses CDN Adresses. | |
| 988 | + * @param {array} $cdn_addresses CDN Addresses. | |
| 874 | 989 | * |
| 875 | 990 | * @return {array} New value. |
| 876 | - * | |
| 877 | 991 | * @since 1.0 |
| 878 | 992 | */ |
| 879 | 993 | return apply_filters( 'powered_cache_cdn_addresses', $cdn_addresses ); |
| 880 | 994 | } |
| @@ -934,9 +1048,8 @@ | ||
| 934 | 1048 | /** |
| 935 | 1049 | * Fires after cache flush. |
| 936 | 1050 | * |
| 937 | 1051 | * @hook powered_cache_flushed |
| 938 | - * | |
| 939 | 1052 | * @since 1.0 |
| 940 | 1053 | */ |
| 941 | 1054 | do_action( 'powered_cache_flushed' ); |
| 942 | 1055 | } |
| @@ -966,9 +1079,8 @@ | ||
| 966 | 1079 | * |
| 967 | 1080 | * @param {string} $log_message The log message. |
| 968 | 1081 | * |
| 969 | 1082 | * @return {string} New value. |
| 970 | - * | |
| 971 | 1083 | * @since 2.0 |
| 972 | 1084 | */ |
| 973 | 1085 | $log_message = apply_filters( 'powered_cache_log_message', $log_message ); |
| 974 | 1086 | |
| @@ -976,15 +1088,14 @@ | ||
| 976 | 1088 | * Filters log message type. |
| 977 | 1089 | * |
| 978 | 1090 | * @hook powered_cache_log_message_type |
| 979 | 1091 | * |
| 980 | - * @param {null|int} null default message type | |
| 1092 | + * @param {int} 0 default message type since 3.6 | |
| 981 | 1093 | * |
| 982 | - * @return {null|int} New value. | |
| 983 | - * | |
| 1094 | + * @return {int} New value. | |
| 984 | 1095 | * @since 2.0 |
| 985 | 1096 | */ |
| 986 | - $message_type = apply_filters( 'powered_cache_log_message_type', null ); | |
| 1097 | + $message_type = apply_filters( 'powered_cache_log_message_type', 0 ); | |
| 987 | 1098 | $destination = null; |
| 988 | 1099 | |
| 989 | 1100 | if ( defined( 'POWERED_CACHE_LOG_FILE' ) ) { |
| 990 | 1101 | $destination = POWERED_CACHE_LOG_FILE; |
| @@ -998,9 +1109,8 @@ | ||
| 998 | 1109 | * |
| 999 | 1110 | * @param {null|string} $destination The destination of the log. |
| 1000 | 1111 | * |
| 1001 | 1112 | * @return {null|string} New value. |
| 1002 | - * | |
| 1003 | 1113 | * @since 2.0 |
| 1004 | 1114 | */ |
| 1005 | 1115 | $log_destination = apply_filters( 'powered_cache_log_destination', $destination ); |
| 1006 | 1116 | |
| @@ -1008,8 +1118,10 @@ | ||
| 1008 | 1118 | if ( defined( 'POWERED_CACHE_LOG_IP' ) && POWERED_CACHE_LOG_IP !== get_client_ip() ) { |
| 1009 | 1119 | return false; |
| 1010 | 1120 | } |
| 1011 | 1121 | |
| 1122 | + $message_type = absint( $message_type ); | |
| 1123 | + | |
| 1012 | 1124 | return error_log( $log_message, $message_type, $log_destination ); // phpcs:ignore |
| 1013 | 1125 | } |
| 1014 | 1126 | |
| 1015 | 1127 | /** |
| @@ -1018,12 +1130,14 @@ | ||
| 1018 | 1130 | * @return mixed |
| 1019 | 1131 | */ |
| 1020 | 1132 | function get_client_ip() { |
| 1021 | 1133 | if ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { |
| 1022 | - return $_SERVER['HTTP_X_FORWARDED_FOR']; | |
| 1134 | + return wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized | |
| 1023 | 1135 | } |
| 1024 | 1136 | |
| 1025 | - return $_SERVER['REMOTE_ADDR']; | |
| 1137 | + if ( isset( $_SERVER['REMOTE_ADDR'] ) ) { | |
| 1138 | + return wp_unslash( $_SERVER['REMOTE_ADDR'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized | |
| 1139 | + } | |
| 1026 | 1140 | } |
| 1027 | 1141 | |
| 1028 | 1142 | /** |
| 1029 | 1143 | * Fragment caching |
| @@ -1115,9 +1229,8 @@ | ||
| 1115 | 1229 | * |
| 1116 | 1230 | * @param {array} $known_headers The list of known HTTP headers. |
| 1117 | 1231 | * |
| 1118 | 1232 | * @return {array} New value. |
| 1119 | - * | |
| 1120 | 1233 | * @since 1.2 |
| 1121 | 1234 | */ |
| 1122 | 1235 | $known_headers = apply_filters( 'powered_cache_known_headers', $known_headers ); |
| 1123 | 1236 | |
| @@ -1242,5 +1355,242 @@ | ||
| 1242 | 1355 | $doc_url .= '#' . $fragment; |
| 1243 | 1356 | } |
| 1244 | 1357 | |
| 1245 | 1358 | return $doc_url; |
| 1359 | +} | |
| 1360 | + | |
| 1361 | +/** | |
| 1362 | + * Sanitize CSS | |
| 1363 | + * | |
| 1364 | + * @param string $css Input | |
| 1365 | + * | |
| 1366 | + * @return string|string[] $css | |
| 1367 | + * @since 2.1 | |
| 1368 | + */ | |
| 1369 | +function sanitize_css( $css ) { | |
| 1370 | + $css = wp_strip_all_tags( $css ); | |
| 1371 | + | |
| 1372 | + if ( false !== strpos( $css, '<' ) ) { | |
| 1373 | + $css = preg_replace( '#<(\/?\w+)#', '\00003C$1', $css ); | |
| 1374 | + } | |
| 1375 | + | |
| 1376 | + return $css; | |
| 1377 | +} | |
| 1378 | + | |
| 1379 | + | |
| 1380 | +/** | |
| 1381 | + * Test if the current browser runs on a mobile device (smart phone, tablet, etc.) | |
| 1382 | + * Sort of custom version of wp_is_mobile | |
| 1383 | + */ | |
| 1384 | +function powered_cache_is_mobile() { | |
| 1385 | + | |
| 1386 | + global $powered_cache_mobile_browsers, $powered_cache_mobile_prefixes; | |
| 1387 | + | |
| 1388 | + $mobile_browsers = addcslashes( implode( '|', preg_split( '/[\s*,\s*]*,+[\s*,\s*]*/', (string) $powered_cache_mobile_browsers ) ), ' ' ); | |
| 1389 | + $mobile_prefixes = addcslashes( implode( '|', preg_split( '/[\s*,\s*]*,+[\s*,\s*]*/', (string) $powered_cache_mobile_prefixes ) ), ' ' ); | |
| 1390 | + | |
| 1391 | + if ( ! isset( $_SERVER['HTTP_USER_AGENT'] ) ) { | |
| 1392 | + return false; | |
| 1393 | + } | |
| 1394 | + | |
| 1395 | + $user_agent = wp_unslash( $_SERVER['HTTP_USER_AGENT'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized | |
| 1396 | + | |
| 1397 | + if ( ( preg_match( '#^.*(' . $mobile_browsers . ').*#i', $user_agent ) || preg_match( '#^(' . $mobile_prefixes . ').*#i', substr( $user_agent, 0, 4 ) ) ) ) { | |
| 1398 | + return true; | |
| 1399 | + } | |
| 1400 | + | |
| 1401 | + return false; | |
| 1402 | +} | |
| 1403 | + | |
| 1404 | +/** | |
| 1405 | + * If the site is a local site. | |
| 1406 | + * | |
| 1407 | + * @return bool | |
| 1408 | + * @since 2.2 | |
| 1409 | + */ | |
| 1410 | +function is_local_site() { | |
| 1411 | + $site_url = site_url(); | |
| 1412 | + if ( ! is_string( $site_url ) ) { | |
| 1413 | + $site_url = ''; | |
| 1414 | + } | |
| 1415 | + | |
| 1416 | + // Check for localhost and sites using an IP only first. | |
| 1417 | + $is_local = $site_url && false === strpos( $site_url, '.' ); | |
| 1418 | + | |
| 1419 | + // Use Core's environment check, if available. Added in 5.5.0 / 5.5.1 (for `local` return value). | |
| 1420 | + if ( function_exists( 'wp_get_environment_type' ) && 'local' === wp_get_environment_type() ) { | |
| 1421 | + $is_local = true; | |
| 1422 | + } | |
| 1423 | + | |
| 1424 | + // Then check for usual usual domains used by local dev tools. | |
| 1425 | + $known_local = array( | |
| 1426 | + '#\.local$#i', | |
| 1427 | + '#\.localhost$#i', | |
| 1428 | + '#\.test$#i', | |
| 1429 | + '#\.docksal$#i', // Docksal. | |
| 1430 | + '#\.docksal\.site$#i', // Docksal. | |
| 1431 | + '#\.dev\.cc$#i', // ServerPress. | |
| 1432 | + '#\.lndo\.site$#i', // Lando. | |
| 1433 | + ); | |
| 1434 | + | |
| 1435 | + if ( ! $is_local ) { | |
| 1436 | + foreach ( $known_local as $url ) { | |
| 1437 | + if ( preg_match( $url, $site_url ) ) { | |
| 1438 | + $is_local = true; | |
| 1439 | + break; | |
| 1440 | + } | |
| 1441 | + } | |
| 1442 | + } | |
| 1443 | + | |
| 1444 | + /** | |
| 1445 | + * Filters is_local_site check. | |
| 1446 | + * | |
| 1447 | + * @param bool $is_local If the current site is a local site. | |
| 1448 | + * | |
| 1449 | + * @since 2.2 | |
| 1450 | + */ | |
| 1451 | + $is_local = apply_filters( 'powered_cache_is_local_site', $is_local ); | |
| 1452 | + | |
| 1453 | + return $is_local; | |
| 1454 | +} | |
| 1455 | + | |
| 1456 | +/** | |
| 1457 | + * Check whether request for bypass or process normally | |
| 1458 | + * | |
| 1459 | + * @return bool | |
| 1460 | + * @since 3.0 | |
| 1461 | + */ | |
| 1462 | +function bypass_request() { | |
| 1463 | + if ( isset( $_GET['nopoweredcache'] ) && $_GET['nopoweredcache'] ) { // phpcs:ignore | |
| 1464 | + return true; | |
| 1465 | + } | |
| 1466 | + | |
| 1467 | + return false; | |
| 1468 | +} | |
| 1469 | + | |
| 1470 | + | |
| 1471 | +/** | |
| 1472 | + * Calculate total amount of autoloaded data. | |
| 1473 | + * | |
| 1474 | + * @return int autoloaded data in bytes. | |
| 1475 | + * @global wpdb $wpdb WordPress database abstraction object. | |
| 1476 | + * @since 3.4 | |
| 1477 | + */ | |
| 1478 | +function autoloaded_options_size() { | |
| 1479 | + global $wpdb; | |
| 1480 | + | |
| 1481 | + return (int) $wpdb->get_var( 'SELECT SUM(LENGTH(option_value)) FROM ' . $wpdb->prefix . 'options WHERE autoload = \'yes\'' ); // phpcs:ignore | |
| 1482 | +} | |
| 1483 | + | |
| 1484 | +/** | |
| 1485 | + * Mask the string with asterisk | |
| 1486 | + * | |
| 1487 | + * @param string $input_string String | |
| 1488 | + * @param int $unmask_length The length of the string that will not be masked | |
| 1489 | + * | |
| 1490 | + * @return string | |
| 1491 | + * @since 3.4 | |
| 1492 | + */ | |
| 1493 | +function mask_string( $input_string, $unmask_length ) { | |
| 1494 | + $output_string = substr( $input_string, 0, $unmask_length ); | |
| 1495 | + | |
| 1496 | + if ( strlen( $input_string ) > $unmask_length ) { | |
| 1497 | + $output_string .= str_repeat( '*', strlen( $input_string ) - $unmask_length ); | |
| 1498 | + } | |
| 1499 | + | |
| 1500 | + return $output_string; | |
| 1501 | +} | |
| 1502 | + | |
| 1503 | +/** | |
| 1504 | + * Get sensitive data in decrypted form | |
| 1505 | + * | |
| 1506 | + * @param string $field field name | |
| 1507 | + * | |
| 1508 | + * @return bool|mixed|string | |
| 1509 | + */ | |
| 1510 | +function get_decrypted_setting( $field ) { | |
| 1511 | + $settings = \PoweredCache\Utils\get_settings(); | |
| 1512 | + $value = isset( $settings[ $field ] ) ? $settings[ $field ] : ''; | |
| 1513 | + | |
| 1514 | + // decrypt the value | |
| 1515 | + $encryption = new Encryption(); | |
| 1516 | + $decrypted_value = $encryption->decrypt( $value ); | |
| 1517 | + if ( false !== $decrypted_value ) { | |
| 1518 | + return $decrypted_value; | |
| 1519 | + } | |
| 1520 | + | |
| 1521 | + return $value; | |
| 1522 | +} | |
| 1523 | + | |
| 1524 | + | |
| 1525 | +/** | |
| 1526 | + * Check if a given IP is within a specific range. | |
| 1527 | + * Supports both IPv4 and IPv6 addresses. | |
| 1528 | + * | |
| 1529 | + * @param string $ip The IP address to check. | |
| 1530 | + * @param string $range The IP range in CIDR notation. | |
| 1531 | + * | |
| 1532 | + * @return bool True if the IP is in the range, false otherwise. | |
| 1533 | + */ | |
| 1534 | +function is_ip_in_range( $ip, $range ) { | |
| 1535 | + if ( false !== strpos( $range, '/' ) ) { | |
| 1536 | + list( $subnet, $bits ) = explode( '/', $range, 2 ); | |
| 1537 | + } else { | |
| 1538 | + $subnet = $range; | |
| 1539 | + $bits = ( false === filter_var( $subnet, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) ? 32 : 128; | |
| 1540 | + } | |
| 1541 | + | |
| 1542 | + $bits = intval( $bits ); | |
| 1543 | + | |
| 1544 | + if ( false !== filter_var( $subnet, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) { | |
| 1545 | + $subnet_bin = inet_pton( $subnet ); | |
| 1546 | + $ip_bin = inet_pton( $ip ); | |
| 1547 | + | |
| 1548 | + if ( false === $subnet_bin || false === $ip_bin ) { | |
| 1549 | + return false; | |
| 1550 | + } | |
| 1551 | + | |
| 1552 | + $subnet_bin = str_pad( $subnet_bin, 16, "\0" ); | |
| 1553 | + $ip_bin = str_pad( $ip_bin, 16, "\0" ); | |
| 1554 | + | |
| 1555 | + for ( $i = 0; $i * 8 < $bits; $i ++ ) { | |
| 1556 | + if ( $bits >= ( $i + 1 ) * 8 && $subnet_bin[ $i ] !== $ip_bin[ $i ] ) { | |
| 1557 | + return false; | |
| 1558 | + } elseif ( $bits > $i * 8 ) { | |
| 1559 | + $bitmask = 0xff00 >> ( $bits % 8 ); | |
| 1560 | + if ( ( ord( $subnet_bin[ $i ] ) & $bitmask ) !== ( ord( $ip_bin[ $i ] ) & $bitmask ) ) { | |
| 1561 | + return false; | |
| 1562 | + } | |
| 1563 | + } | |
| 1564 | + } | |
| 1565 | + | |
| 1566 | + return true; | |
| 1567 | + } | |
| 1568 | + | |
| 1569 | + if ( false === filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) { | |
| 1570 | + return false; | |
| 1571 | + } | |
| 1572 | + | |
| 1573 | + $subnet_decimal = ip2long( $subnet ); | |
| 1574 | + $ip_decimal = ip2long( $ip ); | |
| 1575 | + $mask_decimal = - 1 << ( 32 - $bits ); | |
| 1576 | + | |
| 1577 | + return ( $subnet_decimal & $mask_decimal ) === ( $ip_decimal & $mask_decimal ); | |
| 1578 | +} | |
| 1579 | + | |
| 1580 | +/** | |
| 1581 | + * Check if the dev mode is active | |
| 1582 | + * | |
| 1583 | + * @return bool | |
| 1584 | + * @since 3.6 | |
| 1585 | + */ | |
| 1586 | +function is_dev_mode_active() { | |
| 1587 | + // Check global config first (fast) | |
| 1588 | + if ( ! empty( $GLOBALS['powered_cache_options']['dev_mode'] ) ) { | |
| 1589 | + return true; | |
| 1590 | + } | |
| 1591 | + | |
| 1592 | + // Fallback to database option | |
| 1593 | + $settings = \PoweredCache\Utils\get_settings(); | |
| 1594 | + | |
| 1595 | + return ! empty( $settings['dev_mode'] ); | |
| 1246 | 1596 | } |