Plugin Directory

Changeset 3355428


Ignore:
Timestamp:
09/03/2025 12:17:33 PM (3 months ago)
Author:
quentinldd
Message:

Update to version 2.0.2 from GitHub

Location:
zenpress
Files:
40 edited
1 copied

Legend:

Unmodified
Added
Removed
  • zenpress/tags/2.0.2/assets/build/index.asset.php

    r3352459 r3355428  
    1 <?php return array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-notices'), 'version' => '9b91df213cf8e0f8ef1f');
     1<?php return array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-notices'), 'version' => 'ce3e5cbcbfb948f49cc1');
  • zenpress/tags/2.0.2/assets/build/index.js

    r3352459 r3355428  
    1 (()=>{"use strict";var e={n:s=>{var t=s&&s.__esModule?()=>s.default:()=>s;return e.d(t,{a:t}),t},d:(s,t)=>{for(var n in t)e.o(t,n)&&!e.o(s,n)&&Object.defineProperty(s,n,{enumerable:!0,get:t[n]})},o:(e,s)=>Object.prototype.hasOwnProperty.call(e,s)};const s=window.wp.domReady;var t=e.n(s);const n=window.wp.element,i=window.wp.i18n,a=window.wp.components,r=window.wp.apiFetch;var c=e.n(r);const o=window.wp.data,l=window.wp.notices,p=window.ReactJSXRuntime,d=({label:e,value:s,onChange:t,help:n})=>(0,p.jsx)(a.ToggleControl,{label:e,checked:s,onChange:t,help:n,__nextHasNoMarginBottom:!0}),h=({onClick:e,isBusy:s})=>(0,p.jsx)(a.Button,{variant:"primary",onClick:e,isBusy:s,__next40pxDefaultSize:!0,children:(0,i.__)("Save settings","zenpress")}),u=()=>{const{removeNotice:e}=(0,o.useDispatch)(l.store),s=(0,o.useSelect)(e=>e(l.store).getNotices());return s?.length?(0,p.jsx)(a.NoticeList,{notices:s,onRemove:e}):null},_=()=>{const{snippets:e,setSnippets:s,saveSettings:t,isSaving:r}=(()=>{const[e,s]=(0,n.useState)({}),[t,a]=(0,n.useState)(!1),{createSuccessNotice:r,createErrorNotice:p}=(0,o.useDispatch)(l.store);return(0,n.useEffect)(()=>{c()({path:"/wp/v2/settings"}).then(e=>{const t=Array.isArray(e?.zenpress_active_snippets)?e.zenpress_active_snippets:[],n={},i=window?.zenpressSnippetsMeta||{};Object.keys(i).forEach(e=>{const s=i[e]||{};n[e]={...s,"enable-snippet":t.includes(e)}}),s(n)}).catch(()=>{p((0,i.__)("Failed to load settings.","zenpress"))})},[p]),{snippets:e,setSnippets:s,saveSettings:()=>{a(!0);const s=Object.keys(e).filter(s=>e[s]?.["enable-snippet"]||!1);return c()({path:"/wp/v2/settings",method:"POST",data:{zenpress_active_snippets:s}}).then(()=>{r((0,i.__)("Settings saved.","zenpress"))}).catch(()=>{p((0,i.__)("Failed to save settings.","zenpress"))}).finally(()=>a(!1))},isSaving:t}})(),[_,w]=(0,n.useState)(new Set),v=e=>{s(s=>{const t={},n=new Set(_);return Object.entries(s).forEach(([s,a])=>{const r=(Array.isArray(a?.preset)?a.preset:[]).includes(e);t[s]={...a,"enable-snippet":r},r&&n.add(a.category||(0,i.__)("Uncategorized","zenpress"))}),w(n),t})},x={};Object.keys(e).forEach(s=>{const t=e[s],n=t?.category||(0,i.__)("Uncategorized","zenpress");x[n]||(x[n]=[]),x[n].push({name:s,data:t})});const j=Object.keys(x).sort((e,s)=>e.localeCompare(s,void 0,{sensitivity:"base"}));return(0,p.jsx)(p.Fragment,{children:(0,p.jsx)("div",{className:"zenpress-row",children:(0,p.jsxs)("div",{className:"zenpress-col",children:[(0,p.jsxs)("div",{className:"zenpress-presets",children:[(0,p.jsxs)("div",{className:"zenpress-presets-description",children:[(0,p.jsx)("p",{children:(0,i.__)("Select the features that suit your needs. If you don't know which ones to choose, just select your site's type and it will set the right features for you.","zenpress")}),(0,p.jsx)("h2",{children:(0,i.__)("Pick a preset","zenpress")})]}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>v("showcase-website"),__next40pxDefaultSize:!0,children:(0,i.__)("Showcase website","zenpress")}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>v("blog"),__next40pxDefaultSize:!0,children:(0,i.__)("Blog","zenpress")}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>v("ecommerce"),__next40pxDefaultSize:!0,children:(0,i.__)("E-commerce","zenpress")}),(0,p.jsx)("div",{className:"zenpress-presets-description",children:(0,p.jsx)("h2",{children:(0,i.__)("Or just enable what you need","zenpress")})}),(0,p.jsxs)("div",{className:"zenpress-actions-bulk",children:[(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>{s(e=>{const s={};return Object.keys(e).forEach(t=>{s[t]={...e[t],"enable-snippet":!0}}),s}),w(new Set(Object.values(e).map(e=>e.category||(0,i.__)("Uncategorized","zenpress"))))},__next40pxDefaultSize:!0,children:(0,i.__)("Enable all actions","zenpress")}),(0,p.jsx)(a.Button,{isDestructive:"true",onClick:()=>{s(e=>{const s={};return Object.keys(e).forEach(t=>{s[t]={...e[t],"enable-snippet":!1}}),s})},__next40pxDefaultSize:!0,children:(0,i.__)("Disable all actions","zenpress")})]})]}),j.map(e=>(0,p.jsx)(a.Panel,{children:(0,p.jsx)(a.PanelBody,{title:e,initialOpen:_.has(e)||x[e].some(({data:e})=>e?.["enable-snippet"]),children:x[e].map(({name:e,data:t})=>(0,p.jsx)(a.PanelRow,{children:(0,p.jsx)(d,{label:t.title||e,value:t?.["enable-snippet"]||!1,onChange:()=>{return t=e,void s(e=>({...e,[t]:{...e[t],"enable-snippet":!e[t]?.["enable-snippet"]}}));var t},help:t.description||""})},e))})},e)),(0,p.jsx)("div",{className:"zenpress-actions",children:(0,p.jsx)(h,{onClick:t,isBusy:r})}),(0,p.jsx)("div",{className:"zenpress-notices",children:(0,p.jsx)(u,{})})]})})})};t()(()=>{const e=document.getElementById("zenpress-settings");e&&(0,n.createRoot)(e).render((0,p.jsx)(_,{}))})})();
     1(()=>{"use strict";var e={n:s=>{var t=s&&s.__esModule?()=>s.default:()=>s;return e.d(t,{a:t}),t},d:(s,t)=>{for(var n in t)e.o(t,n)&&!e.o(s,n)&&Object.defineProperty(s,n,{enumerable:!0,get:t[n]})},o:(e,s)=>Object.prototype.hasOwnProperty.call(e,s)};const s=window.wp.domReady;var t=e.n(s);const n=window.wp.element,i=window.wp.i18n,a=window.wp.components,r=window.wp.apiFetch;var c=e.n(r);const o=window.wp.data,l=window.wp.notices,p=window.ReactJSXRuntime,d=({label:e,value:s,onChange:t,help:n})=>(0,p.jsx)(a.ToggleControl,{label:e,checked:s,onChange:t,help:n,__nextHasNoMarginBottom:!0}),h=({onClick:e,isBusy:s})=>(0,p.jsx)(a.Button,{variant:"primary",onClick:e,isBusy:s,__next40pxDefaultSize:!0,children:(0,i.__)("Save settings","zenpress")}),u=()=>{const{removeNotice:e}=(0,o.useDispatch)(l.store),s=(0,o.useSelect)(e=>e(l.store).getNotices());return s?.length?(0,p.jsx)(a.NoticeList,{notices:s,onRemove:e}):null},_=()=>{const{snippets:e,setSnippets:s,saveSettings:t,isSaving:r}=(()=>{const[e,s]=(0,n.useState)({}),[t,a]=(0,n.useState)(!1),{createSuccessNotice:r,createErrorNotice:p}=(0,o.useDispatch)(l.store);return(0,n.useEffect)(()=>{c()({path:"/wp/v2/settings"}).then(e=>{const t=Array.isArray(e?.zenpress_active_snippets)?e.zenpress_active_snippets:[],n={},i=window?.zenpressSnippetsMeta||{};Object.keys(i).forEach(e=>{const s=i[e]||{};n[e]={...s,"enable-snippet":t.includes(e)}}),s(n)}).catch(()=>{p((0,i.__)("Failed to load settings.","zenpress"))})},[p]),{snippets:e,setSnippets:s,saveSettings:()=>{a(!0);const s=Object.keys(e).filter(s=>e[s]?.["enable-snippet"]||!1);return c()({path:"/wp/v2/settings",method:"POST",data:{zenpress_active_snippets:s}}).then(()=>{r((0,i.__)("Settings saved.","zenpress"))}).catch(()=>{p((0,i.__)("Failed to save settings.","zenpress"))}).finally(()=>a(!1))},isSaving:t}})(),[_,w]=(0,n.useState)(new Set),x=e=>{s(s=>{const t={};return Object.entries(s).forEach(([s,n])=>{const i=(Array.isArray(n?.preset)?n.preset:[]).includes(e);t[s]={...n,"enable-snippet":i}}),t}),w(new Set(j))},v={};Object.keys(e).forEach(s=>{const t=e[s],n=t?.category||(0,i.__)("Uncategorized","zenpress");v[n]||(v[n]=[]),v[n].push({name:s,data:t})});const j=Object.keys(v).sort((e,s)=>e.localeCompare(s,void 0,{sensitivity:"base"}));return(0,p.jsx)(p.Fragment,{children:(0,p.jsx)("div",{className:"zenpress-row",children:(0,p.jsxs)("div",{className:"zenpress-col",children:[(0,p.jsxs)("div",{className:"zenpress-presets",children:[(0,p.jsxs)("div",{className:"zenpress-presets-description",children:[(0,p.jsx)("p",{children:(0,i.__)("Select the features that suit your needs. If you don't know which ones to choose, just select your site's type and it will set the right features for you.","zenpress")}),(0,p.jsx)("h2",{children:(0,i.__)("Pick a preset","zenpress")})]}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>x("showcase-website"),__next40pxDefaultSize:!0,children:(0,i.__)("Showcase website","zenpress")}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>x("blog"),__next40pxDefaultSize:!0,children:(0,i.__)("Blog","zenpress")}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>x("ecommerce"),__next40pxDefaultSize:!0,children:(0,i.__)("E-commerce","zenpress")}),(0,p.jsx)("div",{className:"zenpress-presets-description",children:(0,p.jsx)("h2",{children:(0,i.__)("Or just enable what you need","zenpress")})}),(0,p.jsxs)("div",{className:"zenpress-actions-bulk",children:[(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>{s(e=>{const s={};return Object.keys(e).forEach(t=>{s[t]={...e[t],"enable-snippet":!0}}),s}),w(new Set(j))},__next40pxDefaultSize:!0,children:(0,i.__)("Enable all actions","zenpress")}),(0,p.jsx)(a.Button,{isDestructive:"true",onClick:()=>{s(e=>{const s={};return Object.keys(e).forEach(t=>{s[t]={...e[t],"enable-snippet":!1}}),s})},__next40pxDefaultSize:!0,children:(0,i.__)("Disable all actions","zenpress")})]})]}),j.map(e=>(0,p.jsx)(a.Panel,{children:(0,p.jsx)(a.PanelBody,{title:e,initialOpen:_.has(e),children:v[e].map(({name:e,data:t})=>(0,p.jsx)(a.PanelRow,{children:(0,p.jsx)(d,{label:t.title||e,value:t?.["enable-snippet"]||!1,onChange:()=>{return t=e,void s(e=>({...e,[t]:{...e[t],"enable-snippet":!e[t]?.["enable-snippet"]}}));var t},help:t.description||""})},e))})},e)),(0,p.jsx)("div",{className:"zenpress-actions",children:(0,p.jsx)(h,{onClick:t,isBusy:r})}),(0,p.jsx)("div",{className:"zenpress-notices",children:(0,p.jsx)(u,{})})]})})})};t()(()=>{const e=document.getElementById("zenpress-settings");e&&(0,n.createRoot)(e).render((0,p.jsx)(_,{}))})})();
  • zenpress/tags/2.0.2/assets/src/index.js

    r3352459 r3355428  
    176176        });
    177177        // Open all categories
    178         setOpenCategories(new Set(Object.values(snippets).map((s) => s.category || __('Uncategorized', 'zenpress'))));
     178        setOpenCategories(new Set(sortedCategories));
    179179    };
    180180
     
    192192            return updated;
    193193        });
    194         // Keep categories open (do not clear)
    195194    };
    196195
    197196    /**
    198197     * Enable snippets by preset.
    199      *
    200      * All snippets not in the preset will be disabled.
    201198     *
    202199     * @param {string} preset - Preset key to enable.
     
    206203        setSnippets((prev) => {
    207204            const updated = {};
    208             const newOpen = new Set(openCategories);
    209205            Object.entries(prev).forEach(([name, data]) => {
    210206                const presets = Array.isArray(data?.preset) ? data.preset : [];
     
    214210                    'enable-snippet': isEnabled,
    215211                };
    216                 if (isEnabled) {
    217                     newOpen.add(data.category || __('Uncategorized', 'zenpress'));
    218                 }
    219212            });
    220             setOpenCategories(newOpen);
    221213            return updated;
    222214        });
     215        // Open all categories
     216        setOpenCategories(new Set(sortedCategories));
    223217    };
    224218
     
    298292                            <PanelBody
    299293                                title={category}
    300                                 // Keep open if already marked or if a snippet is enabled
    301                                 initialOpen={
    302                                     openCategories.has(category) ||
    303                                     groupedSnippets[category].some(
    304                                         ({ data }) => data?.['enable-snippet']
    305                                     )
    306                                 }
     294                                initialOpen={openCategories.has(category)}
    307295                            >
    308296                                {groupedSnippets[category].map(({ name, data }) => (
  • zenpress/tags/2.0.2/inc/snippets/disable-author-archives.php

    r3352459 r3355428  
    88remove_filter('template_redirect', 'redirect_canonical');
    99
    10 add_action('template_redirect', function () {
     10add_action('template_redirect', static function () {
    1111    if (is_author()) {
    1212        global $wp_query;
  • zenpress/tags/2.0.2/inc/snippets/disable-dashicons.php

    r3352459 r3355428  
    55}
    66
    7 add_action('wp_enqueue_scripts', function () {
     7add_action('wp_enqueue_scripts', static function () {
    88    if (!is_user_logged_in()) {
    99        wp_dequeue_style('dashicons');
  • zenpress/tags/2.0.2/inc/snippets/disable-emoji-scripts.php

    r3352459 r3355428  
    2222
    2323// Remove emoji support from TinyMCE editor.
    24 add_filter('tiny_mce_plugins', function ($plugins) {
     24add_filter('tiny_mce_plugins', static function ($plugins) {
    2525    return array_diff($plugins, ['wpemoji']);
    2626});
  • zenpress/tags/2.0.2/inc/snippets/disable-jquery-migrate.php

    r3352459 r3355428  
    55}
    66
    7 add_action('wp_default_scripts', function (&$scripts) {
     7add_action('wp_default_scripts', static function (&$scripts) {
    88    if (!is_admin() && isset($scripts->registered['jquery'])) {
    99        $script = $scripts->registered['jquery'];
  • zenpress/tags/2.0.2/inc/snippets/disable-oembed.php

    r3352459 r3355428  
    55}
    66
    7 add_action('init', 'zenpress_disable_oembed');
    8 function zenpress_disable_oembed() {
     7add_action('init', static function () {
    98    // Remove oEmbed from query vars.
    109    global $wp;
     
    4544        wp_deregister_script('wp-embed');
    4645    }
    47 }
     46});
  • zenpress/tags/2.0.2/inc/snippets/disable-pdf-thumbnails.php

    r3352459 r3355428  
    55}
    66
    7 add_filter('fallback_intermediate_image_sizes', function () {
     7add_filter('fallback_intermediate_image_sizes', static function () {
    88    return [];
    99});
  • zenpress/tags/2.0.2/inc/snippets/disable-pingback-trackback.php

    r3352459 r3355428  
    66
    77// Remove X-Pingback header from HTTP responses.
    8 add_filter('wp_headers', function ($headers) {
     8add_filter('wp_headers', static function ($headers) {
    99    unset($headers['X-Pingback']);
    1010
     
    1313
    1414// Disable pingbacks and trackbacks for new posts.
    15 add_action('after_setup_theme', function () {
     15add_action('after_setup_theme', static function () {
    1616    update_option('default_ping_status', 'closed');
    1717    update_option('default_pingback_flag', 0);
     
    1919
    2020// Prevent self-pingbacks.
    21 add_action('pre_ping', function (&$links) {
     21add_action('pre_ping', static function (&$links) {
    2222    $home = get_option('home');
    2323    foreach ($links as $l => $link) {
  • zenpress/tags/2.0.2/inc/snippets/disable-woocommerce-cart-fragments.php

    r3352459 r3355428  
    55}
    66
    7 add_action('wp_enqueue_scripts', 'zenpress_disable_cart_fragments', 11);
    8 
    9 function zenpress_disable_cart_fragments() {
    10     if (class_exists('WooCommerce')) {
     7if (class_exists('WooCommerce')) {
     8    add_action('wp_enqueue_scripts', static function () {
    119        wp_dequeue_script('wc-cart-fragments');
    12     }
     10    }, 11);
    1311}
  • zenpress/tags/2.0.2/inc/snippets/disable-woocommerce-scripts-styles.php

    r3352459 r3355428  
    11<?php
    22
    3 add_action('wp_enqueue_scripts', 'zenpress_disable_woocommerce_scripts_styles', 11);
     3if (!defined('ABSPATH')) {
     4    exit;
     5}
    46
    5 function zenpress_disable_woocommerce_scripts_styles() {
    6     if (!class_exists('WooCommerce')) {
    7         return;
    8     }
     7if (class_exists('WooCommerce')) {
     8    add_action('wp_enqueue_scripts', static function () {
     9        if (!is_woocommerce() && !is_cart() && !is_checkout() && !is_account_page() && !is_product() && !is_product_category() && !is_shop()) {
     10            // Dequeue WooCommerce Styles
     11            wp_dequeue_style('woocommerce-general');
     12            wp_dequeue_style('woocommerce-layout');
     13            wp_dequeue_style('woocommerce-smallscreen');
     14            wp_dequeue_style('woocommerce_frontend_styles');
     15            wp_dequeue_style('woocommerce_fancybox_styles');
     16            wp_dequeue_style('woocommerce_chosen_styles');
     17            wp_dequeue_style('woocommerce_prettyPhoto_css');
    918
    10     if (!is_woocommerce() && !is_cart() && !is_checkout() && !is_account_page() && !is_product() && !is_product_category() && !is_shop()) {
    11         // Dequeue WooCommerce Styles
    12         wp_dequeue_style('woocommerce-general');
    13         wp_dequeue_style('woocommerce-layout');
    14         wp_dequeue_style('woocommerce-smallscreen');
    15         wp_dequeue_style('woocommerce_frontend_styles');
    16         wp_dequeue_style('woocommerce_fancybox_styles');
    17         wp_dequeue_style('woocommerce_chosen_styles');
    18         wp_dequeue_style('woocommerce_prettyPhoto_css');
    19 
    20         // Dequeue WooCommerce Scripts
    21         wp_dequeue_script('wc-price-slider');
    22         wp_dequeue_script('wc-single-product');
    23         wp_dequeue_script('wc-add-to-cart');
    24         wp_dequeue_script('wc-checkout');
    25         wp_dequeue_script('wc-add-to-cart-variation');
    26         wp_dequeue_script('wc-cart');
    27         wp_dequeue_script('wc-chosen');
    28         wp_dequeue_script('woocommerce');
    29         wp_dequeue_script('prettyPhoto');
    30         wp_dequeue_script('prettyPhoto-init');
    31         wp_dequeue_script('jquery-blockui');
    32         wp_dequeue_script('jquery-placeholder');
    33         wp_dequeue_script('fancybox');
    34         wp_dequeue_script('jqueryui');
    35     }
     19            // Dequeue WooCommerce Scripts
     20            wp_dequeue_script('wc-price-slider');
     21            wp_dequeue_script('wc-single-product');
     22            wp_dequeue_script('wc-add-to-cart');
     23            wp_dequeue_script('wc-checkout');
     24            wp_dequeue_script('wc-add-to-cart-variation');
     25            wp_dequeue_script('wc-cart');
     26            wp_dequeue_script('wc-chosen');
     27            wp_dequeue_script('woocommerce');
     28            wp_dequeue_script('prettyPhoto');
     29            wp_dequeue_script('prettyPhoto-init');
     30            wp_dequeue_script('jquery-blockui');
     31            wp_dequeue_script('jquery-placeholder');
     32            wp_dequeue_script('fancybox');
     33            wp_dequeue_script('jqueryui');
     34        }
     35    }, 11);
    3636}
  • zenpress/tags/2.0.2/inc/snippets/disable-woocommerce-widgets.php

    r3352459 r3355428  
    66
    77if (class_exists('WooCommerce')) {
    8     add_action('widgets_init', 'zenpress_disable_woocommerce_widgets', 99);
    9 
    10     function zenpress_disable_woocommerce_widgets() {
     8    add_action('widgets_init', static function() {
    119        unregister_widget('WC_Widget_Products');
    1210        unregister_widget('WC_Widget_Product_Categories');
     
    2119        unregister_widget('WC_Widget_Top_Rated_Products');
    2220        unregister_widget('WC_Widget_Rating_Filter');
    23     }
     21    }, 99);
    2422}
  • zenpress/tags/2.0.2/inc/snippets/hide-woocommerce-version.php

    r3352459 r3355428  
    77if (class_exists('WooCommerce') && !is_admin()) {
    88    // Remove WooCommerce version from HTTP headers
    9     add_filter('wp_headers', 'zenpress_remove_woocommerce_version');
    10     function zenpress_remove_woocommerce_version($headers) {
     9    add_filter('wp_headers', static function ($headers) {
    1110        if (isset($headers['X-WooCommerce-Version'])) {
    1211            unset($headers['X-WooCommerce-Version']);
     
    1413
    1514        return $headers;
    16     }
     15    });
    1716
    18     // Remove WooCommerce version from script and style URLs
    19     add_filter('style_loader_src', 'zenpress_remove_woocommerce_version_scripts_styles', 10);
    20     add_filter('script_loader_src', 'zenpress_remove_woocommerce_version_scripts_styles', 10);
    21     function zenpress_remove_woocommerce_version_scripts_styles($src) {
     17    // Remove WooCommerce version from style URLs
     18    add_filter('style_loader_src', static function ($src) {
    2219        if (strpos($src, 'ver=') !== false && strpos($src, 'woocommerce') !== false) {
    2320            $src = remove_query_arg('ver', $src);
     
    2522
    2623        return $src;
    27     }
     24    }, 10);
     25
     26    // Remove WooCommerce version from script URLs
     27    add_filter('script_loader_src', static function ($src) {
     28        if (strpos($src, 'ver=') !== false && strpos($src, 'woocommerce') !== false) {
     29            $src = remove_query_arg('ver', $src);
     30        }
     31
     32        return $src;
     33    }, 10);
    2834}
  • zenpress/tags/2.0.2/inc/snippets/hide-wordpress-version.php

    r3352459 r3355428  
    99
    1010// Remove WordPress version from generator
    11 add_filter('the_generator', 'zenpress_remove_wordpress_version');
    12 function zenpress_remove_wordpress_version() {
     11add_filter('the_generator', static function () {
    1312    return '';
    14 }
     13});
    1514
    16 // Remove WordPress version from script and style URLs
    17 add_filter('style_loader_src', 'zenpress_remove_version_from_assets');
    18 add_filter('script_loader_src', 'zenpress_remove_version_from_assets');
    19 function zenpress_remove_version_from_assets($src) {
     15// Remove WordPress version from script URLs
     16add_filter('script_loader_src', static function ($src) {
    2017    if (strpos($src, 'ver=' . get_bloginfo('version')) !== false) {
    2118        $src = remove_query_arg('ver', $src);
     
    2320
    2421    return $src;
    25 }
     22});
     23
     24// Remove WordPress version from style URLs
     25add_filter('style_loader_src', static function ($src) {
     26    if (strpos($src, 'ver=' . get_bloginfo('version')) !== false) {
     27        $src = remove_query_arg('ver', $src);
     28    }
     29
     30    return $src;
     31});
  • zenpress/tags/2.0.2/inc/snippets/protect-wp-login.php

    r3352459 r3355428  
    66
    77// Remove detailed login errors
    8 add_filter('login_errors', function () {
     8add_filter('login_errors', static function () {
    99    return __('Login error.', 'zenpress');
    1010});
    1111
    1212// Limit login attempts
    13 add_filter('authenticate', 'zenpress_login_protection', 30, 3);
    14 function zenpress_login_protection(mixed $user, string $username, string $password): mixed {
     13add_filter('authenticate', static function (mixed $user, string $username, string $password): mixed {
    1514    $MAX_LOGIN_ATTEMPTS = 5;
    1615    $BLOCK_DURATION = 300; // 5 minutes
     
    5554
    5655    return $user;
    57 }
     56}, 30, 3);
  • zenpress/tags/2.0.2/inc/snippets/remove-gutenberg-unwanted-block-patterns.php

    r3352459 r3355428  
    99
    1010// Remove core block patterns
    11 add_action('after_setup_theme', 'zenpress_remove_core_block_patterns');
    12 function zenpress_remove_core_block_patterns() {
     11add_action('after_setup_theme', static function () {
    1312    remove_theme_support('core-block-patterns');
    14 }
     13});
  • zenpress/tags/2.0.2/inc/snippets/remove-woocommerce-patterns.php

    r3352459 r3355428  
    77use Automattic\WooCommerce\Blocks\Package;
    88
    9 add_action('woocommerce_blocks_loaded', 'zenpress_remove_wc_patterns');
    10 function zenpress_remove_wc_patterns(): void {
     9add_action('woocommerce_blocks_loaded', static function (): void {
    1110    remove_action(
    1211        'init',
     
    1615        ]
    1716    );
    18 }
     17});
  • zenpress/tags/2.0.2/readme.txt

    r3352462 r3355428  
    1 === ZenPress ===
     1=== ZenPress — Cleaner, Lighter, Faster WP ===
    22Contributors: @quentinldd
    33Donate link: https://github.com/sponsors/quentin-ld/
     
    55Requires at least: 6.0
    66Tested up to: 6.8
    7 Stable tag: 2.0.1
     7Stable tag: 2.0.2
    88Requires PHP: 7.4
    99License: GPLv2 or later
     
    1414== Description ==
    1515
    16 ZenPress is a lightweight, super-fast plugin that boosts your WordPress & WooCommerce website through a wide range of solid actions. This is a simple solution for improving your WordPress website's performance and security while enjoying a simpler and lighter UI.
     16ZenPress is a lightweight, super-fast plugin that boosts your WordPress & WooCommerce website through a wide range of solid actions.
     17This is a simple solution for improving your WordPress website's performance and security while enjoying a simpler and lighter UI.
    1718No database clutter, no ads, no pro version. Just install, activate, select what you need or pick up your settings preset and you are ready to go !
    1819
     
    7475* Remove WooCommerce default remote block patterns
    7576
     77== Roadmap ==
     78
     79= Global =
     80* New presets
     81
     82= Security =
     83* Disable Application Passwords
     84* Manage Heartbeat API (frontend + backend + admin whitelist)
     85* Disable REST API
     86
     87= Performance =
     88* Disable capital_P_dangit filter
     89* Disable autosave
     90* Disable post revision
     91* Disable native lazy loading
     92* Disable Password Strength Meter
     93* Disable WordPress default lazy loading
     94
     95= UI =
     96* Remove "howdy" from admin bar
     97* Remove WordPress logo
     98* Remove "Help button"
     99* Remove "Thanks for using WordPress" in footer
     100* Remove "site health" page
     101* Remove "Privacy tools"
     102
     103= WooCommerce =
     104* Disable WooCommerce tracking
     105* Disable marketing hub
     106* Disable dashboard setup widget
     107* Disable new product editor
     108* Disable WooCommerce blocks
     109* Disable WooCommerce promo emails
     110
     111= Plugins =
     112* Disable CF7 CSS & JS
     113* Disable Elementor bloat
     114* Disable WP Bakery bloat
     115* Disable Divi bloat
     116* Disable Yoast SEO bloat
     117* Disable Jetpack bloat
     118* Disable Updraft bloat
     119
     120== Privacy Statement ==
     121
     122ZenPress is private by default and always will be. It does not store any data. It does not send data to any third party, nor does it include any third party resources.
     123
     124== Accessibility Statement ==
     125
     126ZenPress aims to be fully accessible to all of its users.
     127
    76128== Screenshots ==
    77129
    781301. ZenPress admin interface.
    79 1. Dashboard without ZenPress.
    80 2. Dashboard with ZenPress.
    81 3. Site editor without ZenPress.
    82 4. Site editor with ZenPress.
    83 5. Login page without ZenPress login protection.
    84 6. Login page with ZenPress login protection.
    85 7. Login page with ZenPress login protection after trying to brute force it.
    86 8. Website head without ZenPress.
    87 9. Website head with ZenPress.
    88 
    89 == Privacy Statement ==
    90 
    91 ZenPress is private by default and always will be. It does not store any data. It does not send data to any third party, nor does it include any third party resources.
    92 
    93 == Accessibility Statement ==
    94 
    95 ZenPress aims to be fully accessible to all of its users.
     1312. Dashboard without ZenPress.
     1323. Dashboard with ZenPress.
     1334. Site editor without ZenPress.
     1345. Site editor with ZenPress.
     1356. Login page without ZenPress login protection.
     1367. Login page with ZenPress login protection.
     1378. Login page with ZenPress login protection after trying to brute force it.
     1389. Website head without ZenPress.
     13910. Website head with ZenPress.
    96140
    97141== Frequently Asked Questions ==
     
    101145Yes, there is no pro version for this plugin and there never will be.
    102146
    103 However, I am accepting donations on my buymeacoffee page : https://buymeacoffee.com/quentinld. If you work at an agency that develops with WordPress, ask your company to provide sponsorship in order to invest in its supply chain. The tools that I maintain probably save your company time and money, and Buy me a coffee support can now be done at the organisation level.
    104 
    105 In addition, if you like the plugin then I'd love for you to leave a review. Tell all your friends about it too!
     147However, [I am accepting sponsorships via the GitHub Sponsors program](https://github.com/sponsors/quentin-ld/dashboard). If you work at an agency that develops with WordPress, ask your company to provide sponsorship in order to invest in its supply chain. The tools that I maintain probably save your company time and money, and GitHub sponsorship can now be done at the organisation level.
     148
     149In addition, if you like the plugin then I'd love for you to [leave a review](https://wordpress.org/support/plugin/zenpress/reviews/). Tell all your friends about it too!
    106150
    107151= I have a suggestion =
     
    114158
    115159== Changelog ==
     160
     161= 2.0.2 =
     162
     163- Global : Codebase and snippets optimization
     164- Global : Fixed a bug in the automatic opening and closing function of the panels on the settings page.
    116165
    117166= 2.0.1 =
  • zenpress/tags/2.0.2/zenpress.php

    r3352462 r3355428  
    1010 * @license   GPL v2 or later
    1111 *
    12  * Plugin Name: ZenPress
     12 * Plugin Name: ZenPress — Cleaner, Lighter, Faster WP
    1313 * Description: Easily speed up and strengthen your WordPress site by cleaning out unnecessary features and protecting weak points.
    14  * Version: 2.0.1
     14 * Version: 2.0.2
    1515 * Plugin URI: https://wordpress.org/plugins/zenpress/
    1616 * Author: Quentin Le Duff
     
    3131 * This program is distributed in the hope that it will be useful,
    3232 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    33  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    3434 * GNU General Public License for more details.
    35  *
    36  */
    37 
    38 /*****
    39  * TODOLIST ▓▒░(°◡°)░▒▓
    40 ****/
    41 // TODO: Disable comments URL
    42 // TODO: CHECK THE DEPLOYMENT WORKING PROPERLY
     35 */
    4336
    4437if (!defined('ABSPATH')) {
     
    4740
    4841/**
    49  * Add settings link on the plugins list page (next to Activate/Deactivate).
    50  *
    51  * @param array $links Existing plugin action links.
    52  * @return array Modified links with Settings link appended at the end.
    53  */
    54 function zenpress_add_settings_link(array $links): array {
    55     $settings_url = admin_url('options-general.php?page=zenpress');
    56 
    57     $settings_link = sprintf(
    58         '<a href="%s" aria-label="%s">%s</a>',
    59         esc_url($settings_url),
    60         esc_attr__('Go to ZenPress settings page', 'zenpress'),
    61         esc_html__('Settings', 'zenpress')
    62     );
    63 
    64     // Add "Settings" link at the end instead of first
    65     $links[] = $settings_link;
    66 
    67     return $links;
    68 }
    69 add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'zenpress_add_settings_link');
    70 
    71 
    72 /**
    73  * Add extra links under the plugin description on the plugins page.
    74  *
    75  * @param array  $links Existing links.
    76  * @param string $file  Current plugin file.
    77  * @return array Modified links.
    78  */
    79 function zenpress_plugin_row_meta($links, $file) {
    80     if ($file === plugin_basename(__FILE__)) {
    81         $extra_links = array(
    82             '<a href="' . esc_url('https://wordpress.org/plugins/zenpress/#developers') . '" target="_blank" rel="noopener noreferrer" aria-label="' . esc_attr__('View ZenPress changelog on WordPress.org (opens in a new tab)', 'zenpress') . '">' . esc_html__('Changelog', 'zenpress') . '</a>',
    83             '<a href="' . esc_url('https://holdmywp.com/zenpress/') . '" target="_blank" rel="noopener noreferrer" aria-label="' . esc_attr__('Read ZenPress documentation (opens in a new tab)', 'zenpress') . '">' . esc_html__('Docs', 'zenpress') . '</a>',
    84             '<a href="' . esc_url('https://buymeacoffee.com/quentinld') . '" target="_blank" rel="noopener noreferrer" aria-label="' . esc_attr__('Support ZenPress by buying a coffee (opens in a new tab)', 'zenpress') . '">' . esc_html__('Support ☕', 'zenpress') . '</a>',
    85         );
    86 
    87         $links = array_merge($links, $extra_links);
    88     }
    89 
    90     return $links;
    91 }
    92 add_filter('plugin_row_meta', 'zenpress_plugin_row_meta', 10, 2);
    93 
    94 
    95 
    96 /**
    9742 * Enqueue scripts and styles used by the plugin in admin area.
    9843 *
     
    10045 * @return void
    10146 */
     47add_action('admin_enqueue_scripts', 'zenpress_admin_enqueue_scripts');
    10248function zenpress_admin_enqueue_scripts(string $admin_page): void {
    103     if ($admin_page !== 'settings_page_zenpress') {
     49    if ('settings_page_zenpress' !== $admin_page) {
    10450        return;
    10551    }
    10652
    10753    $asset_file = plugin_dir_path(__FILE__) . 'assets/build/index.asset.php';
    108     if (!is_file($asset_file)) {
     54    if (!file_exists($asset_file)) {
    10955        return;
    11056    }
    11157
    112     /** @var mixed $asset */
    11358    $asset = include $asset_file;
    114 
    115     if (!is_array($asset) || empty($asset['dependencies']) || empty($asset['version'])) {
    116         return;
    117     }
    118 
    119     $dependencies = array_map('sanitize_key', (array) $asset['dependencies']);
    120     $version      = sanitize_text_field((string) $asset['version']);
    121 
    12259    wp_enqueue_script(
    12360        'zenpress-scripts',
    12461        plugins_url('assets/build/index.js', __FILE__),
    125         $dependencies,
    126         $version,
     62        $asset['dependencies'],
     63        $asset['version'],
    12764        true
    12865    );
     
    13269        plugins_url('assets/build/index.css', __FILE__),
    13370        array_filter(
    134             $dependencies,
    135             static fn($style) => is_string($style) && wp_style_is($style, 'registered')
     71            $asset['dependencies'],
     72            function ($style) {
     73                return wp_style_is($style, 'registered');
     74            }
    13675        ),
    137         $version
    138     );
    139 }
    140 add_action('admin_enqueue_scripts', 'zenpress_admin_enqueue_scripts');
     76        $asset['version']
     77    );
     78}
     79
     80/**
     81 * Localize translated snippet metadata for use in JavaScript.
     82 *
     83 * @param string $admin_page Current admin page hook.
     84 * @return void
     85 */
     86add_action('admin_enqueue_scripts', 'zenpress_localize_snippets_meta');
     87function zenpress_localize_snippets_meta(string $admin_page): void {
     88    if ('settings_page_zenpress' !== $admin_page) {
     89        return;
     90    }
     91
     92    $snippets = [];
     93    $snippets_path = plugin_dir_path(__FILE__) . 'inc/snippets/';
     94    if (!is_dir($snippets_path)) {
     95        return;
     96    }
     97
     98    foreach (glob($snippets_path . '*.php') as $file) {
     99        $basename = basename($file, '.php');
     100        $snippets[$basename] = zenpress_extract_snippet_metadata($basename);
     101    }
     102
     103    wp_localize_script('zenpress-scripts', 'zenpressSnippetsMeta', $snippets);
     104}
     105
     106/**
     107 * Add a settings link on the plugins list page.
     108 *
     109 * @param array $links Existing plugin action links.
     110 * @return array Modified plugin action links.
     111 */
     112add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'zenpress_add_settings_link');
     113function zenpress_add_settings_link(array $links): array {
     114    $url = admin_url('options-general.php?page=zenpress');
     115    $links[] = sprintf(
     116        '<a href="%s" aria-label="%s">%s</a>',
     117        esc_url($url),
     118        esc_attr__('Go to ZenPress settings page', 'zenpress'),
     119        esc_html__('Settings', 'zenpress')
     120    );
     121    return $links;
     122}
     123
     124/**
     125 * Add extra links under the plugin description on the plugins page.
     126 *
     127 * @param array  $links Existing row meta links.
     128 * @param string $file  Current plugin file.
     129 * @return array Modified row meta links.
     130 */
     131add_filter('plugin_row_meta', 'zenpress_plugin_row_meta', 10, 2);
     132function zenpress_plugin_row_meta(array $links, string $file): array {
     133    if ($file === plugin_basename(__FILE__)) {
     134        $extra_links = array(
     135            sprintf(
     136                '<a href="%s" target="_blank" rel="noopener noreferrer" aria-label="%s">%s</a>',
     137                esc_url('https://wordpress.org/plugins/zenpress/#developers'),
     138                esc_attr__('View ZenPress changelog on WordPress.org (opens in a new tab)', 'zenpress'),
     139                esc_html__('Changelog', 'zenpress')
     140            ),
     141            sprintf(
     142                '<a href="%s" target="_blank" rel="noopener noreferrer" aria-label="%s">%s</a>',
     143                esc_url('https://holdmywp.com/zenpress/'),
     144                esc_attr__('Read ZenPress documentation (opens in a new tab)', 'zenpress'),
     145                esc_html__('Docs', 'zenpress')
     146            ),
     147            sprintf(
     148                '<a href="%s" target="_blank" rel="noopener noreferrer" aria-label="%s">%s</a>',
     149                esc_url('https://buymeacoffee.com/quentinld'),
     150                esc_attr__('Support ZenPress by buying a coffee (opens in a new tab)', 'zenpress'),
     151                esc_html__('Support ☕', 'zenpress')
     152            )
     153        );
     154        $links = array_merge($links, $extra_links);
     155    }
     156    return $links;
     157}
    141158
    142159/**
     
    145162 * @return void
    146163 */
     164add_action('admin_menu', 'zenpress_add_option_page');
    147165function zenpress_add_option_page(): void {
    148166    add_options_page(
     
    154172    );
    155173}
    156 add_action('admin_menu', 'zenpress_add_option_page');
    157174
    158175/**
     
    162179 */
    163180function zenpress_options_page(): void {
    164     $plugin_data = get_file_data(__FILE__, ['Version' => 'Version'], 'plugin');
    165     $plugin_version = $plugin_data['Version'] ?? '';
     181    $plugin_data = get_file_data(__FILE__, ['Version' => 'Version'], 'plugin');
     182    $plugin_version = $plugin_data['Version'] ?? '';
    166183    ?>
    167184    <div class="wrap zenpress-dashboard-wrap">
    168185        <div class="zenpress-header">
    169186            <div class="zenpress-header-title">
    170                 <h1>
    171                     <?php echo esc_html__('ZenPress', 'zenpress'); ?>
    172                 </h1>
    173                 <?php if ($plugin_version) : ?>
    174                     <p class="zenpress-plugin-version">
    175                         <?php echo esc_html__('Version', 'zenpress') . ' ' . esc_html($plugin_version) . ' - '; ?>
    176                         <a href="https://wordpress.org/plugins/zenpress/#developers"
    177                         target="_blank"
    178                         rel="noopener noreferrer"
    179                         aria-label="<?php echo esc_attr__('View ZenPress changelog on WordPress.org (opens in a new tab)', 'zenpress'); ?>">
    180                             <?php echo esc_html__('What\'s new ?', 'zenpress'); ?>
    181                         </a>
    182                     </p>
    183                 <?php endif; ?>
    184             </div>
    185             <div class="zenpress-header-navigation">
    186                 <a href="https://holdmywp.com/zenpress/"
    187                    target="_blank"
    188                    rel="noopener noreferrer"
    189                    aria-label="<?php echo esc_attr__('Read the ZenPress documentation (opens in a new tab)', 'zenpress'); ?>">
    190                     <?php echo esc_html__('Documentation', 'zenpress'); ?>
    191                 </a>
    192 
    193                 <a href="https://wordpress.org/plugins/zenpress/#reviews"
    194                    target="_blank"
    195                    rel="noopener noreferrer"
    196                    aria-label="<?php echo esc_attr__('Leave a review for ZenPress on WordPress.org (opens in a new tab)', 'zenpress'); ?>">
    197                     <?php echo esc_html__('Leave a review (helps a lot)', 'zenpress'); ?>
    198                 </a>
    199 
    200                 <a href="https://buymeacoffee.com/quentinld"
    201                    target="_blank"
    202                    rel="noopener noreferrer"
    203                    class="components-button is-next-40px-default-size is-tertiary"
    204                    aria-label="<?php echo esc_attr__('Support development: Buy me a coffee (opens in a new tab)', 'zenpress'); ?>">
    205                     <?php echo esc_html__('Buy me a coffee', 'zenpress'); ?> <span aria-hidden="true">☕</span>
    206                 </a>
    207             </div>
     187                <h1><?php echo esc_html__('ZenPress', 'zenpress'); ?></h1>
     188                <?php if ($plugin_version) : ?>
     189                    <p class="zenpress-plugin-version">
     190                        <?php echo esc_html__('Version', 'zenpress') . ' ' . esc_html($plugin_version) . ' - '; ?>
     191                        <a href="https://wordpress.org/plugins/zenpress/#developers"
     192                           target="_blank"
     193                           rel="noopener noreferrer"
     194                           aria-label="<?php echo esc_attr__('View ZenPress changelog on WordPress.org (opens in a new tab)', 'zenpress'); ?>">
     195                            <?php echo esc_html__('What\'s new ?', 'zenpress'); ?>
     196                        </a>
     197                    </p>
     198                <?php endif; ?>
     199            </div>
     200            <div class="zenpress-header-navigation">
     201                <a href="https://holdmywp.com/zenpress/"
     202                   target="_blank"
     203                   rel="noopener noreferrer"
     204                   aria-label="<?php echo esc_attr__('Read the ZenPress documentation (opens in a new tab)', 'zenpress'); ?>">
     205                    <?php echo esc_html__('Documentation', 'zenpress'); ?>
     206                </a>
     207                <a href="https://wordpress.org/plugins/zenpress/#reviews"
     208                   target="_blank"
     209                   rel="noopener noreferrer"
     210                   aria-label="<?php echo esc_attr__('Leave a review for ZenPress on WordPress.org (opens in a new tab)', 'zenpress'); ?>">
     211                    <?php echo esc_html__('Leave a review (helps a lot)', 'zenpress'); ?>
     212                </a>
     213                <a href="https://buymeacoffee.com/quentinld"
     214                   target="_blank"
     215                   rel="noopener noreferrer"
     216                   class="components-button is-next-40px-default-size is-tertiary"
     217                   aria-label="<?php echo esc_attr__('Support development: Buy me a coffee (opens in a new tab)', 'zenpress'); ?>">
     218                    <?php echo esc_html__('Buy me a coffee', 'zenpress'); ?> <span aria-hidden="true">☕</span>
     219                </a>
     220            </div>
    208221        </div>
    209 
    210222        <div id="zenpress-settings" class="zenpress-settings">
    211             <div class="zenpress-loading card">
    212                 <div class="zenpress-loading-body">
    213                     <p class="zenpress-loading-text">
    214                         <?php echo esc_html__('Loading your ZenPress settings…', 'zenpress'); ?>
    215                     </p>
    216                 </div>
    217             </div>
     223            <div class="zenpress-loading card">
     224                <div class="zenpress-loading-body">
     225                    <p class="zenpress-loading-text">
     226                        <?php echo esc_html__('Loading your ZenPress settings…', 'zenpress'); ?>
     227                    </p>
     228                </div>
     229            </div>
    218230        </div>
    219 
    220         <div class="zenpress-footer">
    221             <div class="zenpress-footer-title">
     231        <div class="zenpress-footer">
     232            <div class="zenpress-footer-title">
    222233                <p>
    223                     <?php echo esc_html__('Made ', 'zenpress'); ?>
    224                     <span aria-hidden="true"> x ❤️ </span>
    225                     <?php echo esc_html__(' by Quentin Le Duff - Your WordPress Partner', 'zenpress'); ?>
    226                 </p>
    227             </div>
    228             <div class="zenpress-footer-navigation">
    229                 <a href="https://holdmywp.com/"
    230                    target="_blank"
    231                    rel="noopener noreferrer"
    232                    aria-label="<?php echo esc_attr__('Visite the developper website', 'zenpress'); ?>">
    233                     <?php echo esc_html__('My place', 'zenpress'); ?>
    234                 </a>
    235                 <a href="https://github.com/quentin-ld/zenpress"
    236                    target="_blank"
    237                    rel="noopener noreferrer"
    238                    aria-label="<?php echo esc_attr__('Review the code on Github', 'zenpress'); ?>">
    239                     <?php echo esc_html__('ZenPress code repository', 'zenpress'); ?>
    240                 </a>
    241             </div>
     234                    <?php echo esc_html__('Made ', 'zenpress'); ?>
     235                    <span aria-hidden="true"> x ❤️ </span>
     236                    <?php echo esc_html__(' by Quentin Le Duff - Your WordPress Partner', 'zenpress'); ?>
     237                </p>
     238            </div>
     239            <div class="zenpress-footer-navigation">
     240                <a href="https://holdmywp.com/"
     241                   target="_blank"
     242                   rel="noopener noreferrer"
     243                   aria-label="<?php echo esc_attr__('Visite the developper website', 'zenpress'); ?>">
     244                    <?php echo esc_html__('My place', 'zenpress'); ?>
     245                </a>
     246                <a href="https://github.com/quentin-ld/zenpress"
     247                   target="_blank"
     248                   rel="noopener noreferrer"
     249                   aria-label="<?php echo esc_attr__('Review the code on Github', 'zenpress'); ?>">
     250                    <?php echo esc_html__('ZenPress code repository', 'zenpress'); ?>
     251                </a>
     252            </div>
    242253        </div>
    243254    </div>
     
    246257
    247258/**
    248  * Extract snippet metadata from corresponding meta file.
    249  *
    250  * @param string $snippet_name Base name of the snippet (without extension).
    251  * @return array<string,mixed> Metadata array with keys: title, description, category, weight, preset.
     259 * Extract snippet metadata from its meta file.
     260 *
     261 * @param string $snippet_name Snippet base name (without extension).
     262 * @return array<string,mixed> Sanitized metadata (title, description, category, weight, preset).
    252263 */
    253264function zenpress_extract_snippet_metadata(string $snippet_name): array {
    254     $metadata = [
     265    $defaults = array(
    255266        'title'       => '',
    256267        'description' => '',
    257268        'category'    => '',
    258269        'weight'      => 0,
    259         'preset'      => [],
    260     ];
    261 
    262     $safe_name = sanitize_file_name($snippet_name);
    263     $meta_file = plugin_dir_path(__FILE__) . 'inc/meta/' . $safe_name . '.meta.php';
    264 
    265     if (is_file($meta_file)) {
    266         /** @var mixed $data */
    267         $data = include $meta_file;
    268         if (is_array($data)) {
    269             $metadata = array_merge($metadata, array_intersect_key($data, $metadata));
    270         }
    271     }
    272 
    273     // Sanitize values securely
    274     $metadata['title']       = sanitize_text_field($metadata['title']);
    275     $metadata['description'] = sanitize_text_field($metadata['description']);
    276     $metadata['category']    = sanitize_text_field($metadata['category']);
    277     $metadata['weight']      = intval($metadata['weight']);
    278     $metadata['preset']      = array_map('sanitize_text_field', (array) $metadata['preset']);
    279 
    280     return $metadata;
    281 }
    282 
    283 
    284 /**
    285  * Register a single option to store all active snippets.
    286  *
    287  * @return void
    288  */
     270        'preset'      => array()
     271    );
     272
     273    $file = plugin_dir_path(__FILE__) . 'inc/meta/' . sanitize_file_name($snippet_name) . '.meta.php';
     274    $data = is_file($file) ? include $file : array();
     275    $metadata = array_merge($defaults, is_array($data) ? $data : array());
     276
     277    return array(
     278        'title'       => sanitize_text_field($metadata['title']),
     279        'description' => sanitize_text_field($metadata['description']),
     280        'category'    => sanitize_text_field($metadata['category']),
     281        'weight'      => (int) $metadata['weight'],
     282        'preset'      => array_map('sanitize_text_field', (array) $metadata['preset'])
     283    );
     284}
     285
     286/**
     287 * Register option to store active snippets.
     288 */
     289add_action('init', 'zenpress_register_snippet_settings');
    289290function zenpress_register_snippet_settings(): void {
    290291    register_setting(
    291292        'options',
    292293        'zenpress_active_snippets',
    293         [
     294        array(
    294295            'type'              => 'array',
    295             'default'           => [],
    296             'sanitize_callback' => static function ($value): array {
    297                 return array_values(array_filter(
    298                     array_map('sanitize_file_name', (array) $value)
    299                 ));
    300             },
    301             'show_in_rest' => [
    302                 'schema' => [
     296            'default'           => array(),
     297            'sanitize_callback' => 'zenpress_sanitize_snippets_option',
     298            'show_in_rest'      => array(
     299                'schema' => array(
    303300                    'type'  => 'array',
    304                     'items' => [ 'type' => 'string' ],
    305                 ],
    306             ],
    307         ]
    308     );
    309 }
    310 add_action('init', 'zenpress_register_snippet_settings');
    311 
    312 /**
    313  * Load enabled snippets.
    314  *
    315  * @param string $folder Relative folder where snippets are stored.
    316  * @return array<int,string> List of loaded snippet base names.
     301                    'items' => array('type' => 'string')
     302                )
     303            )
     304        )
     305    );
     306}
     307
     308/**
     309 * Sanitize the list of active snippets.
     310 *
     311 * @param mixed $value Option value.
     312 * @return array<string> Sanitized base names.
     313 */
     314function zenpress_sanitize_snippets_option($value): array {
     315    return array_values(
     316        array_filter(
     317            array_map('sanitize_file_name', (array) $value)
     318        )
     319    );
     320}
     321
     322/**
     323 * Load all active snippets.
     324 *
     325 * @param string $folder Relative folder path for snippets.
     326 * @return array<string> Loaded snippet base names.
    317327 */
    318328function zenpress_load_snippets(string $folder = 'inc/snippets/'): array {
    319     $snippets_path = plugin_dir_path(__FILE__) . rtrim($folder, '/') . '/';
    320     if (!is_dir($snippets_path)) {
    321         return [];
    322     }
    323 
    324     $active_snippets = get_option('zenpress_active_snippets', []);
    325     if (!is_array($active_snippets)) {
    326         $active_snippets = [];
    327     }
    328 
    329     $loaded = [];
    330     foreach ($active_snippets as $base_name) {
    331         $safe_name     = sanitize_file_name($base_name);
    332         $file          = $snippets_path . $safe_name . '.php';
    333         $constant_name = 'ZENPRESS_' . strtoupper(str_replace(['-', '_'], '_', $safe_name));
    334 
    335         if (is_file($file) && (!defined($constant_name) || constant($constant_name) !== false)) {
     329    $path = plugin_dir_path(__FILE__) . rtrim($folder, '/') . '/';
     330
     331    if (!is_dir($path)) {
     332        return array();
     333    }
     334
     335    $snippets = (array) get_option('zenpress_active_snippets', array());
     336    $loaded = array();
     337    foreach ($snippets as $name) {
     338        $name = sanitize_file_name($name);
     339        $file = $path . $name . '.php';
     340        $constant = 'ZENPRESS_' . strtoupper(str_replace(array('-', '_'), '_', $name));
     341        if (is_file($file) && (!defined($constant) || constant($constant) !== false)) {
    336342            include_once $file;
    337             $loaded[] = $safe_name;
     343            $loaded[] = $name;
    338344        }
    339345    }
    340 
    341346    return $loaded;
    342347}
    343 add_action('init', function () {
    344     return zenpress_load_snippets();
     348
     349/**
     350 * Boot ZenPress snippets.
     351 */
     352add_action('init', function() : void {
     353    zenpress_load_snippets();
    345354});
    346 
    347 /**
    348  * Localize translated snippet metadata for use in JavaScript.
    349  *
    350  * @param string $hook Current admin page hook.
    351  * @return void
    352  */
    353 add_action('admin_enqueue_scripts', static function (string $hook): void {
    354     if ($hook !== 'settings_page_zenpress') {
    355         return;
    356     }
    357 
    358     $snippets = [];
    359     $snippets_path = plugin_dir_path(__FILE__) . 'inc/snippets/';
    360     if (!is_dir($snippets_path)) {
    361         return;
    362     }
    363 
    364     foreach (glob($snippets_path . '*.php') ?: [] as $file) {
    365         $base_name = basename($file, '.php');
    366         $snippets[$base_name] = zenpress_extract_snippet_metadata($base_name);
    367     }
    368 
    369     wp_localize_script('zenpress-scripts', 'zenpressSnippetsMeta', $snippets);
    370 });
  • zenpress/trunk/assets/build/index.asset.php

    r3352459 r3355428  
    1 <?php return array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-notices'), 'version' => '9b91df213cf8e0f8ef1f');
     1<?php return array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-notices'), 'version' => 'ce3e5cbcbfb948f49cc1');
  • zenpress/trunk/assets/build/index.js

    r3352459 r3355428  
    1 (()=>{"use strict";var e={n:s=>{var t=s&&s.__esModule?()=>s.default:()=>s;return e.d(t,{a:t}),t},d:(s,t)=>{for(var n in t)e.o(t,n)&&!e.o(s,n)&&Object.defineProperty(s,n,{enumerable:!0,get:t[n]})},o:(e,s)=>Object.prototype.hasOwnProperty.call(e,s)};const s=window.wp.domReady;var t=e.n(s);const n=window.wp.element,i=window.wp.i18n,a=window.wp.components,r=window.wp.apiFetch;var c=e.n(r);const o=window.wp.data,l=window.wp.notices,p=window.ReactJSXRuntime,d=({label:e,value:s,onChange:t,help:n})=>(0,p.jsx)(a.ToggleControl,{label:e,checked:s,onChange:t,help:n,__nextHasNoMarginBottom:!0}),h=({onClick:e,isBusy:s})=>(0,p.jsx)(a.Button,{variant:"primary",onClick:e,isBusy:s,__next40pxDefaultSize:!0,children:(0,i.__)("Save settings","zenpress")}),u=()=>{const{removeNotice:e}=(0,o.useDispatch)(l.store),s=(0,o.useSelect)(e=>e(l.store).getNotices());return s?.length?(0,p.jsx)(a.NoticeList,{notices:s,onRemove:e}):null},_=()=>{const{snippets:e,setSnippets:s,saveSettings:t,isSaving:r}=(()=>{const[e,s]=(0,n.useState)({}),[t,a]=(0,n.useState)(!1),{createSuccessNotice:r,createErrorNotice:p}=(0,o.useDispatch)(l.store);return(0,n.useEffect)(()=>{c()({path:"/wp/v2/settings"}).then(e=>{const t=Array.isArray(e?.zenpress_active_snippets)?e.zenpress_active_snippets:[],n={},i=window?.zenpressSnippetsMeta||{};Object.keys(i).forEach(e=>{const s=i[e]||{};n[e]={...s,"enable-snippet":t.includes(e)}}),s(n)}).catch(()=>{p((0,i.__)("Failed to load settings.","zenpress"))})},[p]),{snippets:e,setSnippets:s,saveSettings:()=>{a(!0);const s=Object.keys(e).filter(s=>e[s]?.["enable-snippet"]||!1);return c()({path:"/wp/v2/settings",method:"POST",data:{zenpress_active_snippets:s}}).then(()=>{r((0,i.__)("Settings saved.","zenpress"))}).catch(()=>{p((0,i.__)("Failed to save settings.","zenpress"))}).finally(()=>a(!1))},isSaving:t}})(),[_,w]=(0,n.useState)(new Set),v=e=>{s(s=>{const t={},n=new Set(_);return Object.entries(s).forEach(([s,a])=>{const r=(Array.isArray(a?.preset)?a.preset:[]).includes(e);t[s]={...a,"enable-snippet":r},r&&n.add(a.category||(0,i.__)("Uncategorized","zenpress"))}),w(n),t})},x={};Object.keys(e).forEach(s=>{const t=e[s],n=t?.category||(0,i.__)("Uncategorized","zenpress");x[n]||(x[n]=[]),x[n].push({name:s,data:t})});const j=Object.keys(x).sort((e,s)=>e.localeCompare(s,void 0,{sensitivity:"base"}));return(0,p.jsx)(p.Fragment,{children:(0,p.jsx)("div",{className:"zenpress-row",children:(0,p.jsxs)("div",{className:"zenpress-col",children:[(0,p.jsxs)("div",{className:"zenpress-presets",children:[(0,p.jsxs)("div",{className:"zenpress-presets-description",children:[(0,p.jsx)("p",{children:(0,i.__)("Select the features that suit your needs. If you don't know which ones to choose, just select your site's type and it will set the right features for you.","zenpress")}),(0,p.jsx)("h2",{children:(0,i.__)("Pick a preset","zenpress")})]}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>v("showcase-website"),__next40pxDefaultSize:!0,children:(0,i.__)("Showcase website","zenpress")}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>v("blog"),__next40pxDefaultSize:!0,children:(0,i.__)("Blog","zenpress")}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>v("ecommerce"),__next40pxDefaultSize:!0,children:(0,i.__)("E-commerce","zenpress")}),(0,p.jsx)("div",{className:"zenpress-presets-description",children:(0,p.jsx)("h2",{children:(0,i.__)("Or just enable what you need","zenpress")})}),(0,p.jsxs)("div",{className:"zenpress-actions-bulk",children:[(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>{s(e=>{const s={};return Object.keys(e).forEach(t=>{s[t]={...e[t],"enable-snippet":!0}}),s}),w(new Set(Object.values(e).map(e=>e.category||(0,i.__)("Uncategorized","zenpress"))))},__next40pxDefaultSize:!0,children:(0,i.__)("Enable all actions","zenpress")}),(0,p.jsx)(a.Button,{isDestructive:"true",onClick:()=>{s(e=>{const s={};return Object.keys(e).forEach(t=>{s[t]={...e[t],"enable-snippet":!1}}),s})},__next40pxDefaultSize:!0,children:(0,i.__)("Disable all actions","zenpress")})]})]}),j.map(e=>(0,p.jsx)(a.Panel,{children:(0,p.jsx)(a.PanelBody,{title:e,initialOpen:_.has(e)||x[e].some(({data:e})=>e?.["enable-snippet"]),children:x[e].map(({name:e,data:t})=>(0,p.jsx)(a.PanelRow,{children:(0,p.jsx)(d,{label:t.title||e,value:t?.["enable-snippet"]||!1,onChange:()=>{return t=e,void s(e=>({...e,[t]:{...e[t],"enable-snippet":!e[t]?.["enable-snippet"]}}));var t},help:t.description||""})},e))})},e)),(0,p.jsx)("div",{className:"zenpress-actions",children:(0,p.jsx)(h,{onClick:t,isBusy:r})}),(0,p.jsx)("div",{className:"zenpress-notices",children:(0,p.jsx)(u,{})})]})})})};t()(()=>{const e=document.getElementById("zenpress-settings");e&&(0,n.createRoot)(e).render((0,p.jsx)(_,{}))})})();
     1(()=>{"use strict";var e={n:s=>{var t=s&&s.__esModule?()=>s.default:()=>s;return e.d(t,{a:t}),t},d:(s,t)=>{for(var n in t)e.o(t,n)&&!e.o(s,n)&&Object.defineProperty(s,n,{enumerable:!0,get:t[n]})},o:(e,s)=>Object.prototype.hasOwnProperty.call(e,s)};const s=window.wp.domReady;var t=e.n(s);const n=window.wp.element,i=window.wp.i18n,a=window.wp.components,r=window.wp.apiFetch;var c=e.n(r);const o=window.wp.data,l=window.wp.notices,p=window.ReactJSXRuntime,d=({label:e,value:s,onChange:t,help:n})=>(0,p.jsx)(a.ToggleControl,{label:e,checked:s,onChange:t,help:n,__nextHasNoMarginBottom:!0}),h=({onClick:e,isBusy:s})=>(0,p.jsx)(a.Button,{variant:"primary",onClick:e,isBusy:s,__next40pxDefaultSize:!0,children:(0,i.__)("Save settings","zenpress")}),u=()=>{const{removeNotice:e}=(0,o.useDispatch)(l.store),s=(0,o.useSelect)(e=>e(l.store).getNotices());return s?.length?(0,p.jsx)(a.NoticeList,{notices:s,onRemove:e}):null},_=()=>{const{snippets:e,setSnippets:s,saveSettings:t,isSaving:r}=(()=>{const[e,s]=(0,n.useState)({}),[t,a]=(0,n.useState)(!1),{createSuccessNotice:r,createErrorNotice:p}=(0,o.useDispatch)(l.store);return(0,n.useEffect)(()=>{c()({path:"/wp/v2/settings"}).then(e=>{const t=Array.isArray(e?.zenpress_active_snippets)?e.zenpress_active_snippets:[],n={},i=window?.zenpressSnippetsMeta||{};Object.keys(i).forEach(e=>{const s=i[e]||{};n[e]={...s,"enable-snippet":t.includes(e)}}),s(n)}).catch(()=>{p((0,i.__)("Failed to load settings.","zenpress"))})},[p]),{snippets:e,setSnippets:s,saveSettings:()=>{a(!0);const s=Object.keys(e).filter(s=>e[s]?.["enable-snippet"]||!1);return c()({path:"/wp/v2/settings",method:"POST",data:{zenpress_active_snippets:s}}).then(()=>{r((0,i.__)("Settings saved.","zenpress"))}).catch(()=>{p((0,i.__)("Failed to save settings.","zenpress"))}).finally(()=>a(!1))},isSaving:t}})(),[_,w]=(0,n.useState)(new Set),x=e=>{s(s=>{const t={};return Object.entries(s).forEach(([s,n])=>{const i=(Array.isArray(n?.preset)?n.preset:[]).includes(e);t[s]={...n,"enable-snippet":i}}),t}),w(new Set(j))},v={};Object.keys(e).forEach(s=>{const t=e[s],n=t?.category||(0,i.__)("Uncategorized","zenpress");v[n]||(v[n]=[]),v[n].push({name:s,data:t})});const j=Object.keys(v).sort((e,s)=>e.localeCompare(s,void 0,{sensitivity:"base"}));return(0,p.jsx)(p.Fragment,{children:(0,p.jsx)("div",{className:"zenpress-row",children:(0,p.jsxs)("div",{className:"zenpress-col",children:[(0,p.jsxs)("div",{className:"zenpress-presets",children:[(0,p.jsxs)("div",{className:"zenpress-presets-description",children:[(0,p.jsx)("p",{children:(0,i.__)("Select the features that suit your needs. If you don't know which ones to choose, just select your site's type and it will set the right features for you.","zenpress")}),(0,p.jsx)("h2",{children:(0,i.__)("Pick a preset","zenpress")})]}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>x("showcase-website"),__next40pxDefaultSize:!0,children:(0,i.__)("Showcase website","zenpress")}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>x("blog"),__next40pxDefaultSize:!0,children:(0,i.__)("Blog","zenpress")}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>x("ecommerce"),__next40pxDefaultSize:!0,children:(0,i.__)("E-commerce","zenpress")}),(0,p.jsx)("div",{className:"zenpress-presets-description",children:(0,p.jsx)("h2",{children:(0,i.__)("Or just enable what you need","zenpress")})}),(0,p.jsxs)("div",{className:"zenpress-actions-bulk",children:[(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>{s(e=>{const s={};return Object.keys(e).forEach(t=>{s[t]={...e[t],"enable-snippet":!0}}),s}),w(new Set(j))},__next40pxDefaultSize:!0,children:(0,i.__)("Enable all actions","zenpress")}),(0,p.jsx)(a.Button,{isDestructive:"true",onClick:()=>{s(e=>{const s={};return Object.keys(e).forEach(t=>{s[t]={...e[t],"enable-snippet":!1}}),s})},__next40pxDefaultSize:!0,children:(0,i.__)("Disable all actions","zenpress")})]})]}),j.map(e=>(0,p.jsx)(a.Panel,{children:(0,p.jsx)(a.PanelBody,{title:e,initialOpen:_.has(e),children:v[e].map(({name:e,data:t})=>(0,p.jsx)(a.PanelRow,{children:(0,p.jsx)(d,{label:t.title||e,value:t?.["enable-snippet"]||!1,onChange:()=>{return t=e,void s(e=>({...e,[t]:{...e[t],"enable-snippet":!e[t]?.["enable-snippet"]}}));var t},help:t.description||""})},e))})},e)),(0,p.jsx)("div",{className:"zenpress-actions",children:(0,p.jsx)(h,{onClick:t,isBusy:r})}),(0,p.jsx)("div",{className:"zenpress-notices",children:(0,p.jsx)(u,{})})]})})})};t()(()=>{const e=document.getElementById("zenpress-settings");e&&(0,n.createRoot)(e).render((0,p.jsx)(_,{}))})})();
  • zenpress/trunk/assets/src/index.js

    r3352459 r3355428  
    176176        });
    177177        // Open all categories
    178         setOpenCategories(new Set(Object.values(snippets).map((s) => s.category || __('Uncategorized', 'zenpress'))));
     178        setOpenCategories(new Set(sortedCategories));
    179179    };
    180180
     
    192192            return updated;
    193193        });
    194         // Keep categories open (do not clear)
    195194    };
    196195
    197196    /**
    198197     * Enable snippets by preset.
    199      *
    200      * All snippets not in the preset will be disabled.
    201198     *
    202199     * @param {string} preset - Preset key to enable.
     
    206203        setSnippets((prev) => {
    207204            const updated = {};
    208             const newOpen = new Set(openCategories);
    209205            Object.entries(prev).forEach(([name, data]) => {
    210206                const presets = Array.isArray(data?.preset) ? data.preset : [];
     
    214210                    'enable-snippet': isEnabled,
    215211                };
    216                 if (isEnabled) {
    217                     newOpen.add(data.category || __('Uncategorized', 'zenpress'));
    218                 }
    219212            });
    220             setOpenCategories(newOpen);
    221213            return updated;
    222214        });
     215        // Open all categories
     216        setOpenCategories(new Set(sortedCategories));
    223217    };
    224218
     
    298292                            <PanelBody
    299293                                title={category}
    300                                 // Keep open if already marked or if a snippet is enabled
    301                                 initialOpen={
    302                                     openCategories.has(category) ||
    303                                     groupedSnippets[category].some(
    304                                         ({ data }) => data?.['enable-snippet']
    305                                     )
    306                                 }
     294                                initialOpen={openCategories.has(category)}
    307295                            >
    308296                                {groupedSnippets[category].map(({ name, data }) => (
  • zenpress/trunk/inc/snippets/disable-author-archives.php

    r3352459 r3355428  
    88remove_filter('template_redirect', 'redirect_canonical');
    99
    10 add_action('template_redirect', function () {
     10add_action('template_redirect', static function () {
    1111    if (is_author()) {
    1212        global $wp_query;
  • zenpress/trunk/inc/snippets/disable-dashicons.php

    r3352459 r3355428  
    55}
    66
    7 add_action('wp_enqueue_scripts', function () {
     7add_action('wp_enqueue_scripts', static function () {
    88    if (!is_user_logged_in()) {
    99        wp_dequeue_style('dashicons');
  • zenpress/trunk/inc/snippets/disable-emoji-scripts.php

    r3352459 r3355428  
    2222
    2323// Remove emoji support from TinyMCE editor.
    24 add_filter('tiny_mce_plugins', function ($plugins) {
     24add_filter('tiny_mce_plugins', static function ($plugins) {
    2525    return array_diff($plugins, ['wpemoji']);
    2626});
  • zenpress/trunk/inc/snippets/disable-jquery-migrate.php

    r3352459 r3355428  
    55}
    66
    7 add_action('wp_default_scripts', function (&$scripts) {
     7add_action('wp_default_scripts', static function (&$scripts) {
    88    if (!is_admin() && isset($scripts->registered['jquery'])) {
    99        $script = $scripts->registered['jquery'];
  • zenpress/trunk/inc/snippets/disable-oembed.php

    r3352459 r3355428  
    55}
    66
    7 add_action('init', 'zenpress_disable_oembed');
    8 function zenpress_disable_oembed() {
     7add_action('init', static function () {
    98    // Remove oEmbed from query vars.
    109    global $wp;
     
    4544        wp_deregister_script('wp-embed');
    4645    }
    47 }
     46});
  • zenpress/trunk/inc/snippets/disable-pdf-thumbnails.php

    r3352459 r3355428  
    55}
    66
    7 add_filter('fallback_intermediate_image_sizes', function () {
     7add_filter('fallback_intermediate_image_sizes', static function () {
    88    return [];
    99});
  • zenpress/trunk/inc/snippets/disable-pingback-trackback.php

    r3352459 r3355428  
    66
    77// Remove X-Pingback header from HTTP responses.
    8 add_filter('wp_headers', function ($headers) {
     8add_filter('wp_headers', static function ($headers) {
    99    unset($headers['X-Pingback']);
    1010
     
    1313
    1414// Disable pingbacks and trackbacks for new posts.
    15 add_action('after_setup_theme', function () {
     15add_action('after_setup_theme', static function () {
    1616    update_option('default_ping_status', 'closed');
    1717    update_option('default_pingback_flag', 0);
     
    1919
    2020// Prevent self-pingbacks.
    21 add_action('pre_ping', function (&$links) {
     21add_action('pre_ping', static function (&$links) {
    2222    $home = get_option('home');
    2323    foreach ($links as $l => $link) {
  • zenpress/trunk/inc/snippets/disable-woocommerce-cart-fragments.php

    r3352459 r3355428  
    55}
    66
    7 add_action('wp_enqueue_scripts', 'zenpress_disable_cart_fragments', 11);
    8 
    9 function zenpress_disable_cart_fragments() {
    10     if (class_exists('WooCommerce')) {
     7if (class_exists('WooCommerce')) {
     8    add_action('wp_enqueue_scripts', static function () {
    119        wp_dequeue_script('wc-cart-fragments');
    12     }
     10    }, 11);
    1311}
  • zenpress/trunk/inc/snippets/disable-woocommerce-scripts-styles.php

    r3352459 r3355428  
    11<?php
    22
    3 add_action('wp_enqueue_scripts', 'zenpress_disable_woocommerce_scripts_styles', 11);
     3if (!defined('ABSPATH')) {
     4    exit;
     5}
    46
    5 function zenpress_disable_woocommerce_scripts_styles() {
    6     if (!class_exists('WooCommerce')) {
    7         return;
    8     }
     7if (class_exists('WooCommerce')) {
     8    add_action('wp_enqueue_scripts', static function () {
     9        if (!is_woocommerce() && !is_cart() && !is_checkout() && !is_account_page() && !is_product() && !is_product_category() && !is_shop()) {
     10            // Dequeue WooCommerce Styles
     11            wp_dequeue_style('woocommerce-general');
     12            wp_dequeue_style('woocommerce-layout');
     13            wp_dequeue_style('woocommerce-smallscreen');
     14            wp_dequeue_style('woocommerce_frontend_styles');
     15            wp_dequeue_style('woocommerce_fancybox_styles');
     16            wp_dequeue_style('woocommerce_chosen_styles');
     17            wp_dequeue_style('woocommerce_prettyPhoto_css');
    918
    10     if (!is_woocommerce() && !is_cart() && !is_checkout() && !is_account_page() && !is_product() && !is_product_category() && !is_shop()) {
    11         // Dequeue WooCommerce Styles
    12         wp_dequeue_style('woocommerce-general');
    13         wp_dequeue_style('woocommerce-layout');
    14         wp_dequeue_style('woocommerce-smallscreen');
    15         wp_dequeue_style('woocommerce_frontend_styles');
    16         wp_dequeue_style('woocommerce_fancybox_styles');
    17         wp_dequeue_style('woocommerce_chosen_styles');
    18         wp_dequeue_style('woocommerce_prettyPhoto_css');
    19 
    20         // Dequeue WooCommerce Scripts
    21         wp_dequeue_script('wc-price-slider');
    22         wp_dequeue_script('wc-single-product');
    23         wp_dequeue_script('wc-add-to-cart');
    24         wp_dequeue_script('wc-checkout');
    25         wp_dequeue_script('wc-add-to-cart-variation');
    26         wp_dequeue_script('wc-cart');
    27         wp_dequeue_script('wc-chosen');
    28         wp_dequeue_script('woocommerce');
    29         wp_dequeue_script('prettyPhoto');
    30         wp_dequeue_script('prettyPhoto-init');
    31         wp_dequeue_script('jquery-blockui');
    32         wp_dequeue_script('jquery-placeholder');
    33         wp_dequeue_script('fancybox');
    34         wp_dequeue_script('jqueryui');
    35     }
     19            // Dequeue WooCommerce Scripts
     20            wp_dequeue_script('wc-price-slider');
     21            wp_dequeue_script('wc-single-product');
     22            wp_dequeue_script('wc-add-to-cart');
     23            wp_dequeue_script('wc-checkout');
     24            wp_dequeue_script('wc-add-to-cart-variation');
     25            wp_dequeue_script('wc-cart');
     26            wp_dequeue_script('wc-chosen');
     27            wp_dequeue_script('woocommerce');
     28            wp_dequeue_script('prettyPhoto');
     29            wp_dequeue_script('prettyPhoto-init');
     30            wp_dequeue_script('jquery-blockui');
     31            wp_dequeue_script('jquery-placeholder');
     32            wp_dequeue_script('fancybox');
     33            wp_dequeue_script('jqueryui');
     34        }
     35    }, 11);
    3636}
  • zenpress/trunk/inc/snippets/disable-woocommerce-widgets.php

    r3352459 r3355428  
    66
    77if (class_exists('WooCommerce')) {
    8     add_action('widgets_init', 'zenpress_disable_woocommerce_widgets', 99);
    9 
    10     function zenpress_disable_woocommerce_widgets() {
     8    add_action('widgets_init', static function() {
    119        unregister_widget('WC_Widget_Products');
    1210        unregister_widget('WC_Widget_Product_Categories');
     
    2119        unregister_widget('WC_Widget_Top_Rated_Products');
    2220        unregister_widget('WC_Widget_Rating_Filter');
    23     }
     21    }, 99);
    2422}
  • zenpress/trunk/inc/snippets/hide-woocommerce-version.php

    r3352459 r3355428  
    77if (class_exists('WooCommerce') && !is_admin()) {
    88    // Remove WooCommerce version from HTTP headers
    9     add_filter('wp_headers', 'zenpress_remove_woocommerce_version');
    10     function zenpress_remove_woocommerce_version($headers) {
     9    add_filter('wp_headers', static function ($headers) {
    1110        if (isset($headers['X-WooCommerce-Version'])) {
    1211            unset($headers['X-WooCommerce-Version']);
     
    1413
    1514        return $headers;
    16     }
     15    });
    1716
    18     // Remove WooCommerce version from script and style URLs
    19     add_filter('style_loader_src', 'zenpress_remove_woocommerce_version_scripts_styles', 10);
    20     add_filter('script_loader_src', 'zenpress_remove_woocommerce_version_scripts_styles', 10);
    21     function zenpress_remove_woocommerce_version_scripts_styles($src) {
     17    // Remove WooCommerce version from style URLs
     18    add_filter('style_loader_src', static function ($src) {
    2219        if (strpos($src, 'ver=') !== false && strpos($src, 'woocommerce') !== false) {
    2320            $src = remove_query_arg('ver', $src);
     
    2522
    2623        return $src;
    27     }
     24    }, 10);
     25
     26    // Remove WooCommerce version from script URLs
     27    add_filter('script_loader_src', static function ($src) {
     28        if (strpos($src, 'ver=') !== false && strpos($src, 'woocommerce') !== false) {
     29            $src = remove_query_arg('ver', $src);
     30        }
     31
     32        return $src;
     33    }, 10);
    2834}
  • zenpress/trunk/inc/snippets/hide-wordpress-version.php

    r3352459 r3355428  
    99
    1010// Remove WordPress version from generator
    11 add_filter('the_generator', 'zenpress_remove_wordpress_version');
    12 function zenpress_remove_wordpress_version() {
     11add_filter('the_generator', static function () {
    1312    return '';
    14 }
     13});
    1514
    16 // Remove WordPress version from script and style URLs
    17 add_filter('style_loader_src', 'zenpress_remove_version_from_assets');
    18 add_filter('script_loader_src', 'zenpress_remove_version_from_assets');
    19 function zenpress_remove_version_from_assets($src) {
     15// Remove WordPress version from script URLs
     16add_filter('script_loader_src', static function ($src) {
    2017    if (strpos($src, 'ver=' . get_bloginfo('version')) !== false) {
    2118        $src = remove_query_arg('ver', $src);
     
    2320
    2421    return $src;
    25 }
     22});
     23
     24// Remove WordPress version from style URLs
     25add_filter('style_loader_src', static function ($src) {
     26    if (strpos($src, 'ver=' . get_bloginfo('version')) !== false) {
     27        $src = remove_query_arg('ver', $src);
     28    }
     29
     30    return $src;
     31});
  • zenpress/trunk/inc/snippets/protect-wp-login.php

    r3352459 r3355428  
    66
    77// Remove detailed login errors
    8 add_filter('login_errors', function () {
     8add_filter('login_errors', static function () {
    99    return __('Login error.', 'zenpress');
    1010});
    1111
    1212// Limit login attempts
    13 add_filter('authenticate', 'zenpress_login_protection', 30, 3);
    14 function zenpress_login_protection(mixed $user, string $username, string $password): mixed {
     13add_filter('authenticate', static function (mixed $user, string $username, string $password): mixed {
    1514    $MAX_LOGIN_ATTEMPTS = 5;
    1615    $BLOCK_DURATION = 300; // 5 minutes
     
    5554
    5655    return $user;
    57 }
     56}, 30, 3);
  • zenpress/trunk/inc/snippets/remove-gutenberg-unwanted-block-patterns.php

    r3352459 r3355428  
    99
    1010// Remove core block patterns
    11 add_action('after_setup_theme', 'zenpress_remove_core_block_patterns');
    12 function zenpress_remove_core_block_patterns() {
     11add_action('after_setup_theme', static function () {
    1312    remove_theme_support('core-block-patterns');
    14 }
     13});
  • zenpress/trunk/inc/snippets/remove-woocommerce-patterns.php

    r3352459 r3355428  
    77use Automattic\WooCommerce\Blocks\Package;
    88
    9 add_action('woocommerce_blocks_loaded', 'zenpress_remove_wc_patterns');
    10 function zenpress_remove_wc_patterns(): void {
     9add_action('woocommerce_blocks_loaded', static function (): void {
    1110    remove_action(
    1211        'init',
     
    1615        ]
    1716    );
    18 }
     17});
  • zenpress/trunk/readme.txt

    r3352462 r3355428  
    1 === ZenPress ===
     1=== ZenPress — Cleaner, Lighter, Faster WP ===
    22Contributors: @quentinldd
    33Donate link: https://github.com/sponsors/quentin-ld/
     
    55Requires at least: 6.0
    66Tested up to: 6.8
    7 Stable tag: 2.0.1
     7Stable tag: 2.0.2
    88Requires PHP: 7.4
    99License: GPLv2 or later
     
    1414== Description ==
    1515
    16 ZenPress is a lightweight, super-fast plugin that boosts your WordPress & WooCommerce website through a wide range of solid actions. This is a simple solution for improving your WordPress website's performance and security while enjoying a simpler and lighter UI.
     16ZenPress is a lightweight, super-fast plugin that boosts your WordPress & WooCommerce website through a wide range of solid actions.
     17This is a simple solution for improving your WordPress website's performance and security while enjoying a simpler and lighter UI.
    1718No database clutter, no ads, no pro version. Just install, activate, select what you need or pick up your settings preset and you are ready to go !
    1819
     
    7475* Remove WooCommerce default remote block patterns
    7576
     77== Roadmap ==
     78
     79= Global =
     80* New presets
     81
     82= Security =
     83* Disable Application Passwords
     84* Manage Heartbeat API (frontend + backend + admin whitelist)
     85* Disable REST API
     86
     87= Performance =
     88* Disable capital_P_dangit filter
     89* Disable autosave
     90* Disable post revision
     91* Disable native lazy loading
     92* Disable Password Strength Meter
     93* Disable WordPress default lazy loading
     94
     95= UI =
     96* Remove "howdy" from admin bar
     97* Remove WordPress logo
     98* Remove "Help button"
     99* Remove "Thanks for using WordPress" in footer
     100* Remove "site health" page
     101* Remove "Privacy tools"
     102
     103= WooCommerce =
     104* Disable WooCommerce tracking
     105* Disable marketing hub
     106* Disable dashboard setup widget
     107* Disable new product editor
     108* Disable WooCommerce blocks
     109* Disable WooCommerce promo emails
     110
     111= Plugins =
     112* Disable CF7 CSS & JS
     113* Disable Elementor bloat
     114* Disable WP Bakery bloat
     115* Disable Divi bloat
     116* Disable Yoast SEO bloat
     117* Disable Jetpack bloat
     118* Disable Updraft bloat
     119
     120== Privacy Statement ==
     121
     122ZenPress is private by default and always will be. It does not store any data. It does not send data to any third party, nor does it include any third party resources.
     123
     124== Accessibility Statement ==
     125
     126ZenPress aims to be fully accessible to all of its users.
     127
    76128== Screenshots ==
    77129
    781301. ZenPress admin interface.
    79 1. Dashboard without ZenPress.
    80 2. Dashboard with ZenPress.
    81 3. Site editor without ZenPress.
    82 4. Site editor with ZenPress.
    83 5. Login page without ZenPress login protection.
    84 6. Login page with ZenPress login protection.
    85 7. Login page with ZenPress login protection after trying to brute force it.
    86 8. Website head without ZenPress.
    87 9. Website head with ZenPress.
    88 
    89 == Privacy Statement ==
    90 
    91 ZenPress is private by default and always will be. It does not store any data. It does not send data to any third party, nor does it include any third party resources.
    92 
    93 == Accessibility Statement ==
    94 
    95 ZenPress aims to be fully accessible to all of its users.
     1312. Dashboard without ZenPress.
     1323. Dashboard with ZenPress.
     1334. Site editor without ZenPress.
     1345. Site editor with ZenPress.
     1356. Login page without ZenPress login protection.
     1367. Login page with ZenPress login protection.
     1378. Login page with ZenPress login protection after trying to brute force it.
     1389. Website head without ZenPress.
     13910. Website head with ZenPress.
    96140
    97141== Frequently Asked Questions ==
     
    101145Yes, there is no pro version for this plugin and there never will be.
    102146
    103 However, I am accepting donations on my buymeacoffee page : https://buymeacoffee.com/quentinld. If you work at an agency that develops with WordPress, ask your company to provide sponsorship in order to invest in its supply chain. The tools that I maintain probably save your company time and money, and Buy me a coffee support can now be done at the organisation level.
    104 
    105 In addition, if you like the plugin then I'd love for you to leave a review. Tell all your friends about it too!
     147However, [I am accepting sponsorships via the GitHub Sponsors program](https://github.com/sponsors/quentin-ld/dashboard). If you work at an agency that develops with WordPress, ask your company to provide sponsorship in order to invest in its supply chain. The tools that I maintain probably save your company time and money, and GitHub sponsorship can now be done at the organisation level.
     148
     149In addition, if you like the plugin then I'd love for you to [leave a review](https://wordpress.org/support/plugin/zenpress/reviews/). Tell all your friends about it too!
    106150
    107151= I have a suggestion =
     
    114158
    115159== Changelog ==
     160
     161= 2.0.2 =
     162
     163- Global : Codebase and snippets optimization
     164- Global : Fixed a bug in the automatic opening and closing function of the panels on the settings page.
    116165
    117166= 2.0.1 =
  • zenpress/trunk/zenpress.php

    r3352462 r3355428  
    1010 * @license   GPL v2 or later
    1111 *
    12  * Plugin Name: ZenPress
     12 * Plugin Name: ZenPress — Cleaner, Lighter, Faster WP
    1313 * Description: Easily speed up and strengthen your WordPress site by cleaning out unnecessary features and protecting weak points.
    14  * Version: 2.0.1
     14 * Version: 2.0.2
    1515 * Plugin URI: https://wordpress.org/plugins/zenpress/
    1616 * Author: Quentin Le Duff
     
    3131 * This program is distributed in the hope that it will be useful,
    3232 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    33  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    3434 * GNU General Public License for more details.
    35  *
    36  */
    37 
    38 /*****
    39  * TODOLIST ▓▒░(°◡°)░▒▓
    40 ****/
    41 // TODO: Disable comments URL
    42 // TODO: CHECK THE DEPLOYMENT WORKING PROPERLY
     35 */
    4336
    4437if (!defined('ABSPATH')) {
     
    4740
    4841/**
    49  * Add settings link on the plugins list page (next to Activate/Deactivate).
    50  *
    51  * @param array $links Existing plugin action links.
    52  * @return array Modified links with Settings link appended at the end.
    53  */
    54 function zenpress_add_settings_link(array $links): array {
    55     $settings_url = admin_url('options-general.php?page=zenpress');
    56 
    57     $settings_link = sprintf(
    58         '<a href="%s" aria-label="%s">%s</a>',
    59         esc_url($settings_url),
    60         esc_attr__('Go to ZenPress settings page', 'zenpress'),
    61         esc_html__('Settings', 'zenpress')
    62     );
    63 
    64     // Add "Settings" link at the end instead of first
    65     $links[] = $settings_link;
    66 
    67     return $links;
    68 }
    69 add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'zenpress_add_settings_link');
    70 
    71 
    72 /**
    73  * Add extra links under the plugin description on the plugins page.
    74  *
    75  * @param array  $links Existing links.
    76  * @param string $file  Current plugin file.
    77  * @return array Modified links.
    78  */
    79 function zenpress_plugin_row_meta($links, $file) {
    80     if ($file === plugin_basename(__FILE__)) {
    81         $extra_links = array(
    82             '<a href="' . esc_url('https://wordpress.org/plugins/zenpress/#developers') . '" target="_blank" rel="noopener noreferrer" aria-label="' . esc_attr__('View ZenPress changelog on WordPress.org (opens in a new tab)', 'zenpress') . '">' . esc_html__('Changelog', 'zenpress') . '</a>',
    83             '<a href="' . esc_url('https://holdmywp.com/zenpress/') . '" target="_blank" rel="noopener noreferrer" aria-label="' . esc_attr__('Read ZenPress documentation (opens in a new tab)', 'zenpress') . '">' . esc_html__('Docs', 'zenpress') . '</a>',
    84             '<a href="' . esc_url('https://buymeacoffee.com/quentinld') . '" target="_blank" rel="noopener noreferrer" aria-label="' . esc_attr__('Support ZenPress by buying a coffee (opens in a new tab)', 'zenpress') . '">' . esc_html__('Support ☕', 'zenpress') . '</a>',
    85         );
    86 
    87         $links = array_merge($links, $extra_links);
    88     }
    89 
    90     return $links;
    91 }
    92 add_filter('plugin_row_meta', 'zenpress_plugin_row_meta', 10, 2);
    93 
    94 
    95 
    96 /**
    9742 * Enqueue scripts and styles used by the plugin in admin area.
    9843 *
     
    10045 * @return void
    10146 */
     47add_action('admin_enqueue_scripts', 'zenpress_admin_enqueue_scripts');
    10248function zenpress_admin_enqueue_scripts(string $admin_page): void {
    103     if ($admin_page !== 'settings_page_zenpress') {
     49    if ('settings_page_zenpress' !== $admin_page) {
    10450        return;
    10551    }
    10652
    10753    $asset_file = plugin_dir_path(__FILE__) . 'assets/build/index.asset.php';
    108     if (!is_file($asset_file)) {
     54    if (!file_exists($asset_file)) {
    10955        return;
    11056    }
    11157
    112     /** @var mixed $asset */
    11358    $asset = include $asset_file;
    114 
    115     if (!is_array($asset) || empty($asset['dependencies']) || empty($asset['version'])) {
    116         return;
    117     }
    118 
    119     $dependencies = array_map('sanitize_key', (array) $asset['dependencies']);
    120     $version      = sanitize_text_field((string) $asset['version']);
    121 
    12259    wp_enqueue_script(
    12360        'zenpress-scripts',
    12461        plugins_url('assets/build/index.js', __FILE__),
    125         $dependencies,
    126         $version,
     62        $asset['dependencies'],
     63        $asset['version'],
    12764        true
    12865    );
     
    13269        plugins_url('assets/build/index.css', __FILE__),
    13370        array_filter(
    134             $dependencies,
    135             static fn($style) => is_string($style) && wp_style_is($style, 'registered')
     71            $asset['dependencies'],
     72            function ($style) {
     73                return wp_style_is($style, 'registered');
     74            }
    13675        ),
    137         $version
    138     );
    139 }
    140 add_action('admin_enqueue_scripts', 'zenpress_admin_enqueue_scripts');
     76        $asset['version']
     77    );
     78}
     79
     80/**
     81 * Localize translated snippet metadata for use in JavaScript.
     82 *
     83 * @param string $admin_page Current admin page hook.
     84 * @return void
     85 */
     86add_action('admin_enqueue_scripts', 'zenpress_localize_snippets_meta');
     87function zenpress_localize_snippets_meta(string $admin_page): void {
     88    if ('settings_page_zenpress' !== $admin_page) {
     89        return;
     90    }
     91
     92    $snippets = [];
     93    $snippets_path = plugin_dir_path(__FILE__) . 'inc/snippets/';
     94    if (!is_dir($snippets_path)) {
     95        return;
     96    }
     97
     98    foreach (glob($snippets_path . '*.php') as $file) {
     99        $basename = basename($file, '.php');
     100        $snippets[$basename] = zenpress_extract_snippet_metadata($basename);
     101    }
     102
     103    wp_localize_script('zenpress-scripts', 'zenpressSnippetsMeta', $snippets);
     104}
     105
     106/**
     107 * Add a settings link on the plugins list page.
     108 *
     109 * @param array $links Existing plugin action links.
     110 * @return array Modified plugin action links.
     111 */
     112add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'zenpress_add_settings_link');
     113function zenpress_add_settings_link(array $links): array {
     114    $url = admin_url('options-general.php?page=zenpress');
     115    $links[] = sprintf(
     116        '<a href="%s" aria-label="%s">%s</a>',
     117        esc_url($url),
     118        esc_attr__('Go to ZenPress settings page', 'zenpress'),
     119        esc_html__('Settings', 'zenpress')
     120    );
     121    return $links;
     122}
     123
     124/**
     125 * Add extra links under the plugin description on the plugins page.
     126 *
     127 * @param array  $links Existing row meta links.
     128 * @param string $file  Current plugin file.
     129 * @return array Modified row meta links.
     130 */
     131add_filter('plugin_row_meta', 'zenpress_plugin_row_meta', 10, 2);
     132function zenpress_plugin_row_meta(array $links, string $file): array {
     133    if ($file === plugin_basename(__FILE__)) {
     134        $extra_links = array(
     135            sprintf(
     136                '<a href="%s" target="_blank" rel="noopener noreferrer" aria-label="%s">%s</a>',
     137                esc_url('https://wordpress.org/plugins/zenpress/#developers'),
     138                esc_attr__('View ZenPress changelog on WordPress.org (opens in a new tab)', 'zenpress'),
     139                esc_html__('Changelog', 'zenpress')
     140            ),
     141            sprintf(
     142                '<a href="%s" target="_blank" rel="noopener noreferrer" aria-label="%s">%s</a>',
     143                esc_url('https://holdmywp.com/zenpress/'),
     144                esc_attr__('Read ZenPress documentation (opens in a new tab)', 'zenpress'),
     145                esc_html__('Docs', 'zenpress')
     146            ),
     147            sprintf(
     148                '<a href="%s" target="_blank" rel="noopener noreferrer" aria-label="%s">%s</a>',
     149                esc_url('https://buymeacoffee.com/quentinld'),
     150                esc_attr__('Support ZenPress by buying a coffee (opens in a new tab)', 'zenpress'),
     151                esc_html__('Support ☕', 'zenpress')
     152            )
     153        );
     154        $links = array_merge($links, $extra_links);
     155    }
     156    return $links;
     157}
    141158
    142159/**
     
    145162 * @return void
    146163 */
     164add_action('admin_menu', 'zenpress_add_option_page');
    147165function zenpress_add_option_page(): void {
    148166    add_options_page(
     
    154172    );
    155173}
    156 add_action('admin_menu', 'zenpress_add_option_page');
    157174
    158175/**
     
    162179 */
    163180function zenpress_options_page(): void {
    164     $plugin_data = get_file_data(__FILE__, ['Version' => 'Version'], 'plugin');
    165     $plugin_version = $plugin_data['Version'] ?? '';
     181    $plugin_data = get_file_data(__FILE__, ['Version' => 'Version'], 'plugin');
     182    $plugin_version = $plugin_data['Version'] ?? '';
    166183    ?>
    167184    <div class="wrap zenpress-dashboard-wrap">
    168185        <div class="zenpress-header">
    169186            <div class="zenpress-header-title">
    170                 <h1>
    171                     <?php echo esc_html__('ZenPress', 'zenpress'); ?>
    172                 </h1>
    173                 <?php if ($plugin_version) : ?>
    174                     <p class="zenpress-plugin-version">
    175                         <?php echo esc_html__('Version', 'zenpress') . ' ' . esc_html($plugin_version) . ' - '; ?>
    176                         <a href="https://wordpress.org/plugins/zenpress/#developers"
    177                         target="_blank"
    178                         rel="noopener noreferrer"
    179                         aria-label="<?php echo esc_attr__('View ZenPress changelog on WordPress.org (opens in a new tab)', 'zenpress'); ?>">
    180                             <?php echo esc_html__('What\'s new ?', 'zenpress'); ?>
    181                         </a>
    182                     </p>
    183                 <?php endif; ?>
    184             </div>
    185             <div class="zenpress-header-navigation">
    186                 <a href="https://holdmywp.com/zenpress/"
    187                    target="_blank"
    188                    rel="noopener noreferrer"
    189                    aria-label="<?php echo esc_attr__('Read the ZenPress documentation (opens in a new tab)', 'zenpress'); ?>">
    190                     <?php echo esc_html__('Documentation', 'zenpress'); ?>
    191                 </a>
    192 
    193                 <a href="https://wordpress.org/plugins/zenpress/#reviews"
    194                    target="_blank"
    195                    rel="noopener noreferrer"
    196                    aria-label="<?php echo esc_attr__('Leave a review for ZenPress on WordPress.org (opens in a new tab)', 'zenpress'); ?>">
    197                     <?php echo esc_html__('Leave a review (helps a lot)', 'zenpress'); ?>
    198                 </a>
    199 
    200                 <a href="https://buymeacoffee.com/quentinld"
    201                    target="_blank"
    202                    rel="noopener noreferrer"
    203                    class="components-button is-next-40px-default-size is-tertiary"
    204                    aria-label="<?php echo esc_attr__('Support development: Buy me a coffee (opens in a new tab)', 'zenpress'); ?>">
    205                     <?php echo esc_html__('Buy me a coffee', 'zenpress'); ?> <span aria-hidden="true">☕</span>
    206                 </a>
    207             </div>
     187                <h1><?php echo esc_html__('ZenPress', 'zenpress'); ?></h1>
     188                <?php if ($plugin_version) : ?>
     189                    <p class="zenpress-plugin-version">
     190                        <?php echo esc_html__('Version', 'zenpress') . ' ' . esc_html($plugin_version) . ' - '; ?>
     191                        <a href="https://wordpress.org/plugins/zenpress/#developers"
     192                           target="_blank"
     193                           rel="noopener noreferrer"
     194                           aria-label="<?php echo esc_attr__('View ZenPress changelog on WordPress.org (opens in a new tab)', 'zenpress'); ?>">
     195                            <?php echo esc_html__('What\'s new ?', 'zenpress'); ?>
     196                        </a>
     197                    </p>
     198                <?php endif; ?>
     199            </div>
     200            <div class="zenpress-header-navigation">
     201                <a href="https://holdmywp.com/zenpress/"
     202                   target="_blank"
     203                   rel="noopener noreferrer"
     204                   aria-label="<?php echo esc_attr__('Read the ZenPress documentation (opens in a new tab)', 'zenpress'); ?>">
     205                    <?php echo esc_html__('Documentation', 'zenpress'); ?>
     206                </a>
     207                <a href="https://wordpress.org/plugins/zenpress/#reviews"
     208                   target="_blank"
     209                   rel="noopener noreferrer"
     210                   aria-label="<?php echo esc_attr__('Leave a review for ZenPress on WordPress.org (opens in a new tab)', 'zenpress'); ?>">
     211                    <?php echo esc_html__('Leave a review (helps a lot)', 'zenpress'); ?>
     212                </a>
     213                <a href="https://buymeacoffee.com/quentinld"
     214                   target="_blank"
     215                   rel="noopener noreferrer"
     216                   class="components-button is-next-40px-default-size is-tertiary"
     217                   aria-label="<?php echo esc_attr__('Support development: Buy me a coffee (opens in a new tab)', 'zenpress'); ?>">
     218                    <?php echo esc_html__('Buy me a coffee', 'zenpress'); ?> <span aria-hidden="true">☕</span>
     219                </a>
     220            </div>
    208221        </div>
    209 
    210222        <div id="zenpress-settings" class="zenpress-settings">
    211             <div class="zenpress-loading card">
    212                 <div class="zenpress-loading-body">
    213                     <p class="zenpress-loading-text">
    214                         <?php echo esc_html__('Loading your ZenPress settings…', 'zenpress'); ?>
    215                     </p>
    216                 </div>
    217             </div>
     223            <div class="zenpress-loading card">
     224                <div class="zenpress-loading-body">
     225                    <p class="zenpress-loading-text">
     226                        <?php echo esc_html__('Loading your ZenPress settings…', 'zenpress'); ?>
     227                    </p>
     228                </div>
     229            </div>
    218230        </div>
    219 
    220         <div class="zenpress-footer">
    221             <div class="zenpress-footer-title">
     231        <div class="zenpress-footer">
     232            <div class="zenpress-footer-title">
    222233                <p>
    223                     <?php echo esc_html__('Made ', 'zenpress'); ?>
    224                     <span aria-hidden="true"> x ❤️ </span>
    225                     <?php echo esc_html__(' by Quentin Le Duff - Your WordPress Partner', 'zenpress'); ?>
    226                 </p>
    227             </div>
    228             <div class="zenpress-footer-navigation">
    229                 <a href="https://holdmywp.com/"
    230                    target="_blank"
    231                    rel="noopener noreferrer"
    232                    aria-label="<?php echo esc_attr__('Visite the developper website', 'zenpress'); ?>">
    233                     <?php echo esc_html__('My place', 'zenpress'); ?>
    234                 </a>
    235                 <a href="https://github.com/quentin-ld/zenpress"
    236                    target="_blank"
    237                    rel="noopener noreferrer"
    238                    aria-label="<?php echo esc_attr__('Review the code on Github', 'zenpress'); ?>">
    239                     <?php echo esc_html__('ZenPress code repository', 'zenpress'); ?>
    240                 </a>
    241             </div>
     234                    <?php echo esc_html__('Made ', 'zenpress'); ?>
     235                    <span aria-hidden="true"> x ❤️ </span>
     236                    <?php echo esc_html__(' by Quentin Le Duff - Your WordPress Partner', 'zenpress'); ?>
     237                </p>
     238            </div>
     239            <div class="zenpress-footer-navigation">
     240                <a href="https://holdmywp.com/"
     241                   target="_blank"
     242                   rel="noopener noreferrer"
     243                   aria-label="<?php echo esc_attr__('Visite the developper website', 'zenpress'); ?>">
     244                    <?php echo esc_html__('My place', 'zenpress'); ?>
     245                </a>
     246                <a href="https://github.com/quentin-ld/zenpress"
     247                   target="_blank"
     248                   rel="noopener noreferrer"
     249                   aria-label="<?php echo esc_attr__('Review the code on Github', 'zenpress'); ?>">
     250                    <?php echo esc_html__('ZenPress code repository', 'zenpress'); ?>
     251                </a>
     252            </div>
    242253        </div>
    243254    </div>
     
    246257
    247258/**
    248  * Extract snippet metadata from corresponding meta file.
    249  *
    250  * @param string $snippet_name Base name of the snippet (without extension).
    251  * @return array<string,mixed> Metadata array with keys: title, description, category, weight, preset.
     259 * Extract snippet metadata from its meta file.
     260 *
     261 * @param string $snippet_name Snippet base name (without extension).
     262 * @return array<string,mixed> Sanitized metadata (title, description, category, weight, preset).
    252263 */
    253264function zenpress_extract_snippet_metadata(string $snippet_name): array {
    254     $metadata = [
     265    $defaults = array(
    255266        'title'       => '',
    256267        'description' => '',
    257268        'category'    => '',
    258269        'weight'      => 0,
    259         'preset'      => [],
    260     ];
    261 
    262     $safe_name = sanitize_file_name($snippet_name);
    263     $meta_file = plugin_dir_path(__FILE__) . 'inc/meta/' . $safe_name . '.meta.php';
    264 
    265     if (is_file($meta_file)) {
    266         /** @var mixed $data */
    267         $data = include $meta_file;
    268         if (is_array($data)) {
    269             $metadata = array_merge($metadata, array_intersect_key($data, $metadata));
    270         }
    271     }
    272 
    273     // Sanitize values securely
    274     $metadata['title']       = sanitize_text_field($metadata['title']);
    275     $metadata['description'] = sanitize_text_field($metadata['description']);
    276     $metadata['category']    = sanitize_text_field($metadata['category']);
    277     $metadata['weight']      = intval($metadata['weight']);
    278     $metadata['preset']      = array_map('sanitize_text_field', (array) $metadata['preset']);
    279 
    280     return $metadata;
    281 }
    282 
    283 
    284 /**
    285  * Register a single option to store all active snippets.
    286  *
    287  * @return void
    288  */
     270        'preset'      => array()
     271    );
     272
     273    $file = plugin_dir_path(__FILE__) . 'inc/meta/' . sanitize_file_name($snippet_name) . '.meta.php';
     274    $data = is_file($file) ? include $file : array();
     275    $metadata = array_merge($defaults, is_array($data) ? $data : array());
     276
     277    return array(
     278        'title'       => sanitize_text_field($metadata['title']),
     279        'description' => sanitize_text_field($metadata['description']),
     280        'category'    => sanitize_text_field($metadata['category']),
     281        'weight'      => (int) $metadata['weight'],
     282        'preset'      => array_map('sanitize_text_field', (array) $metadata['preset'])
     283    );
     284}
     285
     286/**
     287 * Register option to store active snippets.
     288 */
     289add_action('init', 'zenpress_register_snippet_settings');
    289290function zenpress_register_snippet_settings(): void {
    290291    register_setting(
    291292        'options',
    292293        'zenpress_active_snippets',
    293         [
     294        array(
    294295            'type'              => 'array',
    295             'default'           => [],
    296             'sanitize_callback' => static function ($value): array {
    297                 return array_values(array_filter(
    298                     array_map('sanitize_file_name', (array) $value)
    299                 ));
    300             },
    301             'show_in_rest' => [
    302                 'schema' => [
     296            'default'           => array(),
     297            'sanitize_callback' => 'zenpress_sanitize_snippets_option',
     298            'show_in_rest'      => array(
     299                'schema' => array(
    303300                    'type'  => 'array',
    304                     'items' => [ 'type' => 'string' ],
    305                 ],
    306             ],
    307         ]
    308     );
    309 }
    310 add_action('init', 'zenpress_register_snippet_settings');
    311 
    312 /**
    313  * Load enabled snippets.
    314  *
    315  * @param string $folder Relative folder where snippets are stored.
    316  * @return array<int,string> List of loaded snippet base names.
     301                    'items' => array('type' => 'string')
     302                )
     303            )
     304        )
     305    );
     306}
     307
     308/**
     309 * Sanitize the list of active snippets.
     310 *
     311 * @param mixed $value Option value.
     312 * @return array<string> Sanitized base names.
     313 */
     314function zenpress_sanitize_snippets_option($value): array {
     315    return array_values(
     316        array_filter(
     317            array_map('sanitize_file_name', (array) $value)
     318        )
     319    );
     320}
     321
     322/**
     323 * Load all active snippets.
     324 *
     325 * @param string $folder Relative folder path for snippets.
     326 * @return array<string> Loaded snippet base names.
    317327 */
    318328function zenpress_load_snippets(string $folder = 'inc/snippets/'): array {
    319     $snippets_path = plugin_dir_path(__FILE__) . rtrim($folder, '/') . '/';
    320     if (!is_dir($snippets_path)) {
    321         return [];
    322     }
    323 
    324     $active_snippets = get_option('zenpress_active_snippets', []);
    325     if (!is_array($active_snippets)) {
    326         $active_snippets = [];
    327     }
    328 
    329     $loaded = [];
    330     foreach ($active_snippets as $base_name) {
    331         $safe_name     = sanitize_file_name($base_name);
    332         $file          = $snippets_path . $safe_name . '.php';
    333         $constant_name = 'ZENPRESS_' . strtoupper(str_replace(['-', '_'], '_', $safe_name));
    334 
    335         if (is_file($file) && (!defined($constant_name) || constant($constant_name) !== false)) {
     329    $path = plugin_dir_path(__FILE__) . rtrim($folder, '/') . '/';
     330
     331    if (!is_dir($path)) {
     332        return array();
     333    }
     334
     335    $snippets = (array) get_option('zenpress_active_snippets', array());
     336    $loaded = array();
     337    foreach ($snippets as $name) {
     338        $name = sanitize_file_name($name);
     339        $file = $path . $name . '.php';
     340        $constant = 'ZENPRESS_' . strtoupper(str_replace(array('-', '_'), '_', $name));
     341        if (is_file($file) && (!defined($constant) || constant($constant) !== false)) {
    336342            include_once $file;
    337             $loaded[] = $safe_name;
     343            $loaded[] = $name;
    338344        }
    339345    }
    340 
    341346    return $loaded;
    342347}
    343 add_action('init', function () {
    344     return zenpress_load_snippets();
     348
     349/**
     350 * Boot ZenPress snippets.
     351 */
     352add_action('init', function() : void {
     353    zenpress_load_snippets();
    345354});
    346 
    347 /**
    348  * Localize translated snippet metadata for use in JavaScript.
    349  *
    350  * @param string $hook Current admin page hook.
    351  * @return void
    352  */
    353 add_action('admin_enqueue_scripts', static function (string $hook): void {
    354     if ($hook !== 'settings_page_zenpress') {
    355         return;
    356     }
    357 
    358     $snippets = [];
    359     $snippets_path = plugin_dir_path(__FILE__) . 'inc/snippets/';
    360     if (!is_dir($snippets_path)) {
    361         return;
    362     }
    363 
    364     foreach (glob($snippets_path . '*.php') ?: [] as $file) {
    365         $base_name = basename($file, '.php');
    366         $snippets[$base_name] = zenpress_extract_snippet_metadata($base_name);
    367     }
    368 
    369     wp_localize_script('zenpress-scripts', 'zenpressSnippetsMeta', $snippets);
    370 });
Note: See TracChangeset for help on using the changeset viewer.