| @@ -36,9 +36,10 @@ | ||
| 36 | 36 | public function ui_metadata(): array { |
| 37 | 37 | return array( |
| 38 | 38 | 'label' => __( 'Bloat Control', 'xspeed' ), |
| 39 | 39 | 'icon' => 'Sliders', |
| 40 | - 'description' => __( 'Turn off WordPress defaults you do not use — saves bytes, requests, and attack surface.', 'xspeed' ), | |
| 40 | + 'description' => __( 'Turns off WordPress features you do not use, so pages load less.', 'xspeed' ), | |
| 41 | + 'group' => 'performance', | |
| 41 | 42 | ); |
| 42 | 43 | } |
| 43 | 44 | |
| 44 | 45 | public function settings_schema(): array { |
| @@ -45,82 +46,83 @@ | ||
| 45 | 46 | return array( |
| 46 | 47 | 'disable_emojis' => array( |
| 47 | 48 | 'type' => 'bool', |
| 48 | 49 | 'default' => false, |
| 49 | - 'label' => __( 'Disable Emojis', 'xspeed' ), | |
| 50 | + 'label' => __( 'Disable emojis', 'xspeed' ), | |
| 50 | 51 | 'description' => __( 'Remove the emoji detection script and its inline styles from every page. Modern browsers draw emojis natively, so visitors still see them. Saves a script and an inline stylesheet per page.', 'xspeed' ), |
| 51 | 52 | ), |
| 52 | 53 | 'disable_dashicons_frontend' => array( |
| 53 | 54 | 'type' => 'bool', |
| 54 | 55 | 'default' => false, |
| 55 | - 'label' => __( 'Disable Dashicons on Frontend', 'xspeed' ), | |
| 56 | - 'description' => __( 'Drop the dashicons stylesheet from non-admin pages. Most themes do not need it. Saves ~45 KB per visitor.', 'xspeed' ), | |
| 56 | + 'label' => __( 'Remove Dashicons for visitors', 'xspeed' ), | |
| 57 | + 'description' => __( 'Removes the WordPress admin icon font for logged-out visitors. Most themes do not use it, and it saves about 45 KB.', 'xspeed' ), | |
| 57 | 58 | ), |
| 58 | 59 | 'disable_oembed' => array( |
| 59 | 60 | 'type' => 'bool', |
| 60 | 61 | 'default' => false, |
| 61 | - 'label' => __( 'Disable oEmbed Discovery + wp-embed.min.js', 'xspeed' ), | |
| 62 | - 'description' => __( 'Strip the auto-embed handlers + the embed script. Posts that paste a YouTube URL will no longer auto-render the player — embed it via a block instead. Saves a request per page.', 'xspeed' ), | |
| 62 | + 'label' => __( 'Disable auto-embeds', 'xspeed' ), | |
| 63 | + 'description' => __( 'Removes the embed script, saving one request per page. A pasted YouTube link no longer turns into a player, so use an embed block.', 'xspeed' ), | |
| 63 | 64 | ), |
| 64 | 65 | 'disable_rss_feeds' => array( |
| 65 | 66 | 'type' => 'bool', |
| 66 | 67 | 'default' => false, |
| 67 | - 'label' => __( 'Disable RSS Feeds', 'xspeed' ), | |
| 68 | - 'description' => __( 'Return a 404 on /feed/ and similar endpoints. Useful for sites that do not publish feeds and want to cut feed-fetcher traffic.', 'xspeed' ), | |
| 68 | + 'label' => __( 'Disable RSS feeds', 'xspeed' ), | |
| 69 | + 'description' => __( 'Feed addresses such as /feed/ return "not found". Use this if your site has no feed readers.', 'xspeed' ), | |
| 69 | 70 | ), |
| 70 | 71 | 'disable_xmlrpc' => array( |
| 71 | 72 | 'type' => 'bool', |
| 72 | 73 | 'default' => false, |
| 73 | 74 | 'label' => __( 'Disable XML-RPC', 'xspeed' ), |
| 74 | - 'description' => __( 'Disable the legacy xmlrpc.php endpoint. Cuts pingback brute-force noise; safe to disable unless you use a remote WP client (Jetpack, WordPress mobile app).', 'xspeed' ), | |
| 75 | + 'description' => __( 'Turns off the old xmlrpc.php file that attackers often target. Leave this off if you use Jetpack or the WordPress mobile app.', 'xspeed' ), | |
| 75 | 76 | ), |
| 76 | 77 | 'strip_jquery_migrate' => array( |
| 77 | 78 | 'type' => 'bool', |
| 78 | 79 | 'default' => false, |
| 79 | - 'label' => __( 'Strip jQuery Migrate on Frontend', 'xspeed' ), | |
| 80 | - 'description' => __( 'Remove the jquery-migrate compatibility shim from non-admin pages. Saves ~10 KB; safe on modern themes / plugins.', 'xspeed' ), | |
| 80 | + 'label' => __( 'Remove jQuery Migrate', 'xspeed' ), | |
| 81 | + 'description' => __( 'Removes a script that old themes and plugins need, from pages visitors see. Saves about 10 KB and is safe on current themes.', 'xspeed' ), | |
| 81 | 82 | ), |
| 82 | 83 | 'strip_editor_styles' => array( |
| 83 | 84 | 'type' => 'bool', |
| 84 | 85 | 'default' => false, |
| 85 | - 'label' => __( 'Strip Block-Editor Styles on Frontend', 'xspeed' ), | |
| 86 | - 'description' => __( 'Drop editor-only stylesheets (wp-editor, wp-components, and friends) from anonymous pages. A plugin that enqueues them on the frontend usually does so by accident — they can add hundreds of KB of render-blocking CSS. Frontend block styles (wp-block-library) are never touched.', 'xspeed' ), | |
| 86 | + 'label' => __( 'Remove editor styles for visitors', 'xspeed' ), | |
| 87 | + 'description' => __( 'Removes block editor CSS that some plugins load on public pages by mistake, which can add hundreds of KB. Block styles for visitors stay.', 'xspeed' ), | |
| 87 | 88 | ), |
| 88 | 89 | 'remove_rsd_link' => array( |
| 89 | 90 | 'type' => 'bool', |
| 90 | 91 | 'default' => false, |
| 91 | - 'label' => __( 'Remove RSD Link', 'xspeed' ), | |
| 92 | + 'label' => __( 'Remove RSD link', 'xspeed' ), | |
| 92 | 93 | 'description' => __( 'Drop the Really Simple Discovery link from the page head. Only old desktop blogging clients read it.', 'xspeed' ), |
| 93 | 94 | ), |
| 94 | 95 | 'remove_shortlink' => array( |
| 95 | 96 | 'type' => 'bool', |
| 96 | 97 | 'default' => false, |
| 97 | - 'label' => __( 'Remove Shortlink', 'xspeed' ), | |
| 98 | + 'label' => __( 'Remove shortlink', 'xspeed' ), | |
| 98 | 99 | 'description' => __( 'Drop the ?p=123 shortlink tag and header from posts and pages. The shortlinks keep working; they are just no longer advertised.', 'xspeed' ), |
| 99 | 100 | ), |
| 100 | 101 | 'remove_rest_api_links' => array( |
| 101 | 102 | 'type' => 'bool', |
| 102 | 103 | 'default' => false, |
| 103 | - 'label' => __( 'Remove REST API Links', 'xspeed' ), | |
| 104 | + 'label' => __( 'Remove REST API links', 'xspeed' ), | |
| 104 | 105 | 'description' => __( 'Drop the /wp-json/ discovery link tag and Link header. The REST API itself stays on; to block it, use the setting below.', 'xspeed' ), |
| 105 | 106 | ), |
| 106 | 107 | 'hide_wp_version' => array( |
| 107 | 108 | 'type' => 'bool', |
| 108 | 109 | 'default' => false, |
| 109 | - 'label' => __( 'Hide WordPress Version', 'xspeed' ), | |
| 110 | + 'label' => __( 'Hide WordPress version', 'xspeed' ), | |
| 110 | 111 | 'description' => __( 'Remove the WordPress generator tag from pages and feeds, so it no longer states the WordPress version. Other plugins print their own tags; those stay. Script and style URLs still carry ?ver= numbers.', 'xspeed' ), |
| 111 | 112 | ), |
| 112 | 113 | 'disable_self_pingbacks' => array( |
| 113 | 114 | 'type' => 'bool', |
| 114 | 115 | 'default' => false, |
| 115 | - 'label' => __( 'Disable Self-Pingbacks', 'xspeed' ), | |
| 116 | + 'label' => __( 'Disable self-pingbacks', 'xspeed' ), | |
| 116 | 117 | 'description' => __( 'Stop WordPress from sending a pingback to your own site when a post links to another of your posts. Pingbacks to other sites are not affected.', 'xspeed' ), |
| 117 | 118 | ), |
| 118 | 119 | 'restrict_rest_to_authed' => array( |
| 119 | 120 | 'type' => 'bool', |
| 120 | 121 | 'default' => false, |
| 121 | - 'label' => __( 'Restrict REST API to Logged-In Users', 'xspeed' ), | |
| 122 | - 'description' => __( 'Block /wp-json/ for anonymous requests. WooCommerce checkout, contact-form submissions, and many block-editor previews need anonymous REST — keep this off unless you know your site does not depend on it.', 'xspeed' ), | |
| 122 | + 'label' => __( 'REST API for logged-in users only', 'xspeed' ), | |
| 123 | + 'description' => __( 'Blocks /wp-json/ for logged-out visitors. This breaks WooCommerce checkout and many contact forms, so keep it off unless you are sure.', 'xspeed' ), | |
| 124 | + 'advanced' => true, | |
| 123 | 125 | ), |
| 124 | 126 | ); |
| 125 | 127 | } |
| 126 | 128 | |
| @@ -175,8 +177,19 @@ | ||
| 175 | 177 | } |
| 176 | 178 | |
| 177 | 179 | if ( ! empty( $opts['strip_jquery_migrate'] ) ) { |
| 178 | 180 | add_action( 'wp_default_scripts', array( __CLASS__, 'strip_jquery_migrate' ) ); |
| 181 | + /* | |
| 182 | + * `wp_default_scripts` fires once, when something first builds the | |
| 183 | + * script registry. A plugin that registers a script while it loads | |
| 184 | + * (Elementor Pro's Forms module registers its reCAPTCHA script) does | |
| 185 | + * that before this runs on `init`, so the hook above never fires and | |
| 186 | + * Migrate stays. Strip it from the registry that already exists, | |
| 187 | + * before the page enqueues anything. (#587) | |
| 188 | + */ | |
| 189 | + if ( did_action( 'wp_default_scripts' ) ) { | |
| 190 | + add_action( 'wp_enqueue_scripts', array( __CLASS__, 'strip_jquery_migrate_now' ), 0 ); | |
| 191 | + } | |
| 179 | 192 | } |
| 180 | 193 | |
| 181 | 194 | if ( ! empty( $opts['strip_editor_styles'] ) ) { |
| 182 | 195 | // Late, so anything enqueued at normal priority is already queued. |
| @@ -407,8 +420,16 @@ | ||
| 407 | 420 | $jquery = $scripts->registered['jquery']; |
| 408 | 421 | if ( is_array( $jquery->deps ?? null ) ) { |
| 409 | 422 | $jquery->deps = array_values( array_diff( $jquery->deps, array( 'jquery-migrate' ) ) ); |
| 410 | 423 | } |
| 424 | + } | |
| 425 | + | |
| 426 | + /** | |
| 427 | + * strip_jquery_migrate() on the registry that exists now, for a request | |
| 428 | + * where `wp_default_scripts` fired before this module hooked it. (#587) | |
| 429 | + */ | |
| 430 | + public static function strip_jquery_migrate_now(): void { | |
| 431 | + self::strip_jquery_migrate( wp_scripts() ); | |
| 411 | 432 | } |
| 412 | 433 | |
| 413 | 434 | /** |
| 414 | 435 | * Block anonymous /wp-json/ access. Logged-in users + already-errored |