• Resolved neikoloves

    (@neikoloves)


    I’m truly impressed with your plugin — it’s exceptionally well-designed and engineered. After evaluating numerous alternatives, many of which are bloated and fall short in functionality, your solution stands out as a beacon of quality. Unlike other products that over-promise and under-deliver, your plugin provides genuinely features without any unnecessary bloat, which I greatly appreciate.

    I would love to see an addition of a visual dashboard admin interface and an admin drop-down menu. While I’m still working out the UI/UX details and the code base for this idea, I’m eager to leverage your existing framework to maintain consistency and clarity in the user experience. Do you have any more API information or could you help with some direction on this?

    A visual dashboard could provide quick access to essential functions, particularly for efficiently clearing caches during testing. Many similar tools I’ve evaluated offer such features but often fall short in terms of control and usability. Implementing this would enhance both accessibility and effectiveness, making it easier for users to manage cache operations seamlessly from any admin location.

    Thank you and best regards …

Viewing 3 replies - 1 through 3 (of 3 total)
  • Plugin Author Nawawi Jamili

    (@nawawijamili)

    Hi there,

    Thanks for your feedback. I really appreciate it.

    Due to my schedule availability, I can’t guarantee that I will implement it. Perhaps you could create a new plugin to handle such a feature.

    Here the code to create action hook to use with other plugin:

    https://gist.github.com/nawawi/25a6f666adbc338b776d1b93a59415b5

    Thanks.

    Thread Starter neikoloves

    (@neikoloves)

    Ok here is my starting point, needs some more refinements, but it does do some things, I was looking for, maybe this can be useful for the cause?

    <?php

    /**
    * Docket Cache Controls Dashboard Widget
    *
    * Version: 1.0.0
    * This code adds a custom dashboard widget to the WordPress admin area that allows administrators
    * to execute Docket Cache controls and provides real-time status updates.
    *
    * BBOL "Be Blessed, Open License". https://www.gotquestions.org/mean-to-be-blessed.html
    *
    */

    // Register the dashboard widget
    function register_docket_cache_dashboard_widget() {
    wp_add_dashboard_widget(
    'docket_cache_dashboard_widget', // Widget ID
    'Docket Cache Controls', // Widget Title
    'render_docket_cache_dashboard_widget_content' // Callback function to render content
    );
    }
    add_action('wp_dashboard_setup', 'register_docket_cache_dashboard_widget');

    // Render the widget content
    function render_docket_cache_dashboard_widget_content() {
    $nonce = wp_create_nonce('docket_cache_action_nonce');
    ?>
    <div id="docket-cache-widget">
    <div class="docket-cache-buttons-container">
    <?php
    $buttons = [
    'flush_cache' => 'Flush Cache',
    'flush_precache' => 'Flush PreCache',
    'flush_menucache' => 'Flush Menu Cache',
    'flush_mocache' => 'Flush MoCache',
    'flush_transient' => 'Flush Transients',
    'update_dropin' => 'Update Drop-In',
    'enable_dropin' => 'Enable Drop-In',
    'disable_dropin' => 'Disable Drop-In',
    'runtime_install' => 'Install Runtime',
    'runtime_uninstall' => 'Remove Runtime',
    'optimizedb' => 'Optimize DB',
    ];

    foreach ($buttons as $action => $label) {
    echo '<div class="docket-cache-button-container">';
    echo '<button class="docket-cache-button" data-action="' . esc_attr($action) . '">' . esc_html($label) . '</button>';
    echo '<div class="docket-cache-status" id="status-' . esc_attr($action) . '">Status: Pending</div>';
    echo '</div>';
    }
    ?>
    </div>
    <div id="docket-cache-response"></div>
    </div>
    <style>
    #docket-cache-widget {
    padding: 10px;
    }
    .docket-cache-buttons-container {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    }
    .docket-cache-button-container {
    flex: 1 1 calc(33.33% - 10px);
    text-align: center;
    min-width: 120px;
    }
    .docket-cache-button {
    padding: 6px 10px;
    background-color: #a30000; /* Red color */
    color: #fff;
    border: none;
    cursor: pointer;
    border-radius: 3px;
    font-size: 12px;
    width: 100%;
    box-sizing: border-box;
    transition: background-color 0.3s ease;
    }
    .docket-cache-button:hover {
    background-color: #c63c3c; /* Lighten red on hover */
    }
    .docket-cache-button.success {
    background-color: #2a7d2f; /* Green color for success */
    }
    .docket-cache-status {
    margin-top: 5px;
    font-size: 12px;
    color: #666;
    }
    .docket-cache-status.success {
    color: #2a7d2f; /* Green color for success */
    }
    .docket-cache-status.error {
    color: #a30000; /* Red color for error */
    }
    #docket-cache-response {
    margin-top: 10px;
    font-size: 14px;
    color: #444;
    }
    </style>
    <script>
    (function($) {
    $('.docket-cache-button').on('click', function() {
    var action = $(this).data('action');
    var nonce = '<?php echo $nonce; ?>';
    var $button = $(this);
    var $statusElement = $('#status-' + action);
    var originalText = $button.text();

    $('.docket-cache-button').prop('disabled', true);
    $button.removeClass('success').text('Executing...');
    $statusElement.removeClass('success error').text('Status: Executing...');

    $.post(ajaxurl, {
    action: 'execute_docket_cache_action',
    nonce: nonce,
    custom_action: action
    }, function(response) {
    if (response.success) {
    var message = response.data.message;
    var timestamp = response.data.timestamp;
    $statusElement.addClass('success').html('Status: ' + message + '<br>' + timestamp);
    $button.addClass('success').text(originalText);
    } else {
    $statusElement.addClass('error').html('Status: Error - ' + response.data.message + '<br>' + response.data.timestamp);
    $button.removeClass('success').text('Failed');
    }

    // Hide the status message after 5 seconds
    setTimeout(function() {
    $statusElement.text('Status: Pending');
    $button.removeClass('success').text(originalText);
    }, 5000);

    }).fail(function(xhr, textStatus, errorThrown) {
    console.error('AJAX Error:', textStatus, errorThrown);
    $statusElement.addClass('error').html('Status: Error - ' + textStatus + ' - ' + errorThrown + '<br>' + new Date().toLocaleString());
    $button.removeClass('success').text('Failed');

    // Hide the status message after 5 seconds
    setTimeout(function() {
    $statusElement.text('Status: Pending');
    $button.removeClass('success').text(originalText);
    }, 5000);

    }).always(function() {
    $('.docket-cache-button').prop('disabled', false);
    });
    });
    })(jQuery);
    </script>
    <?php
    }

    // Handle AJAX request for executing Docket Cache actions
    function handle_docket_cache_action() {
    if ( !isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'docket_cache_action_nonce') ) {
    wp_send_json_error(['message' => 'Nonce verification failed.']);
    }

    if ( !current_user_can('manage_options') ) {
    wp_send_json_error(['message' => 'Insufficient permissions.']);
    }

    $action = isset($_POST['custom_action']) ? sanitize_text_field($_POST['custom_action']) : '';

    $action_hooks = [
    'flush_cache' => 'docket_cache_control_flush_cache',
    'flush_precache' => 'docket_cache_control_flush_precache',
    'flush_menucache' => 'docket_cache_control_flush_menucache',
    'flush_mocache' => 'docket_cache_control_flush_mocache',
    'flush_transient' => 'docket_cache_control_flush_transient',
    'update_dropin' => 'docket_cache_control_update_dropin',
    'enable_dropin' => 'docket_cache_control_enable_dropin',
    'disable_dropin' => 'docket_cache_control_disable_dropin',
    'runtime_install' => 'docket_cache_control_runtime_install',
    'runtime_uninstall' => 'docket_cache_control_runtime_uninstall',
    'optimizedb' => 'docket_cache_control_optimizedb',
    ];

    if (!array_key_exists($action, $action_hooks)) {
    wp_send_json_error(['message' => 'Unknown action.']);
    }

    ob_start();
    do_action($action_hooks[$action]);
    $output = ob_get_clean();

    $success_messages = [
    'flush_cache' => 'Cache flushed',
    'flush_precache' => 'PreCache flushed',
    'flush_menucache' => 'Menu cache flushed',
    'flush_mocache' => 'Mo cache flushed',
    'flush_transient' => 'Transients flushed',
    'update_dropin' => 'Drop-In updated',
    'enable_dropin' => 'Drop-In enabled',
    'disable_dropin' => 'Drop-In disabled',
    'runtime_install' => 'Runtime installed',
    'runtime_uninstall' => 'Runtime removed',
    'optimizedb' => 'Database optimized',
    ];

    $message = isset($success_messages[$action]) ? $success_messages[$action] : 'Action executed successfully.';
    $timestamp = current_time('mysql');
    $formatted_timestamp = date('m/d/y g:i:sa', strtotime($timestamp)); // Adjusted format

    wp_send_json_success([
    'message' => $message . '. ' . $output,
    'timestamp' => $formatted_timestamp
    ]);
    }
    add_action('wp_ajax_execute_docket_cache_action', 'handle_docket_cache_action');

    // Actions to handle Docket Cache controls
    add_action('docketcache/init', function($docket_cache_instance) {
    $docket_cache = $docket_cache_instance;

    // Flush cache
    add_action('docket_cache_control_flush_cache', function() use($docket_cache) {
    try {
    $result = $docket_cache->flush_cache(true);
    $docket_cache->co()->lookup_set('occacheflushed', $result);
    do_action('docketcache/action/flush/objectcache', 'Cache flushed');
    } catch (Exception $e) {
    error_log('Error flushing cache: ' . $e->getMessage());
    do_action('docketcache/action/flush/objectcache', 'Error: ' . $e->getMessage());
    }
    });

    // Enable Drop-In
    add_action('docket_cache_control_enable_dropin', function() use($docket_cache) {
    try {
    $result = $docket_cache->cx()->install(true);
    do_action('docketcache/action/enable/objectcache', 'Drop-In enabled');
    } catch (Exception $e) {
    error_log('Error enabling drop-in: ' . $e->getMessage());
    do_action('docketcache/action/enable/objectcache', 'Error: ' . $e->getMessage());
    }
    });

    // Disable Drop-In
    add_action('docket_cache_control_disable_dropin', function() use($docket_cache) {
    try {
    $result = $docket_cache->cx()->uninstall();
    do_action('docketcache/action/disable/objectcache', 'Drop-In disabled');
    } catch (Exception $e) {
    error_log('Error disabling drop-in: ' . $e->getMessage());
    do_action('docketcache/action/disable/objectcache', 'Error: ' . $e->getMessage());
    }
    });

    // Update Drop-In
    add_action('docket_cache_control_update_dropin', function() use($docket_cache) {
    try {
    $result = $docket_cache->cx()->install(true);
    do_action('docketcache/action/update/objectcache', 'Drop-In updated');
    } catch (Exception $e) {
    error_log('Error updating drop-in: ' . $e->getMessage());
    do_action('docketcache/action/update/objectcache', 'Error: ' . $e->getMessage());
    }
    });

    // Flush Menu Cache
    add_action('docket_cache_control_flush_menucache', function() use($docket_cache) {
    try {
    $result = 0;
    $ok = false;
    if (function_exists('wp_cache_flush_group') && method_exists('WP_Object_Cache', 'dc_remove_group')) {
    $result = wp_cache_flush_group('docketcache-menu');
    $docket_cache->co()->lookup_set('menucacheflushed', $result);
    $ok = true;
    }
    do_action('docketcache/action/flush/file/menucache', $ok ? 'Menu cache flushed' : 'Error');
    } catch (Exception $e) {
    error_log('Error flushing menu cache: ' . $e->getMessage());
    do_action('docketcache/action/flush/file/menucache', 'Error: ' . $e->getMessage());
    }
    });

    // Flush Mo Cache
    add_action('docket_cache_control_flush_mocache', function() use($docket_cache) {
    try {
    $result = 0;
    $ok = false;
    if (function_exists('wp_cache_flush_group') && method_exists('WP_Object_Cache', 'dc_remove_group')) {
    $result = wp_cache_flush_group('docketcache-mo');
    $docket_cache->pt->co()->lookup_set('mocacheflushed', $result);
    $ok = true;
    }
    do_action('docketcache/action/flush/file/mocache', $ok ? 'Mo cache flushed' : 'Error');
    } catch (Exception $e) {
    error_log('Error flushing Mo cache: ' . $e->getMessage());
    do_action('docketcache/action/flush/file/mocache', 'Error: ' . $e->getMessage());
    }
    });

    // Flush PreCache
    add_action('docket_cache_control_flush_precache', function() use($docket_cache) {
    try {
    $result = 0;
    $ok = false;
    if (function_exists('wp_cache_flush_group') && method_exists('WP_Object_Cache', 'dc_remove_group')) {
    $result = wp_cache_flush_group('docketcache-precache');
    $docket_cache->pt->co()->lookup_set('ocprecacheflushed', $result);
    $ok = true;
    }
    do_action('docketcache/action/flush/file/ocprecache', $ok ? 'PreCache flushed' : 'Error');
    } catch (Exception $e) {
    error_log('Error flushing PreCache: ' . $e->getMessage());
    do_action('docketcache/action/flush/file/ocprecache', 'Error: ' . $e->getMessage());
    }
    });

    // Flush Transients
    add_action('docket_cache_control_flush_transient', function() use($docket_cache) {
    try {
    global $wpdb;
    $result = $wpdb->query("DELETE FROM $wpdb->options WHERE option_name LIKE '_transient_%'");
    $docket_cache->pt->co()->lookup_set('transientflushed', $result);
    do_action('docketcache/action/flush/file/transient', 'Transients flushed');
    } catch (Exception $e) {
    error_log('Error flushing transients: ' . $e->getMessage());
    do_action('docketcache/action/flush/file/transient', 'Error: ' . $e->getMessage());
    }
    });

    // Optimize DB
    add_action('docket_cache_control_optimizedb', function() use($docket_cache) {
    try {
    $result = (new Nawawi\DocketCache\Event($docket_cache))->optimizedb();
    do_action('docketcache/action/event/optimizedb', 'Database optimized');
    } catch (Exception $e) {
    error_log('Error optimizing database: ' . $e->getMessage());
    do_action('docketcache/action/event/optimizedb', 'Error: ' . $e->getMessage());
    }
    });

    // Install Runtime Code
    add_action('docket_cache_control_runtime_install', function() use($docket_cache) {
    try {
    $result = Nawawi\DocketCache\WpConfig::runtime_install();
    do_action('docketcache/action/updatewpconfig', 'Runtime installed');
    } catch (Exception $e) {
    error_log('Error installing runtime code: ' . $e->getMessage());
    do_action('docketcache/action/updatewpconfig', 'Error: ' . $e->getMessage());
    }
    });

    // Uninstall Runtime Code
    add_action('docket_cache_control_runtime_uninstall', function() use($docket_cache) {
    try {
    $result = Nawawi\DocketCache\WpConfig::runtime_remove();
    do_action('docketcache/action/updatewpconfig', 'Runtime removed');
    } catch (Exception $e) {
    error_log('Error uninstalling runtime code: ' . $e->getMessage());
    do_action('docketcache/action/updatewpconfig', 'Error: ' . $e->getMessage());
    }
    });
    });
    Plugin Author Nawawi Jamili

    (@nawawijamili)

    It’s pretty impressive and neat code. Yes, it needs some adjustment to handle the status.

    You may refer to this file https://github.com/nawawi/docket-cache/blob/master/includes/src/ReqAction.php; all code for actions and notice messages reside there.

    You can use Canopt() class (https://github.com/nawawi/docket-cache/blob/master/includes/src/Canopt.php) to save and get data. Access it from docketcache/init action

    Save data: $docket_cache->co()->save_part('data', 'filename')
    Get data: $docket_cache->co()->get_part('filename')

    The data will be stored in wp-content/docket-cache-data/filename.php

    Thanks.

Viewing 3 replies - 1 through 3 (of 3 total)
  • You must be logged in to reply to this topic.