Plugin Directory

Changeset 3451904


Ignore:
Timestamp:
02/02/2026 09:40:44 AM (8 weeks ago)
Author:
quentinldd
Message:

Update to version 2.2.2 from GitHub

Location:
zenpress
Files:
10 added
36 edited
1 copied

Legend:

Unmodified
Added
Removed
  • zenpress/tags/2.2.2/assets/build/index-rtl.css

    r3412245 r3451904  
    1 .components-button{gap:4px}.components-notice-list{display:flex;flex-direction:column;gap:8px;margin-bottom:16px;width:100%}.zenpress-tabs{display:grid;gap:0;width:100%}.zenpress-tabs--vertical{grid-template-columns:200px 1fr}@media screen and (max-width:768px){.zenpress-tabs--vertical{grid-template-columns:1fr}}.zenpress-tabs__list{display:flex;list-style:none;margin:0}.zenpress-tabs__list--vertical{border-left:1px solid #d6e2ed;flex-direction:column;padding-left:0}.zenpress-tabs__tab{align-items:center;background:transparent;border:none;border-radius:0;color:var(--wp-components-color-foreground,#1e1e1e);cursor:pointer;display:flex;font-size:13px;font-weight:400;gap:8px;line-height:1.2;margin:0;min-height:40px;padding:16px;position:relative;text-align:right;transition:all .1s ease}.zenpress-tabs__tab:before{display:inline-block;font-family:dashicons;font-size:20px;height:20px;line-height:1;text-align:center;width:20px}.zenpress-tabs__tab:hover{background:#f0f0f1;color:#1e1e1e}.zenpress-tabs__tab:focus,.zenpress-tabs__tab:hover{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__tab--is-active{background:transparent;background-color:color-mix(in srgb,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)),transparent 96%);color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));fill:currentcolor;font-weight:400}.zenpress-tabs__tab--is-active:after{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));bottom:0;content:"";position:absolute;left:0;top:0;width:3px}.zenpress-tabs__tab--category-core:before{content:""}.zenpress-tabs__tab--category-gutenberg:before{content:""}.zenpress-tabs__tab--category-woocommerce:before{content:""}.zenpress-tabs__tab--category-tools:before{content:""}.zenpress-tabs__tab--category-ads-blocker:before{content:""}.zenpress-tabs__list--vertical .zenpress-tabs__tab{justify-content:flex-start;width:100%}.zenpress-tabs__panel{flex:1;height:65vh;max-height:65vh;min-width:0;overflow:auto;padding:16px 16px 0;position:relative}@media screen and (max-width:1281px){.zenpress-tabs__panel{height:600px;max-height:600px}}@media screen and (max-width:960px){.zenpress-tabs__panel{height:unset;max-height:unset}}.zenpress-tabs__panel:focus{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__panel[hidden]{display:none}.components-toggle-control{margin:1em 0}.components-toggle-control__help{font-size:1.1em}.zenpress-dashboard-wrap *{box-sizing:border-box}.zenpress-dashboard-wrap a:not(.components-button){color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))))}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]{gap:4px;position:relative}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]:after{content:" ↗"}.zenpress-footer,.zenpress-header,.zenpress-loading,.zenpress-row,.zenpress-settings{margin:0 auto;max-width:1440px;width:100%}.zenpress-header{background:#fff;border:1px solid #e0e0e0;border-radius:4px;gap:40px;overflow-x:auto;padding:16px}.zenpress-header,.zenpress-header-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-header-navigation{gap:16px}.zenpress-header h1,.zenpress-header p{margin:0;padding:0}.zenpress-footer{border-top:1px solid #e0e0e0;gap:32px;overflow-x:auto;padding:32px 16px 16px}.zenpress-footer,.zenpress-footer-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-footer-navigation{gap:16px}.zenpress-footer p{margin:0;padding:0}.zenpress-settings{border-radius:4px;margin-bottom:32px;margin-top:32px}@media screen and (max-width:1281px){.zenpress-settings{margin-bottom:16px;margin-top:16px}}.zenpress-row{display:grid;gap:32px;grid-template-columns:3fr 1fr}@media screen and (max-width:1281px){.zenpress-row{gap:16px}}@media screen and (max-width:960px){.zenpress-row{grid-template-columns:1fr}}.zenpress-panel{background:#fff;border:1px solid #e0e0e0;border-radius:4px}.zenpress-main,.zenpress-notices,.zenpress-panel{max-width:100%;width:100%}.zenpress-actions{border-top:1px solid #e0e0e0;gap:16px;justify-content:space-between;padding:16px}.zenpress-actions,.zenpress-actions-bulk{align-items:center;display:flex;flex-wrap:wrap}.zenpress-actions-bulk{gap:8px;justify-content:flex-start}.zenpress-sidebar{align-items:stretch;display:flex;flex-direction:column;gap:16px;justify-content:flex-start}.zenpress-sidebar hr{margin-top:2em}.zenpress-presets{background:#fff;border:1px solid #e0e0e0;border-radius:4px;max-width:100%;padding:16px;width:100%}.zenpress-subcategory h3{margin-bottom:1.5em;padding-right:32px;position:relative}.zenpress-subcategory h3:before{display:inline-block;font-size:20px;height:20px;right:0;line-height:1;position:absolute;top:50%;transform:translateY(-50%);width:20px}.zenpress-subcategory-performance h3:before{content:"🚀"}.zenpress-subcategory-security h3:before{content:"🛡️"}.zenpress-subcategory-user-interface h3:before{content:"💻️"}.zenpress-tabs__panel h2{font-size:1.5em;padding-right:36px;position:relative}.zenpress-tabs__panel h2:before{content:"";display:inline-block;font-family:dashicons;font-size:28px;height:28px;right:0;line-height:28px;position:absolute;text-align:center;top:50%;transform:translateY(-50%);width:28px}#zenpress-tab-panel-core h2:before{content:""}#zenpress-tab-panel-gutenberg h2:before{content:""}#zenpress-tab-panel-woocommerce h2:before{content:""}#zenpress-tab-panel-tools h2:before{content:""}#zenpress-tab-panel-ads-blocker h2:before{content:""}
     1.components-button{gap:4px}.components-notice-list{display:flex;flex-direction:column;gap:8px;margin-bottom:16px;width:100%}.zenpress-tabs{display:grid;gap:0;width:100%}.zenpress-tabs--vertical{grid-template-columns:200px 1fr}@media screen and (max-width:768px){.zenpress-tabs--vertical{grid-template-columns:1fr}}.zenpress-tabs__list{display:flex;list-style:none;margin:0}.zenpress-tabs__list--vertical{border-left:1px solid #d6e2ed;flex-direction:column;padding-left:0}.zenpress-tabs__tab{align-items:center;background:transparent;border:none;border-radius:0;color:var(--wp-components-color-foreground,#1e1e1e);cursor:pointer;display:flex;font-size:13px;font-weight:400;gap:8px;line-height:1.2;margin:0;min-height:40px;padding:16px;position:relative;text-align:right;transition:all .1s ease}.zenpress-tabs__tab:before{display:inline-block;font-family:dashicons;font-size:20px;height:20px;line-height:1;text-align:center;width:20px}.zenpress-tabs__tab:hover{background:#f0f0f1;color:#1e1e1e}.zenpress-tabs__tab:focus,.zenpress-tabs__tab:hover{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__tab--is-active{background:transparent;background-color:color-mix(in srgb,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)),transparent 96%);color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));fill:currentcolor;font-weight:400}.zenpress-tabs__tab--is-active:after{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));bottom:0;content:"";position:absolute;left:0;top:0;width:3px}.zenpress-tabs__tab--category-core:before{content:""}.zenpress-tabs__tab--category-gutenberg:before{content:""}.zenpress-tabs__tab--category-woocommerce:before{content:""}.zenpress-tabs__tab--category-tools:before{content:""}.zenpress-tabs__tab--category-ads-blocker:before{content:""}.zenpress-tabs__list--vertical .zenpress-tabs__tab{justify-content:flex-start;width:100%}.zenpress-tabs__panel{flex:1;height:65vh;max-height:65vh;min-width:0;overflow:auto;padding:16px 16px 0;position:relative}@media screen and (max-width:1281px){.zenpress-tabs__panel{height:600px;max-height:600px}}@media screen and (max-width:960px){.zenpress-tabs__panel{height:unset;max-height:unset}}.zenpress-tabs__panel:focus{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__panel[hidden]{display:none}.components-toggle-control{margin:1em 0}.components-toggle-control__help{font-size:1.1em}.zenpress-dashboard-wrap *{box-sizing:border-box}.zenpress-dashboard-wrap a:not(.components-button){color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))))}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]{gap:4px;position:relative}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]:after{content:" ↗"}.zenpress-footer,.zenpress-header,.zenpress-loading,.zenpress-row,.zenpress-settings{margin:0 auto;max-width:1440px;width:100%}.zenpress-header{background:#fff;border:1px solid #e0e0e0;border-radius:4px;gap:40px;overflow-x:auto;padding:16px}.zenpress-header,.zenpress-header-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-header-navigation{gap:16px}.zenpress-header h1,.zenpress-header p{margin:0;padding:0}.zenpress-footer{border-top:1px solid #e0e0e0;gap:32px;overflow-x:auto;padding:32px 16px 16px}.zenpress-footer,.zenpress-footer-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-footer-navigation{gap:16px}.zenpress-footer p{margin:0;padding:0}.zenpress-settings{border-radius:4px;margin-bottom:32px;margin-top:32px}@media screen and (max-width:1281px){.zenpress-settings{margin-bottom:16px;margin-top:16px}}.zenpress-row{display:grid;gap:32px;grid-template-columns:3fr 1fr}@media screen and (max-width:1281px){.zenpress-row{gap:16px}}@media screen and (max-width:960px){.zenpress-row{grid-template-columns:1fr}}.zenpress-panel{background:#fff;border:1px solid #e0e0e0;border-radius:4px}.zenpress-main,.zenpress-notices,.zenpress-panel{max-width:100%;width:100%}.zenpress-actions{border-top:1px solid #e0e0e0;gap:16px;justify-content:space-between;padding:16px}.zenpress-actions,.zenpress-actions-bulk{align-items:center;display:flex;flex-wrap:wrap}.zenpress-actions-bulk{gap:8px;justify-content:flex-start}.zenpress-sidebar{align-items:stretch;display:flex;flex-direction:column;gap:16px;justify-content:flex-start}.zenpress-sidebar hr{margin-top:2em}.zenpress-presets{background:#fff;border:1px solid #e0e0e0;border-radius:4px;max-width:100%;padding:16px;width:100%}.zenpress-subcategory h3{margin-bottom:1.5em;padding-right:32px;position:relative}.zenpress-subcategory h3:before{display:inline-block;font-size:20px;height:20px;right:0;line-height:1;position:absolute;top:50%;transform:translateY(-50%);width:20px}.zenpress-subcategory-performance h3:before{content:"🚀"}.zenpress-subcategory-security h3:before{content:"🛡️"}.zenpress-subcategory-user-interface h3:before{content:"💻️"}.zenpress-subcategory-integrations h3:before{content:"🔌"}.zenpress-autoconfig-actions{margin-top:1em}.zenpress-autoconfig-help{font-size:.9em;margin-bottom:0;margin-top:.5em;opacity:.9}.zenpress-tabs__panel h2{font-size:1.5em;padding-right:36px;position:relative}.zenpress-tabs__panel h2:before{content:"";display:inline-block;font-family:dashicons;font-size:28px;height:28px;right:0;line-height:28px;position:absolute;text-align:center;top:50%;transform:translateY(-50%);width:28px}#zenpress-tab-panel-core h2:before{content:""}#zenpress-tab-panel-gutenberg h2:before{content:""}#zenpress-tab-panel-woocommerce h2:before{content:""}#zenpress-tab-panel-tools h2:before{content:""}#zenpress-tab-panel-ads-blocker h2:before{content:""}
  • zenpress/tags/2.2.2/assets/build/index.asset.php

    r3448585 r3451904  
    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' => '253355e0f124eff32114');
     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' => '71f7100577c2edd9e445');
  • zenpress/tags/2.2.2/assets/build/index.css

    r3412245 r3451904  
    1 .components-button{gap:4px}.components-notice-list{display:flex;flex-direction:column;gap:8px;margin-bottom:16px;width:100%}.zenpress-tabs{display:grid;gap:0;width:100%}.zenpress-tabs--vertical{grid-template-columns:200px 1fr}@media screen and (max-width:768px){.zenpress-tabs--vertical{grid-template-columns:1fr}}.zenpress-tabs__list{display:flex;list-style:none;margin:0}.zenpress-tabs__list--vertical{border-right:1px solid #d6e2ed;flex-direction:column;padding-right:0}.zenpress-tabs__tab{align-items:center;background:transparent;border:none;border-radius:0;color:var(--wp-components-color-foreground,#1e1e1e);cursor:pointer;display:flex;font-size:13px;font-weight:400;gap:8px;line-height:1.2;margin:0;min-height:40px;padding:16px;position:relative;text-align:left;transition:all .1s ease}.zenpress-tabs__tab:before{display:inline-block;font-family:dashicons;font-size:20px;height:20px;line-height:1;text-align:center;width:20px}.zenpress-tabs__tab:hover{background:#f0f0f1;color:#1e1e1e}.zenpress-tabs__tab:focus,.zenpress-tabs__tab:hover{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__tab--is-active{background:transparent;background-color:color-mix(in srgb,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)),transparent 96%);color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));fill:currentcolor;font-weight:400}.zenpress-tabs__tab--is-active:after{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));bottom:0;content:"";position:absolute;right:0;top:0;width:3px}.zenpress-tabs__tab--category-core:before{content:""}.zenpress-tabs__tab--category-gutenberg:before{content:""}.zenpress-tabs__tab--category-woocommerce:before{content:""}.zenpress-tabs__tab--category-tools:before{content:""}.zenpress-tabs__tab--category-ads-blocker:before{content:""}.zenpress-tabs__list--vertical .zenpress-tabs__tab{justify-content:flex-start;width:100%}.zenpress-tabs__panel{flex:1;height:65vh;max-height:65vh;min-width:0;overflow:auto;padding:16px 16px 0;position:relative}@media screen and (max-width:1281px){.zenpress-tabs__panel{height:600px;max-height:600px}}@media screen and (max-width:960px){.zenpress-tabs__panel{height:unset;max-height:unset}}.zenpress-tabs__panel:focus{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__panel[hidden]{display:none}.components-toggle-control{margin:1em 0}.components-toggle-control__help{font-size:1.1em}.zenpress-dashboard-wrap *{box-sizing:border-box}.zenpress-dashboard-wrap a:not(.components-button){color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))))}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]{gap:4px;position:relative}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]:after{content:" ↗"}.zenpress-footer,.zenpress-header,.zenpress-loading,.zenpress-row,.zenpress-settings{margin:0 auto;max-width:1440px;width:100%}.zenpress-header{background:#fff;border:1px solid #e0e0e0;border-radius:4px;gap:40px;overflow-x:auto;padding:16px}.zenpress-header,.zenpress-header-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-header-navigation{gap:16px}.zenpress-header h1,.zenpress-header p{margin:0;padding:0}.zenpress-footer{border-top:1px solid #e0e0e0;gap:32px;overflow-x:auto;padding:32px 16px 16px}.zenpress-footer,.zenpress-footer-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-footer-navigation{gap:16px}.zenpress-footer p{margin:0;padding:0}.zenpress-settings{border-radius:4px;margin-bottom:32px;margin-top:32px}@media screen and (max-width:1281px){.zenpress-settings{margin-bottom:16px;margin-top:16px}}.zenpress-row{display:grid;gap:32px;grid-template-columns:3fr 1fr}@media screen and (max-width:1281px){.zenpress-row{gap:16px}}@media screen and (max-width:960px){.zenpress-row{grid-template-columns:1fr}}.zenpress-panel{background:#fff;border:1px solid #e0e0e0;border-radius:4px}.zenpress-main,.zenpress-notices,.zenpress-panel{max-width:100%;width:100%}.zenpress-actions{border-top:1px solid #e0e0e0;gap:16px;justify-content:space-between;padding:16px}.zenpress-actions,.zenpress-actions-bulk{align-items:center;display:flex;flex-wrap:wrap}.zenpress-actions-bulk{gap:8px;justify-content:flex-start}.zenpress-sidebar{align-items:stretch;display:flex;flex-direction:column;gap:16px;justify-content:flex-start}.zenpress-sidebar hr{margin-top:2em}.zenpress-presets{background:#fff;border:1px solid #e0e0e0;border-radius:4px;max-width:100%;padding:16px;width:100%}.zenpress-subcategory h3{margin-bottom:1.5em;padding-left:32px;position:relative}.zenpress-subcategory h3:before{display:inline-block;font-size:20px;height:20px;left:0;line-height:1;position:absolute;top:50%;transform:translateY(-50%);width:20px}.zenpress-subcategory-performance h3:before{content:"🚀"}.zenpress-subcategory-security h3:before{content:"🛡️"}.zenpress-subcategory-user-interface h3:before{content:"💻️"}.zenpress-tabs__panel h2{font-size:1.5em;padding-left:36px;position:relative}.zenpress-tabs__panel h2:before{content:"";display:inline-block;font-family:dashicons;font-size:28px;height:28px;left:0;line-height:28px;position:absolute;text-align:center;top:50%;transform:translateY(-50%);width:28px}#zenpress-tab-panel-core h2:before{content:""}#zenpress-tab-panel-gutenberg h2:before{content:""}#zenpress-tab-panel-woocommerce h2:before{content:""}#zenpress-tab-panel-tools h2:before{content:""}#zenpress-tab-panel-ads-blocker h2:before{content:""}
     1.components-button{gap:4px}.components-notice-list{display:flex;flex-direction:column;gap:8px;margin-bottom:16px;width:100%}.zenpress-tabs{display:grid;gap:0;width:100%}.zenpress-tabs--vertical{grid-template-columns:200px 1fr}@media screen and (max-width:768px){.zenpress-tabs--vertical{grid-template-columns:1fr}}.zenpress-tabs__list{display:flex;list-style:none;margin:0}.zenpress-tabs__list--vertical{border-right:1px solid #d6e2ed;flex-direction:column;padding-right:0}.zenpress-tabs__tab{align-items:center;background:transparent;border:none;border-radius:0;color:var(--wp-components-color-foreground,#1e1e1e);cursor:pointer;display:flex;font-size:13px;font-weight:400;gap:8px;line-height:1.2;margin:0;min-height:40px;padding:16px;position:relative;text-align:left;transition:all .1s ease}.zenpress-tabs__tab:before{display:inline-block;font-family:dashicons;font-size:20px;height:20px;line-height:1;text-align:center;width:20px}.zenpress-tabs__tab:hover{background:#f0f0f1;color:#1e1e1e}.zenpress-tabs__tab:focus,.zenpress-tabs__tab:hover{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__tab--is-active{background:transparent;background-color:color-mix(in srgb,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)),transparent 96%);color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));fill:currentcolor;font-weight:400}.zenpress-tabs__tab--is-active:after{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));bottom:0;content:"";position:absolute;right:0;top:0;width:3px}.zenpress-tabs__tab--category-core:before{content:""}.zenpress-tabs__tab--category-gutenberg:before{content:""}.zenpress-tabs__tab--category-woocommerce:before{content:""}.zenpress-tabs__tab--category-tools:before{content:""}.zenpress-tabs__tab--category-ads-blocker:before{content:""}.zenpress-tabs__list--vertical .zenpress-tabs__tab{justify-content:flex-start;width:100%}.zenpress-tabs__panel{flex:1;height:65vh;max-height:65vh;min-width:0;overflow:auto;padding:16px 16px 0;position:relative}@media screen and (max-width:1281px){.zenpress-tabs__panel{height:600px;max-height:600px}}@media screen and (max-width:960px){.zenpress-tabs__panel{height:unset;max-height:unset}}.zenpress-tabs__panel:focus{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__panel[hidden]{display:none}.components-toggle-control{margin:1em 0}.components-toggle-control__help{font-size:1.1em}.zenpress-dashboard-wrap *{box-sizing:border-box}.zenpress-dashboard-wrap a:not(.components-button){color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))))}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]{gap:4px;position:relative}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]:after{content:" ↗"}.zenpress-footer,.zenpress-header,.zenpress-loading,.zenpress-row,.zenpress-settings{margin:0 auto;max-width:1440px;width:100%}.zenpress-header{background:#fff;border:1px solid #e0e0e0;border-radius:4px;gap:40px;overflow-x:auto;padding:16px}.zenpress-header,.zenpress-header-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-header-navigation{gap:16px}.zenpress-header h1,.zenpress-header p{margin:0;padding:0}.zenpress-footer{border-top:1px solid #e0e0e0;gap:32px;overflow-x:auto;padding:32px 16px 16px}.zenpress-footer,.zenpress-footer-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-footer-navigation{gap:16px}.zenpress-footer p{margin:0;padding:0}.zenpress-settings{border-radius:4px;margin-bottom:32px;margin-top:32px}@media screen and (max-width:1281px){.zenpress-settings{margin-bottom:16px;margin-top:16px}}.zenpress-row{display:grid;gap:32px;grid-template-columns:3fr 1fr}@media screen and (max-width:1281px){.zenpress-row{gap:16px}}@media screen and (max-width:960px){.zenpress-row{grid-template-columns:1fr}}.zenpress-panel{background:#fff;border:1px solid #e0e0e0;border-radius:4px}.zenpress-main,.zenpress-notices,.zenpress-panel{max-width:100%;width:100%}.zenpress-actions{border-top:1px solid #e0e0e0;gap:16px;justify-content:space-between;padding:16px}.zenpress-actions,.zenpress-actions-bulk{align-items:center;display:flex;flex-wrap:wrap}.zenpress-actions-bulk{gap:8px;justify-content:flex-start}.zenpress-sidebar{align-items:stretch;display:flex;flex-direction:column;gap:16px;justify-content:flex-start}.zenpress-sidebar hr{margin-top:2em}.zenpress-presets{background:#fff;border:1px solid #e0e0e0;border-radius:4px;max-width:100%;padding:16px;width:100%}.zenpress-subcategory h3{margin-bottom:1.5em;padding-left:32px;position:relative}.zenpress-subcategory h3:before{display:inline-block;font-size:20px;height:20px;left:0;line-height:1;position:absolute;top:50%;transform:translateY(-50%);width:20px}.zenpress-subcategory-performance h3:before{content:"🚀"}.zenpress-subcategory-security h3:before{content:"🛡️"}.zenpress-subcategory-user-interface h3:before{content:"💻️"}.zenpress-subcategory-integrations h3:before{content:"🔌"}.zenpress-autoconfig-actions{margin-top:1em}.zenpress-autoconfig-help{font-size:.9em;margin-bottom:0;margin-top:.5em;opacity:.9}.zenpress-tabs__panel h2{font-size:1.5em;padding-left:36px;position:relative}.zenpress-tabs__panel h2:before{content:"";display:inline-block;font-family:dashicons;font-size:28px;height:28px;left:0;line-height:28px;position:absolute;text-align:center;top:50%;transform:translateY(-50%);width:28px}#zenpress-tab-panel-core h2:before{content:""}#zenpress-tab-panel-gutenberg h2:before{content:""}#zenpress-tab-panel-woocommerce h2:before{content:""}#zenpress-tab-panel-tools h2:before{content:""}#zenpress-tab-panel-ads-blocker h2:before{content:""}
  • zenpress/tags/2.2.2/assets/build/index.js

    r3448585 r3451904  
    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,r=window.wp.i18n,a=window.wp.components,i=window.wp.apiFetch;var o=e.n(i);const c=window.wp.data,l=window.wp.notices,p=window.ReactJSXRuntime,d=({label:e,value:s,onChange:t,help:r})=>{const i=(0,n.useRef)(null);return(0,n.useEffect)(()=>((e,s)=>{if(!e)return;const t=t=>{if("Enter"===t.key){const n=e.querySelector('input[type="checkbox"]'),r=e.ownerDocument||document;n&&(r.activeElement===n||e.contains(r.activeElement))&&(t.preventDefault(),t.stopPropagation(),s())}};return e.addEventListener("keydown",t),()=>{e.removeEventListener("keydown",t)}})(i.current,t),[t]),(0,p.jsx)("div",{ref:i,children:(0,p.jsx)(a.ToggleControl,{label:e,checked:s,onChange:t,help:r,__nextHasNoMarginBottom:!0})})},u=({onClick:e,isBusy:s})=>(0,p.jsx)(a.Button,{variant:"primary",onClick:e,isBusy:s,__next40pxDefaultSize:!0,children:(0,r.__)("Save settings","zenpress")}),b=()=>{const{removeNotice:e}=(0,c.useDispatch)(l.store),s=(0,c.useSelect)(e=>e(l.store).getNotices(),[]);return s&&0!==s.length?(0,p.jsx)(a.NoticeList,{notices:s,onRemove:e}):null},h=(0,n.createContext)(),f=({selectedTabId:e,onSelect:s,orientation:t="horizontal",children:r})=>{const[a,i]=(0,n.useState)(),o=(0,n.useRef)(null),c=void 0!==e?e:a;return(0,p.jsx)(h.Provider,{value:{selectedTabId:c,onSelect:t=>{void 0===e&&i(t),s?.(t)},orientation:t,getOrderedTabIds:()=>o.current?Array.from(o.current.querySelectorAll('[role="tab"]')).map(e=>{const s=e.getAttribute("id");return s?s.replace("zenpress-tab-",""):null}).filter(Boolean):[],tabListRef:o},children:(0,p.jsx)("div",{className:`zenpress-tabs zenpress-tabs--${t}`,children:r})})};f.TabList=({children:e})=>{const{orientation:s,tabListRef:t}=(0,n.useContext)(h);return(0,p.jsx)("div",{ref:t,className:`zenpress-tabs__list zenpress-tabs__list--${s}`,role:"tablist","aria-orientation":s,children:e})},f.Tab=({tabId:e,title:s,className:t="",children:r})=>{const{selectedTabId:a,onSelect:i,orientation:o,getOrderedTabIds:c}=(0,n.useContext)(h),l=a===e,d=(0,n.useRef)(null);return(0,p.jsx)("button",{ref:d,className:`zenpress-tabs__tab ${l?"zenpress-tabs__tab--is-active":""} ${t}`.trim(),role:"tab","aria-selected":l,"aria-controls":`zenpress-tab-panel-${e}`,id:`zenpress-tab-${e}`,tabIndex:l?0:-1,onClick:()=>i(e),onKeyDown:s=>{const t=c();if(!t||0===t.length)return;const n=t.indexOf(e);if(-1===n)return;let r=n;if("vertical"===o?"ArrowDown"===s.key?(s.preventDefault(),r=n<t.length-1?n+1:0):"ArrowUp"===s.key&&(s.preventDefault(),r=n>0?n-1:t.length-1):"ArrowRight"===s.key?(s.preventDefault(),r=n<t.length-1?n+1:0):"ArrowLeft"===s.key&&(s.preventDefault(),r=n>0?n-1:t.length-1),"Home"===s.key?(s.preventDefault(),r=0):"End"===s.key&&(s.preventDefault(),r=t.length-1)," "===s.key||"Enter"===s.key)return s.preventDefault(),void i(e);if(r!==n&&r>=0&&r<t.length){const e=t[r],s=document.getElementById(`zenpress-tab-${e}`);s&&(s.focus(),i(e))}},onFocus:()=>{l||i(e)},children:s||r})},f.TabPanel=({tabId:e,children:s})=>{const{selectedTabId:t}=(0,n.useContext)(h),r=(0,n.useRef)(null),a=t===e;return(0,n.useEffect)(()=>{a&&r.current&&(0===r.current.querySelectorAll('a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"]), input:not([disabled]), select:not([disabled]), textarea:not([disabled])').length?r.current.setAttribute("tabindex","0"):r.current.removeAttribute("tabindex"))},[a]),a?(0,p.jsx)("div",{ref:r,className:"zenpress-tabs__panel",role:"tabpanel",id:`zenpress-tab-panel-${e}`,"aria-labelledby":`zenpress-tab-${e}`,children:s}):(0,p.jsx)("div",{className:"zenpress-tabs__panel",role:"tabpanel",id:`zenpress-tab-panel-${e}`,"aria-labelledby":`zenpress-tab-${e}`,hidden:!0,children:s})};const x=()=>{const{snippets:e,setSnippets:s,saveSettings:t,isSaving:i}=(()=>{const[e,s]=(0,n.useState)({}),[t,a]=(0,n.useState)(!1),{createSuccessNotice:i,createErrorNotice:p}=(0,c.useDispatch)(l.store);return(0,n.useEffect)(()=>{o()({path:"/wp/v2/settings"}).then(e=>{const t=Array.isArray(e?.zenpress_active_snippets)?e.zenpress_active_snippets:[],n=window?.zenpressSnippetsMeta||{},r={};Object.keys(n).forEach(e=>{r[e]={...n[e],"enable-snippet":t.includes(e)}}),s(r)}).catch(()=>{p((0,r.__)("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 o()({path:"/wp/v2/settings",method:"POST",data:{zenpress_active_snippets:s}}),i((0,r.__)("Settings saved.","zenpress"))}catch{p((0,r.__)("Failed to save settings.","zenpress"))}finally{a(!1)}},isSaving:t}})(),[h,x]=(0,n.useState)(),_=e=>{s(s=>{const t={};return Object.entries(s).forEach(([s,n])=>{const r=(Array.isArray(n?.preset)?n.preset:[]).includes(e);t[s]={...n,"enable-snippet":r}}),t})},m=e=>e?e.charAt(0).toUpperCase()+e.slice(1).toLowerCase():e,v=["core","gutenberg","woocommerce","ads-blocker","tools"],y={};Object.keys(e).forEach(s=>{const t=e[s],n=(t?.category||(0,r.__)("Uncategorized","zenpress")).toLowerCase(),a=(t?.subcategory||(0,r.__)("uncategorized","zenpress")).toLowerCase();y[n]||(y[n]={}),y[n][a]||(y[n][a]=[]),y[n][a].push({name:s,data:t})});const z=Object.keys(y).sort((e,s)=>{const t=v.indexOf(e.toLowerCase()),n=v.indexOf(s.toLowerCase());return-1!==t&&-1!==n?t-n:-1!==t?-1:-1!==n?1:e.localeCompare(s,void 0,{sensitivity:"base"})});return(0,n.useEffect)(()=>{!h&&z.length>0&&x(z[0])},[h,z]),(0,n.useEffect)(()=>{const e=e=>{(e.ctrlKey||e.metaKey)&&"s"===e.key&&(e.preventDefault(),i||t())};return document.addEventListener("keydown",e),()=>{document.removeEventListener("keydown",e)}},[t,i]),(0,p.jsxs)("article",{className:"zenpress-row",children:[(0,p.jsxs)("section",{className:"zenpress-main",children:[(0,p.jsx)("div",{className:"zenpress-notices",children:(0,p.jsx)(b,{})}),(0,p.jsxs)("div",{className:"zenpress-panel",children:[(0,p.jsxs)(f,{orientation:"vertical",selectedTabId:h,onSelect:e=>{x(e),x(e)},children:[(0,p.jsx)(f.TabList,{children:z.map(e=>{const s=`zenpress-tabs__tab--category-${e.toLowerCase().replace(/\s+/g,"-")}`;return(0,p.jsx)(f.Tab,{tabId:e,title:m(e),className:s,children:m(e)},e)})}),z.map(e=>{const t=Object.keys(y[e]).sort();return(0,p.jsxs)(f.TabPanel,{tabId:e,children:[(0,p.jsx)("h2",{children:m(e)}),t.map(t=>(0,p.jsxs)("div",{className:`zenpress-subcategory zenpress-subcategory-${t.toLowerCase().replace(/\s+/g,"-")}`,children:[(0,p.jsx)("hr",{}),(0,p.jsx)("h3",{children:m(t)}),y[e][t].map(({name:e,data:t})=>(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))]},t))]},e)})]}),(0,p.jsxs)("div",{className:"zenpress-actions",children:[(0,p.jsxs)("div",{className:"zenpress-actions-bulk",children:[(0,p.jsx)(a.Button,{variant:"tertiary",onClick:()=>{s(e=>{const s={};return Object.keys(e).forEach(t=>{s[t]={...e[t],"enable-snippet":!0}}),s})},__next40pxDefaultSize:!0,children:(0,r.__)("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,r.__)("Disable all actions","zenpress")})]}),(0,p.jsx)(u,{onClick:t,isBusy:i})]})]})]}),(0,p.jsx)("aside",{className:"zenpress-sidebar",children:(0,p.jsx)("div",{className:"zenpress-presets",children:(0,p.jsxs)("div",{className:"zenpress-presets-description",children:[(0,p.jsx)("h2",{children:(0,r.__)("Pick configuration preset","zenpress")}),(0,p.jsx)("p",{children:(0,r.__)("Don't know which features to enable? Quickly configure ZenPress by selecting a preset that matches your site type. Each preset enables optimized features for your specific use case.","zenpress")}),(0,p.jsx)("hr",{}),(0,p.jsxs)("h3",{children:["🖼️ ",(0,r.__)("Corporate website","zenpress")]}),(0,p.jsx)("p",{children:(0,r.__)("Optimized for business sites and portfolios. Focuses on security, performance, and removing unnecessary features like RSS feeds and author archives.","zenpress")}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>_("corporate-website"),__next40pxDefaultSize:!0,children:(0,r.__)("Enable","zenpress")}),(0,p.jsx)("hr",{}),(0,p.jsxs)("h3",{children:[" 📰 ",(0,r.__)("Blog","zenpress")]}),(0,p.jsx)("p",{children:(0,r.__)("Tailored for content-focused blogs. Includes performance and security optimizations while preserving essential blog features like RSS feeds.","zenpress")}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>_("blog"),__next40pxDefaultSize:!0,children:(0,r.__)("Enable","zenpress")}),(0,p.jsx)("hr",{}),(0,p.jsxs)("h3",{children:["🛒 ",(0,r.__)("E-commerce","zenpress")]}),(0,p.jsx)("p",{children:(0,r.__)("Designed for WooCommerce stores. Includes all performance and security features plus WooCommerce-specific optimizations for faster checkout.","zenpress")}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>_("ecommerce"),__next40pxDefaultSize:!0,children:(0,r.__)("Enable","zenpress")})]})})})]})};t()(()=>{const e=document.getElementById("zenpress-settings");e&&(0,n.createRoot)(e).render((0,p.jsx)(x,{}))})})();
     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,a=window.wp.i18n,r=window.wp.components,i=window.wp.data,c=window.wp.notices,o=window.wp.apiFetch;var l=e.n(o);const p=window.ReactJSXRuntime,d=({label:e,value:s,onChange:t,help:a})=>{const i=(0,n.useRef)(null);return(0,n.useEffect)(()=>((e,s)=>{if(!e)return;const t=t=>{if("Enter"===t.key){const n=e.querySelector('input[type="checkbox"]'),a=e.ownerDocument||document;n&&(a.activeElement===n||e.contains(a.activeElement))&&(t.preventDefault(),t.stopPropagation(),s())}};return e.addEventListener("keydown",t),()=>{e.removeEventListener("keydown",t)}})(i.current,t),[t]),(0,p.jsx)("div",{ref:i,children:(0,p.jsx)(r.ToggleControl,{label:e,checked:s,onChange:t,help:a,__nextHasNoMarginBottom:!0})})},u=({onClick:e,isBusy:s})=>(0,p.jsx)(r.Button,{variant:"primary",onClick:e,isBusy:s,__next40pxDefaultSize:!0,children:(0,a.__)("Save settings","zenpress")}),b=()=>{const{removeNotice:e}=(0,i.useDispatch)(c.store),s=(0,i.useSelect)(e=>e(c.store).getNotices(),[]);return s&&0!==s.length?(0,p.jsx)(r.NoticeList,{notices:s,onRemove:e}):null},h=(0,n.createContext)(),_=({selectedTabId:e,onSelect:s,orientation:t="horizontal",children:a})=>{const[r,i]=(0,n.useState)(),c=(0,n.useRef)(null),o=void 0!==e?e:r;return(0,p.jsx)(h.Provider,{value:{selectedTabId:o,onSelect:t=>{void 0===e&&i(t),s?.(t)},orientation:t,getOrderedTabIds:()=>c.current?Array.from(c.current.querySelectorAll('[role="tab"]')).map(e=>{const s=e.getAttribute("id");return s?s.replace("zenpress-tab-",""):null}).filter(Boolean):[],tabListRef:c},children:(0,p.jsx)("div",{className:`zenpress-tabs zenpress-tabs--${t}`,children:a})})};_.TabList=({children:e})=>{const{orientation:s,tabListRef:t}=(0,n.useContext)(h);return(0,p.jsx)("div",{ref:t,className:`zenpress-tabs__list zenpress-tabs__list--${s}`,role:"tablist","aria-orientation":s,children:e})},_.Tab=({tabId:e,title:s,className:t="",children:a})=>{const{selectedTabId:r,onSelect:i,orientation:c,getOrderedTabIds:o}=(0,n.useContext)(h),l=r===e,d=(0,n.useRef)(null);return(0,p.jsx)("button",{ref:d,className:`zenpress-tabs__tab ${l?"zenpress-tabs__tab--is-active":""} ${t}`.trim(),role:"tab","aria-selected":l,"aria-controls":`zenpress-tab-panel-${e}`,id:`zenpress-tab-${e}`,tabIndex:l?0:-1,onClick:()=>i(e),onKeyDown:s=>{const t=o();if(!t||0===t.length)return;const n=t.indexOf(e);if(-1===n)return;let a=n;if("vertical"===c?"ArrowDown"===s.key?(s.preventDefault(),a=n<t.length-1?n+1:0):"ArrowUp"===s.key&&(s.preventDefault(),a=n>0?n-1:t.length-1):"ArrowRight"===s.key?(s.preventDefault(),a=n<t.length-1?n+1:0):"ArrowLeft"===s.key&&(s.preventDefault(),a=n>0?n-1:t.length-1),"Home"===s.key?(s.preventDefault(),a=0):"End"===s.key&&(s.preventDefault(),a=t.length-1)," "===s.key||"Enter"===s.key)return s.preventDefault(),void i(e);if(a!==n&&a>=0&&a<t.length){const e=t[a],s=document.getElementById(`zenpress-tab-${e}`);s&&(s.focus(),i(e))}},onFocus:()=>{l||i(e)},children:s||a})},_.TabPanel=({tabId:e,children:s})=>{const{selectedTabId:t}=(0,n.useContext)(h),a=(0,n.useRef)(null),r=t===e;return(0,n.useEffect)(()=>{r&&a.current&&(0===a.current.querySelectorAll('a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"]), input:not([disabled]), select:not([disabled]), textarea:not([disabled])').length?a.current.setAttribute("tabindex","0"):a.current.removeAttribute("tabindex"))},[r]),r?(0,p.jsx)("div",{ref:a,className:"zenpress-tabs__panel",role:"tabpanel",id:`zenpress-tab-panel-${e}`,"aria-labelledby":`zenpress-tab-${e}`,children:s}):(0,p.jsx)("div",{className:"zenpress-tabs__panel",role:"tabpanel",id:`zenpress-tab-panel-${e}`,"aria-labelledby":`zenpress-tab-${e}`,hidden:!0,children:s})};const z=()=>{const{snippets:e,setSnippets:s,adminBarEnabled:t,setAdminBarEnabled:o,saveSettings:h,isSaving:z}=(()=>{const[e,s]=(0,n.useState)({}),[t,r]=(0,n.useState)(!0),[o,p]=(0,n.useState)(!1),{createSuccessNotice:d,createErrorNotice:u}=(0,i.useDispatch)(c.store);return(0,n.useEffect)(()=>{l()({path:"/wp/v2/settings"}).then(e=>{const t=Array.isArray(e?.zenpress_active_snippets)?e.zenpress_active_snippets:[],n=window?.zenpressSnippetsMeta||{},a={};Object.keys(n).forEach(e=>{a[e]={...n[e],"enable-snippet":t.includes(e)}}),s(a),r(!1!==e?.zenpress_admin_bar_enabled)}).catch(()=>{u((0,a.__)("Failed to load settings.","zenpress"))})},[u]),{snippets:e,setSnippets:s,adminBarEnabled:t,setAdminBarEnabled:r,saveSettings:async()=>{p(!0);const s=Object.keys(e).filter(s=>e[s]?.["enable-snippet"]);try{await l()({path:"/wp/v2/settings",method:"POST",data:{zenpress_active_snippets:s,zenpress_admin_bar_enabled:t}}),d((0,a.__)("Settings saved.","zenpress"))}catch{u((0,a.__)("Failed to save settings.","zenpress"))}finally{p(!1)}},isSaving:o}})(),[f,m]=(0,n.useState)(),[g,v]=(0,n.useState)(null),{createSuccessNotice:x,createErrorNotice:y}=(0,i.useDispatch)(c.store),j=e=>{s(s=>{const t={};return Object.entries(s).forEach(([s,n])=>{const a=(Array.isArray(n?.preset)?n.preset:[]).includes(e);t[s]={...n,"enable-snippet":a}}),t})},w=e=>e?e.charAt(0).toUpperCase()+e.slice(1).toLowerCase():e,S=["core","gutenberg","woocommerce","ads-blocker","tools"],k={};Object.keys(e).forEach(s=>{const t=e[s],n=(t?.category||(0,a.__)("Uncategorized","zenpress")).toLowerCase(),r=(t?.subcategory||(0,a.__)("uncategorized","zenpress")).toLowerCase();k[n]||(k[n]={}),k[n][r]||(k[n][r]=[]),k[n][r].push({name:s,data:t})});const C=Object.keys(k).sort((e,s)=>{const t=S.indexOf(e.toLowerCase()),n=S.indexOf(s.toLowerCase());return-1!==t&&-1!==n?t-n:-1!==t?-1:-1!==n?1:e.localeCompare(s,void 0,{sensitivity:"base"})});(0,n.useEffect)(()=>{!f&&C.length>0&&m(C[0])},[f,C]);const E=async(e,s,t,n)=>{v(e);try{const e=await l()({path:s,method:"POST"});x(e?.message||t)}catch{y(n)}finally{v(null)}},A=()=>E("autoptimize","/zenpress/v1/autoconfig/autoptimize",(0,a.__)("Autoptimize has been configured.","zenpress"),(0,a.__)("Autoptimize autoconfig failed. Is Autoptimize installed and active?","zenpress")),N=()=>E("cache_enabler","/zenpress/v1/autoconfig/cache-enabler",(0,a.__)("Cache Enabler has been configured.","zenpress"),(0,a.__)("Cache Enabler autoconfig failed. Is Cache Enabler installed and active?","zenpress")),O=()=>E("sqlite_object_cache","/zenpress/v1/autoconfig/sqlite-object-cache",(0,a.__)("SQLite Object Cache has been configured.","zenpress"),(0,a.__)("SQLite Object Cache autoconfig failed. Is SQLite Object Cache installed and active?","zenpress"));return(0,n.useEffect)(()=>{const e=e=>{(e.ctrlKey||e.metaKey)&&"s"===e.key&&(e.preventDefault(),z||h())};return document.addEventListener("keydown",e),()=>{document.removeEventListener("keydown",e)}},[h,z]),(0,p.jsxs)("article",{className:"zenpress-row",children:[(0,p.jsxs)("section",{className:"zenpress-main",children:[(0,p.jsx)("div",{className:"zenpress-notices",children:(0,p.jsx)(b,{})}),(0,p.jsxs)("div",{className:"zenpress-panel",children:[(0,p.jsxs)(_,{orientation:"vertical",selectedTabId:f,onSelect:e=>{m(e),m(e)},children:[(0,p.jsx)(_.TabList,{children:C.map(e=>{const s=`zenpress-tabs__tab--category-${e.toLowerCase().replace(/\s+/g,"-")}`;return(0,p.jsx)(_.Tab,{tabId:e,title:w(e),className:s,children:w(e)},e)})}),C.map(e=>{const n=Object.keys(k[e]).sort();return(0,p.jsxs)(_.TabPanel,{tabId:e,children:[(0,p.jsx)("h2",{children:w(e)}),n.map(t=>(0,p.jsxs)("div",{className:`zenpress-subcategory zenpress-subcategory-${t.toLowerCase().replace(/\s+/g,"-")}`,children:[(0,p.jsx)("hr",{}),(0,p.jsx)("h3",{children:w(t)}),k[e][t].map(({name:e,data:t})=>(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))]},t)),"tools"===e&&Object.values(window?.zenpressIntegrationsActive||{}).some(Boolean)&&(0,p.jsxs)("div",{className:"zenpress-subcategory zenpress-subcategory-integrations",children:[(0,p.jsx)("hr",{}),(0,p.jsx)("h3",{children:(0,a.__)("Integrations","zenpress")}),(0,p.jsx)(d,{label:(0,a.__)("Show ZenPress admin bar button","zenpress"),value:t,onChange:()=>o(!t),help:(0,a.__)('Show a "ZenPress" item in the admin bar with "Clear caches". When enabled, integration buttons (e.g. Autoptimize) are hidden.',"zenpress")}),window?.zenpressIntegrationsActive?.autoptimize&&(0,p.jsxs)("div",{className:"zenpress-autoconfig-actions",children:[(0,p.jsx)(r.Button,{variant:"secondary",onClick:A,disabled:null!==g,__next40pxDefaultSize:!0,children:"autoptimize"===g?(0,a.__)("Applying…","zenpress"):(0,a.__)("One-click autoconfig Autoptimize","zenpress")}),(0,p.jsx)("p",{className:"zenpress-autoconfig-help",children:(0,a.__)("Apply recommended Autoptimize settings (optimize JS/CSS, aggregate CSS, static files, 404 fallbacks; disable defer, HTML optimize, optimize for logged-in, per post/page). Only works if Autoptimize is active.","zenpress")})]}),window?.zenpressIntegrationsActive?.cache_enabler&&(0,p.jsxs)("div",{className:"zenpress-autoconfig-actions",children:[(0,p.jsx)(r.Button,{variant:"secondary",onClick:N,disabled:null!==g,__next40pxDefaultSize:!0,children:"cache_enabler"===g?(0,a.__)("Applying…","zenpress"):(0,a.__)("One-click autoconfig Cache Enabler","zenpress")}),(0,p.jsx)("p",{className:"zenpress-autoconfig-help",children:(0,a.__)("Apply recommended Cache Enabler settings. Only works if Cache Enabler is active.","zenpress")})]}),window?.zenpressIntegrationsActive?.sqlite_object_cache&&(0,p.jsxs)("div",{className:"zenpress-autoconfig-actions",children:[(0,p.jsx)(r.Button,{variant:"secondary",onClick:O,disabled:null!==g,__next40pxDefaultSize:!0,children:"sqlite_object_cache"===g?(0,a.__)("Applying…","zenpress"):(0,a.__)("One-click autoconfig SQLite Object Cache","zenpress")}),(0,p.jsx)("p",{className:"zenpress-autoconfig-help",children:(0,a.__)("Apply recommended SQLite Object Cache settings. Only works if SQLite Object Cache is active.","zenpress")})]})]})]},e)})]}),(0,p.jsxs)("div",{className:"zenpress-actions",children:[(0,p.jsxs)("div",{className:"zenpress-actions-bulk",children:[(0,p.jsx)(r.Button,{variant:"tertiary",onClick:()=>{s(e=>{const s={};return Object.keys(e).forEach(t=>{s[t]={...e[t],"enable-snippet":!0}}),s})},__next40pxDefaultSize:!0,children:(0,a.__)("Enable all actions","zenpress")}),(0,p.jsx)(r.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,a.__)("Disable all actions","zenpress")})]}),(0,p.jsx)(u,{onClick:h,isBusy:z})]})]})]}),(0,p.jsx)("aside",{className:"zenpress-sidebar",children:(0,p.jsx)("div",{className:"zenpress-presets",children:(0,p.jsxs)("div",{className:"zenpress-presets-description",children:[(0,p.jsx)("h2",{children:(0,a.__)("Pick configuration preset","zenpress")}),(0,p.jsx)("p",{children:(0,a.__)("Don't know which features to enable? Quickly configure ZenPress by selecting a preset that matches your site type. Each preset enables optimized features for your specific use case.","zenpress")}),(0,p.jsx)("hr",{}),(0,p.jsxs)("h3",{children:["🖼️ ",(0,a.__)("Corporate website","zenpress")]}),(0,p.jsx)("p",{children:(0,a.__)("Optimized for business sites and portfolios. Focuses on security, performance, and removing unnecessary features like RSS feeds and author archives.","zenpress")}),(0,p.jsx)(r.Button,{variant:"secondary",onClick:()=>j("corporate-website"),__next40pxDefaultSize:!0,children:(0,a.__)("Enable","zenpress")}),(0,p.jsx)("hr",{}),(0,p.jsxs)("h3",{children:[" 📰 ",(0,a.__)("Blog","zenpress")]}),(0,p.jsx)("p",{children:(0,a.__)("Tailored for content-focused blogs. Includes performance and security optimizations while preserving essential blog features like RSS feeds.","zenpress")}),(0,p.jsx)(r.Button,{variant:"secondary",onClick:()=>j("blog"),__next40pxDefaultSize:!0,children:(0,a.__)("Enable","zenpress")}),(0,p.jsx)("hr",{}),(0,p.jsxs)("h3",{children:["🛒 ",(0,a.__)("E-commerce","zenpress")]}),(0,p.jsx)("p",{children:(0,a.__)("Designed for WooCommerce stores. Includes all performance and security features plus WooCommerce-specific optimizations for faster checkout.","zenpress")}),(0,p.jsx)(r.Button,{variant:"secondary",onClick:()=>j("ecommerce"),__next40pxDefaultSize:!0,children:(0,a.__)("Enable","zenpress")})]})})})]})};t()(()=>{const e=document.getElementById("zenpress-settings");e&&(0,n.createRoot)(e).render((0,p.jsx)(z,{}))})})();
  • zenpress/tags/2.2.2/assets/src/js/hooks/useSettings.js

    r3448585 r3451904  
    99 *
    1010 * @return {Object} Settings state and actions.
    11  * @property {Object}   snippets     - Current snippets with metadata.
    12  * @property {Function} setSnippets  - Setter to update snippets state.
    13  * @property {Function} saveSettings - Function to persist settings to REST API.
    14  * @property {boolean}  isSaving     - Whether settings are currently being saved.
     11 * @property {Object}   snippets           - Current snippets with metadata.
     12 * @property {Function} setSnippets        - Setter to update snippets state.
     13 * @property {boolean}  adminBarEnabled    - Whether the ZenPress admin bar is enabled.
     14 * @property {Function} setAdminBarEnabled - Setter for admin bar enabled.
     15 * @property {Function} saveSettings       - Function to persist settings to REST API.
     16 * @property {boolean}  isSaving           - Whether settings are currently being saved.
    1517 */
    1618export const useSettings = () => {
    1719    const [snippets, setSnippets] = useState({});
     20    const [adminBarEnabled, setAdminBarEnabled] = useState(true);
    1821    const [isSaving, setIsSaving] = useState(false);
    1922    const { createSuccessNotice, createErrorNotice } =
     
    3841
    3942                setSnippets(snippetsData);
     43                setAdminBarEnabled(
     44                    settings?.zenpress_admin_bar_enabled !== false
     45                );
    4046            })
    4147            .catch(() => {
     
    5561                path: '/wp/v2/settings',
    5662                method: 'POST',
    57                 data: { zenpress_active_snippets: active },
     63                data: {
     64                    zenpress_active_snippets: active,
     65                    zenpress_admin_bar_enabled: adminBarEnabled,
     66                },
    5867            });
    5968            createSuccessNotice(__('Settings saved.', 'zenpress'));
     
    6574    };
    6675
    67     return { snippets, setSnippets, saveSettings, isSaving };
     76    return {
     77        snippets,
     78        setSnippets,
     79        adminBarEnabled,
     80        setAdminBarEnabled,
     81        saveSettings,
     82        isSaving,
     83    };
    6884};
  • zenpress/tags/2.2.2/assets/src/js/pages/SettingsPage.js

    r3448585 r3451904  
    22import { __ } from '@wordpress/i18n';
    33import { Button } from '@wordpress/components';
     4import { useDispatch } from '@wordpress/data';
     5import { store as noticesStore } from '@wordpress/notices';
     6import apiFetch from '@wordpress/api-fetch';
    47import { useSettings } from '../hooks/useSettings';
    58import { SnippetToggleControl } from '../components/SnippetToggleControl';
     
    1417 */
    1518export const SettingsPage = () => {
    16     const { snippets, setSnippets, saveSettings, isSaving } = useSettings();
     19    const {
     20        snippets,
     21        setSnippets,
     22        adminBarEnabled,
     23        setAdminBarEnabled,
     24        saveSettings,
     25        isSaving,
     26    } = useSettings();
    1727    const [selectedTabId, setSelectedTabId] = useState();
     28    const [autoconfigBusy, setAutoconfigBusy] = useState(null);
     29    const { createSuccessNotice, createErrorNotice } =
     30        useDispatch(noticesStore);
    1831
    1932    const handleToggleChange = (snippetName) => {
     
    133146        setSelectedTabId(tabName);
    134147    };
     148
     149    const runAutoconfig = async (
     150        integrationKey,
     151        path,
     152        successMessage,
     153        errorMessage
     154    ) => {
     155        setAutoconfigBusy(integrationKey);
     156        try {
     157            const response = await apiFetch({
     158                path,
     159                method: 'POST',
     160            });
     161            createSuccessNotice(response?.message || successMessage);
     162        } catch {
     163            createErrorNotice(errorMessage);
     164        } finally {
     165            setAutoconfigBusy(null);
     166        }
     167    };
     168
     169    const handleAutoconfigAutoptimize = () =>
     170        runAutoconfig(
     171            'autoptimize',
     172            '/zenpress/v1/autoconfig/autoptimize',
     173            __('Autoptimize has been configured.', 'zenpress'),
     174            __(
     175                'Autoptimize autoconfig failed. Is Autoptimize installed and active?',
     176                'zenpress'
     177            )
     178        );
     179
     180    const handleAutoconfigCacheEnabler = () =>
     181        runAutoconfig(
     182            'cache_enabler',
     183            '/zenpress/v1/autoconfig/cache-enabler',
     184            __('Cache Enabler has been configured.', 'zenpress'),
     185            __(
     186                'Cache Enabler autoconfig failed. Is Cache Enabler installed and active?',
     187                'zenpress'
     188            )
     189        );
     190
     191    const handleAutoconfigSqliteObjectCache = () =>
     192        runAutoconfig(
     193            'sqlite_object_cache',
     194            '/zenpress/v1/autoconfig/sqlite-object-cache',
     195            __('SQLite Object Cache has been configured.', 'zenpress'),
     196            __(
     197                'SQLite Object Cache autoconfig failed. Is SQLite Object Cache installed and active?',
     198                'zenpress'
     199            )
     200        );
    135201
    136202    // Add keyboard shortcuts and ensure toggles are keyboard accessible
     
    221287                                        </div>
    222288                                    ))}
     289                                    {category === 'tools' &&
     290                                        Object.values(
     291                                            window?.zenpressIntegrationsActive ||
     292                                                {}
     293                                        ).some(Boolean) && (
     294                                            <div className="zenpress-subcategory zenpress-subcategory-integrations">
     295                                                <hr />
     296                                                <h3>
     297                                                    {__(
     298                                                        'Integrations',
     299                                                        'zenpress'
     300                                                    )}
     301                                                </h3>
     302                                                <SnippetToggleControl
     303                                                    label={__(
     304                                                        'Show ZenPress admin bar button',
     305                                                        'zenpress'
     306                                                    )}
     307                                                    value={adminBarEnabled}
     308                                                    onChange={() =>
     309                                                        setAdminBarEnabled(
     310                                                            !adminBarEnabled
     311                                                        )
     312                                                    }
     313                                                    help={__(
     314                                                        'Show a "ZenPress" item in the admin bar with "Clear caches". When enabled, integration buttons (e.g. Autoptimize) are hidden.',
     315                                                        'zenpress'
     316                                                    )}
     317                                                />
     318                                                {window
     319                                                    ?.zenpressIntegrationsActive
     320                                                    ?.autoptimize && (
     321                                                    <div className="zenpress-autoconfig-actions">
     322                                                        <Button
     323                                                            variant="secondary"
     324                                                            onClick={
     325                                                                handleAutoconfigAutoptimize
     326                                                            }
     327                                                            disabled={
     328                                                                autoconfigBusy !==
     329                                                                null
     330                                                            }
     331                                                            __next40pxDefaultSize
     332                                                        >
     333                                                            {autoconfigBusy ===
     334                                                            'autoptimize'
     335                                                                ? __(
     336                                                                        'Applying…',
     337                                                                        'zenpress'
     338                                                                    )
     339                                                                : __(
     340                                                                        'One-click autoconfig Autoptimize',
     341                                                                        'zenpress'
     342                                                                    )}
     343                                                        </Button>
     344                                                        <p className="zenpress-autoconfig-help">
     345                                                            {__(
     346                                                                'Apply recommended Autoptimize settings (optimize JS/CSS, aggregate CSS, static files, 404 fallbacks; disable defer, HTML optimize, optimize for logged-in, per post/page). Only works if Autoptimize is active.',
     347                                                                'zenpress'
     348                                                            )}
     349                                                        </p>
     350                                                    </div>
     351                                                )}
     352                                                {window
     353                                                    ?.zenpressIntegrationsActive
     354                                                    ?.cache_enabler && (
     355                                                    <div className="zenpress-autoconfig-actions">
     356                                                        <Button
     357                                                            variant="secondary"
     358                                                            onClick={
     359                                                                handleAutoconfigCacheEnabler
     360                                                            }
     361                                                            disabled={
     362                                                                autoconfigBusy !==
     363                                                                null
     364                                                            }
     365                                                            __next40pxDefaultSize
     366                                                        >
     367                                                            {autoconfigBusy ===
     368                                                            'cache_enabler'
     369                                                                ? __(
     370                                                                        'Applying…',
     371                                                                        'zenpress'
     372                                                                    )
     373                                                                : __(
     374                                                                        'One-click autoconfig Cache Enabler',
     375                                                                        'zenpress'
     376                                                                    )}
     377                                                        </Button>
     378                                                        <p className="zenpress-autoconfig-help">
     379                                                            {__(
     380                                                                'Apply recommended Cache Enabler settings. Only works if Cache Enabler is active.',
     381                                                                'zenpress'
     382                                                            )}
     383                                                        </p>
     384                                                    </div>
     385                                                )}
     386                                                {window
     387                                                    ?.zenpressIntegrationsActive
     388                                                    ?.sqlite_object_cache && (
     389                                                    <div className="zenpress-autoconfig-actions">
     390                                                        <Button
     391                                                            variant="secondary"
     392                                                            onClick={
     393                                                                handleAutoconfigSqliteObjectCache
     394                                                            }
     395                                                            disabled={
     396                                                                autoconfigBusy !==
     397                                                                null
     398                                                            }
     399                                                            __next40pxDefaultSize
     400                                                        >
     401                                                            {autoconfigBusy ===
     402                                                            'sqlite_object_cache'
     403                                                                ? __(
     404                                                                        'Applying…',
     405                                                                        'zenpress'
     406                                                                    )
     407                                                                : __(
     408                                                                        'One-click autoconfig SQLite Object Cache',
     409                                                                        'zenpress'
     410                                                                    )}
     411                                                        </Button>
     412                                                        <p className="zenpress-autoconfig-help">
     413                                                            {__(
     414                                                                'Apply recommended SQLite Object Cache settings. Only works if SQLite Object Cache is active.',
     415                                                                'zenpress'
     416                                                            )}
     417                                                        </p>
     418                                                    </div>
     419                                                )}
     420                                            </div>
     421                                        )}
    223422                                </Tabs.TabPanel>
    224423                            );
  • zenpress/tags/2.2.2/assets/src/scss/pages/_settings.scss

    r3412245 r3451904  
    197197            }
    198198        }
     199
     200        &-integrations {
     201            h3::before {
     202                content: '🔌';
     203            }
     204        }
     205    }
     206
     207    &-autoconfig-actions {
     208        margin-top: 1em;
     209    }
     210
     211    &-autoconfig-help {
     212        margin-top: 0.5em;
     213        margin-bottom: 0;
     214        font-size: 0.9em;
     215        opacity: 0.9;
    199216    }
    200217}
  • zenpress/tags/2.2.2/inc/admin/enqueue.php

    r3448585 r3451904  
    66
    77/**
    8  * Enqueue scripts and styles used by the plugin in admin area.
    9  *
    10  * @param string $admin_page Current admin page hook.
    11  * @return void
     8 * Enqueues script and style on ZenPress settings page only.
    129 */
    1310add_action('admin_enqueue_scripts', 'zenpress_admin_enqueue_scripts');
     
    4946
    5047/**
    51  * Localize translated snippet metadata for use in JavaScript.
    52  *
    53  * @param string $admin_page Current admin page hook.
    54  * @return void
     48 * Localizes zenpressSnippetsMeta and zenpressIntegrationsActive on ZenPress settings page.
    5549 */
    5650add_action('admin_enqueue_scripts', 'zenpress_localize_snippets_meta');
     
    7367
    7468    wp_localize_script('zenpress-scripts', 'zenpressSnippetsMeta', $snippets);
     69    wp_localize_script('zenpress-scripts', 'zenpressIntegrationsActive', ZenPress_Integrations::get_active_integrations_for_ui());
    7570}
  • zenpress/tags/2.2.2/inc/admin/links.php

    r3372200 r3451904  
    66
    77/**
    8  * Add a settings link on the plugins list page.
    9  *
    10  * @param array $links Existing plugin action links.
    11  * @return array Modified plugin action links.
     8 * Adds "Settings" to plugin action links on Plugins screen.
    129 */
    1310add_filter('plugin_action_links_' . plugin_basename(ZENPRESS_PLUGIN_FILE), 'zenpress_add_settings_link');
     
    2522
    2623/**
    27  * Add extra links under the plugin description on the plugins page.
    28  *
    29  * @param array  $links Existing row meta links.
    30  * @param string $file  Current plugin file.
    31  * @return array Modified row meta links.
     24 * Adds Changelog, Docs, Support to plugin row meta for ZenPress.
    3225 */
    3326add_filter('plugin_row_meta', 'zenpress_plugin_row_meta', 10, 2);
  • zenpress/tags/2.2.2/inc/admin/menu.php

    r3412245 r3451904  
    66
    77/**
    8  * Register ZenPress options page under the Settings menu.
    9  *
    10  * @return void
     8 * Adds ZenPress under Settings.
    119 */
    1210add_action('admin_menu', 'zenpress_add_option_page');
     
    2220
    2321/**
    24  * Render ZenPress options page content.
    25  *
    26  * @return void
     22 * Outputs ZenPress settings page (shell; React app mounts in #zenpress-settings).
    2723 */
    2824function zenpress_options_page(): void {
  • zenpress/tags/2.2.2/inc/core/constants.php

    r3448604 r3451904  
    11<?php
    22/**
    3  * ZenPress constants
     3 * Plugin path constants.
     4 *
    45 * @package zenpress
    56 */
  • zenpress/tags/2.2.2/inc/core/metadata.php

    r3448585 r3451904  
    66
    77/**
    8  * Extract snippet metadata from its meta file.
     8 * Loads and sanitizes snippet metadata from inc/snippets/meta/{$snippet_name}.meta.php.
    99 *
    10  * @param string $snippet_name Snippet base name (without extension).
    11  * @return array<string,mixed> Sanitized metadata (title, description, category, weight, preset).
     10 * @param string $snippet_name Snippet base name (no extension).
     11 * @return array<string, mixed> title, description, category, subcategory, weight, preset.
    1212 */
    1313function zenpress_extract_snippet_metadata(string $snippet_name): array {
     
    2222
    2323    $file = ZENPRESS_PLUGIN_DIR . 'inc/snippets/meta/' . sanitize_file_name($snippet_name) . '.meta.php';
    24     $data = is_file($file) ? include $file : [];
     24    $data = [];
     25    if (is_file($file)) {
     26        try {
     27            $data = include $file;
     28        } catch (\Throwable $e) {
     29            $data = [];
     30        }
     31    }
    2532    $metadata = array_merge($defaults, is_array($data) ? $data : []);
    2633
  • zenpress/tags/2.2.2/inc/core/sanitize.php

    r3448585 r3451904  
    66
    77/**
    8  * Sanitize the list of active snippets.
     8 * Sanitizes zenpress_active_snippets option to an array of file-safe base names.
    99 *
    10  * @param mixed $value Option value.
    11  * @return array<string> Sanitized base names.
     10 * @param mixed $value Raw option value.
     11 * @return array<string>
    1212 */
    1313function zenpress_sanitize_snippets_option(mixed $value): array {
  • zenpress/tags/2.2.2/inc/settings/loader.php

    r3448585 r3451904  
    66
    77/**
    8  * Load all active snippets.
     8 * Includes active snippet files from the given folder. Skips path traversal and disabled-by-constant snippets.
    99 *
    10  * @param string $folder Relative folder path for snippets.
     10 * @param string $folder Relative path under plugin dir (default: inc/snippets/functions/).
    1111 * @return array<string> Loaded snippet base names.
    1212 */
     
    3030        $constant = 'ZENPRESS_' . strtoupper(str_replace(['-', '_'], '_', $name));
    3131        if (is_file($file) && (!defined($constant) || constant($constant) !== false)) {
    32             include_once $file;
    33             $loaded[] = $name;
     32            try {
     33                include_once $file;
     34                $loaded[] = $name;
     35            } catch (\Throwable $e) {
     36                continue;
     37            }
    3438        }
    3539    }
  • zenpress/tags/2.2.2/inc/settings/options.php

    r3448585 r3451904  
    66
    77/**
    8  * Register option to store active snippets.
     8 * Registers zenpress_active_snippets and zenpress_admin_bar_enabled (REST + sanitize).
    99 */
    1010add_action('init', 'zenpress_register_snippet_settings');
     
    2525        ]
    2626    );
     27
     28    register_setting(
     29        'options',
     30        'zenpress_admin_bar_enabled',
     31        [
     32            'type' => 'boolean',
     33            'default' => true,
     34            'sanitize_callback' => 'zenpress_sanitize_admin_bar_enabled',
     35            'show_in_rest' => [
     36                'schema' => ['type' => 'boolean'],
     37            ],
     38        ]
     39    );
    2740}
     41
     42/**
     43 * Sanitizes zenpress_admin_bar_enabled to bool.
     44 */
     45function zenpress_sanitize_admin_bar_enabled(mixed $value): bool {
     46    return (bool) $value;
     47}
  • zenpress/tags/2.2.2/inc/snippets/functions/protect-wp-login.php

    r3448585 r3451904  
    1010});
    1111
    12 // Limit login attempts
     12// Limit login attempts (only when a valid IP is available to avoid site-wide lockout)
    1313add_filter('authenticate', static function (mixed $user, string $username, string $password): mixed {
    14     $MAX_LOGIN_ATTEMPTS = 5;
    15     $BLOCK_DURATION = 300; // 5 minutes
    16 
    1714    $ipAddress = filter_var(
    1815        wp_unslash($_SERVER['REMOTE_ADDR'] ?? ''),
    1916        FILTER_VALIDATE_IP
    20     ) ?: 'unknown';
     17    );
     18    if ($ipAddress === false) {
     19        return $user;
     20    }
    2121
     22    $MAX_LOGIN_ATTEMPTS = 5;
     23    $BLOCK_DURATION = 300; // 5 minutes
    2224    $blockKey = 'zenpress_login_block_' . $ipAddress;
    2325    $attemptKey = 'zenpress_login_attempts_' . $ipAddress;
  • zenpress/tags/2.2.2/readme.txt

    r3448604 r3451904  
    55Requires at least: 6.0
    66Tested up to: 6.9
    7 Stable tag: 2.2.1
    8 Requires PHP: 8.3
     7Stable tag: 2.2.3
     8Requires PHP: 8.1
    99License: GPLv2 or later
    1010License URI: https://www.gnu.org/licenses/gpl-2.0.html/
     
    4141* Native WordPress interface, benefits from Gutenberg's new features and the site editor.
    4242
    43 = Core - Performance =
     43= Core =
    4444
    4545* Disable adjacent posts link tags.
     
    5959* Disable Password Strength Meter.
    6060* Disable WordPress default lazy loading.
    61 
    62 = Core - Security =
    63 
    6461* Block user enumeration.
    6562* Disable application passwords.
     
    6966* Disable XML-RPC and remove RSD link.
    7067* Hide WordPress version.
    71 
    72 = Core - User Interface =
    73 
    7468* Clean up the WordPress admin bar.
    7569* Disable the login language selector.
     
    7872* Remove "Thanks for using WordPress" in footer.
    7973
    80 = WooCommerce - Performance =
     74= WooCommerce =
    8175* Disable WooCommerce cart fragments script.
    8276* Disable WooCommerce scripts and styles on non-WooCommerce pages.
     
    8478* Disable WooCommerce widgets.
    8579* Remove WooCommerce default block patterns.
    86 
    87 = WooCommerce - Security =
    8880* Hide WooCommerce version.
    8981
    90 = Gutenberg - Performance =
     82= Gutenberg =
    9183* Remove WordPress default remote block patterns.
    9284* Separate loading of core block styles.
    93 
    94 = Gutenberg - User Interface =
    9585* Disable default pattern categories in site editor.
    9686
    97 = Ads-blocker - User Interface =
     87= Ads-blocker =
    9888* Clean up the WordPress Dashboard.
    9989
    100 = Tools - Security =
     90= Tools =
    10191* Protect the wp-login form from brute force attacks.
     92* Toggle "Show ZenPress admin bar button" (clear caches from the admin bar when at least one integration is active).
     93
     94= Integrations =
     95
     96ZenPress integrates with Cache Enabler, Autoptimize, and SQLite Object Cache. When any of these plugins is active, the Tools tab shows integration status and one-click autoconfig actions.
     97
     98* Admin bar: One "Clear all caches" button (dashicon) in the admin bar, with sub-items to clear page cache (Cache Enabler), static assets (Autoptimize), or object cache (SQLite Object Cache) separately. The ZenPress button replaces the third-party cache buttons when the ZenPress admin bar is enabled. You can hide it via Settings > ZenPress > Tools.
     99* Autoptimize: One-click autoconfig enables recommended options (JS/CSS/aggregate/nogzip/fallback on; defer/HTML/logged-in/meta off) and clears the Autoptimize cache.
     100* Cache Enabler: One-click autoconfig enables clear site cache on post or plugin changes, WebP support, Gzip compression, and minify HTML (excluding inline CSS/JS), then clears the page cache.
     101* SQLite Object Cache: One-click autoconfig enables the "Use APCu" option in the plugin settings when the APCu extension is available (no wp-config editing; the plugin may write its constant when its own settings are saved).
    102102
    103103= Presets =
     
    115115== Roadmap ==
    116116
    117 = Global =
    118117* Additional presets for specific use cases.
    119118* Documentation pages with detailed guides.
    120 
    121 = Security =
    122119* Manage Heartbeat API (frontend + backend + admin whitelist).
    123 
    124 = User Interface =
    125120* Remove "site health" page.
    126121* Remove "Privacy tools".
    127 
    128 = WooCommerce =
    129122* Disable WooCommerce tracking.
    130123* Disable marketing hub.
     
    133126* Disable WooCommerce blocks.
    134127* Disable WooCommerce promo emails.
    135 
    136 = Plugins =
    137128* Disable CF7 CSS & JS.
    138129* Disable Elementor bloat.
     
    204195Nice ! If you can't find anything in the roadmap, feel free to submit your suggestion on the support page! If you know how to code, you can even contribute on GitHub.
    205196
     197== Hooks & filters ==
     198
     199For developers: ZenPress exposes the following action and filters for extending or bypassing behavior.
     200
     201= Action =
     202* `zenpress_caches_clear` – Fired when the user clears caches from the ZenPress admin bar. Integrations (e.g. Autoptimize) hook into this to clear their own caches. You can add custom cache clear logic with `add_action('zenpress_caches_clear', 'your_callback');`.
     203
     204= Filters (Disable REST API snippet) =
     205* `zenpress_disable_wp_rest_api_post_var` – Allow unauthenticated REST access when a specific POST key is present (e.g. for webhooks). Return a string or array of key names. Use non-guessable values only.
     206* `zenpress_disable_wp_rest_api_server_var` – Allow unauthenticated REST access when `REQUEST_URI` matches a specific value. Return a string or array. Use non-guessable values only.
     207
    206208== Changelog ==
     209
     210= 2.2.3 =
     211- Integrations: Cache Enabler one-click autoconfig (clear on post/plugin, WebP, Gzip, minify HTML excl. inline CSS/JS).
     212- Integrations: SQLite Object Cache one-click autoconfig (enable "Use APCu" option when APCu available; no wp-config editing by ZenPress).
     213- Integrations: Admin bar "Clear all caches" button now uses dashicons-trash icon.
     214- Defensive: REST and AJAX handlers wrap integration calls in try/catch; failed autoconfig or cache clear returns 500 with message instead of fatal.
     215- Defensive: get_active_integrations_for_ui() wraps ReflectionClass in try/catch so one missing integration does not break the settings UI.
     216- Defensive: Cache Enabler autoconfig ensures option value is array before merge (corrupted option no longer triggers warning).
     217- Defensive: Metadata and snippet loader wrap include in try/catch so a single bad meta file or snippet does not fatal the site.
     218- Defensive: Protect wp-login skips rate limiting when REMOTE_ADDR is missing or invalid to avoid site-wide lockout (e.g. CLI or proxy).
     219- Defensive: Autoptimize clear_cache and autoconfig check method_exists before calling third-party API.
     220- Docblocks: Reviewed and tightened docblocks across inc/ (file headers, classes, methods) for coherence, readability, and conciseness; removed redundant @param/@return where type is obvious.
     221- Lint: PHPStan and PHP CS Fixer fixes (autoptimize method_exists ignore, protect-wp-login strict comparison).
     222
     223= 2.2.2 =
     224- Integrations: Admin bar and one-click autoconfig (e.g. Autoptimize) in Tools tab; visible only when at least one integration is active.
     225- Documentation: Added Hooks & filters section in readme; Integrations section in workflow.md; config comments for PHPStan and PHP CS Fixer.
     226- Version alignment: Stable tag and plugin header set to 2.2.2.
    207227
    208228= 2.2.1 =
     
    338358== Upgrade Notice ==
    339359
     360= 2.2.3 =
     361- Integrations: Cache Enabler and SQLite Object Cache one-click autoconfig; admin bar trash icon; defensive fixes and docblock cleanup.
     362
     363= 2.2.2 =
     364- Integrations: ZenPress admin bar and one-click autoconfig in Tools tab (Autoptimize). Documentation updates.
     365
    340366= 2.2.1 =
    341367- Security and code quality improvements. Recommended update.
    342368
    343369= 2.2.0 =
    344 - Breaking: PHP 8.3 is now required (PHP 7.4 support dropped). Major code modernization with improved type safety and performance.
     370- Breaking: PHP 8.1 is now required (PHP 7.4 support dropped). Major code modernization with improved type safety and performance.
    345371- Security: HTTP 403 on login block, path traversal guard in snippet loader, and in-code docs for REST API bypass filters.
    346372
  • zenpress/tags/2.2.2/zenpress.php

    r3448604 r3451904  
    1212 * Plugin Name: ZenPress - Optimize & Secure
    1313 * Description: Easily speed up and strengthen your WordPress site by cleaning out unnecessary features and protecting weak points.
    14  * Version: 2.2.1
     14 * Version: 2.2.2
    1515 * Plugin URI: https://wordpress.org/plugins/zenpress/
    1616 * Author: Quentin Le Duff
     
    2020 * Requires at least: 6.0
    2121 * Tested up to: 6.9
    22  * Requires PHP: 8.3
     22 * Requires PHP: 8.1
    2323 * License URI: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html/
    2424 * License: GPL v2 or later
     
    4747require_once __DIR__ . '/inc/core/sanitize.php';
    4848
     49// Integrations (one file per plugin: handlers + autoconfig)
     50require_once __DIR__ . '/inc/classes/autoptimize.php';
     51require_once __DIR__ . '/inc/classes/cache-enabler.php';
     52require_once __DIR__ . '/inc/classes/sqlite-object-cache.php';
     53require_once __DIR__ . '/inc/classes/integrations.php';
     54
    4955// Admin UI
    5056require_once __DIR__ . '/inc/admin/enqueue.php';
  • zenpress/trunk/assets/build/index-rtl.css

    r3412245 r3451904  
    1 .components-button{gap:4px}.components-notice-list{display:flex;flex-direction:column;gap:8px;margin-bottom:16px;width:100%}.zenpress-tabs{display:grid;gap:0;width:100%}.zenpress-tabs--vertical{grid-template-columns:200px 1fr}@media screen and (max-width:768px){.zenpress-tabs--vertical{grid-template-columns:1fr}}.zenpress-tabs__list{display:flex;list-style:none;margin:0}.zenpress-tabs__list--vertical{border-left:1px solid #d6e2ed;flex-direction:column;padding-left:0}.zenpress-tabs__tab{align-items:center;background:transparent;border:none;border-radius:0;color:var(--wp-components-color-foreground,#1e1e1e);cursor:pointer;display:flex;font-size:13px;font-weight:400;gap:8px;line-height:1.2;margin:0;min-height:40px;padding:16px;position:relative;text-align:right;transition:all .1s ease}.zenpress-tabs__tab:before{display:inline-block;font-family:dashicons;font-size:20px;height:20px;line-height:1;text-align:center;width:20px}.zenpress-tabs__tab:hover{background:#f0f0f1;color:#1e1e1e}.zenpress-tabs__tab:focus,.zenpress-tabs__tab:hover{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__tab--is-active{background:transparent;background-color:color-mix(in srgb,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)),transparent 96%);color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));fill:currentcolor;font-weight:400}.zenpress-tabs__tab--is-active:after{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));bottom:0;content:"";position:absolute;left:0;top:0;width:3px}.zenpress-tabs__tab--category-core:before{content:""}.zenpress-tabs__tab--category-gutenberg:before{content:""}.zenpress-tabs__tab--category-woocommerce:before{content:""}.zenpress-tabs__tab--category-tools:before{content:""}.zenpress-tabs__tab--category-ads-blocker:before{content:""}.zenpress-tabs__list--vertical .zenpress-tabs__tab{justify-content:flex-start;width:100%}.zenpress-tabs__panel{flex:1;height:65vh;max-height:65vh;min-width:0;overflow:auto;padding:16px 16px 0;position:relative}@media screen and (max-width:1281px){.zenpress-tabs__panel{height:600px;max-height:600px}}@media screen and (max-width:960px){.zenpress-tabs__panel{height:unset;max-height:unset}}.zenpress-tabs__panel:focus{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__panel[hidden]{display:none}.components-toggle-control{margin:1em 0}.components-toggle-control__help{font-size:1.1em}.zenpress-dashboard-wrap *{box-sizing:border-box}.zenpress-dashboard-wrap a:not(.components-button){color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))))}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]{gap:4px;position:relative}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]:after{content:" ↗"}.zenpress-footer,.zenpress-header,.zenpress-loading,.zenpress-row,.zenpress-settings{margin:0 auto;max-width:1440px;width:100%}.zenpress-header{background:#fff;border:1px solid #e0e0e0;border-radius:4px;gap:40px;overflow-x:auto;padding:16px}.zenpress-header,.zenpress-header-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-header-navigation{gap:16px}.zenpress-header h1,.zenpress-header p{margin:0;padding:0}.zenpress-footer{border-top:1px solid #e0e0e0;gap:32px;overflow-x:auto;padding:32px 16px 16px}.zenpress-footer,.zenpress-footer-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-footer-navigation{gap:16px}.zenpress-footer p{margin:0;padding:0}.zenpress-settings{border-radius:4px;margin-bottom:32px;margin-top:32px}@media screen and (max-width:1281px){.zenpress-settings{margin-bottom:16px;margin-top:16px}}.zenpress-row{display:grid;gap:32px;grid-template-columns:3fr 1fr}@media screen and (max-width:1281px){.zenpress-row{gap:16px}}@media screen and (max-width:960px){.zenpress-row{grid-template-columns:1fr}}.zenpress-panel{background:#fff;border:1px solid #e0e0e0;border-radius:4px}.zenpress-main,.zenpress-notices,.zenpress-panel{max-width:100%;width:100%}.zenpress-actions{border-top:1px solid #e0e0e0;gap:16px;justify-content:space-between;padding:16px}.zenpress-actions,.zenpress-actions-bulk{align-items:center;display:flex;flex-wrap:wrap}.zenpress-actions-bulk{gap:8px;justify-content:flex-start}.zenpress-sidebar{align-items:stretch;display:flex;flex-direction:column;gap:16px;justify-content:flex-start}.zenpress-sidebar hr{margin-top:2em}.zenpress-presets{background:#fff;border:1px solid #e0e0e0;border-radius:4px;max-width:100%;padding:16px;width:100%}.zenpress-subcategory h3{margin-bottom:1.5em;padding-right:32px;position:relative}.zenpress-subcategory h3:before{display:inline-block;font-size:20px;height:20px;right:0;line-height:1;position:absolute;top:50%;transform:translateY(-50%);width:20px}.zenpress-subcategory-performance h3:before{content:"🚀"}.zenpress-subcategory-security h3:before{content:"🛡️"}.zenpress-subcategory-user-interface h3:before{content:"💻️"}.zenpress-tabs__panel h2{font-size:1.5em;padding-right:36px;position:relative}.zenpress-tabs__panel h2:before{content:"";display:inline-block;font-family:dashicons;font-size:28px;height:28px;right:0;line-height:28px;position:absolute;text-align:center;top:50%;transform:translateY(-50%);width:28px}#zenpress-tab-panel-core h2:before{content:""}#zenpress-tab-panel-gutenberg h2:before{content:""}#zenpress-tab-panel-woocommerce h2:before{content:""}#zenpress-tab-panel-tools h2:before{content:""}#zenpress-tab-panel-ads-blocker h2:before{content:""}
     1.components-button{gap:4px}.components-notice-list{display:flex;flex-direction:column;gap:8px;margin-bottom:16px;width:100%}.zenpress-tabs{display:grid;gap:0;width:100%}.zenpress-tabs--vertical{grid-template-columns:200px 1fr}@media screen and (max-width:768px){.zenpress-tabs--vertical{grid-template-columns:1fr}}.zenpress-tabs__list{display:flex;list-style:none;margin:0}.zenpress-tabs__list--vertical{border-left:1px solid #d6e2ed;flex-direction:column;padding-left:0}.zenpress-tabs__tab{align-items:center;background:transparent;border:none;border-radius:0;color:var(--wp-components-color-foreground,#1e1e1e);cursor:pointer;display:flex;font-size:13px;font-weight:400;gap:8px;line-height:1.2;margin:0;min-height:40px;padding:16px;position:relative;text-align:right;transition:all .1s ease}.zenpress-tabs__tab:before{display:inline-block;font-family:dashicons;font-size:20px;height:20px;line-height:1;text-align:center;width:20px}.zenpress-tabs__tab:hover{background:#f0f0f1;color:#1e1e1e}.zenpress-tabs__tab:focus,.zenpress-tabs__tab:hover{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__tab--is-active{background:transparent;background-color:color-mix(in srgb,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)),transparent 96%);color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));fill:currentcolor;font-weight:400}.zenpress-tabs__tab--is-active:after{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));bottom:0;content:"";position:absolute;left:0;top:0;width:3px}.zenpress-tabs__tab--category-core:before{content:""}.zenpress-tabs__tab--category-gutenberg:before{content:""}.zenpress-tabs__tab--category-woocommerce:before{content:""}.zenpress-tabs__tab--category-tools:before{content:""}.zenpress-tabs__tab--category-ads-blocker:before{content:""}.zenpress-tabs__list--vertical .zenpress-tabs__tab{justify-content:flex-start;width:100%}.zenpress-tabs__panel{flex:1;height:65vh;max-height:65vh;min-width:0;overflow:auto;padding:16px 16px 0;position:relative}@media screen and (max-width:1281px){.zenpress-tabs__panel{height:600px;max-height:600px}}@media screen and (max-width:960px){.zenpress-tabs__panel{height:unset;max-height:unset}}.zenpress-tabs__panel:focus{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__panel[hidden]{display:none}.components-toggle-control{margin:1em 0}.components-toggle-control__help{font-size:1.1em}.zenpress-dashboard-wrap *{box-sizing:border-box}.zenpress-dashboard-wrap a:not(.components-button){color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))))}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]{gap:4px;position:relative}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]:after{content:" ↗"}.zenpress-footer,.zenpress-header,.zenpress-loading,.zenpress-row,.zenpress-settings{margin:0 auto;max-width:1440px;width:100%}.zenpress-header{background:#fff;border:1px solid #e0e0e0;border-radius:4px;gap:40px;overflow-x:auto;padding:16px}.zenpress-header,.zenpress-header-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-header-navigation{gap:16px}.zenpress-header h1,.zenpress-header p{margin:0;padding:0}.zenpress-footer{border-top:1px solid #e0e0e0;gap:32px;overflow-x:auto;padding:32px 16px 16px}.zenpress-footer,.zenpress-footer-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-footer-navigation{gap:16px}.zenpress-footer p{margin:0;padding:0}.zenpress-settings{border-radius:4px;margin-bottom:32px;margin-top:32px}@media screen and (max-width:1281px){.zenpress-settings{margin-bottom:16px;margin-top:16px}}.zenpress-row{display:grid;gap:32px;grid-template-columns:3fr 1fr}@media screen and (max-width:1281px){.zenpress-row{gap:16px}}@media screen and (max-width:960px){.zenpress-row{grid-template-columns:1fr}}.zenpress-panel{background:#fff;border:1px solid #e0e0e0;border-radius:4px}.zenpress-main,.zenpress-notices,.zenpress-panel{max-width:100%;width:100%}.zenpress-actions{border-top:1px solid #e0e0e0;gap:16px;justify-content:space-between;padding:16px}.zenpress-actions,.zenpress-actions-bulk{align-items:center;display:flex;flex-wrap:wrap}.zenpress-actions-bulk{gap:8px;justify-content:flex-start}.zenpress-sidebar{align-items:stretch;display:flex;flex-direction:column;gap:16px;justify-content:flex-start}.zenpress-sidebar hr{margin-top:2em}.zenpress-presets{background:#fff;border:1px solid #e0e0e0;border-radius:4px;max-width:100%;padding:16px;width:100%}.zenpress-subcategory h3{margin-bottom:1.5em;padding-right:32px;position:relative}.zenpress-subcategory h3:before{display:inline-block;font-size:20px;height:20px;right:0;line-height:1;position:absolute;top:50%;transform:translateY(-50%);width:20px}.zenpress-subcategory-performance h3:before{content:"🚀"}.zenpress-subcategory-security h3:before{content:"🛡️"}.zenpress-subcategory-user-interface h3:before{content:"💻️"}.zenpress-subcategory-integrations h3:before{content:"🔌"}.zenpress-autoconfig-actions{margin-top:1em}.zenpress-autoconfig-help{font-size:.9em;margin-bottom:0;margin-top:.5em;opacity:.9}.zenpress-tabs__panel h2{font-size:1.5em;padding-right:36px;position:relative}.zenpress-tabs__panel h2:before{content:"";display:inline-block;font-family:dashicons;font-size:28px;height:28px;right:0;line-height:28px;position:absolute;text-align:center;top:50%;transform:translateY(-50%);width:28px}#zenpress-tab-panel-core h2:before{content:""}#zenpress-tab-panel-gutenberg h2:before{content:""}#zenpress-tab-panel-woocommerce h2:before{content:""}#zenpress-tab-panel-tools h2:before{content:""}#zenpress-tab-panel-ads-blocker h2:before{content:""}
  • zenpress/trunk/assets/build/index.asset.php

    r3448585 r3451904  
    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' => '253355e0f124eff32114');
     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' => '71f7100577c2edd9e445');
  • zenpress/trunk/assets/build/index.css

    r3412245 r3451904  
    1 .components-button{gap:4px}.components-notice-list{display:flex;flex-direction:column;gap:8px;margin-bottom:16px;width:100%}.zenpress-tabs{display:grid;gap:0;width:100%}.zenpress-tabs--vertical{grid-template-columns:200px 1fr}@media screen and (max-width:768px){.zenpress-tabs--vertical{grid-template-columns:1fr}}.zenpress-tabs__list{display:flex;list-style:none;margin:0}.zenpress-tabs__list--vertical{border-right:1px solid #d6e2ed;flex-direction:column;padding-right:0}.zenpress-tabs__tab{align-items:center;background:transparent;border:none;border-radius:0;color:var(--wp-components-color-foreground,#1e1e1e);cursor:pointer;display:flex;font-size:13px;font-weight:400;gap:8px;line-height:1.2;margin:0;min-height:40px;padding:16px;position:relative;text-align:left;transition:all .1s ease}.zenpress-tabs__tab:before{display:inline-block;font-family:dashicons;font-size:20px;height:20px;line-height:1;text-align:center;width:20px}.zenpress-tabs__tab:hover{background:#f0f0f1;color:#1e1e1e}.zenpress-tabs__tab:focus,.zenpress-tabs__tab:hover{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__tab--is-active{background:transparent;background-color:color-mix(in srgb,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)),transparent 96%);color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));fill:currentcolor;font-weight:400}.zenpress-tabs__tab--is-active:after{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));bottom:0;content:"";position:absolute;right:0;top:0;width:3px}.zenpress-tabs__tab--category-core:before{content:""}.zenpress-tabs__tab--category-gutenberg:before{content:""}.zenpress-tabs__tab--category-woocommerce:before{content:""}.zenpress-tabs__tab--category-tools:before{content:""}.zenpress-tabs__tab--category-ads-blocker:before{content:""}.zenpress-tabs__list--vertical .zenpress-tabs__tab{justify-content:flex-start;width:100%}.zenpress-tabs__panel{flex:1;height:65vh;max-height:65vh;min-width:0;overflow:auto;padding:16px 16px 0;position:relative}@media screen and (max-width:1281px){.zenpress-tabs__panel{height:600px;max-height:600px}}@media screen and (max-width:960px){.zenpress-tabs__panel{height:unset;max-height:unset}}.zenpress-tabs__panel:focus{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__panel[hidden]{display:none}.components-toggle-control{margin:1em 0}.components-toggle-control__help{font-size:1.1em}.zenpress-dashboard-wrap *{box-sizing:border-box}.zenpress-dashboard-wrap a:not(.components-button){color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))))}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]{gap:4px;position:relative}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]:after{content:" ↗"}.zenpress-footer,.zenpress-header,.zenpress-loading,.zenpress-row,.zenpress-settings{margin:0 auto;max-width:1440px;width:100%}.zenpress-header{background:#fff;border:1px solid #e0e0e0;border-radius:4px;gap:40px;overflow-x:auto;padding:16px}.zenpress-header,.zenpress-header-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-header-navigation{gap:16px}.zenpress-header h1,.zenpress-header p{margin:0;padding:0}.zenpress-footer{border-top:1px solid #e0e0e0;gap:32px;overflow-x:auto;padding:32px 16px 16px}.zenpress-footer,.zenpress-footer-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-footer-navigation{gap:16px}.zenpress-footer p{margin:0;padding:0}.zenpress-settings{border-radius:4px;margin-bottom:32px;margin-top:32px}@media screen and (max-width:1281px){.zenpress-settings{margin-bottom:16px;margin-top:16px}}.zenpress-row{display:grid;gap:32px;grid-template-columns:3fr 1fr}@media screen and (max-width:1281px){.zenpress-row{gap:16px}}@media screen and (max-width:960px){.zenpress-row{grid-template-columns:1fr}}.zenpress-panel{background:#fff;border:1px solid #e0e0e0;border-radius:4px}.zenpress-main,.zenpress-notices,.zenpress-panel{max-width:100%;width:100%}.zenpress-actions{border-top:1px solid #e0e0e0;gap:16px;justify-content:space-between;padding:16px}.zenpress-actions,.zenpress-actions-bulk{align-items:center;display:flex;flex-wrap:wrap}.zenpress-actions-bulk{gap:8px;justify-content:flex-start}.zenpress-sidebar{align-items:stretch;display:flex;flex-direction:column;gap:16px;justify-content:flex-start}.zenpress-sidebar hr{margin-top:2em}.zenpress-presets{background:#fff;border:1px solid #e0e0e0;border-radius:4px;max-width:100%;padding:16px;width:100%}.zenpress-subcategory h3{margin-bottom:1.5em;padding-left:32px;position:relative}.zenpress-subcategory h3:before{display:inline-block;font-size:20px;height:20px;left:0;line-height:1;position:absolute;top:50%;transform:translateY(-50%);width:20px}.zenpress-subcategory-performance h3:before{content:"🚀"}.zenpress-subcategory-security h3:before{content:"🛡️"}.zenpress-subcategory-user-interface h3:before{content:"💻️"}.zenpress-tabs__panel h2{font-size:1.5em;padding-left:36px;position:relative}.zenpress-tabs__panel h2:before{content:"";display:inline-block;font-family:dashicons;font-size:28px;height:28px;left:0;line-height:28px;position:absolute;text-align:center;top:50%;transform:translateY(-50%);width:28px}#zenpress-tab-panel-core h2:before{content:""}#zenpress-tab-panel-gutenberg h2:before{content:""}#zenpress-tab-panel-woocommerce h2:before{content:""}#zenpress-tab-panel-tools h2:before{content:""}#zenpress-tab-panel-ads-blocker h2:before{content:""}
     1.components-button{gap:4px}.components-notice-list{display:flex;flex-direction:column;gap:8px;margin-bottom:16px;width:100%}.zenpress-tabs{display:grid;gap:0;width:100%}.zenpress-tabs--vertical{grid-template-columns:200px 1fr}@media screen and (max-width:768px){.zenpress-tabs--vertical{grid-template-columns:1fr}}.zenpress-tabs__list{display:flex;list-style:none;margin:0}.zenpress-tabs__list--vertical{border-right:1px solid #d6e2ed;flex-direction:column;padding-right:0}.zenpress-tabs__tab{align-items:center;background:transparent;border:none;border-radius:0;color:var(--wp-components-color-foreground,#1e1e1e);cursor:pointer;display:flex;font-size:13px;font-weight:400;gap:8px;line-height:1.2;margin:0;min-height:40px;padding:16px;position:relative;text-align:left;transition:all .1s ease}.zenpress-tabs__tab:before{display:inline-block;font-family:dashicons;font-size:20px;height:20px;line-height:1;text-align:center;width:20px}.zenpress-tabs__tab:hover{background:#f0f0f1;color:#1e1e1e}.zenpress-tabs__tab:focus,.zenpress-tabs__tab:hover{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__tab--is-active{background:transparent;background-color:color-mix(in srgb,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9)),transparent 96%);color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));fill:currentcolor;font-weight:400}.zenpress-tabs__tab--is-active:after{background:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))));bottom:0;content:"";position:absolute;right:0;top:0;width:3px}.zenpress-tabs__tab--category-core:before{content:""}.zenpress-tabs__tab--category-gutenberg:before{content:""}.zenpress-tabs__tab--category-woocommerce:before{content:""}.zenpress-tabs__tab--category-tools:before{content:""}.zenpress-tabs__tab--category-ads-blocker:before{content:""}.zenpress-tabs__list--vertical .zenpress-tabs__tab{justify-content:flex-start;width:100%}.zenpress-tabs__panel{flex:1;height:65vh;max-height:65vh;min-width:0;overflow:auto;padding:16px 16px 0;position:relative}@media screen and (max-width:1281px){.zenpress-tabs__panel{height:600px;max-height:600px}}@media screen and (max-width:960px){.zenpress-tabs__panel{height:unset;max-height:unset}}.zenpress-tabs__panel:focus{box-shadow:inset 0 0 0 2px #1e1e1e!important;outline:2px solid transparent}.zenpress-tabs__panel[hidden]{display:none}.components-toggle-control{margin:1em 0}.components-toggle-control__help{font-size:1.1em}.zenpress-dashboard-wrap *{box-sizing:border-box}.zenpress-dashboard-wrap a:not(.components-button){color:var(--wp-components-color-accent,var(--wp-admin-theme-color,var(--wp-components-color-accent,var(--wp-admin-theme-color,#3858e9))))}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]{gap:4px;position:relative}.zenpress-dashboard-wrap a:not(.components-button)[target=_blank]:after{content:" ↗"}.zenpress-footer,.zenpress-header,.zenpress-loading,.zenpress-row,.zenpress-settings{margin:0 auto;max-width:1440px;width:100%}.zenpress-header{background:#fff;border:1px solid #e0e0e0;border-radius:4px;gap:40px;overflow-x:auto;padding:16px}.zenpress-header,.zenpress-header-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-header-navigation{gap:16px}.zenpress-header h1,.zenpress-header p{margin:0;padding:0}.zenpress-footer{border-top:1px solid #e0e0e0;gap:32px;overflow-x:auto;padding:32px 16px 16px}.zenpress-footer,.zenpress-footer-navigation{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.zenpress-footer-navigation{gap:16px}.zenpress-footer p{margin:0;padding:0}.zenpress-settings{border-radius:4px;margin-bottom:32px;margin-top:32px}@media screen and (max-width:1281px){.zenpress-settings{margin-bottom:16px;margin-top:16px}}.zenpress-row{display:grid;gap:32px;grid-template-columns:3fr 1fr}@media screen and (max-width:1281px){.zenpress-row{gap:16px}}@media screen and (max-width:960px){.zenpress-row{grid-template-columns:1fr}}.zenpress-panel{background:#fff;border:1px solid #e0e0e0;border-radius:4px}.zenpress-main,.zenpress-notices,.zenpress-panel{max-width:100%;width:100%}.zenpress-actions{border-top:1px solid #e0e0e0;gap:16px;justify-content:space-between;padding:16px}.zenpress-actions,.zenpress-actions-bulk{align-items:center;display:flex;flex-wrap:wrap}.zenpress-actions-bulk{gap:8px;justify-content:flex-start}.zenpress-sidebar{align-items:stretch;display:flex;flex-direction:column;gap:16px;justify-content:flex-start}.zenpress-sidebar hr{margin-top:2em}.zenpress-presets{background:#fff;border:1px solid #e0e0e0;border-radius:4px;max-width:100%;padding:16px;width:100%}.zenpress-subcategory h3{margin-bottom:1.5em;padding-left:32px;position:relative}.zenpress-subcategory h3:before{display:inline-block;font-size:20px;height:20px;left:0;line-height:1;position:absolute;top:50%;transform:translateY(-50%);width:20px}.zenpress-subcategory-performance h3:before{content:"🚀"}.zenpress-subcategory-security h3:before{content:"🛡️"}.zenpress-subcategory-user-interface h3:before{content:"💻️"}.zenpress-subcategory-integrations h3:before{content:"🔌"}.zenpress-autoconfig-actions{margin-top:1em}.zenpress-autoconfig-help{font-size:.9em;margin-bottom:0;margin-top:.5em;opacity:.9}.zenpress-tabs__panel h2{font-size:1.5em;padding-left:36px;position:relative}.zenpress-tabs__panel h2:before{content:"";display:inline-block;font-family:dashicons;font-size:28px;height:28px;left:0;line-height:28px;position:absolute;text-align:center;top:50%;transform:translateY(-50%);width:28px}#zenpress-tab-panel-core h2:before{content:""}#zenpress-tab-panel-gutenberg h2:before{content:""}#zenpress-tab-panel-woocommerce h2:before{content:""}#zenpress-tab-panel-tools h2:before{content:""}#zenpress-tab-panel-ads-blocker h2:before{content:""}
  • zenpress/trunk/assets/build/index.js

    r3448585 r3451904  
    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,r=window.wp.i18n,a=window.wp.components,i=window.wp.apiFetch;var o=e.n(i);const c=window.wp.data,l=window.wp.notices,p=window.ReactJSXRuntime,d=({label:e,value:s,onChange:t,help:r})=>{const i=(0,n.useRef)(null);return(0,n.useEffect)(()=>((e,s)=>{if(!e)return;const t=t=>{if("Enter"===t.key){const n=e.querySelector('input[type="checkbox"]'),r=e.ownerDocument||document;n&&(r.activeElement===n||e.contains(r.activeElement))&&(t.preventDefault(),t.stopPropagation(),s())}};return e.addEventListener("keydown",t),()=>{e.removeEventListener("keydown",t)}})(i.current,t),[t]),(0,p.jsx)("div",{ref:i,children:(0,p.jsx)(a.ToggleControl,{label:e,checked:s,onChange:t,help:r,__nextHasNoMarginBottom:!0})})},u=({onClick:e,isBusy:s})=>(0,p.jsx)(a.Button,{variant:"primary",onClick:e,isBusy:s,__next40pxDefaultSize:!0,children:(0,r.__)("Save settings","zenpress")}),b=()=>{const{removeNotice:e}=(0,c.useDispatch)(l.store),s=(0,c.useSelect)(e=>e(l.store).getNotices(),[]);return s&&0!==s.length?(0,p.jsx)(a.NoticeList,{notices:s,onRemove:e}):null},h=(0,n.createContext)(),f=({selectedTabId:e,onSelect:s,orientation:t="horizontal",children:r})=>{const[a,i]=(0,n.useState)(),o=(0,n.useRef)(null),c=void 0!==e?e:a;return(0,p.jsx)(h.Provider,{value:{selectedTabId:c,onSelect:t=>{void 0===e&&i(t),s?.(t)},orientation:t,getOrderedTabIds:()=>o.current?Array.from(o.current.querySelectorAll('[role="tab"]')).map(e=>{const s=e.getAttribute("id");return s?s.replace("zenpress-tab-",""):null}).filter(Boolean):[],tabListRef:o},children:(0,p.jsx)("div",{className:`zenpress-tabs zenpress-tabs--${t}`,children:r})})};f.TabList=({children:e})=>{const{orientation:s,tabListRef:t}=(0,n.useContext)(h);return(0,p.jsx)("div",{ref:t,className:`zenpress-tabs__list zenpress-tabs__list--${s}`,role:"tablist","aria-orientation":s,children:e})},f.Tab=({tabId:e,title:s,className:t="",children:r})=>{const{selectedTabId:a,onSelect:i,orientation:o,getOrderedTabIds:c}=(0,n.useContext)(h),l=a===e,d=(0,n.useRef)(null);return(0,p.jsx)("button",{ref:d,className:`zenpress-tabs__tab ${l?"zenpress-tabs__tab--is-active":""} ${t}`.trim(),role:"tab","aria-selected":l,"aria-controls":`zenpress-tab-panel-${e}`,id:`zenpress-tab-${e}`,tabIndex:l?0:-1,onClick:()=>i(e),onKeyDown:s=>{const t=c();if(!t||0===t.length)return;const n=t.indexOf(e);if(-1===n)return;let r=n;if("vertical"===o?"ArrowDown"===s.key?(s.preventDefault(),r=n<t.length-1?n+1:0):"ArrowUp"===s.key&&(s.preventDefault(),r=n>0?n-1:t.length-1):"ArrowRight"===s.key?(s.preventDefault(),r=n<t.length-1?n+1:0):"ArrowLeft"===s.key&&(s.preventDefault(),r=n>0?n-1:t.length-1),"Home"===s.key?(s.preventDefault(),r=0):"End"===s.key&&(s.preventDefault(),r=t.length-1)," "===s.key||"Enter"===s.key)return s.preventDefault(),void i(e);if(r!==n&&r>=0&&r<t.length){const e=t[r],s=document.getElementById(`zenpress-tab-${e}`);s&&(s.focus(),i(e))}},onFocus:()=>{l||i(e)},children:s||r})},f.TabPanel=({tabId:e,children:s})=>{const{selectedTabId:t}=(0,n.useContext)(h),r=(0,n.useRef)(null),a=t===e;return(0,n.useEffect)(()=>{a&&r.current&&(0===r.current.querySelectorAll('a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"]), input:not([disabled]), select:not([disabled]), textarea:not([disabled])').length?r.current.setAttribute("tabindex","0"):r.current.removeAttribute("tabindex"))},[a]),a?(0,p.jsx)("div",{ref:r,className:"zenpress-tabs__panel",role:"tabpanel",id:`zenpress-tab-panel-${e}`,"aria-labelledby":`zenpress-tab-${e}`,children:s}):(0,p.jsx)("div",{className:"zenpress-tabs__panel",role:"tabpanel",id:`zenpress-tab-panel-${e}`,"aria-labelledby":`zenpress-tab-${e}`,hidden:!0,children:s})};const x=()=>{const{snippets:e,setSnippets:s,saveSettings:t,isSaving:i}=(()=>{const[e,s]=(0,n.useState)({}),[t,a]=(0,n.useState)(!1),{createSuccessNotice:i,createErrorNotice:p}=(0,c.useDispatch)(l.store);return(0,n.useEffect)(()=>{o()({path:"/wp/v2/settings"}).then(e=>{const t=Array.isArray(e?.zenpress_active_snippets)?e.zenpress_active_snippets:[],n=window?.zenpressSnippetsMeta||{},r={};Object.keys(n).forEach(e=>{r[e]={...n[e],"enable-snippet":t.includes(e)}}),s(r)}).catch(()=>{p((0,r.__)("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 o()({path:"/wp/v2/settings",method:"POST",data:{zenpress_active_snippets:s}}),i((0,r.__)("Settings saved.","zenpress"))}catch{p((0,r.__)("Failed to save settings.","zenpress"))}finally{a(!1)}},isSaving:t}})(),[h,x]=(0,n.useState)(),_=e=>{s(s=>{const t={};return Object.entries(s).forEach(([s,n])=>{const r=(Array.isArray(n?.preset)?n.preset:[]).includes(e);t[s]={...n,"enable-snippet":r}}),t})},m=e=>e?e.charAt(0).toUpperCase()+e.slice(1).toLowerCase():e,v=["core","gutenberg","woocommerce","ads-blocker","tools"],y={};Object.keys(e).forEach(s=>{const t=e[s],n=(t?.category||(0,r.__)("Uncategorized","zenpress")).toLowerCase(),a=(t?.subcategory||(0,r.__)("uncategorized","zenpress")).toLowerCase();y[n]||(y[n]={}),y[n][a]||(y[n][a]=[]),y[n][a].push({name:s,data:t})});const z=Object.keys(y).sort((e,s)=>{const t=v.indexOf(e.toLowerCase()),n=v.indexOf(s.toLowerCase());return-1!==t&&-1!==n?t-n:-1!==t?-1:-1!==n?1:e.localeCompare(s,void 0,{sensitivity:"base"})});return(0,n.useEffect)(()=>{!h&&z.length>0&&x(z[0])},[h,z]),(0,n.useEffect)(()=>{const e=e=>{(e.ctrlKey||e.metaKey)&&"s"===e.key&&(e.preventDefault(),i||t())};return document.addEventListener("keydown",e),()=>{document.removeEventListener("keydown",e)}},[t,i]),(0,p.jsxs)("article",{className:"zenpress-row",children:[(0,p.jsxs)("section",{className:"zenpress-main",children:[(0,p.jsx)("div",{className:"zenpress-notices",children:(0,p.jsx)(b,{})}),(0,p.jsxs)("div",{className:"zenpress-panel",children:[(0,p.jsxs)(f,{orientation:"vertical",selectedTabId:h,onSelect:e=>{x(e),x(e)},children:[(0,p.jsx)(f.TabList,{children:z.map(e=>{const s=`zenpress-tabs__tab--category-${e.toLowerCase().replace(/\s+/g,"-")}`;return(0,p.jsx)(f.Tab,{tabId:e,title:m(e),className:s,children:m(e)},e)})}),z.map(e=>{const t=Object.keys(y[e]).sort();return(0,p.jsxs)(f.TabPanel,{tabId:e,children:[(0,p.jsx)("h2",{children:m(e)}),t.map(t=>(0,p.jsxs)("div",{className:`zenpress-subcategory zenpress-subcategory-${t.toLowerCase().replace(/\s+/g,"-")}`,children:[(0,p.jsx)("hr",{}),(0,p.jsx)("h3",{children:m(t)}),y[e][t].map(({name:e,data:t})=>(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))]},t))]},e)})]}),(0,p.jsxs)("div",{className:"zenpress-actions",children:[(0,p.jsxs)("div",{className:"zenpress-actions-bulk",children:[(0,p.jsx)(a.Button,{variant:"tertiary",onClick:()=>{s(e=>{const s={};return Object.keys(e).forEach(t=>{s[t]={...e[t],"enable-snippet":!0}}),s})},__next40pxDefaultSize:!0,children:(0,r.__)("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,r.__)("Disable all actions","zenpress")})]}),(0,p.jsx)(u,{onClick:t,isBusy:i})]})]})]}),(0,p.jsx)("aside",{className:"zenpress-sidebar",children:(0,p.jsx)("div",{className:"zenpress-presets",children:(0,p.jsxs)("div",{className:"zenpress-presets-description",children:[(0,p.jsx)("h2",{children:(0,r.__)("Pick configuration preset","zenpress")}),(0,p.jsx)("p",{children:(0,r.__)("Don't know which features to enable? Quickly configure ZenPress by selecting a preset that matches your site type. Each preset enables optimized features for your specific use case.","zenpress")}),(0,p.jsx)("hr",{}),(0,p.jsxs)("h3",{children:["🖼️ ",(0,r.__)("Corporate website","zenpress")]}),(0,p.jsx)("p",{children:(0,r.__)("Optimized for business sites and portfolios. Focuses on security, performance, and removing unnecessary features like RSS feeds and author archives.","zenpress")}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>_("corporate-website"),__next40pxDefaultSize:!0,children:(0,r.__)("Enable","zenpress")}),(0,p.jsx)("hr",{}),(0,p.jsxs)("h3",{children:[" 📰 ",(0,r.__)("Blog","zenpress")]}),(0,p.jsx)("p",{children:(0,r.__)("Tailored for content-focused blogs. Includes performance and security optimizations while preserving essential blog features like RSS feeds.","zenpress")}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>_("blog"),__next40pxDefaultSize:!0,children:(0,r.__)("Enable","zenpress")}),(0,p.jsx)("hr",{}),(0,p.jsxs)("h3",{children:["🛒 ",(0,r.__)("E-commerce","zenpress")]}),(0,p.jsx)("p",{children:(0,r.__)("Designed for WooCommerce stores. Includes all performance and security features plus WooCommerce-specific optimizations for faster checkout.","zenpress")}),(0,p.jsx)(a.Button,{variant:"secondary",onClick:()=>_("ecommerce"),__next40pxDefaultSize:!0,children:(0,r.__)("Enable","zenpress")})]})})})]})};t()(()=>{const e=document.getElementById("zenpress-settings");e&&(0,n.createRoot)(e).render((0,p.jsx)(x,{}))})})();
     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,a=window.wp.i18n,r=window.wp.components,i=window.wp.data,c=window.wp.notices,o=window.wp.apiFetch;var l=e.n(o);const p=window.ReactJSXRuntime,d=({label:e,value:s,onChange:t,help:a})=>{const i=(0,n.useRef)(null);return(0,n.useEffect)(()=>((e,s)=>{if(!e)return;const t=t=>{if("Enter"===t.key){const n=e.querySelector('input[type="checkbox"]'),a=e.ownerDocument||document;n&&(a.activeElement===n||e.contains(a.activeElement))&&(t.preventDefault(),t.stopPropagation(),s())}};return e.addEventListener("keydown",t),()=>{e.removeEventListener("keydown",t)}})(i.current,t),[t]),(0,p.jsx)("div",{ref:i,children:(0,p.jsx)(r.ToggleControl,{label:e,checked:s,onChange:t,help:a,__nextHasNoMarginBottom:!0})})},u=({onClick:e,isBusy:s})=>(0,p.jsx)(r.Button,{variant:"primary",onClick:e,isBusy:s,__next40pxDefaultSize:!0,children:(0,a.__)("Save settings","zenpress")}),b=()=>{const{removeNotice:e}=(0,i.useDispatch)(c.store),s=(0,i.useSelect)(e=>e(c.store).getNotices(),[]);return s&&0!==s.length?(0,p.jsx)(r.NoticeList,{notices:s,onRemove:e}):null},h=(0,n.createContext)(),_=({selectedTabId:e,onSelect:s,orientation:t="horizontal",children:a})=>{const[r,i]=(0,n.useState)(),c=(0,n.useRef)(null),o=void 0!==e?e:r;return(0,p.jsx)(h.Provider,{value:{selectedTabId:o,onSelect:t=>{void 0===e&&i(t),s?.(t)},orientation:t,getOrderedTabIds:()=>c.current?Array.from(c.current.querySelectorAll('[role="tab"]')).map(e=>{const s=e.getAttribute("id");return s?s.replace("zenpress-tab-",""):null}).filter(Boolean):[],tabListRef:c},children:(0,p.jsx)("div",{className:`zenpress-tabs zenpress-tabs--${t}`,children:a})})};_.TabList=({children:e})=>{const{orientation:s,tabListRef:t}=(0,n.useContext)(h);return(0,p.jsx)("div",{ref:t,className:`zenpress-tabs__list zenpress-tabs__list--${s}`,role:"tablist","aria-orientation":s,children:e})},_.Tab=({tabId:e,title:s,className:t="",children:a})=>{const{selectedTabId:r,onSelect:i,orientation:c,getOrderedTabIds:o}=(0,n.useContext)(h),l=r===e,d=(0,n.useRef)(null);return(0,p.jsx)("button",{ref:d,className:`zenpress-tabs__tab ${l?"zenpress-tabs__tab--is-active":""} ${t}`.trim(),role:"tab","aria-selected":l,"aria-controls":`zenpress-tab-panel-${e}`,id:`zenpress-tab-${e}`,tabIndex:l?0:-1,onClick:()=>i(e),onKeyDown:s=>{const t=o();if(!t||0===t.length)return;const n=t.indexOf(e);if(-1===n)return;let a=n;if("vertical"===c?"ArrowDown"===s.key?(s.preventDefault(),a=n<t.length-1?n+1:0):"ArrowUp"===s.key&&(s.preventDefault(),a=n>0?n-1:t.length-1):"ArrowRight"===s.key?(s.preventDefault(),a=n<t.length-1?n+1:0):"ArrowLeft"===s.key&&(s.preventDefault(),a=n>0?n-1:t.length-1),"Home"===s.key?(s.preventDefault(),a=0):"End"===s.key&&(s.preventDefault(),a=t.length-1)," "===s.key||"Enter"===s.key)return s.preventDefault(),void i(e);if(a!==n&&a>=0&&a<t.length){const e=t[a],s=document.getElementById(`zenpress-tab-${e}`);s&&(s.focus(),i(e))}},onFocus:()=>{l||i(e)},children:s||a})},_.TabPanel=({tabId:e,children:s})=>{const{selectedTabId:t}=(0,n.useContext)(h),a=(0,n.useRef)(null),r=t===e;return(0,n.useEffect)(()=>{r&&a.current&&(0===a.current.querySelectorAll('a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"]), input:not([disabled]), select:not([disabled]), textarea:not([disabled])').length?a.current.setAttribute("tabindex","0"):a.current.removeAttribute("tabindex"))},[r]),r?(0,p.jsx)("div",{ref:a,className:"zenpress-tabs__panel",role:"tabpanel",id:`zenpress-tab-panel-${e}`,"aria-labelledby":`zenpress-tab-${e}`,children:s}):(0,p.jsx)("div",{className:"zenpress-tabs__panel",role:"tabpanel",id:`zenpress-tab-panel-${e}`,"aria-labelledby":`zenpress-tab-${e}`,hidden:!0,children:s})};const z=()=>{const{snippets:e,setSnippets:s,adminBarEnabled:t,setAdminBarEnabled:o,saveSettings:h,isSaving:z}=(()=>{const[e,s]=(0,n.useState)({}),[t,r]=(0,n.useState)(!0),[o,p]=(0,n.useState)(!1),{createSuccessNotice:d,createErrorNotice:u}=(0,i.useDispatch)(c.store);return(0,n.useEffect)(()=>{l()({path:"/wp/v2/settings"}).then(e=>{const t=Array.isArray(e?.zenpress_active_snippets)?e.zenpress_active_snippets:[],n=window?.zenpressSnippetsMeta||{},a={};Object.keys(n).forEach(e=>{a[e]={...n[e],"enable-snippet":t.includes(e)}}),s(a),r(!1!==e?.zenpress_admin_bar_enabled)}).catch(()=>{u((0,a.__)("Failed to load settings.","zenpress"))})},[u]),{snippets:e,setSnippets:s,adminBarEnabled:t,setAdminBarEnabled:r,saveSettings:async()=>{p(!0);const s=Object.keys(e).filter(s=>e[s]?.["enable-snippet"]);try{await l()({path:"/wp/v2/settings",method:"POST",data:{zenpress_active_snippets:s,zenpress_admin_bar_enabled:t}}),d((0,a.__)("Settings saved.","zenpress"))}catch{u((0,a.__)("Failed to save settings.","zenpress"))}finally{p(!1)}},isSaving:o}})(),[f,m]=(0,n.useState)(),[g,v]=(0,n.useState)(null),{createSuccessNotice:x,createErrorNotice:y}=(0,i.useDispatch)(c.store),j=e=>{s(s=>{const t={};return Object.entries(s).forEach(([s,n])=>{const a=(Array.isArray(n?.preset)?n.preset:[]).includes(e);t[s]={...n,"enable-snippet":a}}),t})},w=e=>e?e.charAt(0).toUpperCase()+e.slice(1).toLowerCase():e,S=["core","gutenberg","woocommerce","ads-blocker","tools"],k={};Object.keys(e).forEach(s=>{const t=e[s],n=(t?.category||(0,a.__)("Uncategorized","zenpress")).toLowerCase(),r=(t?.subcategory||(0,a.__)("uncategorized","zenpress")).toLowerCase();k[n]||(k[n]={}),k[n][r]||(k[n][r]=[]),k[n][r].push({name:s,data:t})});const C=Object.keys(k).sort((e,s)=>{const t=S.indexOf(e.toLowerCase()),n=S.indexOf(s.toLowerCase());return-1!==t&&-1!==n?t-n:-1!==t?-1:-1!==n?1:e.localeCompare(s,void 0,{sensitivity:"base"})});(0,n.useEffect)(()=>{!f&&C.length>0&&m(C[0])},[f,C]);const E=async(e,s,t,n)=>{v(e);try{const e=await l()({path:s,method:"POST"});x(e?.message||t)}catch{y(n)}finally{v(null)}},A=()=>E("autoptimize","/zenpress/v1/autoconfig/autoptimize",(0,a.__)("Autoptimize has been configured.","zenpress"),(0,a.__)("Autoptimize autoconfig failed. Is Autoptimize installed and active?","zenpress")),N=()=>E("cache_enabler","/zenpress/v1/autoconfig/cache-enabler",(0,a.__)("Cache Enabler has been configured.","zenpress"),(0,a.__)("Cache Enabler autoconfig failed. Is Cache Enabler installed and active?","zenpress")),O=()=>E("sqlite_object_cache","/zenpress/v1/autoconfig/sqlite-object-cache",(0,a.__)("SQLite Object Cache has been configured.","zenpress"),(0,a.__)("SQLite Object Cache autoconfig failed. Is SQLite Object Cache installed and active?","zenpress"));return(0,n.useEffect)(()=>{const e=e=>{(e.ctrlKey||e.metaKey)&&"s"===e.key&&(e.preventDefault(),z||h())};return document.addEventListener("keydown",e),()=>{document.removeEventListener("keydown",e)}},[h,z]),(0,p.jsxs)("article",{className:"zenpress-row",children:[(0,p.jsxs)("section",{className:"zenpress-main",children:[(0,p.jsx)("div",{className:"zenpress-notices",children:(0,p.jsx)(b,{})}),(0,p.jsxs)("div",{className:"zenpress-panel",children:[(0,p.jsxs)(_,{orientation:"vertical",selectedTabId:f,onSelect:e=>{m(e),m(e)},children:[(0,p.jsx)(_.TabList,{children:C.map(e=>{const s=`zenpress-tabs__tab--category-${e.toLowerCase().replace(/\s+/g,"-")}`;return(0,p.jsx)(_.Tab,{tabId:e,title:w(e),className:s,children:w(e)},e)})}),C.map(e=>{const n=Object.keys(k[e]).sort();return(0,p.jsxs)(_.TabPanel,{tabId:e,children:[(0,p.jsx)("h2",{children:w(e)}),n.map(t=>(0,p.jsxs)("div",{className:`zenpress-subcategory zenpress-subcategory-${t.toLowerCase().replace(/\s+/g,"-")}`,children:[(0,p.jsx)("hr",{}),(0,p.jsx)("h3",{children:w(t)}),k[e][t].map(({name:e,data:t})=>(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))]},t)),"tools"===e&&Object.values(window?.zenpressIntegrationsActive||{}).some(Boolean)&&(0,p.jsxs)("div",{className:"zenpress-subcategory zenpress-subcategory-integrations",children:[(0,p.jsx)("hr",{}),(0,p.jsx)("h3",{children:(0,a.__)("Integrations","zenpress")}),(0,p.jsx)(d,{label:(0,a.__)("Show ZenPress admin bar button","zenpress"),value:t,onChange:()=>o(!t),help:(0,a.__)('Show a "ZenPress" item in the admin bar with "Clear caches". When enabled, integration buttons (e.g. Autoptimize) are hidden.',"zenpress")}),window?.zenpressIntegrationsActive?.autoptimize&&(0,p.jsxs)("div",{className:"zenpress-autoconfig-actions",children:[(0,p.jsx)(r.Button,{variant:"secondary",onClick:A,disabled:null!==g,__next40pxDefaultSize:!0,children:"autoptimize"===g?(0,a.__)("Applying…","zenpress"):(0,a.__)("One-click autoconfig Autoptimize","zenpress")}),(0,p.jsx)("p",{className:"zenpress-autoconfig-help",children:(0,a.__)("Apply recommended Autoptimize settings (optimize JS/CSS, aggregate CSS, static files, 404 fallbacks; disable defer, HTML optimize, optimize for logged-in, per post/page). Only works if Autoptimize is active.","zenpress")})]}),window?.zenpressIntegrationsActive?.cache_enabler&&(0,p.jsxs)("div",{className:"zenpress-autoconfig-actions",children:[(0,p.jsx)(r.Button,{variant:"secondary",onClick:N,disabled:null!==g,__next40pxDefaultSize:!0,children:"cache_enabler"===g?(0,a.__)("Applying…","zenpress"):(0,a.__)("One-click autoconfig Cache Enabler","zenpress")}),(0,p.jsx)("p",{className:"zenpress-autoconfig-help",children:(0,a.__)("Apply recommended Cache Enabler settings. Only works if Cache Enabler is active.","zenpress")})]}),window?.zenpressIntegrationsActive?.sqlite_object_cache&&(0,p.jsxs)("div",{className:"zenpress-autoconfig-actions",children:[(0,p.jsx)(r.Button,{variant:"secondary",onClick:O,disabled:null!==g,__next40pxDefaultSize:!0,children:"sqlite_object_cache"===g?(0,a.__)("Applying…","zenpress"):(0,a.__)("One-click autoconfig SQLite Object Cache","zenpress")}),(0,p.jsx)("p",{className:"zenpress-autoconfig-help",children:(0,a.__)("Apply recommended SQLite Object Cache settings. Only works if SQLite Object Cache is active.","zenpress")})]})]})]},e)})]}),(0,p.jsxs)("div",{className:"zenpress-actions",children:[(0,p.jsxs)("div",{className:"zenpress-actions-bulk",children:[(0,p.jsx)(r.Button,{variant:"tertiary",onClick:()=>{s(e=>{const s={};return Object.keys(e).forEach(t=>{s[t]={...e[t],"enable-snippet":!0}}),s})},__next40pxDefaultSize:!0,children:(0,a.__)("Enable all actions","zenpress")}),(0,p.jsx)(r.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,a.__)("Disable all actions","zenpress")})]}),(0,p.jsx)(u,{onClick:h,isBusy:z})]})]})]}),(0,p.jsx)("aside",{className:"zenpress-sidebar",children:(0,p.jsx)("div",{className:"zenpress-presets",children:(0,p.jsxs)("div",{className:"zenpress-presets-description",children:[(0,p.jsx)("h2",{children:(0,a.__)("Pick configuration preset","zenpress")}),(0,p.jsx)("p",{children:(0,a.__)("Don't know which features to enable? Quickly configure ZenPress by selecting a preset that matches your site type. Each preset enables optimized features for your specific use case.","zenpress")}),(0,p.jsx)("hr",{}),(0,p.jsxs)("h3",{children:["🖼️ ",(0,a.__)("Corporate website","zenpress")]}),(0,p.jsx)("p",{children:(0,a.__)("Optimized for business sites and portfolios. Focuses on security, performance, and removing unnecessary features like RSS feeds and author archives.","zenpress")}),(0,p.jsx)(r.Button,{variant:"secondary",onClick:()=>j("corporate-website"),__next40pxDefaultSize:!0,children:(0,a.__)("Enable","zenpress")}),(0,p.jsx)("hr",{}),(0,p.jsxs)("h3",{children:[" 📰 ",(0,a.__)("Blog","zenpress")]}),(0,p.jsx)("p",{children:(0,a.__)("Tailored for content-focused blogs. Includes performance and security optimizations while preserving essential blog features like RSS feeds.","zenpress")}),(0,p.jsx)(r.Button,{variant:"secondary",onClick:()=>j("blog"),__next40pxDefaultSize:!0,children:(0,a.__)("Enable","zenpress")}),(0,p.jsx)("hr",{}),(0,p.jsxs)("h3",{children:["🛒 ",(0,a.__)("E-commerce","zenpress")]}),(0,p.jsx)("p",{children:(0,a.__)("Designed for WooCommerce stores. Includes all performance and security features plus WooCommerce-specific optimizations for faster checkout.","zenpress")}),(0,p.jsx)(r.Button,{variant:"secondary",onClick:()=>j("ecommerce"),__next40pxDefaultSize:!0,children:(0,a.__)("Enable","zenpress")})]})})})]})};t()(()=>{const e=document.getElementById("zenpress-settings");e&&(0,n.createRoot)(e).render((0,p.jsx)(z,{}))})})();
  • zenpress/trunk/assets/src/js/hooks/useSettings.js

    r3448585 r3451904  
    99 *
    1010 * @return {Object} Settings state and actions.
    11  * @property {Object}   snippets     - Current snippets with metadata.
    12  * @property {Function} setSnippets  - Setter to update snippets state.
    13  * @property {Function} saveSettings - Function to persist settings to REST API.
    14  * @property {boolean}  isSaving     - Whether settings are currently being saved.
     11 * @property {Object}   snippets           - Current snippets with metadata.
     12 * @property {Function} setSnippets        - Setter to update snippets state.
     13 * @property {boolean}  adminBarEnabled    - Whether the ZenPress admin bar is enabled.
     14 * @property {Function} setAdminBarEnabled - Setter for admin bar enabled.
     15 * @property {Function} saveSettings       - Function to persist settings to REST API.
     16 * @property {boolean}  isSaving           - Whether settings are currently being saved.
    1517 */
    1618export const useSettings = () => {
    1719    const [snippets, setSnippets] = useState({});
     20    const [adminBarEnabled, setAdminBarEnabled] = useState(true);
    1821    const [isSaving, setIsSaving] = useState(false);
    1922    const { createSuccessNotice, createErrorNotice } =
     
    3841
    3942                setSnippets(snippetsData);
     43                setAdminBarEnabled(
     44                    settings?.zenpress_admin_bar_enabled !== false
     45                );
    4046            })
    4147            .catch(() => {
     
    5561                path: '/wp/v2/settings',
    5662                method: 'POST',
    57                 data: { zenpress_active_snippets: active },
     63                data: {
     64                    zenpress_active_snippets: active,
     65                    zenpress_admin_bar_enabled: adminBarEnabled,
     66                },
    5867            });
    5968            createSuccessNotice(__('Settings saved.', 'zenpress'));
     
    6574    };
    6675
    67     return { snippets, setSnippets, saveSettings, isSaving };
     76    return {
     77        snippets,
     78        setSnippets,
     79        adminBarEnabled,
     80        setAdminBarEnabled,
     81        saveSettings,
     82        isSaving,
     83    };
    6884};
  • zenpress/trunk/assets/src/js/pages/SettingsPage.js

    r3448585 r3451904  
    22import { __ } from '@wordpress/i18n';
    33import { Button } from '@wordpress/components';
     4import { useDispatch } from '@wordpress/data';
     5import { store as noticesStore } from '@wordpress/notices';
     6import apiFetch from '@wordpress/api-fetch';
    47import { useSettings } from '../hooks/useSettings';
    58import { SnippetToggleControl } from '../components/SnippetToggleControl';
     
    1417 */
    1518export const SettingsPage = () => {
    16     const { snippets, setSnippets, saveSettings, isSaving } = useSettings();
     19    const {
     20        snippets,
     21        setSnippets,
     22        adminBarEnabled,
     23        setAdminBarEnabled,
     24        saveSettings,
     25        isSaving,
     26    } = useSettings();
    1727    const [selectedTabId, setSelectedTabId] = useState();
     28    const [autoconfigBusy, setAutoconfigBusy] = useState(null);
     29    const { createSuccessNotice, createErrorNotice } =
     30        useDispatch(noticesStore);
    1831
    1932    const handleToggleChange = (snippetName) => {
     
    133146        setSelectedTabId(tabName);
    134147    };
     148
     149    const runAutoconfig = async (
     150        integrationKey,
     151        path,
     152        successMessage,
     153        errorMessage
     154    ) => {
     155        setAutoconfigBusy(integrationKey);
     156        try {
     157            const response = await apiFetch({
     158                path,
     159                method: 'POST',
     160            });
     161            createSuccessNotice(response?.message || successMessage);
     162        } catch {
     163            createErrorNotice(errorMessage);
     164        } finally {
     165            setAutoconfigBusy(null);
     166        }
     167    };
     168
     169    const handleAutoconfigAutoptimize = () =>
     170        runAutoconfig(
     171            'autoptimize',
     172            '/zenpress/v1/autoconfig/autoptimize',
     173            __('Autoptimize has been configured.', 'zenpress'),
     174            __(
     175                'Autoptimize autoconfig failed. Is Autoptimize installed and active?',
     176                'zenpress'
     177            )
     178        );
     179
     180    const handleAutoconfigCacheEnabler = () =>
     181        runAutoconfig(
     182            'cache_enabler',
     183            '/zenpress/v1/autoconfig/cache-enabler',
     184            __('Cache Enabler has been configured.', 'zenpress'),
     185            __(
     186                'Cache Enabler autoconfig failed. Is Cache Enabler installed and active?',
     187                'zenpress'
     188            )
     189        );
     190
     191    const handleAutoconfigSqliteObjectCache = () =>
     192        runAutoconfig(
     193            'sqlite_object_cache',
     194            '/zenpress/v1/autoconfig/sqlite-object-cache',
     195            __('SQLite Object Cache has been configured.', 'zenpress'),
     196            __(
     197                'SQLite Object Cache autoconfig failed. Is SQLite Object Cache installed and active?',
     198                'zenpress'
     199            )
     200        );
    135201
    136202    // Add keyboard shortcuts and ensure toggles are keyboard accessible
     
    221287                                        </div>
    222288                                    ))}
     289                                    {category === 'tools' &&
     290                                        Object.values(
     291                                            window?.zenpressIntegrationsActive ||
     292                                                {}
     293                                        ).some(Boolean) && (
     294                                            <div className="zenpress-subcategory zenpress-subcategory-integrations">
     295                                                <hr />
     296                                                <h3>
     297                                                    {__(
     298                                                        'Integrations',
     299                                                        'zenpress'
     300                                                    )}
     301                                                </h3>
     302                                                <SnippetToggleControl
     303                                                    label={__(
     304                                                        'Show ZenPress admin bar button',
     305                                                        'zenpress'
     306                                                    )}
     307                                                    value={adminBarEnabled}
     308                                                    onChange={() =>
     309                                                        setAdminBarEnabled(
     310                                                            !adminBarEnabled
     311                                                        )
     312                                                    }
     313                                                    help={__(
     314                                                        'Show a "ZenPress" item in the admin bar with "Clear caches". When enabled, integration buttons (e.g. Autoptimize) are hidden.',
     315                                                        'zenpress'
     316                                                    )}
     317                                                />
     318                                                {window
     319                                                    ?.zenpressIntegrationsActive
     320                                                    ?.autoptimize && (
     321                                                    <div className="zenpress-autoconfig-actions">
     322                                                        <Button
     323                                                            variant="secondary"
     324                                                            onClick={
     325                                                                handleAutoconfigAutoptimize
     326                                                            }
     327                                                            disabled={
     328                                                                autoconfigBusy !==
     329                                                                null
     330                                                            }
     331                                                            __next40pxDefaultSize
     332                                                        >
     333                                                            {autoconfigBusy ===
     334                                                            'autoptimize'
     335                                                                ? __(
     336                                                                        'Applying…',
     337                                                                        'zenpress'
     338                                                                    )
     339                                                                : __(
     340                                                                        'One-click autoconfig Autoptimize',
     341                                                                        'zenpress'
     342                                                                    )}
     343                                                        </Button>
     344                                                        <p className="zenpress-autoconfig-help">
     345                                                            {__(
     346                                                                'Apply recommended Autoptimize settings (optimize JS/CSS, aggregate CSS, static files, 404 fallbacks; disable defer, HTML optimize, optimize for logged-in, per post/page). Only works if Autoptimize is active.',
     347                                                                'zenpress'
     348                                                            )}
     349                                                        </p>
     350                                                    </div>
     351                                                )}
     352                                                {window
     353                                                    ?.zenpressIntegrationsActive
     354                                                    ?.cache_enabler && (
     355                                                    <div className="zenpress-autoconfig-actions">
     356                                                        <Button
     357                                                            variant="secondary"
     358                                                            onClick={
     359                                                                handleAutoconfigCacheEnabler
     360                                                            }
     361                                                            disabled={
     362                                                                autoconfigBusy !==
     363                                                                null
     364                                                            }
     365                                                            __next40pxDefaultSize
     366                                                        >
     367                                                            {autoconfigBusy ===
     368                                                            'cache_enabler'
     369                                                                ? __(
     370                                                                        'Applying…',
     371                                                                        'zenpress'
     372                                                                    )
     373                                                                : __(
     374                                                                        'One-click autoconfig Cache Enabler',
     375                                                                        'zenpress'
     376                                                                    )}
     377                                                        </Button>
     378                                                        <p className="zenpress-autoconfig-help">
     379                                                            {__(
     380                                                                'Apply recommended Cache Enabler settings. Only works if Cache Enabler is active.',
     381                                                                'zenpress'
     382                                                            )}
     383                                                        </p>
     384                                                    </div>
     385                                                )}
     386                                                {window
     387                                                    ?.zenpressIntegrationsActive
     388                                                    ?.sqlite_object_cache && (
     389                                                    <div className="zenpress-autoconfig-actions">
     390                                                        <Button
     391                                                            variant="secondary"
     392                                                            onClick={
     393                                                                handleAutoconfigSqliteObjectCache
     394                                                            }
     395                                                            disabled={
     396                                                                autoconfigBusy !==
     397                                                                null
     398                                                            }
     399                                                            __next40pxDefaultSize
     400                                                        >
     401                                                            {autoconfigBusy ===
     402                                                            'sqlite_object_cache'
     403                                                                ? __(
     404                                                                        'Applying…',
     405                                                                        'zenpress'
     406                                                                    )
     407                                                                : __(
     408                                                                        'One-click autoconfig SQLite Object Cache',
     409                                                                        'zenpress'
     410                                                                    )}
     411                                                        </Button>
     412                                                        <p className="zenpress-autoconfig-help">
     413                                                            {__(
     414                                                                'Apply recommended SQLite Object Cache settings. Only works if SQLite Object Cache is active.',
     415                                                                'zenpress'
     416                                                            )}
     417                                                        </p>
     418                                                    </div>
     419                                                )}
     420                                            </div>
     421                                        )}
    223422                                </Tabs.TabPanel>
    224423                            );
  • zenpress/trunk/assets/src/scss/pages/_settings.scss

    r3412245 r3451904  
    197197            }
    198198        }
     199
     200        &-integrations {
     201            h3::before {
     202                content: '🔌';
     203            }
     204        }
     205    }
     206
     207    &-autoconfig-actions {
     208        margin-top: 1em;
     209    }
     210
     211    &-autoconfig-help {
     212        margin-top: 0.5em;
     213        margin-bottom: 0;
     214        font-size: 0.9em;
     215        opacity: 0.9;
    199216    }
    200217}
  • zenpress/trunk/inc/admin/enqueue.php

    r3448585 r3451904  
    66
    77/**
    8  * Enqueue scripts and styles used by the plugin in admin area.
    9  *
    10  * @param string $admin_page Current admin page hook.
    11  * @return void
     8 * Enqueues script and style on ZenPress settings page only.
    129 */
    1310add_action('admin_enqueue_scripts', 'zenpress_admin_enqueue_scripts');
     
    4946
    5047/**
    51  * Localize translated snippet metadata for use in JavaScript.
    52  *
    53  * @param string $admin_page Current admin page hook.
    54  * @return void
     48 * Localizes zenpressSnippetsMeta and zenpressIntegrationsActive on ZenPress settings page.
    5549 */
    5650add_action('admin_enqueue_scripts', 'zenpress_localize_snippets_meta');
     
    7367
    7468    wp_localize_script('zenpress-scripts', 'zenpressSnippetsMeta', $snippets);
     69    wp_localize_script('zenpress-scripts', 'zenpressIntegrationsActive', ZenPress_Integrations::get_active_integrations_for_ui());
    7570}
  • zenpress/trunk/inc/admin/links.php

    r3372200 r3451904  
    66
    77/**
    8  * Add a settings link on the plugins list page.
    9  *
    10  * @param array $links Existing plugin action links.
    11  * @return array Modified plugin action links.
     8 * Adds "Settings" to plugin action links on Plugins screen.
    129 */
    1310add_filter('plugin_action_links_' . plugin_basename(ZENPRESS_PLUGIN_FILE), 'zenpress_add_settings_link');
     
    2522
    2623/**
    27  * Add extra links under the plugin description on the plugins page.
    28  *
    29  * @param array  $links Existing row meta links.
    30  * @param string $file  Current plugin file.
    31  * @return array Modified row meta links.
     24 * Adds Changelog, Docs, Support to plugin row meta for ZenPress.
    3225 */
    3326add_filter('plugin_row_meta', 'zenpress_plugin_row_meta', 10, 2);
  • zenpress/trunk/inc/admin/menu.php

    r3412245 r3451904  
    66
    77/**
    8  * Register ZenPress options page under the Settings menu.
    9  *
    10  * @return void
     8 * Adds ZenPress under Settings.
    119 */
    1210add_action('admin_menu', 'zenpress_add_option_page');
     
    2220
    2321/**
    24  * Render ZenPress options page content.
    25  *
    26  * @return void
     22 * Outputs ZenPress settings page (shell; React app mounts in #zenpress-settings).
    2723 */
    2824function zenpress_options_page(): void {
  • zenpress/trunk/inc/core/constants.php

    r3448604 r3451904  
    11<?php
    22/**
    3  * ZenPress constants
     3 * Plugin path constants.
     4 *
    45 * @package zenpress
    56 */
  • zenpress/trunk/inc/core/metadata.php

    r3448585 r3451904  
    66
    77/**
    8  * Extract snippet metadata from its meta file.
     8 * Loads and sanitizes snippet metadata from inc/snippets/meta/{$snippet_name}.meta.php.
    99 *
    10  * @param string $snippet_name Snippet base name (without extension).
    11  * @return array<string,mixed> Sanitized metadata (title, description, category, weight, preset).
     10 * @param string $snippet_name Snippet base name (no extension).
     11 * @return array<string, mixed> title, description, category, subcategory, weight, preset.
    1212 */
    1313function zenpress_extract_snippet_metadata(string $snippet_name): array {
     
    2222
    2323    $file = ZENPRESS_PLUGIN_DIR . 'inc/snippets/meta/' . sanitize_file_name($snippet_name) . '.meta.php';
    24     $data = is_file($file) ? include $file : [];
     24    $data = [];
     25    if (is_file($file)) {
     26        try {
     27            $data = include $file;
     28        } catch (\Throwable $e) {
     29            $data = [];
     30        }
     31    }
    2532    $metadata = array_merge($defaults, is_array($data) ? $data : []);
    2633
  • zenpress/trunk/inc/core/sanitize.php

    r3448585 r3451904  
    66
    77/**
    8  * Sanitize the list of active snippets.
     8 * Sanitizes zenpress_active_snippets option to an array of file-safe base names.
    99 *
    10  * @param mixed $value Option value.
    11  * @return array<string> Sanitized base names.
     10 * @param mixed $value Raw option value.
     11 * @return array<string>
    1212 */
    1313function zenpress_sanitize_snippets_option(mixed $value): array {
  • zenpress/trunk/inc/settings/loader.php

    r3448585 r3451904  
    66
    77/**
    8  * Load all active snippets.
     8 * Includes active snippet files from the given folder. Skips path traversal and disabled-by-constant snippets.
    99 *
    10  * @param string $folder Relative folder path for snippets.
     10 * @param string $folder Relative path under plugin dir (default: inc/snippets/functions/).
    1111 * @return array<string> Loaded snippet base names.
    1212 */
     
    3030        $constant = 'ZENPRESS_' . strtoupper(str_replace(['-', '_'], '_', $name));
    3131        if (is_file($file) && (!defined($constant) || constant($constant) !== false)) {
    32             include_once $file;
    33             $loaded[] = $name;
     32            try {
     33                include_once $file;
     34                $loaded[] = $name;
     35            } catch (\Throwable $e) {
     36                continue;
     37            }
    3438        }
    3539    }
  • zenpress/trunk/inc/settings/options.php

    r3448585 r3451904  
    66
    77/**
    8  * Register option to store active snippets.
     8 * Registers zenpress_active_snippets and zenpress_admin_bar_enabled (REST + sanitize).
    99 */
    1010add_action('init', 'zenpress_register_snippet_settings');
     
    2525        ]
    2626    );
     27
     28    register_setting(
     29        'options',
     30        'zenpress_admin_bar_enabled',
     31        [
     32            'type' => 'boolean',
     33            'default' => true,
     34            'sanitize_callback' => 'zenpress_sanitize_admin_bar_enabled',
     35            'show_in_rest' => [
     36                'schema' => ['type' => 'boolean'],
     37            ],
     38        ]
     39    );
    2740}
     41
     42/**
     43 * Sanitizes zenpress_admin_bar_enabled to bool.
     44 */
     45function zenpress_sanitize_admin_bar_enabled(mixed $value): bool {
     46    return (bool) $value;
     47}
  • zenpress/trunk/inc/snippets/functions/protect-wp-login.php

    r3448585 r3451904  
    1010});
    1111
    12 // Limit login attempts
     12// Limit login attempts (only when a valid IP is available to avoid site-wide lockout)
    1313add_filter('authenticate', static function (mixed $user, string $username, string $password): mixed {
    14     $MAX_LOGIN_ATTEMPTS = 5;
    15     $BLOCK_DURATION = 300; // 5 minutes
    16 
    1714    $ipAddress = filter_var(
    1815        wp_unslash($_SERVER['REMOTE_ADDR'] ?? ''),
    1916        FILTER_VALIDATE_IP
    20     ) ?: 'unknown';
     17    );
     18    if ($ipAddress === false) {
     19        return $user;
     20    }
    2121
     22    $MAX_LOGIN_ATTEMPTS = 5;
     23    $BLOCK_DURATION = 300; // 5 minutes
    2224    $blockKey = 'zenpress_login_block_' . $ipAddress;
    2325    $attemptKey = 'zenpress_login_attempts_' . $ipAddress;
  • zenpress/trunk/readme.txt

    r3448604 r3451904  
    55Requires at least: 6.0
    66Tested up to: 6.9
    7 Stable tag: 2.2.1
    8 Requires PHP: 8.3
     7Stable tag: 2.2.3
     8Requires PHP: 8.1
    99License: GPLv2 or later
    1010License URI: https://www.gnu.org/licenses/gpl-2.0.html/
     
    4141* Native WordPress interface, benefits from Gutenberg's new features and the site editor.
    4242
    43 = Core - Performance =
     43= Core =
    4444
    4545* Disable adjacent posts link tags.
     
    5959* Disable Password Strength Meter.
    6060* Disable WordPress default lazy loading.
    61 
    62 = Core - Security =
    63 
    6461* Block user enumeration.
    6562* Disable application passwords.
     
    6966* Disable XML-RPC and remove RSD link.
    7067* Hide WordPress version.
    71 
    72 = Core - User Interface =
    73 
    7468* Clean up the WordPress admin bar.
    7569* Disable the login language selector.
     
    7872* Remove "Thanks for using WordPress" in footer.
    7973
    80 = WooCommerce - Performance =
     74= WooCommerce =
    8175* Disable WooCommerce cart fragments script.
    8276* Disable WooCommerce scripts and styles on non-WooCommerce pages.
     
    8478* Disable WooCommerce widgets.
    8579* Remove WooCommerce default block patterns.
    86 
    87 = WooCommerce - Security =
    8880* Hide WooCommerce version.
    8981
    90 = Gutenberg - Performance =
     82= Gutenberg =
    9183* Remove WordPress default remote block patterns.
    9284* Separate loading of core block styles.
    93 
    94 = Gutenberg - User Interface =
    9585* Disable default pattern categories in site editor.
    9686
    97 = Ads-blocker - User Interface =
     87= Ads-blocker =
    9888* Clean up the WordPress Dashboard.
    9989
    100 = Tools - Security =
     90= Tools =
    10191* Protect the wp-login form from brute force attacks.
     92* Toggle "Show ZenPress admin bar button" (clear caches from the admin bar when at least one integration is active).
     93
     94= Integrations =
     95
     96ZenPress integrates with Cache Enabler, Autoptimize, and SQLite Object Cache. When any of these plugins is active, the Tools tab shows integration status and one-click autoconfig actions.
     97
     98* Admin bar: One "Clear all caches" button (dashicon) in the admin bar, with sub-items to clear page cache (Cache Enabler), static assets (Autoptimize), or object cache (SQLite Object Cache) separately. The ZenPress button replaces the third-party cache buttons when the ZenPress admin bar is enabled. You can hide it via Settings > ZenPress > Tools.
     99* Autoptimize: One-click autoconfig enables recommended options (JS/CSS/aggregate/nogzip/fallback on; defer/HTML/logged-in/meta off) and clears the Autoptimize cache.
     100* Cache Enabler: One-click autoconfig enables clear site cache on post or plugin changes, WebP support, Gzip compression, and minify HTML (excluding inline CSS/JS), then clears the page cache.
     101* SQLite Object Cache: One-click autoconfig enables the "Use APCu" option in the plugin settings when the APCu extension is available (no wp-config editing; the plugin may write its constant when its own settings are saved).
    102102
    103103= Presets =
     
    115115== Roadmap ==
    116116
    117 = Global =
    118117* Additional presets for specific use cases.
    119118* Documentation pages with detailed guides.
    120 
    121 = Security =
    122119* Manage Heartbeat API (frontend + backend + admin whitelist).
    123 
    124 = User Interface =
    125120* Remove "site health" page.
    126121* Remove "Privacy tools".
    127 
    128 = WooCommerce =
    129122* Disable WooCommerce tracking.
    130123* Disable marketing hub.
     
    133126* Disable WooCommerce blocks.
    134127* Disable WooCommerce promo emails.
    135 
    136 = Plugins =
    137128* Disable CF7 CSS & JS.
    138129* Disable Elementor bloat.
     
    204195Nice ! If you can't find anything in the roadmap, feel free to submit your suggestion on the support page! If you know how to code, you can even contribute on GitHub.
    205196
     197== Hooks & filters ==
     198
     199For developers: ZenPress exposes the following action and filters for extending or bypassing behavior.
     200
     201= Action =
     202* `zenpress_caches_clear` – Fired when the user clears caches from the ZenPress admin bar. Integrations (e.g. Autoptimize) hook into this to clear their own caches. You can add custom cache clear logic with `add_action('zenpress_caches_clear', 'your_callback');`.
     203
     204= Filters (Disable REST API snippet) =
     205* `zenpress_disable_wp_rest_api_post_var` – Allow unauthenticated REST access when a specific POST key is present (e.g. for webhooks). Return a string or array of key names. Use non-guessable values only.
     206* `zenpress_disable_wp_rest_api_server_var` – Allow unauthenticated REST access when `REQUEST_URI` matches a specific value. Return a string or array. Use non-guessable values only.
     207
    206208== Changelog ==
     209
     210= 2.2.3 =
     211- Integrations: Cache Enabler one-click autoconfig (clear on post/plugin, WebP, Gzip, minify HTML excl. inline CSS/JS).
     212- Integrations: SQLite Object Cache one-click autoconfig (enable "Use APCu" option when APCu available; no wp-config editing by ZenPress).
     213- Integrations: Admin bar "Clear all caches" button now uses dashicons-trash icon.
     214- Defensive: REST and AJAX handlers wrap integration calls in try/catch; failed autoconfig or cache clear returns 500 with message instead of fatal.
     215- Defensive: get_active_integrations_for_ui() wraps ReflectionClass in try/catch so one missing integration does not break the settings UI.
     216- Defensive: Cache Enabler autoconfig ensures option value is array before merge (corrupted option no longer triggers warning).
     217- Defensive: Metadata and snippet loader wrap include in try/catch so a single bad meta file or snippet does not fatal the site.
     218- Defensive: Protect wp-login skips rate limiting when REMOTE_ADDR is missing or invalid to avoid site-wide lockout (e.g. CLI or proxy).
     219- Defensive: Autoptimize clear_cache and autoconfig check method_exists before calling third-party API.
     220- Docblocks: Reviewed and tightened docblocks across inc/ (file headers, classes, methods) for coherence, readability, and conciseness; removed redundant @param/@return where type is obvious.
     221- Lint: PHPStan and PHP CS Fixer fixes (autoptimize method_exists ignore, protect-wp-login strict comparison).
     222
     223= 2.2.2 =
     224- Integrations: Admin bar and one-click autoconfig (e.g. Autoptimize) in Tools tab; visible only when at least one integration is active.
     225- Documentation: Added Hooks & filters section in readme; Integrations section in workflow.md; config comments for PHPStan and PHP CS Fixer.
     226- Version alignment: Stable tag and plugin header set to 2.2.2.
    207227
    208228= 2.2.1 =
     
    338358== Upgrade Notice ==
    339359
     360= 2.2.3 =
     361- Integrations: Cache Enabler and SQLite Object Cache one-click autoconfig; admin bar trash icon; defensive fixes and docblock cleanup.
     362
     363= 2.2.2 =
     364- Integrations: ZenPress admin bar and one-click autoconfig in Tools tab (Autoptimize). Documentation updates.
     365
    340366= 2.2.1 =
    341367- Security and code quality improvements. Recommended update.
    342368
    343369= 2.2.0 =
    344 - Breaking: PHP 8.3 is now required (PHP 7.4 support dropped). Major code modernization with improved type safety and performance.
     370- Breaking: PHP 8.1 is now required (PHP 7.4 support dropped). Major code modernization with improved type safety and performance.
    345371- Security: HTTP 403 on login block, path traversal guard in snippet loader, and in-code docs for REST API bypass filters.
    346372
  • zenpress/trunk/zenpress.php

    r3448604 r3451904  
    1212 * Plugin Name: ZenPress - Optimize & Secure
    1313 * Description: Easily speed up and strengthen your WordPress site by cleaning out unnecessary features and protecting weak points.
    14  * Version: 2.2.1
     14 * Version: 2.2.2
    1515 * Plugin URI: https://wordpress.org/plugins/zenpress/
    1616 * Author: Quentin Le Duff
     
    2020 * Requires at least: 6.0
    2121 * Tested up to: 6.9
    22  * Requires PHP: 8.3
     22 * Requires PHP: 8.1
    2323 * License URI: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html/
    2424 * License: GPL v2 or later
     
    4747require_once __DIR__ . '/inc/core/sanitize.php';
    4848
     49// Integrations (one file per plugin: handlers + autoconfig)
     50require_once __DIR__ . '/inc/classes/autoptimize.php';
     51require_once __DIR__ . '/inc/classes/cache-enabler.php';
     52require_once __DIR__ . '/inc/classes/sqlite-object-cache.php';
     53require_once __DIR__ . '/inc/classes/integrations.php';
     54
    4955// Admin UI
    5056require_once __DIR__ . '/inc/admin/enqueue.php';
Note: See TracChangeset for help on using the changeset viewer.