StaticSite 静态化插件 ,实现真正的纯静态HTML生成功能。这个插件会将你的文章、页面、分类归档等所有页面生成静态HTML文件,并自动处理URL重写,让访客直接访问静态文件。
StaticSite 静态化插件
插件功能
- 支持手动生成全站静态HTML
- 支持发布/更新文章时自动生成对应静态页
- 支持首页、文章页、独立页面、分类归档页、标签页、搜索页(可配置)
- 自动处理静态资源路径(CSS/JS/图片)
- 智能URL重写:优先访问静态文件,不存在时回退到动态页面
- 一键清除所有静态文件
插件目录结构
usr/plugins/StaticSite/
├── Plugin.php # 插件主文件
├── Action.php # 后台操作处理
├── static/
│ └── style.css # 插件后台样式
└── README.md # 说明文档完整插件代码
Plugin.php
<?php
/**
* 纯静态页面生成器 - 将Typecho站点转换为纯静态HTML
*
* @package StaticSite
* @author YourName
* @version 1.0.0
* @link https://yourwebsite.com
* @since 1.2.0
*/
namespace TypechoPlugin\StaticSite;
use Typecho\Plugin\PluginInterface;
use Typecho\Widget\Helper\Form;
use Typecho\Widget\Helper\Form\Element\Radio;
use Typecho\Widget\Helper\Form\Element\Text;
use Typecho\Widget\Helper\Form\Element\Textarea;
use Typecho\Widget\Helper\Form\Element\Checkbox;
use Typecho\Common;
use Widget\Options;
use Widget\Contents\Post\Post;
use Widget\Contents\Page\Pages;
use Widget\Metas\Category\Categories;
use Widget\Metas\Tag\Tags;
use Utils\Helper;
if (!defined('__TYPECHO_ROOT_DIR__')) {
exit;
}
/**
* StaticSite 静态化插件
*/
class Plugin implements PluginInterface
{
/**
* 静态文件存放目录
*/
const STATIC_DIR = '/usr/uploads/static-site/';
/**
* 激活插件
*/
public static function activate()
{
// 注册后台菜单
\Typecho\Plugin::factory('admin/menu.php')->navBar = __CLASS__ . '::renderMenu';
// 注册文章发布钩子
\Typecho\Plugin::factory('Widget_Contents_Post_Edit')->finishPublish = __CLASS__ . '::generatePost';
\Typecho\Plugin::factory('Widget_Contents_Page_Edit')->finishPublish = __CLASS__ . '::generatePage';
// 注册文章删除钩子
\Typecho\Plugin::factory('Widget_Contents_Post_Edit')->delete = __CLASS__ . '::removePost';
\Typecho\Plugin::factory('Widget_Contents_Page_Edit')->delete = __CLASS__ . '::removePage';
// 注册分类/标签更新钩子
\Typecho\Plugin::factory('Widget_Metas_Category_Edit')->finishPublish = __CLASS__ . '::generateArchive';
// 创建静态文件目录
self::createStaticDir();
// 添加重写规则提示
return _t('静态化插件已激活,请配置伪静态规则以确保正常访问');
}
/**
* 禁用插件
*/
public static function deactivate()
{
// 禁用时不做清理,保留静态文件
return _t('静态化插件已禁用,静态文件保留在服务器上,如需删除请手动清理');
}
/**
* 插件配置面板
*/
public static function config(Form $form)
{
// 基本设置
$form->addInput(new \Typecho\Widget\Helper\Form\Element\Text(
'static_dir',
null,
self::STATIC_DIR,
_t('静态文件存储目录'),
_t('相对于网站根目录的路径,默认:/usr/uploads/static-site/')
));
// 生成选项
$generateOptions = [
'home' => _t('首页'),
'post' => _t('文章页'),
'page' => _t('独立页面'),
'category' => _t('分类归档页'),
'tag' => _t('标签页'),
'archive' => _t('日期归档页'),
'search' => _t('搜索页(可能无法正常工作)'),
];
$form->addInput(new \Typecho\Widget\Helper\Form\Element\Checkbox(
'generate_pages',
$generateOptions,
['home', 'post', 'page', 'category', 'tag'],
_t('需要静态化的页面类型')
));
// URL重写选项
$form->addInput(new \Typecho\Widget\Helper\Form\Element\Radio(
'url_rewrite',
[
'1' => _t('启用 - 优先访问静态文件,不存在时回退到动态页面'),
'0' => _t('禁用 - 只生成静态文件,需手动配置服务器重写规则'),
],
'1',
_t('URL重写模式')
));
// 自动生成设置
$form->addInput(new \Typecho\Widget\Helper\Form\Element\Radio(
'auto_generate',
[
'1' => _t('启用 - 发布/更新内容时自动生成对应静态页'),
'0' => _t('禁用 - 手动通过后台生成'),
],
'1',
_t('自动生成模式')
));
// 排除的URL规则
$form->addInput(new \Typecho\Widget\Helper\Form\Element\Textarea(
'exclude_urls',
null,
"/admin\n/login\n/action\n/feed\n",
_t('排除的URL规则(一行一个)'),
_t('包含这些路径的URL不会被静态化,支持通配符*')
));
}
/**
* 个人配置
*/
public static function personalConfig(Form $form)
{
// 个人配置留空
}
/**
* 渲染后台菜单
*/
public static function renderMenu()
{
$options = Options::alloc();
$pluginUrl = Helper::url('extending.php?panel=StaticSite%2FAction.php');
echo '<a href="' . $pluginUrl . '" class="message success">⚡ 静态化管理</a>';
}
/**
* 创建静态文件目录
*/
private static function createStaticDir()
{
$options = Options::alloc();
$pluginConfig = $options->plugin('StaticSite');
$staticDir = !empty($pluginConfig->static_dir) ? $pluginConfig->static_dir : self::STATIC_DIR;
$fullPath = __TYPECHO_ROOT_DIR__ . $staticDir;
if (!is_dir($fullPath)) {
if (!@mkdir($fullPath, 0755, true)) {
throw new \Typecho\Plugin\Exception(_t('无法创建静态文件目录:%s', $fullPath));
}
// 创建.htaccess保护
$htaccess = $fullPath . '.htaccess';
if (!file_exists($htaccess)) {
file_put_contents($htaccess, "Order Deny,Allow\nDeny from all");
}
}
return $fullPath;
}
/**
* 获取静态文件保存路径
*/
public static function getStaticPath($uri)
{
$options = Options::alloc();
$pluginConfig = $options->plugin('StaticSite');
$baseDir = !empty($pluginConfig->static_dir) ? $pluginConfig->static_dir : self::STATIC_DIR;
// 清理URI
$uri = trim($uri, '/');
if (empty($uri)) {
$uri = 'index';
}
// 替换特殊字符
$uri = preg_replace('/[^a-zA-Z0-9\/\-_]/', '_', $uri);
return $baseDir . $uri . '.html';
}
/**
* 生成文章静态页
*/
public static function generatePost($post)
{
$options = Options::alloc();
$pluginConfig = $options->plugin('StaticSite');
// 检查是否启用自动生成
if (empty($pluginConfig->auto_generate) || $pluginConfig->auto_generate != '1') {
return;
}
// 检查是否需要生成文章页
$generatePages = $pluginConfig->generate_pages ?: [];
if (!in_array('post', $generatePages)) {
return;
}
// 获取文章URL
$postUrl = $post->permalink;
self::generatePageContent($postUrl);
// 如果首页也需要更新
if (in_array('home', $generatePages)) {
self::generateHomePage();
}
}
/**
* 生成独立页面静态页
*/
public static function generatePage($page)
{
$options = Options::alloc();
$pluginConfig = $options->plugin('StaticSite');
if (empty($pluginConfig->auto_generate) || $pluginConfig->auto_generate != '1') {
return;
}
$generatePages = $pluginConfig->generate_pages ?: [];
if (!in_array('page', $generatePages)) {
return;
}
$pageUrl = $page->permalink;
self::generatePageContent($pageUrl);
}
/**
* 生成归档页(分类/标签更新时触发)
*/
public static function generateArchive($meta)
{
$options = Options::alloc();
$pluginConfig = $options->plugin('StaticSite');
if (empty($pluginConfig->auto_generate) || $pluginConfig->auto_generate != '1') {
return;
}
$generatePages = $pluginConfig->generate_pages ?: [];
// 根据元数据类型生成对应归档页
if ($meta->type == 'category' && in_array('category', $generatePages)) {
$archiveUrl = Helper::url($meta->slug, $options->routingTable['category']['url']);
self::generatePageContent($archiveUrl);
} elseif ($meta->type == 'tag' && in_array('tag', $generatePages)) {
$archiveUrl = Helper::url($meta->slug, $options->routingTable['tag']['url']);
self::generatePageContent($archiveUrl);
}
}
/**
* 生成首页
*/
public static function generateHomePage()
{
$options = Options::alloc();
$homeUrl = $options->siteUrl;
self::generatePageContent($homeUrl);
}
/**
* 生成页面内容并保存为静态文件
*/
public static function generatePageContent($url)
{
// 排除不需要生成的URL
if (self::shouldExclude($url)) {
return false;
}
// 使用cURL获取页面内容
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_USERAGENT, 'StaticSite Generator/1.0');
$content = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode != 200 || empty($content)) {
return false;
}
// 处理相对路径为绝对路径
$content = self::fixResourcePaths($content, $url);
// 添加静态文件标记(可选)
$content = self::addStaticMarker($content);
// 保存文件
$options = Options::alloc();
$uri = parse_url($url, PHP_URL_PATH);
if (empty($uri) || $uri == '/') {
$uri = '/index';
}
$staticPath = self::getStaticPath($uri);
$fullPath = __TYPECHO_ROOT_DIR__ . $staticPath;
$dir = dirname($fullPath);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
return file_put_contents($fullPath, $content) !== false;
}
/**
* 判断URL是否需要排除
*/
private static function shouldExclude($url)
{
$options = Options::alloc();
$pluginConfig = $options->plugin('StaticSite');
if (empty($pluginConfig->exclude_urls)) {
return false;
}
$excludeRules = explode("\n", $pluginConfig->exclude_urls);
$path = parse_url($url, PHP_URL_PATH);
foreach ($excludeRules as $rule) {
$rule = trim($rule);
if (empty($rule)) {
continue;
}
// 转换为正则表达式
$pattern = '/' . str_replace(['*', '/'], ['.*', '\/'], preg_quote($rule, '/')) . '/';
if (preg_match($pattern, $path)) {
return true;
}
}
return false;
}
/**
* 修复资源路径(将相对路径转为绝对路径)
*/
private static function fixResourcePaths($content, $pageUrl)
{
$options = Options::alloc();
$siteUrl = $options->siteUrl;
$parsedSite = parse_url($siteUrl);
$siteHost = $parsedSite['host'];
// 替换CSS/JS/图片路径
$patterns = [
// src="path/to/file" 或 src='path/to/file'
'/(src|href)=(["\'])(?!https?:\/\/|\/\/|data:)([^"\']+)(["\'])/i' => '$1=$2' . $siteUrl . '$3$4',
// url(path/to/file)
'/url\((["\']?)(?!https?:\/\/|\/\/|data:)([^"\')]+)(["\']?)\)/i' => 'url($1' . $siteUrl . '$2$3)',
// 处理相对根路径
'/(src|href)=(["\'])\/(?!\/)([^"\']+)(["\'])/i' => '$1=$2' . $siteUrl . '$3$4',
];
foreach ($patterns as $pattern => $replacement) {
$content = preg_replace($pattern, $replacement, $content);
}
return $content;
}
/**
* 添加静态文件标记(用于调试)
*/
private static function addStaticMarker($content)
{
if (defined('TYPECHO_DEBUG') && TYPECHO_DEBUG) {
$marker = "\n<!-- Generated by StaticSite plugin at " . date('Y-m-d H:i:s') . " -->\n";
$content = str_replace('</body>', $marker . '</body>', $content);
}
return $content;
}
/**
* 删除文章静态页
*/
public static function removePost($post)
{
$uri = parse_url($post->permalink, PHP_URL_PATH);
$staticPath = self::getStaticPath($uri);
$fullPath = __TYPECHO_ROOT_DIR__ . $staticPath;
if (file_exists($fullPath)) {
@unlink($fullPath);
}
}
/**
* 删除页面静态页
*/
public static function removePage($page)
{
$uri = parse_url($page->permalink, PHP_URL_PATH);
$staticPath = self::getStaticPath($uri);
$fullPath = __TYPECHO_ROOT_DIR__ . $staticPath;
if (file_exists($fullPath)) {
@unlink($fullPath);
}
}
/**
* 批量生成所有页面
*/
public static function generateAll()
{
$options = Options::alloc();
$pluginConfig = $options->plugin('StaticSite');
$generatePages = $pluginConfig->generate_pages ?: [];
$results = [
'success' => [],
'failed' => []
];
// 生成首页
if (in_array('home', $generatePages)) {
if (self::generateHomePage()) {
$results['success'][] = '首页';
} else {
$results['failed'][] = '首页';
}
}
// 获取所有文章
if (in_array('post', $generatePages)) {
$posts = Post::alloc()->select()->where('status = ?', 'publish');
while ($posts->next()) {
$url = $posts->permalink;
if (self::generatePageContent($url)) {
$results['success'][] = '文章:' . $posts->title;
} else {
$results['failed'][] = '文章:' . $posts->title;
}
}
}
// 获取所有独立页面
if (in_array('page', $generatePages)) {
$pages = Pages::alloc()->select()->where('status = ?', 'publish');
while ($pages->next()) {
$url = $pages->permalink;
if (self::generatePageContent($url)) {
$results['success'][] = '页面:' . $pages->title;
} else {
$results['failed'][] = '页面:' . $pages->title;
}
}
}
// 获取所有分类
if (in_array('category', $generatePages)) {
$categories = Categories::alloc()->select();
while ($categories->next()) {
$url = $categories->permalink;
if (self::generatePageContent($url)) {
$results['success'][] = '分类:' . $categories->name;
} else {
$results['failed'][] = '分类:' . $categories->name;
}
}
}
// 获取所有标签
if (in_array('tag', $generatePages)) {
$tags = Tags::alloc()->select();
while ($tags->next()) {
$url = $tags->permalink;
if (self::generatePageContent($url)) {
$results['success'][] = '标签:' . $tags->name;
} else {
$results['failed'][] = '标签:' . $tags->name;
}
}
}
return $results;
}
/**
* 清除所有静态文件
*/
public static function clearAll()
{
$options = Options::alloc();
$pluginConfig = $options->plugin('StaticSite');
$staticDir = !empty($pluginConfig->static_dir) ? $pluginConfig->static_dir : self::STATIC_DIR;
$fullPath = __TYPECHO_ROOT_DIR__ . $staticDir;
if (!is_dir($fullPath)) {
return 0;
}
$count = 0;
$files = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($fullPath, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($files as $file) {
if ($file->isDir()) {
@rmdir($file->getRealPath());
} else {
@unlink($file->getRealPath());
$count++;
}
}
return $count;
}
}Action.php
<?php
/**
* 静态化管理页面
*/
namespace TypechoPlugin\StaticSite;
use Widget\Base\Options;
use Widget\ActionInterface;
use Typecho\Widget\Helper\Form;
use Typecho\Widget\Helper\Page;
use Utils\Helper;
class Action extends Options implements ActionInterface
{
/**
* 动作执行入口
*/
public function action()
{
$this->on($this->request->is('generate'))->generate();
$this->on($this->request->is('clear'))->clear();
$this->on($this->request->is('rewrite'))->rewriteGuide();
$this->render();
}
/**
* 渲染管理页面
*/
public function render()
{
$this->currentPage = 'static-site';
$this->menuTitle = _t('静态化管理');
// 获取静态文件统计
$pluginConfig = Helper::options()->plugin('StaticSite');
$staticDir = !empty($pluginConfig->static_dir) ? $pluginConfig->static_dir : Plugin::STATIC_DIR;
$fullPath = __TYPECHO_ROOT_DIR__ . $staticDir;
$fileCount = 0;
$totalSize = 0;
if (is_dir($fullPath)) {
$files = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($fullPath, \RecursiveDirectoryIterator::SKIP_DOTS)
);
foreach ($files as $file) {
if ($file->isFile()) {
$fileCount++;
$totalSize += $file->getSize();
}
}
}
include 'page.php';
}
/**
* 生成静态文件
*/
public function generate()
{
$type = $this->request->get('type', 'all');
if ($type == 'all') {
$results = Plugin::generateAll();
$message = sprintf(
'生成完成:成功 %d 个,失败 %d 个',
count($results['success']),
count($results['failed'])
);
} else {
// 单页生成
$url = $this->request->get('url');
if (Plugin::generatePageContent($url)) {
$message = '页面生成成功';
} else {
$message = '页面生成失败';
}
}
$this->widget('Widget_Notice')->set($message, 'success');
$this->response->redirect(Helper::url('extending.php?panel=StaticSite%2FAction.php'));
}
/**
* 清除静态文件
*/
public function clear()
{
$count = Plugin::clearAll();
$this->widget('Widget_Notice')->set(
sprintf('已清除 %d 个静态文件', $count),
'success'
);
$this->response->redirect(Helper::url('extending.php?panel=StaticSite%2FAction.php'));
}
/**
* 显示伪静态规则指南
*/
public function rewriteGuide()
{
$this->currentPage = 'static-site';
$this->menuTitle = _t('伪静态规则');
$rewriteRules = $this->getRewriteRules();
include 'rewrite.php';
}
/**
* 获取不同服务器的重写规则
*/
private function getRewriteRules()
{
$options = Helper::options();
$pluginConfig = $options->plugin('StaticSite');
$staticDir = !empty($pluginConfig->static_dir) ? $pluginConfig->static_dir : Plugin::STATIC_DIR;
return [
'apache' => [
'name' => 'Apache (.htaccess)',
'code' => "<IfModule mod_rewrite.c>\n"
. "RewriteEngine On\n"
. "RewriteBase /\n\n"
. "# 如果静态文件存在则直接访问\n"
. "RewriteCond %{DOCUMENT_ROOT}" . $staticDir . "%{REQUEST_URI}.html -f\n"
. "RewriteRule ^(.*)$ " . $staticDir . "$1.html [L]\n\n"
. "# 否则交给Typecho处理\n"
. "RewriteCond %{REQUEST_FILENAME} !-f\n"
. "RewriteCond %{REQUEST_FILENAME} !-d\n"
. "RewriteRule ^(.*)$ /index.php/$1 [L]\n"
. "</IfModule>"
],
'nginx' => [
'name' => 'Nginx',
'code' => "location / {\n"
. " # 尝试访问静态文件\n"
. " set $static_file \"{$staticDir}${uri}.html\";\n"
. " if (-f $document_root$static_file) {\n"
. " rewrite ^(.*)$ $static_file last;\n"
. " }\n"
. " \n"
. " # 否则交给PHP处理\n"
. " if (!-e $request_filename) {\n"
. " rewrite ^(.*)$ /index.php/$1 last;\n"
. " }\n"
. "}"
],
'iis' => [
'name' => 'IIS (web.config)',
'code' => "<configuration>\n"
. " <system.webServer>\n"
. " <rewrite>\n"
. " <rules>\n"
. " <rule name=\"StaticSite\" stopProcessing=\"true\">\n"
. " <match url=\"^(.*)$\" />\n"
. " <conditions>\n"
. " <add input=\"{DOCUMENT_ROOT}" . $staticDir . "{R:1}.html\" matchType=\"IsFile\" />\n"
. " </conditions>\n"
. " <action type=\"Rewrite\" url=\"" . $staticDir . "{R:1}.html\" />\n"
. " </rule>\n"
. " </rules>\n"
. " </rewrite>\n"
. " </system.webServer>\n"
. "</configuration>"
]
];
}
}page.php(管理页面模板)
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<?php $this->need('header.php'); ?>
<div class="typecho-page-title">
<h2><?php echo $this->menuTitle; ?></h2>
</div>
<div class="row typecho-page-main">
<div class="col-mb-12 col-tb-8" style="margin:0 auto; float:none;">
<div class="typecho-list">
<div class="typecho-table-wrap">
<table class="typecho-list-table">
<colgroup>
<col width="30%">
<col width="70%">
</colgroup>
<thead>
<tr>
<th colspan="2"><?php _e('静态文件统计'); ?></th>
</tr>
</thead>
<tbody>
<tr>
<td><?php _e('文件数量'); ?></td>
<td><?php echo $fileCount; ?> 个</td>
</tr>
<tr>
<td><?php _e('总大小'); ?></td>
<td><?php echo round($totalSize / 1024, 2); ?> KB</td>
</tr>
<tr>
<td><?php _e('存储目录'); ?></td>
<td><code><?php echo $staticDir; ?></code></td>
</tr>
</tbody>
</table>
</div>
</div>
<div style="margin:20px 0; text-align:center;">
<a class="btn primary" href="<?php echo Helper::url('extending.php?panel=StaticSite%2FAction.php&generate=1&type=all'); ?>">
<?php _e('⚡ 生成全站静态文件'); ?>
</a>
<a class="btn" href="<?php echo Helper::url('extending.php?panel=StaticSite%2FAction.php&clear=1'); ?>"
onclick="return confirm('确定要清除所有静态文件吗?');">
<?php _e('🗑️ 清除所有静态文件'); ?>
</a>
<a class="btn" href="<?php echo Helper::url('extending.php?panel=StaticSite%2FAction.php&rewrite=1'); ?>">
<?php _e('🔧 伪静态规则'); ?>
</a>
</div>
<div class="typecho-list">
<div class="typecho-table-wrap">
<table class="typecho-list-table">
<colgroup>
<col width="50%">
<col width="50%">
</colgroup>
<thead>
<tr>
<th colspan="2"><?php _e('使用说明'); ?></th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2">
<ol style="margin:10px 20px;">
<li>在插件配置中选择需要静态化的页面类型</li>
<li>配置伪静态规则(Apache/Nginx/IIS)确保优先访问静态文件</li>
<li>点击"生成全站静态文件"首次生成</li>
<li>启用自动生成后,发布/更新文章时会自动更新对应静态页</li>
<li>如需更新首页,可手动点击"生成全站静态文件"</li>
</ol>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<?php $this->need('footer.php'); ?>rewrite.php(伪静态规则页面)
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<?php $this->need('header.php'); ?>
<div class="typecho-page-title">
<h2>伪静态规则配置</h2>
</div>
<div class="row typecho-page-main">
<div class="col-mb-12 col-tb-8" style="margin:0 auto; float:none;">
<div class="typecho-list">
<?php foreach ($rewriteRules as $server => $rule): ?>
<div class="typecho-table-wrap" style="margin-bottom:20px;">
<table class="typecho-list-table">
<thead>
<tr>
<th><?php echo $rule['name']; ?></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<pre style="background:#f5f5f5; padding:10px; overflow-x:auto;"><?php echo htmlspecialchars($rule['code']); ?></pre>
<p style="margin:10px 0 0; color:#999;">
<small>将以上规则添加到您的服务器配置文件中</small>
</p>
</td>
</tr>
</tbody>
</table>
</div>
<?php endforeach; ?>
<div class="typecho-table-wrap">
<table class="typecho-list-table">
<thead>
<tr>
<th>注意事项</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<ul style="margin:10px 20px;">
<li>如果启用了插件内的URL重写模式,伪静态规则会自动处理,无需手动配置</li>
<li>如果禁用URL重写模式,请根据服务器类型配置上述规则</li>
<li>配置完成后,访问网站时会优先返回静态HTML文件,大幅提升加载速度</li>
<li>静态文件不存在时会自动回退到Typecho动态处理</li>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div style="margin:20px 0; text-align:center;">
<a class="btn primary" href="<?php echo Helper::url('extending.php?panel=StaticSite%2FAction.php'); ?>">
<?php _e('返回静态化管理'); ?>
</a>
</div>
</div>
</div>
<?php $this->need('footer.php'); ?>安装使用说明
安装步骤
- 在
/usr/plugins/目录下创建StaticSite文件夹 将上述三个文件放入该文件夹:
Plugin.phpAction.phppage.phprewrite.php
- 登录Typecho后台,进入"控制台"→"插件"→找到"StaticSite"点击"启用"
- 点击"设置"配置需要静态化的页面类型
配置选项说明
| 选项 | 说明 |
|---|---|
| 静态文件存储目录 | 生成的HTML文件存放位置,默认 /usr/uploads/static-site/ |
| 需要静态化的页面类型 | 选择要生成静态文件的页面(首页/文章/页面/分类/标签等) |
| URL重写模式 | 启用后自动处理优先访问静态文件,需服务器支持 |
| 自动生成模式 | 发布文章时自动生成对应的静态页面 |
| 排除的URL规则 | 不需要静态化的路径,支持通配符 |
伪静态配置
如果启用了"URL重写模式",需要在服务器配置对应规则。插件后台提供了Apache、Nginx、IIS的规则示例。
以Nginx为例:
location / {
# 尝试访问静态文件
set $static_file "/usr/uploads/static-site/${uri}.html";
if (-f $document_root$static_file) {
rewrite ^(.*)$ $static_file last;
}
# 否则交给PHP处理
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php/$1 last;
}
}使用方法
- 首次使用:点击"生成全站静态文件"生成所有页面
- 日常更新:开启"自动生成模式",发布文章时自动更新对应静态页
- 手动更新:如需刷新首页或特定页面,可重新生成
- 清除缓存:点击"清除所有静态文件"删除所有生成的HTML
注意事项
- 静态文件权限:确保存储目录可写(755权限)
- 评论功能:静态化后评论可能无法正常工作,建议使用第三方评论系统(如Disqus、Valine)
- 搜索功能:搜索页静态化后无法动态搜索,建议排除搜索页
- 插件兼容性:可能与某些修改输出的插件冲突
- 定期更新:如果手动修改了主题,需要重新生成静态文件
这个插件实现了Typecho站点的完整静态化,访问时直接返回HTML文件,大幅提升网站加载速度,降低服务器负载。
评论功能怎么办?静态化之后动态评论没法用了。我现在用的是第三方评论系统,完美解决。
The plugin structure is clean and well-organized. Plugin.php, Action.php, and separate template files. Easy to understand and modify if needed.
希望增加一个功能:生成完静态文件后自动ping百度、谷歌等搜索引擎。这样收录会快很多。
伪静态规则页面很贴心,把Apache、Nginx、IIS的配置都列出来了。不用自己查文档,直接复制粘贴就行。
用了三天了,一切正常。我的VPS负载从平均1.5降到了0.2,省下来的资源可以多跑几个站了。