1) return true; } return false; } /* 3.0.6 (WordPress.org-granskningen): sidans HTML tas emot med WordPress 6.9:s mall-buffert (filtret wp_template_enhancement_output_buffer). I äldre WordPress öppnas en egen buffert som stängs uttryckligen på shutdown – ingen buffert lämnas öppen. */ add_action('template_redirect', static function () { if (!datoden_cache_can_store()) return; $GLOBALS['datoden_cache_start'] = microtime(true); if (function_exists('wp_start_template_enhancement_output_buffer')) { /* sist av alla filter – får den färdiga sidan (efter t.ex. DT-svg-supports inline-SVG) */ add_filter('wp_template_enhancement_output_buffer', static function ($html) { return is_string($html) ? datoden_cache_store($html) : $html; }, PHP_INT_MAX); return; } ob_start('datoden_cache_store'); // först av alla – får den färdiga sidan sist $level = ob_get_level(); add_action('shutdown', static function () use ($level) { while (ob_get_level() >= $level && ob_get_level() > 0) ob_end_flush(); }, 0); }, PHP_INT_MIN); /* Spara sidan när den är färdig. Sidan skickas alltid som den är – sparandet påverkar aldrig det besökaren får. */ function datoden_cache_store(string $html): string { if (defined('DONOTCACHEPAGE') && DONOTCACHEPAGE) return $html; if (http_response_code() !== 200 || strlen($html) < 255 || strlen($html) > 5 * MB_IN_BYTES) return $html; if (stripos($html, '') === false || stripos(substr($html, 0, 512), ''; datoden_cache_write($file, datoden_cache_cron_tag($out)); // 3.0.15 (Pro 3.0.16): bara i den sparade sidan return $html; } /* 3.0.15 (Pro 3.0.16): schemalagda händelser på cachade sidor. En sida från cachen startar inte WordPress (servern skickar filen direkt), så WP-Cron kördes bara när någon besökte adminpanelen – WooCommerces kö, schemalagda inlägg och uppdateringar blev liggande på sajter med lite trafik. Den sparade sidan får därför veta när nästa händelse ska köras; har den tiden passerat ber besökarens webbläsare WordPress köra dem (wp-cron.php, i bakgrunden – sidan väntar inte). Högst var femte minut per besökare, och WordPress egen spärr kör dem högst en gång i minuten. Inget när DISABLE_WP_CRON är satt (cron-jobb på servern) eller inget är schemalagt. Inget skickas någon annanstans, inga kakor. */ function datoden_cache_cron_tag(string $html): string { if ((defined('DISABLE_WP_CRON') && DISABLE_WP_CRON) || !function_exists('_get_cron_array')) return $html; $crons = _get_cron_array(); if (!is_array($crons) || !$crons) return $html; $pos = strripos($html, ''); if ($pos === false) return $html; $js = sprintf('(function(){var d=%1$d,n=Math.floor(Date.now()/1e3),k="dt-cache-cron";if(n' . $js . '', $pos, 0); } function datoden_cache_write(string $file, string $content): void { $dir = dirname($file); if (!is_dir($dir) && !wp_mkdir_p($dir)) return; $tmp = $dir . '/.tmp-' . wp_generate_password(8, false); if (@file_put_contents($tmp, $content) === false) return; // phpcs:ignore @chmod($tmp, 0644); // phpcs:ignore if (!@rename($tmp, $file)) @unlink($tmp); // phpcs:ignore } /* ---------- tömma ---------- */ function datoden_cache_rmdir(string $dir): void { if (!is_dir($dir)) return; $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST); foreach ($it as $f) { $f->isDir() ? @rmdir($f->getPathname()) : @unlink($f->getPathname()); } // phpcs:ignore @rmdir($dir); // phpcs:ignore } /* Tömmer allt. Mappen byter namn först, så att ingen besökare får en halvt tömd cache. */ function datoden_cache_purge_all(): void { if (is_dir(DATODEN_CACHE_PATH)) { $trash = DATODEN_CACHE_PATH . '-old-' . wp_generate_password(6, false); if (@rename(DATODEN_CACHE_PATH, $trash)) datoden_cache_rmdir($trash); else datoden_cache_rmdir(DATODEN_CACHE_PATH); // phpcs:ignore } foreach (glob(DATODEN_CACHE_PATH . '-old-*', GLOB_ONLYDIR) ?: [] as $old) datoden_cache_rmdir($old); datoden_cache_rmdir(WP_CONTENT_DIR . '/cache/dt-cache-min'); // kvarlämnade filer i den gamla mappen för förminskade kopior tas bort update_option('datoden_cache_purged', time(), false); datoden_core_do_action('cache_purged'); } /* Tömmer en adress. */ function datoden_cache_purge_url(string $url): void { $host = strtolower((string) wp_parse_url($url, PHP_URL_HOST)); $path = (string) wp_parse_url($url, PHP_URL_PATH); if ($path === '' || substr($path, -1) !== '/') $path .= '/'; $f = datoden_cache_file_for($host, $path); if ($f !== '' && is_file($f)) @unlink($f); // phpcs:ignore } /* Andra tillägg tömmer cachen så här: do_action('datoden_cache_purge') (det gamla namnet dt_cache_purge fungerar också). DT-tilläggen och Responsit-temat skickar redan litespeed_purge_all (den vanliga signalen till sidcacher) – den lyssnar DT-cache också på. 1.0.2: DT-cache definierar inte längre wpfc_clear_all_cache() – WP Fastest Cache definierar samma funktion, så det gick inte att radera WP Fastest Cache (WordPress laddar tilläggets fil när det raderas → "Cannot redeclare"). */ add_action('datoden_cache_purge', 'datoden_cache_schedule_purge'); add_action('litespeed_purge_all', 'datoden_cache_schedule_purge'); /* Det som ändrar sidorna tömmer cachen (en gång per sidvisning, i slutet). */ function datoden_cache_schedule_purge(): void { if (!empty($GLOBALS['datoden_cache_purge_pending'])) return; $GLOBALS['datoden_cache_purge_pending'] = true; add_action('shutdown', static function () { datoden_cache_purge_all(); }, 0); } add_action('transition_post_status', static function ($new, $old, $post) { if (!$post || wp_is_post_revision($post) || wp_is_post_autosave($post)) return; if (function_exists('datoden_cache_shop_takes') && datoden_cache_shop_takes($post)) return; // butiksläget: bara produktens sidor if ($new !== 'publish' && $old !== 'publish') return; $pt = get_post_type_object($post->post_type); if (!$pt || (!$pt->public && $post->post_type !== 'nav_menu_item' && $post->post_type !== 'wp_block' && $post->post_type !== 'wp_template' && $post->post_type !== 'wp_template_part' && $post->post_type !== 'wp_global_styles' && $post->post_type !== 'wp_navigation')) return; datoden_cache_schedule_purge(); }, 10, 3); add_action('post_updated', static function ($id, $after) { if ($after && function_exists('datoden_cache_shop_takes') && datoden_cache_shop_takes($after)) return; if ($after && $after->post_status === 'publish' && !wp_is_post_revision($id)) { $pt = get_post_type_object($after->post_type); if ($pt && $pt->public) datoden_cache_schedule_purge(); } }, 10, 2); foreach (['wp_update_nav_menu', 'customize_save_after', 'switch_theme', 'activated_plugin', 'deactivated_plugin', 'upgrader_process_complete', 'edited_term', 'created_term', 'delete_term', 'wp_set_comment_status', 'comment_post', 'edit_comment', 'update_option_sidebars_widgets', 'update_option_permalink_structure', 'update_option_blogname', 'update_option_blogdescription', 'update_option_show_on_front', 'update_option_page_on_front', 'update_option_datoden_lang_options', 'update_option_theme_mods_' . get_option('stylesheet')] as $datoden_hook) { add_action($datoden_hook, 'datoden_cache_schedule_purge'); } /* ---------- gamla filer: tas bort en gång i timmen ---------- */ add_action('init', static function () { if (datoden_cache_on() && !wp_next_scheduled('datoden_cache_gc')) wp_schedule_event(time() + HOUR_IN_SECONDS, 'hourly', 'datoden_cache_gc'); }); add_action('datoden_cache_gc', static function () { $life = (int) datoden_cache_options()['lifetime']; if ($life <= 0 || !is_dir(DATODEN_CACHE_PATH)) return; $limit = time() - $life * HOUR_IN_SECONDS; $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(DATODEN_CACHE_PATH, FilesystemIterator::SKIP_DOTS)); $gone = 0; foreach ($it as $f) { if ($f->isFile() && $f->getMTime() < $limit && $f->getFilename() === 'index.html') @unlink($f->getPathname()); } // phpcs:ignore }); /* ---------- statistik ---------- */ function datoden_cache_stats(): array { $n = 0; $bytes = 0; $hosts = []; if (is_dir(DATODEN_CACHE_PATH)) { $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(DATODEN_CACHE_PATH, FilesystemIterator::SKIP_DOTS)); foreach ($it as $f) { if (!$f->isFile() || $f->getFilename() !== 'index.html') continue; $n++; $bytes += $f->getSize(); $rel = substr(wp_normalize_path($f->getPathname()), strlen(wp_normalize_path(DATODEN_CACHE_PATH)) + 1); $h = strtok($rel, '/'); $hosts[$h] = ($hosts[$h] ?? 0) + 1; } } return ['pages' => $n, 'bytes' => $bytes, 'hosts' => $hosts, 'purged' => (int) get_option('datoden_cache_purged', 0)]; } /* ---------- adminlisten: Töm cache ---------- */ /* DT-caches egen ikon i adminlisten (på ::after – WordPress tar bort bakgrundsbilden på .ab-icon med !important) */ function datoden_cache_bar_css(): void { if (!is_admin_bar_showing() || !current_user_can('manage_options') || !datoden_cache_on()) return; wp_add_inline_style('admin-bar', '#wpadminbar #wp-admin-bar-datoden-cache .dtpc-ico{width:20px!important;height:20px!important;margin:6px 6px 0 0!important;padding:0!important}' . '#wpadminbar #wp-admin-bar-datoden-cache .dtpc-ico::before{content:none!important}' . '#wpadminbar #wp-admin-bar-datoden-cache .dtpc-ico::after{content:"";display:block;width:20px;height:20px;background:url(' . esc_url(plugin_dir_url(__DIR__) . 'dt-core/img/icons/datoden-page-cache.svg') . ') center/contain no-repeat}' . '@media screen and (max-width:782px){#wpadminbar #wp-admin-bar-datoden-cache .dtpc-ico{margin-top:13px!important}}'); } add_action('wp_enqueue_scripts', 'datoden_cache_bar_css'); add_action('admin_enqueue_scripts', 'datoden_cache_bar_css'); add_action('admin_bar_menu', static function ($bar) { if (!current_user_can('manage_options') || !datoden_cache_on()) return; $bar->add_node(['id' => 'datoden-cache', 'title' => '' . 'DT-cache' . '', 'href' => admin_url('admin.php?page=datoden-page-cache')]); $bar->add_node(['parent' => 'datoden-cache', 'id' => 'datoden-cache-all', 'title' => esc_html__('Empty all cache', 'datoden-page-cache'), 'href' => wp_nonce_url(admin_url('admin-post.php?action=datoden_cache_purge'), 'datoden_cache_purge')]); if (!is_admin()) { $url = (is_ssl() ? 'https://' : 'http://') . sanitize_text_field((string) ($GLOBALS['datoden_cache_host'] ?? '')) . sanitize_text_field(datoden_cache_uri()); $bar->add_node(['parent' => 'datoden-cache', 'id' => 'datoden-cache-this', 'title' => esc_html__('Empty this page', 'datoden-page-cache'), 'href' => wp_nonce_url(admin_url('admin-post.php?action=datoden_cache_purge&url=' . rawurlencode($url)), 'datoden_cache_purge')]); } $bar->add_node(['parent' => 'datoden-cache', 'id' => 'datoden-cache-settings', 'title' => esc_html__('Settings', 'datoden-page-cache'), 'href' => admin_url('admin.php?page=datoden-page-cache')]); }, 90); add_action('admin_post_datoden_cache_purge', static function () { if (!current_user_can('manage_options')) wp_die('', 403); check_admin_referer('datoden_cache_purge'); $url = isset($_GET['url']) ? esc_url_raw(wp_unslash($_GET['url'])) : ''; if ($url !== '') datoden_cache_purge_url($url); else datoden_cache_purge_all(); $back = wp_get_referer() ?: admin_url('admin.php?page=datoden-page-cache'); wp_safe_redirect(add_query_arg('dtcache', $url !== '' ? 'page' : 'all', $back)); exit; }); /* Kvitto efter tömning (adminpanelen och webbplatsen). */ add_action('admin_notices', static function () { $k = isset($_GET['dtcache']) ? sanitize_key(wp_unslash($_GET['dtcache'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification if ($k === 'all') echo '

' . esc_html__('The cache is empty. It fills up again as the pages are visited.', 'datoden-page-cache') . '

'; if ($k === 'page') echo '

' . esc_html__('The page is removed from the cache.', 'datoden-page-cache') . '

'; });