Plugin Directory

Changeset 3372200


Ignore:
Timestamp:
10/03/2025 08:20:31 AM (5 months ago)
Author:
quentinldd
Message:

Update to version 2.0.3 from GitHub

Location:
zenpress
Files:
160 added
58 deleted
14 edited
1 copied

Legend:

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

    r3355428 r3372200  
    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');
     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' => '64ce0d65ec54e96537a1');
  • zenpress/tags/2.0.3/assets/build/index.js

    r3355428 r3372200  
    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)(_,{}))})})();
     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&&0!==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=window?.zenpressSnippetsMeta||{},i={};Object.keys(n).forEach(e=>{i[e]={...n[e],"enable-snippet":t.includes(e)}}),s(i)}).catch(()=>{p((0,i.__)("Failed to load settings.","zenpress"))})},[p]),{snippets:e,setSnippets:s,saveSettings:async()=>{a(!0);const s=Object.keys(e).filter(s=>e[s]?.["enable-snippet"]);try{await c()({path:"/wp/v2/settings",method:"POST",data:{zenpress_active_snippets:s}}),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={};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))},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)("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(j))},__next40pxDefaultSize:!0,children:(0,i.__)("Enable all actions","zenpress")}),(0,p.jsx)(a.Button,{isDestructive:!0,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: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)(_,{}))})})();
  • zenpress/tags/2.0.3/assets/src/index.js

    r3355428 r3372200  
    1 // Import necessary modules from WordPress libraries
    21import domReady from '@wordpress/dom-ready';
    32import { createRoot } from '@wordpress/element';
    4 import { __ } from '@wordpress/i18n';
    5 import { ToggleControl } from '@wordpress/components';
    6 import { Button } from '@wordpress/components';
    7 import { Panel, PanelBody, PanelRow } from '@wordpress/components';
    8 import { useState } from '@wordpress/element';
    9 import apiFetch from '@wordpress/api-fetch';
    10 import { useEffect } from '@wordpress/element';
    11 import { useDispatch, useSelect } from '@wordpress/data';
    12 import { store as noticesStore } from '@wordpress/notices';
    13 import { NoticeList } from '@wordpress/components';
    143import './index.scss';
    15 
    16 /**
    17  * Custom hook to manage ZenPress settings state.
    18  *
    19  * @returns {object} Settings state and actions.
    20  * @property {object} snippets - Current snippets with metadata.
    21  * @property {Function} setSnippets - Setter to update snippets state.
    22  * @property {Function} saveSettings - Function to persist settings to REST API.
    23  * @property {boolean} isSaving - Whether settings are currently being saved.
    24  */
    25 const useSettings = () => {
    26     const [snippets, setSnippets] = useState({});
    27     const [isSaving, setIsSaving] = useState(false);
    28     const { createSuccessNotice, createErrorNotice } = useDispatch(noticesStore);
    29 
    30     useEffect(() => {
    31         apiFetch({ path: '/wp/v2/settings' })
    32             .then((settings) => {
    33                 const active = Array.isArray(settings?.zenpress_active_snippets)
    34                     ? settings.zenpress_active_snippets
    35                     : [];
    36 
    37                 const snippetsData = {};
    38                 const meta = window?.zenpressSnippetsMeta || {};
    39 
    40                 Object.keys(meta).forEach((snippetName) => {
    41                     const m = meta[snippetName] || {};
    42                     snippetsData[snippetName] = {
    43                         ...m,
    44                         'enable-snippet': active.includes(snippetName),
    45                     };
    46                 });
    47 
    48                 setSnippets(snippetsData);
    49             })
    50             .catch(() => {
    51                 createErrorNotice(__('Failed to load settings.', 'zenpress'));
    52             });
    53     }, [createErrorNotice]);
    54 
    55     /**
    56      * Save updated snippets to WordPress REST API.
    57      *
    58      * @returns {Promise<void>}
    59      */
    60     const saveSettings = () => {
    61         setIsSaving(true);
    62 
    63         const active = Object.keys(snippets).filter(
    64             (snippetName) => snippets[snippetName]?.['enable-snippet'] || false
    65         );
    66 
    67         return apiFetch({
    68             path: '/wp/v2/settings',
    69             method: 'POST',
    70             data: { zenpress_active_snippets: active },
    71         })
    72             .then(() => {
    73                 createSuccessNotice(__('Settings saved.', 'zenpress'));
    74             })
    75             .catch(() => {
    76                 createErrorNotice(__('Failed to save settings.', 'zenpress'));
    77             })
    78             .finally(() => setIsSaving(false));
    79     };
    80 
    81     return { snippets, setSnippets, saveSettings, isSaving };
    82 };
    83 
    84 /**
    85  * Toggle control for enabling/disabling a snippet.
    86  *
    87  * @param {object} props - Component props.
    88  * @param {string} props.label - Label of the toggle.
    89  * @param {boolean} props.value - Current state of the toggle.
    90  * @param {Function} props.onChange - Change handler.
    91  * @param {string} [props.help] - Optional description/help text.
    92  * @returns {JSX.Element} The toggle control.
    93  */
    94 const SnippetToggleControl = ({ label, value, onChange, help }) => (
    95     <ToggleControl
    96         label={label}
    97         checked={value}
    98         onChange={onChange}
    99         help={help}
    100         __nextHasNoMarginBottom
    101     />
    102 );
    103 
    104 /**
    105  * Save button component.
    106  *
    107  * @param {object} props - Component props.
    108  * @param {Function} props.onClick - Click handler for save action.
    109  * @param {boolean} props.isBusy - Whether the button is in loading state.
    110  * @returns {JSX.Element} The save button.
    111  */
    112 const SaveButton = ({ onClick, isBusy }) => (
    113     <Button
    114         variant="primary"
    115         onClick={onClick}
    116         isBusy={isBusy}
    117         __next40pxDefaultSize
    118     >
    119         {__('Save settings', 'zenpress')}
    120     </Button>
    121 );
    122 
    123 /**
    124  * Notices component to display success/error messages.
    125  *
    126  * @returns {JSX.Element|null} List of notices or null if none exist.
    127  */
    128 const Notices = () => {
    129     const { removeNotice } = useDispatch(noticesStore);
    130     const notices = useSelect((select) => select(noticesStore).getNotices());
    131 
    132     if (!notices?.length) return null;
    133 
    134     return <NoticeList notices={notices} onRemove={removeNotice} />;
    135 };
    136 
    137 /**
    138  * Main settings page component for ZenPress.
    139  *
    140  * @returns {JSX.Element} The settings page UI.
    141  */
    142 const SettingsPage = () => {
    143     const { snippets, setSnippets, saveSettings, isSaving } = useSettings();
    144 
    145     // Track which categories should remain open
    146     const [openCategories, setOpenCategories] = useState(new Set());
    147 
    148     /**
    149      * Handle toggle state change for a snippet.
    150      *
    151      * @param {string} snippetName - Name of the snippet to toggle.
    152      * @return {void}
    153      */
    154     const handleToggleChange = (snippetName) => {
    155         setSnippets((prev) => ({
    156             ...prev,
    157             [snippetName]: {
    158                 ...prev[snippetName],
    159                 'enable-snippet': !prev[snippetName]?.['enable-snippet'],
    160             },
    161         }));
    162     };
    163 
    164     /**
    165      * Enable all snippets at once.
    166      *
    167      * @return {void}
    168      */
    169     const enableAllSnippets = () => {
    170         setSnippets((prev) => {
    171             const updated = {};
    172             Object.keys(prev).forEach((name) => {
    173                 updated[name] = { ...prev[name], 'enable-snippet': true };
    174             });
    175             return updated;
    176         });
    177         // Open all categories
    178         setOpenCategories(new Set(sortedCategories));
    179     };
    180 
    181     /**
    182      * Reset all snippets (disable everything).
    183      *
    184      * @return {void}
    185      */
    186     const resetSettings = () => {
    187         setSnippets((prev) => {
    188             const updated = {};
    189             Object.keys(prev).forEach((name) => {
    190                 updated[name] = { ...prev[name], 'enable-snippet': false };
    191             });
    192             return updated;
    193         });
    194     };
    195 
    196     /**
    197      * Enable snippets by preset.
    198      *
    199      * @param {string} preset - Preset key to enable.
    200      * @return {void}
    201      */
    202     const enableByPreset = (preset) => {
    203         setSnippets((prev) => {
    204             const updated = {};
    205             Object.entries(prev).forEach(([name, data]) => {
    206                 const presets = Array.isArray(data?.preset) ? data.preset : [];
    207                 const isEnabled = presets.includes(preset);
    208                 updated[name] = {
    209                     ...data,
    210                     'enable-snippet': isEnabled,
    211                 };
    212             });
    213             return updated;
    214         });
    215         // Open all categories
    216         setOpenCategories(new Set(sortedCategories));
    217     };
    218 
    219     // Group snippets by category
    220     const groupedSnippets = {};
    221     Object.keys(snippets).forEach((snippetName) => {
    222         const snippet = snippets[snippetName];
    223         const category = snippet?.category || __('Uncategorized', 'zenpress');
    224         if (!groupedSnippets[category]) groupedSnippets[category] = [];
    225         groupedSnippets[category].push({ name: snippetName, data: snippet });
    226     });
    227 
    228     // Sort categories alphabetically (case-insensitive)
    229     const sortedCategories = Object.keys(groupedSnippets).sort((a, b) =>
    230         a.localeCompare(b, undefined, { sensitivity: 'base' })
    231     );
    232 
    233     return (
    234         <>
    235             <div className="zenpress-row">
    236                 <div className="zenpress-col">
    237                     <div className="zenpress-presets">
    238                         <div className="zenpress-presets-description">
    239                             <p>
    240                                 {__(
    241                                     '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.',
    242                                     'zenpress'
    243                                 )}
    244                             </p>
    245                             <h2>{__('Pick a preset', 'zenpress')}</h2>
    246                         </div>
    247 
    248                         <Button
    249                             variant="secondary"
    250                             onClick={() => enableByPreset('showcase-website')}
    251                             __next40pxDefaultSize
    252                         >
    253                             {__('Showcase website', 'zenpress')}
    254                         </Button>
    255                         <Button
    256                             variant="secondary"
    257                             onClick={() => enableByPreset('blog')}
    258                             __next40pxDefaultSize
    259                         >
    260                             {__('Blog', 'zenpress')}
    261                         </Button>
    262                         <Button
    263                             variant="secondary"
    264                             onClick={() => enableByPreset('ecommerce')}
    265                             __next40pxDefaultSize
    266                         >
    267                             {__('E-commerce', 'zenpress')}
    268                         </Button>
    269                         <div className="zenpress-presets-description">
    270                             <h2>{__('Or just enable what you need', 'zenpress')}</h2>
    271                         </div>
    272                         <div className="zenpress-actions-bulk">
    273                             <Button
    274                                 variant="secondary"
    275                                 onClick={enableAllSnippets}
    276                                 __next40pxDefaultSize
    277                             >
    278                                 {__('Enable all actions', 'zenpress')}
    279                             </Button>
    280 
    281                             <Button
    282                                 isDestructive="true"
    283                                 onClick={resetSettings}
    284                                 __next40pxDefaultSize
    285                             >
    286                                 {__('Disable all actions', 'zenpress')}
    287                             </Button>
    288                         </div>
    289                     </div>
    290                     {sortedCategories.map((category) => (
    291                         <Panel key={category}>
    292                             <PanelBody
    293                                 title={category}
    294                                 initialOpen={openCategories.has(category)}
    295                             >
    296                                 {groupedSnippets[category].map(({ name, data }) => (
    297                                     <PanelRow key={name}>
    298                                         <SnippetToggleControl
    299                                             label={data.title || name}
    300                                             value={data?.['enable-snippet'] || false}
    301                                             onChange={() => handleToggleChange(name)}
    302                                             help={data.description || ''}
    303                                         />
    304                                     </PanelRow>
    305                                 ))}
    306                             </PanelBody>
    307                         </Panel>
    308                     ))}
    309                     <div className="zenpress-actions">
    310                         <SaveButton onClick={saveSettings} isBusy={isSaving} />
    311                     </div>
    312                     <div className="zenpress-notices">
    313                         <Notices />
    314                     </div>
    315                 </div>
    316             </div>
    317         </>
    318     );
    319 };
     4import { SettingsPage } from './pages/SettingsPage';
    3205
    3216/**
    3227 * Render the ZenPress settings page once the DOM is ready.
    323  *
    324  * @return {void}
    3258 */
    3269domReady(() => {
    32710    const rootEl = document.getElementById('zenpress-settings');
    328     if (!rootEl) return; // Prevent fatal error if DOM element is missing
     11    if (!rootEl) return;
     12
    32913    const root = createRoot(rootEl);
    33014    root.render(<SettingsPage />);
  • zenpress/tags/2.0.3/assets/src/index.scss

    r3352459 r3372200  
    147147    }
    148148}
    149 
    150 /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LnNjc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEiLCJmaWxlIjoiaW5kZXguc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIi56ZW5wcmVzcyB7XG5cblx0Ji1sb2FkaW5nIHtcblx0XHR3aWR0aDogMTAwJTtcblx0XHRtYXgtd2lkdGg6IDkwMHB4O1xuXHRcdG1hcmdpbjogMjBweCBhdXRvO1xuXHR9XG5cblx0Ji1kYXNoYm9hcmQtd3JhcCB7XG5cdFx0YTpub3QoLmNvbXBvbmVudHMtYnV0dG9uKSB7XG5cdFx0XHRjb2xvcjogdmFyKC0td3AtY29tcG9uZW50cy1jb2xvci1hY2NlbnQsIHZhcigtLXdwLWFkbWluLXRoZW1lLWNvbG9yLCAjMzg1OGU5KSk7XG5cblx0XHRcdCZbdGFyZ2V0PSdfYmxhbmsnXSB7XG5cdFx0XHRcdHBvc2l0aW9uOiByZWxhdGl2ZTtcblx0XHRcdFx0Z2FwOiA0cHg7XG5cblx0XHRcdFx0Jjo6YWZ0ZXIge1xuXHRcdFx0XHRcdGNvbnRlbnQ6ICcg4oaXJztcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC5jb21wb25lbnRzLWJ1dHRvbiB7XG5cdFx0XHRnYXA6IDRweDtcblx0XHR9XG5cblx0XHQuY29tcG9uZW50cy1wYW5lbCB7XG5cdFx0XHR3aWR0aDogMTAwJTtcblx0XHRcdG1hcmdpbjogMCBhdXRvIDIwcHggYXV0bztcblx0XHRcdG1heC13aWR0aDogMTAwJTtcblxuXHRcdFx0Jl9fYm9keSB7XG5cdFx0XHRcdCYtdGl0bGUge1xuXHRcdFx0XHRcdHRleHQtdHJhbnNmb3JtOiBjYXBpdGFsaXplO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ji10b2dnbGUge1xuXHRcdFx0XHRcdGJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjZDZlMmVkO1xuXHRcdFx0XHRcdHRleHQtdHJhbnNmb3JtOiBjYXBpdGFsaXplO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0LmNvbXBvbmVudHMtdG9nZ2xlLWNvbnRyb2wge1xuXHRcdFx0Jl9faGVscCB7XG5cdFx0XHRcdGZvbnQtc2l6ZTogMS4xZW07XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0LmNvbXBvbmVudHMtbm90aWNlLWxpc3Qge1xuXHRcdFx0d2lkdGg6IDEwMCU7XG5cdFx0XHRtYXJnaW4tYm90dG9tOiAyMHB4O1xuXHRcdH1cblx0fVxuXG5cdCYtcm93IHtcblx0XHRkaXNwbGF5OiBncmlkO1xuXHRcdGdyaWQtdGVtcGxhdGUtY29sdW1uczogMWZyO1xuXHRcdGdhcDogNDBweDtcblx0XHR3aWR0aDogMTAwJTtcblx0XHRtYXgtd2lkdGg6IDkyMHB4O1xuXHRcdG1hcmdpbjogMCBhdXRvO1xuXHR9XG5cblx0Ji1hY3Rpb25zIHtcblx0XHRkaXNwbGF5OiBmbGV4O1xuXHRcdGZsZXgtd3JhcDogd3JhcDtcblx0XHRnYXA6IDIwcHg7XG5cdFx0anVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xuXHRcdGFsaWduLWl0ZW1zOiBjZW50ZXI7XG5cdFx0bWFyZ2luLWJvdHRvbTogMjBweDtcblxuXHRcdCYtYnVsayB7XG5cdFx0XHRkaXNwbGF5OiBmbGV4O1xuXHRcdFx0ZmxleC13cmFwOiB3cmFwO1xuXHRcdFx0Z2FwOiAxMHB4O1xuXHRcdFx0anVzdGlmeS1jb250ZW50OiBmbGV4LXN0YXJ0O1xuXHRcdFx0YWxpZ24taXRlbXM6IGNlbnRlcjtcblx0XHR9XG5cdH1cblxuXG5cdCYtcHJlc2V0cyB7XG5cdFx0ZGlzcGxheTogZmxleDtcblx0XHRmbGV4LXdyYXA6IHdyYXA7XG5cdFx0Z2FwOiAxMHB4O1xuXHRcdGp1c3RpZnktY29udGVudDogZmxleC1zdGFydDtcblx0XHRhbGlnbi1pdGVtczogY2VudGVyO1xuXHRcdG1hcmdpbi1ib3R0b206IDIwcHg7XG5cblx0XHQmLWRlc2NyaXB0aW9uIHtcblx0XHRcdGZsZXg6IDEwMCU7XG5cdFx0XHR3aWR0aDogMTAwJTtcblx0XHRcdG1heC13aWR0aDogMTAwJTtcblx0XHR9XG5cdH1cblxuXHQmLWhlYWRlciB7XG5cdFx0YWxpZ24taXRlbXM6IGNlbnRlcjtcblx0XHRkaXNwbGF5OiBmbGV4O1xuXHRcdGZsZXgtd3JhcDogd3JhcDtcblx0XHRqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG5cdFx0b3ZlcmZsb3cteDogYXV0bztcblx0XHRwYWRkaW5nOiAxNnB4O1xuXHRcdG1hcmdpbjogMCAwIDIwcHggMDtcblx0XHRnYXA6IDQwcHg7XG5cdFx0YmFja2dyb3VuZDogI2ZmZjtcblx0XHRib3JkZXI6IDFweCBzb2xpZCAjZTBlMGUwO1xuXG5cdFx0Ji1uYXZpZ2F0aW9uIHtcblx0XHRcdGRpc3BsYXk6IGZsZXg7XG5cdFx0XHRmbGV4LXdyYXA6IHdyYXA7XG5cdFx0XHRnYXA6IDIwcHg7XG5cdFx0XHRqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG5cdFx0XHRhbGlnbi1pdGVtczogY2VudGVyO1xuXHRcdH1cblxuXHRcdGgxLFxuXHRcdHAge1xuXHRcdFx0bWFyZ2luOiAwO1xuXHRcdFx0cGFkZGluZzogMDtcblx0XHR9XG5cdH1cblxuXHQmLWZvb3RlciB7XG5cdFx0YWxpZ24taXRlbXM6IGNlbnRlcjtcblx0XHRkaXNwbGF5OiBmbGV4O1xuXHRcdGZsZXgtd3JhcDogd3JhcDtcblx0XHRqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG5cdFx0b3ZlcmZsb3cteDogYXV0bztcblx0XHRwYWRkaW5nOiAxNnB4O1xuXHRcdG1hcmdpbjogMCAwIDIwcHggMDtcblx0XHRnYXA6IDQwcHg7XG5cdFx0Ym9yZGVyLXRvcDogMXB4IHNvbGlkICNlMGUwZTA7XG5cdFx0cGFkZGluZy10b3A6IDMycHg7XG5cblx0XHQmLW5hdmlnYXRpb24ge1xuXHRcdFx0ZGlzcGxheTogZmxleDtcblx0XHRcdGZsZXgtd3JhcDogd3JhcDtcblx0XHRcdGdhcDogMjBweDtcblx0XHRcdGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2Vlbjtcblx0XHRcdGFsaWduLWl0ZW1zOiBjZW50ZXI7XG5cdFx0fVxuXG5cdFx0cCB7XG5cdFx0XHRtYXJnaW46IDA7XG5cdFx0XHRwYWRkaW5nOiAwO1xuXHRcdH1cblx0fVxufVxuIl19 */
  • zenpress/tags/2.0.3/languages/zenpress.pot

    r3352459 r3372200  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: ZenPress 2.0\n"
     5"Project-Id-Version: ZenPress — Cleaner, Lighter, Faster WP 2.0.3\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/zenpress\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2025-08-29T07:34:31+00:00\n"
     12"POT-Creation-Date: 2025-10-02T20:30:15+00:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.12.0\n"
     
    1717#. Plugin Name of the plugin
    1818#: zenpress.php
    19 #: zenpress.php:150
    20 #: zenpress.php:171
    21 msgid "ZenPress"
     19msgid "ZenPress — Cleaner, Lighter, Faster WP"
    2220msgstr ""
    2321
     
    4240msgstr ""
    4341
    44 #: inc/meta/block-user-enumeration.meta.php:13
     42#: inc/admin/links.php:19
     43msgid "Go to ZenPress settings page"
     44msgstr ""
     45
     46#: inc/admin/links.php:20
     47msgid "Settings"
     48msgstr ""
     49
     50#: inc/admin/links.php:40
     51#: inc/admin/menu.php:42
     52msgid "View ZenPress changelog on WordPress.org (opens in a new tab)"
     53msgstr ""
     54
     55#: inc/admin/links.php:41
     56msgid "Changelog"
     57msgstr ""
     58
     59#: inc/admin/links.php:46
     60msgid "Read ZenPress documentation (opens in a new tab)"
     61msgstr ""
     62
     63#: inc/admin/links.php:47
     64msgid "Docs"
     65msgstr ""
     66
     67#: inc/admin/links.php:52
     68msgid "Support ZenPress by buying a coffee (opens in a new tab)"
     69msgstr ""
     70
     71#: inc/admin/links.php:53
     72msgid "Support ☕"
     73msgstr ""
     74
     75#: inc/admin/menu.php:15
     76msgid "ZenPress options"
     77msgstr ""
     78
     79#: inc/admin/menu.php:16
     80#: inc/admin/menu.php:35
     81msgid "ZenPress"
     82msgstr ""
     83
     84#: inc/admin/menu.php:38
     85msgid "Version"
     86msgstr ""
     87
     88#: inc/admin/menu.php:43
     89msgid "What's new ?"
     90msgstr ""
     91
     92#: inc/admin/menu.php:52
     93msgid "Read the ZenPress documentation (opens in a new tab)"
     94msgstr ""
     95
     96#: inc/admin/menu.php:53
     97msgid "Documentation"
     98msgstr ""
     99
     100#: inc/admin/menu.php:58
     101msgid "Leave a review for ZenPress on WordPress.org (opens in a new tab)"
     102msgstr ""
     103
     104#: inc/admin/menu.php:59
     105msgid "Leave a review (helps a lot)"
     106msgstr ""
     107
     108#: inc/admin/menu.php:65
     109msgid "Support development: Buy me a coffee (opens in a new tab)"
     110msgstr ""
     111
     112#: inc/admin/menu.php:66
     113msgid "Buy me a coffee"
     114msgstr ""
     115
     116#: inc/admin/menu.php:74
     117msgid "Loading your ZenPress settings…"
     118msgstr ""
     119
     120#: inc/admin/menu.php:82
     121msgid "Made "
     122msgstr ""
     123
     124#: inc/admin/menu.php:84
     125msgid " by Quentin Le Duff - Your WordPress Partner"
     126msgstr ""
     127
     128#: inc/admin/menu.php:91
     129msgid "Visite the developper website"
     130msgstr ""
     131
     132#: inc/admin/menu.php:92
     133msgid "My place"
     134msgstr ""
     135
     136#: inc/admin/menu.php:97
     137msgid "Review the code on Github"
     138msgstr ""
     139
     140#: inc/admin/menu.php:98
     141msgid "ZenPress code repository"
     142msgstr ""
     143
     144#: inc/snippets/functions/block-user-enumeration.php:13
     145#: inc/snippets/functions/block-user-enumeration.php:21
     146msgid "Access denied."
     147msgstr ""
     148
     149#: inc/snippets/functions/protect-wp-login.php:9
     150msgid "Login error."
     151msgstr ""
     152
     153#: inc/snippets/functions/protect-wp-login.php:35
     154#: inc/snippets/functions/protect-wp-login.php:48
     155msgid "Too many failed login attempts. Try again later."
     156msgstr ""
     157
     158#: inc/snippets/meta/block-user-enumeration.meta.php:13
    45159msgid "Block user enumeration"
    46160msgstr ""
    47161
    48 #: inc/meta/block-user-enumeration.meta.php:14
     162#: inc/snippets/meta/block-user-enumeration.meta.php:14
    49163msgid "Prevents attackers from guessing WordPress usernames by blocking requests with the `author` parameter in query strings or permalinks. Reduces exposure to brute-force and user-targeted attacks."
    50164msgstr ""
    51165
    52 #: inc/meta/block-user-enumeration.meta.php:18
    53 #: inc/meta/disable-author-archives.meta.php:18
    54 #: inc/meta/disable-pingback-trackback.meta.php:15
    55 #: inc/meta/disable-xmlrpc-rsdlink.meta.php:15
    56 #: inc/meta/hide-wordpress-version.meta.php:15
    57 #: inc/meta/protect-wp-login.meta.php:15
     166#: inc/snippets/meta/block-user-enumeration.meta.php:18
     167#: inc/snippets/meta/disable-application-passwords.meta.php:18
     168#: inc/snippets/meta/disable-author-archives.meta.php:18
     169#: inc/snippets/meta/disable-pingback-trackback.meta.php:15
     170#: inc/snippets/meta/disable-xmlrpc-rsdlink.meta.php:15
     171#: inc/snippets/meta/hide-wordpress-version.meta.php:15
     172#: inc/snippets/meta/protect-wp-login.meta.php:15
    58173msgid "Security 🔒️"
    59174msgstr ""
    60175
    61 #: inc/meta/clean-admin-bar.meta.php:13
     176#: inc/snippets/meta/clean-admin-bar.meta.php:13
    62177msgid "Clean up the WordPress admin bar"
    63178msgstr ""
    64179
    65 #: inc/meta/clean-admin-bar.meta.php:14
     180#: inc/snippets/meta/clean-admin-bar.meta.php:14
    66181msgid "Removes unnecessary items from the admin bar in both backend and frontend. Reduces clutter and simplifies the interface."
    67182msgstr ""
    68183
    69 #: inc/meta/clean-admin-bar.meta.php:18
    70 #: inc/meta/clean-dashboard-items.meta.php:18
    71 #: inc/meta/disable-login-language-selector.meta.php:15
     184#: inc/snippets/meta/clean-admin-bar.meta.php:18
     185#: inc/snippets/meta/clean-dashboard-items.meta.php:18
     186#: inc/snippets/meta/disable-login-language-selector.meta.php:15
    72187msgid "User interface 💻️"
    73188msgstr ""
    74189
    75 #: inc/meta/clean-dashboard-items.meta.php:13
     190#: inc/snippets/meta/clean-dashboard-items.meta.php:13
    76191msgid "Clean up the WordPress Dashboard"
    77192msgstr ""
    78193
    79 #: inc/meta/clean-dashboard-items.meta.php:14
     194#: inc/snippets/meta/clean-dashboard-items.meta.php:14
    80195msgid "Removes unnecessary widgets and ads widgets from the dashboard. Declutters the admin area and improves usability."
    81196msgstr ""
    82197
    83 #: inc/meta/disable-adjacent-posts.meta.php:13
     198#: inc/snippets/meta/disable-adjacent-posts.meta.php:13
    84199msgid "Disable adjacent posts link tags"
    85200msgstr ""
    86201
    87 #: inc/meta/disable-adjacent-posts.meta.php:14
     202#: inc/snippets/meta/disable-adjacent-posts.meta.php:14
    88203msgid "Removes rel=\"prev\" and rel=\"next\" tags from wp_head. Reduces unnecessary HTML output and slightly improves performance."
    89204msgstr ""
    90205
    91 #: inc/meta/disable-adjacent-posts.meta.php:18
    92 #: inc/meta/disable-dashicons.meta.php:18
    93 #: inc/meta/disable-dns-prefetch.meta.php:18
    94 #: inc/meta/disable-emoji-scripts.meta.php:18
    95 #: inc/meta/disable-jquery-migrate.meta.php:18
    96 #: inc/meta/disable-oembed.meta.php:15
    97 #: inc/meta/disable-pdf-thumbnails.meta.php:15
    98 #: inc/meta/disable-rss.meta.php:15
    99 #: inc/meta/disable-shortlink.meta.php:15
    100 #: inc/meta/disable-wlw-manifest.meta.php:15
    101 #: inc/meta/remove-gutenberg-unwanted-block-patterns.meta.php:15
    102 #: inc/meta/remove-rest-api-link.meta.php:15
    103 #: inc/meta/separate-gutenberg-core-block-styles.meta.php:15
     206#: inc/snippets/meta/disable-adjacent-posts.meta.php:18
     207#: inc/snippets/meta/disable-dashicons.meta.php:18
     208#: inc/snippets/meta/disable-dns-prefetch.meta.php:18
     209#: inc/snippets/meta/disable-emoji-scripts.meta.php:18
     210#: inc/snippets/meta/disable-jquery-migrate.meta.php:18
     211#: inc/snippets/meta/disable-oembed.meta.php:15
     212#: inc/snippets/meta/disable-pdf-thumbnails.meta.php:15
     213#: inc/snippets/meta/disable-rss.meta.php:15
     214#: inc/snippets/meta/disable-shortlink.meta.php:15
     215#: inc/snippets/meta/disable-wlw-manifest.meta.php:15
     216#: inc/snippets/meta/remove-gutenberg-unwanted-block-patterns.meta.php:15
     217#: inc/snippets/meta/remove-rest-api-link.meta.php:15
     218#: inc/snippets/meta/separate-gutenberg-core-block-styles.meta.php:15
    104219msgid "Performance 🚀"
    105220msgstr ""
    106221
    107 #: inc/meta/disable-author-archives.meta.php:13
     222#: inc/snippets/meta/disable-application-passwords.meta.php:13
     223msgid "Disable application passwords"
     224msgstr ""
     225
     226#: inc/snippets/meta/disable-application-passwords.meta.php:14
     227msgid "Disables WordPress application passwords for all users, improving security. Only disable if API access is not needed."
     228msgstr ""
     229
     230#: inc/snippets/meta/disable-author-archives.meta.php:13
    108231msgid "Disable author archives"
    109232msgstr ""
    110233
    111 #: inc/meta/disable-author-archives.meta.php:14
     234#: inc/snippets/meta/disable-author-archives.meta.php:14
    112235msgid "Forces author archive pages to return a 404 error. Prevents user enumeration and hides unnecessary author pages."
    113236msgstr ""
    114237
    115 #: inc/meta/disable-dashicons.meta.php:13
     238#: inc/snippets/meta/disable-dashicons.meta.php:13
    116239msgid "Disable dashicons"
    117240msgstr ""
    118241
    119 #: inc/meta/disable-dashicons.meta.php:14
     242#: inc/snippets/meta/disable-dashicons.meta.php:14
    120243msgid "Prevents WordPress from loading the Dashicons CSS for visitors who are not logged in. Improves frontend performance by reducing unnecessary styles."
    121244msgstr ""
    122245
    123 #: inc/meta/disable-dns-prefetch.meta.php:13
     246#: inc/snippets/meta/disable-dns-prefetch.meta.php:13
    124247msgid "Disable DNS prefetch"
    125248msgstr ""
    126249
    127 #: inc/meta/disable-dns-prefetch.meta.php:14
     250#: inc/snippets/meta/disable-dns-prefetch.meta.php:14
    128251msgid "Removes DNS prefetch resource hints from wp_head avoids unnecessary DNS lookups and slightly improve performance on some sites."
    129252msgstr ""
    130253
    131 #: inc/meta/disable-emoji-scripts.meta.php:13
     254#: inc/snippets/meta/disable-emoji-scripts.meta.php:13
    132255msgid "Disable WordPress emoji scripts and styles"
    133256msgstr ""
    134257
    135 #: inc/meta/disable-emoji-scripts.meta.php:14
     258#: inc/snippets/meta/disable-emoji-scripts.meta.php:14
    136259msgid "Removes emoji scripts, styles, and filters from frontend, backend, feeds, emails, and TinyMCE. Reduces unnecessary assets and improves performance."
    137260msgstr ""
    138261
    139 #: inc/meta/disable-jquery-migrate.meta.php:13
     262#: inc/snippets/meta/disable-jquery-migrate.meta.php:13
    140263msgid "Disable jQuery migrate"
    141264msgstr ""
    142265
    143 #: inc/meta/disable-jquery-migrate.meta.php:14
     266#: inc/snippets/meta/disable-jquery-migrate.meta.php:14
    144267msgid "Removes jQuery Migrate from loading on the frontend while keeping it enabled in the admin. Improves frontend performance and reduces legacy overhead."
    145268msgstr ""
    146269
    147 #: inc/meta/disable-login-language-selector.meta.php:13
     270#: inc/snippets/meta/disable-login-language-selector.meta.php:13
    148271msgid "Disable the login language selector"
    149272msgstr ""
    150273
    151 #: inc/meta/disable-login-language-selector.meta.php:14
     274#: inc/snippets/meta/disable-login-language-selector.meta.php:14
    152275msgid "Removes the language dropdown from the WordPress login page. Simplifies login screen and reduces distractions."
    153276msgstr ""
    154277
    155 #: inc/meta/disable-oembed.meta.php:13
     278#: inc/snippets/meta/disable-oembed.meta.php:13
    156279msgid "Disable oEmbed"
    157280msgstr ""
    158281
    159 #: inc/meta/disable-oembed.meta.php:14
     282#: inc/snippets/meta/disable-oembed.meta.php:14
    160283msgid "Removes WordPress oEmbed features such as auto-discovery, REST API routes, TinyMCE integration, and the wp-embed script. Reduces API calls, improves performance, and limits unnecessary external requests."
    161284msgstr ""
    162285
    163 #: inc/meta/disable-pdf-thumbnails.meta.php:13
     286#: inc/snippets/meta/disable-pdf-thumbnails.meta.php:13
    164287msgid "Disable PDF thumbnails"
    165288msgstr ""
    166289
    167 #: inc/meta/disable-pdf-thumbnails.meta.php:14
     290#: inc/snippets/meta/disable-pdf-thumbnails.meta.php:14
    168291msgid "Prevents WordPress from generating thumbnails for uploaded PDF files by removing fallback image sizes. saves storage space and improves performance by avoiding unnecessary image generation."
    169292msgstr ""
    170293
    171 #: inc/meta/disable-pingback-trackback.meta.php:13
     294#: inc/snippets/meta/disable-pingback-trackback.meta.php:13
    172295msgid "Disable pingback and trackback"
    173296msgstr ""
    174297
    175 #: inc/meta/disable-pingback-trackback.meta.php:14
     298#: inc/snippets/meta/disable-pingback-trackback.meta.php:14
    176299msgid "Removes the X-Pingback header, disables pingbacks and trackbacks on new posts, and prevents self-pingbacks. reduces spam, blocks potential DDoS vectors, and slightly improves performance by avoiding useless requests."
    177300msgstr ""
    178301
    179 #: inc/meta/disable-rss.meta.php:13
     302#: inc/snippets/meta/disable-rss.meta.php:13
    180303msgid "Disable all WordPress feeds (RDF, RSS, RSS2, Atom, and comments)"
    181304msgstr ""
    182305
    183 #: inc/meta/disable-rss.meta.php:14
     306#: inc/snippets/meta/disable-rss.meta.php:14
    184307msgid "Prevents access to all default feeds (RDF, RSS, RSS2, Atom, and comments). Also removes feed links from head, and redirects feed requests to the homepage. Reduces unnecessary requests and improves SEO consistency."
    185308msgstr ""
    186309
    187 #: inc/meta/disable-shortlink.meta.php:13
     310#: inc/snippets/meta/disable-shortlink.meta.php:13
    188311msgid "Disable WordPress shortlink"
    189312msgstr ""
    190313
    191 #: inc/meta/disable-shortlink.meta.php:14
     314#: inc/snippets/meta/disable-shortlink.meta.php:14
    192315msgid "Removes shortlink functionality from both the HTML head and HTTP headers. Reduces unnecessary output, improves performance and SEO clarity."
    193316msgstr ""
    194317
    195 #: inc/meta/disable-wlw-manifest.meta.php:13
     318#: inc/snippets/meta/disable-wlw-manifest.meta.php:13
    196319msgid "Disable WLW link"
    197320msgstr ""
    198321
    199 #: inc/meta/disable-wlw-manifest.meta.php:14
     322#: inc/snippets/meta/disable-wlw-manifest.meta.php:14
    200323msgid "Removes the WLW manifest link from the head, which was only used by the deprecated Windows Live Writer app. Reduces unnecessary metadata and improves performance."
    201324msgstr ""
    202325
    203 #: inc/meta/disable-woocommerce-cart-fragments.meta.php:13
     326#: inc/snippets/meta/disable-woocommerce-cart-fragments.meta.php:13
    204327msgid "Disable WooCommerce cart fragments script"
    205328msgstr ""
    206329
    207 #: inc/meta/disable-woocommerce-cart-fragments.meta.php:14
     330#: inc/snippets/meta/disable-woocommerce-cart-fragments.meta.php:14
    208331msgid "Removes the WooCommerce cart fragments JavaScript (wc-cart-fragments), which is responsible for dynamically updating the cart contents without a page reload. Disabling this can improve performance on stores that do not require live cart updates."
    209332msgstr ""
    210333
    211 #: inc/meta/disable-woocommerce-cart-fragments.meta.php:15
    212 #: inc/meta/disable-woocommerce-scripts-styles.meta.php:15
    213 #: inc/meta/disable-woocommerce-stripe-scripts.meta.php:15
    214 #: inc/meta/disable-woocommerce-widgets.meta.php:15
    215 #: inc/meta/hide-woocommerce-version.meta.php:15
    216 #: inc/meta/remove-woocommerce-patterns.meta.php:15
     334#: inc/snippets/meta/disable-woocommerce-cart-fragments.meta.php:15
     335#: inc/snippets/meta/disable-woocommerce-scripts-styles.meta.php:15
     336#: inc/snippets/meta/disable-woocommerce-stripe-scripts.meta.php:15
     337#: inc/snippets/meta/disable-woocommerce-widgets.meta.php:15
     338#: inc/snippets/meta/hide-woocommerce-version.meta.php:15
     339#: inc/snippets/meta/remove-woocommerce-patterns.meta.php:15
    217340msgid "WooCommerce 🛒"
    218341msgstr ""
    219342
    220 #: inc/meta/disable-woocommerce-scripts-styles.meta.php:13
     343#: inc/snippets/meta/disable-woocommerce-scripts-styles.meta.php:13
    221344msgid "Disable WooCommerce scripts and styles on non-WooCommerce pages"
    222345msgstr ""
    223346
    224 #: inc/meta/disable-woocommerce-scripts-styles.meta.php:14
     347#: inc/snippets/meta/disable-woocommerce-scripts-styles.meta.php:14
    225348msgid "Dequeues WooCommerce assets on pages where WooCommerce functionality is not required, such as homepage, blog posts, or custom pages. Helps improve performance by preventing unnecessary asset loading."
    226349msgstr ""
    227350
    228 #: inc/meta/disable-woocommerce-stripe-scripts.meta.php:13
     351#: inc/snippets/meta/disable-woocommerce-stripe-scripts.meta.php:13
    229352msgid "Disable unnecessary Stripe scripts on WooCommerce pages"
    230353msgstr ""
    231354
    232 #: inc/meta/disable-woocommerce-stripe-scripts.meta.php:14
     355#: inc/snippets/meta/disable-woocommerce-stripe-scripts.meta.php:14
    233356msgid "Prevents loading of Stripe-related scripts on the product and cart pages when the \"Payment Request Button Support\" (PRBS) is disabled. Helps improve performance by avoiding unnecessary JavaScript loading."
    234357msgstr ""
    235358
    236 #: inc/meta/disable-woocommerce-widgets.meta.php:13
     359#: inc/snippets/meta/disable-woocommerce-widgets.meta.php:13
    237360msgid "Disable WooCommerce widgets"
    238361msgstr ""
    239362
    240 #: inc/meta/disable-woocommerce-widgets.meta.php:14
     363#: inc/snippets/meta/disable-woocommerce-widgets.meta.php:14
    241364msgid "Unregisters default WooCommerce widgets to reduce bloat in the widget screen and improve performance by removing unused features."
    242365msgstr ""
    243366
    244 #: inc/meta/disable-xmlrpc-rsdlink.meta.php:13
     367#: inc/snippets/meta/disable-xmlrpc-rsdlink.meta.php:13
    245368msgid "Disable XML-RPC and remove RSD link"
    246369msgstr ""
    247370
    248 #: inc/meta/disable-xmlrpc-rsdlink.meta.php:14
     371#: inc/snippets/meta/disable-xmlrpc-rsdlink.meta.php:14
    249372msgid "Disables XML-RPC (often targeted by brute force or DDoS attacks) and removes the RSD link from the HTML head to reduce exposure."
    250373msgstr ""
    251374
    252 #: inc/meta/hide-woocommerce-version.meta.php:13
     375#: inc/snippets/meta/hide-woocommerce-version.meta.php:13
    253376msgid "Hide WooCommerce version"
    254377msgstr ""
    255378
    256 #: inc/meta/hide-woocommerce-version.meta.php:14
     379#: inc/snippets/meta/hide-woocommerce-version.meta.php:14
    257380msgid "Removes WooCommerce version info from HTTP headers and asset URLs. Reduces exposure of version number and makes it harder for attackers to target specific WooCommerce versions."
    258381msgstr ""
    259382
    260 #: inc/meta/hide-wordpress-version.meta.php:13
     383#: inc/snippets/meta/hide-wordpress-version.meta.php:13
    261384msgid "Hide WordPress version"
    262385msgstr ""
    263386
    264 #: inc/meta/hide-wordpress-version.meta.php:14
     387#: inc/snippets/meta/hide-wordpress-version.meta.php:14
    265388msgid "Removes WordPress version info from the head, generator, and asset URLs. Reduces exposure of version number and makes it harder for attackers to target specific WordPress versions."
    266389msgstr ""
    267390
    268 #: inc/meta/protect-wp-login.meta.php:13
     391#: inc/snippets/meta/protect-wp-login.meta.php:13
    269392msgid "Protect the wp-login form from brute force attacks"
    270393msgstr ""
    271394
    272 #: inc/meta/protect-wp-login.meta.php:14
     395#: inc/snippets/meta/protect-wp-login.meta.php:14
    273396msgid "Removes detailed login error messages and limits failed login attempts per IP address. Blocks further attempts for a set duration after too many failures. Improves security by mitigating brute force attacks."
    274397msgstr ""
    275398
    276 #: inc/meta/remove-gutenberg-unwanted-block-patterns.meta.php:13
     399#: inc/snippets/meta/remove-gutenberg-unwanted-block-patterns.meta.php:13
    277400msgid "Remove WordPress default remote block patterns"
    278401msgstr ""
    279402
    280 #: inc/meta/remove-gutenberg-unwanted-block-patterns.meta.php:14
     403#: inc/snippets/meta/remove-gutenberg-unwanted-block-patterns.meta.php:14
    281404msgid "Prevents WordPress from loading remote block patterns and removes the built-in core block patterns. Reduces editor clutter and improves performance by avoiding unnecessary data loading."
    282405msgstr ""
    283406
    284 #: inc/meta/remove-rest-api-link.meta.php:13
     407#: inc/snippets/meta/remove-rest-api-link.meta.php:13
    285408msgid "Remove REST API links"
    286409msgstr ""
    287410
    288 #: inc/meta/remove-rest-api-link.meta.php:14
     411#: inc/snippets/meta/remove-rest-api-link.meta.php:14
    289412msgid "Prevents WordPress from adding REST API discovery links to the head section of the site. reduces unnecessary HTML output and slightly improves performance while keeping REST API functionality available."
    290413msgstr ""
    291414
    292 #: inc/meta/remove-woocommerce-patterns.meta.php:13
     415#: inc/snippets/meta/remove-woocommerce-patterns.meta.php:13
    293416msgid "Remove WooCommerce default remote block patterns"
    294417msgstr ""
    295418
    296 #: inc/meta/remove-woocommerce-patterns.meta.php:14
     419#: inc/snippets/meta/remove-woocommerce-patterns.meta.php:14
    297420msgid "Removes all WooCommerce remote block patterns to avoid unnecessary pattern registration in the editor."
    298421msgstr ""
    299422
    300 #: inc/meta/separate-gutenberg-core-block-styles.meta.php:13
     423#: inc/snippets/meta/separate-gutenberg-core-block-styles.meta.php:13
    301424msgid "Separate loading of core block styles"
    302425msgstr ""
    303426
    304 #: inc/meta/separate-gutenberg-core-block-styles.meta.php:14
     427#: inc/snippets/meta/separate-gutenberg-core-block-styles.meta.php:14
    305428msgid "Forces WordPress to load core block styles separately, improving performance by only loading the styles required for the blocks used on a page."
    306429msgstr ""
    307430
    308 #: inc/snippets/block-user-enumeration.php:13
    309 #: inc/snippets/block-user-enumeration.php:21
    310 msgid "Access denied."
    311 msgstr ""
    312 
    313 #: inc/snippets/protect-wp-login.php:9
    314 msgid "Login error."
    315 msgstr ""
    316 
    317 #: inc/snippets/protect-wp-login.php:36
    318 #: inc/snippets/protect-wp-login.php:49
    319 msgid "Too many failed login attempts. Try again later."
    320 msgstr ""
    321 
    322 #: zenpress.php:60
    323 msgid "Go to ZenPress settings page"
    324 msgstr ""
    325 
    326 #: zenpress.php:61
    327 msgid "Settings"
    328 msgstr ""
    329 
    330 #: zenpress.php:82
    331 #: zenpress.php:179
    332 msgid "View ZenPress changelog on WordPress.org (opens in a new tab)"
    333 msgstr ""
    334 
    335 #: zenpress.php:82
    336 msgid "Changelog"
    337 msgstr ""
    338 
    339 #: zenpress.php:83
    340 msgid "Read ZenPress documentation (opens in a new tab)"
    341 msgstr ""
    342 
    343 #: zenpress.php:83
    344 msgid "Docs"
    345 msgstr ""
    346 
    347 #: zenpress.php:84
    348 msgid "Support ZenPress by buying a coffee (opens in a new tab)"
    349 msgstr ""
    350 
    351 #: zenpress.php:84
    352 msgid "Support ☕"
    353 msgstr ""
    354 
    355 #: zenpress.php:149
    356 msgid "ZenPress options"
    357 msgstr ""
    358 
    359 #: zenpress.php:175
    360 msgid "Version"
    361 msgstr ""
    362 
    363 #: zenpress.php:180
    364 msgid "What's new ?"
    365 msgstr ""
    366 
    367 #: zenpress.php:189
    368 msgid "Read the ZenPress documentation (opens in a new tab)"
    369 msgstr ""
    370 
    371 #: zenpress.php:190
    372 msgid "Documentation"
    373 msgstr ""
    374 
    375 #: zenpress.php:196
    376 msgid "Leave a review for ZenPress on WordPress.org (opens in a new tab)"
    377 msgstr ""
    378 
    379 #: zenpress.php:197
    380 msgid "Leave a review (helps a lot)"
    381 msgstr ""
    382 
    383 #: zenpress.php:204
    384 msgid "Support development: Buy me a coffee (opens in a new tab)"
    385 msgstr ""
    386 
    387 #: zenpress.php:205
    388 msgid "Buy me a coffee"
    389 msgstr ""
    390 
    391 #: zenpress.php:214
    392 msgid "Loading your ZenPress settings…"
    393 msgstr ""
    394 
    395 #: zenpress.php:223
    396 msgid "Made "
    397 msgstr ""
    398 
    399 #: zenpress.php:225
    400 msgid " by Quentin Le Duff - Your WordPress Partner"
    401 msgstr ""
    402 
    403 #: zenpress.php:232
    404 msgid "Visite the developper website"
    405 msgstr ""
    406 
    407 #: zenpress.php:233
    408 msgid "My place"
    409 msgstr ""
    410 
    411 #: zenpress.php:238
    412 msgid "Review the code on Github"
    413 msgstr ""
    414 
    415 #: zenpress.php:239
    416 msgid "ZenPress code repository"
    417 msgstr ""
    418 
    419 #: assets/build/index.js:1
    420 #: assets/src/index.js:119
     431#: assets/build/index.js:1
     432#: assets/src/components/SaveButton.js:16
    421433msgid "Save settings"
    422434msgstr ""
    423435
    424436#: assets/build/index.js:1
    425 #: assets/src/index.js:51
     437#: assets/src/hooks/useSettings.js:41
    426438msgid "Failed to load settings."
    427439msgstr ""
    428440
    429441#: assets/build/index.js:1
    430 #: assets/src/index.js:73
     442#: assets/src/hooks/useSettings.js:56
    431443msgid "Settings saved."
    432444msgstr ""
    433445
    434446#: assets/build/index.js:1
    435 #: assets/src/index.js:76
     447#: assets/src/hooks/useSettings.js:58
    436448msgid "Failed to save settings."
    437449msgstr ""
    438450
    439451#: assets/build/index.js:1
    440 #: assets/src/index.js:178
    441 #: assets/src/index.js:217
    442 #: assets/src/index.js:229
     452#: assets/src/pages/SettingsPage.js:66
    443453msgid "Uncategorized"
    444454msgstr ""
    445455
    446456#: assets/build/index.js:1
    447 #: assets/src/index.js:246
     457#: assets/src/pages/SettingsPage.js:83
    448458msgid "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."
    449459msgstr ""
    450460
    451461#: assets/build/index.js:1
    452 #: assets/src/index.js:251
     462#: assets/src/pages/SettingsPage.js:88
    453463msgid "Pick a preset"
    454464msgstr ""
    455465
    456466#: assets/build/index.js:1
    457 #: assets/src/index.js:259
     467#: assets/src/pages/SettingsPage.js:96
    458468msgid "Showcase website"
    459469msgstr ""
    460470
    461471#: assets/build/index.js:1
    462 #: assets/src/index.js:266
     472#: assets/src/pages/SettingsPage.js:99
    463473msgid "Blog"
    464474msgstr ""
    465475
    466476#: assets/build/index.js:1
    467 #: assets/src/index.js:273
     477#: assets/src/pages/SettingsPage.js:102
    468478msgid "E-commerce"
    469479msgstr ""
    470480
    471481#: assets/build/index.js:1
    472 #: assets/src/index.js:276
     482#: assets/src/pages/SettingsPage.js:106
    473483msgid "Or just enable what you need"
    474484msgstr ""
    475485
    476486#: assets/build/index.js:1
    477 #: assets/src/index.js:284
     487#: assets/src/pages/SettingsPage.js:111
    478488msgid "Enable all actions"
    479489msgstr ""
    480490
    481491#: assets/build/index.js:1
    482 #: assets/src/index.js:292
     492#: assets/src/pages/SettingsPage.js:115
    483493msgid "Disable all actions"
    484494msgstr ""
  • zenpress/tags/2.0.3/readme.txt

    r3355428 r3372200  
    55Requires at least: 6.0
    66Tested up to: 6.8
    7 Stable tag: 2.0.2
     7Stable tag: 2.0.3
    88Requires PHP: 7.4
    99License: GPLv2 or later
     
    5555
    5656* Block user enumeration
     57* Disable application passwords
    5758* Disable author archives
    5859* Disable pingback and trackback
     
    8182
    8283= Security =
    83 * Disable Application Passwords
    8484* Manage Heartbeat API (frontend + backend + admin whitelist)
    8585* Disable REST API
     
    8989* Disable autosave
    9090* Disable post revision
    91 * Disable native lazy loading
    9291* Disable Password Strength Meter
    9392* Disable WordPress default lazy loading
     
    159158== Changelog ==
    160159
     160= 2.0.3 =
     161- Global: Codebase and snippets optimization
     162- Global: Fix typo
     163- New actionable function: Disable application passwords
     164
    161165= 2.0.2 =
    162166
     
    178182= 1.0.9.1 =
    179183
    180 - Compatibility : Plugin tested up to PHP 8.4
     184- Compatibility: Plugin tested up to PHP 8.4
    181185
    182186= 1.0.9 =
    183187
    184 - Compatibility : Plugin tested up to PHP 8.4
    185 - UI : Disable login language selector
     188- Compatibility: Plugin tested up to PHP 8.4
     189- New actionable function: Disable login language selector
    186190- Fix constant naming in readme.txt
    187191
    188192= 1.0.8 =
    189193
    190 - UI : Remove smash baloon ads meta box
     194- UI: Remove smash baloon ads meta box
    191195- Global : Files naming and call for scalability
    192196
     
    194198
    195199- ZenPress tested for WordPress 6.8.1
    196 - UI : Remove site health meta box
    197 - UI : Remove WooCommerce admin dashboard setup metabox
     200- UI: Remove site health meta box
     201- UI: Remove WooCommerce admin dashboard setup metabox
    198202
    199203= 1.0.6 =
     
    210214
    211215- Fix ABSPATH on woocommerce patterns snippets.
    212 - Performance : Disable RSS feeds except main one.
    213 - Performance : Remove RSS feeds links in head except main one.
    214 - Performance : Remove Rest API link in head.
    215 - Performance : Remove WP Mail SMTP ads widget.
     216- New actionable function: Disable RSS feeds except main one.
     217- New actionable function: Remove RSS feeds links in head except main one.
     218- New actionable function: Remove Rest API link in head.
     219- New actionable function: Remove WP Mail SMTP ads widget.
    216220
    217221= 1.0.3 =
    218222
    219223- ZenPress tested for WordPress 6.8.
    220 - UI : Disable AARVE plugin bloat widget.
     224- UI: Disable AARVE plugin bloat widget.
    221225
    222226= 1.0.2 =
    223227
    224228- Remove load_plugin_textdomain, not needed since WordPress 4.6.
    225 - Protect wp login : Add zenpress_ prefix to transients.
     229- Protect wp login: Add zenpress_ prefix to transients.
    226230- Remove woocommerce patterns : Add zenpress_ prefix to function.
    227231- Lint and fix PHP code with phpstan.
  • zenpress/tags/2.0.3/zenpress.php

    r3355428 r3372200  
    1212 * 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.2
     14 * Version: 2.0.3
    1515 * Plugin URI: https://wordpress.org/plugins/zenpress/
    1616 * Author: Quentin Le Duff
     
    3939}
    4040
    41 /**
    42  * Enqueue scripts and styles used by the plugin in admin area.
    43  *
    44  * @param string $admin_page Current admin page hook.
    45  * @return void
    46  */
    47 add_action('admin_enqueue_scripts', 'zenpress_admin_enqueue_scripts');
    48 function zenpress_admin_enqueue_scripts(string $admin_page): void {
    49     if ('settings_page_zenpress' !== $admin_page) {
    50         return;
    51     }
     41define('ZENPRESS_PLUGIN_FILE', __FILE__);
     42define('ZENPRESS_PLUGIN_DIR', plugin_dir_path(__FILE__));
    5243
    53     $asset_file = plugin_dir_path(__FILE__) . 'assets/build/index.asset.php';
    54     if (!file_exists($asset_file)) {
    55         return;
    56     }
     44// Core
     45require_once __DIR__ . '/inc/core/constants.php';
     46require_once __DIR__ . '/inc/core/metadata.php';
     47require_once __DIR__ . '/inc/core/sanitize.php';
    5748
    58     $asset = include $asset_file;
    59     wp_enqueue_script(
    60         'zenpress-scripts',
    61         plugins_url('assets/build/index.js', __FILE__),
    62         $asset['dependencies'],
    63         $asset['version'],
    64         true
    65     );
     49// Admin UI
     50require_once __DIR__ . '/inc/admin/enqueue.php';
     51require_once __DIR__ . '/inc/admin/links.php';
     52require_once __DIR__ . '/inc/admin/menu.php';
    6653
    67     wp_enqueue_style(
    68         'zenpress-style',
    69         plugins_url('assets/build/index.css', __FILE__),
    70         array_filter(
    71             $asset['dependencies'],
    72             function ($style) {
    73                 return wp_style_is($style, 'registered');
    74             }
    75         ),
    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  */
    86 add_action('admin_enqueue_scripts', 'zenpress_localize_snippets_meta');
    87 function 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  */
    112 add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'zenpress_add_settings_link');
    113 function 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  */
    131 add_filter('plugin_row_meta', 'zenpress_plugin_row_meta', 10, 2);
    132 function 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 }
    158 
    159 /**
    160  * Register ZenPress options page under the Settings menu.
    161  *
    162  * @return void
    163  */
    164 add_action('admin_menu', 'zenpress_add_option_page');
    165 function zenpress_add_option_page(): void {
    166     add_options_page(
    167         __('ZenPress options', 'zenpress'),
    168         __('ZenPress', 'zenpress'),
    169         'manage_options',
    170         'zenpress',
    171         'zenpress_options_page'
    172     );
    173 }
    174 
    175 /**
    176  * Render ZenPress options page content.
    177  *
    178  * @return void
    179  */
    180 function zenpress_options_page(): void {
    181     $plugin_data = get_file_data(__FILE__, ['Version' => 'Version'], 'plugin');
    182     $plugin_version = $plugin_data['Version'] ?? '';
    183     ?>
    184     <div class="wrap zenpress-dashboard-wrap">
    185         <div class="zenpress-header">
    186             <div class="zenpress-header-title">
    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>
    221         </div>
    222         <div id="zenpress-settings" class="zenpress-settings">
    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>
    230         </div>
    231         <div class="zenpress-footer">
    232             <div class="zenpress-footer-title">
    233                 <p>
    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>
    253         </div>
    254     </div>
    255     <?php
    256 }
    257 
    258 /**
    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).
    263  */
    264 function zenpress_extract_snippet_metadata(string $snippet_name): array {
    265     $defaults = array(
    266         'title'       => '',
    267         'description' => '',
    268         'category'    => '',
    269         'weight'      => 0,
    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  */
    289 add_action('init', 'zenpress_register_snippet_settings');
    290 function zenpress_register_snippet_settings(): void {
    291     register_setting(
    292         'options',
    293         'zenpress_active_snippets',
    294         array(
    295             'type'              => 'array',
    296             'default'           => array(),
    297             'sanitize_callback' => 'zenpress_sanitize_snippets_option',
    298             'show_in_rest'      => array(
    299                 'schema' => array(
    300                     'type'  => 'array',
    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  */
    314 function 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.
    327  */
    328 function zenpress_load_snippets(string $folder = 'inc/snippets/'): array {
    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)) {
    342             include_once $file;
    343             $loaded[] = $name;
    344         }
    345     }
    346     return $loaded;
    347 }
    348 
    349 /**
    350  * Boot ZenPress snippets.
    351  */
    352 add_action('init', function() : void {
    353     zenpress_load_snippets();
    354 });
     54// Settings logic
     55require_once __DIR__ . '/inc/settings/options.php';
     56require_once __DIR__ . '/inc/settings/loader.php';
  • zenpress/trunk/assets/build/index.asset.php

    r3355428 r3372200  
    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');
     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' => '64ce0d65ec54e96537a1');
  • zenpress/trunk/assets/build/index.js

    r3355428 r3372200  
    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)(_,{}))})})();
     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&&0!==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=window?.zenpressSnippetsMeta||{},i={};Object.keys(n).forEach(e=>{i[e]={...n[e],"enable-snippet":t.includes(e)}}),s(i)}).catch(()=>{p((0,i.__)("Failed to load settings.","zenpress"))})},[p]),{snippets:e,setSnippets:s,saveSettings:async()=>{a(!0);const s=Object.keys(e).filter(s=>e[s]?.["enable-snippet"]);try{await c()({path:"/wp/v2/settings",method:"POST",data:{zenpress_active_snippets:s}}),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={};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))},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)("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(j))},__next40pxDefaultSize:!0,children:(0,i.__)("Enable all actions","zenpress")}),(0,p.jsx)(a.Button,{isDestructive:!0,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: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)(_,{}))})})();
  • zenpress/trunk/assets/src/index.js

    r3355428 r3372200  
    1 // Import necessary modules from WordPress libraries
    21import domReady from '@wordpress/dom-ready';
    32import { createRoot } from '@wordpress/element';
    4 import { __ } from '@wordpress/i18n';
    5 import { ToggleControl } from '@wordpress/components';
    6 import { Button } from '@wordpress/components';
    7 import { Panel, PanelBody, PanelRow } from '@wordpress/components';
    8 import { useState } from '@wordpress/element';
    9 import apiFetch from '@wordpress/api-fetch';
    10 import { useEffect } from '@wordpress/element';
    11 import { useDispatch, useSelect } from '@wordpress/data';
    12 import { store as noticesStore } from '@wordpress/notices';
    13 import { NoticeList } from '@wordpress/components';
    143import './index.scss';
    15 
    16 /**
    17  * Custom hook to manage ZenPress settings state.
    18  *
    19  * @returns {object} Settings state and actions.
    20  * @property {object} snippets - Current snippets with metadata.
    21  * @property {Function} setSnippets - Setter to update snippets state.
    22  * @property {Function} saveSettings - Function to persist settings to REST API.
    23  * @property {boolean} isSaving - Whether settings are currently being saved.
    24  */
    25 const useSettings = () => {
    26     const [snippets, setSnippets] = useState({});
    27     const [isSaving, setIsSaving] = useState(false);
    28     const { createSuccessNotice, createErrorNotice } = useDispatch(noticesStore);
    29 
    30     useEffect(() => {
    31         apiFetch({ path: '/wp/v2/settings' })
    32             .then((settings) => {
    33                 const active = Array.isArray(settings?.zenpress_active_snippets)
    34                     ? settings.zenpress_active_snippets
    35                     : [];
    36 
    37                 const snippetsData = {};
    38                 const meta = window?.zenpressSnippetsMeta || {};
    39 
    40                 Object.keys(meta).forEach((snippetName) => {
    41                     const m = meta[snippetName] || {};
    42                     snippetsData[snippetName] = {
    43                         ...m,
    44                         'enable-snippet': active.includes(snippetName),
    45                     };
    46                 });
    47 
    48                 setSnippets(snippetsData);
    49             })
    50             .catch(() => {
    51                 createErrorNotice(__('Failed to load settings.', 'zenpress'));
    52             });
    53     }, [createErrorNotice]);
    54 
    55     /**
    56      * Save updated snippets to WordPress REST API.
    57      *
    58      * @returns {Promise<void>}
    59      */
    60     const saveSettings = () => {
    61         setIsSaving(true);
    62 
    63         const active = Object.keys(snippets).filter(
    64             (snippetName) => snippets[snippetName]?.['enable-snippet'] || false
    65         );
    66 
    67         return apiFetch({
    68             path: '/wp/v2/settings',
    69             method: 'POST',
    70             data: { zenpress_active_snippets: active },
    71         })
    72             .then(() => {
    73                 createSuccessNotice(__('Settings saved.', 'zenpress'));
    74             })
    75             .catch(() => {
    76                 createErrorNotice(__('Failed to save settings.', 'zenpress'));
    77             })
    78             .finally(() => setIsSaving(false));
    79     };
    80 
    81     return { snippets, setSnippets, saveSettings, isSaving };
    82 };
    83 
    84 /**
    85  * Toggle control for enabling/disabling a snippet.
    86  *
    87  * @param {object} props - Component props.
    88  * @param {string} props.label - Label of the toggle.
    89  * @param {boolean} props.value - Current state of the toggle.
    90  * @param {Function} props.onChange - Change handler.
    91  * @param {string} [props.help] - Optional description/help text.
    92  * @returns {JSX.Element} The toggle control.
    93  */
    94 const SnippetToggleControl = ({ label, value, onChange, help }) => (
    95     <ToggleControl
    96         label={label}
    97         checked={value}
    98         onChange={onChange}
    99         help={help}
    100         __nextHasNoMarginBottom
    101     />
    102 );
    103 
    104 /**
    105  * Save button component.
    106  *
    107  * @param {object} props - Component props.
    108  * @param {Function} props.onClick - Click handler for save action.
    109  * @param {boolean} props.isBusy - Whether the button is in loading state.
    110  * @returns {JSX.Element} The save button.
    111  */
    112 const SaveButton = ({ onClick, isBusy }) => (
    113     <Button
    114         variant="primary"
    115         onClick={onClick}
    116         isBusy={isBusy}
    117         __next40pxDefaultSize
    118     >
    119         {__('Save settings', 'zenpress')}
    120     </Button>
    121 );
    122 
    123 /**
    124  * Notices component to display success/error messages.
    125  *
    126  * @returns {JSX.Element|null} List of notices or null if none exist.
    127  */
    128 const Notices = () => {
    129     const { removeNotice } = useDispatch(noticesStore);
    130     const notices = useSelect((select) => select(noticesStore).getNotices());
    131 
    132     if (!notices?.length) return null;
    133 
    134     return <NoticeList notices={notices} onRemove={removeNotice} />;
    135 };
    136 
    137 /**
    138  * Main settings page component for ZenPress.
    139  *
    140  * @returns {JSX.Element} The settings page UI.
    141  */
    142 const SettingsPage = () => {
    143     const { snippets, setSnippets, saveSettings, isSaving } = useSettings();
    144 
    145     // Track which categories should remain open
    146     const [openCategories, setOpenCategories] = useState(new Set());
    147 
    148     /**
    149      * Handle toggle state change for a snippet.
    150      *
    151      * @param {string} snippetName - Name of the snippet to toggle.
    152      * @return {void}
    153      */
    154     const handleToggleChange = (snippetName) => {
    155         setSnippets((prev) => ({
    156             ...prev,
    157             [snippetName]: {
    158                 ...prev[snippetName],
    159                 'enable-snippet': !prev[snippetName]?.['enable-snippet'],
    160             },
    161         }));
    162     };
    163 
    164     /**
    165      * Enable all snippets at once.
    166      *
    167      * @return {void}
    168      */
    169     const enableAllSnippets = () => {
    170         setSnippets((prev) => {
    171             const updated = {};
    172             Object.keys(prev).forEach((name) => {
    173                 updated[name] = { ...prev[name], 'enable-snippet': true };
    174             });
    175             return updated;
    176         });
    177         // Open all categories
    178         setOpenCategories(new Set(sortedCategories));
    179     };
    180 
    181     /**
    182      * Reset all snippets (disable everything).
    183      *
    184      * @return {void}
    185      */
    186     const resetSettings = () => {
    187         setSnippets((prev) => {
    188             const updated = {};
    189             Object.keys(prev).forEach((name) => {
    190                 updated[name] = { ...prev[name], 'enable-snippet': false };
    191             });
    192             return updated;
    193         });
    194     };
    195 
    196     /**
    197      * Enable snippets by preset.
    198      *
    199      * @param {string} preset - Preset key to enable.
    200      * @return {void}
    201      */
    202     const enableByPreset = (preset) => {
    203         setSnippets((prev) => {
    204             const updated = {};
    205             Object.entries(prev).forEach(([name, data]) => {
    206                 const presets = Array.isArray(data?.preset) ? data.preset : [];
    207                 const isEnabled = presets.includes(preset);
    208                 updated[name] = {
    209                     ...data,
    210                     'enable-snippet': isEnabled,
    211                 };
    212             });
    213             return updated;
    214         });
    215         // Open all categories
    216         setOpenCategories(new Set(sortedCategories));
    217     };
    218 
    219     // Group snippets by category
    220     const groupedSnippets = {};
    221     Object.keys(snippets).forEach((snippetName) => {
    222         const snippet = snippets[snippetName];
    223         const category = snippet?.category || __('Uncategorized', 'zenpress');
    224         if (!groupedSnippets[category]) groupedSnippets[category] = [];
    225         groupedSnippets[category].push({ name: snippetName, data: snippet });
    226     });
    227 
    228     // Sort categories alphabetically (case-insensitive)
    229     const sortedCategories = Object.keys(groupedSnippets).sort((a, b) =>
    230         a.localeCompare(b, undefined, { sensitivity: 'base' })
    231     );
    232 
    233     return (
    234         <>
    235             <div className="zenpress-row">
    236                 <div className="zenpress-col">
    237                     <div className="zenpress-presets">
    238                         <div className="zenpress-presets-description">
    239                             <p>
    240                                 {__(
    241                                     '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.',
    242                                     'zenpress'
    243                                 )}
    244                             </p>
    245                             <h2>{__('Pick a preset', 'zenpress')}</h2>
    246                         </div>
    247 
    248                         <Button
    249                             variant="secondary"
    250                             onClick={() => enableByPreset('showcase-website')}
    251                             __next40pxDefaultSize
    252                         >
    253                             {__('Showcase website', 'zenpress')}
    254                         </Button>
    255                         <Button
    256                             variant="secondary"
    257                             onClick={() => enableByPreset('blog')}
    258                             __next40pxDefaultSize
    259                         >
    260                             {__('Blog', 'zenpress')}
    261                         </Button>
    262                         <Button
    263                             variant="secondary"
    264                             onClick={() => enableByPreset('ecommerce')}
    265                             __next40pxDefaultSize
    266                         >
    267                             {__('E-commerce', 'zenpress')}
    268                         </Button>
    269                         <div className="zenpress-presets-description">
    270                             <h2>{__('Or just enable what you need', 'zenpress')}</h2>
    271                         </div>
    272                         <div className="zenpress-actions-bulk">
    273                             <Button
    274                                 variant="secondary"
    275                                 onClick={enableAllSnippets}
    276                                 __next40pxDefaultSize
    277                             >
    278                                 {__('Enable all actions', 'zenpress')}
    279                             </Button>
    280 
    281                             <Button
    282                                 isDestructive="true"
    283                                 onClick={resetSettings}
    284                                 __next40pxDefaultSize
    285                             >
    286                                 {__('Disable all actions', 'zenpress')}
    287                             </Button>
    288                         </div>
    289                     </div>
    290                     {sortedCategories.map((category) => (
    291                         <Panel key={category}>
    292                             <PanelBody
    293                                 title={category}
    294                                 initialOpen={openCategories.has(category)}
    295                             >
    296                                 {groupedSnippets[category].map(({ name, data }) => (
    297                                     <PanelRow key={name}>
    298                                         <SnippetToggleControl
    299                                             label={data.title || name}
    300                                             value={data?.['enable-snippet'] || false}
    301                                             onChange={() => handleToggleChange(name)}
    302                                             help={data.description || ''}
    303                                         />
    304                                     </PanelRow>
    305                                 ))}
    306                             </PanelBody>
    307                         </Panel>
    308                     ))}
    309                     <div className="zenpress-actions">
    310                         <SaveButton onClick={saveSettings} isBusy={isSaving} />
    311                     </div>
    312                     <div className="zenpress-notices">
    313                         <Notices />
    314                     </div>
    315                 </div>
    316             </div>
    317         </>
    318     );
    319 };
     4import { SettingsPage } from './pages/SettingsPage';
    3205
    3216/**
    3227 * Render the ZenPress settings page once the DOM is ready.
    323  *
    324  * @return {void}
    3258 */
    3269domReady(() => {
    32710    const rootEl = document.getElementById('zenpress-settings');
    328     if (!rootEl) return; // Prevent fatal error if DOM element is missing
     11    if (!rootEl) return;
     12
    32913    const root = createRoot(rootEl);
    33014    root.render(<SettingsPage />);
  • zenpress/trunk/assets/src/index.scss

    r3352459 r3372200  
    147147    }
    148148}
    149 
    150 /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LnNjc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEiLCJmaWxlIjoiaW5kZXguc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIi56ZW5wcmVzcyB7XG5cblx0Ji1sb2FkaW5nIHtcblx0XHR3aWR0aDogMTAwJTtcblx0XHRtYXgtd2lkdGg6IDkwMHB4O1xuXHRcdG1hcmdpbjogMjBweCBhdXRvO1xuXHR9XG5cblx0Ji1kYXNoYm9hcmQtd3JhcCB7XG5cdFx0YTpub3QoLmNvbXBvbmVudHMtYnV0dG9uKSB7XG5cdFx0XHRjb2xvcjogdmFyKC0td3AtY29tcG9uZW50cy1jb2xvci1hY2NlbnQsIHZhcigtLXdwLWFkbWluLXRoZW1lLWNvbG9yLCAjMzg1OGU5KSk7XG5cblx0XHRcdCZbdGFyZ2V0PSdfYmxhbmsnXSB7XG5cdFx0XHRcdHBvc2l0aW9uOiByZWxhdGl2ZTtcblx0XHRcdFx0Z2FwOiA0cHg7XG5cblx0XHRcdFx0Jjo6YWZ0ZXIge1xuXHRcdFx0XHRcdGNvbnRlbnQ6ICcg4oaXJztcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC5jb21wb25lbnRzLWJ1dHRvbiB7XG5cdFx0XHRnYXA6IDRweDtcblx0XHR9XG5cblx0XHQuY29tcG9uZW50cy1wYW5lbCB7XG5cdFx0XHR3aWR0aDogMTAwJTtcblx0XHRcdG1hcmdpbjogMCBhdXRvIDIwcHggYXV0bztcblx0XHRcdG1heC13aWR0aDogMTAwJTtcblxuXHRcdFx0Jl9fYm9keSB7XG5cdFx0XHRcdCYtdGl0bGUge1xuXHRcdFx0XHRcdHRleHQtdHJhbnNmb3JtOiBjYXBpdGFsaXplO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ji10b2dnbGUge1xuXHRcdFx0XHRcdGJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjZDZlMmVkO1xuXHRcdFx0XHRcdHRleHQtdHJhbnNmb3JtOiBjYXBpdGFsaXplO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0LmNvbXBvbmVudHMtdG9nZ2xlLWNvbnRyb2wge1xuXHRcdFx0Jl9faGVscCB7XG5cdFx0XHRcdGZvbnQtc2l6ZTogMS4xZW07XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0LmNvbXBvbmVudHMtbm90aWNlLWxpc3Qge1xuXHRcdFx0d2lkdGg6IDEwMCU7XG5cdFx0XHRtYXJnaW4tYm90dG9tOiAyMHB4O1xuXHRcdH1cblx0fVxuXG5cdCYtcm93IHtcblx0XHRkaXNwbGF5OiBncmlkO1xuXHRcdGdyaWQtdGVtcGxhdGUtY29sdW1uczogMWZyO1xuXHRcdGdhcDogNDBweDtcblx0XHR3aWR0aDogMTAwJTtcblx0XHRtYXgtd2lkdGg6IDkyMHB4O1xuXHRcdG1hcmdpbjogMCBhdXRvO1xuXHR9XG5cblx0Ji1hY3Rpb25zIHtcblx0XHRkaXNwbGF5OiBmbGV4O1xuXHRcdGZsZXgtd3JhcDogd3JhcDtcblx0XHRnYXA6IDIwcHg7XG5cdFx0anVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xuXHRcdGFsaWduLWl0ZW1zOiBjZW50ZXI7XG5cdFx0bWFyZ2luLWJvdHRvbTogMjBweDtcblxuXHRcdCYtYnVsayB7XG5cdFx0XHRkaXNwbGF5OiBmbGV4O1xuXHRcdFx0ZmxleC13cmFwOiB3cmFwO1xuXHRcdFx0Z2FwOiAxMHB4O1xuXHRcdFx0anVzdGlmeS1jb250ZW50OiBmbGV4LXN0YXJ0O1xuXHRcdFx0YWxpZ24taXRlbXM6IGNlbnRlcjtcblx0XHR9XG5cdH1cblxuXG5cdCYtcHJlc2V0cyB7XG5cdFx0ZGlzcGxheTogZmxleDtcblx0XHRmbGV4LXdyYXA6IHdyYXA7XG5cdFx0Z2FwOiAxMHB4O1xuXHRcdGp1c3RpZnktY29udGVudDogZmxleC1zdGFydDtcblx0XHRhbGlnbi1pdGVtczogY2VudGVyO1xuXHRcdG1hcmdpbi1ib3R0b206IDIwcHg7XG5cblx0XHQmLWRlc2NyaXB0aW9uIHtcblx0XHRcdGZsZXg6IDEwMCU7XG5cdFx0XHR3aWR0aDogMTAwJTtcblx0XHRcdG1heC13aWR0aDogMTAwJTtcblx0XHR9XG5cdH1cblxuXHQmLWhlYWRlciB7XG5cdFx0YWxpZ24taXRlbXM6IGNlbnRlcjtcblx0XHRkaXNwbGF5OiBmbGV4O1xuXHRcdGZsZXgtd3JhcDogd3JhcDtcblx0XHRqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG5cdFx0b3ZlcmZsb3cteDogYXV0bztcblx0XHRwYWRkaW5nOiAxNnB4O1xuXHRcdG1hcmdpbjogMCAwIDIwcHggMDtcblx0XHRnYXA6IDQwcHg7XG5cdFx0YmFja2dyb3VuZDogI2ZmZjtcblx0XHRib3JkZXI6IDFweCBzb2xpZCAjZTBlMGUwO1xuXG5cdFx0Ji1uYXZpZ2F0aW9uIHtcblx0XHRcdGRpc3BsYXk6IGZsZXg7XG5cdFx0XHRmbGV4LXdyYXA6IHdyYXA7XG5cdFx0XHRnYXA6IDIwcHg7XG5cdFx0XHRqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG5cdFx0XHRhbGlnbi1pdGVtczogY2VudGVyO1xuXHRcdH1cblxuXHRcdGgxLFxuXHRcdHAge1xuXHRcdFx0bWFyZ2luOiAwO1xuXHRcdFx0cGFkZGluZzogMDtcblx0XHR9XG5cdH1cblxuXHQmLWZvb3RlciB7XG5cdFx0YWxpZ24taXRlbXM6IGNlbnRlcjtcblx0XHRkaXNwbGF5OiBmbGV4O1xuXHRcdGZsZXgtd3JhcDogd3JhcDtcblx0XHRqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG5cdFx0b3ZlcmZsb3cteDogYXV0bztcblx0XHRwYWRkaW5nOiAxNnB4O1xuXHRcdG1hcmdpbjogMCAwIDIwcHggMDtcblx0XHRnYXA6IDQwcHg7XG5cdFx0Ym9yZGVyLXRvcDogMXB4IHNvbGlkICNlMGUwZTA7XG5cdFx0cGFkZGluZy10b3A6IDMycHg7XG5cblx0XHQmLW5hdmlnYXRpb24ge1xuXHRcdFx0ZGlzcGxheTogZmxleDtcblx0XHRcdGZsZXgtd3JhcDogd3JhcDtcblx0XHRcdGdhcDogMjBweDtcblx0XHRcdGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2Vlbjtcblx0XHRcdGFsaWduLWl0ZW1zOiBjZW50ZXI7XG5cdFx0fVxuXG5cdFx0cCB7XG5cdFx0XHRtYXJnaW46IDA7XG5cdFx0XHRwYWRkaW5nOiAwO1xuXHRcdH1cblx0fVxufVxuIl19 */
  • zenpress/trunk/languages/zenpress.pot

    r3352459 r3372200  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: ZenPress 2.0\n"
     5"Project-Id-Version: ZenPress — Cleaner, Lighter, Faster WP 2.0.3\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/zenpress\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2025-08-29T07:34:31+00:00\n"
     12"POT-Creation-Date: 2025-10-02T20:30:15+00:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.12.0\n"
     
    1717#. Plugin Name of the plugin
    1818#: zenpress.php
    19 #: zenpress.php:150
    20 #: zenpress.php:171
    21 msgid "ZenPress"
     19msgid "ZenPress — Cleaner, Lighter, Faster WP"
    2220msgstr ""
    2321
     
    4240msgstr ""
    4341
    44 #: inc/meta/block-user-enumeration.meta.php:13
     42#: inc/admin/links.php:19
     43msgid "Go to ZenPress settings page"
     44msgstr ""
     45
     46#: inc/admin/links.php:20
     47msgid "Settings"
     48msgstr ""
     49
     50#: inc/admin/links.php:40
     51#: inc/admin/menu.php:42
     52msgid "View ZenPress changelog on WordPress.org (opens in a new tab)"
     53msgstr ""
     54
     55#: inc/admin/links.php:41
     56msgid "Changelog"
     57msgstr ""
     58
     59#: inc/admin/links.php:46
     60msgid "Read ZenPress documentation (opens in a new tab)"
     61msgstr ""
     62
     63#: inc/admin/links.php:47
     64msgid "Docs"
     65msgstr ""
     66
     67#: inc/admin/links.php:52
     68msgid "Support ZenPress by buying a coffee (opens in a new tab)"
     69msgstr ""
     70
     71#: inc/admin/links.php:53
     72msgid "Support ☕"
     73msgstr ""
     74
     75#: inc/admin/menu.php:15
     76msgid "ZenPress options"
     77msgstr ""
     78
     79#: inc/admin/menu.php:16
     80#: inc/admin/menu.php:35
     81msgid "ZenPress"
     82msgstr ""
     83
     84#: inc/admin/menu.php:38
     85msgid "Version"
     86msgstr ""
     87
     88#: inc/admin/menu.php:43
     89msgid "What's new ?"
     90msgstr ""
     91
     92#: inc/admin/menu.php:52
     93msgid "Read the ZenPress documentation (opens in a new tab)"
     94msgstr ""
     95
     96#: inc/admin/menu.php:53
     97msgid "Documentation"
     98msgstr ""
     99
     100#: inc/admin/menu.php:58
     101msgid "Leave a review for ZenPress on WordPress.org (opens in a new tab)"
     102msgstr ""
     103
     104#: inc/admin/menu.php:59
     105msgid "Leave a review (helps a lot)"
     106msgstr ""
     107
     108#: inc/admin/menu.php:65
     109msgid "Support development: Buy me a coffee (opens in a new tab)"
     110msgstr ""
     111
     112#: inc/admin/menu.php:66
     113msgid "Buy me a coffee"
     114msgstr ""
     115
     116#: inc/admin/menu.php:74
     117msgid "Loading your ZenPress settings…"
     118msgstr ""
     119
     120#: inc/admin/menu.php:82
     121msgid "Made "
     122msgstr ""
     123
     124#: inc/admin/menu.php:84
     125msgid " by Quentin Le Duff - Your WordPress Partner"
     126msgstr ""
     127
     128#: inc/admin/menu.php:91
     129msgid "Visite the developper website"
     130msgstr ""
     131
     132#: inc/admin/menu.php:92
     133msgid "My place"
     134msgstr ""
     135
     136#: inc/admin/menu.php:97
     137msgid "Review the code on Github"
     138msgstr ""
     139
     140#: inc/admin/menu.php:98
     141msgid "ZenPress code repository"
     142msgstr ""
     143
     144#: inc/snippets/functions/block-user-enumeration.php:13
     145#: inc/snippets/functions/block-user-enumeration.php:21
     146msgid "Access denied."
     147msgstr ""
     148
     149#: inc/snippets/functions/protect-wp-login.php:9
     150msgid "Login error."
     151msgstr ""
     152
     153#: inc/snippets/functions/protect-wp-login.php:35
     154#: inc/snippets/functions/protect-wp-login.php:48
     155msgid "Too many failed login attempts. Try again later."
     156msgstr ""
     157
     158#: inc/snippets/meta/block-user-enumeration.meta.php:13
    45159msgid "Block user enumeration"
    46160msgstr ""
    47161
    48 #: inc/meta/block-user-enumeration.meta.php:14
     162#: inc/snippets/meta/block-user-enumeration.meta.php:14
    49163msgid "Prevents attackers from guessing WordPress usernames by blocking requests with the `author` parameter in query strings or permalinks. Reduces exposure to brute-force and user-targeted attacks."
    50164msgstr ""
    51165
    52 #: inc/meta/block-user-enumeration.meta.php:18
    53 #: inc/meta/disable-author-archives.meta.php:18
    54 #: inc/meta/disable-pingback-trackback.meta.php:15
    55 #: inc/meta/disable-xmlrpc-rsdlink.meta.php:15
    56 #: inc/meta/hide-wordpress-version.meta.php:15
    57 #: inc/meta/protect-wp-login.meta.php:15
     166#: inc/snippets/meta/block-user-enumeration.meta.php:18
     167#: inc/snippets/meta/disable-application-passwords.meta.php:18
     168#: inc/snippets/meta/disable-author-archives.meta.php:18
     169#: inc/snippets/meta/disable-pingback-trackback.meta.php:15
     170#: inc/snippets/meta/disable-xmlrpc-rsdlink.meta.php:15
     171#: inc/snippets/meta/hide-wordpress-version.meta.php:15
     172#: inc/snippets/meta/protect-wp-login.meta.php:15
    58173msgid "Security 🔒️"
    59174msgstr ""
    60175
    61 #: inc/meta/clean-admin-bar.meta.php:13
     176#: inc/snippets/meta/clean-admin-bar.meta.php:13
    62177msgid "Clean up the WordPress admin bar"
    63178msgstr ""
    64179
    65 #: inc/meta/clean-admin-bar.meta.php:14
     180#: inc/snippets/meta/clean-admin-bar.meta.php:14
    66181msgid "Removes unnecessary items from the admin bar in both backend and frontend. Reduces clutter and simplifies the interface."
    67182msgstr ""
    68183
    69 #: inc/meta/clean-admin-bar.meta.php:18
    70 #: inc/meta/clean-dashboard-items.meta.php:18
    71 #: inc/meta/disable-login-language-selector.meta.php:15
     184#: inc/snippets/meta/clean-admin-bar.meta.php:18
     185#: inc/snippets/meta/clean-dashboard-items.meta.php:18
     186#: inc/snippets/meta/disable-login-language-selector.meta.php:15
    72187msgid "User interface 💻️"
    73188msgstr ""
    74189
    75 #: inc/meta/clean-dashboard-items.meta.php:13
     190#: inc/snippets/meta/clean-dashboard-items.meta.php:13
    76191msgid "Clean up the WordPress Dashboard"
    77192msgstr ""
    78193
    79 #: inc/meta/clean-dashboard-items.meta.php:14
     194#: inc/snippets/meta/clean-dashboard-items.meta.php:14
    80195msgid "Removes unnecessary widgets and ads widgets from the dashboard. Declutters the admin area and improves usability."
    81196msgstr ""
    82197
    83 #: inc/meta/disable-adjacent-posts.meta.php:13
     198#: inc/snippets/meta/disable-adjacent-posts.meta.php:13
    84199msgid "Disable adjacent posts link tags"
    85200msgstr ""
    86201
    87 #: inc/meta/disable-adjacent-posts.meta.php:14
     202#: inc/snippets/meta/disable-adjacent-posts.meta.php:14
    88203msgid "Removes rel=\"prev\" and rel=\"next\" tags from wp_head. Reduces unnecessary HTML output and slightly improves performance."
    89204msgstr ""
    90205
    91 #: inc/meta/disable-adjacent-posts.meta.php:18
    92 #: inc/meta/disable-dashicons.meta.php:18
    93 #: inc/meta/disable-dns-prefetch.meta.php:18
    94 #: inc/meta/disable-emoji-scripts.meta.php:18
    95 #: inc/meta/disable-jquery-migrate.meta.php:18
    96 #: inc/meta/disable-oembed.meta.php:15
    97 #: inc/meta/disable-pdf-thumbnails.meta.php:15
    98 #: inc/meta/disable-rss.meta.php:15
    99 #: inc/meta/disable-shortlink.meta.php:15
    100 #: inc/meta/disable-wlw-manifest.meta.php:15
    101 #: inc/meta/remove-gutenberg-unwanted-block-patterns.meta.php:15
    102 #: inc/meta/remove-rest-api-link.meta.php:15
    103 #: inc/meta/separate-gutenberg-core-block-styles.meta.php:15
     206#: inc/snippets/meta/disable-adjacent-posts.meta.php:18
     207#: inc/snippets/meta/disable-dashicons.meta.php:18
     208#: inc/snippets/meta/disable-dns-prefetch.meta.php:18
     209#: inc/snippets/meta/disable-emoji-scripts.meta.php:18
     210#: inc/snippets/meta/disable-jquery-migrate.meta.php:18
     211#: inc/snippets/meta/disable-oembed.meta.php:15
     212#: inc/snippets/meta/disable-pdf-thumbnails.meta.php:15
     213#: inc/snippets/meta/disable-rss.meta.php:15
     214#: inc/snippets/meta/disable-shortlink.meta.php:15
     215#: inc/snippets/meta/disable-wlw-manifest.meta.php:15
     216#: inc/snippets/meta/remove-gutenberg-unwanted-block-patterns.meta.php:15
     217#: inc/snippets/meta/remove-rest-api-link.meta.php:15
     218#: inc/snippets/meta/separate-gutenberg-core-block-styles.meta.php:15
    104219msgid "Performance 🚀"
    105220msgstr ""
    106221
    107 #: inc/meta/disable-author-archives.meta.php:13
     222#: inc/snippets/meta/disable-application-passwords.meta.php:13
     223msgid "Disable application passwords"
     224msgstr ""
     225
     226#: inc/snippets/meta/disable-application-passwords.meta.php:14
     227msgid "Disables WordPress application passwords for all users, improving security. Only disable if API access is not needed."
     228msgstr ""
     229
     230#: inc/snippets/meta/disable-author-archives.meta.php:13
    108231msgid "Disable author archives"
    109232msgstr ""
    110233
    111 #: inc/meta/disable-author-archives.meta.php:14
     234#: inc/snippets/meta/disable-author-archives.meta.php:14
    112235msgid "Forces author archive pages to return a 404 error. Prevents user enumeration and hides unnecessary author pages."
    113236msgstr ""
    114237
    115 #: inc/meta/disable-dashicons.meta.php:13
     238#: inc/snippets/meta/disable-dashicons.meta.php:13
    116239msgid "Disable dashicons"
    117240msgstr ""
    118241
    119 #: inc/meta/disable-dashicons.meta.php:14
     242#: inc/snippets/meta/disable-dashicons.meta.php:14
    120243msgid "Prevents WordPress from loading the Dashicons CSS for visitors who are not logged in. Improves frontend performance by reducing unnecessary styles."
    121244msgstr ""
    122245
    123 #: inc/meta/disable-dns-prefetch.meta.php:13
     246#: inc/snippets/meta/disable-dns-prefetch.meta.php:13
    124247msgid "Disable DNS prefetch"
    125248msgstr ""
    126249
    127 #: inc/meta/disable-dns-prefetch.meta.php:14
     250#: inc/snippets/meta/disable-dns-prefetch.meta.php:14
    128251msgid "Removes DNS prefetch resource hints from wp_head avoids unnecessary DNS lookups and slightly improve performance on some sites."
    129252msgstr ""
    130253
    131 #: inc/meta/disable-emoji-scripts.meta.php:13
     254#: inc/snippets/meta/disable-emoji-scripts.meta.php:13
    132255msgid "Disable WordPress emoji scripts and styles"
    133256msgstr ""
    134257
    135 #: inc/meta/disable-emoji-scripts.meta.php:14
     258#: inc/snippets/meta/disable-emoji-scripts.meta.php:14
    136259msgid "Removes emoji scripts, styles, and filters from frontend, backend, feeds, emails, and TinyMCE. Reduces unnecessary assets and improves performance."
    137260msgstr ""
    138261
    139 #: inc/meta/disable-jquery-migrate.meta.php:13
     262#: inc/snippets/meta/disable-jquery-migrate.meta.php:13
    140263msgid "Disable jQuery migrate"
    141264msgstr ""
    142265
    143 #: inc/meta/disable-jquery-migrate.meta.php:14
     266#: inc/snippets/meta/disable-jquery-migrate.meta.php:14
    144267msgid "Removes jQuery Migrate from loading on the frontend while keeping it enabled in the admin. Improves frontend performance and reduces legacy overhead."
    145268msgstr ""
    146269
    147 #: inc/meta/disable-login-language-selector.meta.php:13
     270#: inc/snippets/meta/disable-login-language-selector.meta.php:13
    148271msgid "Disable the login language selector"
    149272msgstr ""
    150273
    151 #: inc/meta/disable-login-language-selector.meta.php:14
     274#: inc/snippets/meta/disable-login-language-selector.meta.php:14
    152275msgid "Removes the language dropdown from the WordPress login page. Simplifies login screen and reduces distractions."
    153276msgstr ""
    154277
    155 #: inc/meta/disable-oembed.meta.php:13
     278#: inc/snippets/meta/disable-oembed.meta.php:13
    156279msgid "Disable oEmbed"
    157280msgstr ""
    158281
    159 #: inc/meta/disable-oembed.meta.php:14
     282#: inc/snippets/meta/disable-oembed.meta.php:14
    160283msgid "Removes WordPress oEmbed features such as auto-discovery, REST API routes, TinyMCE integration, and the wp-embed script. Reduces API calls, improves performance, and limits unnecessary external requests."
    161284msgstr ""
    162285
    163 #: inc/meta/disable-pdf-thumbnails.meta.php:13
     286#: inc/snippets/meta/disable-pdf-thumbnails.meta.php:13
    164287msgid "Disable PDF thumbnails"
    165288msgstr ""
    166289
    167 #: inc/meta/disable-pdf-thumbnails.meta.php:14
     290#: inc/snippets/meta/disable-pdf-thumbnails.meta.php:14
    168291msgid "Prevents WordPress from generating thumbnails for uploaded PDF files by removing fallback image sizes. saves storage space and improves performance by avoiding unnecessary image generation."
    169292msgstr ""
    170293
    171 #: inc/meta/disable-pingback-trackback.meta.php:13
     294#: inc/snippets/meta/disable-pingback-trackback.meta.php:13
    172295msgid "Disable pingback and trackback"
    173296msgstr ""
    174297
    175 #: inc/meta/disable-pingback-trackback.meta.php:14
     298#: inc/snippets/meta/disable-pingback-trackback.meta.php:14
    176299msgid "Removes the X-Pingback header, disables pingbacks and trackbacks on new posts, and prevents self-pingbacks. reduces spam, blocks potential DDoS vectors, and slightly improves performance by avoiding useless requests."
    177300msgstr ""
    178301
    179 #: inc/meta/disable-rss.meta.php:13
     302#: inc/snippets/meta/disable-rss.meta.php:13
    180303msgid "Disable all WordPress feeds (RDF, RSS, RSS2, Atom, and comments)"
    181304msgstr ""
    182305
    183 #: inc/meta/disable-rss.meta.php:14
     306#: inc/snippets/meta/disable-rss.meta.php:14
    184307msgid "Prevents access to all default feeds (RDF, RSS, RSS2, Atom, and comments). Also removes feed links from head, and redirects feed requests to the homepage. Reduces unnecessary requests and improves SEO consistency."
    185308msgstr ""
    186309
    187 #: inc/meta/disable-shortlink.meta.php:13
     310#: inc/snippets/meta/disable-shortlink.meta.php:13
    188311msgid "Disable WordPress shortlink"
    189312msgstr ""
    190313
    191 #: inc/meta/disable-shortlink.meta.php:14
     314#: inc/snippets/meta/disable-shortlink.meta.php:14
    192315msgid "Removes shortlink functionality from both the HTML head and HTTP headers. Reduces unnecessary output, improves performance and SEO clarity."
    193316msgstr ""
    194317
    195 #: inc/meta/disable-wlw-manifest.meta.php:13
     318#: inc/snippets/meta/disable-wlw-manifest.meta.php:13
    196319msgid "Disable WLW link"
    197320msgstr ""
    198321
    199 #: inc/meta/disable-wlw-manifest.meta.php:14
     322#: inc/snippets/meta/disable-wlw-manifest.meta.php:14
    200323msgid "Removes the WLW manifest link from the head, which was only used by the deprecated Windows Live Writer app. Reduces unnecessary metadata and improves performance."
    201324msgstr ""
    202325
    203 #: inc/meta/disable-woocommerce-cart-fragments.meta.php:13
     326#: inc/snippets/meta/disable-woocommerce-cart-fragments.meta.php:13
    204327msgid "Disable WooCommerce cart fragments script"
    205328msgstr ""
    206329
    207 #: inc/meta/disable-woocommerce-cart-fragments.meta.php:14
     330#: inc/snippets/meta/disable-woocommerce-cart-fragments.meta.php:14
    208331msgid "Removes the WooCommerce cart fragments JavaScript (wc-cart-fragments), which is responsible for dynamically updating the cart contents without a page reload. Disabling this can improve performance on stores that do not require live cart updates."
    209332msgstr ""
    210333
    211 #: inc/meta/disable-woocommerce-cart-fragments.meta.php:15
    212 #: inc/meta/disable-woocommerce-scripts-styles.meta.php:15
    213 #: inc/meta/disable-woocommerce-stripe-scripts.meta.php:15
    214 #: inc/meta/disable-woocommerce-widgets.meta.php:15
    215 #: inc/meta/hide-woocommerce-version.meta.php:15
    216 #: inc/meta/remove-woocommerce-patterns.meta.php:15
     334#: inc/snippets/meta/disable-woocommerce-cart-fragments.meta.php:15
     335#: inc/snippets/meta/disable-woocommerce-scripts-styles.meta.php:15
     336#: inc/snippets/meta/disable-woocommerce-stripe-scripts.meta.php:15
     337#: inc/snippets/meta/disable-woocommerce-widgets.meta.php:15
     338#: inc/snippets/meta/hide-woocommerce-version.meta.php:15
     339#: inc/snippets/meta/remove-woocommerce-patterns.meta.php:15
    217340msgid "WooCommerce 🛒"
    218341msgstr ""
    219342
    220 #: inc/meta/disable-woocommerce-scripts-styles.meta.php:13
     343#: inc/snippets/meta/disable-woocommerce-scripts-styles.meta.php:13
    221344msgid "Disable WooCommerce scripts and styles on non-WooCommerce pages"
    222345msgstr ""
    223346
    224 #: inc/meta/disable-woocommerce-scripts-styles.meta.php:14
     347#: inc/snippets/meta/disable-woocommerce-scripts-styles.meta.php:14
    225348msgid "Dequeues WooCommerce assets on pages where WooCommerce functionality is not required, such as homepage, blog posts, or custom pages. Helps improve performance by preventing unnecessary asset loading."
    226349msgstr ""
    227350
    228 #: inc/meta/disable-woocommerce-stripe-scripts.meta.php:13
     351#: inc/snippets/meta/disable-woocommerce-stripe-scripts.meta.php:13
    229352msgid "Disable unnecessary Stripe scripts on WooCommerce pages"
    230353msgstr ""
    231354
    232 #: inc/meta/disable-woocommerce-stripe-scripts.meta.php:14
     355#: inc/snippets/meta/disable-woocommerce-stripe-scripts.meta.php:14
    233356msgid "Prevents loading of Stripe-related scripts on the product and cart pages when the \"Payment Request Button Support\" (PRBS) is disabled. Helps improve performance by avoiding unnecessary JavaScript loading."
    234357msgstr ""
    235358
    236 #: inc/meta/disable-woocommerce-widgets.meta.php:13
     359#: inc/snippets/meta/disable-woocommerce-widgets.meta.php:13
    237360msgid "Disable WooCommerce widgets"
    238361msgstr ""
    239362
    240 #: inc/meta/disable-woocommerce-widgets.meta.php:14
     363#: inc/snippets/meta/disable-woocommerce-widgets.meta.php:14
    241364msgid "Unregisters default WooCommerce widgets to reduce bloat in the widget screen and improve performance by removing unused features."
    242365msgstr ""
    243366
    244 #: inc/meta/disable-xmlrpc-rsdlink.meta.php:13
     367#: inc/snippets/meta/disable-xmlrpc-rsdlink.meta.php:13
    245368msgid "Disable XML-RPC and remove RSD link"
    246369msgstr ""
    247370
    248 #: inc/meta/disable-xmlrpc-rsdlink.meta.php:14
     371#: inc/snippets/meta/disable-xmlrpc-rsdlink.meta.php:14
    249372msgid "Disables XML-RPC (often targeted by brute force or DDoS attacks) and removes the RSD link from the HTML head to reduce exposure."
    250373msgstr ""
    251374
    252 #: inc/meta/hide-woocommerce-version.meta.php:13
     375#: inc/snippets/meta/hide-woocommerce-version.meta.php:13
    253376msgid "Hide WooCommerce version"
    254377msgstr ""
    255378
    256 #: inc/meta/hide-woocommerce-version.meta.php:14
     379#: inc/snippets/meta/hide-woocommerce-version.meta.php:14
    257380msgid "Removes WooCommerce version info from HTTP headers and asset URLs. Reduces exposure of version number and makes it harder for attackers to target specific WooCommerce versions."
    258381msgstr ""
    259382
    260 #: inc/meta/hide-wordpress-version.meta.php:13
     383#: inc/snippets/meta/hide-wordpress-version.meta.php:13
    261384msgid "Hide WordPress version"
    262385msgstr ""
    263386
    264 #: inc/meta/hide-wordpress-version.meta.php:14
     387#: inc/snippets/meta/hide-wordpress-version.meta.php:14
    265388msgid "Removes WordPress version info from the head, generator, and asset URLs. Reduces exposure of version number and makes it harder for attackers to target specific WordPress versions."
    266389msgstr ""
    267390
    268 #: inc/meta/protect-wp-login.meta.php:13
     391#: inc/snippets/meta/protect-wp-login.meta.php:13
    269392msgid "Protect the wp-login form from brute force attacks"
    270393msgstr ""
    271394
    272 #: inc/meta/protect-wp-login.meta.php:14
     395#: inc/snippets/meta/protect-wp-login.meta.php:14
    273396msgid "Removes detailed login error messages and limits failed login attempts per IP address. Blocks further attempts for a set duration after too many failures. Improves security by mitigating brute force attacks."
    274397msgstr ""
    275398
    276 #: inc/meta/remove-gutenberg-unwanted-block-patterns.meta.php:13
     399#: inc/snippets/meta/remove-gutenberg-unwanted-block-patterns.meta.php:13
    277400msgid "Remove WordPress default remote block patterns"
    278401msgstr ""
    279402
    280 #: inc/meta/remove-gutenberg-unwanted-block-patterns.meta.php:14
     403#: inc/snippets/meta/remove-gutenberg-unwanted-block-patterns.meta.php:14
    281404msgid "Prevents WordPress from loading remote block patterns and removes the built-in core block patterns. Reduces editor clutter and improves performance by avoiding unnecessary data loading."
    282405msgstr ""
    283406
    284 #: inc/meta/remove-rest-api-link.meta.php:13
     407#: inc/snippets/meta/remove-rest-api-link.meta.php:13
    285408msgid "Remove REST API links"
    286409msgstr ""
    287410
    288 #: inc/meta/remove-rest-api-link.meta.php:14
     411#: inc/snippets/meta/remove-rest-api-link.meta.php:14
    289412msgid "Prevents WordPress from adding REST API discovery links to the head section of the site. reduces unnecessary HTML output and slightly improves performance while keeping REST API functionality available."
    290413msgstr ""
    291414
    292 #: inc/meta/remove-woocommerce-patterns.meta.php:13
     415#: inc/snippets/meta/remove-woocommerce-patterns.meta.php:13
    293416msgid "Remove WooCommerce default remote block patterns"
    294417msgstr ""
    295418
    296 #: inc/meta/remove-woocommerce-patterns.meta.php:14
     419#: inc/snippets/meta/remove-woocommerce-patterns.meta.php:14
    297420msgid "Removes all WooCommerce remote block patterns to avoid unnecessary pattern registration in the editor."
    298421msgstr ""
    299422
    300 #: inc/meta/separate-gutenberg-core-block-styles.meta.php:13
     423#: inc/snippets/meta/separate-gutenberg-core-block-styles.meta.php:13
    301424msgid "Separate loading of core block styles"
    302425msgstr ""
    303426
    304 #: inc/meta/separate-gutenberg-core-block-styles.meta.php:14
     427#: inc/snippets/meta/separate-gutenberg-core-block-styles.meta.php:14
    305428msgid "Forces WordPress to load core block styles separately, improving performance by only loading the styles required for the blocks used on a page."
    306429msgstr ""
    307430
    308 #: inc/snippets/block-user-enumeration.php:13
    309 #: inc/snippets/block-user-enumeration.php:21
    310 msgid "Access denied."
    311 msgstr ""
    312 
    313 #: inc/snippets/protect-wp-login.php:9
    314 msgid "Login error."
    315 msgstr ""
    316 
    317 #: inc/snippets/protect-wp-login.php:36
    318 #: inc/snippets/protect-wp-login.php:49
    319 msgid "Too many failed login attempts. Try again later."
    320 msgstr ""
    321 
    322 #: zenpress.php:60
    323 msgid "Go to ZenPress settings page"
    324 msgstr ""
    325 
    326 #: zenpress.php:61
    327 msgid "Settings"
    328 msgstr ""
    329 
    330 #: zenpress.php:82
    331 #: zenpress.php:179
    332 msgid "View ZenPress changelog on WordPress.org (opens in a new tab)"
    333 msgstr ""
    334 
    335 #: zenpress.php:82
    336 msgid "Changelog"
    337 msgstr ""
    338 
    339 #: zenpress.php:83
    340 msgid "Read ZenPress documentation (opens in a new tab)"
    341 msgstr ""
    342 
    343 #: zenpress.php:83
    344 msgid "Docs"
    345 msgstr ""
    346 
    347 #: zenpress.php:84
    348 msgid "Support ZenPress by buying a coffee (opens in a new tab)"
    349 msgstr ""
    350 
    351 #: zenpress.php:84
    352 msgid "Support ☕"
    353 msgstr ""
    354 
    355 #: zenpress.php:149
    356 msgid "ZenPress options"
    357 msgstr ""
    358 
    359 #: zenpress.php:175
    360 msgid "Version"
    361 msgstr ""
    362 
    363 #: zenpress.php:180
    364 msgid "What's new ?"
    365 msgstr ""
    366 
    367 #: zenpress.php:189
    368 msgid "Read the ZenPress documentation (opens in a new tab)"
    369 msgstr ""
    370 
    371 #: zenpress.php:190
    372 msgid "Documentation"
    373 msgstr ""
    374 
    375 #: zenpress.php:196
    376 msgid "Leave a review for ZenPress on WordPress.org (opens in a new tab)"
    377 msgstr ""
    378 
    379 #: zenpress.php:197
    380 msgid "Leave a review (helps a lot)"
    381 msgstr ""
    382 
    383 #: zenpress.php:204
    384 msgid "Support development: Buy me a coffee (opens in a new tab)"
    385 msgstr ""
    386 
    387 #: zenpress.php:205
    388 msgid "Buy me a coffee"
    389 msgstr ""
    390 
    391 #: zenpress.php:214
    392 msgid "Loading your ZenPress settings…"
    393 msgstr ""
    394 
    395 #: zenpress.php:223
    396 msgid "Made "
    397 msgstr ""
    398 
    399 #: zenpress.php:225
    400 msgid " by Quentin Le Duff - Your WordPress Partner"
    401 msgstr ""
    402 
    403 #: zenpress.php:232
    404 msgid "Visite the developper website"
    405 msgstr ""
    406 
    407 #: zenpress.php:233
    408 msgid "My place"
    409 msgstr ""
    410 
    411 #: zenpress.php:238
    412 msgid "Review the code on Github"
    413 msgstr ""
    414 
    415 #: zenpress.php:239
    416 msgid "ZenPress code repository"
    417 msgstr ""
    418 
    419 #: assets/build/index.js:1
    420 #: assets/src/index.js:119
     431#: assets/build/index.js:1
     432#: assets/src/components/SaveButton.js:16
    421433msgid "Save settings"
    422434msgstr ""
    423435
    424436#: assets/build/index.js:1
    425 #: assets/src/index.js:51
     437#: assets/src/hooks/useSettings.js:41
    426438msgid "Failed to load settings."
    427439msgstr ""
    428440
    429441#: assets/build/index.js:1
    430 #: assets/src/index.js:73
     442#: assets/src/hooks/useSettings.js:56
    431443msgid "Settings saved."
    432444msgstr ""
    433445
    434446#: assets/build/index.js:1
    435 #: assets/src/index.js:76
     447#: assets/src/hooks/useSettings.js:58
    436448msgid "Failed to save settings."
    437449msgstr ""
    438450
    439451#: assets/build/index.js:1
    440 #: assets/src/index.js:178
    441 #: assets/src/index.js:217
    442 #: assets/src/index.js:229
     452#: assets/src/pages/SettingsPage.js:66
    443453msgid "Uncategorized"
    444454msgstr ""
    445455
    446456#: assets/build/index.js:1
    447 #: assets/src/index.js:246
     457#: assets/src/pages/SettingsPage.js:83
    448458msgid "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."
    449459msgstr ""
    450460
    451461#: assets/build/index.js:1
    452 #: assets/src/index.js:251
     462#: assets/src/pages/SettingsPage.js:88
    453463msgid "Pick a preset"
    454464msgstr ""
    455465
    456466#: assets/build/index.js:1
    457 #: assets/src/index.js:259
     467#: assets/src/pages/SettingsPage.js:96
    458468msgid "Showcase website"
    459469msgstr ""
    460470
    461471#: assets/build/index.js:1
    462 #: assets/src/index.js:266
     472#: assets/src/pages/SettingsPage.js:99
    463473msgid "Blog"
    464474msgstr ""
    465475
    466476#: assets/build/index.js:1
    467 #: assets/src/index.js:273
     477#: assets/src/pages/SettingsPage.js:102
    468478msgid "E-commerce"
    469479msgstr ""
    470480
    471481#: assets/build/index.js:1
    472 #: assets/src/index.js:276
     482#: assets/src/pages/SettingsPage.js:106
    473483msgid "Or just enable what you need"
    474484msgstr ""
    475485
    476486#: assets/build/index.js:1
    477 #: assets/src/index.js:284
     487#: assets/src/pages/SettingsPage.js:111
    478488msgid "Enable all actions"
    479489msgstr ""
    480490
    481491#: assets/build/index.js:1
    482 #: assets/src/index.js:292
     492#: assets/src/pages/SettingsPage.js:115
    483493msgid "Disable all actions"
    484494msgstr ""
  • zenpress/trunk/readme.txt

    r3355428 r3372200  
    55Requires at least: 6.0
    66Tested up to: 6.8
    7 Stable tag: 2.0.2
     7Stable tag: 2.0.3
    88Requires PHP: 7.4
    99License: GPLv2 or later
     
    5555
    5656* Block user enumeration
     57* Disable application passwords
    5758* Disable author archives
    5859* Disable pingback and trackback
     
    8182
    8283= Security =
    83 * Disable Application Passwords
    8484* Manage Heartbeat API (frontend + backend + admin whitelist)
    8585* Disable REST API
     
    8989* Disable autosave
    9090* Disable post revision
    91 * Disable native lazy loading
    9291* Disable Password Strength Meter
    9392* Disable WordPress default lazy loading
     
    159158== Changelog ==
    160159
     160= 2.0.3 =
     161- Global: Codebase and snippets optimization
     162- Global: Fix typo
     163- New actionable function: Disable application passwords
     164
    161165= 2.0.2 =
    162166
     
    178182= 1.0.9.1 =
    179183
    180 - Compatibility : Plugin tested up to PHP 8.4
     184- Compatibility: Plugin tested up to PHP 8.4
    181185
    182186= 1.0.9 =
    183187
    184 - Compatibility : Plugin tested up to PHP 8.4
    185 - UI : Disable login language selector
     188- Compatibility: Plugin tested up to PHP 8.4
     189- New actionable function: Disable login language selector
    186190- Fix constant naming in readme.txt
    187191
    188192= 1.0.8 =
    189193
    190 - UI : Remove smash baloon ads meta box
     194- UI: Remove smash baloon ads meta box
    191195- Global : Files naming and call for scalability
    192196
     
    194198
    195199- ZenPress tested for WordPress 6.8.1
    196 - UI : Remove site health meta box
    197 - UI : Remove WooCommerce admin dashboard setup metabox
     200- UI: Remove site health meta box
     201- UI: Remove WooCommerce admin dashboard setup metabox
    198202
    199203= 1.0.6 =
     
    210214
    211215- Fix ABSPATH on woocommerce patterns snippets.
    212 - Performance : Disable RSS feeds except main one.
    213 - Performance : Remove RSS feeds links in head except main one.
    214 - Performance : Remove Rest API link in head.
    215 - Performance : Remove WP Mail SMTP ads widget.
     216- New actionable function: Disable RSS feeds except main one.
     217- New actionable function: Remove RSS feeds links in head except main one.
     218- New actionable function: Remove Rest API link in head.
     219- New actionable function: Remove WP Mail SMTP ads widget.
    216220
    217221= 1.0.3 =
    218222
    219223- ZenPress tested for WordPress 6.8.
    220 - UI : Disable AARVE plugin bloat widget.
     224- UI: Disable AARVE plugin bloat widget.
    221225
    222226= 1.0.2 =
    223227
    224228- Remove load_plugin_textdomain, not needed since WordPress 4.6.
    225 - Protect wp login : Add zenpress_ prefix to transients.
     229- Protect wp login: Add zenpress_ prefix to transients.
    226230- Remove woocommerce patterns : Add zenpress_ prefix to function.
    227231- Lint and fix PHP code with phpstan.
  • zenpress/trunk/zenpress.php

    r3355428 r3372200  
    1212 * 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.2
     14 * Version: 2.0.3
    1515 * Plugin URI: https://wordpress.org/plugins/zenpress/
    1616 * Author: Quentin Le Duff
     
    3939}
    4040
    41 /**
    42  * Enqueue scripts and styles used by the plugin in admin area.
    43  *
    44  * @param string $admin_page Current admin page hook.
    45  * @return void
    46  */
    47 add_action('admin_enqueue_scripts', 'zenpress_admin_enqueue_scripts');
    48 function zenpress_admin_enqueue_scripts(string $admin_page): void {
    49     if ('settings_page_zenpress' !== $admin_page) {
    50         return;
    51     }
     41define('ZENPRESS_PLUGIN_FILE', __FILE__);
     42define('ZENPRESS_PLUGIN_DIR', plugin_dir_path(__FILE__));
    5243
    53     $asset_file = plugin_dir_path(__FILE__) . 'assets/build/index.asset.php';
    54     if (!file_exists($asset_file)) {
    55         return;
    56     }
     44// Core
     45require_once __DIR__ . '/inc/core/constants.php';
     46require_once __DIR__ . '/inc/core/metadata.php';
     47require_once __DIR__ . '/inc/core/sanitize.php';
    5748
    58     $asset = include $asset_file;
    59     wp_enqueue_script(
    60         'zenpress-scripts',
    61         plugins_url('assets/build/index.js', __FILE__),
    62         $asset['dependencies'],
    63         $asset['version'],
    64         true
    65     );
     49// Admin UI
     50require_once __DIR__ . '/inc/admin/enqueue.php';
     51require_once __DIR__ . '/inc/admin/links.php';
     52require_once __DIR__ . '/inc/admin/menu.php';
    6653
    67     wp_enqueue_style(
    68         'zenpress-style',
    69         plugins_url('assets/build/index.css', __FILE__),
    70         array_filter(
    71             $asset['dependencies'],
    72             function ($style) {
    73                 return wp_style_is($style, 'registered');
    74             }
    75         ),
    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  */
    86 add_action('admin_enqueue_scripts', 'zenpress_localize_snippets_meta');
    87 function 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  */
    112 add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'zenpress_add_settings_link');
    113 function 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  */
    131 add_filter('plugin_row_meta', 'zenpress_plugin_row_meta', 10, 2);
    132 function 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 }
    158 
    159 /**
    160  * Register ZenPress options page under the Settings menu.
    161  *
    162  * @return void
    163  */
    164 add_action('admin_menu', 'zenpress_add_option_page');
    165 function zenpress_add_option_page(): void {
    166     add_options_page(
    167         __('ZenPress options', 'zenpress'),
    168         __('ZenPress', 'zenpress'),
    169         'manage_options',
    170         'zenpress',
    171         'zenpress_options_page'
    172     );
    173 }
    174 
    175 /**
    176  * Render ZenPress options page content.
    177  *
    178  * @return void
    179  */
    180 function zenpress_options_page(): void {
    181     $plugin_data = get_file_data(__FILE__, ['Version' => 'Version'], 'plugin');
    182     $plugin_version = $plugin_data['Version'] ?? '';
    183     ?>
    184     <div class="wrap zenpress-dashboard-wrap">
    185         <div class="zenpress-header">
    186             <div class="zenpress-header-title">
    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>
    221         </div>
    222         <div id="zenpress-settings" class="zenpress-settings">
    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>
    230         </div>
    231         <div class="zenpress-footer">
    232             <div class="zenpress-footer-title">
    233                 <p>
    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>
    253         </div>
    254     </div>
    255     <?php
    256 }
    257 
    258 /**
    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).
    263  */
    264 function zenpress_extract_snippet_metadata(string $snippet_name): array {
    265     $defaults = array(
    266         'title'       => '',
    267         'description' => '',
    268         'category'    => '',
    269         'weight'      => 0,
    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  */
    289 add_action('init', 'zenpress_register_snippet_settings');
    290 function zenpress_register_snippet_settings(): void {
    291     register_setting(
    292         'options',
    293         'zenpress_active_snippets',
    294         array(
    295             'type'              => 'array',
    296             'default'           => array(),
    297             'sanitize_callback' => 'zenpress_sanitize_snippets_option',
    298             'show_in_rest'      => array(
    299                 'schema' => array(
    300                     'type'  => 'array',
    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  */
    314 function 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.
    327  */
    328 function zenpress_load_snippets(string $folder = 'inc/snippets/'): array {
    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)) {
    342             include_once $file;
    343             $loaded[] = $name;
    344         }
    345     }
    346     return $loaded;
    347 }
    348 
    349 /**
    350  * Boot ZenPress snippets.
    351  */
    352 add_action('init', function() : void {
    353     zenpress_load_snippets();
    354 });
     54// Settings logic
     55require_once __DIR__ . '/inc/settings/options.php';
     56require_once __DIR__ . '/inc/settings/loader.php';
Note: See TracChangeset for help on using the changeset viewer.