This commit is contained in:
2026-07-02 15:54:39 -06:00
commit 9883323161
17470 changed files with 4470592 additions and 0 deletions
@@ -0,0 +1,90 @@
<?php // Pressable Cache Management - Admin Menu
// disable direct file access
if (!defined('ABSPATH'))
{
exit;
}
// add sub-level administrative menu
function pressable_cache_management_add_sublevel_menu()
{
/*
add_submenu_page(
'options-general.php',
string $parent_slug,
string $page_title,
string $menu_title,
string $capability,
string $menu_slug,
callable $function = ''
);
*/
add_submenu_page('admin.php', '', 'Pressable Cache Management', 'manage_options', 'pressable_cache_management', 'pressable_cache_management_display_settings_page');
}
add_action('admin_menu', 'pressable_cache_management_add_sublevel_menu');
// add top-level administrative menu
function pressable_cache_management_add_toplevel_menu()
{
/*
add_menu_page(
string $page_title,
string $menu_title,
string $capability,
string $menu_slug,
callable $function = '',
string $icon_url = '',
int $position = null
)
*/
//Check if branding Pressable branding is enabled or disabled
$remove_pressable_branding_tab_options = false;
$remove_pressable_branding_tab_options = get_option('remove_pressable_branding_tab_options');
if ($remove_pressable_branding_tab_options && 'disable' == $remove_pressable_branding_tab_options['branding_on_off_radio_button'] )
{
add_menu_page(esc_html__('Cache Management Settings', 'pressable_cache_management') , esc_html__('Cache Control', 'pressable_cache_management') , 'manage_options', 'pressable_cache_management', 'pressable_cache_management_display_settings_page',
plugin_dir_url(__FILE__) . '/assets/img/cache_control.png', 2);
} else {
add_menu_page(esc_html__('Pressable Cache Management Settings', 'pressable_cache_management') , esc_html__('Pressable CM', 'pressable_cache_management') , 'manage_options', 'pressable_cache_management', 'pressable_cache_management_display_settings_page',
plugin_dir_url(__FILE__) . '/assets/img/pressable-icon-primary.svg', 2);
}
}
add_action('admin_menu', 'pressable_cache_management_add_toplevel_menu');
//Display admin notices for top level menu
function plugin_admin_notice()
{
//get the current screen
$screen = get_current_screen();
//return if not plugin settings page
if ($screen->id !== 'toplevel_page_pressable_cache_management') return;
// Settings saved notice is handled by settings-page.php (pcm_branded_settings_saved_notice)
// which outputs a single branded card. This block intentionally left empty.
}
add_action('admin_notices', 'plugin_admin_notice');
Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72.31 72.31"><defs><style>.cls-1{fill:#fff;}</style></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g id="pressable-icon-primary-reverse"><polygon class="cls-1" points="0 0 0 0.03 0.03 0 0 0"/><path class="cls-1" d="M37,15.8H26.25V35.57H37c8.57,0,10.63-1.78,10.63-9.29V25.06C47.59,17.58,45.53,15.8,37,15.8Z"/><path class="cls-1" d="M0,0,0,0V72.31H46.34l26-26V0ZM54.15,26.28c0,11.71-4.42,15-17.19,15H26.25V60.41a1.69,1.69,0,0,1-1.72,1.86c-1.5,0-4.7-.42-4.7-1.28V11.93c0-1.56.78-1.86,1.78-1.86H37c13,0,17.19,3.56,17.19,15Z"/></g></g></g></svg>

After

Width:  |  Height:  |  Size: 628 B

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12pt" height="12pt" viewBox="0 0 12 12" version="1.1">
<g id="surface1">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 0 0 L 0 0.0078125 L 0.0078125 0 Z M 0 0 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 6.140625 2.621094 L 4.355469 2.621094 L 4.355469 5.902344 L 6.140625 5.902344 C 7.5625 5.902344 7.902344 5.605469 7.902344 4.363281 L 7.902344 4.160156 C 7.898438 2.917969 7.554688 2.621094 6.140625 2.621094 Z M 6.140625 2.621094 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 0 0 L 0 12 L 7.691406 12 L 12.003906 7.683594 L 12.003906 0 Z M 8.984375 4.363281 C 8.984375 6.304688 8.253906 6.847656 6.136719 6.847656 L 4.355469 6.847656 L 4.355469 10.027344 C 4.363281 10.105469 4.339844 10.183594 4.285156 10.246094 C 4.226562 10.304688 4.152344 10.335938 4.074219 10.332031 C 3.824219 10.332031 3.289062 10.261719 3.289062 10.121094 L 3.289062 1.980469 C 3.289062 1.71875 3.417969 1.667969 3.585938 1.667969 L 6.140625 1.667969 C 8.296875 1.667969 8.996094 2.261719 8.996094 4.160156 Z M 8.984375 4.363281 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 376.99 72.21">
<defs>
<style>
.cls-1 {
fill: #020124;
}
.cls-1, .cls-2 {
stroke-width: 0px;
}
.cls-2 {
fill: #dd3a03;
}
</style>
</defs>
<g id="Layer_1-2" data-name="Layer 1">
<g id="pressable-logo-v8">
<g>
<path class="cls-2" d="M40.07,24.08c-1.2-.94-3.05-1.4-5.54-1.4h-4.18v12.1h4.18c2.35,0,4.16-.46,5.44-1.37,1.27-.91,1.91-2.45,1.91-4.61s-.6-3.78-1.8-4.72Z"/>
<path class="cls-2" d="M68.69,0H3.52C1.58,0,0,1.58,0,3.52v65.18c0,1.94,1.58,3.52,3.52,3.52h37.89l30.81-30.81V3.52c0-1.94-1.58-3.52-3.52-3.52ZM49.03,40.64c-3.14,2.81-7.93,4.21-14.36,4.21h-4.32v13.82c0,.56-.45,1.01-1.01,1.01h-9.86c-.56,0-1.01-.45-1.01-1.01V13.53c0-.56.45-1.01,1.01-1.01h15.12c6.77,0,11.65,1.39,14.65,4.18,3,2.79,4.5,6.82,4.5,12.1s-1.57,9.04-4.72,11.84Z"/>
</g>
<g>
<path class="cls-1" d="M96.48,59.69c-.62,0-.94-.31-.94-.94V13.46c0-.62.31-.94.94-.94h14.26c6.53,0,11.28,1.34,14.26,4.03,2.98,2.69,4.46,6.62,4.46,11.81s-1.55,8.86-4.64,11.59c-3.1,2.74-7.76,4.1-14,4.1h-4.97v14.69c0,.62-.31.94-.94.94h-8.42ZM105.84,35.35h4.82c2.83,0,4.96-.54,6.37-1.62,1.42-1.08,2.12-2.84,2.12-5.29s-.7-4.37-2.09-5.47c-1.39-1.1-3.53-1.66-6.41-1.66h-4.82v14.04Z"/>
<path class="cls-1" d="M134.57,59.69c-.62,0-.94-.31-.94-.94v-25.63c0-1.49-.04-2.89-.11-4.21-.07-1.32-.18-2.6-.32-3.85-.1-.67.22-1.01.94-1.01h7.13c.53,0,.86.26,1.01.79.19.82.33,1.75.43,2.81.1,1.06.17,2.04.22,2.95l.72,4.39v23.76c0,.62-.31.94-.94.94h-8.14ZM142.92,38.88l-.58-8.35c.96-1.39,2.06-2.64,3.31-3.74,1.25-1.1,2.51-1.98,3.78-2.63,1.27-.65,2.46-.97,3.56-.97.77,0,1.39.1,1.87.29.48.14.74.48.79,1.01,0,1.25-.01,2.62-.04,4.1-.03,1.49-.11,2.88-.25,4.18-.1.72-.46,1.01-1.08.86-.29-.09-.65-.17-1.08-.22-.43-.05-.84-.07-1.22-.07-1.01,0-2.04.22-3.1.65-1.06.43-2.1,1.04-3.13,1.84-1.03.79-1.98,1.81-2.84,3.06Z"/>
<path class="cls-1" d="M174.38,60.55c-5.57,0-9.68-1.19-12.35-3.56s-4-5.89-4-10.55v-8.28c0-4.9,1.33-8.62,4-11.16,2.66-2.54,6.73-3.82,12.2-3.82s9.35,1.22,12.06,3.67,4.07,6.05,4.07,10.8v5.62c0,.62-.31.94-.94.94h-21.46v2.16c0,2.21.49,3.85,1.48,4.93.98,1.08,2.6,1.62,4.86,1.62,1.73,0,3.1-.28,4.1-.83s1.51-1.38,1.51-2.48c0-.62.31-.94.94-.94h7.85c.58,0,.89.31.94.94.1,3.65-1.13,6.38-3.67,8.21-2.54,1.83-6.41,2.74-11.59,2.74ZM167.98,38.16h12.6v-.36c0-2.4-.5-4.15-1.51-5.26-1.01-1.1-2.57-1.66-4.68-1.66-2.26,0-3.89.56-4.9,1.69-1.01,1.13-1.51,2.89-1.51,5.29v.29Z"/>
<path class="cls-1" d="M207.65,60.55c-5.04,0-8.7-.94-10.98-2.81-2.28-1.87-3.3-4.8-3.06-8.78.05-.58.36-.86.94-.86h7.63c.58,0,.86.29.86.86,0,1.49.37,2.59,1.12,3.31.74.72,1.91,1.08,3.49,1.08,1.68,0,2.93-.26,3.74-.79.82-.53,1.22-1.34,1.22-2.45,0-.86-.29-1.57-.86-2.12-.58-.55-1.54-1.12-2.88-1.69l-8.28-3.53c-2.4-1.01-4.13-2.24-5.18-3.71-1.06-1.46-1.58-3.37-1.58-5.72,0-3.41,1.12-5.95,3.35-7.63,2.23-1.68,5.7-2.52,10.4-2.52s8.44.88,10.76,2.63c2.33,1.75,3.49,4.36,3.49,7.81,0,.62-.31.94-.94.94h-7.56c-.62,0-.94-.38-.94-1.15,0-1.01-.37-1.76-1.12-2.27-.75-.5-1.84-.76-3.28-.76s-2.5.24-3.17.72c-.67.48-1.01,1.22-1.01,2.23,0,.72.24,1.3.72,1.73.48.43,1.39.94,2.74,1.51l8.21,3.46c2.5,1.01,4.31,2.26,5.44,3.74,1.13,1.49,1.69,3.46,1.69,5.9,0,3.6-1.27,6.31-3.82,8.14-2.54,1.83-6.26,2.74-11.16,2.74Z"/>
<path class="cls-1" d="M239.83,60.55c-5.04,0-8.7-.94-10.98-2.81-2.28-1.87-3.3-4.8-3.06-8.78.05-.58.36-.86.94-.86h7.63c.58,0,.86.29.86.86,0,1.49.37,2.59,1.12,3.31.74.72,1.91,1.08,3.49,1.08,1.68,0,2.93-.26,3.74-.79.82-.53,1.22-1.34,1.22-2.45,0-.86-.29-1.57-.86-2.12-.58-.55-1.54-1.12-2.88-1.69l-8.28-3.53c-2.4-1.01-4.13-2.24-5.18-3.71-1.06-1.46-1.58-3.37-1.58-5.72,0-3.41,1.12-5.95,3.35-7.63,2.23-1.68,5.7-2.52,10.4-2.52s8.44.88,10.76,2.63c2.33,1.75,3.49,4.36,3.49,7.81,0,.62-.31.94-.94.94h-7.56c-.62,0-.94-.38-.94-1.15,0-1.01-.37-1.76-1.12-2.27-.75-.5-1.84-.76-3.28-.76s-2.5.24-3.17.72c-.67.48-1.01,1.22-1.01,2.23,0,.72.24,1.3.72,1.73.48.43,1.39.94,2.74,1.51l8.21,3.46c2.5,1.01,4.31,2.26,5.44,3.74,1.13,1.49,1.69,3.46,1.69,5.9,0,3.6-1.27,6.31-3.82,8.14-2.54,1.83-6.26,2.74-11.16,2.74Z"/>
<path class="cls-1" d="M267.62,60.55c-2.88,0-5.11-.88-6.7-2.63s-2.38-4.24-2.38-7.45c0-2.5.47-4.52,1.4-6.08.94-1.56,2.5-2.78,4.68-3.67,2.18-.89,5.1-1.48,8.75-1.76l6.7-.65-.07,5.47-5.33.5c-2.45.24-4.14.73-5.08,1.48-.94.74-1.4,1.93-1.4,3.56,0,1.3.26,2.23.79,2.81.53.58,1.32.86,2.38.86,1.34,0,2.69-.41,4.03-1.22,1.34-.82,2.98-2.26,4.9-4.32l.43,5.98c-1.34,1.39-2.68,2.63-4,3.71-1.32,1.08-2.71,1.92-4.18,2.52-1.46.6-3.11.9-4.93.9ZM281.45,59.69c-.29,0-.5-.08-.65-.25-.14-.17-.26-.4-.36-.68-.1-.53-.22-1.33-.36-2.41s-.26-2.15-.36-3.2l-.72-3.02v-14.47c0-1.82-.35-3.11-1.04-3.85-.7-.74-1.93-1.12-3.71-1.12-3.26,0-4.82,1.22-4.68,3.67.05.62-.26.94-.94.94h-7.56c-.58,0-.91-.38-1.01-1.15-.29-3.5.83-6.2,3.35-8.1,2.52-1.9,6.25-2.84,11.2-2.84s8.7,1.02,10.98,3.06c2.28,2.04,3.42,5.27,3.42,9.68v14.62c0,1.54.04,2.96.11,4.28.07,1.32.18,2.6.32,3.85.1.67-.22,1.01-.94,1.01h-7.06Z"/>
<path class="cls-1" d="M310.24,60.55c-1.97,0-3.79-.11-5.47-.32-1.68-.22-3.37-.46-5.08-.72-1.7-.26-3.54-.47-5.51-.61V11.45c0-.62.31-.94.94-.94h8.14c.62,0,.94.31.94.94v40.32c.86.14,1.74.28,2.63.4.89.12,1.74.18,2.56.18,2.21,0,3.84-.61,4.9-1.84,1.05-1.22,1.58-3.04,1.58-5.44v-7.42c0-2.06-.36-3.55-1.08-4.46-.72-.91-1.83-1.37-3.31-1.37-1.2,0-2.46.35-3.78,1.04-1.32.7-2.89,1.81-4.72,3.35l.22-7.49c2.02-1.87,4.03-3.26,6.05-4.18,2.02-.91,4.08-1.37,6.19-1.37,3.5,0,6.12,1.02,7.85,3.06,1.73,2.04,2.59,5.17,2.59,9.4v10.3c0,4.94-1.27,8.62-3.82,11.02-2.54,2.4-6.48,3.6-11.81,3.6Z"/>
<path class="cls-1" d="M331.27,59.69c-.62,0-.94-.31-.94-.94V11.45c0-.62.31-.94.94-.94h8.14c.62,0,.94.31.94.94v47.3c0,.62-.31.94-.94.94h-8.14Z"/>
<path class="cls-1" d="M361,60.55c-5.57,0-9.68-1.19-12.35-3.56s-4-5.89-4-10.55v-8.28c0-4.9,1.33-8.62,4-11.16,2.66-2.54,6.73-3.82,12.2-3.82s9.35,1.22,12.06,3.67,4.07,6.05,4.07,10.8v5.62c0,.62-.31.94-.94.94h-21.46v2.16c0,2.21.49,3.85,1.48,4.93.98,1.08,2.6,1.62,4.86,1.62,1.73,0,3.1-.28,4.1-.83s1.51-1.38,1.51-2.48c0-.62.31-.94.94-.94h7.85c.58,0,.89.31.94.94.1,3.65-1.13,6.38-3.67,8.21-2.54,1.83-6.41,2.74-11.59,2.74ZM354.59,38.16h12.6v-.36c0-2.4-.5-4.15-1.51-5.26-1.01-1.1-2.57-1.66-4.68-1.66-2.26,0-3.89.56-4.9,1.69-1.01,1.13-1.51,2.89-1.51,5.29v.29Z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1,75 @@
<?php //Pressable Cache Purge Adds a Cache Purge button to the admin bar
// disable direct file access
if (!defined('ABSPATH'))
{
exit;
}
add_action( 'admin_bar_menu', 'cache_add_item', 100 );
function cache_add_item( $admin_bar ) {
if ( is_admin() ) {
global $pagenow;
$admin_bar->add_menu(
array(
'id' => 'cache-purge',
'title' => 'Object Cache Purge',
'href' => '#',
)
);
// $admin_bar->add_menu( array( 'id'=>'settings','title'=>'Cache Settings', 'parent'=> 'cache-purge', 'href'=>'admin.php?page=pressable_cache_management' ) );
}
}
add_action( 'admin_footer', 'cache_purge_action_js' );
function cache_purge_action_js() { ?>
<script type="text/javascript" >
jQuery("li#wp-admin-bar-cache-purge .ab-item").on( "click", function() {
var data = {
'action': 'pressable_cache_purge',
};
jQuery.post(ajaxurl, data, function(response) {
alert( response );
});
});
</script>
<style type="text/css">
/*#wp-admin-bar-cache-purge .ab-item {
background-color: #0AD8C7;
}
*/
</style>
<?php
}
add_action( 'wp_ajax_pressable_cache_purge', 'pressable_cache_purge_callback' );
function pressable_cache_purge_callback() {
wp_cache_flush();
//Save time stamp to database if cache is flushed.
$object_cache_flush_time = date( ' jS F Y g:ia' ) . "\nUTC";
update_option( 'flush-obj-cache-time-stamp', $object_cache_flush_time );
$response = 'Object Cache Purged';
echo $response;
wp_die();
}
@@ -0,0 +1,117 @@
<?php // Pressable Cache Management - Enable Caching for pages which has wpp_ cookies
// disable direct file access
if (!defined('ABSPATH'))
{
exit;
}
$options = get_option('pressable_cache_management_options');
if (isset($options['cache_wpp_cookies_pages']) && !empty($options['cache_wpp_cookies_pages']))
{
//Create the pressable-cache-management mu-plugin index file
$pcm_mu_plugins_index = WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management.php';
if (!file_exists($pcm_mu_plugins_index))
{
// Copy pressable-cache-management.php from plugin directory to mu-plugins directory
copy(plugin_dir_path(__FILE__) . '/pressable_cache_management_mu_plugin_index.php', $pcm_mu_plugins_index);
}
// Check if the pressable-cache-management directory exists or create the folder
if (!file_exists(WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/'))
{
//create the directory
wp_mkdir_p(WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/');
}
//Add the option from the textbox into the database
update_option('cache_wpp_cookies_pages', $options['cache_wpp_cookies_pages']);
$obj_cache_wpp_cookies_pages = WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/pcm_cache_wpp_cookies_pages.php';
if (file_exists($obj_cache_wpp_cookies_pages))
{
}
else
{
$obj_cache_wpp_cookies_pages = plugin_dir_path(__FILE__) . '/cache_wpp_cookie_page_mu_plugin.php';
$obj_cache_wpp_cookies_pages_active = WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/pcm_cache_wpp_cookies_pages.php';
//Flush cache to enable activation take effect immediately
wp_cache_flush();
if (!copy($obj_cache_wpp_cookies_pages, $obj_cache_wpp_cookies_pages_active))
{
}
else
{
}
}
//Display admin notice
function cache_wpp_cookies_pages_admin_notice($message = '', $classes = 'notice-success')
{
if (!empty($message))
{
printf('<div class="notice %2$s">%1$s</div>', $message, $classes);
}
}
function pcm_cache_wpp_cookies_pages_admin_notice()
{
$cache_wpp_cookies_pages_activate_display_notice = get_option('cache_wpp_cookies_pages_activate_notice', 'activating');
if ('activating' === $cache_wpp_cookies_pages_activate_display_notice && current_user_can('manage_options'))
{
add_action('admin_notices', function ()
{
$screen = get_current_screen();
//Display admin notice for this plugin page only
if ($screen->id !== 'toplevel_page_pressable_cache_management') return;
$user = $GLOBALS['current_user'];
$message = sprintf('<p>Batcache will now cache pages with wpp_ cookies.</p>');
cache_wpp_cookies_pages_admin_notice($message, 'notice notice-success is-dismissible');
});
update_option('cache_wpp_cookies_pages_activate_notice', 'activated');
}
}
add_action('init', 'pcm_cache_wpp_cookies_pages_admin_notice');
}
else
{
/**Update option from the database if the option is deactivated
used by admin notice to display and remove notice**/
update_option('cache_wpp_cookies_pages_activate_notice', 'activating');
$obj_cache_wpp_cookies_pages = WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/pcm_cache_wpp_cookies_pages.php';
if (file_exists($obj_cache_wpp_cookies_pages))
{
unlink($obj_cache_wpp_cookies_pages);
//Flush cache to enable deactivation take effect immediately
wp_cache_flush();
}
else
{
// File not found.
}
}
@@ -0,0 +1,35 @@
<?php // Pressable Cache Management - Cache pages which sets wpp_ cookies
// disable direct file access
if (!defined('ABSPATH'))
{
exit;
}
/**
* Batcache by default ignore all cookies starting with wp so
* we have to add cookies to skip list if we want batcache to
* cache certain pages with cookies.
*
* Wonder plugin sets cookies starting with wpp which was preventing pages
* getting cached. We collect all the cookies starting with wpp_ below
* and adds it to the list that can be cached
*/
$all_wpp_cookies = array();
if ( is_array( $_COOKIE) && ! empty( $_COOKIE ) ) {
foreach ( array_keys( $_COOKIE ) as $maybe_wpp ) {
if ( substr( $maybe_wpp, 0, 4 ) == 'wpp_' ) {
$all_wpp_cookies[] = $maybe_wpp;
}
}
}
// Only add cookies to noskip if we found any starting with wpp_
// The wordpress_test_cookies is the default one
if( count($all_wpp_cookies) > 0 ){
global $batcache;
$batcache['noskip_cookies'] = array_merge( array('wordpress_test_cookie'), $all_wpp_cookies );
}
@@ -0,0 +1,229 @@
<?php
/**
* Pressable Cache Management - Edge Cache Defensive Mode
*
* Mirrors the exact pattern used in edge_cache_admin_action_handler():
* query_ec_backend( $endpoint, array( 'body' => $data ) )
*
* Enable: POST to ddos_until with body timestamp = time() + duration_seconds
* Disable: POST to ddos_until with body timestamp = 0
* Status: get_ec_ddos_until() — returns the Unix timestamp or 0 if off
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// ─── Duration map: slug => [ label, seconds ] ────────────────────────────────
function pcm_defensive_mode_durations() {
return [
'30-minutes' => [ 'label' => '30 minutes', 'seconds' => 30 * MINUTE_IN_SECONDS ],
'45-minutes' => [ 'label' => '45 minutes', 'seconds' => 45 * MINUTE_IN_SECONDS ],
'1-hour' => [ 'label' => '1 hour', 'seconds' => HOUR_IN_SECONDS ],
'2-hours' => [ 'label' => '2 hours', 'seconds' => 2 * HOUR_IN_SECONDS ],
'3-hours' => [ 'label' => '3 hours', 'seconds' => 3 * HOUR_IN_SECONDS ],
'4-hours' => [ 'label' => '4 hours', 'seconds' => 4 * HOUR_IN_SECONDS ],
'5-hours' => [ 'label' => '5 hours', 'seconds' => 5 * HOUR_IN_SECONDS ],
'6-hours' => [ 'label' => '6 hours', 'seconds' => 6 * HOUR_IN_SECONDS ],
'7-hours' => [ 'label' => '7 hours', 'seconds' => 7 * HOUR_IN_SECONDS ],
'8-hours' => [ 'label' => '8 hours', 'seconds' => 8 * HOUR_IN_SECONDS ],
'9-hours' => [ 'label' => '9 hours', 'seconds' => 9 * HOUR_IN_SECONDS ],
'10-hours' => [ 'label' => '10 hours', 'seconds' => 10 * HOUR_IN_SECONDS ],
'11-hours' => [ 'label' => '11 hours', 'seconds' => 11 * HOUR_IN_SECONDS ],
'12-hours' => [ 'label' => '12 hours', 'seconds' => 12 * HOUR_IN_SECONDS ],
'13-hours' => [ 'label' => '13 hours', 'seconds' => 13 * HOUR_IN_SECONDS ],
'14-hours' => [ 'label' => '14 hours', 'seconds' => 14 * HOUR_IN_SECONDS ],
'15-hours' => [ 'label' => '15 hours', 'seconds' => 15 * HOUR_IN_SECONDS ],
'16-hours' => [ 'label' => '16 hours', 'seconds' => 16 * HOUR_IN_SECONDS ],
'17-hours' => [ 'label' => '17 hours', 'seconds' => 17 * HOUR_IN_SECONDS ],
'18-hours' => [ 'label' => '18 hours', 'seconds' => 18 * HOUR_IN_SECONDS ],
'19-hours' => [ 'label' => '19 hours', 'seconds' => 19 * HOUR_IN_SECONDS ],
'20-hours' => [ 'label' => '20 hours', 'seconds' => 20 * HOUR_IN_SECONDS ],
'21-hours' => [ 'label' => '21 hours', 'seconds' => 21 * HOUR_IN_SECONDS ],
'22-hours' => [ 'label' => '22 hours', 'seconds' => 22 * HOUR_IN_SECONDS ],
'23-hours' => [ 'label' => '23 hours', 'seconds' => 23 * HOUR_IN_SECONDS ],
'1-day' => [ 'label' => '1 day', 'seconds' => DAY_IN_SECONDS ],
'2-days' => [ 'label' => '2 days', 'seconds' => 2 * DAY_IN_SECONDS ],
'3-days' => [ 'label' => '3 days', 'seconds' => 3 * DAY_IN_SECONDS ],
'4-days' => [ 'label' => '4 days', 'seconds' => 4 * DAY_IN_SECONDS ],
'5-days' => [ 'label' => '5 days', 'seconds' => 5 * DAY_IN_SECONDS ],
'6-days' => [ 'label' => '6 days', 'seconds' => 6 * DAY_IN_SECONDS ],
'7-days' => [ 'label' => '7 days', 'seconds' => 7 * DAY_IN_SECONDS ],
];
}
// ─── Enable Defensive Mode ────────────────────────────────────────────────────
function pcm_pressable_enable_defensive_mode() {
if ( ! isset( $_POST['enable_defensive_mode_nonce'] ) ) {
return;
}
if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['enable_defensive_mode_nonce'] ) ), 'enable_defensive_mode_nonce' ) ) {
return;
}
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$durations = pcm_defensive_mode_durations();
$slug = isset( $_POST['defensive_mode_duration'] )
? sanitize_text_field( wp_unslash( $_POST['defensive_mode_duration'] ) )
: '30-minutes';
if ( ! array_key_exists( $slug, $durations ) ) {
$slug = '30-minutes';
}
if ( ! class_exists( 'Edge_Cache_Plugin' ) ) {
add_action( 'admin_notices', function() {
if ( function_exists( 'pcm_branded_notice' ) ) {
pcm_branded_notice( esc_html__( 'Error: Edge Cache Plugin is not active.', 'pressable_cache_management' ), '#dd3a03' );
}
} );
return;
}
$expires_at = time() + $durations[ $slug ]['seconds'];
$edge_cache = Edge_Cache_Plugin::get_instance();
$result = $edge_cache->query_ec_backend( 'ddos_until', array(
'body' => array(
'timestamp' => $expires_at,
'wp_action' => 'manual_dashboard_set',
),
) );
if ( false === $result['success'] ) {
$err = ! empty( $result['error'] ) ? $result['error'] : esc_html__( 'Unknown error enabling Defensive Mode.', 'pressable_cache_management' );
add_action( 'admin_notices', function() use ( $err ) {
if ( function_exists( 'pcm_branded_notice' ) ) {
pcm_branded_notice( $err, '#dd3a03' );
}
} );
} else {
update_option( 'edge-cache-defensive-mode-active', 'yes' );
update_option( 'edge-cache-defensive-mode-slug', $slug );
update_option( 'edge-cache-defensive-mode-expires-at', $expires_at );
update_option( 'edge-cache-defensive-mode-set-at', gmdate( 'j M Y, g:ia' ) . ' UTC' );
delete_transient( 'pcm_ec_status_cache' );
do_action( 'pcm_after_defensive_mode_change' );
$label = $durations[ $slug ]['label'];
add_action( 'admin_notices', function() use ( $label ) {
if ( function_exists( 'pcm_branded_notice' ) ) {
pcm_branded_notice(
sprintf( esc_html__( 'Defensive Mode enabled for %s.', 'pressable_cache_management' ), $label ),
'#03fcc2'
);
}
} );
}
}
add_action( 'init', 'pcm_pressable_enable_defensive_mode' );
// ─── Disable Defensive Mode ───────────────────────────────────────────────────
function pcm_pressable_disable_defensive_mode() {
if ( ! isset( $_POST['disable_defensive_mode_nonce'] ) ) {
return;
}
if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['disable_defensive_mode_nonce'] ) ), 'disable_defensive_mode_nonce' ) ) {
return;
}
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
if ( ! class_exists( 'Edge_Cache_Plugin' ) ) {
add_action( 'admin_notices', function() {
if ( function_exists( 'pcm_branded_notice' ) ) {
pcm_branded_notice( esc_html__( 'Error: Edge Cache Plugin is not active.', 'pressable_cache_management' ), '#dd3a03' );
}
} );
return;
}
$edge_cache = Edge_Cache_Plugin::get_instance();
$result = $edge_cache->query_ec_backend( 'ddos_until', array(
'body' => array(
'timestamp' => 0,
'wp_action' => 'manual_dashboard_set',
),
) );
if ( false === $result['success'] ) {
$err = ! empty( $result['error'] ) ? $result['error'] : esc_html__( 'Unknown error disabling Defensive Mode.', 'pressable_cache_management' );
add_action( 'admin_notices', function() use ( $err ) {
if ( function_exists( 'pcm_branded_notice' ) ) {
pcm_branded_notice( $err, '#dd3a03' );
}
} );
} else {
update_option( 'edge-cache-defensive-mode-active', 'no' );
update_option( 'edge-cache-defensive-mode-slug', '' );
update_option( 'edge-cache-defensive-mode-expires-at', 0 );
update_option( 'edge-cache-defensive-mode-set-at', '' );
delete_transient( 'pcm_ec_status_cache' );
do_action( 'pcm_after_defensive_mode_change' );
add_action( 'admin_notices', function() {
if ( function_exists( 'pcm_branded_notice' ) ) {
pcm_branded_notice( esc_html__( 'Defensive Mode disabled.', 'pressable_cache_management' ), '#03fcc2' );
}
} );
}
}
add_action( 'init', 'pcm_pressable_disable_defensive_mode' );
// ─── AJAX: check defensive mode status from server ───────────────────────────
// Uses get_ec_ddos_until() which calls query_ec_backend( 'ddos_until' ) as a
// GET (no body args) and returns the ddos_until Unix timestamp, or 0 if off.
function pcm_ajax_check_defensive_mode_status() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( [ 'message' => 'Unauthorized' ], 403 );
return;
}
if ( ! class_exists( 'Edge_Cache_Plugin' ) ) {
wp_send_json_error( [ 'message' => 'Edge Cache Plugin not available.' ] );
return;
}
$edge_cache = Edge_Cache_Plugin::get_instance();
$ddos_until = $edge_cache->get_ec_ddos_until(); // returns int timestamp or EC_ERROR (-1)
// EC_ERROR means the API call failed
if ( Edge_Cache_Plugin::EC_ERROR === $ddos_until ) {
wp_send_json_error( [ 'message' => 'Could not retrieve Defensive Mode status from server.' ] );
return;
}
$is_defensive = $ddos_until > time();
if ( $is_defensive ) {
// Sync local flag if mode was activated externally (WP-CLI, direct API)
update_option( 'edge-cache-defensive-mode-active', 'yes' );
update_option( 'edge-cache-defensive-mode-expires-at', $ddos_until );
$set_at = get_option( 'edge-cache-defensive-mode-set-at', '' );
$expires_str = gmdate( 'j M Y, g:ia', $ddos_until ) . ' UTC';
wp_send_json_success( [
'defensive_active' => true,
'set_at' => $set_at,
'expires_at' => $expires_str,
] );
} else {
// Server says off — sync local options
update_option( 'edge-cache-defensive-mode-active', 'no' );
update_option( 'edge-cache-defensive-mode-slug', '' );
update_option( 'edge-cache-defensive-mode-expires-at', 0 );
update_option( 'edge-cache-defensive-mode-set-at', '' );
wp_send_json_success( [
'defensive_active' => false,
'set_at' => '',
'expires_at' => '',
] );
}
}
add_action( 'wp_ajax_pcm_check_defensive_mode_status', 'pcm_ajax_check_defensive_mode_status' );
@@ -0,0 +1,73 @@
<?php // Pressable Cache Management - Exclude pages from Batcache
// disable direct file access
if (!defined('ABSPATH'))
{
exit;
}
$options = get_option('pressable_cache_management_options');
if (isset($options['exempt_from_batcache']) && !empty($options['exempt_from_batcache']))
{
//Create the pressable-cache-management mu-plugin index file
$pcm_mu_plugins_index = WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management.php';
if (!file_exists($pcm_mu_plugins_index)) {
// Copy pressable-cache-management.php from plugin directory to mu-plugins directory
copy( plugin_dir_path(__FILE__) . '/pressable_cache_management_mu_plugin_index.php', $pcm_mu_plugins_index);
}
// Check if the pressable-cache-management directory exists or create the folder
if (!file_exists(WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/')) {
//create the directory
wp_mkdir_p(WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/');
}
//Add the option from the textbox into the database
update_option('exempt_from_batcache', $options['exempt_from_batcache']);
// Exclude pages from Batcache
$obj_exclude_pages_from_batcache = WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/pcm_exclude_pages_from_batcache.php';
if (file_exists($obj_exclude_pages_from_batcache))
{
}
else
{
$obj_exclude_pages_from_batcache = plugin_dir_path(__FILE__) . '/exclude_pages_from_batcache_mu_plugin.php';
$obj_exclude_pages_from_batcache_active = WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/pcm_exclude_pages_from_batcache.php';
//Flush cache to enable activation take effect immediately
wp_cache_flush();
if (!copy($obj_exclude_pages_from_batcache, $obj_exclude_pages_from_batcache_active))
{
}
else
{
}
}
}
else
{
$obj_exclude_pages_from_batcache = WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/pcm_exclude_pages_from_batcache.php';
if (file_exists($obj_exclude_pages_from_batcache))
{
unlink($obj_exclude_pages_from_batcache);
//Flush cache to enable deactivation take effect immediately
wp_cache_flush();
}
else
{
// File not found.
}
}
@@ -0,0 +1,48 @@
<?php
// Plugin Name: Exclude website pages from the Batcache and Edge Cache
if (!defined('IS_PRESSABLE')) {
return;
}
add_action('init', 'cancel_the_cache');
function cancel_the_cache() {
if (!function_exists('batcache_cancel')) {
return;
}
$options = get_option('pressable_cache_management_options');
$exempted_pages = isset($options['exempt_from_batcache']) ? $options['exempt_from_batcache'] : '';
if (empty($exempted_pages)) {
return;
}
// Convert stored options into an array and trim spaces
$exempted_pages = array_map('trim', explode(',', $exempted_pages));
// Get current URI without query parameters
$uri = strtok($_SERVER["REQUEST_URI"], '?');
// Always exclude homepage if listed or explicitly requested
if ($uri === '/' && in_array('/', $exempted_pages)) {
batcache_cancel();
disable_edge_cache();
return;
}
// Loop through exempted pages
foreach ($exempted_pages as $page) {
// Match exact page or paginated versions (e.g., /about/, /about/page/2/)
if ($uri === $page || preg_match("#^" . preg_quote($page, '#') . "(/page/\d+/?)?$#i", $uri)) {
batcache_cancel();
disable_edge_cache();
return;
}
}
}
function disable_edge_cache() {
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
}
@@ -0,0 +1,122 @@
<?php // Pressable Cache Management - Exclude Google Ads URL's with query string gclid from Batcache
// disable direct file access
if (!defined('ABSPATH'))
{
exit;
}
$options = get_option('pressable_cache_management_options');
if (isset($options['exclude_query_string_gclid_checkbox']) && !empty($options['exclude_query_string_gclid_checkbox']))
{
//Create the pressable-cache-management mu-plugin index file
$pcm_mu_plugins_index = WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management.php';
if (!file_exists($pcm_mu_plugins_index)) {
// Copy pressable-cache-management.php from plugin directory to mu-plugins directory
copy( plugin_dir_path(__FILE__) . '/pressable_cache_management_mu_plugin_index.php', $pcm_mu_plugins_index);
}
// Check if the pressable-cache-management directory exists or create the folder
if (!file_exists(WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/')) {
//create the directory
wp_mkdir_p(WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/');
}
//Declear variable so that it can be accessed from
$exclude_query_string_gclid = get_option('exclude_query_string_gclid');
// Exclude Google Ads URL's with query string gclid from Batcache
$obj_exclude_query_string_gclid = WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/pcm_exclude_query_string_gclid.php';
if (file_exists($obj_exclude_query_string_gclid))
{
}
else
{
$obj_exclude_query_string_gclid = plugin_dir_path(__FILE__) . '/exclude_query_string_gclid_from_cache_mu_plugin.php';
$obj_exclude_query_string_gclid_active = WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/pcm_exclude_query_string_gclid.php';
//Flush cache to enable activation take effect immediately
wp_cache_flush();
if (!copy($obj_exclude_query_string_gclid, $obj_exclude_query_string_gclid_active))
{
}
else
{
}
}
//Display admin notice
function exclude_query_string_gclid_admin_notice($message = '', $classes = 'notice-success')
{
if (!empty($message))
{
printf('<div class="notice %2$s">%1$s</div>', $message, $classes);
}
}
function pcm_exclude_query_string_gclid_admin_notice()
{
$exclude_query_string_gclid_activate_display_notice = get_option('exclude_query_string_gclid_activate_notice', 'activating');
if ('activating' === $exclude_query_string_gclid_activate_display_notice && current_user_can('manage_options'))
{
add_action('admin_notices', function ()
{
$screen = get_current_screen();
//Display admin notice for this plugin page only
if ($screen->id !== 'toplevel_page_pressable_cache_management') return;
$user = $GLOBALS['current_user'];
$message = sprintf('<p> Google Ads URL with query string (gclid) will be excluded from Batcache.</p>', $user->display_name);
exclude_query_string_gclid_admin_notice($message, 'notice notice-success is-dismissible');
});
update_option('exclude_query_string_gclid_activate_notice', 'activated');
}
}
add_action('init', 'pcm_exclude_query_string_gclid_admin_notice');
}
else
{
/**Update option from the database if the option is deactivated
used by admin notice to display and remove notice**/
update_option('exclude_query_string_gclid_activate_notice', 'activating');
$obj_exclude_query_string_gclid = WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/pcm_exclude_query_string_gclid.php';
if (file_exists($obj_exclude_query_string_gclid))
{
unlink($obj_exclude_query_string_gclid);
//Flush cache to enable deactivation take effect immediately
wp_cache_flush();
}
else
{
// File not found.
}
}
@@ -0,0 +1,25 @@
<?php // Pressable Cache Management - Exclude Google Ads URL with query string gclid from Batcache
// disable direct file access
if (!defined('ABSPATH'))
{
exit;
}
/**
* Batcache by default will create a new cached page for each query parameter
* But we want to ignore Google Ads with the URL Param of gclid
**/
if (!function_exists('exclude_gclid_from_batcache')) {
function exclude_gclid_from_batcache() {
global $batcache;
if ( is_object( $batcache ) ) {
$batcache->ignored_query_args = array( 'gclid' );
}
}
}
add_action( 'plugins_loaded', 'exclude_gclid_from_batcache' );
@@ -0,0 +1,50 @@
<?php
// Pressable Cache Management - Extend batcache by 24 hours
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$options = get_option( 'pressable_cache_management_options' );
if ( isset( $options['extend_batcache_checkbox'] ) && ! empty( $options['extend_batcache_checkbox'] ) ) {
update_option( 'extend_batcache_checkbox', $options['extend_batcache_checkbox'] );
$extend_batcache = get_option( 'extend_batcache_checkbox' );
// Create the mu-plugin index file if it doesn't exist
$pcm_mu_plugins_index = WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management.php';
if ( ! file_exists( $pcm_mu_plugins_index ) ) {
copy( plugin_dir_path( __FILE__ ) . '/pressable_cache_management_mu_plugin_index.php', $pcm_mu_plugins_index );
}
// Ensure mu-plugins directory exists
if ( ! file_exists( WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/' ) ) {
wp_mkdir_p( WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/' );
}
$obj_extend_batcache = WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/pcm_extend_batcache.php';
$obj_extend_batcache_source = plugin_dir_path( __FILE__ ) . '/extend_batcache_mu_plugin.php';
$obj_extend_batcache_active = $obj_extend_batcache;
if ( ! file_exists( $obj_extend_batcache ) ) {
// mu-plugin doesn't exist yet — this is a FRESH enable, copy file and queue notice
wp_cache_flush();
if ( copy( $obj_extend_batcache_source, $obj_extend_batcache_active ) ) {
// Mark notice as pending — will show ONCE on next admin page load, then clear itself
update_option( 'pcm_extend_batcache_notice_pending', '1' );
}
}
// If file already exists: checkbox was already on before this load — do NOT re-queue notice
} else {
// Checkbox is OFF — clear the notice flag and remove the mu-plugin
delete_option( 'pcm_extend_batcache_notice_pending' );
$obj_extend_batcache = WP_CONTENT_DIR . '/mu-plugins/pressable-cache-management/pcm_extend_batcache.php';
if ( file_exists( $obj_extend_batcache ) ) {
unlink( $obj_extend_batcache );
wp_cache_flush();
}
}
@@ -0,0 +1,18 @@
<?php // Extend Batcache for Pressable site
if (!defined('IS_PRESSABLE'))
{
return;
}
//Batcache Customizations
global $batcache;
//Check is batcache params are in an object or an array, apply customizations accordingly
if ( is_object( $batcache ) ) {
$batcache->max_age = 86400; // Seconds the cached render of a page will be stored
$batcache->seconds = 1200; // The amount of time at least 2 people are required to
} elseif ( is_array( $batcache ) ) {
$batcache['max_age'] = 86400; // Seconds the cached render of a page will be stored
$batcache['seconds'] = 1200;// The amount of time at least 2 people are required to
}
@@ -0,0 +1,139 @@
<?php
/**
* Pressable Cache Management - Flush cache for a particular page (column link)
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$options = get_option( 'pressable_cache_management_options' );
if ( isset( $options['flush_object_cache_for_single_page'] ) && ! empty( $options['flush_object_cache_for_single_page'] ) ) {
add_action( 'init', 'pcm_show_flush_cache_column' );
function pcm_show_flush_cache_column() {
if ( current_user_can('administrator') || current_user_can('editor') || current_user_can('manage_woocommerce') ) {
$column = new FlushObjectCachePageColumn();
$column->add();
}
}
function flush_object_cache_for_single_page_notice() {
$state = get_option( 'flush-object-cache-for-single-page-notice', 'activating' );
if ( 'activating' === $state &&
( current_user_can('administrator') || current_user_can('editor') || current_user_can('manage_woocommerce') )
) {
add_action( 'admin_notices', function() {
$screen = get_current_screen();
if ( ! isset( $screen ) || $screen->id !== 'toplevel_page_pressable_cache_management' ) return;
$wrap = 'display:flex;align-items:center;justify-content:space-between;gap:12px;'
. 'border-left:4px solid #03fcc2;background:#fff;border-radius:0 8px 8px 0;'
. 'padding:14px 18px;box-shadow:0 2px 8px rgba(4,0,36,.07);'
. 'margin:10px 0;font-family:sans-serif;';
$btn = 'background:none;border:none;cursor:pointer;color:#94a3b8;font-size:18px;line-height:1;padding:0;';
$pcm_nid = 'pcm-sp-notice-' . substr( md5( microtime() ), 0, 8 );
echo '<div style="max-width:1120px;margin:0 auto;padding:0 20px;box-sizing:border-box;">';
echo '<div id="' . $pcm_nid . '" style="' . $wrap . '">';
echo '<p style="margin:0;font-size:13px;color:#040024;">'
. esc_html__( 'You can Flush Cache for Individual page or post from page preview.', 'pressable_cache_management' )
. '</p>';
echo '<button type="button" onclick="document.getElementById(\'' . $pcm_nid . '\').remove();" style="' . $btn . '">&#x2297;</button>';
echo '</div>';
echo '</div>';
});
update_option( 'flush-object-cache-for-single-page-notice', 'activated' );
}
}
add_action( 'init', 'flush_object_cache_for_single_page_notice' );
} else {
update_option( 'flush-object-cache-for-single-page-notice', 'activating' );
}
// ─── FlushObjectCachePageColumn class ────────────────────────────────────────
if ( ! class_exists( 'FlushObjectCachePageColumn' ) ) {
class FlushObjectCachePageColumn {
public function __construct() {}
public function add() {
add_filter( 'post_row_actions', array( $this, 'add_flush_object_cache_link' ), 10, 2 );
add_filter( 'page_row_actions', array( $this, 'add_flush_object_cache_link' ), 10, 2 );
add_action( 'admin_enqueue_scripts', array( $this, 'load_js' ) );
add_action( 'wp_ajax_pcm_flush_object_cache_column', array( $this, 'flush_object_cache_column' ) );
}
public function add_flush_object_cache_link( $actions, $post ) {
if ( current_user_can('administrator') || current_user_can('editor') || current_user_can('manage_woocommerce') ) {
$actions['flush_object_cache_url'] =
'<a data-id="' . esc_attr( $post->ID ) . '"'
. ' data-nonce="' . wp_create_nonce( 'flush-object-cache_' . $post->ID ) . '"'
. ' id="flush-object-cache-url-' . esc_attr( $post->ID ) . '"'
. ' style="cursor:pointer;">'
. esc_html__( 'Flush Cache', 'pressable_cache_management' ) . '</a>';
}
return $actions;
}
public function flush_object_cache_column() {
if ( ! ( current_user_can('administrator') || current_user_can('editor') || current_user_can('manage_woocommerce') ) ) {
die( json_encode( array( 'success' => false, 'message' => 'Unauthorized' ) ) );
}
if ( ! isset( $_GET['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['nonce'] ) ), 'flush-object-cache_' . intval( $_GET['id'] ) ) ) {
die( json_encode( array( 'success' => false, 'message' => 'Nonce verification failed' ) ) );
}
$url_key = get_permalink( intval( $_GET['id'] ) );
$page_title = get_the_title( intval( $_GET['id'] ) );
update_option( 'page-title', $page_title );
global $batcache, $wp_object_cache;
if ( ! isset( $batcache ) || ! is_object( $batcache ) || ! method_exists( $wp_object_cache, 'incr' ) ) {
die( json_encode( array( 'success' => false ) ) );
}
$batcache->configure_groups();
$url = apply_filters( 'batcache_manager_link', $url_key );
if ( empty( $url ) ) {
die( json_encode( array( 'success' => false ) ) );
}
do_action( 'batcache_manager_before_flush', $url );
$url = set_url_scheme( $url, 'http' );
$url_key = md5( $url );
wp_cache_add( "{$url_key}_version", 0, $batcache->group );
wp_cache_incr( "{$url_key}_version", 1, $batcache->group );
if ( property_exists( $wp_object_cache, 'no_remote_groups' ) ) {
$k = array_search( $batcache->group, (array) $wp_object_cache->no_remote_groups );
if ( false !== $k ) {
unset( $wp_object_cache->no_remote_groups[ $k ] );
wp_cache_set( "{$url_key}_version", $batcache->group );
$wp_object_cache->no_remote_groups[ $k ] = $batcache->group;
}
}
do_action( 'batcache_manager_after_flush', $url );
update_option( 'flush-object-cache-for-single-page-time-stamp', gmdate( 'j M Y, g:ia' ) . ' UTC' );
// Also store the flushed URL so it shows on the settings page
update_option( 'single-page-url-flushed', $url );
die( json_encode( array( 'success' => true ) ) );
}
public function load_js() {
wp_enqueue_script(
'flush-object-cache-column',
plugin_dir_url( dirname( __FILE__ ) ) . 'public/js/column.js',
array(), time(), true
);
}
}
}
@@ -0,0 +1,100 @@
<?php
/**
* Pressable Cache Management — Flush Batcache for WooCommerce Individual Pages
*
* When enabled, copies pcm_batcache_manager.php into mu-plugins so that Batcache
* is flushed automatically for any individual page/product updated via WooCommerce API.
* When disabled, removes the mu-plugin file and restores the previous state.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$options = get_option( 'pressable_cache_management_options' );
$enabled = ! empty( $options['flush_batcache_for_woo_product_individual_page_checkbox'] );
$mu_plugin_dest = WP_CONTENT_DIR . '/mu-plugins/pcm_batcache_manager.php';
$mu_plugin_src = plugin_dir_path( __FILE__ ) . 'pcm_batcache_manager.php';
if ( $enabled ) {
// ── Feature ON ───────────────────────────────────────────────────────────
// Always sync the source file into mu-plugins so that any updates to
// pcm_batcache_manager.php (e.g. targeted flush fixes) take effect immediately.
// Previously this only copied on first enable, meaning edits to the source
// were never deployed to the live mu-plugin copy.
$needs_update = ! file_exists( $mu_plugin_dest )
|| ( file_exists( $mu_plugin_src ) && md5_file( $mu_plugin_src ) !== md5_file( $mu_plugin_dest ) );
if ( $needs_update && file_exists( $mu_plugin_src ) && @copy( $mu_plugin_src, $mu_plugin_dest ) ) {
if ( ! file_exists( $mu_plugin_dest ) ) {
// Only flush and show notice on fresh enable, not on every update
wp_cache_flush();
update_option( 'flush_batcache_for_woo_product_individual_page_activate_notice', 'activating' );
}
}
// ── Show branded activation notice (once, on next page load) ─────────────
add_action( 'init', 'pcm_woo_individual_page_activation_notice' );
function pcm_woo_individual_page_activation_notice() {
$state = get_option( 'flush_batcache_for_woo_product_individual_page_activate_notice', 'activated' );
if ( 'activating' !== $state || ! current_user_can( 'manage_options' ) ) {
return;
}
add_action( 'admin_notices', 'pcm_woo_individual_page_render_notice' );
update_option( 'flush_batcache_for_woo_product_individual_page_activate_notice', 'activated' );
}
function pcm_woo_individual_page_render_notice() {
$screen = get_current_screen();
if ( ! $screen || $screen->id !== 'toplevel_page_pressable_cache_management' ) {
return;
}
$nid = 'pcm-woo-notice-' . substr( md5( microtime() ), 0, 8 );
$wrap = 'display:flex;align-items:center;justify-content:space-between;gap:12px;'
. 'border-left:4px solid #03fcc2;background:#fff;border-radius:0 8px 8px 0;'
. 'padding:14px 18px;box-shadow:0 2px 8px rgba(4,0,36,.07);'
. 'margin:10px 0;font-family:sans-serif;';
$icon_wrap = 'display:flex;align-items:center;gap:10px;';
$icon = '<span style="display:inline-flex;align-items:center;justify-content:center;'
. 'width:32px;height:32px;border-radius:50%;background:#f0fdf9;flex-shrink:0;">'
. '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">'
. '<path d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM0 8a8 8 0 1116 0A8 8 0 010 8z" fill="#03fcc2"/>'
. '<path d="M8 7a1 1 0 011 1v3a1 1 0 11-2 0V8a1 1 0 011-1zM8 5.5a1 1 0 100-2 1 1 0 000 2z" fill="#03fcc2"/>'
. '</svg></span>';
$btn = 'background:none;border:none;cursor:pointer;color:#94a3b8;font-size:18px;'
. 'line-height:1;padding:0;flex-shrink:0;margin-top:2px;';
echo '<div style="max-width:1120px;margin:0 auto;padding:0 20px;box-sizing:border-box;">';
echo '<div id="' . esc_attr( $nid ) . '" style="' . $wrap . '">';
echo '<div style="' . $icon_wrap . '">' . $icon;
echo '<div>';
echo '<p style="margin:0 0 2px;font-size:13px;font-weight:600;color:#040024;">'
. esc_html__( 'Flush Batcache for WooCommerce Product Pages — Enabled', 'pressable_cache_management' )
. '</p>';
echo '<p style="margin:0;font-size:12px;color:#64748b;">'
. esc_html__( 'Automatically flush individual pages, including product pages updated via the WooCommerce API.', 'pressable_cache_management' )
. '</p>';
echo '</div></div>';
echo '<button type="button" onclick="document.getElementById(\'' . esc_js( $nid ) . '\').remove();" style="' . $btn . '">&#x2297;</button>';
echo '</div>';
echo '</div>';
}
} else {
// ── Feature OFF ──────────────────────────────────────────────────────────
// Reset so notice shows again next time it is re-enabled
update_option( 'flush_batcache_for_woo_product_individual_page_activate_notice', 'activating' );
if ( file_exists( $mu_plugin_dest ) ) {
@unlink( $mu_plugin_dest );
wp_cache_flush();
}
}
@@ -0,0 +1,28 @@
<?php // Pressable Cache Management - Flush cache when comment is deleted
$options = get_option('pressable_cache_management_options');
if (isset($options['flush_cache_on_comment_delete_checkbox']) && !empty($options['flush_cache_on_comment_delete_checkbox']))
{
add_action( 'trash_comment', 'pcm_trash_comment_action', 10, 2 );
/**
* Function for `trash_comment` action-hook.
*
* @param string $comment_id The comment ID as a numeric string.
* @param WP_Comment $comment The comment to be trashed.
*
* @return void
*/
function pcm_trash_comment_action( $comment_id, $comment ){
wp_cache_flush();
//Save time stamp to database if cache is flushed when comment is deleted.
$object_cache_flush_time = date(' jS F Y g:ia') . "\nUTC";
update_option('flush-cache-on-comment-delete-time-stamp', $object_cache_flush_time);
}
}
@@ -0,0 +1,96 @@
<?php
/**
* Pressable Cache Management — Flush Batcache for the individual page/post on edit.
*
* Instead of flushing the entire object cache on every save, this targets only
* the Batcache entry for the URL of the post that was just saved — the same
* technique used by flush_batcache_for_particular_page.php (column link) and
* flush_single_page_toolbar.php (toolbar button).
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$options = get_option( 'pressable_cache_management_options' );
if ( isset( $options['flush_cache_page_edit_checkbox'] ) && ! empty( $options['flush_cache_page_edit_checkbox'] ) ) {
/**
* Flush Batcache only for the URL of the post that was just saved.
*
* Fires on save_post (covers pages, posts, and all custom post types,
* including WooCommerce products saved via the REST API).
*
* @param int $post_id The saved post ID.
* @param WP_Post $post The saved post object.
* @param bool $update True if this is an update, false for a new post.
*/
function pcm_flush_batcache_on_page_edit( $post_id, $post, $update ) {
// Skip auto-saves, revisions, and non-published posts
if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
return;
}
if ( $post->post_status !== 'publish' ) {
return;
}
// Get the public URL for this post
$url = get_permalink( $post_id );
if ( empty( $url ) ) {
return;
}
global $batcache, $wp_object_cache;
// Batcache must be loaded and the object cache must support incr()
if ( ! isset( $batcache ) || ! is_object( $batcache ) || ! method_exists( $wp_object_cache, 'incr' ) ) {
return;
}
$batcache->configure_groups();
$url = apply_filters( 'batcache_manager_link', $url );
if ( empty( $url ) ) {
return;
}
do_action( 'batcache_manager_before_flush', $url );
// Batcache keys off the http:// version of the URL
$url = set_url_scheme( $url, 'http' );
$url_key = md5( $url );
// Increment the version key — Batcache treats the cached copy as stale
wp_cache_add( "{$url_key}_version", 0, $batcache->group );
wp_cache_incr( "{$url_key}_version", 1, $batcache->group );
// Handle sites where the Batcache group is excluded from remote sync
if ( property_exists( $wp_object_cache, 'no_remote_groups' ) ) {
$k = array_search( $batcache->group, (array) $wp_object_cache->no_remote_groups );
if ( false !== $k ) {
unset( $wp_object_cache->no_remote_groups[ $k ] );
wp_cache_set( "{$url_key}_version", $batcache->group );
$wp_object_cache->no_remote_groups[ $k ] = $batcache->group;
}
}
do_action( 'batcache_manager_after_flush', $url );
// Record the flush for display on the settings page
$post_type_obj = get_post_type_object( $post->post_type );
$post_type_name = $post_type_obj ? $post_type_obj->labels->singular_name : $post->post_type;
$stamp = gmdate( 'j M Y, g:ia' ) . ' UTC'
. '<b> — cache flushed for ' . esc_html( $post_type_name )
. ' edit: ' . esc_html( $post->post_title ) . '</b>';
update_option( 'flush-cache-page-edit-time-stamp', $stamp );
// Also write the flushed URL so the settings page can show it
update_option( 'single-page-url-flushed', $url );
}
add_action( 'save_post', 'pcm_flush_batcache_on_page_edit', 10, 3 );
}
@@ -0,0 +1,40 @@
<?php // Custom function - Add custom functions to flush cache when page or post is deleted
// disable direct file access
if (!defined('ABSPATH'))
{
exit;
}
$options = get_option('pressable_cache_management_options');
if (isset($options['flush_cache_on_page_post_delete_checkbox']) && !empty($options['flush_cache_on_page_post_delete_checkbox']))
{
function fire_on_page_post_delete( $post_ID, $post_after, $post_before ) {
if ( $post_after->post_status == 'trash' && $post_before->post_status == 'publish' ) {
// Flush site cache if post or page is trashed after publishing
wp_cache_flush();
}
if ( $post_after->post_status == 'publish' && $post_before->post_status == 'trash' ) {
// Flush site cache if post or page is published after being trash (post undelete)
wp_cache_flush();
}
// Save time stamp to database if cache is flushed when a post or page was daleted.
$object_cache_flush_time = date(' jS F Y g:ia') . "\nUTC";
update_option('flush-cache-on-page-post-delete-time-stamp', $object_cache_flush_time);
//Set transient for admin notice for 9 seconds
set_transient('pcm-page-post-delete-notice', true, 9);
}
add_action( 'post_updated', 'fire_on_page_post_delete', 10, 3 );
}
@@ -0,0 +1,76 @@
<?php
// Custom function - Flush cache automatically on themes and plugins update
if ( ! defined( 'ABSPATH' ) ) {
exit();
}
$options = get_option( 'pressable_cache_management_options' );
if ( isset( $options['flush_cache_theme_plugin_checkbox'] ) && ! empty( $options['flush_cache_theme_plugin_checkbox'] ) ) {
function pcm_plugins_themes_update_completed( $upgrader_object, $hook_extra ) {
$type = isset( $hook_extra['type'] ) ? $hook_extra['type'] : '';
if ( ! in_array( $type, array( 'plugin', 'theme' ), true ) ) {
return;
}
wp_cache_flush();
// ── Resolve the name of the updated item ────────────────────────────
$name = '';
// Multiple plugins updated at once
if ( $type === 'plugin' && isset( $hook_extra['plugins'] ) && is_array( $hook_extra['plugins'] ) ) {
$names = array();
foreach ( $hook_extra['plugins'] as $plugin_file ) {
$plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin_file, false, false );
if ( ! empty( $plugin_data['Name'] ) ) {
$names[] = $plugin_data['Name'];
}
}
$name = ! empty( $names ) ? implode( ', ', $names ) : 'Unknown plugin';
}
// Single plugin
if ( $type === 'plugin' && empty( $name ) ) {
if ( isset( $hook_extra['plugin'] ) ) {
$plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $hook_extra['plugin'], false, false );
$name = ! empty( $plugin_data['Name'] ) ? $plugin_data['Name'] : $hook_extra['plugin'];
} elseif ( isset( $upgrader_object->skin->plugin_info['Name'] ) ) {
$name = $upgrader_object->skin->plugin_info['Name'];
} else {
$name = 'Unknown plugin';
}
}
// Theme
if ( $type === 'theme' ) {
if ( isset( $hook_extra['themes'] ) && is_array( $hook_extra['themes'] ) ) {
$theme_names = array();
foreach ( $hook_extra['themes'] as $stylesheet ) {
$theme = wp_get_theme( $stylesheet );
if ( $theme->exists() ) {
$theme_names[] = $theme->get('Name');
}
}
$name = ! empty( $theme_names ) ? implode( ', ', $theme_names ) : 'Unknown theme';
} elseif ( isset( $hook_extra['theme'] ) ) {
$theme = wp_get_theme( $hook_extra['theme'] );
$name = $theme->exists() ? $theme->get('Name') : $hook_extra['theme'];
} elseif ( isset( $upgrader_object->skin->theme_info['Name'] ) ) {
$name = $upgrader_object->skin->theme_info['Name'];
} else {
$name = 'Unknown theme';
}
}
// ── Build timestamp with bold item name ──────────────────────────────
$timestamp = gmdate( 'j M Y, g:ia' ) . ' UTC — <b>' . esc_html( $name ) . ' ' . esc_html( $type ) . ' was updated</b>';
update_option( 'flush-cache-theme-plugin-time-stamp', $timestamp );
}
add_action( 'upgrader_process_complete', 'pcm_plugins_themes_update_completed', 10, 2 );
}
@@ -0,0 +1,70 @@
<?php
/**
* Pressable Cache Management - Flush Object Cache + Page Cache
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( isset( $_POST['flush_object_cache_nonce'] ) ) {
function pressable_cache_button() {
if ( ! wp_verify_nonce(
sanitize_text_field( wp_unslash( $_POST['flush_object_cache_nonce'] ) ),
'flush_object_cache_nonce'
) || ! current_user_can( 'manage_options' ) ) {
return;
}
// Flush WP Object Cache (Redis / Memcached)
wp_cache_flush();
// Flush Batcache page cache if available
if ( function_exists( 'batcache_clear_cache' ) ) {
batcache_clear_cache();
}
// WP Super Cache
if ( function_exists( 'wp_cache_clear_cache' ) ) {
wp_cache_clear_cache();
}
// W3 Total Cache
if ( function_exists( 'w3tc_flush_all' ) ) {
w3tc_flush_all();
}
// WP Rocket
if ( function_exists( 'rocket_clean_domain' ) ) {
rocket_clean_domain();
}
// Custom hook for other integrations
do_action( 'pcm_flush_all_cache' );
// Clear the cached Batcache status so the badge refreshes on next page load
do_action( 'pcm_after_object_cache_flush' );
delete_transient( 'pcm_batcache_status' );
}
add_action( 'wp_before_admin_bar_render', 'pressable_cache_button', 999 );
// Branded success notice - only show ONE (remove WP default)
function flush_cache_notice__success() {
$pcm_nid = 'pcm-obj-notice-' . substr( md5( microtime() ), 0, 8 );
$wrap = 'display:flex;align-items:center;justify-content:space-between;gap:12px;'
. 'border-left:4px solid #03fcc2;background:#fff;border-radius:0 8px 8px 0;'
. 'padding:14px 18px;box-shadow:0 2px 8px rgba(4,0,36,.07);'
. 'margin:10px 20px 10px 0;font-family:sans-serif;';
$btn = 'background:none;border:none;cursor:pointer;color:#94a3b8;font-size:18px;line-height:1;padding:0;';
echo '<div id="' . $pcm_nid . '" style="' . $wrap . '">';
echo '<p style="margin:0;font-size:13px;color:#040024;">'
. esc_html__( 'Object Cache Flushed Successfully.', 'pressable_cache_management' )
. '</p>';
echo '<button type="button" onclick="document.getElementById(\'' . $pcm_nid . '\').remove();" style="' . $btn . '">&#x2297;</button>';
echo '</div>';
}
add_action( 'admin_notices', 'flush_cache_notice__success' );
update_option( 'flush-obj-cache-time-stamp', gmdate( 'j M Y, g:ia' ) . ' UTC' );
}
@@ -0,0 +1,214 @@
<?php
/**
* Pressable Cache Management - Flush Batcache for Individual Page from toolbar
* Sourced from official repo flush_single_page_toolbar.php with branded notices.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$options = get_option( 'pressable_cache_management_options' );
if ( isset( $options['flush_object_cache_for_single_page'] ) && ! empty( $options['flush_object_cache_for_single_page'] ) ) {
if ( ! class_exists( 'PcmFlushCacheAdminbar' ) ) {
class PcmFlushCacheAdminbar {
public function __construct() {}
public function add() {
if ( is_admin() ) {
add_action( 'wp_before_admin_bar_render', array( $this, 'PcmFlushCacheAdminbar' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'load_toolbar_js' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'load_remove_branding_toolbar_js' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'load_toolbar_css' ) );
} else {
if ( is_admin() || is_admin_bar_showing() ) {
add_action( 'wp_before_admin_bar_render', array( $this, 'pcm_toolbar_for_page_preview' ) );
add_action( 'wp_enqueue_scripts', array( $this, 'load_toolbar_js' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'load_remove_branding_toolbar_js' ) );
add_action( 'wp_enqueue_scripts', array( $this, 'load_toolbar_css' ) );
add_action( 'wp_footer', array( $this, 'print_my_inline_script' ) );
}
}
// AJAX: flush batcache for current page
add_action( 'wp_ajax_pcm_delete_current_page_cache', array( $this, 'pcm_delete_current_page_cache' ) );
// AJAX: purge edge cache for current page
add_action( 'wp_ajax_pcm_purge_current_page_edge_cache', array( $this, 'pcm_purge_current_page_edge_cache' ) );
}
public function pcm_delete_current_page_cache() {
if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['nonce'] ) ), 'pcm_nonce' ) ) {
die( json_encode( array( 'Security Error!', 'error', 'alert' ) ) );
}
global $batcache, $wp_object_cache;
if ( ! isset( $batcache ) || ! is_object( $batcache ) || ! method_exists( $wp_object_cache, 'incr' ) ) {
return;
}
$batcache->configure_groups();
$path = urldecode( esc_url_raw( wp_unslash( $_GET['path'] ) ) );
if ( preg_match( '/\.{2,}/', $path ) ) {
die( 'Suspected Directory Traversal Attack' );
}
$url = get_home_url() . $path;
$url = apply_filters( 'batcache_manager_link', $url );
if ( empty( $url ) ) return false;
do_action( 'batcache_manager_before_flush', $url );
$url = set_url_scheme( $url, 'http' );
update_option( 'single-page-url-flushed', $url );
$url_key = md5( $url );
if ( is_object( $batcache ) ) {
wp_cache_add( "{$url_key}_version", 0, $batcache->group );
wp_cache_incr( "{$url_key}_version", 1, $batcache->group );
}
if ( property_exists( $wp_object_cache, 'no_remote_groups' ) ) {
$k = array_search( $batcache->group, (array) $wp_object_cache->no_remote_groups );
if ( false !== $k ) {
unset( $wp_object_cache->no_remote_groups[ $k ] );
wp_cache_set( "{$url_key}_version", $batcache->group );
$wp_object_cache->no_remote_groups[ $k ] = $batcache->group;
}
}
do_action( 'batcache_manager_after_flush', $url );
update_option( 'flush-object-cache-for-single-page-time-stamp', gmdate( 'j M Y, g:ia' ) . ' UTC' );
wp_send_json_success( array( 'flushed' => 'batcache' ) );
}
public function pcm_purge_current_page_edge_cache() {
if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['nonce'] ) ), 'pcm_nonce' ) ) {
die( json_encode( array( 'Security Error!', 'error', 'alert' ) ) );
}
$path = urldecode( esc_url_raw( wp_unslash( $_GET['path'] ) ) );
if ( preg_match( '/\.{2,}/', $path ) ) {
die( 'Suspected Directory Traversal Attack' );
}
$url = get_home_url() . $path;
update_option( 'edge-cache-single-page-url-purged', $url );
if ( empty( $url ) ) return false;
if ( class_exists( 'Edge_Cache_Plugin' ) ) {
$edge_cache = Edge_Cache_Plugin::get_instance();
$result = $edge_cache->purge_uris_now( array( $url ) );
update_option( 'single-page-edge-cache-purge-time-stamp', gmdate( 'j M Y, g:ia' ) . ' UTC' );
wp_send_json_success( array( 'flushed' => 'edge-cache' ) );
}
wp_send_json_error( array( 'reason' => 'Edge_Cache_Plugin not available' ) );
}
public function load_toolbar_css() {
wp_enqueue_style( 'pressable-cache-management-toolbar',
plugin_dir_url( dirname( __FILE__ ) ) . 'public/css/toolbar.css',
array(), time(), 'all' );
}
public function load_toolbar_js() {
wp_enqueue_script( 'pcm-toolbar',
plugin_dir_url( dirname( __FILE__ ) ) . 'public/js/toolbar.js',
array( 'jquery' ), time(), true );
// Pass nonce and edge-cache state to JS for BOTH admin and frontend contexts.
// pcm_nonce from print_my_inline_script() only runs on wp_footer (frontend).
// wp_localize_script covers both admin and frontend reliably.
$edge_on = ( get_option('edge-cache-enabled') === 'enabled' ) ? '1' : '0';
wp_localize_script( 'pcm-toolbar', 'pcmToolbarData', array(
'nonce' => wp_create_nonce( 'pcm_nonce' ),
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'flushEdge'=> $edge_on,
) );
}
public function load_remove_branding_toolbar_js() {
wp_enqueue_script( 'pcm-toolbar-branding',
plugin_dir_url( dirname( __FILE__ ) ) . 'public/js/toolbar_remove_branding.js',
array( 'jquery' ), time(), true );
}
public function print_my_inline_script() { ?>
<script>
var pcm_ajaxurl = "<?php echo esc_url( admin_url('admin-ajax.php') ); ?>";
var pcm_nonce = "<?php echo wp_create_nonce('pcm_nonce'); ?>";
</script>
<?php
}
public function pcm_toolbar_for_page_preview() {
global $wp_admin_bar;
$branding_opts = get_option( 'remove_pressable_branding_tab_options' );
$branding_disabled = $branding_opts && 'disable' == $branding_opts['branding_on_off_radio_button'];
$edge_cache_on = ( get_option('edge-cache-enabled') === 'enabled' );
// Single label: include Edge Cache in the title when it is active
$flush_label = $edge_cache_on
? __( 'Flush Cache for This Page', 'pressable_cache_management' )
: __( 'Flush Batcache for This Page', 'pressable_cache_management' );
if ( $branding_disabled ) {
$parent = 'pcm-toolbar-parent-remove-branding';
$wp_admin_bar->add_node( array(
'id' => $parent,
'title' => __( 'Flush Cache', 'pressable_cache_management' ),
'class' => 'pcm-toolbar-child',
));
// Combined item — JS fires both Batcache + Edge Cache flushes in sequence
$wp_admin_bar->add_menu( array(
'id' => 'pcm-toolbar-parent-remove-branding-flush-cache-of-this-page',
'title' => $flush_label,
'parent' => $parent,
'meta' => array( 'class' => 'pcm-toolbar-child' ),
));
} else {
$parent = 'pcm-toolbar-parent';
$wp_admin_bar->add_node( array(
'id' => $parent,
'title' => __( 'Flush Cache', 'pressable_cache_management' ),
));
// Combined item — JS fires both Batcache + Edge Cache flushes in sequence
$wp_admin_bar->add_menu( array(
'id' => 'pcm-toolbar-parent-flush-cache-of-this-page',
'title' => $flush_label,
'parent' => $parent,
'meta' => array( 'class' => 'pcm-toolbar-child' ),
));
}
}
// Empty admin-side toolbar (handled by object_cache_admin_bar.php)
public function PcmFlushCacheAdminbar() {}
}
}
add_action( 'init', 'pcm_show_flush_cache_option_for_single_page' );
function pcm_show_flush_cache_option_for_single_page() {
$current_user = wp_get_current_user();
if ( current_user_can('manage_woocommerce') || current_user_can('administrator') ) {
$toolbar = new PcmFlushCacheAdminbar();
$toolbar->add();
} else {
if ( ! function_exists('load_admin_toolbar_css') ) {
function load_admin_toolbar_css() {
wp_enqueue_style( 'pressable-cache-management-toolbar',
plugin_dir_url( dirname( __FILE__ ) ) . 'public/css/toolbar.css',
array(), time(), 'all' );
}
}
add_action( 'init', 'load_admin_toolbar_css' );
}
}
}
@@ -0,0 +1,240 @@
<?php
/**
* Pressable Cache Management - Admin Bar Cache Buttons
* Branded popup notices matching plugin theme (#dd3a03, #040024, #03fcc2)
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// ─── Branded modal popup (replaces browser alert) ─────────────────────────
add_action( 'admin_footer', 'pcm_abar_modal_html' );
function pcm_abar_modal_html() {
if ( ! pcm_abar_can_view() ) return;
?>
<div id="pcm-modal-overlay" style="display:none;position:fixed;inset:0;background:rgba(4,0,36,.45);z-index:999999;align-items:center;justify-content:center;">
<div style="background:#fff;border-radius:12px;padding:28px 32px;max-width:440px;width:90%;box-shadow:0 8px 40px rgba(4,0,36,.18);font-family:sans-serif;position:relative;">
<div style="width:48px;height:4px;background:#03fcc2;border-radius:4px;margin-bottom:18px;"></div>
<div id="pcm-modal-message" style="font-size:14px;color:#040024;line-height:1.6;white-space:pre-line;margin-bottom:22px;"></div>
<button id="pcm-modal-ok" style="background:#dd3a03;color:#fff;border:none;border-radius:8px;padding:10px 28px;font-size:13.5px;font-weight:700;cursor:pointer;font-family:sans-serif;letter-spacing:.4px;transition:background .2s;">OK</button>
</div>
</div>
<script>
(function($){
function pcmShowModal(msg) {
$('#pcm-modal-message').text(msg);
$('#pcm-modal-overlay').css('display','flex');
}
$('#pcm-modal-ok, #pcm-modal-overlay').on('click', function(e){
if (e.target === this) $('#pcm-modal-overlay').hide();
});
$('#pcm-modal-ok').hover(
function(){ $(this).css('background','#b82f00'); },
function(){ $(this).css('background','#dd3a03'); }
);
window.pcmShowModal = pcmShowModal;
})(jQuery);
</script>
<?php
}
// ─── JS: Flush Object Cache ────────────────────────────────────────────────
add_action( 'admin_footer', 'pcm_abar_object_js' );
function pcm_abar_object_js() { ?>
<script>
jQuery(document).ready(function($){
$('li#wp-admin-bar-cache-purge .ab-item').on('click', function(e){
e.preventDefault();
$.post(ajaxurl, { action: 'flush_pressable_cache' }, function(r){
window.pcmShowModal(r.trim());
});
});
});
</script>
<?php }
// ─── JS: Purge Edge Cache ──────────────────────────────────────────────────
add_action( 'admin_footer', 'pcm_abar_edge_js' );
function pcm_abar_edge_js() { ?>
<script>
jQuery(document).ready(function($){
$('li#wp-admin-bar-edge-purge .ab-item').on('click', function(e){
e.preventDefault();
$.ajax({ url: ajaxurl, type: 'POST', data: { action: 'pressable_edge_cache_purge' },
success: function(r){ window.pcmShowModal(r.trim()); },
error: function(){ window.pcmShowModal('An error occurred during the Edge Cache purge request.'); }
});
});
});
</script>
<?php }
// ─── JS: Flush Object + Edge Cache ────────────────────────────────────────
add_action( 'admin_footer', 'pcm_abar_combined_js' );
function pcm_abar_combined_js() { ?>
<script>
jQuery(document).ready(function($){
$('li#wp-admin-bar-combined-cache-purge .ab-item').on('click', function(e){
e.preventDefault();
$.ajax({ url: ajaxurl, type: 'POST', data: { action: 'flush_combined_cache' },
success: function(r){ window.pcmShowModal(r.trim()); },
error: function(){ window.pcmShowModal('An error occurred during the combined cache flush.'); }
});
});
});
</script>
<?php }
// ─── Enqueue toolbar CSS ───────────────────────────────────────────────────
function pcm_abar_load_css() {
wp_enqueue_style( 'pressable-cache-management-toolbar',
plugin_dir_url( dirname( __FILE__ ) ) . 'public/css/toolbar.css',
array(), time(), 'all' );
}
add_action( 'init', 'pcm_abar_load_css' );
// ─── AJAX Hooks ───────────────────────────────────────────────────────────
add_action( 'wp_ajax_flush_pressable_cache', 'pcm_abar_flush_object_callback' );
add_action( 'wp_ajax_pressable_edge_cache_purge', 'pcm_abar_purge_edge_callback' );
add_action( 'wp_ajax_flush_combined_cache', 'pcm_abar_flush_combined_callback' );
function pcm_abar_flush_object_callback() {
if ( ! current_user_can('administrator') && ! current_user_can('editor') && ! current_user_can('manage_woocommerce') ) {
echo 'You do not have permission to flush the Object Cache.';
wp_die();
}
wp_cache_flush();
if ( function_exists('batcache_clear_cache') ) batcache_clear_cache();
update_option( 'flush-obj-cache-time-stamp', gmdate('j M Y, g:ia') . ' UTC' );
echo esc_html__( 'Object Cache Flushed successfully.', 'pressable_cache_management' );
wp_die();
}
function pcm_abar_purge_edge_callback() {
if ( ! current_user_can('administrator') && ! current_user_can('editor') && ! current_user_can('manage_woocommerce') ) {
echo 'You do not have permission to purge the Edge Cache.';
wp_die();
}
if ( ! class_exists('Edge_Cache_Plugin') ) {
echo esc_html__( 'Error: Edge Cache Plugin is not active. Purge aborted.', 'pressable_cache_management' );
wp_die();
}
$edge_cache = Edge_Cache_Plugin::get_instance();
if ( ! method_exists( $edge_cache, 'purge_domain_now' ) ) {
echo esc_html__( 'Error: Edge Cache purge method unavailable.', 'pressable_cache_management' );
wp_die();
}
$result = $edge_cache->purge_domain_now( 'admin-bar-edge-purge' );
if ( $result ) {
update_option( 'edge-cache-purge-time-stamp', gmdate('j M Y, g:ia') . ' UTC' );
echo esc_html__( 'Edge Cache purged successfully.', 'pressable_cache_management' );
} else {
echo esc_html__( 'Edge Cache purge failed. It might be disabled or rate-limited.', 'pressable_cache_management' );
}
wp_die();
}
function pcm_abar_flush_combined_callback() {
if ( ! current_user_can('administrator') && ! current_user_can('editor') && ! current_user_can('manage_woocommerce') ) {
echo 'You do not have permission to flush the combined cache.';
wp_die();
}
$messages = array();
// Object cache
wp_cache_flush();
if ( function_exists('batcache_clear_cache') ) batcache_clear_cache();
update_option( 'flush-obj-cache-time-stamp', gmdate('j M Y, g:ia') . ' UTC' );
$messages[] = esc_html__( 'Object Cache Flushed successfully.', 'pressable_cache_management' );
// Edge cache
if ( class_exists('Edge_Cache_Plugin') ) {
$edge_cache = Edge_Cache_Plugin::get_instance();
if ( method_exists( $edge_cache, 'purge_domain_now' ) ) {
$result = $edge_cache->purge_domain_now( 'admin-bar-combined-purge' );
if ( $result ) {
update_option( 'edge-cache-purge-time-stamp', gmdate('j M Y, g:ia') . ' UTC' );
$messages[] = esc_html__( 'Edge Cache Purged successfully.', 'pressable_cache_management' );
} else {
$messages[] = esc_html__( 'Edge Cache purge failed (possibly disabled or rate-limited).', 'pressable_cache_management' );
}
} else {
$messages[] = esc_html__( 'Edge Cache Plugin active, but purge method unavailable.', 'pressable_cache_management' );
}
} else {
$messages[] = esc_html__( 'Edge Cache Plugin not found; skipping Edge Cache purge.', 'pressable_cache_management' );
}
echo '- ' . implode( "\n- ", $messages );
wp_die();
}
// ─── Permission check ─────────────────────────────────────────────────────
if ( ! function_exists('pcm_abar_can_view') ) {
function pcm_abar_can_view() {
return current_user_can('administrator') || current_user_can('editor') || current_user_can('manage_woocommerce');
}
}
// ─── Admin Bar Menu ───────────────────────────────────────────────────────
add_action( 'admin_bar_menu', 'pcm_abar_add_menu', 100 );
function pcm_abar_add_menu( $wp_admin_bar ) {
if ( is_network_admin() || ! pcm_abar_can_view() ) return;
$branding_opts = get_option('remove_pressable_branding_tab_options');
$branding_disabled = $branding_opts && 'disable' == $branding_opts['branding_on_off_radio_button'];
$parent_id = $branding_disabled ? 'pcm-wp-admin-toolbar-parent-remove-branding' : 'pcm-wp-admin-toolbar-parent';
$parent_title = $branding_disabled ? 'Cache Control' : 'Cache Management';
// Detect Edge Cache state
$edge_cache_is_enabled = false;
if ( class_exists('Edge_Cache_Plugin') ) {
$ec = Edge_Cache_Plugin::get_instance();
$server_status = method_exists($ec,'get_ec_status') ? $ec->get_ec_status() : null;
if ( defined('Edge_Cache_Plugin::EC_ENABLED') && $server_status === Edge_Cache_Plugin::EC_ENABLED ) {
$edge_cache_is_enabled = true;
} elseif ( get_option('edge-cache-enabled') === 'enabled' ) {
$edge_cache_is_enabled = true;
}
}
// Parent
$wp_admin_bar->add_node( array( 'id' => $parent_id, 'title' => $parent_title ) );
// Flush Object Cache
$wp_admin_bar->add_menu( array(
'id' => 'cache-purge',
'title' => __( 'Flush Object Cache', 'pressable_cache_management' ),
'parent' => $parent_id,
'meta' => array( 'class' => 'pcm-wp-admin-toolbar-child' ),
));
// Edge Cache options (only if enabled)
if ( $edge_cache_is_enabled ) {
$wp_admin_bar->add_menu( array(
'id' => 'edge-purge',
'title' => __( 'Purge Edge Cache', 'pressable_cache_management' ),
'parent' => $parent_id,
'meta' => array( 'class' => 'pcm-wp-admin-toolbar-child' ),
));
$wp_admin_bar->add_menu( array(
'id' => 'combined-cache-purge',
'title' => __( 'Flush Object & Edge Cache', 'pressable_cache_management' ),
'parent' => $parent_id,
'meta' => array( 'class' => 'pcm-wp-admin-toolbar-child' ),
));
}
// Cache Settings (admin only)
if ( current_user_can('administrator') ) {
$wp_admin_bar->add_menu( array(
'id' => 'settings',
'title' => __( 'Cache Settings', 'pressable_cache_management' ),
'parent' => $parent_id,
'href' => admin_url('admin.php?page=pressable_cache_management'),
'meta' => array( 'class' => 'pcm-wp-admin-toolbar-child' ),
));
}
}
@@ -0,0 +1,486 @@
<?php
/*
* Plugin name: Batcache Manager
* Plugin URI: http://www.github.com/spacedmonkey/batcache-manager
* Description: Cache clearing for batcache
* Author: Jonathan Harris
* Author URI: http://www.jonathandavidharris.co.uk
* Version: 2.0.2
*/
/**
* Class Batcache_Manager
*/
class Batcache_Manager {
/**
* List of feeds
*
* @since 2.0.0
*
* @var array
*/
private $feeds = array( 'rss', 'rss2', 'rdf', 'atom' );
/**
* List of links to process
*
* @since 2.0.0
*
* @var array
*/
private $links = array();
/**
* Instance of this class.
*
* @since 2.0.0
*
* @var object
*/
protected static $instance = null;
/**
*
*/
private function __construct() {
global $batcache, $wp_object_cache;
// Do not load if our advanced-cache.php isn't loaded
if ( ! isset( $batcache ) || ! is_object( $batcache ) || ! method_exists( $wp_object_cache, 'incr' ) ) {
return;
}
$batcache->configure_groups();
// Posts
add_action( 'clean_post_cache', array( $this, 'action_clean_post_cache' ), 15 );
// Terms
add_action( 'clean_term_cache', array( $this, 'action_clean_term_cache' ), 10, 3 );
//Comments
add_action( 'clean_comment_cache', array( $this, 'action_update_comment' ) ); // Only supported in 4.5
add_action( 'comment_post', array( $this, 'action_update_comment' ) );
add_action( 'wp_set_comment_status', array( $this, 'action_update_comment' ) );
add_action( 'edit_comment', array( $this, 'action_update_comment' ) );
// Users
add_action( 'clean_user_cache', array( $this, 'action_update_user' ) );
add_action( 'profile_update', array( $this, 'action_update_user' ) );
// Widgets
add_filter( 'widget_update_callback', array( $this, 'action_update_widget' ), 50 );
// Customiser
add_action( 'customize_save_after', array( $this, 'flush_all' ) );
// Theme
add_action( 'switch_theme', array( $this, 'flush_all' ) );
// Nav
add_action( 'wp_update_nav_menu', array( $this, 'flush_all' ) );
// Add site aliases to list of links
add_filter( 'batcache_manager_links', array( $this, 'add_site_alias' ) );
// Do the flush of the urls on shutdown
add_action( 'shutdown', array( $this, 'clear_urls' ) );
}
/**
* Return an instance of this class.
*
* @since 2.0.0
*
* @return object A single instance of this class.
*/
public static function get_instance() {
// If the single instance hasn't been set, set it now.
if ( null == self::$instance ) {
self::$instance = new self;
}
return self::$instance;
}
/**
* Determines whether a post type is considered "viewable".
*
* For built-in post types such as posts and pages, the 'public' value will be evaluated.
* For all others, the 'publicly_queryable' value will be used.
*
*
* @param string $post_type Post type.
*
* @return bool Whether the post type should be considered viewable.
*/
public function is_post_type_viewable( $post_type ) {
$post_type_object = get_post_type_object( $post_type );
if ( empty( $post_type_object ) ) {
return false;
}
return $post_type_object->publicly_queryable || ( $post_type_object->_builtin && $post_type_object->public );
}
/**
* Whether the taxonomy object is public.
*
* Checks to make sure that the taxonomy is an object first. Then Gets the
* object, and finally returns the public value in the object.
*
* A false return value might also mean that the taxonomy does not exist.
*
* @since 2.0.0
*
* @param string $taxonomy Name of taxonomy object.
*
* @return bool Whether the taxonomy is public.
*/
function is_taxonomy_viewable( $taxonomy ) {
if ( ! taxonomy_exists( $taxonomy ) ) {
return false;
}
$taxonomy = get_taxonomy( $taxonomy );
return $taxonomy->public;
}
/**
* Clear post on post update
*
* @param $post_id
*/
public function action_clean_post_cache( $post_id ) {
$post = get_post( $post_id );
if ( $post && $post->post_type && ! $this->is_post_type_viewable( $post->post_type ) || ! in_array( get_post_status( $post_id ), array( 'publish', 'trash' ) ) ) {
return;
}
// Only flush the permalink of the specific post that changed.
// Date archives, author archives, feeds, and the homepage are intentionally
// NOT flushed here — those shared URLs should only be invalidated on a
// full manual flush, not on every individual page save.
$permalink = get_permalink( $post );
if ( ! empty( $permalink ) ) {
$this->links[] = $permalink;
}
// --- START OF MODIFIED CODE ---
// Check if the updated post is a WooCommerce product
if ( 'product' === $post->post_type ) {
$product_url = get_permalink( $post );
// 1. Flush the specific product URL (Batcache)
self::clear_url( $product_url );
// 2. Store the product URL in the option table
update_option( 'edge-cache-single-page-url-purged', $product_url );
// 3. Purge Edge Cache for the specific URL
if (class_exists('Edge_Cache_Plugin')) {
// Set the default timezone to UTC before calling date()
$timezone_backup = date_default_timezone_get();
date_default_timezone_set('UTC');
$edge_cache = Edge_Cache_Plugin::get_instance();
$urls = array($product_url);
// Use the correct method to purge URIs
$result = $edge_cache->purge_uris_now($urls);
// Save time stamp to database if edge cache is purged for particular page
$edge_cache_purge_time = date('jS F Y g:ia') . "\nUTC";
update_option('single-page-edge-cache-purge-time-stamp', $edge_cache_purge_time);
// Restore the original timezone
date_default_timezone_set($timezone_backup);
}
}
// --- END OF MODIFIED CODE ---
}
/**
* Clear terms on term update
*
* @param array $ids Single or list of Term IDs.
* @param string $taxonomy
* @param bool $clean_taxonomy Optional. Whether to clean taxonomy wide caches (true), or just individual
* term object caches (false). Default true. Only support in WP 4.5
*/
public function action_clean_term_cache( $ids, $taxonomy, $clean_taxonomy = true ) {
// Clear taxonomy global caches. If false, lets not both.
if ( ! $clean_taxonomy ) {
return;
}
// If not a public taxonomy, don't clear caches.
if ( ! $this->is_taxonomy_viewable( $taxonomy ) ) {
return;
}
foreach ( $ids as $term ) {
$this->setup_term_urls( $term, $taxonomy );
}
}
/**
* Clear post page on comment update
*
* @param $comment_id
*/
public function action_update_comment( $comment_id ) {
$comment = get_comment( $comment_id );
$post_id = $comment->comment_post_ID;
$this->setup_post_urls( $post_id );
$this->setup_post_comment_urls( $post_id, $comment_id );
}
/**
* Clear author links on update user.
*
* @param $user_id
*/
public function action_update_user( $user_id ) {
$this->setup_author_urls( $user_id );
}
public function flush_all() {
if ( function_exists( 'batcache_flush_all' ) ) {
batcache_flush_all();
}
}
/**
* Flush all of the caches when a widget is updated.
*
* @param array $instance The current widget instance's settings.
*
* @return array $instance
*/
public function action_update_widget( $instance ) {
$this->flush_all();
return $instance;
}
/**
* Get term archive and feed links for each term
*
* @param $term
* @param $taxonomy
*/
public function setup_term_urls( $term, $taxonomy ) {
$term_link = get_term_link( $term, $taxonomy );
if ( ! is_wp_error( $term_link ) ) {
$this->links[] = $term_link;
}
foreach ( $this->feeds as $feed ) {
$term_link_feed = get_term_feed_link( $term, $taxonomy, $feed );
if ( $term_link_feed ) {
$this->links[] = $term_link_feed;
}
}
$taxonomy_object = get_taxonomy( $taxonomy );
if ( $taxonomy_object->show_in_rest && $taxonomy_object->rest_base ) {
$base = $taxonomy_object->rest_base;
$this->links[] = get_rest_url( null, '/wp/v2/' . $base );
$this->links[] = get_rest_url( null, '/wp/v2/' . $base . '/'. $term );
}
}
/**
* Home page / blog page and feed links
*/
public function setup_site_urls() {
if ( get_option( 'show_on_front' ) == 'page' ) {
$this->links[] = get_permalink( get_option( 'page_for_posts' ) );
}
$this->links[] = home_url( '/' );
foreach ( $this->feeds as $feed ) {
$this->links[] = get_feed_link( $feed );
}
}
/**
* Get permalink, date archives and custom post type links
*
* @param $post
*/
public function setup_post_urls( $post ) {
$post = get_post( $post );
$this->links[] = get_permalink( $post );
if ( $post->post_type == 'post' ) {
$year = get_the_time( "Y", $post );
$month = get_the_time( "m", $post );
$day = get_the_time( "d", $post );
$this->links[] = get_year_link( $year );
$this->links[] = get_month_link( $year, $month );
$this->links[] = get_day_link( $year, $month, $day );
} else if ( ! in_array( $post->post_type, get_post_types( array( 'public' => true ) ) ) ) {
if ( $archive_link = get_post_type_archive_link( $post->post_type ) ) {
$this->links[] = $archive_link;
}
foreach ( $this->feeds as $feed ) {
if ( $archive_link_feed = get_post_type_archive_feed_link( $post->post_type, $feed ) ) {
$this->links[] = $archive_link_feed;
}
}
}
$post_type = get_post_type_object( $post->post_type );
if ( $post_type->show_in_rest && $post_type->rest_base ) {
$base = $post_type->rest_base;
$this->links[] = get_rest_url( null, '/wp/v2/' . $base );
$this->links[] = get_rest_url( null, '/wp/v2/' . $base . '/'. $post->ID );
}
}
/**
* Author profile and feed links
*
* @param $author_id
*/
public function setup_author_urls( $author_id ) {
$this->links[] = get_author_posts_url( $author_id );
foreach ( $this->feeds as $feed ) {
$this->links[] = get_author_feed_link( $author_id, $feed );
}
$this->links[] = get_rest_url( null, '/wp/v2/users' );
$this->links[] = get_rest_url( null, '/wp/v2/users/' . $author_id );
}
/**
* Get feed urls for comments for single posts
*
* @param $post_id
*/
public function setup_post_comment_urls( $post_id, $comment_id = 0 ) {
foreach ( $this->feeds as $feed ) {
$this->links[] = get_post_comments_feed_link( $post_id, $feed );
}
foreach ( $this->feeds as $feed ) {
$this->links[] = get_feed_link( "comments_" . $feed );
}
$this->links[] = get_rest_url( null, '/wp/v2/comments' );
$this->links[] = get_rest_url( null, '/wp/v2/comments/' . $comment_id );
}
/**
* Work around for those using Domain mapping or have CMS on different url.
*
* @param $links
*/
public function add_site_alias( $links ) {
$home = parse_url( home_url(), PHP_URL_HOST );
$compare_urls = array(
parse_url( get_option( 'home' ), PHP_URL_HOST ),
parse_url( get_option( 'siteurl' ), PHP_URL_HOST ),
parse_url( site_url(), PHP_URL_HOST )
);
// Compare home, site urls with filtered home url
foreach ( $compare_urls as $compare_url ) {
if ( $compare_url != $home ) {
foreach ( $links as $url ) {
$links[] = str_replace( $home, $compare_url, $url );
}
}
}
return $links;
}
/**
* Loop around all urls and clear
*/
public function clear_urls() {
if ( empty ( $this->get_links() ) ) {
return;
}
foreach ( $this->get_links() as $url ) {
self::clear_url( $url );
}
// Clear out links
$this->links = array();
// --- START OF MODIFIED CODE ---
// Set the default timezone to UTC before calling date()
$timezone_backup = date_default_timezone_get();
date_default_timezone_set('UTC');
// Update the timestamp option with the specified format
$batcache_flush_time = date('jS F Y g:ia') . "\nUTC";
update_option( 'flush-object-cache-for-single-page-time-stamp', $batcache_flush_time );
// Restore the original timezone
date_default_timezone_set($timezone_backup);
// --- END OF MODIFIED CODE ---
}
/**
*
* @param $url
*
* @return bool|false|int
*/
public static function clear_url( $url ) {
global $batcache, $wp_object_cache;
$url = apply_filters( 'batcache_manager_link', $url );
if ( empty( $url ) ) {
return false;
}
do_action( 'batcache_manager_before_flush', $url );
// Force to http
$url = set_url_scheme( $url, 'http' );
$url_key = md5( $url );
wp_cache_add( "{$url_key}_version", 0, $batcache->group );
$retval = wp_cache_incr( "{$url_key}_version", 1, $batcache->group );
// $batcache_no_remote_group_key = array_search( $batcache->group, (array) $wp_object_cache->no_remote_groups );
$batcache_no_remote_group_key = property_exists($wp_object_cache, 'no_remote_groups') ? array_search( $batcache->group, (array) $wp_object_cache->no_remote_groups ) : false;
if ( false !== $batcache_no_remote_group_key ) {
// The *_version key needs to be replicated remotely, otherwise invalidation won't work.
// The race condition here should be acceptable.
unset( $wp_object_cache->no_remote_groups[ $batcache_no_remote_group_key ] );
$retval = wp_cache_set( "{$url_key}_version", $retval, $batcache->group );
$wp_object_cache->no_remote_groups[ $batcache_no_remote_group_key ] = $batcache->group;
}
do_action( 'batcache_manager_after_flush', $url, $retval );
return $retval;
}
/**
* Filter links
*
* @return array
*/
public function get_links() {
$this->links = apply_filters( 'batcache_manager_links', $this->links );
return array_unique( $this->links );
}
}
global $batcache_manager;
$batcache_manager = Batcache_Manager::get_instance();
@@ -0,0 +1,64 @@
<?php // Pressable Cache Management mu-plugins index
// disable direct file access
if (!defined('ABSPATH'))
{
exit;
}
/*****
* This file references the Pressable Cache Management mu-plugins
* https://wordpress.org/documentation/article/must-use-plugins/
******/
if(file_exists(WPMU_PLUGIN_DIR.'/pressable-cache-management/pcm_extend_batcache.php')) {
require WPMU_PLUGIN_DIR.'/pressable-cache-management/pcm_extend_batcache.php';
}
if(file_exists(WPMU_PLUGIN_DIR.'/pressable-cache-management/cdn_exclude_specific_file.php')) {
require WPMU_PLUGIN_DIR.'/pressable-cache-management/cdn_exclude_specific_file.php';
}
if(file_exists(WPMU_PLUGIN_DIR.'/pressable-cache-management/pcm_cdn_extender.php')) {
require WPMU_PLUGIN_DIR.'/pressable-cache-management/pcm_cdn_extender.php';
}
if(file_exists(WPMU_PLUGIN_DIR.'/pressable-cache-management/cdn_exclude_jpg_png_webp.php')) {
require WPMU_PLUGIN_DIR.'/pressable-cache-management/cdn_exclude_jpg_png_webp.php';
}
if(file_exists(WPMU_PLUGIN_DIR.'/pressable-cache-management/cdn_exclude_css.php')) {
require WPMU_PLUGIN_DIR.'/pressable-cache-management/cdn_exclude_css.php';
}
if(file_exists(WPMU_PLUGIN_DIR.'/pressable-cache-management/cdn_exclude_js_json.php')) {
require WPMU_PLUGIN_DIR.'/pressable-cache-management/cdn_exclude_js_json.php';
}
if(file_exists(WPMU_PLUGIN_DIR.'/pressable-cache-management/pcm_exclude_font_files_from_cdn.php')) {
require WPMU_PLUGIN_DIR.'/pressable-cache-management/pcm_exclude_font_files_from_cdn.php';
}
// if(file_exists(WPMU_PLUGIN_DIR.'/pressable-cache-management/batcache_manager.php')) {
// require WPMU_PLUGIN_DIR.'/pressable-cache-management/pcm_batcache_manager.php.php';
// }
if(file_exists(WPMU_PLUGIN_DIR.'/pressable-cache-management/pcm_cache_wpp_cookies_pages.php')) {
require WPMU_PLUGIN_DIR.'/pressable-cache-management/pcm_cache_wpp_cookies_pages.php';
}
if(file_exists(WPMU_PLUGIN_DIR.'/pressable-cache-management/pcm_exclude_query_string_gclid.php')) {
require WPMU_PLUGIN_DIR.'/pressable-cache-management/pcm_exclude_query_string_gclid.php';
}
if(file_exists(WPMU_PLUGIN_DIR.'/pressable-cache-management/pcm_exclude_pages_from_batcache.php')) {
require WPMU_PLUGIN_DIR.'/pressable-cache-management/pcm_exclude_pages_from_batcache.php';
}
@@ -0,0 +1,122 @@
<?php
/**
* Pressable Edge Cache Purge Functionality
* Mirrors the official repo's purge-edge-cache.php exactly,
* with branded admin notices applied.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( isset( $_POST['purge_edge_cache_nonce'] ) ) {
if ( ! function_exists( 'pcm_pressable_edge_cache_purge_local' ) ) {
function pcm_pressable_edge_cache_purge_local() {
// 1. Verify nonce + capability
if (
! isset( $_POST['purge_edge_cache_nonce'] ) ||
! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['purge_edge_cache_nonce'] ) ), 'purge_edge_cache_nonce' ) ||
! current_user_can( 'manage_options' )
) {
return;
}
// 2. Ensure Edge Cache Plugin exists
if ( ! class_exists( 'Edge_Cache_Plugin' ) ) {
add_action( 'admin_notices', function() {
if ( function_exists( 'pcm_branded_notice' ) ) {
pcm_branded_notice( esc_html__( 'Error: Edge Cache Plugin is not active.', 'pressable_cache_management' ), '#dd3a03' );
} else {
printf( '<div class="notice notice-error is-dismissible"><p>%s</p></div>', esc_html__( 'Error: Edge Cache Plugin is not active.', 'pressable_cache_management' ) );
}
});
return;
}
// 3. Get Edge Cache instance and current status
$edge_cache = Edge_Cache_Plugin::get_instance();
$status_method = method_exists( $edge_cache, 'get_ec_status' ) ? 'get_ec_status' : null;
$enable_method = method_exists( $edge_cache, 'enable_ec' ) ? 'enable_ec' : null;
$server_status = $status_method ? $edge_cache->$status_method() : null;
$auto_enabled = false;
// 4. If disabled, handle based on availability of enable_ec()
if ( Edge_Cache_Plugin::EC_DISABLED === $server_status ) {
if ( null !== $enable_method ) {
$enabled = $edge_cache->$enable_method();
if ( $enabled ) {
$auto_enabled = true;
sleep( 2 );
} else {
add_action( 'admin_notices', function() {
if ( function_exists( 'pcm_branded_notice' ) ) {
pcm_branded_notice( esc_html__( 'Edge Cache was disabled and could not be auto-enabled. Purge aborted.', 'pressable_cache_management' ), '#dd3a03' );
} else {
printf( '<div class="notice notice-error is-dismissible"><p>%s</p></div>', esc_html__( 'Edge Cache was disabled and could not be auto-enabled. Purge aborted.', 'pressable_cache_management' ) );
}
});
return;
}
} else {
add_action( 'admin_notices', function() {
if ( function_exists( 'pcm_branded_notice' ) ) {
pcm_branded_notice( esc_html__( 'Edge Cache is disabled on the server. Enable Edge Cache.', 'pressable_cache_management' ), '#f59e0b' );
} else {
printf( '<div class="notice notice-warning is-dismissible"><p>%s</p></div>', esc_html__( 'Edge Cache is disabled on the server. Enable Edge Cache.', 'pressable_cache_management' ) );
}
});
return;
}
}
// 5. Purge domain cache
$result = method_exists( $edge_cache, 'purge_domain_now' )
? $edge_cache->purge_domain_now( 'dashboard-auto-purge' )
: false;
if ( $result ) {
update_option( 'edge-cache-purge-time-stamp', gmdate( 'jS F Y g:ia' ) . ' UTC' );
// Clear the Batcache status transient so the badge re-probes immediately.
// Without this the badge can sit on 'active' for up to 90s after a purge
// even though Batcache is now in a transitional broken state.
do_action( 'pcm_after_edge_cache_purge' );
$message = $auto_enabled
? esc_html__( 'Edge Cache was disabled on the server. It has been automatically enabled and purged successfully.', 'pressable_cache_management' )
: esc_html__( 'Edge Cache purged successfully.', 'pressable_cache_management' );
add_action( 'admin_notices', function() use ( $message ) {
if ( function_exists( 'pcm_branded_notice' ) ) {
pcm_branded_notice( $message, '#03fcc2' );
} else {
printf( '<div class="notice notice-success is-dismissible"><p>%s</p></div>', esc_html( $message ) );
}
});
} else {
add_action( 'admin_notices', function() {
if ( function_exists( 'pcm_branded_notice' ) ) {
pcm_branded_notice( esc_html__( 'Edge Cache purge failed. Please try again.', 'pressable_cache_management' ), '#dd3a03' );
} else {
printf( '<div class="notice notice-error is-dismissible"><p>%s</p></div>', esc_html__( 'Edge Cache purge failed. Please try again.', 'pressable_cache_management' ) );
}
});
}
}
add_action( 'init', 'pcm_pressable_edge_cache_purge_local' );
}
}
// Prevent duplicate section callback declarations
if ( ! function_exists( 'pressable_cache_management_callback_section_edge_cache' ) ) {
function pressable_cache_management_callback_section_edge_cache() {
echo '<p>' . esc_html__( 'These settings enable you to manage Edge Cache.', 'pressable_cache_management' ) . '</p>';
}
}
if ( ! function_exists( 'pressable_cache_management_callback_section_cache' ) ) {
function pressable_cache_management_callback_section_cache() {
echo '<p>' . esc_html__( 'These settings enable you to manage the object cache.', 'pressable_cache_management' ) . '</p>';
}
}
@@ -0,0 +1,63 @@
<?php //Pressable Cache Management - Custom function to turn on/off Pressable branding
/******************************
* Show branding Option
*******************************/
$pressable_branding = false;
$hide_pressable_branding_tab_options = get_option('remove_pressable_branding_tab_options');
//Check if options are set before processing
if (isset($hide_pressable_branding_tab_options['branding_on_off_radio_button']) && !empty($hide_pressable_branding_tab_options['branding_on_off_radio_button']))
{
$hide_pressable_branding_tab_options = sanitize_text_field($hide_pressable_branding_tab_options['branding_on_off_radio_button']);
}
//Set radion button state to defualt
if ('enable' === $hide_pressable_branding_tab_options)
{
$hide_pressable_branding_tab_options = get_option('remove_pressable_branding_tab_options');
// echo 'Show Branding';
//run your functions here if radio button is enabled
}
/******************************
* Hide branding Option
*******************************/
else
{
$pressable_branding = false;
$pressable_branding = get_option('remove_pressable_branding_tab_options');
//Check if options are set before processing
if (isset($hide_pressable_branding_tab_options['branding_on_off_radio_button']) && !empty($hide_pressable_branding_tab_options['branding_on_off_radio_button']))
{
$hide_pressable_branding_tab_options = sanitize_text_field($hide_pressable_branding_tab_options['branding_on_off_radio_button']);
}
//Set radio button state to defualt
if ('disable' === $hide_pressable_branding_tab_options)
{
$hide_pressable_branding_tab_options = get_option('remove_pressable_branding_tab_options');
// echo 'Hide Branding';
//run your functions here if radio button is disbaled
}
}
@@ -0,0 +1,146 @@
<?php
/**
* Pressable Cache Management - Turn On/Off Edge Cache
* Based directly on the official repo's turn-on-off-edge-cache.php
* with branded admin notices applied.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// ─── Shared branded notice helper (defined once here) ──────────────────────
if ( ! function_exists( 'pcm_branded_notice' ) ) {
function pcm_branded_notice( $message, $border_color = '#03fcc2', $is_html = false ) {
$id = 'pcm-notice-' . substr( md5( $message . $border_color . microtime() ), 0, 8 );
$wrap = 'display:inline-flex;align-items:flex-start;justify-content:space-between;gap:16px;'
. 'border-left:4px solid ' . esc_attr( $border_color ) . ';background:#fff;'
. 'border-radius:0 8px 8px 0;padding:14px 18px;'
. 'box-shadow:0 2px 8px rgba(4,0,36,.07);margin:10px 20px 10px 0;font-family:sans-serif;'
. 'min-width:260px;max-width:520px;';
$btn = 'background:none;border:none;cursor:pointer;color:#94a3b8;font-size:18px;'
. 'line-height:1;padding:0;flex-shrink:0;margin-top:2px;';
echo '<div id="' . esc_attr( $id ) . '" style="' . $wrap . '">';
echo '<div style="flex:1;">';
if ( $is_html ) {
echo $message; // caller already escaped
} else {
echo '<p style="margin:0;font-size:13px;color:#040024;">' . esc_html( $message ) . '</p>';
}
echo '</div>';
echo '<button type="button" onclick="document.getElementById(\'' . esc_js( $id ) . '\').remove();" style="' . $btn . '">&#x2297;</button>';
echo '</div>';
}
}
// ─── Notice: Edge Cache Enabled ─────────────────────────────────────────────
if ( ! function_exists( 'pressable_edge_cache_notice_success_enable' ) ) {
function pressable_edge_cache_notice_success_enable() {
$screen = get_current_screen();
if ( isset( $screen ) && 'toplevel_page_pressable_cache_management' !== $screen->id ) return;
$html = '<h3 style="margin:0 0 8px;font-size:14px;font-weight:700;color:#040024;">'
. '&#x1F389; ' . esc_html__( 'Edge Cache Enabled!', 'pressable_cache_management' ) . '</h3>';
$html .= '<p style="margin:0 0 6px;font-size:13px;color:#475569;">'
. esc_html__( 'Edge Cache provides performance improvements, particularly for Time to First Byte (TTFB), by serving page cache from the nearest server to your website visitors.', 'pressable_cache_management' )
. '</p>';
$html .= '<a href="https://pressable.com/knowledgebase/edge-cache/" target="_blank" '
. 'rel="noopener noreferrer" style="font-size:13px;color:#dd3a03;font-weight:600;text-decoration:none;">'
. esc_html__( 'Learn more about Edge Cache.', 'pressable_cache_management' ) . '</a>';
$nid = 'pcm-ec-enabled-' . substr( md5( microtime() ), 0, 8 );
$wrap = 'display:flex;align-items:flex-start;justify-content:space-between;gap:16px;'
. 'border-left:4px solid #03fcc2;background:#fff;'
. 'border-radius:0 8px 8px 0;padding:14px 18px;'
. 'box-shadow:0 2px 8px rgba(4,0,36,.07);margin:10px 0;font-family:sans-serif;';
$btn = 'background:none;border:none;cursor:pointer;color:#94a3b8;font-size:18px;'
. 'line-height:1;padding:0;flex-shrink:0;margin-top:2px;';
echo '<div style="max-width:920px;margin:0 20px;">';
echo '<div id="' . esc_attr( $nid ) . '" style="' . $wrap . '">';
echo '<div style="flex:1;">' . $html . '</div>';
echo '<button type="button" onclick="document.getElementById(\'' . esc_js( $nid ) . '\').remove();" style="' . $btn . '">&#x2297;</button>';
echo '</div>';
echo '</div>';
}
}
// ─── Notice: Edge Cache Disabled ────────────────────────────────────────────
if ( ! function_exists( 'pressable_edge_cache_notice_success_disable' ) ) {
function pressable_edge_cache_notice_success_disable() {
$screen = get_current_screen();
if ( isset( $screen ) && 'toplevel_page_pressable_cache_management' !== $screen->id ) return;
pcm_branded_notice( esc_html__( 'Edge Cache Deactivated.', 'pressable_cache_management' ), '#03fcc2' );
}
}
// ─── Notice: Error ───────────────────────────────────────────────────────────
if ( ! function_exists( 'pcm_pressable_edge_cache_error_msg' ) ) {
function pcm_pressable_edge_cache_error_msg( $error_message = '' ) {
$screen = get_current_screen();
if ( isset( $screen ) && 'toplevel_page_pressable_cache_management' !== $screen->id ) return;
$msg = empty( $error_message )
? esc_html__( 'Something went wrong trying to communicate with the Edge Cache system. Try again.', 'pressable_cache_management' )
: esc_html( $error_message );
pcm_branded_notice( $msg, '#dd3a03' );
}
}
// ─── Enable Edge Cache (mirrors repo exactly, adds branded notices) ─────────
function pcm_pressable_enable_edge_cache() {
if ( isset( $_POST['enable_edge_cache_nonce'] ) &&
wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['enable_edge_cache_nonce'] ) ), 'enable_edge_cache_nonce' ) ) {
if ( class_exists( 'Edge_Cache_Plugin' ) ) {
$edge_cache = Edge_Cache_Plugin::get_instance();
$result = $edge_cache->query_ec_backend( 'on', array( 'wp_action' => 'manual_dashboard_set' ) );
if ( is_wp_error( $result ) ) {
update_option( 'edge-cache-status', 'Error' );
update_option( 'edge-cache-enabled', 'disabled' );
add_action( 'admin_notices', function() use ( $result ) {
pcm_pressable_edge_cache_error_msg( $result->get_error_message() );
});
} else {
update_option( 'edge-cache-status', 'Success' );
update_option( 'edge-cache-enabled', 'enabled' );
delete_transient( 'pcm_ec_status_cache' ); // force fresh status on next page load
add_action( 'admin_notices', 'pressable_edge_cache_notice_success_enable' );
}
} else {
add_action( 'admin_notices', function() {
pcm_pressable_edge_cache_error_msg( 'Required Edge Cache dependency is not available.' );
});
}
}
}
add_action( 'init', 'pcm_pressable_enable_edge_cache' );
// ─── Disable Edge Cache (mirrors repo exactly, adds branded notices) ────────
function pcm_pressable_disable_edge_cache() {
if ( isset( $_POST['disable_edge_cache_nonce'] ) &&
wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['disable_edge_cache_nonce'] ) ), 'disable_edge_cache_nonce' ) ) {
if ( class_exists( 'Edge_Cache_Plugin' ) ) {
$edge_cache = Edge_Cache_Plugin::get_instance();
$result = $edge_cache->query_ec_backend( 'off', array( 'wp_action' => 'manual_dashboard_set' ) );
if ( is_wp_error( $result ) ) {
update_option( 'edge-cache-status', 'Error' );
update_option( 'edge-cache-enabled', 'enabled' ); // stays enabled on failure
add_action( 'admin_notices', function() use ( $result ) {
pcm_pressable_edge_cache_error_msg( $result->get_error_message() );
});
} else {
update_option( 'edge-cache-status', 'Success' );
update_option( 'edge-cache-enabled', 'disabled' );
delete_transient( 'pcm_ec_status_cache' ); // force fresh status on next page load
add_action( 'admin_notices', 'pressable_edge_cache_notice_success_disable' );
}
} else {
add_action( 'admin_notices', function() {
pcm_pressable_edge_cache_error_msg( 'Required Edge Cache dependency is not available.' );
});
}
}
}
add_action( 'init', 'pcm_pressable_disable_edge_cache' );
@@ -0,0 +1,181 @@
<?php
function pressable_cache_extend()
{
}
// http://www.php.net/is_writable
function is_writeable_wp_config($path)
{
if ((defined('PHP_OS_FAMILY') && 'Windows' !== constant('PHP_OS_FAMILY')) || stristr(PHP_OS, 'DAR') || !stristr(PHP_OS, 'WIN'))
{
return is_writeable($path);
}
// PHP's is_writable does not work with Win32 NTFS
if ($path[strlen($path) - 1] == '/')
{ // recursively return a temporary file path
return is_writeable_wp_config($path . uniqid(mt_rand()) . '.tmp');
}
elseif (is_dir($path))
{
return is_writeable_wp_config($path . '/' . uniqid(mt_rand()) . '.tmp');
}
// check tmp file for read/write capabilities
$rm = file_exists($path);
$f = @fopen($path, 'a');
if ($f === false) return false;
fclose($f);
if (!$rm)
{
unlink($path);
}
return true;
}
// function wp_cache_setting( $field, $value ) {
// global $wp_cache_config_file;
// $GLOBALS[ $field ] = $value;
// if ( is_numeric( $value ) ) {
// return wp_config_file_replace_line( '^ *\$' . $field, "\$$field = $value;", $wp_cache_config_file );
// } elseif ( is_bool( $value ) ) {
// $output_value = $value === true ? 'true' : 'false';
// return wp_config_file_replace_line( '^ *\$' . $field, "\$$field = $output_value;", $wp_cache_config_file );
// } elseif ( is_object( $value ) || is_array( $value ) ) {
// $text = var_export( $value, true );
// $text = preg_replace( '/[\s]+/', ' ', $text );
// return wp_config_file_replace_line( '^ *\$' . $field, "\$$field = $text;", $wp_cache_config_file );
// } else {
// return wp_config_file_replace_line( '^ *\$' . $field, "\$$field = '$value';", $wp_cache_config_file );
// }
// }
function wp_config_file_replace_line($old, $new, $my_file)
{
if (@is_file($my_file) == false)
{
if (function_exists('set_transient'))
{
set_transient('wpsc_config_error', 'config_file_missing', 10);
}
return false;
}
if (!is_writeable_wp_config($my_file))
{
if (function_exists('set_transient'))
{
set_transient('wpsc_config_error', 'config_file_ro', 10);
}
trigger_error("Error: file $my_file is not writable.");
return false;
}
$found = false;
$loaded = false;
$c = 0;
$lines = array();
while (!$loaded)
{
$lines = file($my_file);
if (!empty($lines) && is_array($lines))
{
$loaded = true;
}
else
{
$c++;
if ($c > 100)
{
if (function_exists('set_transient'))
{
set_transient('wpsc_config_error', 'config_file_not_loaded', 10);
}
trigger_error("wp_config_file_replace_line: Error - file $my_file could not be loaded.");
return false;
}
}
}
foreach ((array)$lines as $line)
{
if (trim($new) != '' && trim($new) == trim($line))
{
pressable_cache_extend("wp_config_file_replace_line: setting not changed - $new");
return true;
}
elseif (preg_match("/$old/", $line))
{
pressable_cache_extend("wp_config_file_replace_line: changing line " . trim($line) . " to *$new*");
$found = true;
}
}
global $cache_path;
$tmp_config_filename = tempnam($GLOBALS['cache_path'], 'wpsc');
rename($tmp_config_filename, $tmp_config_filename . ".php");
$tmp_config_filename .= ".php";
pressable_cache_extend('wp_config_file_replace_line: writing to ' . $tmp_config_filename);
$fd = fopen($tmp_config_filename, 'w');
if (!$fd)
{
if (function_exists('set_transient'))
{
set_transient('wpsc_config_error', 'config_file_ro', 10);
}
trigger_error("wp_config_file_replace_line: Error - could not write to $my_file");
return false;
}
if ($found)
{
foreach ((array)$lines as $line)
{
if (!preg_match("/$old/", $line))
{
fputs($fd, $line);
}
elseif ($new != '')
{
fputs($fd, "$new\n");
}
}
}
else
{
$done = false;
foreach ((array)$lines as $line)
{
// if ( $done || ! preg_match( '/\brequire_once\b/i', $line ) ) {
if ($done || !preg_match('/\b(require_once)\b/', $line))
{
fputs($fd, $line);
}
else
{
//add fputs($fd, "$new\n"); here to write function above require_once
fputs($fd, $line);
//Write function at the button of require_once
fputs($fd, "$new\n");
$done = true;
}
}
}
fclose($fd);
rename($tmp_config_filename, $my_file);
pressable_cache_extend('wp_config_file_replace_line: moved ' . $tmp_config_filename . ' to ' . $my_file);
// if (function_exists("opcache_invalidate"))
// {
// @opcache_invalidate($my_file);
// }
if (function_exists("wp_opcache_invalidate"))
{
wp_opcache_invalidate($my_file);
}
return true;
}
@@ -0,0 +1 @@
<?php // Silence is golden
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12pt" height="12pt" viewBox="0 0 12 12" version="1.1">
<g id="surface1">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 0 0 L 0 0.0078125 L 0.0078125 0 Z M 0 0 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 6.140625 2.621094 L 4.355469 2.621094 L 4.355469 5.902344 L 6.140625 5.902344 C 7.5625 5.902344 7.902344 5.605469 7.902344 4.363281 L 7.902344 4.160156 C 7.898438 2.917969 7.554688 2.621094 6.140625 2.621094 Z M 6.140625 2.621094 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 0 0 L 0 12 L 7.691406 12 L 12.003906 7.683594 L 12.003906 0 Z M 8.984375 4.363281 C 8.984375 6.304688 8.253906 6.847656 6.136719 6.847656 L 4.355469 6.847656 L 4.355469 10.027344 C 4.363281 10.105469 4.339844 10.183594 4.285156 10.246094 C 4.226562 10.304688 4.152344 10.335938 4.074219 10.332031 C 3.824219 10.332031 3.289062 10.261719 3.289062 10.121094 L 3.289062 1.980469 C 3.289062 1.71875 3.417969 1.667969 3.585938 1.667969 L 6.140625 1.667969 C 8.296875 1.667969 8.996094 2.261719 8.996094 4.160156 Z M 8.984375 4.363281 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -0,0 +1 @@
<?php // Silence is golden
@@ -0,0 +1,91 @@
/**
* Pressable Cache Management - Flush cache for individual page column
* Branded modal popup replaces browser alert()
*/
if (window.attachEvent) {
window.attachEvent('onload', flush_object_cache_column_button_action);
} else {
if (window.onload) {
var curronload_1 = window.onload;
var newonload_1 = function(evt) { curronload_1(evt); flush_object_cache_column_button_action(evt); };
window.onload = newonload_1;
} else {
window.onload = flush_object_cache_column_button_action;
}
}
/* ── Branded modal (injected once) ─────────────────────────────────────── */
function pcmEnsureModal() {
if (document.getElementById('pcm-col-modal-overlay')) return;
var overlay = document.createElement('div');
overlay.id = 'pcm-col-modal-overlay';
overlay.style.cssText =
'display:none;position:fixed;inset:0;background:rgba(4,0,36,.45);'
+ 'z-index:999999;align-items:center;justify-content:center;';
overlay.innerHTML =
'<div style="background:#fff;border-radius:12px;padding:28px 32px;max-width:420px;width:90%;'
+ 'box-shadow:0 8px 40px rgba(4,0,36,.18);font-family:sans-serif;position:relative;">'
+ '<div style="width:48px;height:4px;background:#03fcc2;border-radius:4px;margin-bottom:16px;"></div>'
+ '<p id="pcm-col-modal-msg" style="margin:0 0 22px;font-size:14px;color:#040024;line-height:1.6;"></p>'
+ '<button id="pcm-col-modal-ok" style="background:#dd3a03;color:#fff;border:none;border-radius:8px;'
+ 'padding:10px 28px;font-size:13.5px;font-weight:700;cursor:pointer;font-family:sans-serif;'
+ 'transition:background .2s;">OK</button>'
+ '</div>';
document.body.appendChild(overlay);
overlay.style.display = 'flex'; overlay.style.display = 'none'; // force style parse
document.getElementById('pcm-col-modal-ok').addEventListener('click', function() {
overlay.style.display = 'none';
});
overlay.addEventListener('click', function(e) {
if (e.target === overlay) overlay.style.display = 'none';
});
// hover on OK button
var okBtn = document.getElementById('pcm-col-modal-ok');
okBtn.addEventListener('mouseenter', function() { okBtn.style.background = '#b82f00'; });
okBtn.addEventListener('mouseleave', function() { okBtn.style.background = '#dd3a03'; });
}
function pcmShowColumnModal(msg) {
pcmEnsureModal();
document.getElementById('pcm-col-modal-msg').textContent = msg;
document.getElementById('pcm-col-modal-overlay').style.display = 'flex';
}
function flush_object_cache_column_button_action() {
jQuery(document).ready(function($) {
$("a[id^='flush-object-cache-url']").on('click', function(e) {
e.preventDefault();
var post_id = $(e.currentTarget).attr('data-id');
var nonce = $(e.currentTarget).attr('data-nonce');
$('#flush-object-cache-url-' + post_id).css('cursor', 'wait');
$.ajax({
type: 'GET',
url: ajaxurl,
data: { action: 'pcm_flush_object_cache_column', id: post_id, nonce: nonce },
dataType: 'json',
cache: false,
success: function(data) {
$('#flush-object-cache-url-' + post_id).css('cursor', 'pointer');
if (typeof data.success !== 'undefined' && data.success === true) {
pcmShowColumnModal('Batcache flushed successfully \u2705');
} else {
pcmShowColumnModal('Something went wrong while trying to flush the cache for this page.');
}
},
error: function() {
$('#flush-object-cache-url-' + post_id).css('cursor', 'pointer');
pcmShowColumnModal('Request failed. Please try again.');
}
});
return false;
});
});
}
@@ -0,0 +1,89 @@
/**
* Pressable Cache Management — Toolbar JS
*
* Handles the combined "Flush Cache for This Page" admin bar button.
*
* Bug fixes vs previous version:
* 1. data-edge on <li> is unsupported by WP add_menu() meta — now uses pcmToolbarData.flushEdge
* passed via wp_localize_script() which works on both admin and frontend.
* 2. Event delegation now targets document.body and checks closest('li').attr('id') correctly,
* rather than querying a non-existent '#wp-admin-bar-*-default' wrapper selector.
* 3. pcm_nonce was only available on frontend (wp_footer). Now comes from pcmToolbarData.nonce
* which is always present via wp_localize_script.
* 4. AJAX handlers now return wp_send_json_success() so jQuery parses valid JSON.
*/
jQuery(document).ready(function($) {
// Ensure the loader overlay exists once
if ( !$('#revert-loader-toolbar').length ) {
$('body').append('<div id="revert-loader-toolbar"></div>');
}
// Resolve AJAX URL: prefer localized value, fall back to WP global
var ajaxUrl = ( typeof pcmToolbarData !== 'undefined' && pcmToolbarData.ajaxurl )
? pcmToolbarData.ajaxurl
: ( typeof ajaxurl !== 'undefined' ? ajaxurl : '' );
// Nonce: from wp_localize_script (works on both admin + frontend)
var nonce = ( typeof pcmToolbarData !== 'undefined' ) ? pcmToolbarData.nonce : '';
// Whether edge cache flush should also fire (passed from PHP via wp_localize_script)
var flushEdge = ( typeof pcmToolbarData !== 'undefined' && pcmToolbarData.flushEdge === '1' );
// ── IDs for both branding variants ───────────────────────────────────────
var combinedIds = [
'wp-admin-bar-pcm-toolbar-parent-flush-cache-of-this-page',
'wp-admin-bar-pcm-toolbar-parent-remove-branding-flush-cache-of-this-page',
];
// ── Fire a single AJAX GET, returns a jQuery deferred ────────────────────
function sendRequest( action ) {
return $.ajax({
type : 'GET',
url : ajaxUrl,
data : { action: action, path: window.location.pathname, nonce: nonce },
dataType: 'json',
cache : false,
});
}
// ── Sequential flush: Batcache first, then Edge Cache if active ───────────
function flushCurrentPage() {
$('#revert-loader-toolbar').show();
sendRequest('pcm_delete_current_page_cache')
.always(function() {
if ( flushEdge ) {
sendRequest('pcm_purge_current_page_edge_cache')
.always(done);
} else {
done();
}
});
}
function done() {
if ( typeof pcmCacheStatics !== 'undefined' ) {
pcmCacheStatics.update();
} else {
$('#revert-loader-toolbar').hide();
}
}
// ── Event delegation on body — catches clicks anywhere inside the <li> ───
// We delegate from body because the admin bar is injected late and the
// submenu UL wrapper varies by WP version. Matching by the <li> id directly
// is the most reliable approach and avoids the broken '-default' suffix.
$('body').on('click', function(e) {
// Walk up from the clicked element to find the nearest <li>
var $li = $(e.target).closest('li');
var id = $li.attr('id') || '';
if ( combinedIds.indexOf(id) !== -1 ) {
e.preventDefault();
flushCurrentPage();
}
});
});
@@ -0,0 +1,6 @@
/**
* Pressable Cache Management — toolbar_remove_branding.js
* This file is intentionally empty.
* The branding-off toolbar handler is now consolidated in toolbar.js
* (PCM_TOOLBAR_REMOVE_BRANDING object) to avoid duplicate AJAX calls.
*/
@@ -0,0 +1,672 @@
<?php //Pressable Cache Management - Settings Callbacks
// Disable direct file access
if (!defined('ABSPATH'))
{
exit;
}
/**********************************************
* Process all call-backs from the plugin forms
**********************************************/
// callback: object cache section section
function pressable_cache_management_callback_section_cache()
{
$remove_pressable_branding_tab_options = false;
$remove_pressable_branding_tab_options = get_option('remove_pressable_branding_tab_options');
if ($remove_pressable_branding_tab_options && 'disable' == $remove_pressable_branding_tab_options['branding_on_off_radio_button'])
{
}
else
{
//Pressable branding logo
echo '<div><img width="230" height="50" class="pressablecmlogo" src="' . plugin_dir_url(__FILE__) . '/assets/img/pressable-logo-primary.svg' . '" > </div>';
}
echo '<p>' . esc_html__('These settings enable you to manage the object cache.', 'pressable_cache_management') . '</p>';
// Check if the site uses Cloudflare
$response = wp_remote_get( get_site_url(), array( 'timeout' => 120 ) );
$headers = wp_remote_retrieve_headers( $response );
if ( isset( $headers['server'] ) && stripos( $headers['server'], 'cloudflare' ) !== false ) {
//Cloudflare is present in the website header.
// Check Batcache status
$site_url = get_site_url();
$response = wp_remote_get( $site_url, array( 'timeout' => 120 ) );
if ( is_wp_error( $response ) || strpos( $response['body'], 'batcache' ) === false ) {
echo '<p style="text-align:right; font-weight:bold">Batcache Status: Broken &#128308;</p>';
echo '<p style="text-align:right; font-size: smaller;">Disable Cloudflare proxy and caching and try again &#x1F7E0</p></br>';
} else {
echo '<p style="text-align:right; font-weight:bold">Batcache Status: OK &#x1F7E2;</p>';
}
} else {
//Cloudflare is not present in the website header.
// Check for Batcache
$site_url = get_site_url();
$response = wp_remote_get( $site_url, array( 'timeout' => 120 ) );
if ( is_wp_error( $response ) || strpos( $response['body'], 'batcache' ) === false ) {
echo '<p style="text-align:right; font-weight:bold">Batcache Status: Broken &#128308;</p></br>';
} else {
echo '<p style="text-align:right; font-weight:bold">Batcache Status: OK &#x1F7E2;</p>';
}
}
}
// RESTORED: This function is required by admin/settings-validate.php but was accidentally removed during cleanup.
function pressable_cache_management_options_radio_button()
{
return array(
'enable' => esc_html__('Enable CDN (Recommended)', 'pressable_cache_management') ,
'disable' => esc_html__('Disable CDN', 'pressable_cache_management')
);
}
// Removed redundant code related to CDN and old API flags
$pcm_con_auth = 'pressable_api_admin_notice__status';
// If the option already exists, update it to "OK"
if ( get_option( $pcm_con_auth ) !== false ) {
update_option( $pcm_con_auth, 'OK' );
} else {
add_option( $pcm_con_auth, 'OK' );
}
function pressable_cache_management_callback_section_edge_cache()
{
echo '<p>' . esc_html__('These settings enable you to manage Edge Cache settings.', 'pressable_cache_management') . '</p>';
}
// callback: Hide Pressable branding tab page description
function pressable_cache_management_callback_section_branding()
{
echo '<p>' . esc_html__('This setting allows you to show or hide the plugin branding.', 'pressable_cache_management') . '</p>';
}
/**
********************************
* Object Cache *
* Management Tab *
********************************
*
*/
// Flush object cache button
function pressable_cache_management_callback_field_button($args)
{
$options = get_option('pressable_cache_management_options');
$id = isset($args['id']) ? $args['id'] : '';
$label = isset($args['label']) ? $args['label'] : '';
echo '</form>';
echo '<form method="post" id="flush_object_cache_nonce">
<span id="flush_cache_button">
<input id="pressable_cache_management_options_' . esc_attr( $id ) . '" name="pressable_cache_management_options[' . $id . ']" type="submit" size="40" value="' . __('Flush Cache', 'pressable_cache_management') . '" class="flushcache"/><input type="hidden" name="flush_object_cache_nonce" value="' . wp_create_nonce('flush_object_cache_nonce') . '" <br/><label class="rad-text for="pressable_cache_management_options_' . esc_attr( $id ) . '">' . $label . '</label>
</span>
</form>';
echo '</br>';
//Display time stamp when object cache was last flushed
echo '<small><strong>Last flushed at: </strong></small> ' . wp_kses_post( get_option('flush-obj-cache-time-stamp') );
}
// Extend batcache checkbox
function pressable_cache_management_callback_field_extend_cache_checkbox($args)
{
$options = get_option('pressable_cache_management_options');
$id = isset($args['id']) ? $args['id'] : '';
$label = isset($args['label']) ? $args['label'] : '';
$checked = isset($options[$id]) ? checked($options[$id], 1, false) : '';
echo '<div class="container">';
echo '<label class="switch">';
echo '<input type="checkbox" id="pressable_cache_management_options_' . esc_attr( $id ) . '" name="pressable_cache_management_options[' . $id . ']" value="1"' . $checked . ' />';
echo '<span class="slider round"></span>
</label>';
// echo '</br>';
echo '<label class="rad-text for="pressable_cache_management_options_' . esc_attr( $id ) . '">' . esc_html( $label ) . '</label>';
}
// Flush site cache on Theme/Plugin update checkbox
function pressable_cache_management_callback_field_plugin_theme_update_checkbox($args)
{
$options = get_option('pressable_cache_management_options');
$id = isset($args['id']) ? $args['id'] : '';
$label = isset($args['label']) ? $args['label'] : '';
$checked = isset($options[$id]) ? checked($options[$id], 1, false) : '';
echo '<div class="container">';
echo '<label class="switch">';
echo '<input type="checkbox" id="pressable_cache_management_options_' . esc_attr( $id ) . '" name="pressable_cache_management_options[' . $id . ']" value="1"' . $checked . ' />';
echo '<span class="slider round"></span>
</label>';
echo '<label class="rad-text for="pressable_cache_management_options_' . esc_attr( $id ) . '">' . esc_html( $label ) . '</label>';
echo '</br>';
echo '</br>';
//Display time stamp when object cache was last flushed when theme plugin
echo '<small><strong>Last flushed at: </strong></small>' . wp_kses_post( get_option('flush-cache-theme-plugin-time-stamp') );
}
// Flush site object cache on page & post update checkbox
function pressable_cache_management_callback_field_page_edit_checkbox($args)
{
$options = get_option('pressable_cache_management_options');
$id = isset($args['id']) ? $args['id'] : '';
$label = isset($args['label']) ? $args['label'] : '';
$checked = isset($options[$id]) ? checked($options[$id], 1, false) : '';
echo '<div class="container">';
echo '<label class="switch">';
echo '<input type="checkbox" id="pressable_cache_management_options_' . esc_attr( $id ) . '" name="pressable_cache_management_options[' . $id . ']" value="1"' . $checked . ' />';
echo '<span class="slider round"></span>
</label>';
// echo '</br>';
echo '<label class="rad-text for="pressable_cache_management_options_' . esc_attr( $id ) . '">' . esc_html( $label ) . '</label>';
echo '</br>';
echo '</br>';
//Display time stamp when object cache was last flushed when page or post was updated
echo '<small><strong>Last flushed at: </strong></small>' . wp_kses_post( get_option('flush-cache-page-edit-time-stamp') );
}
// Flush site object cache when page, post and posttypes are updated checkbox
function pressable_cache_management_callback_field_page_post_delete_checkbox($args)
{
$options = get_option('pressable_cache_management_options');
$id = isset($args['id']) ? $args['id'] : '';
$label = isset($args['label']) ? $args['label'] : '';
$checked = isset($options[$id]) ? checked($options[$id], 1, false) : '';
echo '<div class="container">';
echo '<label class="switch">';
echo '<input type="checkbox" id="pressable_cache_management_options_' . esc_attr( $id ) . '" name="pressable_cache_management_options[' . $id . ']" value="1"' . $checked . ' />';
echo '<span class="slider round"></span>
</label>';
// echo '</br>';
echo '<label class="rad-text for="pressable_cache_management_options_' . esc_attr( $id ) . '">' . esc_html( $label ) . '</label>';
echo '</br>';
echo '</br>';
//Display time stamp when object cache was last flushed when page or post was deleted
echo '<small><strong>Last flushed at: </strong></small>' . wp_kses_post( get_option('flush-cache-on-page-post-delete-time-stamp') );
}
// Flush cache when comment is deleted checkbox
function pressable_cache_management_callback_field_comment_delete_checkbox($args)
{
$options = get_option('pressable_cache_management_options');
$id = isset($args['id']) ? $args['id'] : '';
$label = isset($args['label']) ? $args['label'] : '';
$checked = isset($options[$id]) ? checked($options[$id], 1, false) : '';
echo '<div class="container">';
echo '<label class="switch">';
echo '<input type="checkbox" id="pressable_cache_management_options_' . esc_attr( $id ) . '" name="pressable_cache_management_options[' . $id . ']" value="1"' . $checked . ' />';
echo '<span class="slider round"></span>
</label>';
// echo '</br>';
echo '<label class="rad-text for="pressable_cache_management_options_' . esc_attr( $id ) . '">' . esc_html( $label ) . '</label>';
echo '</br>';
echo '</br>';
//Display time stamp when object cache was last flushed when comment was deleted
echo '<small><strong>Last flushed at: </strong></small>' . wp_kses_post( get_option('flush-cache-on-comment-delete-time-stamp') );
}
//Flush cache for a single page
function pressable_cache_management_callback_field_flush_batcache_particular_page_checbox($args)
{
$options = get_option('pressable_cache_management_options');
$id = isset($args['id']) ? $args['id'] : '';
$label = isset($args['label']) ? $args['label'] : '';
$checked = isset($options[$id]) ? checked($options[$id], 1, false) : '';
echo '<div class="container">';
echo '<label class="switch">';
echo '<input type="checkbox" id="pressable_cache_management_options_' . esc_attr( $id ) . '" name="pressable_cache_management_options[' . $id . ']" value="1"' . $checked . ' />';
echo '<span class="slider round"></span>
</label>';
// echo '</br>';
echo '<label class="rad-text for="pressable_cache_management_options_' . esc_attr( $id ) . '">' . esc_html( $label ) . '</label>';
echo '</br>';
echo '</br>';
//Display time stamp when object cache was last flushed
echo '<small><strong>Last flushed at:</strong></small> ' . wp_kses_post( get_option('flush-object-cache-for-single-page-time-stamp') );
echo '</br>';
echo '<small><strong>Page URL:</strong></small> ' . esc_html( get_option('single-page-url-flushed') );
}
//Flush cache for WooCommerce product single page
function pressable_cache_management_callback_field_flush_batcache_woo_product_page_checbox($args)
{
$options = get_option('pressable_cache_management_options');
$id = isset($args['id']) ? $args['id'] : '';
$label = isset($args['label']) ? $args['label'] : '';
$checked = isset($options[$id]) ? checked($options[$id], 1, false) : '';
echo '<div class="container">';
echo '<label class="switch">';
echo '<input type="checkbox" id="pressable_cache_management_options_' . esc_attr( $id ) . '" name="pressable_cache_management_options[' . $id . ']" value="1"' . $checked . ' />';
echo '<span class="slider round"></span>
</label>';
// echo '</br>';
echo '<label class="rad-text for="pressable_cache_management_options_' . esc_attr( $id ) . '">' . esc_html( $label ) . '</label>';
echo '</br>';
// echo '<small><strong>Last purged Edge at:</strong></small> ' . (get_option('single-page-edge-cache-purge-time-stamp')) . '<small></small>';
// echo '</br>';
}
//Callback: text field to exempt individual page from batcache
function pressable_cache_management_callback_field_exempt_batcache_text($args)
{
$options = get_option('pressable_cache_management_options');
$id = isset($args['id']) ? $args['id'] : '';
$label = isset($args['label']) ? $args['label'] : '';
$value = isset($options[$id]) ? sanitize_text_field($options[$id]) : '';
echo '<input autocomplete="off" id="pressable_cache_management_options_' . esc_attr( $id ) . '" name="pressable_cache_management_options[' . $id . ']" type="text" placeholder=" Exclude single page ex /pagename/" size="70" value="' . esc_attr( $value ) . '"><br/>';
echo '<label class="rad-text for="pressable_cache_management_options_' . esc_attr( $id ) . '">' . esc_html( $label ) . '</label>';
}
/*
/**
********************************
* Edge Cache *
* Management Tab *
********************************
**/
// Radio button options to turn on/off Edge Cache
function pressable_cache_management_options_radio_edge_cache_button()
{
return array(
'enable' => esc_html__('Enable Edge Cache', 'pressable_cache_management') ,
);
}
// AJAX handler function to check Edge Cache status on demand
function pcm_ajax_check_edge_cache_status()
{
if (!current_user_can('manage_options')) {
wp_send_json_error(['message' => 'Unauthorized'], 403);
return;
}
// --- Transient cache: avoid hitting the Pressable API on every page load ---
// Cache TTL: 5 minutes for enabled/disabled, 60 seconds for DDoS/unknown so
// we recover quickly without hammering the API.
$cache_key = 'pcm_ec_status_cache';
$cached = get_transient( $cache_key );
if ( $cached !== false ) {
// Serve from cache — no API call needed
wp_send_json_success([
'enabled' => $cached['is_enabled'],
'status_text' => $cached['status_text'],
'status_flag' => $cached['status_flag'],
'from_cache' => true,
'html_controls_enable_disable' => pressable_cache_management_generate_enable_disable_content( $cached['is_enabled'] ),
]);
return;
}
if ( ! class_exists('Edge_Cache_Plugin') ) {
wp_send_json_error([
'message' => 'Edge Cache dependency is not available.',
'html_controls_enable_disable' => '<p class="notice notice-error" style="padding: 10px;">' . esc_html__('Error: Edge Cache dependency is missing.', 'pressable_cache_management') . '</p>',
]);
return;
}
$edge_cache = Edge_Cache_Plugin::get_instance();
$server_status = $edge_cache->get_ec_status(); // live API call
$is_enabled = false;
$status_text = 'Unknown';
$status_flag = 'Error';
$ttl = 60; // short TTL for unknown/error states
if ( $server_status === Edge_Cache_Plugin::EC_ENABLED ) {
$is_enabled = true;
$status_text = 'Enabled';
$status_flag = 'Success';
$ttl = 300; // 5 minutes — stable state
} elseif ( $server_status === Edge_Cache_Plugin::EC_DISABLED ) {
$is_enabled = false;
$status_text = 'Disabled';
$status_flag = 'Success';
$ttl = 300; // 5 minutes — stable state
} elseif ( $server_status === Edge_Cache_Plugin::EC_DDOS ) {
$status_text = 'Defensive Mode (DDoS)';
$status_flag = 'Warning';
$ttl = 60; // re-check sooner during DDoS mode
}
// Store in transient so subsequent page loads skip the API call
set_transient( $cache_key, [
'is_enabled' => $is_enabled,
'status_text' => $status_text,
'status_flag' => $status_flag,
], $ttl );
// Keep wp_options in sync for server-side badge rendering
update_option('edge-cache-status', $status_flag);
update_option('edge-cache-enabled', $is_enabled ? 'enabled' : 'disabled');
wp_send_json_success([
'enabled' => $is_enabled,
'status_text' => $status_text,
'status_flag' => $status_flag,
'from_cache' => false,
'html_controls_enable_disable' => pressable_cache_management_generate_enable_disable_content( $is_enabled ),
]);
}
add_action('wp_ajax_pcm_check_edge_cache_status', 'pcm_ajax_check_edge_cache_status');
/**
* Clear the edge cache status transient whenever the state changes
* (enable, disable, purge) so the next request gets a fresh live value.
*/
function pcm_clear_ec_status_cache() {
delete_transient( 'pcm_ec_status_cache' );
}
add_action( 'pcm_after_edge_cache_enable', 'pcm_clear_ec_status_cache' );
add_action( 'pcm_after_edge_cache_disable', 'pcm_clear_ec_status_cache' );
add_action( 'pcm_after_edge_cache_purge', 'pcm_clear_ec_status_cache' );
add_action( 'pcm_after_defensive_mode_change','pcm_clear_ec_status_cache' );
/**
* Helper function to generate only the Enable/Disable button form HTML.
*
* @param bool $is_enabled Whether the Edge Cache is currently enabled.
* @return string The HTML containing only the Enable/Disable control.
*/
function pressable_cache_management_generate_enable_disable_content($is_enabled) {
ob_start();
//Button form/label
if ($is_enabled) {
$id = 'disable_edge_cache_nonce';
$value = __('Disable Edge Cache', 'pressable_cache_management');
$submit_class = 'purgecacahe';
echo '</form>';
echo '<form method="post" id="' . esc_attr($id) . '">';
echo '<span id="' . esc_attr($id) . '">';
echo '<input id="edge_cache_settings_tab_options_disable" name="edge_cache_settings_tab_options[edge_cache_on_off_radio_button]" type="submit" size="40" value="' . esc_attr($value) . '" class="' . esc_attr($submit_class) . '"/>';
echo '<input type="hidden" name="' . esc_attr($id) . '" value="' . wp_create_nonce($id) . '" />';
echo '</span>';
echo '</form>';
} else {
$id = 'enable_edge_cache_nonce';
$value = __('Enable Edge Cache', 'pressable_cache_management');
$submit_class = 'purgecacahe';
echo '</form>';
echo '<form method="post" id="' . esc_attr($id) . '">';
echo '<span id="' . esc_attr($id) . '">';
echo '<input id="edge_cache_settings_tab_options_enable" name="edge_cache_settings_tab_options[edge_cache_on_off_radio_button]" type="submit" size="40" value="' . esc_attr($value) . '" class="' . esc_attr($submit_class) . '"/>';
echo '<input type="hidden" name="' . esc_attr($id) . '" value="' . wp_create_nonce($id) . '" />';
echo '</span>';
echo '</form>';
}
return ob_get_clean();
}
// Renders the placeholder div and the synchronization script.
function pressable_cache_management_callback_field_extend_edge_cache_radio_button($args)
{
// Renders the single placeholder div and the synchronization script.
?>
<style>
.edge-cache-loader {
display: flex;
align-items: center;
height: 30px;
font-style: italic;
color: #777;
}
.edge-cache-loader::before {
content: '';
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
width: 14px;
height: 14px;
animation: spin 1s linear infinite;
margin-right: 10px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Style for grayed-out button */
.disabled-button-style {
opacity: 0.6;
cursor: not-allowed;
pointer-events: none; /* Prevents clicks on disabled elements */
}
.disabled-button-style:hover {
opacity: 0.6 !important;
box-shadow: none !important;
}
</style>
<!-- RENDER: Container for ENABLE/DISABLE control -->
<div id="edge-cache-control-wrapper" style="min-height: 30px;">
<div class="edge-cache-loader"><?php esc_html_e('Checking Edge Cache status...', 'pressable_cache_management'); ?></div>
</div>
<script>
jQuery(document).ready(function($) {
var wrapper = $('#edge-cache-control-wrapper');
var purgeButton = $('#purge-edge-cache-button-input');
// This check ensures AJAX only fires if the element exists and hasn't already been checked.
if (wrapper.length && !wrapper.data('status-checked')) {
wrapper.data('status-checked', true);
// --- Set initial state for Purge button (Always disabled/grayed out before AJAX response) ---
purgeButton.prop('disabled', true).addClass('disabled-button-style');
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'pcm_check_edge_cache_status'
},
success: function(response) {
if (response.success && response.data.html_controls_enable_disable) {
// 1. Update Enable/Disable content
wrapper.html(response.data.html_controls_enable_disable);
// 2. Update Purge Button state (Gray out/Enable)
if (response.data.enabled) {
purgeButton.prop('disabled', false).removeClass('disabled-button-style');
} else {
// Keep grayed out
purgeButton.prop('disabled', true).addClass('disabled-button-style');
}
} else {
// Handle failure
var errorMessage = response.data && response.data.message ? response.data.message : 'Failed to retrieve Edge Cache status.';
wrapper.html('<p class="notice notice-error" style="padding: 10px;">' + errorMessage + '</p>');
}
},
error: function(jqXHR, textStatus, errorThrown) {
// Handle AJAX network/server error
var errorMessage = 'AJAX Error: Could not connect to the status server.';
wrapper.html('<p class="notice notice-error" style="padding: 10px;">' + errorMessage + '</p>');
}
});
}
});
</script>
<?php
}
//Purge Edge Cache
function pressable_edge_cache_flush_management_callback_field_button($args)
{
$options = get_option('edge_cache_settings_tab_options');
$id = isset($args['id']) ? $args['id'] : '';
// Remove $label to avoid showing text
// $label = isset($args['label']) ? $args['label'] : '';
// Disabled attribute and class for initial state
$disabled_attr = ' disabled="disabled"';
$disabled_class = ' disabled-button-style';
$submit_class = 'purgecacahe' . $disabled_class;
echo '</form>';
echo '<form method="post" id="purge_edge_cache_nonce_form_static">
<span id="purge_edge_cache_button_span_static">
<input id="purge-edge-cache-button-input"
name="edge_cache_settings_tab_options[' . $id . ']"
type="submit"
size="40"
value="' . esc_attr__( 'Purge Edge Cache', 'pressable_cache_management' ) . '"
class="' . esc_attr($submit_class) . '"' . $disabled_attr . '/>';
echo '<input type="hidden" name="purge_edge_cache_nonce" value="' . wp_create_nonce('purge_edge_cache_nonce') . '" />';
echo '</span>
</form>';
echo '<br/>';
// Display timestamp when object cache was last flushed
echo '<small><strong>' . esc_html__( 'Last purged at:', 'pressable_cache_management' ) . ' </strong></small>' . esc_html( get_option('edge-cache-purge-time-stamp') );
echo '<br/>';
echo '<br/>';
echo '<small><strong>' . esc_html__( 'Single URL last purged at:', 'pressable_cache_management' ) . '</strong></small> ' . esc_html( get_option('single-page-edge-cache-purge-time-stamp') );
echo '<br/>';
echo '<small><strong>' . esc_html__( 'Single URL:', 'pressable_cache_management' ) . '</strong></small> ' . esc_html( get_option('edge-cache-single-page-url-purged') );
echo '<br/>';
echo '<br/>';
echo '<p style="font-size:12px;">'
. __('Purging cache will temporarily slow down your site for all visitors while the cache rebuilds.', 'pressable_cache_management'). '</p>';
}
/**
********************************
* Remove Pressable *
* Branding Tab *
********************************
*
*/
// Radio button options
function pressable_cache_management_options_remove_branding_radio_button()
{
return array(
'enable' => esc_html__('Show Pressable Branding', 'pressable_cache_management') ,
'disable' => esc_html__('Hide Pressable Branding', 'pressable_cache_management')
);
}
function pressable_cache_management_callback_field_extend_remove_branding_radio_button($args)
{
$options = get_option('remove_pressable_branding_tab_options');
$id = isset($args['id']) ? $args['id'] : '';
$label = isset($args['label']) ? $args['label'] : '';
$selected_option = isset($options[$id]) ? sanitize_text_field($options[$id]) : '';
$radio_options = pressable_cache_management_options_remove_branding_radio_button();
foreach ($radio_options as $value => $label)
{
$checked = checked($selected_option === $value, true, false);
echo '<label class="rad-label">';
echo '<input type="radio" class="rad-input" name="remove_pressable_branding_tab_options[' . $id . ']" type="radio" value="' . esc_attr( $value ) . '"' . $checked . ' name="rad">';
echo '<div class="rad-design"></div>';
echo '<span class="rad-text">' . esc_html( $label ) . '</span></label>';
echo '</label>';
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,194 @@
<?php
// Pressable Cache Management - Register Settings
// Disable direct file access
if (!defined('ABSPATH')) {
exit;
}
// Register plugin settings
function pressable_cache_management_register_settings()
{
// Save options for object cache tab
register_setting(
'pressable_cache_management_options',
'pressable_cache_management_options',
'pressable_cache_management_callback_validate_options'
);
// Save options for edge cache tab
register_setting(
'edge_cache_tab_options',
'edge_cache_settings_tab_options',
'edge_cache_settings_tab_callback_validate_options'
);
// Save options for branding tab
register_setting(
'remove_pressable_branding_tab_options',
'remove_pressable_branding_tab_options',
'remove_pressable_branding_tab_callback_validate_options'
);
$remove_pressable_branding_tab_options = get_option('remove_pressable_branding_tab_options');
if ($remove_pressable_branding_tab_options && 'disable' == $remove_pressable_branding_tab_options['branding_on_off_radio_button']) {
add_settings_section(
'pressable_cache_management_section_cache',
esc_html__('Cache Control Management', 'pressable_cache_management'),
'pressable_cache_management_callback_section_cache',
'pressable_cache_management'
);
} else {
add_settings_section(
'pressable_cache_management_section_cache',
esc_html__('Cache Management By', 'pressable_cache_management'),
'pressable_cache_management_callback_section_cache',
'pressable_cache_management'
);
}
// Edge Cache settings tab page
add_settings_section(
'pressable_cache_management_section_edge_cache',
esc_html__('Manage Edge Cache Settings', 'pressable_cache_management'),
'pressable_cache_management_callback_section_edge_cache',
'edge_cache_settings_tab'
);
// Remove Pressable branding tab page
add_settings_section(
'pressable_cache_management_section_branding',
esc_html__('Show or Hide Plugin Branding', 'pressable_cache_management'),
'pressable_cache_management_callback_section_branding',
'remove_pressable_branding_tab'
);
// Verify if the options exist
if (false == get_option('pressable_cache_management_options')) {
add_option('pressable_cache_management_options');
}
/*
* Object Cache Management Tab
*/
add_settings_field(
'flush_cache_button',
esc_html__('Flush Object Cache', 'pressable_cache_management'),
'pressable_cache_management_callback_field_button',
'pressable_cache_management',
'pressable_cache_management_section_cache',
['id' => 'flush_cache_button', 'label' => esc_html__('Flush object cache (Database)', 'pressable_cache_management')]
);
add_settings_field(
'extend_batcache_checkbox',
esc_html__('Extend Batcache', 'pressable_cache_management'),
'pressable_cache_management_callback_field_extend_cache_checkbox',
'pressable_cache_management',
'pressable_cache_management_section_cache',
['id' => 'extend_batcache_checkbox', 'label' => esc_html__('Extend Batcache storage time by 24 hours', 'pressable_cache_management')]
);
add_settings_field(
'flush_cache_theme_plugin_checkbox',
esc_html__('Flush Cache on Update', 'pressable_cache_management'),
'pressable_cache_management_callback_field_plugin_theme_update_checkbox',
'pressable_cache_management',
'pressable_cache_management_section_cache',
['id' => 'flush_cache_theme_plugin_checkbox', 'label' => esc_html__('Flush cache automatically on plugin & theme update', 'pressable_cache_management')]
);
add_settings_field(
'flush_cache_page_edit_checkbox',
esc_html__('Flush Cache on Edit', 'pressable_cache_management'),
'pressable_cache_management_callback_field_page_edit_checkbox',
'pressable_cache_management',
'pressable_cache_management_section_cache',
['id' => 'flush_cache_page_edit_checkbox', 'label' => esc_html__('Flush cache automatically when page/post/post_types are updated', 'pressable_cache_management')]
);
add_settings_field(
'flush_cache_on_page_post_delete_checkbox',
esc_html__('Flush Cache on Page Delete', 'pressable_cache_management'),
'pressable_cache_management_callback_field_page_post_delete_checkbox',
'pressable_cache_management',
'pressable_cache_management_section_cache',
['id' => 'flush_cache_on_page_post_delete_checkbox', 'label' => esc_html__('Flush cache automatically when published pages/posts are deleted', 'pressable_cache_management')]
);
add_settings_field(
'flush_cache_on_comment_delete_checkbox',
esc_html__('Flush Cache on Comment Delete', 'pressable_cache_management'),
'pressable_cache_management_callback_field_comment_delete_checkbox',
'pressable_cache_management',
'pressable_cache_management_section_cache',
['id' => 'flush_cache_on_comment_delete_checkbox', 'label' => esc_html__('Flush cache automatically when comments are deleted', 'pressable_cache_management')]
);
add_settings_field(
'flush_object_cache_for_single_page',
esc_html__('Flush Batcache for Individual Pages', 'pressable_cache_management'),
'pressable_cache_management_callback_field_flush_batcache_particular_page_checbox',
'pressable_cache_management',
'pressable_cache_management_section_cache',
['id' => 'flush_object_cache_for_single_page', 'label' => esc_html__('Flush Batcache for individual pages', 'pressable_cache_management')]
);
add_settings_field(
'flush_batcache_for_woo_product_individual_page_checkbox',
esc_html__('Flush Batcache for Woo Product Pages', 'pressable_cache_management'),
'pressable_cache_management_callback_field_flush_batcache_woo_product_page_checbox',
'pressable_cache_management',
'pressable_cache_management_section_cache',
['id' => 'flush_batcache_for_woo_product_individual_page_checkbox', 'label' => esc_html__('Flush Batcache for WooCommerce product pages', 'pressable_cache_management')]
);
add_settings_field(
'exempt_from_batcache',
esc_html__('Exclude Page from Batcache & Edge Cache', 'pressable_cache_management'),
'pressable_cache_management_callback_field_exempt_batcache_text',
'pressable_cache_management',
'pressable_cache_management_section_cache',
['id' => 'exempt_from_batcache', 'label' => esc_html__('To exclude multiple pages separate with comma ex /your-site.com/, /about-us/, /info/', 'pressable_cache_management')]
);
/*
* Edge Cache Management Tab
*/
add_settings_field(
'edge_cache_on_off_radio_button',
esc_html__('Turn On/Off Edge Cache', 'pressable_cache_management'),
'pressable_cache_management_callback_field_extend_edge_cache_radio_button',
'edge_cache_settings_tab',
'pressable_cache_management_section_edge_cache',
['id' => 'edge_cache_on_off_radio_button', 'label' => esc_html__('Turn on/off Edge Cache', 'pressable_cache_management')]
);
/*
* Display Purge Edge Cache button
*/
add_settings_field(
'purge_edge_cache_button',
esc_html__('Purge Edge Cache', 'pressable_cache_management'),
'pressable_edge_cache_flush_management_callback_field_button',
'edge_cache_settings_tab',
'pressable_cache_management_section_edge_cache',
['id' => 'purge_edge_cache_button', 'label' => esc_html__('Purge Edge Cache', 'pressable_cache_management')]
);
/*
* Remove Pressable Branding Tab
*/
add_settings_field(
'branding_on_off_radio_button',
esc_html__('Hide or Show Plugin Branding', 'pressable_cache_management'),
'pressable_cache_management_callback_field_extend_remove_branding_radio_button',
'remove_pressable_branding_tab',
'pressable_cache_management_section_branding',
['id' => 'branding_on_off_radio_button', 'label' => esc_html__('Hide or show plugin branding', 'pressable_cache_management')]
);
}
add_action('admin_init', 'pressable_cache_management_register_settings');
@@ -0,0 +1,107 @@
<?php // Pressable Cache Management - Validate Settings
// Disable direct file access
if (!defined("ABSPATH")) {
exit();
}
// Callback: validate main options
function pressable_cache_management_callback_validate_options($input) {
if (empty($input)) {
$input = [];
}
// Extend batcache checkbox
if (!isset($input["extend_batcache_checkbox"])) {
$input["extend_batcache_checkbox"] = "";
}
$input["extend_batcache_checkbox"] = filter_var($input["extend_batcache_checkbox"] == 1 ? 1 : 0, FILTER_SANITIZE_NUMBER_INT);
// Flush object cache on theme and plugin update checkbox
if (!isset($input["flush_cache_theme_plugin_checkbox"])) {
$input["flush_cache_theme_plugin_checkbox"] = "";
}
$input["flush_cache_theme_plugin_checkbox"] = filter_var($input["flush_cache_theme_plugin_checkbox"] == 1 ? 1 : 0, FILTER_SANITIZE_NUMBER_INT);
// Flush object cache on page and post update
if (!isset($input["flush_cache_page_edit_checkbox"])) {
$input["flush_cache_page_edit_checkbox"] = "";
}
$input["flush_cache_page_edit_checkbox"] = filter_var($input["flush_cache_page_edit_checkbox"] == 1 ? 1 : 0, FILTER_SANITIZE_NUMBER_INT);
// Flush object cache on page and post delete
if (!isset($input["flush_cache_on_page_post_delete_checkbox"])) {
$input["flush_cache_on_page_post_delete_checkbox"] = "";
}
$input["flush_cache_on_page_post_delete_checkbox"] = filter_var($input["flush_cache_on_page_post_delete_checkbox"] == 1 ? 1 : 0, FILTER_SANITIZE_NUMBER_INT);
// Flush object cache on comment delete
if (!isset($input["flush_cache_on_comment_delete_checkbox"])) {
$input["flush_cache_on_comment_delete_checkbox"] = "";
}
$input["flush_cache_on_comment_delete_checkbox"] = filter_var($input["flush_cache_on_comment_delete_checkbox"] == 1 ? 1 : 0, FILTER_SANITIZE_NUMBER_INT);
// Flush Batcache for individual page
if (!isset($input["flush_object_cache_for_single_page"])) {
$input["flush_object_cache_for_single_page"] = "";
}
$input["flush_object_cache_for_single_page"] = filter_var($input["flush_object_cache_for_single_page"] == 1 ? 1 : 0, FILTER_SANITIZE_NUMBER_INT);
// Flush Batcache for WooCommerce individual page
$input["flush_batcache_for_woo_product_individual_page_checkbox"] = isset($input["flush_batcache_for_woo_product_individual_page_checkbox"]) ? filter_var($input["flush_batcache_for_woo_product_individual_page_checkbox"] == 1 ? 1 : 0, FILTER_SANITIZE_NUMBER_INT) : 0;
// Exclude pages from Batcache — sanitize comma-separated URL paths
if ( isset( $input['exempt_from_batcache'] ) ) {
$raw_paths = explode( ',', $input['exempt_from_batcache'] );
$clean_paths = array_filter( array_map( function( $path ) {
$path = sanitize_text_field( wp_unslash( trim( $path ) ) );
// Strip full URLs — extract just the path portion
$parsed = wp_parse_url( $path );
if ( isset( $parsed['path'] ) && '' !== $parsed['path'] ) {
$path = $parsed['path'];
}
// Allow only safe path characters: alphanumeric, hyphen, underscore, dot, slash
$path = preg_replace( '/[^a-zA-Z0-9\-_\/\.]/', '', $path );
// Collapse multiple slashes
$path = preg_replace( '/\/+/', '/', $path );
// Ensure leading slash
if ( substr( $path, 0, 1 ) !== '/' ) $path = '/' . $path;
// Ensure trailing slash
if ( substr( $path, -1 ) !== '/' ) $path = $path . '/';
// Must be more than just a single slash
return strlen( $path ) > 1 ? $path : '';
}, $raw_paths ) );
$input['exempt_from_batcache'] = implode( ', ', $clean_paths );
}
return $input;
}
// Callback: validate Edge Cache options
function egde_cache_settings_tab_callback_validate_options($input) {
if ( ! is_array( $input ) ) {
return array();
}
// Sanitize each value — edge cache options are radio/checkbox strings
$allowed = array( 'enabled', 'disabled', 'enable', 'disable', '1', '0', '' );
foreach ( $input as $key => $value ) {
$key = sanitize_key( $key );
$input[ $key ] = in_array( $value, $allowed, true ) ? $value : sanitize_text_field( $value );
}
return $input;
}
// Callback: validate branding options
function remove_pressable_branding_tab_callback_validate_options($input) {
// Turn On/Off Pressable branding option
$radio_options = pressable_cache_management_options_radio_button();
if (!isset($input["branding_on_off_radio_button"])) {
$input["branding_on_off_radio_button"] = null;
}
if (!array_key_exists($input["branding_on_off_radio_button"], $radio_options)) {
$input["branding_on_off_radio_button"] = null;
}
return $input;
}