PATH:
var
/
www
/
vhosts
/
sandbox.dos-group.com
/
httpdocs
/
mendrisio
/
wp-content
/
plugins
/
transients-manager
/
src
<?php namespace AM\TransientsManager; /** * Transients Manager class */ class TransientsManager { /** @var ?self */ private static $instance = null; /** * ID of the plugin page * * @since 2.0 * @var string */ public $page_id = 'transients-manager'; /** * ID of the Admin Screen * * @since 2.0.5 * @var string */ public $screen_id = ''; /** * Capability the current-user needs to manage transients * * @since 2.0 * @var string */ public $capability = 'manage_options'; /** * Timestamp for right now * * @since 2.0 * @var int */ public $time_now = 0; /** * The next timestamp to delete expired transients (via WP Cron) * * @since 2.0 * @var int */ public $next_cron_delete = 0; /** * Transient ID * * @since 2.0.4 * @var int */ public $transient_id = 0; /** * Transient object * * @since 2.0.4 * @var object */ public $transient = false; /** * Action name * * @since 2.0.4 * @var string */ public $action = ''; /** * * @return self */ public static function getInstance() { if (is_null(self::$instance)) { self::$instance = new self(); } return self::$instance; } /** * Get things started * * @since 1.0 */ public function __construct() { // nothing to do } /** * Get the plugin install time * * @return int */ public function getInstallTime() { $installTime = get_option('am_tm_install_time', false); if (!$installTime) { $installTime = time(); update_option('am_tm_install_time', $installTime); } return $installTime; } /** * Add all of the hooks * * @since 2.0 */ public function init() { add_action( 'after_setup_theme', array( $this, 'text_domain' ) ); add_action( 'admin_init', array( $this, 'set_vars' ) ); add_action( 'admin_init', array( $this, 'process_actions' ) ); add_action( 'admin_menu', array( $this, 'tools_link' ) ); add_action( 'admin_notices', array( $this, 'notices' ) ); add_action( 'admin_bar_menu', array( $this, 'suspend_transients_button' ), 99 ); add_filter( 'pre_update_option', array( $this, 'maybe_block_update_transient' ), -1, 2 ); add_filter( 'pre_get_option', array( $this, 'maybe_block_update_transient' ), -1, 2 ); add_action( 'added_option', array( $this, 'maybe_block_set_transient' ), -1, 1 ); // Styles add_action( "admin_print_styles-tools_page_{$this->page_id}", array( $this, 'print_styles' ) ); /** * Allow third-party plugins a chance to modify the hooks above * * @since 2.0 * @param object $this */ do_action( 'transients_manager_hooks', $this ); } /** * Set many of the class variables * * @since 2.0 */ public function set_vars() { // Times $this->time_now = time(); $this->next_cron_delete = wp_next_scheduled( 'delete_expired_transients' ); // Sanitize the transient ID $this->transient_id = ! empty( $_GET['trans_id'] ) ? absint( $_GET['trans_id'] ) : 0; // Get the transient $this->transient = ! empty( $this->transient_id ) ? $this->get_transient_by_id( $this->transient_id ) : false; // Sanitize the action $this->action = ! empty( $_REQUEST['action'] ) ? sanitize_key( $_REQUEST['action'] ) : ''; } /** * Load text domain * * @since 1.0 */ public function text_domain() { load_plugin_textdomain( 'transients-manager' ); } /** * Register menu link under Tools * * @since 1.0 */ public function tools_link() { // Set the screen ID $this->screen_id = add_management_page( esc_html__( 'Transients Manager', 'transients-manager' ), esc_html__( 'Transients', 'transients-manager' ), $this->capability, $this->page_id, array( $this, 'admin' ) ); } /** * Editing or showing? * * @since 2.0 * @return string */ protected function page_type() { // Edit or Show? return ! empty( $this->action ) && ( 'edit_transient' === $this->action ) && ! empty( $this->transient ) ? 'edit' : 'show'; } /** * Render the admin UI * * @since 1.0 */ public function admin() { // Editing a single Transient ( 'edit' === $this->page_type() ) ? $this->page_edit_transient( $this->transient ) : $this->page_show_transients(); } /** * Admin notices * * @since 2.0 */ public function notices() { // Get the current screen $screen = get_current_screen(); // Bail if not the correct screen if ( $screen->id !== $this->screen_id ) { return; } // Persistent Transients if ( wp_using_ext_object_cache() ) : ?> <div class="notice notice-info"> <p><?php esc_html_e( 'You are using a persistent object cache. This screen may show incomplete information.', 'transients-manager' ); ?></p> </div> <?php endif; // Updated Transient if ( ! empty( $_GET['updated'] ) ) : ?> <div class="notice notice-success is-dismissible"> <p><strong><?php esc_html_e( 'Transient updated.', 'transients-manager' ); ?></strong></p> </div> <?php endif; // Deleted Transients if ( ! empty( $_GET['deleted'] ) ) : ?> <div class="notice notice-success is-dismissible"> <p><strong><?php esc_html_e( 'Transient deleted.', 'transients-manager' ); ?></strong></p> </div> <?php endif; } /** * Output the page HTML for the Transients mock-list-table * * @since 2.0 */ protected function page_show_transients() { // Vars $search = ! empty( $_GET['s'] ) ? sanitize_text_field( $_GET['s'] ) : ''; $per_page = ! empty( $_GET['per_page'] ) ? absint( $_GET['per_page'] ) : 30; $page = isset( $_GET['paged'] ) ? absint( $_GET['paged'] ) : 1; $offset = $per_page * ( $page - 1 ); $count = $this->get_total_transients( $search ); $pages = ceil( $count / $per_page ); $one_page = ( 1 === $pages ) ? 'one-page' : ''; // Pagination $pagination = paginate_links( array( 'base' => 'tools.php?%_%', 'format' => '&paged=%#%', 'prev_text' => '«', 'next_text' => '»', 'total' => $pages, 'current' => $page ) ); // Transients $transients = $this->get_transients( array( 'search' => $search, 'offset' => $offset, 'number' => $per_page ) ); ?> <div class="wrap"> <h1 class="wp-heading-inline"><?php esc_html_e( 'Transients', 'transients-manager' ); ?></h1> <hr class="wp-header-end"> <form method="get"> <p class="search-box"> <label class="screen-reader-text" for="transient-search-input"><?php esc_html_e( 'Search', 'transients-manager' ); ?></label> <input type="search" id="transient-search-input" name="s" value="<?php echo esc_attr( $search ); ?>" /> <input type="submit" id="search-submit" class="button" value="<?php esc_attr_e( 'Search Transients', 'transients-manager' ); ?>" /> <input type="hidden" name="page" value="<?php echo esc_html( $this->page_id ); ?>" /> </p> </form> <form method="post" id="transients-delete"> <input type="hidden" name="transient" value="all" /> <?php wp_nonce_field( 'transients_manager' ); ?> <div class="tablenav top"> <div class="alignleft actions bulkactions"> <label for="bulk-action-selector-top" class="screen-reader-text"><?php esc_html_e( 'Select Bulk action', 'transients-manager' ); ?></label> <select name="action" id="bulk-action-selector-top"> <option value="-1"><?php esc_html_e( 'Bulk actions', 'transients-manager' ); ?></option> <optgroup label="<?php esc_attr_e( 'Selection', 'transients-manager' ); ?>"> <option value="delete_selected_transients"><?php esc_html_e( 'Delete Selected', 'transients-manager' ); ?></option> </optgroup> <optgroup label="<?php esc_attr_e( 'Expiration', 'transients-manager' ); ?>"> <option value="delete_expired_transients"><?php esc_html_e( 'Delete Expired', 'transients-manager' ); ?></option> <option value="delete_transients_with_expiration"><?php esc_html_e( 'Delete With Expiration', 'transients-manager' ); ?></option> <option value="delete_transients_without_expiration"><?php esc_html_e( 'Delete Without Expiration', 'transients-manager' ); ?></option> </optgroup> <optgroup label="<?php esc_attr_e( 'Reset', 'transients-manager' ); ?>"> <option value="delete_all_transients"><?php esc_html_e( 'Delete All', 'transients-manager' ); ?></option> </optgroup> </select> <input type="submit" class="button secondary" value="<?php esc_attr_e( 'Apply', 'transients-manager' ); ?>" /> </div> <div class="alignleft actions"> <input type="button" class="button secondary" value="<?php esc_attr_e( 'Delete All', 'transients-manager' ); ?>" onclick="const select = document.getElementById('bulk-action-selector-top'); select.value='delete_all_transients'; select.dispatchEvent(new Event('change')); document.getElementById('transients-delete').submit();" /> </div> <div class="tablenav-pages <?php echo esc_attr( $one_page ); ?>"> <span class="displaying-num"><?php printf( _n( '%s Transient', '%s Transients', $count, 'transients-manager' ), number_format_i18n( $count ) ); ?></span> <span class="pagination-links"><?php echo $pagination; // HTML OK ?></span> </div> </div> <table class="wp-list-table widefat fixed transients striped"> <thead> <tr> <td id="cb" class="manage-column column-cb check-column"> <label for="cb-select-all-<?php echo (int) $page; ?>" class="screen-reader-text"><?php esc_html_e( 'Select All', 'transients-manager' ); ?></label> <input type="checkbox" id="cb-select-all-<?php echo (int) $page; ?>"> </td> <th class="column-primary"><?php esc_html_e( 'Name', 'transients-manager' ); ?></th> <th class="column-value"><?php esc_html_e( 'Value', 'transients-manager' ); ?></th> <th class="column-expiration"><?php esc_html_e( 'Expiration', 'transients-manager' ); ?></th> </tr> </thead> <tbody> <?php if ( ! empty( $transients ) ) : foreach ( $transients as $transient ) : // Get Transient name $name = $this->get_transient_name( $transient ); $value = $this->get_transient_value( $transient ); $expiration = $this->get_transient_expiration( $transient ); // Delete $delete_url = wp_nonce_url( remove_query_arg( array( 'deleted', 'updated' ), add_query_arg( array( 'action' => 'delete_transient', 'transient' => $name, 'name' => $transient->option_name ) ) ), 'transients_manager' ); // Edit $edit_url = remove_query_arg( array( 'updated', 'deleted' ), add_query_arg( array( 'action' => 'edit_transient', 'trans_id' => $transient->option_id ) ) ); ?> <tr> <th id="cb" class="manage-column column-cb check-column"> <label for="cb-select-<?php echo (int) $page; ?>" class="screen-reader-text"><?php printf( esc_attr__( 'Select %s', 'transients-manager' ), esc_html( $name ) ); ?></label> <input type="checkbox" id="cb-select-<?php echo (int) $transient->option_id; ?>" name="transients[]" value="<?php echo (int) $transient->option_id; ?>"> </th> <td class="column-primary" data-colname="<?php esc_attr_e( 'Name', 'transients-manager' ); ?>"> <pre class="truncate"> <code class="transient-name" title="<?php printf( esc_attr__( 'Option ID: %d', 'transients-manager' ), (int) $transient->option_id ); ?>"><?php echo esc_html( $name ); ?></code> </pre> <div class="row-actions"> <span class="edit"><a href="<?php echo esc_url( $edit_url ); ?>" class="edit"><?php esc_html_e( 'Edit', 'transients-manager' ); ?></a></span> | <span class="delete"><a href="<?php echo esc_url( $delete_url ); ?>" class="delete"><?php esc_html_e( 'Delete', 'transients-manager' ); ?></a></span> </div> <button type="button" class="toggle-row"> <span class="screen-reader-text"><?php esc_html_e( 'Show more details', 'transients-manager' ); ?></span> </button> </td> <td data-colname="<?php esc_attr_e( 'Value', 'transients-manager' ); ?>"> <span class="transient-value truncate"><?php echo $value; // HTML OK ?></span> </td> <td data-colname="<?php esc_attr_e( 'Expiration', 'transients-manager' ); ?>"> <span class="transient-expiration"><?php echo $expiration; // HTML OK ?></span> </td> </tr> <?php endforeach; else : ?> <tr><td colspan="4"><?php esc_html_e( 'No transients found.', 'transients-manager' ); ?></td> <?php endif; ?> </tbody> <tfoot> <tr> <td class="manage-column column-cb check-column"> <label for="cb-select-all-<?php echo (int) $page; ?>" class="screen-reader-text"><?php esc_html_e( 'Select All', 'transients-manager' ); ?></label> <input type="checkbox" id="cb-select-all-<?php echo (int) $page; ?>"> </td> <th class="column-primary"><?php esc_html_e( 'Name', 'transients-manager' ); ?></th> <th><?php esc_html_e( 'Value', 'transients-manager' ); ?></th> <th><?php esc_html_e( 'Expiration', 'transients-manager' ); ?></th> </tr> </tfoot> </table> <div class="tablenav bottom"> <div class="alignleft actions bulkactions"> <label for="bulk-action-selector-top" class="screen-reader-text"><?php esc_html_e( 'Select Bulk action', 'transients-manager' ); ?></label> <select name="action" id="bulk-action-selector-bottom"> <option value="-1"><?php esc_html_e( 'Bulk actions', 'transients-manager' ); ?></option> <optgroup label="<?php esc_attr_e( 'Selection', 'transients-manager' ); ?>"> <option value="delete_selected_transients"><?php esc_html_e( 'Delete Selected', 'transients-manager' ); ?></option> </optgroup> <optgroup label="<?php esc_attr_e( 'Expiration', 'transients-manager' ); ?>"> <option value="delete_expired_transients"><?php esc_html_e( 'Delete Expired', 'transients-manager' ); ?></option> <option value="delete_transients_with_expiration"><?php esc_html_e( 'Delete With Expiration', 'transients-manager' ); ?></option> <option value="delete_transients_without_expiration"><?php esc_html_e( 'Delete Without Expiration', 'transients-manager' ); ?></option> </optgroup> <optgroup label="<?php esc_attr_e( 'Reset', 'transients-manager' ); ?>"> <option value="delete_all_transients"><?php esc_html_e( 'Delete All', 'transients-manager' ); ?></option> </optgroup> </select> <input type="submit" class="button secondary" value="<?php esc_attr_e( 'Apply', 'transients-manager' ); ?>" /> </div> <div class="tablenav-pages <?php echo esc_attr( $one_page ); ?>"> <span class="displaying-num"><?php printf( _n( '%s Transient', '%s Transients', $count, 'transients-manager' ), number_format_i18n( $count ) ); ?></span> <span class="pagination-links"><?php echo $pagination; // HTML OK ?></span> </div> </div> </form> <?php $this->site_time(); ?> </div> <?php } /** * Output the page HTML for editing a Transient * * @since 2.0 * @param object $transient */ protected function page_edit_transient( $transient = false) { // Get values $name = $this->get_transient_name( $transient ); $expiration = $this->get_transient_expiration_time( $transient ); ?> <div class="wrap"> <h1 class="wp-heading-inline"><?php esc_html_e( 'Edit Transient', 'transients-manager' ); ?></h1> <hr class="wp-header-end"> <form method="post"> <input type="hidden" name="transient" value="<?php echo esc_attr( $name ); ?>" /> <input type="hidden" name="action" value="update_transient" /> <?php wp_nonce_field( 'transients_manager' ); ?> <table class="form-table"> <tbody> <tr> <th><?php esc_html_e( 'Option ID', 'transients-manager' ); ?></th> <td><input type="text" disabled class="large-text code" name="name" value="<?php echo esc_attr( $transient->option_id ); ?>" /></td> </tr> <tr> <th><?php esc_html_e( 'Name', 'transients-manager' ); ?></th> <td><input type="text" class="large-text code" name="name" value="<?php echo esc_attr( $transient->option_name ); ?>" /></td> </tr> <tr> <th><?php esc_html_e( 'Expiration', 'transients-manager' ); ?></th> <td><input type="text" class="large-text" name="expires" value="<?php echo esc_attr( $expiration ); ?>" /> </tr> <tr> <th><?php esc_html_e( 'Value', 'transients-manager' ); ?></th> <td> <textarea class="large-text code" name="value" id="transient-editor" style="height: 302px; padding-left: 35px;"><?php echo esc_textarea( $transient->option_value ); ?></textarea> </td> </tr> </tbody> </table> <p class="submit"> <?php submit_button( '', 'primary', '', false ); ?> </p> </form> </div> <?php } /** * Output the time for the site * * (Props to WP Crontrol for this approach) * * @since 2.0 */ public function site_time() { // Get options $timezone_string = get_option( 'timezone_string', '' ); $gmt_offset = get_option( 'gmt_offset', 0 ); $timezone_name = 'UTC'; // UTC if ( ( 'UTC' !== $timezone_string ) || ! empty( $gmt_offset ) ) { $formatted_offset = ( 0 <= $gmt_offset ) ? '+' . (string) $gmt_offset : (string) $gmt_offset; $formatted_offset = str_replace( array( '.25', '.5', '.75' ), array( ':15', ':30', ':45' ), $formatted_offset ); } // Format the timezone name $timezone_name = ! empty( $formatted_offset ) ? 'UTC' . $formatted_offset : str_replace( '_', ' ', $timezone_string ); // Site time $site_time = date_i18n( 'Y-m-d H:i:s', $this->time_now ); $site_time_utc = gmdate( 'Y-m-d\TH:i:s+00:00', $this->time_now ); $st_html = esc_html( sprintf( /* translators: 1: Date and time, 2: Timezone */ __( 'Site time: %1$s (%2$s)', 'transients-manager' ), $site_time, $timezone_name ) ); // Cron time $cron_time = wp_date( 'Y-m-d H:i:s', $this->next_cron_delete ); $cron_time_utc = gmdate( 'Y-m-d\TH:i:s+00:00', $this->next_cron_delete ); $ct_time_since = $this->time_since( $this->next_cron_delete - $this->time_now ); $nc_time = esc_html( sprintf( /* translators: 1: Date and time, 2: Timezone, 3: Time since */ __( 'Expired transients scheduled for deletion on: %1$s (%2$s) – %3$s from now', 'transients-manager' ), $cron_time, $timezone_name, $ct_time_since ) ); ?> <p class="transients-manager-helpful-times"> <?php echo sprintf( '<time datetime="%1$s" title="%1$s">%2$s</time>', $site_time_utc, $st_html ); ?><br><br><?php echo sprintf( '<time datetime="%1$s" title="%1$s">%2$s</time>', $cron_time_utc, $nc_time ); ?></p> <?php } /** * Add toolbar node for suspending transients * * @since 1.6 * @param object $wp_admin_bar */ public function suspend_transients_button( $wp_admin_bar ) { // Bail if user is not capable if ( ! current_user_can( $this->capability ) ) { return; } // Suspended if ( get_option( 'pw_tm_suspend' ) ) { $action = 'unsuspend_transients'; $label = '<span style="color: #b32d2e;">' . esc_html__( 'Unsuspend Transients', 'transients-manager' ) . '</span>'; // Not suspended } else { $action = 'suspend_transients'; $label = esc_html__( 'Suspend Transients', 'transients-manager' ); } // Suspend $wp_admin_bar->add_node( array( 'id' => 'tm-suspend', 'title' => $label, 'parent' => 'top-secondary', 'href' => wp_nonce_url( add_query_arg( array( 'action' => $action ) ), 'transients_manager' ) ) ); // View $wp_admin_bar->add_node( array( 'id' => 'tm-view', 'title' => esc_html__( 'View Transients', 'transients-manager' ), 'parent' => 'tm-suspend', 'href' => add_query_arg( array( 'page' => $this->page_id ), admin_url( 'tools.php' ) ) ) ); } /** * Get transients from the database * * These queries are uncached, to prevent race conditions with persistent * object cache setups and the way Transients use them. * * @since 1.0 * @param array $args * @return array */ private function get_transients( $args = array() ) { global $wpdb; // Parse arguments $r = $this->parse_args( $args ); // Escape some LIKE parts $esc_name = '%' . $wpdb->esc_like( '_transient_' ) . '%'; $esc_time = '%' . $wpdb->esc_like( '_transient_timeout_' ) . '%'; // SELECT $sql = array( 'SELECT' ); // COUNT if ( ! empty( $r['count'] ) ) { $sql[] = 'count(option_id)'; } else { $sql[] = '*'; } // FROM $sql[] = "FROM {$wpdb->options} WHERE option_name LIKE %s AND option_name NOT LIKE %s"; // Search if ( ! empty( $r['search'] ) ) { $search = '%' . $wpdb->esc_like( $r['search'] ) . '%'; $sql[] = $wpdb->prepare( "AND option_name LIKE %s", $search ); } // Limits if ( empty( $r['count'] ) ) { $offset = absint( $r['offset'] ); $number = absint( $r['number'] ); $sql[] = $wpdb->prepare( "ORDER BY option_id DESC LIMIT %d, %d", $offset, $number ); } // Combine the SQL parts $query = implode( ' ', $sql ); // Prepare $prepared = $wpdb->prepare( $query, $esc_name, $esc_time ); // Query $transients = empty( $r['count'] ) ? $wpdb->get_results( $prepared ) // Rows : $wpdb->get_var( $prepared ); // Count // Return transients return $transients; } /** * Parse the query arguments * * @since 2.0 * @param array $args * @return array */ private function parse_args( $args = array() ) { // Parse $r = wp_parse_args( $args, array( 'offset' => 0, 'number' => 30, 'search' => '', 'count' => false ) ); // Return return $r; } /** * Retrieve the total number transients in the database * * If a search is performed, it returns the number of found results * * @since 1.0 * @param string $search * @return int */ private function get_total_transients( $search = '' ) { // Query $count = $this->get_transients( array( 'count' => true, 'search' => $search ) ); // Return int return absint( $count ); } /** * Retrieve a transient by its ID * * @since 1.0 * @param int $id * @return object */ private function get_transient_by_id( $id = 0 ) { global $wpdb; $id = absint( $id ); // Bail if empty ID if ( empty( $id ) ) { return false; } // Prepare $prepared = $wpdb->prepare( "SELECT * FROM {$wpdb->options} WHERE option_id = %d", $id ); // Query return $wpdb->get_row( $prepared ); } /** * Is a transient name site-wide? * * @since 2.0 * @param string $transient_name * @return boolean */ private function is_site_wide( $transient_name = '' ) { return ( false !== strpos( $transient_name, '_site_transient' ) ); } /** * Retrieve the transient name from the transient object * * @since 1.0 * @return string */ private function get_transient_name( $transient = false ) { // Bail if no Transient if ( empty( $transient ) ) { return ''; } // Position $pos = $this->is_site_wide( $transient->option_name ) ? 16 : 11; return substr( $transient->option_name, $pos, strlen( $transient->option_name ) ); } /** * Retrieve the human-friendly transient value from the transient object * * @since 1.0 * @param object $transient * @return string/int */ private function get_transient_value( $transient ) { // Get the value type $type = $this->get_transient_value_type( $transient ); // Trim value to 100 chars $value = substr( $transient->option_value, 0, 100 ); // Escape & wrap in <code> tag $value = '<code>' . esc_html( $value ) . '</code>'; // Return return $value . '<br><span class="transient-type badge">' . esc_html( $type ) . '</span>'; } /** * Try to guess the type of value the Transient is * * @since 2.0 * @param object $transient * @return string */ private function get_transient_value_type( $transient ) { // Default type $type = esc_html__( 'unknown', 'transients-manager' ); // Try to unserialize $value = maybe_unserialize( $transient->option_value ); // Array if ( is_array( $value ) ) { $type = esc_html__( 'array', 'transients-manager' ); // Object } elseif ( is_object( $value ) ) { $type = esc_html__( 'object', 'transients-manager' ); // Serialized array } elseif ( is_serialized( $value ) ) { $type = esc_html__( 'serialized', 'transients-manager' ); // HTML } elseif ( strip_tags( $value ) !== $value ) { $type = esc_html__( 'html', 'transients-manager' ); // Scalar } elseif ( is_scalar( $value ) ) { if ( is_numeric( $value ) ) { // Likely a timestamp if ( 10 === strlen( $value ) ) { $type = esc_html__( 'timestamp?', 'transients-manager' ); // Likely a boolean } elseif ( in_array( $value, array( '0', '1' ), true ) ) { $type = esc_html__( 'boolean?', 'transients-manager' ); // Any number } else { $type = esc_html__( 'numeric', 'transients-manager' ); } // JSON } elseif ( is_string( $value ) && is_object( json_decode( $value ) ) ) { $type = esc_html__( 'json', 'transients-manager' ); // Scalar } else { $type = esc_html__( 'scalar', 'transients-manager' ); } // Empty } elseif ( empty( $value ) ) { $type = esc_html__( 'empty', 'transients-manager' ); } // Return type return $type; } /** * Retrieve the expiration timestamp * * @since 1.0 * @param object $transient * @return int */ private function get_transient_expiration_time( $transient ) { // Get the same to use in the option key $name = $this->get_transient_name( $transient ); // Get the value of the timeout $time = $this->is_site_wide( $transient->option_name ) ? get_option( "_site_transient_timeout_{$name}" ) : get_option( "_transient_timeout_{$name}" ); // Return the value return $time; } /** * Retrieve the human-friendly expiration time * * @since 1.0 * @param object $transient * @return string */ private function get_transient_expiration( $transient ) { $expiration = $this->get_transient_expiration_time( $transient ); // Bail if no expiration if ( empty( $expiration ) ) { return '—<br><span class="badge">' . esc_html__( 'Persistent', 'transients-manager' ) . '</span>'; } // UTC & local dates $date_utc = gmdate( 'Y-m-d\TH:i:s+00:00', $expiration ); $date_local = get_date_from_gmt( date( 'Y-m-d H:i:s', $expiration ), 'Y-m-d H:i:s' ); // Create <time> tag $time = sprintf( '<time datetime="%1$s" title="%1$s">%2$s</time>', esc_attr( $date_utc ), esc_html( $date_local ) ); // Expired if ( $this->time_now > $expiration ) { return $time . '<br><span class="transient-expired badge">' . esc_html__( 'Expired', 'transients-manager' ) . '</span>'; } // Return time since return $time . '<br><span class="badge green">' . $this->time_since( $expiration - $this->time_now ) . '</span>'; } /** * Process delete and update actions * * @since 1.0 */ public function process_actions() { if ( empty( $this->action ) ) { return; } // Bail if malformed Transient request if ( empty( $_REQUEST['transient'] ) && ! in_array( $this->action, array( 'suspend_transients', 'unsuspend_transients' ), true ) ) { return; } // Bail if user is not capable if ( ! current_user_can( $this->capability ) ) { return; } // Bail if nonce fails if ( empty( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'transients_manager' ) ) { return; } if ( ! in_array( $this->action, array( 'suspend_transients', 'unsuspend_transients' ), true ) ) { // Encode search string $search = ! empty( $_REQUEST['s'] ) ? urlencode( $_REQUEST['s'] ) : ''; // Sanitize transient $transient = sanitize_key( $_REQUEST['transient'] ); // Site wide $site_wide = ! empty( $_REQUEST['name'] ) && $this->is_site_wide( $_REQUEST['name'] ); } switch ( $this->action ) { case 'suspend_transients' : update_option( 'pw_tm_suspend', 1 ); wp_safe_redirect( remove_query_arg( array( 'updated', 'deleted', 'action', '_wpnonce' ) ) ); exit; case 'unsuspend_transients' : delete_option( 'pw_tm_suspend', 1 ); wp_safe_redirect( remove_query_arg( array( 'updated', 'deleted', 'action', '_wpnonce' ) ) ); exit; case 'delete_transient' : $this->delete_transient( $transient, $site_wide ); wp_safe_redirect( remove_query_arg( array( 'updated' ), add_query_arg( array( 'page' => $this->page_id, 's' => $search, 'deleted' => true ), admin_url( 'tools.php' ) ) ) ); exit; case 'update_transient' : $this->update_transient( $transient, $site_wide ); wp_safe_redirect( remove_query_arg( array( 'deleted' ), add_query_arg( array( 'page' => $this->page_id, 's' => $search, 'updated' => true ), admin_url( 'tools.php' ) ) ) ); exit; case 'delete_selected_transients' : $this->delete_selected_transients(); wp_safe_redirect( remove_query_arg( array( 'updated' ), add_query_arg( array( 'page' => $this->page_id, 'deleted' => true ), admin_url( 'tools.php' ) ) ) ); exit; case 'delete_expired_transients' : $this->delete_expired_transients(); wp_safe_redirect( remove_query_arg( array( 'updated' ), add_query_arg( array( 'page' => $this->page_id, 'deleted' => true ), admin_url( 'tools.php' ) ) ) ); exit; case 'delete_transients_with_expiration' : $this->delete_transients_with_expirations(); wp_safe_redirect( remove_query_arg( array( 'updated' ), add_query_arg( array( 'page' => $this->page_id, 'deleted' => true ), admin_url( 'tools.php' ) ) ) ); exit; case 'delete_transients_without_expiration' : $this->delete_transients_without_expirations(); wp_safe_redirect( remove_query_arg( array( 'updated' ), add_query_arg( array( 'page' => $this->page_id, 'deleted' => true ), admin_url( 'tools.php' ) ) ) ); exit; case 'delete_all_transients' : $this->delete_all_transients(); wp_safe_redirect( remove_query_arg( array( 'updated' ), add_query_arg( array( 'page' => $this->page_id, 'deleted' => true ), admin_url( 'tools.php' ) ) ) ); exit; } } /** * Delete a transient by name * * @since 1.0 * @param object $transient * @param boolean $site_wide * @return boolean */ private function delete_transient( $transient = '', $site_wide = false ) { // Bail if no Transient if ( empty( $transient ) ) { return false; } // Transient type $retval = ( false !== $site_wide ) ? delete_site_transient( $transient ) : delete_transient( $transient ); // Return return $retval; } /** * Bulk delete function * * @since 1.5 * @param array $transients * @return boolean */ private function bulk_delete_transients( $transients = array() ) { // Bail if empty or error if ( empty( $transients ) || is_wp_error( $transients ) ) { return false; } // Loop through Transients, and delete them foreach ( $transients as $transient ) { // Site wide $site_wide = $this->is_site_wide( $transient ); // Get prefix based on site-wide $prefix = ! empty( $site_wide ) ? '_site_transient_timeout_' : '_transient_timeout_'; // Strip prefix from name $name = str_replace( $prefix, '', $transient ); // Delete $this->delete_transient( $name, $site_wide ); } // No errors return true; } /** * Delete Selected transients. * * @since 1.8 * @return false|int */ public function delete_selected_transients() { global $wpdb; // Bail if no Transients if ( empty( $_REQUEST['transients'] ) || ! is_array( $_REQUEST['transients'] ) ) { return 0; } // Filter $transients_ids_filtered = wp_parse_id_list( $_REQUEST['transients'] ); // Bail if no IDs if ( empty( $transients_ids_filtered ) ) { return 0; } // Query $placeholders = array_fill( 0, count( $transients_ids_filtered ), '%d' ); $format = implode( ', ', $placeholders ); $count = $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_id IN ({$format})", $transients_ids_filtered ) ); // Return count of deleted return $count; } /** * Delete all expired transients * * @since 1.1 * @return boolean */ public function delete_expired_transients() { global $wpdb; // Query $esc_time = '%' . $wpdb->esc_like( '_transient_timeout_' ) . '%'; $prepared = $wpdb->prepare( "SELECT option_name FROM {$wpdb->options} where option_name LIKE %s AND option_value+0 < %d", $esc_time, $this->time_now ); $expired = $wpdb->get_col( $prepared ); // Bulk delete return $this->bulk_delete_transients( $expired ); } /** * Delete all transients with expiration * * @since 1.2 * @return boolean */ public function delete_transients_with_expirations() { global $wpdb; // Query $esc_time = '%' . $wpdb->esc_like( '_transient_timeout_' ) . '%'; $prepared = $wpdb->prepare( "SELECT option_name FROM {$wpdb->options} where option_name LIKE %s", $esc_time ); $will_expire = $wpdb->get_col( $prepared ); // Bulk delete return $this->bulk_delete_transients( $will_expire ); } /** * Delete all transients without expiration * * @since 2.0 * @return boolean */ public function delete_transients_without_expirations() { global $wpdb; // Escape likes $esc_time = '%' . $wpdb->esc_like( '_transient_timeout_' ) . '%'; $esc_name = '%' . $wpdb->esc_like( '_transient_' ) . '%'; // Queries $timeouts = $wpdb->get_col( $wpdb->prepare( "SELECT option_name FROM {$wpdb->options} where option_name LIKE %s", $esc_time ) ); $names = $wpdb->get_col( $wpdb->prepare( "SELECT option_name FROM {$wpdb->options} where option_name LIKE %s", $esc_name ) ); // Diff to remove timeouts from names $items = array_diff( $names, $timeouts ); // Remove "%_transient_timeout_" from left of timeouts foreach ( $timeouts as $index => $timeout ) { $pos = strrpos( $timeout, '_transient_timeout_' ) + strlen( '_transient_timeout_' ); $timeouts[ $index ] = substr( $timeout, $pos ); } // Remove "%_transient_" from left of items foreach ( $items as $index => $item ) { $pos = strrpos( $item, '_transient_' ) + strlen( '_transient_' ); $items[ $index ] = substr( $item, $pos ); } // Remove timeouts from items $bulk = array_diff( $items, $timeouts ); // Bulk delete return $this->bulk_delete_transients( $bulk ); } /** * Delete all transients * * @since 1.0 * @return false|int */ public function delete_all_transients() { global $wpdb; // Escape like $esc_name = '%' . $wpdb->esc_like( '_transient_' ) . '%'; // Query $count = $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $esc_name ) ); // Return count return $count; } /** * Update an existing transient * * @since 1.0 * @param object $transient * @param boolean $site_wide * @return boolean */ private function update_transient( $transient = '', $site_wide = false ) { // Bail if no Transient if ( empty( $transient ) ) { return false; } // Values $value = stripslashes( $_POST['value'] ); $expiration = absint( stripslashes( $_POST['expires'] ) ); // Subtract now $expiration = ( $expiration - $this->time_now ); // Transient type $retval = ( false !== $site_wide ) ? set_site_transient( $transient, $value, $expiration ) : set_transient( $transient, $value, $expiration ); // Return return $retval; } /** * Prevent transient from being updated if transients are suspended * * @since 1.6 * @param mixed $value * @param string $option * @return mixed */ public function maybe_block_update_transient( $value = '', $option = '' ) { // Bail if not Suspended if ( ! get_option( 'pw_tm_suspend' ) ) { return $value; } // Bail if not a Transient if ( false === strpos( $option, '_transient' ) ) { return $value; } // Return false return false; } /** * Prevent transient from being updated if transients are suspended * * @since 1.6 */ public function maybe_block_set_transient( $option = '' ) { // Bail if not Suspended if ( ! get_option( 'pw_tm_suspend' ) ) { return; } // Bail if not a Transient if ( false === strpos( $option, '_transient' ) ) { return; } // Delete the Transient delete_option( $option ); } /** * Converts a period of time in seconds into a human-readable format * representing the interval. * * @since 2.0 * @param int $since A period of time in seconds. * @return string An interval represented as a string. */ public function time_since( $since = 0 ) { // Array of time period chunks. $chunks = array( /* translators: 1: The number of years in an interval of time. */ array( 60 * 60 * 24 * 365, _n_noop( '%s year', '%s years', 'transients-manager' ) ), /* translators: 1: The number of months in an interval of time. */ array( 60 * 60 * 24 * 30, _n_noop( '%s month', '%s months', 'transients-manager' ) ), /* translators: 1: The number of weeks in an interval of time. */ array( 60 * 60 * 24 * 7, _n_noop( '%s week', '%s weeks', 'transients-manager' ) ), /* translators: 1: The number of days in an interval of time. */ array( 60 * 60 * 24, _n_noop( '%s day', '%s days', 'transients-manager' ) ), /* translators: 1: The number of hours in an interval of time. */ array( 60 * 60, _n_noop( '%s hour', '%s hours', 'transients-manager' ) ), /* translators: 1: The number of minutes in an interval of time. */ array( 60, _n_noop( '%s minute', '%s minutes', 'transients-manager' ) ), /* translators: 1: The number of seconds in an interval of time. */ array( 1, _n_noop( '%s second', '%s seconds', 'transients-manager' ) ), ); if ( $since <= 0 ) { return esc_html__( 'now', 'transients-manager' ); } /** * We only want to output two chunks of time here, eg: * x years, xx months * x days, xx hours * so there's only two bits of calculation below: */ $j = count( $chunks ); // Step one: the first chunk. for ( $i = 0; $i < $j; $i++ ) { $seconds = $chunks[ $i ][ 0 ]; $name = $chunks[ $i ][ 1 ]; // Finding the biggest chunk (if the chunk fits, break). $count = floor( $since / $seconds ); if ( ! empty( $count ) ) { break; } } // Set output var. $output = sprintf( translate_nooped_plural( $name, $count, 'transients-manager' ), $count ); // Step two: the second chunk. if ( $i + 1 < $j ) { $seconds2 = $chunks[ $i + 1 ][ 0 ]; $name2 = $chunks[ $i + 1 ][ 1 ]; $count2 = floor( ( $since - ( $seconds * $count ) ) / $seconds2 ); // Add to output var. if ( ! empty( $count2 ) ) { $output .= ' ' . sprintf( translate_nooped_plural( $name2, $count2, 'transients-manager' ), $count2 ); } } return $output; } /** * Add <style> tag to "admin_print_styles-{$this->page_id}" hook * * @since 2.0 */ public function print_styles() { // Get the page type $type = $this->page_type(); // Editing... if ( 'edit' === $type ) { // Try to enqueue the code editor $settings = wp_enqueue_code_editor( array( 'type' => 'text/plain', 'codemirror' => array( 'indentUnit' => 4, 'tabSize' => 4, ), ) ); // Bail if user disabled CodeMirror. if ( false === $settings ) { return; } // Target the textarea wp_add_inline_script( 'code-editor', sprintf( 'jQuery( function() { wp.codeEditor.initialize( "transient-editor", %s ); } );', wp_json_encode( $settings ) ) ); // Custom styling wp_add_inline_style( 'code-editor', '.CodeMirror-wrap { width: 99%; border: 1px solid #8c8f94; border-radius: 3px; overflow: hidden; } .CodeMirror-gutters { background: transparent; }' ); // Showing list-table... } else { // Escape once $esc = esc_attr( $this->page_id ); ?> <style type="text/css" id="transients-manager"> body.tools_page_<?php echo $esc; // Escaped ?> table.transients .column-value { width: 38%; } body.tools_page_<?php echo $esc; // Escaped ?> table.transients .column-expiration { width: 170px; } body.tools_page_<?php echo $esc; // Escaped ?> table.transients .truncate { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } body.tools_page_<?php echo $esc; // Escaped ?> table.transients .column-primary pre { margin: 0; } body.tools_page_<?php echo $esc; // Escaped ?> table.transients span.transient-value { display: block; } body.tools_page_<?php echo $esc; // Escaped ?> table.transients code { background: transparent; margin: 0; padding: 0; } body.tools_page_<?php echo $esc; // Escaped ?> table.transients span.transient-value, body.tools_page_<?php echo $esc; // Escaped ?> table.transients span.transient-expiration { cursor: default; } body.tools_page_<?php echo $esc; // Escaped ?> table.transients span.badge, body.tools_page_<?php echo $esc; // Escaped ?> table.transients div.row-actions { margin-top: 5px; } body.tools_page_<?php echo $esc; // Escaped ?> table.transients span.badge { padding: 2px 7px; border-radius: 4px; display: inline-flex; align-items: center; background: rgba(0, 0, 0, 0.07); color: #50575e; } body.tools_page_<?php echo $esc; // Escaped ?> table.transients span.badge.green { color: #017d5c; background: #e5f5f0; } body.tools_page_<?php echo $esc; // Escaped ?> table.transients span.transient-expired { color: #b32d2e; background: #ffd6d6; } body.tools_page_<?php echo $esc; // Escaped ?> .tablenav .info { display: inline-block; margin: 2px 0; padding: 2px 7px; } body.tools_page_<?php echo $esc; // Escaped ?> .tablenav-pages span.displaying-num { display: inline-block; margin: 5px 0; } body.tools_page_<?php echo $esc; // Escaped ?> span.pagination-links .page-numbers { border-color: #7e8993; color: #32373c; display: inline-block; vertical-align: baseline; min-width: 30px; min-height: 30px; text-decoration: none; text-align: center; font-size: 13px; line-height: 2.15384615; margin: 0; padding: 0 10px; cursor: pointer; border-width: 1px; border-style: solid; border-radius: 3px; -webkit-appearance: none; white-space: nowrap; box-sizing: border-box; } body.tools_page_<?php echo $esc; // Escaped ?> span.pagination-links .page-numbers.next, body.tools_page_<?php echo $esc; // Escaped ?> span.pagination-links .page-numbers.prev { font-size: 16px; line-height: 1.625; padding: 0 4px; } body.tools_page_<?php echo $esc; // Escaped ?> span.pagination-links a.page-numbers:hover { background-color: #f0f0f1; border-color: #717c87; color: #262a2e; } body.tools_page_<?php echo $esc; // Escaped ?> span.pagination-links span.page-numbers { color: #a7aaad; border-color: #dcdcde; background: #f6f7f7; box-shadow: none; cursor: default; transform: none; } </style> <?php } } }
[+]
..
[-] TransientsManager.php
[open]
[-] CrossPromotion.php
[open]