/home/arranoyd/energyclinic/wp-content/plugins/docket-cache/includes/src/Plugin.php
<?php
/**
 * Docket Cache.
 *
 * @author  Nawawi Jamili
 * @license MIT
 *
 * @see    https://github.com/nawawi/docket-cache
 */

namespace Nawawi\DocketCache;

\defined('ABSPATH') || exit;

final class Plugin extends Bepart
{
    /**
     * Plugin file.
     *
     * @var string
     */
    public $file;

    /**
     * Plugin slug.
     *
     * @var string
     */
    public $slug;

    /**
     * Plugin hook.
     *
     * @var string
     */
    public $hook;

    /**
     * Plugin path.
     *
     * @var string
     */
    public $path;

    /**
     * Plugin valid page uri.
     *
     * @var string
     */
    public $page;

    /**
     * Plugin action token.
     *
     * @var string
     */
    public $token;

    /**
     * Plugin action notice.
     *
     * @var string
     */
    public $notice;

    /**
     * Plugin screen name.
     *
     * @var string
     */
    public $screen;

    /**
     * The cache path.
     *
     * @var string
     */
    public $cache_path;

    /**
     * API Endpoint.
     *
     * @var string
     */
    public $api_endpoint;

    /**
     * Cronbot Endpoint.
     *
     * @var string
     */
    public $cronbot_endpoint;

    /**
     * WpConfig runtime notice.
     *
     * @var bool
     */
    public $inruntime = false;

    /**
     * constructor.
     */
    public function __construct()
    {
        $this->slug = 'docket-cache';
        $this->file = nwdcx_constval('FILE');
        $this->hook = plugin_basename($this->file);
        $this->path = realpath(plugin_dir_path($this->file));
        $this->register_init();
    }

    /**
     * Dropino().
     */
    public function cx()
    {
        static $inst;
        if (!\is_object($inst)) {
            $inst = new Dropino($this->path);
        }

        return $inst;
    }

    /**
     * Canopt().
     */
    public function co()
    {
        static $inst;
        if (!\is_object($inst)) {
            $inst = new Canopt();
        }

        return $inst;
    }

    /**
     * Constans().
     */
    public function cf()
    {
        static $inst;
        if (!\is_object($inst)) {
            $inst = new Constans();
        }

        return $inst;
    }

    /**
     * get_version.
     */
    public function version()
    {
        static $version = false;

        if (!empty($version)) {
            return $version;
        }

        $version = $this->plugin_meta($this->file)['Version'];

        return $version;
    }

    /**
     * get_info.
     */
    public function get_info()
    {
        $status_code = [
            0 => esc_html__('Disabled', 'docket-cache'),
            1 => esc_html__('Enabled', 'docket-cache'),
            2 => esc_html__('Not Available', 'docket-cache'),
            3 => esc_html__('Unknown', 'docket-cache'),
        ];

        $yesno = [
            0 => esc_html__('No', 'docket-cache'),
            1 => esc_html__('Yes', 'docket-cache'),
        ];

        $force_stats = $this->cf()->is_dctrue('WPCLI');
        $cache_stats = $this->get_cache_stats($force_stats);

        $status = $this->get_status();
        $status_text_stats = '';
        $status_text = '';

        switch ($status) {
            case 1:
                if ($this->cf()->is_dctrue('STATS')) {
                    /* translators: %1$s = size, %2$s number of file */
                    $status_text_stats = sprintf(esc_html__(_n('%1$s object of %2$s file', '%1$s object of %2$s files', $cache_stats->files < 1 ? 1 : $cache_stats->files, 'docket-cache')), $this->normalize_size($cache_stats->size), $cache_stats->files);
                }
                $status_text = $status_code[1];
                break;
            case 2:
                $status_text = esc_html__('Disabled at runtime.', 'docket-cache');
                break;
            default:
                $status_text = $status_code[$status];
        }

        $opcache = $this->get_opcache_status();
        $opcache_text_stats = '';
        $opcache_text = '';

        $opcache_dc_stats = '';
        $opcache_wp_stats = '';
        switch ($opcache->status) {
            case 1:
                /* translators: %1$s = size, %2$s number of file */
                $opcache_text_stats = sprintf(esc_html__(_n('%1$s memory of %2$s file', '%1$s memory of %2$s files', $opcache->files, 'docket-cache')), $this->normalize_size($opcache->size), $opcache->files);

                if ($opcache->dcfiles > 1) {
                    /* translators: %1$s = size, %2$s number of file */
                    $opcache_dc_stats = sprintf(esc_html__(_n('%1$s memory of %2$s file', '%1$s memory of %2$s files', $opcache->dcfiles, 'docket-cache')), $this->normalize_size($opcache->dcsize), $opcache->dcfiles);

                    /* translators: %1$s = size, %2$s number of file */
                    $opcache_wp_stats = sprintf(esc_html__(_n('%1$s memory of %2$s file', '%1$s memory of %2$s files', $opcache->wpfiles, 'docket-cache')), $this->normalize_size($opcache->wpsize), $opcache->wpfiles);
                }
                break;
            case 2:
                $opcache_text = $status_code[1];
                break;
            case 3:
                $opcache_text = $status_code[1].' (<a href="https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.file-cache-only" rel="noopener" target="new">'.esc_html__('File cache only', 'docket-cache').'</a>)';
                break;
            case 4:
                if ($opcache->files > 0) {
                    /* translators: %1$s = size, %2$s number of file */
                    $opcache_text_stats = sprintf(esc_html__(_n('%1$s size of %2$s file', '%1$s size of %2$s files', $opcache->files, 'docket-cache')), $this->normalize_size($opcache->size), $opcache->files);

                    if ($opcache->dcfiles > 1) {
                        /* translators: %1$s = size, %2$s number of file */
                        $opcache_dc_stats = sprintf(esc_html__(_n('%1$s size of %2$s file', '%1$s size of %2$s files', $opcache->dcfiles, 'docket-cache')), $this->normalize_size($opcache->dcsize), $opcache->dcfiles);

                        /* translators: %1$s = size, %2$s number of file */
                        $opcache_wp_stats = sprintf(esc_html__(_n('%1$s size of %2$s file', '%1$s size of %2$s files', $opcache->wpfiles, 'docket-cache')), $this->normalize_size($opcache->wpsize), $opcache->wpfiles);
                    }
                } else {
                    $opcache_text = $status_code[1].' (<a href="https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.file-cache-only" rel="noopener" target="new">'.esc_html__('File cache only', 'docket-cache').'</a>)';
                }

                break;
            default:
                $opcache_text = $status_code[2];
        }

        $log_enable = $this->cf()->is_dctrue('LOG') ? 1 : 0;
        $log_file = $this->cf()->dcvalue('LOG_FILE');

        if (is_multisite()) {
            $log_file = nwdcx_network_filepath($log_file);
        }

        $multisite_text = $status_code[3];
        $multinets_lock = '';

        if (is_multisite()) {
            $netcount = get_networks(['count' => 1]);
            $this->get_network_sites($sitecount, true);

            /* translators: %s = sites */
            $multisite_text = sprintf(esc_html__(_n('%s Site', '%s Sites', $sitecount, 'docket-cache')), $sitecount);

            if ($netcount > 1) {
                /* translators: %s = networks */
                $multisite_text = $multisite_text.' '.sprintf(esc_html__(_n('of %s Network', 'of %s Networks', $netcount, 'docket-cache')), $netcount);

                $multinets_lock = $this->sanitize_rootpath($this->cx()->multinet_tag());
            }
        }

        $file_dropin = $this->cx()->resc()->dst;
        if (@is_file($file_dropin)) {
            $write_dropin = @is_writable($file_dropin);
        } else {
            $write_dropin = @is_writable($this->cx()->condir.'/');
        }

        $file_dropin_wp = $this->cx()->resc()->wpdst;
        $dropin_wp_exist = false;

        $is_dropin_alternative = $this->cx()->is_alternative();
        if ($is_dropin_alternative) {
            $dropin_wp_exist = @is_file($file_dropin_wp) || @is_link($file_dropin_wp);
        }

        $file_max = $this->get_cache_maxfile();
        $disk_max = $this->normalize_size($this->get_cache_maxsize_disk());

        $file_stats = $file_max;
        $disk_stats = $disk_max;

        if (isset($cache_stats->files) && !empty($cache_stats->files)) {
            $file_stats = $cache_stats->files.' / '.$file_max;
        }

        if (isset($cache_stats->filesize) && !empty($cache_stats->filesize)) {
            $disk_stats = $this->normalize_size($cache_stats->filesize).' / '.$disk_max;
        }

        return [
            'status_code' => $status,
            'status_text' => $status_text,
            'status_text_stats' => $status_text_stats,
            'opcache_code' => $opcache->status,
            'opcache_text' => $opcache_text,
            'opcache_text_stats' => $opcache_text_stats,
            'opcache_dc_stats' => $opcache_dc_stats,
            'opcache_wp_stats' => $opcache_wp_stats,
            'php_memory_limit' => $this->normalize_size(@\ini_get('memory_limit')),
            'wp_memory_limit' => $this->normalize_size(WP_MEMORY_LIMIT),
            'wp_max_memory_limit' => $this->normalize_size(WP_MAX_MEMORY_LIMIT),
            'write_dropin' => $yesno[$write_dropin],
            'dropin_path' => $this->sanitize_rootpath($file_dropin),
            'dropin_isalt' => $is_dropin_alternative,
            'dropin_alt' => $yesno[$is_dropin_alternative],
            'dropin_wp' => $this->sanitize_rootpath($file_dropin_wp),
            'dropin_wp_isexist' => $dropin_wp_exist,
            'dropin_wp_exist' => $yesno[$dropin_wp_exist],
            'write_cache' => $yesno[is_writable($this->cache_path)],
            'cache_chunkdir' => $yesno[$this->cf()->dcvalue('CHUNKCACHEDIR')],
            'cache_size' => $this->normalize_size($cache_stats->size),
            'cache_path_real' => $this->cache_path,
            'cache_path' => $this->sanitize_rootpath($this->cache_path),
            'cache_maxfile' => $file_max,
            'cache_file_stats' => $file_stats,
            'cache_maxsize_disk' => $this->normalize_size($this->get_cache_maxsize_disk()),
            'cache_disk_stats' => $disk_stats,
            'log_file_real' => $log_file,
            'log_file' => $this->sanitize_rootpath($log_file),
            'log_enable' => $log_enable,
            'log_enable_text' => $status_code[$log_enable],
            'config_path' => $this->sanitize_rootpath($this->co()->path),
            'write_config' => $yesno[$this->co()->is_options_writable()],
            'wp_multisite' => $multisite_text,
            'wp_multinetlock' => $multinets_lock,
            'wp_multinetmain' => $yesno[is_main_network()],
        ];
    }

    /**
     * sanitize_rootpath.
     */
    public function sanitize_rootpath($path)
    {
        $wp_content_dir = wp_normalize_path(WP_CONTENT_DIR);
        $abspath = wp_normalize_path(ABSPATH);

        return rtrim(str_replace([$wp_content_dir, $abspath], ['/'.basename($wp_content_dir), '/'], $path), '/');
    }

    /**
     * get_status.
     */
    public function get_status()
    {
        if ($this->cf()->is_dctrue('DISABLED')) {
            return 2;
        }

        if (!$this->cx()->exists()) {
            return 0;
        }

        if ($this->cx()->validate() && $this->cx()->multinet_me()) {
            if ($this->cf()->is_dctrue('OBJECTCACHEOFF', true)) {
                $this->co()->save('objectcacheoff', 'default');
            }

            return 1;
        }

        if (!$this->cx()->multinet_me()) {
            return 0;
        }

        return 3;
    }

    /**
     * get_logsize.
     */
    public function get_logsize()
    {
        if ($this->has_log($logfile)) {
            return $this->normalize_size($this->filesize($logfile));
        }

        return 0;
    }

    /**
     * get_opcache_status.
     */
    public function get_opcache_status($is_raw = false)
    {
        $total_bytes = 0;
        $total_files = 0;
        $status = 0;

        $dcfiles = 0;
        $dcbytes = 0;

        $wpfiles = 0;
        $wpbytes = 0;

        $stale = 0;

        $data = [];
        if ($this->is_opcache_enable()) {
            if (!$this->opcache_function_exists('opcache_get_status')) {
                $status = 2;
            } else {
                $nwdcx_suppresserrors = nwdcx_suppresserrors(true);
                $data = opcache_get_status();
                nwdcx_suppresserrors($nwdcx_suppresserrors);

                if (!empty($data) && \is_array($data)) {
                    if (!empty($data['opcache_enabled'])) {
                        if ($is_raw) {
                            return $data;
                        }

                        $status = 1;

                        if (!empty($data['memory_usage']['used_memory'])) {
                            $total_bytes = $data['memory_usage']['used_memory'];
                        }
                        if (!empty($data['opcache_statistics']['num_cached_scripts'])) {
                            $total_files = $data['opcache_statistics']['num_cached_scripts'];
                        }

                        if (!empty($data['scripts']) && \is_array($data['scripts'])) {
                            foreach ($data['scripts'] as $script => $arr) {
                                $cpath = $arr['full_path'];
                                if (!@is_file($cpath)) {
                                    ++$stale;
                                }
                                $cfile = basename($cpath);
                                $cdir = \dirname($cpath);
                                if (false !== strpos($script, $this->cache_path) && $this->is_docketcachedir($cdir) && @preg_match('@^([a-z0-9]{12})\-([a-z0-9]{12})\.php$@', $cfile)) {
                                    ++$dcfiles;
                                    if (isset($arr['memory_consumption'])) {
                                        $dcbytes += $arr['memory_consumption'];
                                    }
                                } else {
                                    ++$wpfiles;
                                    if (isset($arr['memory_consumption'])) {
                                        $wpbytes += $arr['memory_consumption'];
                                    }
                                }
                            }
                        }
                    } elseif (!empty($data['file_cache_only'])) {
                        $status = 3;

                        if (!empty($data['file_cache']) && is_dir($data['file_cache']) && is_readable($data['file_cache'])) {
                            $dir = nwdcx_normalizepath(realpath($data['file_cache']));
                            $cnt = 0;

                            // dummy
                            $cdata = [
                                'opcache_statistics' => [
                                    'num_cached_scripts' => 0,
                                ],
                                'scripts' => [],
                            ];

                            foreach ($this->opcache_filecache_scanfiles($dir) as $object) {
                                try {
                                    if (!$object->isFile()) {
                                        continue;
                                    }

                                    $cpath = nwdcx_normalizepath($object->getPathName());
                                    if (false === strpos($cpath, nwdcx_normalizepath(ABSPATH))) {
                                        continue;
                                    }

                                    $cfile = basename($cpath);
                                    $cdir = \dirname($cpath);
                                    $fs = $object->getSize();

                                    if (false !== strpos($cpath, $this->cache_path) && $this->is_docketcachedir($cdir) && @preg_match('@^([a-z0-9]{12})\-([a-z0-9]{12})\.php\.bin$@', $cfile)) {
                                        ++$dcfiles;
                                        $dcbytes += $fs;
                                    } else {
                                        ++$wpfiles;
                                        $wpbytes += $fs;
                                    }

                                    ++$cnt;

                                    $total_bytes += $fs;

                                    $cdata['scripts'][$cpath] = [
                                        'full_path' => $cpath,
                                        'memory_consumption' => $fs,
                                        'last_used_timestamp' => $object->getATime(),
                                        'hits' => 1,
                                    ];
                                } catch (\Throwable $e) {
                                    nwdcx_throwable(__METHOD__, $e);
                                    continue;
                                }
                            }

                            if ($cnt > 0) {
                                $status = 4;
                                $total_files = $cnt;
                            }
                        }

                        if ($is_raw) {
                            $cdata['opcache_statistics']['num_cached_scripts'] = $cnt;
                            $data = array_merge($data, $cdata);
                            $data['_numfile'] = $cnt;
                            $data['_sizefile'] = $total_bytes;

                            return $data;
                        }
                    }
                }
            }
        }

        $arr = [
            'status' => (int) $status,
            'size' => $total_bytes,
            'files' => (int) $total_files,
            'wpfiles' => (int) $wpfiles,
            'wpsize' => (int) $wpbytes,
            'dcfiles' => (int) $dcfiles,
            'dcsize' => (int) $dcbytes,
            'stale' => (int) $stale,
        ];

        return (object) $arr;
    }

    /**
     * get_cache_maxfile.
     */
    public function get_cache_maxfile()
    {
        $maxfile = $this->cf()->dcvalue('MAXFILE', true);

        return $this->sanitize_maxfile($maxfile);
    }

    /**
     * get_cache_maxttl.
     */
    public function get_cache_maxttl()
    {
        $maxttl = $this->cf()->dcvalue('MAXTTL');

        return $this->sanitize_maxttl($maxttl);
    }

    /**
     * get_cache_maxsize_disk.
     */
    public function get_cache_maxsize_disk()
    {
        $maxsizedisk = $this->cf()->dcvalue('MAXSIZE_DISK');

        return $this->sanitize_maxsizedisk($maxsizedisk);
    }

    /**
     * get_precache_maxfile.
     */
    public function get_precache_maxfile()
    {
        if ($this->cf()->is_dcfalse('PRECACHE')) {
            return 0;
        }

        $maxfile = $this->cf()->dcvalue('PRECACHE_MAXFILE', true);

        return $this->sanitize_precache_maxfile($maxfile);
    }

    /**
     * get_cache_stats.
     */
    public function get_cache_stats($force = false)
    {
        $cache_stats = false;

        if ($this->cf()->is_dctrue('STATS')) {
            if ($force) {
                $cache_stats = $this->cache_size($this->cache_path);
                $this->co()->save_part($cache_stats, 'cachestats');
            } else {
                $cache_stats = $this->co()->get_part('cachestats');
            }
        }

        if (empty($cache_stats) || !\is_array($cache_stats)) {
            $cache_stats = [
                'size' => 0,
                'filesize' => 0,
                'files' => 0,
            ];
        }

        return (object) $cache_stats;
    }

    /**
     * normalize_size.
     */
    public function normalize_size($size, $showb = true)
    {
        $size = wp_convert_hr_to_bytes($size);
        $size = str_replace([',', ' ', 'B'], '', size_format($size));
        if ($showb && is_numeric($size)) {
            $size = $size.'B';
        }

        return $size;
    }

    public function site_url_scheme($site_url)
    {
        $site_url = trim($site_url);
        if ('https://' !== substr($site_url, 0, 8) && $this->is_ssl()) {
            $site_url = nwdcx_fixscheme($site_url, 'https://');
        } elseif (!@preg_match('@^(https?:)?//@', $site_url)) {
            $site_url = nwdcx_fixscheme($site_url, 'http://');
        }

        return rtrim($site_url, '/\\');
    }

    public function site_url($current = false, $is_home = false)
    {
        $option = $is_home ? 'home' : 'siteurl';
        $site_url = get_option($option);
        if (!$current && is_multisite()) {
            $blog_id = get_main_site_id();
            switch_to_blog($blog_id);
            $site_url = get_option($option);
            restore_current_blog();
        }

        return $this->site_url_scheme($site_url);
    }

    public function site_meta($short = false)
    {
        $m = '0,0';
        if (is_multisite()) {
            $n = get_networks(['count' => 1]);
            $s = get_sites(['count' => 1]);
            $m = $n.','.$s;
        }

        if ($short) {
            $meta = $m.','.$this->version();
            $meta = str_replace('0,0,', '', $meta);
            $meta = str_replace('0', '', $meta);
        } else {
            $meta = $m.','.$this->version().','.$GLOBALS['wp_version'];
        }

        return str_replace('.', '', $meta);
    }

    /**
     * flush_cache.
     */
    public function flush_cache($cleanup = false, &$is_timeout = false)
    {
        $this->co()->clear_part('cachestats');
        $this->cx()->delay();

        if (\function_exists('nwdcx_cleanuptransient')) {
            nwdcx_cleanuptransient();
        } else {
            delete_expired_transients(true);
        }

        $cnt = $this->cachedir_flush($this->cache_path, $cleanup, $is_timeout);
        if (false === $cnt) {
            $this->cx()->undelay();

            return $cnt;
        }

        $this->co()->clear_lock();

        return $cnt;
    }

    /**
     * flush_fcache.
     */
    public function flush_fcache(&$file = '')
    {
        if (!empty($_GET['idxv'])) {
            $fx = sanitize_text_field($_GET['idxv']);
            $file = $this->cache_path.$fx.'.php';
            if (@is_file($file)) {
                $this->co()->clear_part('cachestats');

                return $this->unlink($file, true);
            }
        }

        return true;
    }

    /**
     * has_log.
     */
    public function has_log(&$logfile = '')
    {
        $logfile = $this->cf()->dcvalue('LOG_FILE');

        if (is_multisite()) {
            $logfile = nwdcx_network_filepath($logfile);
        }

        return @is_file($logfile) && is_readable($logfile);
    }

    /**
     * flush_log.
     */
    public function flush_log()
    {
        if ($this->has_log($logfile)) {
            return @unlink($logfile);
        }

        return false;
    }

    public function switch_cron_site()
    {
        if (is_multisite()) {
            $cronbot_siteid = $this->get_cron_siteid();
            if (!empty($cronbot_siteid) && (int) $cronbot_siteid > 0) {
                switch_to_blog($cronbot_siteid);

                return true;
            }
        }

        return false;
    }

    public function delete_cron_siteid($userid = false)
    {
        if (empty($userid)) {
            $userid = get_current_user_id();
        }

        $key = 'cronbot-siteid-'.get_current_user_id();

        return $this->co()->lookup_delete($key);
    }

    public function set_cron_siteid($id)
    {
        $key = 'cronbot-siteid-'.get_current_user_id();

        return $this->co()->lookup_set($key, $id);
    }

    public function get_cron_siteid()
    {
        $key = 'cronbot-siteid-'.get_current_user_id();
        $siteid = $this->co()->lookup_get($key);
        if (empty($siteid)) {
            $siteid = is_multisite() ? get_main_site_id() : get_current_blog_id();
        }

        return $siteid;
    }

    public function cleanuppost()
    {
        if (!nwdcx_wpdb($wpdb)) {
            return false;
        }

        $sites = $this->get_network_sites();
        $is_multisite = is_multisite();

        $collect = [
            'revision' => 0,
            'autodraft' => 0,
            'trashbin' => 0,
        ];

        $siteid = 0;
        if ($is_multisite) {
            $collect['site'] = \count($sites);

            if (isset($_GET['siteid'])) {
                $siteid = (int) sanitize_text_field($_GET['siteid']);
                $this->set_current_select_siteid($siteid);
            }
        }

        $max_execution_time = $this->get_max_execution_time();
        $suppress = $wpdb->suppress_errors(true);
        $doflush = false;
        foreach ($sites as $num => $site) {
            if ($is_multisite) {
                if (!empty($siteid) && $siteid !== (int) $site['id']) {
                    continue;
                }

                switch_to_blog($site['id']);
            }

            $query = $wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_type = %s ORDER BY ID ASC LIMIT 1000", 'revision'));
            if ($query) {
                foreach ($query as $id) {
                    $id = (int) $id;
                    wp_delete_post_revision($id);
                    $doflush = true;
                }
                $collect['revision'] += \count($query);
            }

            $query = $wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_status = %s ORDER BY ID ASC LIMIT 1000", 'auto-draft'));
            if ($query) {
                foreach ($query as $id) {
                    $id = (int) $id;
                    wp_delete_post($id, true);
                    $doflush = true;
                }
                $collect['autodraft'] += \count($query);
            }

            $query = $wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_status = %s ORDER BY ID ASC LIMIT 1000", 'trash'));
            if ($query) {
                foreach ($query as $id) {
                    $id = (int) $id;
                    wp_delete_post($id, true);
                    $doflush = true;
                }
                $collect['trashbin'] += \count($query);
            }

            if ($is_multisite) {
                restore_current_blog();
            }

            if ($max_execution_time > 0 && \defined('WP_START_TIMESTAMP') && (microtime(true) - WP_START_TIMESTAMP) > $max_execution_time) {
                $is_timeout = true;
                break;
            }
        }

        $wpdb->suppress_errors($suppress);

        if ($doflush) {
            $this->flush_cache(false);
        }

        return (object) $collect;
    }

    public function delete_current_select_siteid($userid = false)
    {
        if (empty($userid)) {
            $userid = get_current_user_id();
        }

        $key = 'current-select-siteid-'.get_current_user_id();

        return $this->co()->lookup_delete($key);
    }

    public function get_current_select_siteid()
    {
        $key = 'current-select-siteid-'.get_current_user_id();

        return (int) $this->co()->lookup_get($key);
    }

    public function set_current_select_siteid($id)
    {
        $key = 'current-select-siteid-'.get_current_user_id();

        return $this->co()->lookup_set($key, $id);
    }

    /**
     * compat_notice.
     */
    private function compat_notice()
    {
        if (!(\PHP_VERSION_ID >= 70205)) {
            $text = __('Docket Cache plugin requires PHP 7.2.5 or greater.', 'docket-cache');

            add_action(
                'all_admin_notices',
                function () use ($text) {
                    echo '<div id="docket-cache-notice" class="notice notice-warning is-dismissible"><p>'.$text.'</p></div>';
                    deactivate_plugins($this->hook);
                    wp_cache_flush();
                },
                \PHP_INT_MIN
            );

            if (\defined('WP_CLI') && WP_CLI) {
                if (!\function_exists('deactivate_plugins')) {
                    include_once ABSPATH.'/wp-admin/includes/plugin.php';
                }

                if (\function_exists('deactivate_plugins')) {
                    deactivate_plugins($this->hook);
                    wp_cache_flush();

                    \WP_CLI::error($text, false);
                    \WP_CLI::halt(1);
                }
            }

            return false;
        }

        return true;
    }

    /**
     * cleanup.
     */
    private function deactivate_cleanup($is_uninstall = false)
    {
        WpConfig::unlink_runtime();

        if ($this->cx()->validate()) {
            $this->cx()->uninstall();
        }

        $this->cx()->undelay();

        if ($this->cf()->is_dctrue('FLUSH_SHUTDOWN', true)) {
            $this->cachedir_flush($this->cache_path, true);
        }

        $this->flush_log();

        if ($is_uninstall) {
            WpConfig::runtime_remove();

            // reset on/off button
            $this->co()->save('objectcacheoff', 'default');

            // stats
            $this->co()->clear_part('cachestats');

            // cronbot/etc
            $this->co()->save('cronbot', 'default');
            $this->co()->clear_part('cronbot');
            $this->co()->clear_part('pings');
            $this->co()->clear_part('checkversion');

            // clear all network if available
            if (is_multisite()) {
                $this->cx()->multinet_clear($this->cache_path, $this->cf()->dcvalue('LOG_FILE'));
            }
        }

        if ($this->cf()->is_dctrue('OPCSHUTDOWN', true)) {
            $this->opcache_cleanup();
        }

        $this->co()->clear_lock();
    }

    /**
     * uninstall.
     */
    public static function uninstall()
    {
        ( new self() )->deactivate_cleanup(true);
    }

    /**
     * deactivate.
     */
    public function deactivate()
    {
        $this->deactivate_cleanup();
        $this->unregister_cronjob();
    }

    /**
     * activate.
     */
    public function activate()
    {
        if (!$this->compat_notice()) {
            return;
        }

        $this->flush_cache(false);

        if ($this->cf()->is_dcfalse('OBJECTCACHEOFF', true)) {
            $this->cx()->install(true);
        }

        $this->unregister_cronjob();
    }

    /**
     * register_init.
     */
    private function register_init()
    {
        // unofficial constant: possible to disable nag notices
        !\defined('DISABLE_NAG_NOTICES') && \define('DISABLE_NAG_NOTICES', true);

        $this->page = 'admin.php?page='.$this->slug;
        $this->screen = 'toplevel_page_docket-cache';
        $this->cache_path = $this->define_cache_path($this->cf()->dcvalue('PATH'));

        if (is_multisite()) {
            $this->cache_path = nwdcx_network_dirpath($this->cache_path);
        }

        $this->api_endpoint = 'https://api.docketcache.com';
        $this->cronbot_endpoint = 'https://cronbot.docketcache.com';

        // use Constans() to trigger default
        if ($this->cf()->is_dctrue('DEV')) {
            $this->api_endpoint = 'http://api.docketcache.local';
            $this->cronbot_endpoint = 'http://cronbot.docketcache.local';
        }

        $this->token = '';
        $this->notice = '';
        $this->inruntime = false;

        /*add_filter(
            'perflab_oc_site_status_available_object_cache_services',
            function ($services) {
                $services[] = 'docket-cache';

                return $services;
            },
            \PHP_INT_MAX
        );*/

        add_filter('perflab_disable_object_cache_dropin', '__return_true');
    }

    /**
     * critical_version.
     */
    private function critical_version()
    {
        $checkdata = $this->co()->get_part('checkversion', true);
        if (!empty($checkdata) && \is_array($checkdata) && !empty($checkdata['doversion'])) {
            $current_version = $this->plugin_meta($this->file)['Version'];
            if (0 === strcmp($checkdata['doversion'], $current_version)) {
                $this->flush_cache(true);
            }
        }
        unset($checkdata);

        return true;
    }

    /**
     * plugin_upgrade.
     */
    private function plugin_upgrade()
    {
        add_action(
            'shutdown',
            function () {
                if ($this->cf()->is_dcfalse('OBJECTCACHEOFF', true)) {
                    $this->cx()->install(true);
                    if (is_multisite()) {
                        $this->cx()->multinet_install($this->hook);
                    }
                }

                // put last
                $this->critical_version();
            },
            \PHP_INT_MAX
        );
    }

    private function toggle_auto_update($toggle = false)
    {
        $auto_updates = (array) get_site_option('auto_update_plugins', []);
        if (true === $toggle) {
            $auto_updates[] = $this->hook;

            return update_site_option('auto_update_plugins', array_unique($auto_updates));
        }

        return update_site_option('auto_update_plugins', array_diff($auto_updates, [$this->hook]));
    }

    /**
     * register_plugin_hooks.
     */
    private function register_plugin_hooks()
    {
        add_action(
            'init',
            function () {
                load_plugin_textdomain(
                    'docket-cache',
                    false,
                    $this->path.'/languages/'
                );
            },
            0
        );

        add_action(
            'upgrader_process_complete',
            function ($wp_upgrader, $options) {
                if ('update' !== $options['action']) {
                    return;
                }

                if ('plugin' === $options['type'] && !empty($options['plugins'])) {
                    if (!\is_array($options['plugins'])) {
                        return;
                    }

                    foreach ($options['plugins'] as $plugin) {
                        if ($plugin === $this->hook) {
                            $this->plugin_upgrade();
                            break;
                        }
                    }
                }
            },
            \PHP_INT_MAX,
            2
        );

        // wp 5.5 >=
        if (\function_exists('wp_is_maintenance_mode')) {
            add_action(
                'upgrader_overwrote_package',
                function ($package, $package_data, $package_type = 'plugin') {
                    if (!empty($package_data) && \is_array($package_data) && !empty($package_data['TextDomain']) && $this->slug === $package_data['TextDomain']) {
                        $this->plugin_upgrade();
                    }
                },
                \PHP_INT_MAX,
                3
            );
        }

        add_action(
            'admin_footer',
            function () {
                $output = $this->cx()->after_delay();
                if (!empty($output)) {
                    echo $output;
                }
            },
            \PHP_INT_MAX
        );

        if (!is_admin() && $this->cf()->is_dctrue('SIGNATURE')) {
            add_action(
                'send_headers',
                function () {
                    $status = $this->cx()->validate() ? 'on' : 'off';
                    header('x-'.$this->slug.': '.$status.'; '.$this->site_meta(true));
                },
                \PHP_INT_MAX
            );
        }

        if (!empty($_SERVER['REQUEST_URI']) && false !== strpos($_SERVER['REQUEST_URI'], '/admin.php?page=docket-cache')) {
            add_action(
                'plugins_loaded',
                function () {
                    if (!headers_sent() && !empty($_SERVER['REQUEST_URI'])) {
                        if ($this->cf()->is_dctrue('LOG')) {
                            $req = $_SERVER['REQUEST_URI'];
                            if ((false !== strpos($req, '?page=docket-cache&idx=log&dl=0') || false !== strpos($req, '?page=docket-cache-log&idx=log&dl=0'))
                                && preg_match('@log\&dl=\d+$@', $req)) {
                                $file = $this->cf()->dcvalue('LOG_FILE');

                                if (is_multisite()) {
                                    $file = nwdcx_network_filepath($file);
                                }

                                @header('Cache-Control: no-cache, no-store, must-revalidate, max-age=0');
                                @header('Content-Type: text/plain; charset=UTF-8');
                                if (@is_file($file) && @is_readable($file)) {
                                    if (@readfile($file) > 0) {
                                        $this->close_exit();
                                    }
                                }

                                $this->close_exit(__('The log is empty. No data is available.', 'docket-cache'));
                            }
                        }

                        if ($this->cf()->is_true('WP_DEBUG') && $this->cf()->is_true('WP_DEBUG_LOG')) {
                            $req = $_SERVER['REQUEST_URI'];
                            if ((false !== strpos($req, '?page=docket-cache&idx=config&wplog=0') || false !== strpos($req, '?page=docket-cache-config&idx=config&wplog=0'))
                                && preg_match('@config\&wplog=\d+(\&dd=\d+)?$@', $req)) {
                                $file = \ini_get('error_log');

                                @header('Cache-Control: no-cache, no-store, must-revalidate, max-age=0');
                                @header('Content-Type: text/plain; charset=UTF-8');
                                if (@is_file($file) && @is_readable($file)) {
                                    if ($this->cf()->is_dctrue('TRYREADWPDEBUGLOG') || !empty($_GET['dd']) && 1 === (int) $_GET['dd']) {
                                        $log = file_get_contents($file);
                                        if (!empty($log)) {
                                            $log = str_replace(['undefined function', 'Stack trace'], ['undefined-function', 'Stack-trace'], $log);
                                        }
                                        $this->close_exit($log);
                                    }

                                    if (@readfile($file) > 0) {
                                        $this->close_exit();
                                    }
                                }

                                $this->close_exit(__('The log is empty. No data is available.', 'docket-cache'));
                            }
                        }
                    }
                },
                \PHP_INT_MIN
            );
        }

        // low priority
        add_action(
            'plugins_loaded',
            function () {
                if (nwdcx_wpdb($wpdb)) {
                    if ($this->co()->lockexp('sqlbigselect')) {
                        return;
                    }

                    $suppress = $wpdb->suppress_errors(true);
                    $ok = $wpdb->get_var('SELECT @@SESSION.SQL_BIG_SELECTS LIMIT 1');
                    if (empty($ok)) {
                        $wpdb->query('SET SESSION SQL_BIG_SELECTS=1');
                    } else {
                        // already big select, lock 28d
                        $locktime = time() + 2419200;
                        $this->co()->setlock('sqlbigselect', $locktime);
                    }

                    $wpdb->suppress_errors($suppress);
                }
            },
            \PHP_INT_MIN
        );

        add_action(
            'plugins_loaded',
            function () {
                $dc_option = $this->co()->get('DOCKET_CACHE_AUTOUPDATE');
                if (!empty($dc_option)) {
                    $cache_hash_group = substr(md5('options'), 0, 12);
                    $cache_hash_key = substr(md5('auto_update_plugins'), 0, 12);
                    if (is_multisite()) {
                        $cache_hash_group = substr(md5('site-options'), 0, 12);
                        $cache_hash_key = substr(md5(get_current_network_id().':auto_update_plugins'), 0, 12);
                    }

                    $file_cache = $this->cache_path.$cache_hash_group.'-'.$cache_hash_key.'.php';
                    if (is_file($file_cache)) {
                        @unlink($file_cache);
                    }

                    clearstatcache();

                    if ('enable' === $dc_option) {
                        $this->co()->save('autoupdate_toggle', 'enable');
                    } elseif ('disable' === $dc_option) {
                        $this->co()->save('autoupdate_toggle', 'disable');
                    }

                    $this->co()->save('AUTOUPDATE', false);
                }
            },
            \PHP_INT_MAX
        );

        add_action(
            'update_site_option',
            function ($option, $auto_updates, $old_auto_updates, $network_id) {
                if ('auto_update_plugins' === $option) {
                    if (\in_array($this->hook, (array) $auto_updates, true) && !\in_array($this->hook, (array) $old_auto_updates, true)) {
                        $this->co()->save('autoupdate_toggle', 'enable', false);

                        return;
                    }

                    if (\in_array($this->hook, (array) $old_auto_updates, true) && !\in_array($this->hook, (array) $auto_updates, true)) {
                        $this->co()->save('autoupdate_toggle', 'disable', false);

                        return;
                    }

                    return;
                }
            },
            \PHP_INT_MAX,
            4
        );

        // fix index.
        add_filter(
            'pre_update_site_option_auto_update_plugins',
            function ($value, $old_value, $option, $network_id) {
                if (\is_array($value) && !empty($value)) {
                    return array_values($value);
                }

                return $value;
            },
            10,
            4
        );

        add_filter(
            'auto_update_plugin',
            function ($update, $item) {
                if (\is_object($item) && isset($item->slug) && 'docket-cache' === $item->slug) {
                    if (\defined('DOCKET_CACHE_AUTOUPDATE') && \is_bool(DOCKET_CACHE_AUTOUPDATE)) {
                        return DOCKET_CACHE_AUTOUPDATE;
                    }
                }

                return $update;
            },
            \PHP_INT_MAX,
            2
        );

        if ($this->cf()->is_dctrue('CRONBOT') && class_exists('Nawawi\\DocketCache\\CronAgent')) {
            ( new CronAgent($this) )->register();
        }

        register_activation_hook($this->hook, [$this, 'activate']);
        register_deactivation_hook($this->hook, [$this, 'deactivate']);
        register_uninstall_hook($this->hook, [__CLASS__, 'uninstall']);
    }

    /**
     * action_query.
     */
    public function action_query($key, $args_extra = [])
    {
        $key = str_replace('docket-', '', $key);
        $key = 'docket-'.$key;

        $args = array_merge(
            [
                'action' => $key,
            ],
            $args_extra
        );

        // last
        $args['st'] = time();

        $page = $this->page;
        if (!empty($args['idx']) && $this->is_subpage($args['idx'])) {
            $page = $page.'-'.$args['idx'];
        }

        $query = add_query_arg($args, $page);

        return wp_nonce_url(network_admin_url($query), $key);
    }

    /**
     * action_field. Use at addons.
     */
    public function action_field($key, $args = [])
    {
        $key = str_replace('docket-', '', $key);
        $key = 'docket-'.$key;

        $field = wp_nonce_field($key, '_wpnonce', false, false);
        $field .= '<input type="hidden" name="action" value="'.$key.'">';
        if (!empty($args) && \is_array($args)) {
            foreach ($args as $n => $v) {
                if ('page' === $n) {
                    $v = 'docket-cache-'.$v;
                }
                $field .= '<input type="hidden" name="'.$n.'" value="'.$v.'">';
            }
        }

        return $field;
    }

    /**
     * is_subpage.
     */
    public function is_subpage($index)
    {
        if ('mods' === substr($index, 0, 4)) {
            return true;
        }

        $subpage = [
            'config' => 1,
            'log' => 1,
            'cronbot' => 1,
            'opcviewer' => 1,
        ];

        return \array_key_exists($index, $subpage);
    }

    /**
     * get_subpage.
     */
    public function get_subpage()
    {
        if (!empty($_GET['page'])) {
            if ('docket-cache-' === substr($_GET['page'], 0, 13)) {
                $index = substr($_GET['page'], 13);
                if (!empty($index) && $this->is_subpage($index)) {
                    return $index;
                }
            } elseif ('docket-cache' === $_GET['page'] && !empty($_GET['idx']) && 'mods' === substr($_GET['idx'], 0, 4)) {
                return $_GET['idx'];
            }
        }

        return false;
    }

    /**
     * get_screen.
     */
    public function get_screen()
    {
        $screen = $this->screen;
        $index = $this->get_subpage();
        if (!empty($index)) {
            $screen = $this->slug.'_page_'.$this->slug.'-'.$index;
        }

        return $screen;
    }

    /**
     * get_page.
     */
    public function get_page($args = [])
    {
        $page = $this->page;
        $index = $this->get_subpage();
        if (!empty($index)) {
            $page = $page.'-'.$index;
        }

        if (!empty($args) && \is_array($args)) {
            $query = http_build_query($args);
            if (false !== strpos($page, '?')) {
                $page = rtrim($page, '&').'&'.$query;
            } else {
                $page = $page.'?'.$query;
            }
        }

        return $page;
    }

    /**
     * our_screen.
     */
    public function our_screen()
    {
        $current_screen = get_current_screen()->id;
        if (substr($current_screen, 0, \strlen($this->screen)) === $this->screen) {
            return true;
        }

        $subsplug = $this->slug.'_page_'.$this->slug.'-';
        if (substr($current_screen, 0, \strlen($subsplug)) === $subsplug) {
            return true;
        }

        return false;
    }

    /**
     * register_admin_hooks.
     */
    private function register_admin_hooks()
    {
        $action_name = is_multisite() ? 'network_admin_menu' : 'admin_menu';
        add_action(
            $action_name,
            function () {
                $cap = is_multisite() ? 'manage_network_options' : 'manage_options';
                $order = is_multisite() ? '25.1' : '80.1';
                $view = new View($this);

                add_menu_page(
                    'Docket Cache',
                    'Docket Cache',
                    $cap,
                    $this->slug,
                    [$view, 'index'],
                    Resc::iconmenu(),
                    $order
                );

                $title = esc_html__('Overview', 'docket-cache');
                add_submenu_page(
                    $this->slug,
                    $title,
                    $title,
                    $cap,
                    $this->slug,
                    [$view, 'index']
                );

                if ($this->cf()->is_dctrue('CRONBOT')) {
                    $title = esc_html__('Cronbot', 'docket-cache');
                    add_submenu_page(
                        $this->slug,
                        $title,
                        $title,
                        $cap,
                        $this->slug.'-cronbot',
                        [$view, 'index']
                    );
                }

                if ($this->cf()->is_dctrue('OPCVIEWER')) {
                    $title = esc_html__('OPcache', 'docket-cache');
                    add_submenu_page(
                        $this->slug,
                        $title,
                        $title,
                        $cap,
                        $this->slug.'-opcviewer',
                        [$view, 'index']
                    );
                }

                do_action('docketcache/view/submenubefore', $this->slug, $cap, $view);

                if ($this->cf()->is_dctrue('LOG')) {
                    $title = esc_html__('Cache Log', 'docket-cache');
                    add_submenu_page(
                        $this->slug,
                        $title,
                        $title,
                        $cap,
                        $this->slug.'-log',
                        [$view, 'index']
                    );
                }

                $title = esc_html__('Configuration', 'docket-cache');
                add_submenu_page(
                    $this->slug,
                    $title,
                    $title,
                    $cap,
                    $this->slug.'-config',
                    [$view, 'index']
                );

                do_action('docketcache/view/submenuafter', $this->slug, $cap, $view);
            }
        );

        add_action(
            'admin_bar_menu',
            function ($admin_bar) {
                if (!is_multisite() || !current_user_can('manage_network_options')) {
                    return;
                }

                $admin_bar->add_menu(
                    [
                        'id' => 'network-admin-docketcache',
                        'parent' => 'network-admin',
                        'group' => null,
                        'title' => 'Docket Cache',
                        'href' => network_admin_url($this->page),
                        'meta' => [
                            'title' => 'Docket Cache',
                        ],
                    ]
                );

                if (nwdcx_network_multi()) {
                    $networks = get_networks();
                    if (!empty($networks) && \is_array($networks)) {
                        foreach ($networks as $network) {
                            $id = $network->id;
                            $url = $this->site_url_scheme('http://'.$network->domain.$network->path);
                            $admin_bar->add_menu(
                                [
                                    'id' => 'network-admin-docketcache-'.$id,
                                    'parent' => 'network-admin-'.$id,
                                    'group' => null,
                                    'title' => 'Docket Cache',
                                    'href' => $url.'/wp-admin/network/'.$this->page,
                                    'meta' => [
                                        'title' => 'Docket Cache',
                                    ],
                                ]
                            );
                        }
                    }
                }
            },
            \PHP_INT_MAX
        );

        add_action(
            'in_admin_header',
            function () {
                if ($this->our_screen()) {
                    remove_all_actions('admin_notices');
                    remove_all_actions('all_admin_notices');
                }

                add_action(
                    'all_admin_notices',
                    function () {
                        if (!current_user_can(is_multisite() ? 'manage_network_options' : 'manage_options')) {
                            return;
                        }

                        if (!$this->our_screen() && false === strpos($_SERVER['REQUEST_URI'], '/plugins.php') && false === strpos($_SERVER['REQUEST_URI'], '/update-core.php')) {
                            return;
                        }

                        if ($this->cx()->exists()) {
                            $url = $this->action_query('update-dropino');
                            $urld = $this->action_query('dismiss-dropino');

                            if ($this->cx()->validate()) {
                                if ($this->cx()->is_outdated() && !$this->cx()->install(true)) {
                                    /* translators: %s: url */
                                    $message = sprintf(__('The object-cache.php Drop-In is outdated. Please click <strong>Re-Install</strong> to update it now. <br><br><a href="%s" style="min-width:100px;text-align:center;font-wight:bold;" class="button button-primary">Re-Install</a>', 'docket-cache'), $url);
                                }
                            } else {
                                /* translators: %1$s: url install, %2$s = url dismiss */
                                $message = $this->cf()->is_dctrue('OBJECTCACHEOFF', true) ? '' : sprintf(__('An unknown object-cache.php Drop-In was found. Please click <strong>Install</strong> to use <strong>Docket Cache</strong>. <br><br><a href="%1$s" style="min-width:100px;text-align:center;font-weight:bold;" class="button button-primary button-small">Install</a>&nbsp;<a href="%2$s" style="min-width:100px;text-align:center;font-weight:bold;" class="button button-secondary button-small">Dismiss</a>', 'docket-cache'), $url, $urld);
                            }
                        }

                        if (2 === $this->get_status() && $this->our_screen()) {
                            $message = esc_html__('The Object Cache feature has been disabled at runtime.', 'docket-cache');
                        }

                        if (isset($message)) {
                            echo Resc::boxmsg($message, 'warning', false, false, false);
                        }
                    },
                    \PHP_INT_MAX
                );
            },
            \PHP_INT_MAX
        );

        add_action(
            'admin_enqueue_scripts',
            function ($hook) {
                $is_debug = $this->cf()->is_true('WP_DEBUG');
                $plugin_url = plugin_dir_url($this->file);
                $version = str_replace('.', '', $this->version()).'xe'.($is_debug ? date('his') : date('yd'));
                wp_enqueue_script($this->slug.'-worker', $plugin_url.'includes/admin/worker.js', ['jquery'], $version, false);
                wp_localize_script(
                    $this->slug.'-worker',
                    'docket_cache_config',
                    [
                        'ajaxurl' => admin_url('admin-ajax.php'),
                        'token' => wp_create_nonce('docketcache-token-nonce'),
                        'slug' => $this->slug,
                        'debug' => $is_debug ? 'true' : 'false',
                    ]
                );

                if ($hook === $this->screen || $this->our_screen()) {
                    wp_enqueue_style($this->slug.'-core', $plugin_url.'includes/admin/docket.css', null, $version);
                    wp_enqueue_script($this->slug.'-core', $plugin_url.'includes/admin/docket.js', ['jquery'], $version, true);
                }

                if ($this->cf()->is_dctrue('PAGELOADER')) {
                    wp_enqueue_style($this->slug.'-loader', $plugin_url.'includes/admin/pageloader.css', null, $version);
                    wp_enqueue_script($this->slug.'-loader', $plugin_url.'includes/admin/pageloader.js', ['jquery'], $version, true);
                }
            }
        );

        add_filter(
            'script_loader_tag',
            function ($tag, $handle) {
                if (\in_array($handle, ['docket-cache-core', 'docket-cache-worker', 'docket-cache-loader'])) {
                    $tag = str_replace('<script ', '<script data-cfasync="false" data-noptimize="1" data-no-minify="1" ', $tag);
                }

                return $tag;
            },
            10,
            2
        );

        add_filter(
            'style_loader_tag',
            function ($tag, $handle, $href, $media) {
                if (\in_array($handle, ['docket-cache-core', 'docket-cache-loader'])) {
                    $tag = str_replace('<link ', '<link data-noptimize="1" data-no-minify="1" ', $tag);
                }

                return $tag;
            },
            10,
            4
        );
        // refresh user_meta: after logout
        add_action(
            'wp_logout',
            function () {
                add_action(
                    'shutdown',
                    function ($user_id) {
                        wp_cache_delete($user_id, 'user_meta');
                        $this->delete_cron_siteid($user_id);
                        $this->delete_current_select_siteid($user_id);
                    },
                    \PHP_INT_MAX
                );
            },
            \PHP_INT_MAX
        );

        add_action(
            'wp_ajax_docket_worker',
            function () {
                if (!check_ajax_referer('docketcache-token-nonce', 'token', false) && !isset($_POST['type'])) {
                    wp_send_json_error('Invalid security token sent.');
                    exit;
                }

                $type = sanitize_text_field($_POST['type']);

                if ($this->cx()->validate()) {
                    if ('preload' === $type) {
                        $this->send_json_continue($this->slug.':worker: pong '.$type);
                        $this->cx()->undelay();
                        do_action('docketcache/action/preload/objectcache');
                        exit;
                    }

                    if ('fetch' === $type) {
                        $this->send_json_continue($this->slug.':worker: pong '.$type);
                        @Crawler::fetch_home();
                        exit;
                    }

                    if ('countcachesize' === $type) {
                        do_action('docketcache/action/countcachesize');

                        $info = (object) $this->get_info();

                        $cache_stats = 1 === $info->status_code && !empty($info->status_text_stats) ? $info->status_text_stats : $info->status_text;
                        $opcache_stats = 1 === $info->opcache_code && !empty($info->opcache_text_stats) ? $info->opcache_text_stats : $info->opcache_text;
                        $opcache_dc_stats = !empty($info->opcache_dc_stats) ? $info->opcache_dc_stats : esc_html__('Not Available', 'docket-cache');
                        $opcache_wp_stats = !empty($info->opcache_wp_stats) ? $info->opcache_wp_stats : esc_html__('Not Available', 'docket-cache');

                        $response = [];
                        $response = ['success' => true];
                        $response['data'] = $this->slug.':worker: pong '.$type;

                        $stats = [];
                        $stats['obc'] = '0B' !== substr($cache_stats, 0, 2) ? $cache_stats : esc_html__('Not Available', 'docket-cache');
                        $stats['opc'] = $opcache_stats;
                        $stats['obcs'] = '0B' !== substr($info->status_text_stats, 0, 2) ? $info->status_text_stats : esc_html__('Not Available', 'docket-cache');
                        $stats['opcs'] = $info->opcache_text_stats;
                        $stats['opcdc'] = $opcache_dc_stats;
                        $stats['opcwp'] = $opcache_wp_stats;

                        $stats['ofile'] = $info->cache_file_stats;
                        $stats['odisk'] = $info->cache_disk_stats;

                        $response['cachestats'] = $stats;
                        wp_send_json($response);
                        exit;
                    }
                }

                if ('flush' === $type) {
                    $this->send_json_continue($this->slug.':worker: pong '.$type);
                    delete_expired_transients(true);
                    exit;
                }

                wp_send_json_error($this->slug.':worker: "'.$type.'" not available');
                exit;
            }
        );

        add_filter(
            'admin_footer_text',
            function ($text) {
                if ($this->our_screen()) {
                    $meta = $this->plugin_meta($this->file);
                    /* translators: %s: version */
                    $text = $meta['Name'].' '.sprintf(__('Version %s', 'docket-cache'), $meta['Version']);
                    $text = apply_filters('docketcache/filter/footerversion', $text);
                }

                return $text;
            },
            \PHP_INT_MAX
        );

        foreach (['update_footer', 'core_update_footer'] as $fn) {
            add_filter(
                $fn,
                function ($text) {
                    if ($this->our_screen()) {
                        /* translators: %s: version */
                        $text = 'WordPress '.' '.sprintf(__('Version %s', 'docket-cache'), $GLOBALS['wp_version']);
                    }

                    return $text;
                },
                \PHP_INT_MAX
            );
        }

        $filter_name = sprintf('%splugin_action_links_%s', is_multisite() ? 'network_admin_' : '', $this->hook);
        add_filter(
            $filter_name,
            function ($links) {
                $new = [
                    'docket-cache-overview' => sprintf('<a href="%s">%s</a>', network_admin_url($this->page), __('Overview', 'docket-cache')),
                    'docket-cache-configuration' => sprintf('<a href="%s">%s</a>', network_admin_url($this->page.'-config'), __('Configure', 'docket-cache')),
                ];

                return array_merge($new, $links);
            }
        );

        add_filter(
            'plugin_row_meta',
            function ($plugin_meta, $plugin_file) {
                if ($plugin_file === $this->hook) {
                    $row_meta = [
                        'docs' => '<a href="https://docs.docketcache.com/?utm_source=wp-plugins&utm_campaign=doc-uri&utm_medium=wp-dash" target="new" rel="noopener">'.__('Docs', 'docket-cache').'</a>',
                        'sponsor' => '<a href="https://docketcache.com/sponsorship/?utm_source=wp-plugins&utm_campaign=sponsor-uri&utm_medium=wp-dash" target="new" rel="noopener"><span class="dashicons dashicons-star-filled" aria-hidden="true" style="font-size:14px;line-height:1.3"></span>'.__('Sponsor', 'docket-cache').'</a>',
                    ];
                    $plugin_meta = array_merge($plugin_meta, $row_meta);
                }

                return $plugin_meta;
            },
            10,
            2
        );

        /*add_filter(
            'plugin_auto_update_setting_html',
            function ($html, $plugin_file, $plugin_data) {
                if ($plugin_file === $this->hook) {
                    $html .= sprintf('<p><a href="%s"><span class="label">%s</label></a></p>', network_admin_url($this->page.'-config&idx=config&nx=autoupdate'), __('Configure auto-updates', 'docket-cache'));
                }

                return $html;
            },
            10,
            3
        );*/

        // reference: Canopt::save()
        add_action(
            'docketcache/action/saveoption',
            function ($name, $value, $status = true) {
                switch ($name) {
                    case 'log':
                        if (true === $status) {
                            $this->flush_log();
                        }
                        if ('enable' === $value) {
                            @Crawler::fetch_home();
                        }
                        break;
                    case 'wpoptaload':
                        add_action(
                            'shutdown',
                            function () {
                                if (\function_exists('wp_cache_flush_group') && method_exists('WP_Object_Cache', 'dc_remove_group')) {
                                    wp_cache_flush_group(['options', 'site-options', 'docketcache-precache', 'docketcache-precache-gc']);
                                }
                            },
                            \PHP_INT_MAX
                        );

                        break;
                    case 'cronoptmzdb':
                        $this->unregister_cronjob();
                        break;
                    case 'cronbot':
                        $action = 'enable' === $value ? true : false;
                        add_action(
                            'shutdown',
                            function () use ($action) {
                                if (!$action) {
                                    apply_filters('docketcache/filter/active/cronbot', $action);
                                }
                            },
                            \PHP_INT_MAX
                        );
                        break;
                    case 'rtwpdebug':
                    case 'rtwpdebuglog':
                        $error_log = \ini_get('error_log');
                        if ('off' === $value && @is_file($error_log) && @is_writable($error_log)) {
                            @unlink($error_log);
                            clearstatcache();
                        }
                        break;
                    case 'menucache':
                        if (\function_exists('wp_cache_flush_group') && method_exists('WP_Object_Cache', 'dc_remove_group')) {
                            wp_cache_flush_group('docketcache-menu');
                        }
                        break;
                    case 'autoupdate_toggle':
                        if ('enable' === $value) {
                            $this->toggle_auto_update(true);
                        } else {
                            $this->toggle_auto_update(false);
                        }
                        break;
                    case 'transientdb':
                        add_action(
                            'shutdown',
                            function () {
                                if (\function_exists('wp_cache_flush_group') && method_exists('WP_Object_Cache', 'dc_remove_group')) {
                                    wp_cache_flush_group(['transient', 'site-transient', 'options', 'site-options']);
                                }

                                if (\function_exists('nwdcx_cleanuptransient')) {
                                    nwdcx_cleanuptransient();
                                }
                            },
                            \PHP_INT_MAX
                        );
                        break;
                }

                if (WpConfig::is_runtimeconst($name)) {
                    WpConfig::write_runtime();
                }
            },
            -1,
            3
        );

        add_action(
            'docketcache/action/preload/objectcache',
            function () {
                if ($this->cf()->is_dctrue('WPCLI')) {
                    return;
                }

                // lock opcache reset
                $this->co()->setlock('preload_lock_opcache_reset', time() + 20);

                // warmup: see Dropino::after_delay
                if ($this->cf()->is_dcfalse('PRELOAD', true)) {
                    add_action(
                        'shutdown',
                        function () {
                            if ($this->co()->lockproc('preload', time() + 3600)) {
                                return false;
                            }
                            // wp_load_alloptions();
                            wp_count_comments(0);
                            wp_count_posts();
                            @Crawler::fetch_home(['blocking' => true]);

                            $this->co()->lockreset('preload');
                        },
                        \PHP_INT_MAX
                    );

                    return;
                }

                // preload
                add_action(
                    'shutdown',
                    function () {
                        if ($this->co()->lockproc('preload', time() + 3600)) {
                            return false;
                        }

                        wp_load_alloptions();
                        wp_count_comments(0);
                        wp_count_posts();

                        @Crawler::fetch_home(['blocking' => true]);

                        $preload_admin = [
                            'index.php',
                            'options-general.php',
                            'options-writing.php',
                            'options-reading.php',
                            'options-discussion.php',
                            'options-media.php',
                            'options-permalink.php',
                            'edit-comments.php',
                            'profile.php',
                            'users.php',
                            'upload.php',
                            'plugins.php',
                            'edit.php',
                            'edit-tags.php?taxonomy=category',
                            'edit-tags.php?taxonomy=post_tag',
                            'edit.php?post_type=page',
                            'post-new.php?post_type=page',
                            'themes.php',
                            'widgets.php',
                            'nav-menus.php',
                            'tools.php',
                            'import.php',
                            'export.php',
                            'site-health.php',
                            'update-core.php',
                        ];

                        $preload_network = [
                            'index.php',
                            'update-core.php',
                            'sites.php',
                            'users.php',
                            'themes.php',
                            'plugins.php',
                            'settings.php',
                        ];

                        if ($this->cf()->is_dcarray('PRELOAD_ADMIN')) {
                            $preload_admin = $this->cf()->dcvalue('PRELOAD_ADMIN');
                        }

                        if ($this->cf()->is_dcarray('PRELOAD_NETWORK')) {
                            $preload_network = $this->cf()->dcvalue('PRELOAD_NETWORK');
                        }

                        if (\is_array($preload_admin) && !empty($preload_admin)) {
                            foreach ($preload_admin as $path) {
                                $url = admin_url('/'.$path);
                                @Crawler::fetch_admin($url, ['blocking' => true]);
                                usleep(500000);
                            }
                        }

                        if (is_multisite() && \is_array($preload_network) && !empty($preload_network)) {
                            foreach ($preload_network as $path) {
                                $url = network_admin_url('/'.$path);
                                @Crawler::fetch_admin($url, ['blocking' => true]);
                                usleep(500000);
                            }
                        }

                        $this->co()->lockreset('preload');
                    },
                    \PHP_INT_MAX
                );
            }
        );

        add_action(
            'docketcache/action/countcachesize',
            function () {
                // gc is running
                if ($this->co()->locked('garbage_collector')) {
                    return;
                }

                if ($this->co()->lockproc('doing_countcachesize', time() + $this->get_max_execution_time())) {
                    return;
                }

                $cache_stats = $this->cache_size($this->cache_path);
                $this->co()->save_part($cache_stats, 'cachestats');

                $this->co()->lockreset('doing_countcachesize');
            },
            \PHP_INT_MAX
        );

        add_action(
            'docketcache/action/flushcache/object',
            function () {
                $this->flush_cache(true);
            }
        );

        // page action
        if (class_exists('Nawawi\\DocketCache\\ReqAction')) {
            ( new ReqAction($this) )->register();
        }
    }

    /**
     * register_tweaks.
     */
    private function register_tweaks()
    {
        if (\defined('AUTOSAVE_INTERVAL') && false === AUTOSAVE_INTERVAL) {
            add_action(
                'init',
                function () {
                    wp_deregister_script('autosave');
                },
                \PHP_INT_MAX
            );
        }

        if (class_exists('Nawawi\\DocketCache\\Tweaks')) {
            $tweaks = new Tweaks();

            if ($this->cf()->is_dctrue('OPTWPQUERY')) {
                $tweaks->wpquery();
            }

            if ($this->cf()->is_dctrue('WOOTWEAKS')) {
                $tweaks->woocommerce_misc();
            }

            if ($this->cf()->is_dctrue('WOOADMINOFF')) {
                $tweaks->woocommerce_admin_disabled();
            }

            if ($this->cf()->is_dctrue('WOOWPDASHBOARDOFF')) {
                $tweaks->woocommerce_dashboard_status_remove();
            }

            if ($this->cf()->is_dctrue('WOOWIDGETOFF')) {
                $tweaks->woocommerce_widget_remove();
            }

            if ($this->cf()->is_dctrue('WOOCARTFRAGSOFF')) {
                $tweaks->woocommerce_cart_fragments_remove();
            }

            if ($this->cf()->is_dctrue('WOOADDTOCHARTCRAWLING')) {
                $tweaks->woocommerce_crawling_addtochart_links();
            }

            if ($this->cf()->is_dctrue('WOOEXTENSIONPAGEOFF')) {
                $tweaks->woocommerce_extensionpage_remove();
            }

            if ($this->cf()->is_dctrue('MISC_TWEAKS')) {
                $tweaks->misc();
            }

            if ($this->cf()->is_dctrue('HEADERJUNK')) {
                $tweaks->headerjunk();
            }

            if ($this->cf()->is_dctrue('PINGBACK')) {
                $tweaks->pingback();
            }

            if ($this->cf()->is_dctrue('WPEMOJI')) {
                $tweaks->wpemoji();
            }

            if ($this->cf()->is_dctrue('WPFEED')) {
                $tweaks->wpfeed();
            }

            if ($this->cf()->is_dctrue('WPEMBED')) {
                $tweaks->wpembed();
            }

            if ($this->cf()->is_dctrue('WPLAZYLOAD')) {
                $tweaks->wplazyload();
            }

            if ($this->cf()->is_dctrue('WPSITEMAP')) {
                $tweaks->wpsitemap();
            }

            if ($this->cf()->is_dctrue('WPAPPPASSWORD')) {
                $tweaks->wpapppassword();
            }

            if ($this->cf()->is_dctrue('WPDASHBOARDNEWS')) {
                $tweaks->wpdashboardnews();
            }

            if ($this->cf()->is_dctrue('POSTVIAEMAIL')) {
                $tweaks->postviaemail();
            }

            if ($this->cf()->is_dctrue('WPBROWSEHAPPY')) {
                $tweaks->wpbrowsehappy();
            }

            if ($this->cf()->is_dctrue('WPSERVEHAPPY')) {
                $tweaks->wpservehappy();
            }

            if ($this->cf()->is_dctrue('LIMITHTTPREQUEST')) {
                $tweaks->limit_http_request();
            }

            if (version_compare($GLOBALS['wp_version'], '5.8', '<')) {
                if ($this->cf()->is_dctrue('HTTPHEADERSEXPECT')) {
                    $tweaks->http_headers_expect();
                }
            }

            if ($this->cf()->is_dctrue('POSTMISSEDSCHEDULE')) {
                add_action(
                    'shutdown',
                    function () use ($tweaks) {
                        if ($this->co()->lockproc('post_missed_schedule', time() + 180)) {
                            return false;
                        }
                        $tweaks->post_missed_schedule();
                        $this->co()->lockreset('post_missed_schedule');
                    },
                    \PHP_INT_MAX
                );
            }

            if ($this->cf()->is_dctrue('CACHEHTTPRESPONSE')) {
                $tweaks->cache_http_response();
            }
        }

        // only if dropin exists
        if (wp_using_ext_object_cache()) {
            // wp_cache: advanced cache post
            if (version_compare($GLOBALS['wp_version'], '6.1', '<')) {
                if ($this->cf()->is_dctrue('ADVCPOST') && class_exists('Nawawi\\DocketCache\\PostCache')) {
                    ( new PostCache() )->register();
                }
            }

            // wp_cache: translation mo file cache
            if ($this->cf()->is_dctrue('MOCACHE') && class_exists('Nawawi\\DocketCache\\MoCache')) {
                add_filter(
                    'override_load_textdomain',
                    function ($plugin_override, $domain, $mofile) {
                        if (!@is_file($mofile) || !@is_readable($mofile) || !isset($GLOBALS['l10n'])) {
                            return false;
                        }

                        $l10n = $GLOBALS['l10n'];
                        $upstream = empty($l10n[$domain]) ? null : $l10n[$domain];
                        $mo = new MoCache($mofile, $domain, $upstream);
                        $l10n[$domain] = $mo;

                        $GLOBALS['l10n'] = $l10n;

                        return true;
                    },
                    \PHP_INT_MAX,
                    3
                );
            }

            // wp_cache: menu cache
            if ($this->cf()->is_dctrue('MENUCACHE') && class_exists('Nawawi\\DocketCache\\MenuCache')) {
                ( new MenuCache() )->register();
            }
        }

        // optimize term count
        if ($this->cf()->is_dctrue('OPTERMCOUNT') && class_exists('Nawawi\\DocketCache\\TermCount')) {
            ( new TermCount() )->register();
        }

        if ($this->cf()->is_dctrue('LIMITBULKEDIT') && class_exists('Nawawi\\DocketCache\\LimitBulkedit')) {
            ( new LimitBulkedit() )->register();
        }
    }

    /**
     * register_cronjob.
     */
    private function register_cronjob()
    {
        ( new Event($this) )->register();
    }

    /**
     * unregister_cronjob.
     */
    private function unregister_cronjob()
    {
        ( new Event($this) )->unregister();
    }

    private function register_cli()
    {
        if ($this->cf()->is_dctrue('WPCLI') && $this->cf()->is_false('DocketCache_CLI')) {
            \define('DocketCache_CLI', true);
            $cli = new Command($this);

            \WP_CLI::add_command('cache dropin:update', [$cli, 'dropino_update']);
            \WP_CLI::add_command('cache dropin:enable', [$cli, 'dropino_enable']);
            \WP_CLI::add_command('cache dropin:disable', [$cli, 'dropino_disable']);
            \WP_CLI::add_command('cache run:gc', [$cli, 'run_gc']);
            \WP_CLI::add_command('cache run:cron', [$cli, 'run_cron']);
            \WP_CLI::add_command('cache run:stats', [$cli, 'run_stats']);
            \WP_CLI::add_command('cache run:optimizedb', [$cli, 'run_optimizedb']);
            \WP_CLI::add_command('cache reset:lock', [$cli, 'reset_lock']);
            \WP_CLI::add_command('cache reset:cron', [$cli, 'reset_cron']);

            if (version_compare($GLOBALS['wp_version'], '6.1', '<')) {
                \WP_CLI::add_command('cache flush:advcpost', [$cli, 'flush_advcpost']);
            }

            \WP_CLI::add_command('cache flush:precache', [$cli, 'flush_precache']);
            \WP_CLI::add_command('cache flush:menucache', [$cli, 'flush_menucache']);
            \WP_CLI::add_command('cache flush:mocache', [$cli, 'flush_mocache']);
            \WP_CLI::add_command('cache flush:transient', [$cli, 'flush_transient']);
            \WP_CLI::add_command('cache flush', [$cli, 'flush_cache']);
            \WP_CLI::add_command('cache runtime:install', [$cli, 'runtime_install']);
            \WP_CLI::add_command('cache runtime:remove', [$cli, 'runtime_remove']);
            \WP_CLI::add_command('cache status', [$cli, 'status']);
            \WP_CLI::add_command('cache type', [$cli, 'type']);
            nwdcx_runaction('docketcache/init/cli', $this, $cli);
        }
    }

    /**
     * register.
     */
    public function register()
    {
        if (!$this->compat_notice()) {
            return;
        }
        $this->register_plugin_hooks();
        $this->register_admin_hooks();
        $this->register_tweaks();
        $this->register_cronjob();
        $this->register_cli();

        nwdcx_runaction('docketcache/init', $this);
    }
}