Files
EditHistory/Plugin.php

943 lines
31 KiB
PHP
Raw Permalink Normal View History

2026-02-23 17:26:10 +08:00
<?php
/**
* 文章编辑历史
*
* @package EditHistory
* @version 5.4.0
* @author 石头厝
* @link https://www.shitoucuo.com
*/
class EditHistory_Plugin implements Typecho_Plugin_Interface
{
private static $tableName = 'edit_history';
public static function activate()
{
self::createTable();
Typecho_Plugin::factory('Widget_Contents_Post_Edit')->write = array(__CLASS__, 'saveEditHistory');
Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = array(__CLASS__, 'parseContent');
Typecho_Plugin::factory('Widget_Archive')->header = array(__CLASS__, 'outputHeader');
// 🔥 新增:文章删除时同时删除编辑历史
Typecho_Plugin::factory('Widget_Contents_Post_Edit')->delete = array(__CLASS__, 'deletePostHistory');
// 添加后台管理菜单 - 使用正确的Helper方法
Helper::addPanel(1, 'EditHistory/manage-panel.php', '历史管理', '查看编辑历史', 'administrator');
return '编录插件已激活';
}
public static function deactivate()
{
// 使用Helper::removePanel()方法正确移除菜单
try {
Helper::removePanel(1, 'EditHistory/manage-panel.php');
} catch (Exception $e) {
// 如果Helper方法失败尝试直接删除数据库记录
try {
$db = Typecho_Db::get();
$db->query($db->delete('table.options')
->where('name = ?', 'panel:EditHistory/manage-panel.php'));
} catch (Exception $e2) {
// 静默失败
}
}
return '编辑记录插件已禁用';
}
public static function config(Typecho_Widget_Helper_Form $form)
{
$position = new Typecho_Widget_Helper_Form_Element_Radio(
'position',
array('auto' => '自动在文章末尾显示', 'manual' => '手动调用', 'both' => '两者都显示'),
'auto',
'显示位置'
);
$form->addInput($position);
$maxRecords = new Typecho_Widget_Helper_Form_Element_Text('maxRecords', NULL, '10', '最大显示记录数');
$maxRecords->input->setAttribute('type', 'number');
$form->addInput($maxRecords);
$showPublishDays = new Typecho_Widget_Helper_Form_Element_Radio(
'showPublishDays',
array('1' => '显示', '0' => '不显示'),
'1',
'显示发布天数'
);
$form->addInput($showPublishDays);
$timeFormat = new Typecho_Widget_Helper_Form_Element_Select(
'timeFormat',
array('detail' => '详细格式', 'simple' => '简洁格式', 'relative' => '相对时间'),
'detail',
'时间显示格式'
);
$form->addInput($timeFormat);
$showSummary = new Typecho_Widget_Helper_Form_Element_Radio(
'showSummary',
array('1' => '显示', '0' => '不显示'),
'1',
'显示编辑摘要'
);
$form->addInput($showSummary);
$summaryLength = new Typecho_Widget_Helper_Form_Element_Text('summaryLength', NULL, '100', '摘要长度');
$form->addInput($summaryLength);
$requireEditSummary = new Typecho_Widget_Helper_Form_Element_Radio(
'requireEditSummary',
array('1' => '启用(必填)', '0' => '禁用(可选)'),
'0',
'编辑摘要必填'
);
$form->addInput($requireEditSummary);
$editSummaryPlaceholder = new Typecho_Widget_Helper_Form_Element_Text(
'editSummaryPlaceholder',
NULL,
'请简要描述本次编辑的内容(例如:修正错别字、更新数据、补充说明等)',
'编辑摘要提示文字'
);
$form->addInput($editSummaryPlaceholder);
$defaultCollapsed = new Typecho_Widget_Helper_Form_Element_Radio(
'defaultCollapsed',
array('1' => '默认收起', '0' => '默认展开'),
'1',
'默认显示状态'
);
$form->addInput($defaultCollapsed);
}
public static function personalConfig(Typecho_Widget_Helper_Form $form) {}
private static function createTable()
{
try {
$db = Typecho_Db::get();
$prefix = $db->getPrefix();
$sql = "CREATE TABLE IF NOT EXISTS `{$prefix}edit_history` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`cid` int(10) unsigned NOT NULL,
`editor` int(10) unsigned DEFAULT NULL,
`edit_time` int(10) unsigned NOT NULL,
`edit_content` text,
`edit_type` varchar(20) DEFAULT 'update',
PRIMARY KEY (`id`),
KEY `idx_cid` (`cid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
$db->query($sql);
} catch (Exception $e) {
// 静默失败
}
}
/**
* 🔥 新增:删除文章时同时删除编辑历史
*/
public static function deletePostHistory($cid, $widget)
{
try {
$db = Typecho_Db::get();
// 删除该文章的所有编辑历史
$db->query($db->delete('table.' . self::$tableName)
->where('cid = ?', $cid));
} catch (Exception $e) {
// 静默失败
}
return $cid;
}
/**
* 保存编辑记录
*/
public static function saveEditHistory($contents, $widget)
{
try {
$db = Typecho_Db::get();
// 只在有文章ID时保存
if ($widget->cid) {
// 🔥 关键修复:检查是否是真正的发布操作
// 获取当前文章状态
$currentStatus = $widget->status;
// 🔥 重要:草稿状态下的任何操作都不应该记录编辑历史
if ($currentStatus === 'draft' || $currentStatus === 'waiting' || $currentStatus === 'private') {
// 草稿、待审核、私密文章状态下的任何保存都不记录
return $contents;
}
// 🔥 重要:只有已发布的文章才可能记录编辑历史
if ($currentStatus !== 'publish') {
return $contents;
}
// 🔥 现在只处理已发布文章的编辑
// 检查是否是真正的用户编辑操作
$isRealEdit = false;
// 方法1检查是否有编辑摘要用户主动填写了编辑说明
if (isset($_POST['fields']['editSummary']) && !empty(trim($_POST['fields']['editSummary']))) {
$isRealEdit = true;
}
// 方法2检查是否有明确的发布操作
if (isset($_POST['do']) && $_POST['do'] === 'publish') {
// 已经是发布状态,检查是否有内容变化
if (!$isRealEdit) {
// 检查文章内容是否有变化(简单判断)
$oldContent = $widget->text;
$newContent = isset($_POST['text']) ? $_POST['text'] : '';
if ($oldContent != $newContent) {
$isRealEdit = true;
}
}
}
// 方法3检查自动保存标记 - 排除自动保存
$isAutoSave = false;
if (isset($_POST['_']) || isset($_POST['autoSave']) || isset($_POST['autosave'])) {
$isAutoSave = true;
}
// 方法4检查时间间隔 - 短时间内重复提交可能是自动保存
static $lastSaveTime = 0;
$currentTime = time();
if ($currentTime - $lastSaveTime < 10) { // 10秒内重复保存
$isAutoSave = true;
}
// 方法5检查是否是保存草稿或预览
if (isset($_POST['do']) && ($_POST['do'] === 'save' || $_POST['do'] === 'preview')) {
return $contents; // 直接返回,不记录
}
// 🔥 最终判断:只有真正的编辑操作才记录
if (!$isRealEdit || $isAutoSave) {
return $contents;
}
// 更新最后保存时间
$lastSaveTime = $currentTime;
$user = Typecho_Widget::widget('Widget_User');
$time = time();
// 获取编辑摘要
$editSummary = '';
// 从POST数据中获取编辑摘要
if (isset($_POST['fields']['editSummary'])) {
$editSummary = trim($_POST['fields']['editSummary']);
}
// 准备编辑内容摘要
$summaryContent = '';
if (!empty($editSummary)) {
$summaryContent = $editSummary;
} else {
$summaryContent = '未填写编辑说明';
}
// 保存到数据库
$data = array(
'cid' => $widget->cid,
'editor' => $user->uid ? $user->uid : 1,
'edit_time' => $time,
'edit_content' => $summaryContent,
'edit_type' => 'update'
);
// 执行数据库插入
try {
$result = $db->query($db->insert('table.' . self::$tableName)->rows($data));
} catch (Exception $e) {
// 静默失败
}
}
} catch (Exception $e) {
// 静默失败
}
return $contents;
}
/**
* 提供给主题的字段添加方法
*/
public static function addFieldToLayout($layout)
{
$options = Typecho_Widget::widget('Widget_Options');
$pluginOptions = $options->plugin('EditHistory');
$placeholder = isset($pluginOptions->editSummaryPlaceholder) ?
$pluginOptions->editSummaryPlaceholder :
'请简要描述本次编辑的内容(例如:修正错别字、更新数据、补充说明等)';
$required = isset($pluginOptions->requireEditSummary) && $pluginOptions->requireEditSummary == '1';
$editSummary = new Typecho_Widget_Helper_Form_Element_Textarea(
'editSummary',
NULL,
NULL,
'编辑说明',
'此备注会显示在文章的编辑记录中,修改一次填写一次,自动记录修改'
);
$editSummary->input->setAttribute('rows', '4');
$editSummary->input->setAttribute('placeholder', $placeholder);
$editSummary->input->setAttribute('style', 'width: 100%; padding: 10px; border-radius: 4px; resize: vertical;');
// 使用 fields[] 数组作为name这是Typecho自定义字段的标准方式
$editSummary->input->setAttribute('name', 'fields[editSummary]');
$layout->addItem($editSummary);
}
private static function getContentSummary($content, $length = 100)
{
if (empty($content)) return '';
$content = strip_tags($content);
$content = trim($content);
return Typecho_Common::subStr($content, 0, $length, '...');
}
/**
* 输出CSS样式和JavaScript
*/
public static function outputHeader()
{
echo '<style>
.edit-history-container {
margin: 0 0;
padding: 0;
width:100%;
}
.edit-history-box {
border-radius: 10px;
background: #ffffff;
overflow: hidden;
}
.dark .edit-history-box {
background: rgb(30 41 59 / var(--tw-bg-opacity));
}
.edit-history-header {
padding: 18px 24px;
background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
color: white;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
user-select: none;
}
.dark .edit-history-header {
background: rgb(10 12 25 / var(--tw-bg-opacity));
}
.edit-history-title {
font-size: 18px;
font-weight: 600;
margin: 0;
display: flex;
align-items: center;
gap: 10px;
}
.edit-history-count {
background: rgba(255,255,255,0.2);
padding: 2px 8px;
border-radius: 12px;
font-size: 13px;
}
.edit-history-toggle {
background: rgba(255,255,255,0.2);
border: none;
color: white;
padding: 6px 12px;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
font-weight: 500;
display: flex;
align-items: center;
gap: 6px;
transition: all 0.3s ease;
}
.edit-history-toggle:hover {
background: rgba(255,255,255,0.3);
transform: translateY(-1px);
}
.edit-history-toggle .icon {
font-size: 14px;
transition: transform 0.3s ease;
}
.edit-history-toggle.collapsed .icon {
transform: rotate(180deg);
}
.edit-history-content-wrapper {
overflow: hidden;
transition: max-height 0.5s ease;
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
background: #ffffff;
}
.dark .edit-history-content-wrapper {
background: rgb(30 41 59 / var(--tw-bg-opacity));
}
.publish-info {
padding: 16px 24px;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
color: #495057;
font-size: 14px;
line-height: 1.6;
margin:0 auto;
}
.dark .publish-info {
background: rgb(51 65 85 / var(--tw-bg-opacity));
color: #cbd5e1;
}
.publish-days {
color: #dc2626;
background: rgba(106, 17, 203, 0.1);
padding: 5px 15px;
border-radius:20px;
}
.dark .publish-days {
background: rgb(10 12 25 / var(--tw-bg-opacity)) !important;
color: rgb(156 163 175 / var(--tw-text-opacity)) !important;
}
.edit-history-list {
list-style: none;
padding: 0;
margin: 0;
}
.edit-history-item {
padding: 18px 24px;
border-bottom: 1px solid #f1f3f5;
transition: all 0.3s ease;
position: relative;
}
.dark .edit-history-item {
border-bottom: 1px solid #334155;
}
.edit-history-item:last-child {
border-bottom: none;
}
.edit-history-item:hover {
background-color: #f8f9fa;
}
.dark .edit-history-item:hover {
background-color: rgb(51 65 85 / var(--tw-bg-opacity));
}
.edit-history-item.create-item {
background-color: #f0f7ff;
}
.dark .edit-history-item.create-item {
background-color: rgb(30 58 138 / 0.2);
}
.edit-history-time {
font-size: 13px;
color: #666;
margin-bottom: 6px;
display: flex;
align-items: center;
gap: 6px;
}
.dark .edit-history-time {
color: #cbd5e1;
}
.edit-history-author {
font-size: 15px;
color: #333;
margin-bottom: 8px;
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.dark .edit-history-author {
color: #e2e8f0;
}
.edit-history-action {
display: inline-block;
padding: 3px 10px;
border-radius: 15px;
font-size: 12px;
font-weight: 500;
}
.edit-history-action.create {
background: #1890ff;
color: white;
}
.edit-history-action.update {
background: #52c41a;
color: white;
}
.dark .edit-history-action.update{
background: rgb(10 12 25 / var(--tw-bg-opacity)) !important;
color: rgb(156 163 175 /1) !important;
}
.edit-history-summary {
display: inline-block;
margin-left: 8px;
font-size: 14px;
color: #666;
vertical-align: middle;
}
.dark .edit-history-summary {
color: #cbd5e1;
}
.edit-history-summary-text {
color: #1890ff;
font-weight: 500;
}
.dark .edit-history-summary-text {
color: #60a5fa;
}
.edit-history-summary-default {
color: #999;
}
.dark .edit-history-summary-default {
color: #94a3b8;
}
.edit-history-empty {
padding: 60px 24px;
color: #adb5bd;
font-size: 15px;
}
.dark .edit-history-empty {
color: #64748b;
}
.edit-history-footer {
padding: 14px 24px;
background: #f8f9fa;
font-size: 12px;
color: #868e96;
text-align: center;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
}
.dark .edit-history-footer {
background: rgb(51 65 85 / var(--tw-bg-opacity));
color: #94a3b8;
}
@media (max-width: 768px) {
.edit-history-box {
border-radius: 8px;
margin: 30px 0;
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.05);
}
.edit-history-header,
.edit-history-item,
.publish-info {
padding: 14px 16px;
}
.edit-history-footer {
flex-direction: column;
gap: 8px;
padding: 12px 16px;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
.edit-history-title {
font-size: 16px;
}
.edit-history-summary {
margin-left: 0;
margin-top: 4px;
display: block;
width: 100%;
}
.edit-history-content-wrapper {
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
}
</style>';
}
public static function parseContent($content, $widget, $lastResult)
{
$content = empty($lastResult) ? $content : $lastResult;
if ($widget->is('single')) {
$options = Typecho_Widget::widget('Widget_Options');
$pluginOptions = $options->plugin('EditHistory');
$position = isset($pluginOptions->position) ? $pluginOptions->position : 'auto';
// 检查是否有编辑记录
$hasEditHistory = self::hasEditHistory($widget->cid);
// 只要有编辑记录就显示
if ($hasEditHistory) {
if ($position === 'auto' || $position === 'both') {
$editHistory = self::renderEditHistory($widget->cid);
if ($editHistory) {
$content .= $editHistory;
}
}
}
}
return $content;
}
/**
* 判断文章是否有编辑记录
*/
private static function hasEditHistory($cid)
{
try {
$db = Typecho_Db::get();
// 检查是否有更新记录
$updateCount = $db->fetchRow($db->select('COUNT(*) as count')
->from('table.' . self::$tableName)
->where('cid = ?', $cid));
return $updateCount && $updateCount['count'] > 0;
} catch (Exception $e) {
return false;
}
}
/**
* 渲染编辑记录HTML
*/
public static function renderEditHistory($cid = null)
{
if (!$cid) {
$widget = Typecho_Widget::widget('Widget_Archive');
if (!$widget->is('single')) return '';
$cid = $widget->cid;
}
try {
$db = Typecho_Db::get();
$options = Typecho_Widget::widget('Widget_Options');
$pluginOptions = $options->plugin('EditHistory');
// 获取文章信息
$post = $db->fetchRow($db->select('created', 'authorId')
->from('table.contents')
->where('cid = ?', $cid)
->where('type = ?', 'post')
->limit(1));
if (!$post) return '';
// 获取所有编辑记录
$maxRecords = isset($pluginOptions->maxRecords) ? intval($pluginOptions->maxRecords) : 10;
$limit = $maxRecords > 0 ? $maxRecords : 1000;
// 查询所有编辑记录,按时间倒序排列(最新的在最前面)
$history = $db->fetchAll($db->select(
'id',
'edit_time',
'edit_content',
'edit_type',
'editor'
)
->from('table.' . self::$tableName)
->where('cid = ?', $cid)
->order('edit_time', Typecho_Db::SORT_DESC)
->limit($limit));
if (empty($history)) return '';
// 计算正确的编辑次数
$totalEdits = count($history);
// 不使用引用传递,创建新数组
$formattedHistory = array();
foreach ($history as $index => $record) {
$formattedRecord = $record; // 复制数组,不使用引用
$formattedRecord['edit_number'] = $totalEdits - $index;
$formattedHistory[] = $formattedRecord;
}
// 获取用户信息
$userIds = array();
foreach ($formattedHistory as $record) {
if ($record['editor']) {
$userIds[$record['editor']] = $record['editor'];
}
}
$users = array();
if (!empty($userIds)) {
$userResults = $db->fetchAll($db->select('uid', 'screenName', 'name')
->from('table.users')
->where('uid IN (' . implode(',', $userIds) . ')'));
foreach ($userResults as $user) {
$users[$user['uid']] = $user;
}
}
// 计算发布天数
$publishDays = '';
if (isset($pluginOptions->showPublishDays) && $pluginOptions->showPublishDays == '1') {
$days = self::calculateDaysFromPublish($post['created']);
$publishDays = '<div class="publish-info">
<span class="publish-days">本文发布于' . $days . '前,内容可能有时效性,注意参考阅读</span>
</div>';
}
// 获取默认收起/展开设置
$defaultCollapsed = isset($pluginOptions->defaultCollapsed) && $pluginOptions->defaultCollapsed == '1';
$collapseClass = $defaultCollapsed ? 'collapsed' : '';
$toggleText = $defaultCollapsed ? '<!--展开-->' : '<!--收起-->';
$icon = $defaultCollapsed ? '↓' : '↑';
// 生成HTML
$html = '<div class="edit-history-container">
<div class="edit-history-box">
<div class="edit-history-header" onclick="toggleEditHistory(this)">
<h3 class="edit-history-title">
<!--📝-->编辑记录
<span class="edit-history-count">' . count($formattedHistory) . '</span>
</h3>
<button class="editHistory-toggle ' . $collapseClass . '">
<span class="icon1">' . $icon . '</span>
<span class="text">' . $toggleText . '</span>
</button>
</div>
<div class="edit-history-content-wrapper" style="' . ($defaultCollapsed ? 'max-height: 0;' : 'max-height: 2000px;') . '">
' . $publishDays . '
<ul class="edit-history-list">';
foreach ($formattedHistory as $record) {
$timeFormat = isset($pluginOptions->timeFormat) ? $pluginOptions->timeFormat : 'detail';
$editTime = self::formatTime($record['edit_time'], $timeFormat);
// 显示第几次编辑
$editNumber = $record['edit_number'];
$actionText = "{$editNumber}次编辑";
// 获取作者名称
$authorName = '系统';
if ($record['editor'] && isset($users[$record['editor']])) {
$user = $users[$record['editor']];
if (!empty($user['screenName'])) {
$authorName = $user['screenName'];
} elseif (!empty($user['name'])) {
$authorName = $user['name'];
}
}
$html .= '<li class="edit-history-item update-item">
<div class="edit-history-time">🕒 ' . $editTime . '</div>
<div class="edit-history-author">
<span class="edit-history-action update">' . $actionText . '</span>
编辑人:' . htmlspecialchars($authorName);
// 显示编辑摘要
if (isset($pluginOptions->showSummary) && $pluginOptions->showSummary == '1' &&
!empty($record['edit_content'])) {
$content = $record['edit_content'];
// 判断是否是用户填写的摘要
if ($content != '未填写编辑说明') {
$html .= '<span class="edit-history-summary"> 修改摘要:<span class="edit-history-summary-text">' . htmlspecialchars($content) . '</span></span>';
} else {
$html .= '<span class="edit-history-summary"> 修改摘要:<span class="edit-history-summary-default">' . htmlspecialchars($content) . '</span></span>';
}
}
$html .= '</div></li>';
}
$html .= '</ul>
<div class="edit-history-footer">
<div>本文共有' . count($formattedHistory) . '次编辑修改记录</div>
<div>最后编辑:' . self::formatTime($formattedHistory[0]['edit_time'], $timeFormat) . '</div>
</div>
</div>
</div>
</div>
<script>
function toggleEditHistory(header) {
var wrapper = header.nextElementSibling;
var toggleBtn = header.querySelector(".editHistory-toggle");
var icon = toggleBtn.querySelector(".icon");
var text = toggleBtn.querySelector(".text");
if (wrapper.style.maxHeight && wrapper.style.maxHeight !== "0px") {
// 收起
wrapper.style.maxHeight = "0";
toggleBtn.classList.add("collapsed");
icon.textContent = "";
text.textContent = "";
} else {
// 展开
wrapper.style.maxHeight = wrapper.scrollHeight + "px";
toggleBtn.classList.remove("collapsed");
icon.textContent = "";
text.textContent = "";
}
}
// 初始设置
document.addEventListener("DOMContentLoaded", function() {
var wrappers = document.querySelectorAll(".edit-history-content-wrapper");
for (var i = 0; i < wrappers.length; i++) {
var wrapper = wrappers[i];
if (!wrapper.style.maxHeight) {
var header = wrapper.previousElementSibling;
var toggleBtn = header.querySelector(".editHistory-toggle");
if (toggleBtn.classList.contains("collapsed")) {
wrapper.style.maxHeight = "0";
} else {
wrapper.style.maxHeight = wrapper.scrollHeight + "px";
}
}
}
});
</script>';
return $html;
} catch (Exception $e) {
return '';
}
}
private static function calculateDaysFromPublish($publishTime)
{
$currentTime = time();
$diff = $currentTime - $publishTime;
$days = floor($diff / 86400);
if ($days == 0) {
$hours = floor($diff / 3600);
if ($hours == 0) {
$minutes = floor($diff / 60);
return $minutes > 0 ? $minutes . '分钟' : '刚刚';
}
return $hours . '小时';
} elseif ($days == 1) {
return '1天';
} else {
return $days . '天'; // 🔥 修改超过1天全部显示为天数
}
}
private static function formatTime($timestamp, $format)
{
switch ($format) {
case 'simple':
return date('Y年m月d日', $timestamp);
case 'relative':
return self::getRelativeTime($timestamp);
default:
return date('Y年m月d日 H:i', $timestamp);
}
}
private static function getRelativeTime($timestamp)
{
$current = time();
$diff = $current - $timestamp;
if ($diff < 60) return '刚刚';
elseif ($diff < 3600) return floor($diff / 60) . '分钟前';
elseif ($diff < 86400) return floor($diff / 3600) . '小时前';
elseif ($diff < 2592000) return floor($diff / 86400) . '天前';
else return floor($diff / 86400) . '天前'; // 🔥 修改超过30天也显示为天数
}
public static function output()
{
return self::renderEditHistory();
}
/**
* 获取文章永久链接
* 修改方法使用Typecho的标准方法获取文章链接
*/
public static function getPostPermalink($cid)
{
try {
$db = Typecho_Db::get();
$post = $db->fetchRow($db->select('slug', 'type', 'created')
->from('table.contents')
->where('cid = ?', $cid)
->where('type = ?', 'post')
->limit(1));
if (!$post) return '#';
// 使用Typecho的标准方法获取文章对象
$widget = Typecho_Widget::widget('Widget_Archive', array('type' => 'single'), array('cid' => $cid));
// 直接返回文章的永久链接
return $widget->permalink;
} catch (Exception $e) {
// 如果上述方法失败尝试简单构造URL
try {
$options = Typecho_Widget::widget('Widget_Options');
$siteUrl = rtrim($options->siteUrl, '/');
// 查询文章slug
$db = Typecho_Db::get();
$post = $db->fetchRow($db->select('slug')
->from('table.contents')
->where('cid = ?', $cid)
->limit(1));
if ($post && !empty($post['slug'])) {
return $siteUrl . '/' . $post['slug'] . '.html';
}
} catch (Exception $e2) {
return '#';
}
return '#';
}
}
}