From e965f6ed68f56682f4f83aae31962b34c604feba Mon Sep 17 00:00:00 2001
From: XIGE <710062962@qq.com>
Date: Mon, 23 Feb 2026 17:21:48 +0800
Subject: [PATCH] 1.0
---
Plugin.php | 872 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 872 insertions(+)
create mode 100644 Plugin.php
diff --git a/Plugin.php b/Plugin.php
new file mode 100644
index 0000000..1581467
--- /dev/null
+++ b/Plugin.php
@@ -0,0 +1,872 @@
+write = array('CustomInlineTags_Plugin', 'parseTagsOnSave');
+ Typecho_Plugin::factory('Widget_Contents_Page_Edit')->write = array('CustomInlineTags_Plugin', 'parseTagsOnSave');
+
+ // 添加内容解析钩子
+ Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = array('CustomInlineTags_Plugin', 'parseContent');
+ Typecho_Plugin::factory('Widget_Abstract_Contents')->excerptEx = array('CustomInlineTags_Plugin', 'parseContent');
+
+ // 添加编辑器脚本 - 关键:使用header钩子添加脚本
+ Typecho_Plugin::factory('admin/header.php')->header = array('CustomInlineTags_Plugin', 'addHeader');
+ Typecho_Plugin::factory('admin/write-post.php')->bottom = array('CustomInlineTags_Plugin', 'addEditorButton');
+ Typecho_Plugin::factory('admin/write-page.php')->bottom = array('CustomInlineTags_Plugin', 'addEditorButton');
+
+ return _t('插件已激活');
+ }
+
+ /**
+ * 禁用插件
+ */
+ public static function deactivate()
+ {
+ return _t('插件已禁用');
+ }
+
+ /**
+ * 插件配置面板
+ */
+ public static function config(Typecho_Widget_Helper_Form $form)
+ {
+ // 标签样式设置
+ $style = new Typecho_Widget_Helper_Form_Element_Textarea('tagStyle',
+ NULL,
+ "display: inline-block;\nbackground: #f0f0f0;\ncolor: #333;\npadding: 2px 8px;\nmargin: 0 4px;\nborder-radius: 12px;\nfont-size: 0.9em;\nfont-weight: normal;\ntext-decoration: none;",
+ _t('标签样式'),
+ _t('自定义标签的CSS样式'));
+ $form->addInput($style);
+
+ // 标签前缀
+ $prefix = new Typecho_Widget_Helper_Form_Element_Text('tagPrefix',
+ NULL,
+ '#',
+ _t('标签前缀'),
+ _t('在标签前显示的前缀符号'));
+ $form->addInput($prefix);
+
+ // 是否启用标签链接
+ $enableLink = new Typecho_Widget_Helper_Form_Element_Radio('enableLink',
+ array(
+ '1' => _t('启用'),
+ '0' => _t('禁用')
+ ),
+ '1',
+ _t('启用标签链接'),
+ _t('点击标签是否跳转到标签页面'));
+ $form->addInput($enableLink);
+
+ // 伪静态标签链接格式
+ $tagUrlFormat = new Typecho_Widget_Helper_Form_Element_Text('tagUrlFormat',
+ NULL,
+ '/tag-{slug}.html',
+ _t('标签链接格式'),
+ _t('根据你的伪静态设置填写标签链接格式,{slug}会被替换为标签slug'));
+ $form->addInput($tagUrlFormat);
+
+ // 是否新窗口打开
+ $openNewWindow = new Typecho_Widget_Helper_Form_Element_Radio('openNewWindow',
+ array(
+ '1' => _t('是'),
+ '0' => _t('否')
+ ),
+ '1',
+ _t('新窗口打开'),
+ _t('点击标签是否在新窗口打开'));
+ $form->addInput($openNewWindow);
+ }
+
+ /**
+ * 个人配置面板
+ */
+ public static function personalConfig(Typecho_Widget_Helper_Form $form) {}
+
+ /**
+ * 获取所有标签
+ */
+ private static function getAllTags()
+ {
+ if (!empty(self::$_allTags)) {
+ return self::$_allTags;
+ }
+
+ try {
+ $db = Typecho_Db::get();
+ $rows = $db->fetchAll($db->select('name')
+ ->from('table.metas')
+ ->where('type = ?', 'tag')
+ ->order('name', Typecho_Db::SORT_ASC));
+
+ foreach ($rows as $row) {
+ self::$_allTags[] = $row['name'];
+ }
+ } catch (Exception $e) {
+ self::$_allTags = array();
+ }
+
+ return self::$_allTags;
+ }
+
+ /**
+ * 添加头部资源
+ */
+ public static function addHeader()
+ {
+ // 只在写文章/页面页面添加
+ if (strpos($_SERVER['REQUEST_URI'], 'write-post') !== false ||
+ strpos($_SERVER['REQUEST_URI'], 'write-page') !== false) {
+
+ // 获取所有标签并转为JSON
+ $allTags = self::getAllTags();
+ $tagsJson = json_encode($allTags);
+
+ echo '';
+
+ // 在JavaScript中嵌入标签数据
+ echo '';
+ }
+ }
+
+ /**
+ * 添加编辑器按钮 - 带标签联想搜索(本地搜索版)
+ */
+ public static function addEditorButton()
+ {
+ ?>
+
+
+ is('single')) {
+ return $content;
+ }
+
+ // 获取插件配置
+ $options = Helper::options()->plugin('CustomInlineTags');
+ $prefix = $options->tagPrefix ?: '#';
+ $style = $options->tagStyle ?: "display: inline-block; background: #f0f0f0; color: #333; padding: 2px 8px; margin: 0 4px; border-radius: 12px; font-size: 0.9em; font-weight: normal; text-decoration: none;";
+ $className = 'custom-inline-tag';
+ $enableLink = isset($options->enableLink) ? $options->enableLink : '1';
+ $tagUrlFormat = isset($options->tagUrlFormat) ? $options->tagUrlFormat : '/tag-{slug}.html';
+ $openNewWindow = isset($options->openNewWindow) ? $options->openNewWindow : '1';
+
+ // 替换短代码为HTML
+ $content = preg_replace_callback(
+ '/\[tag\]([^\[\]]+?)\[\/tag\]/',
+ function($matches) use ($prefix, $style, $className, $enableLink, $tagUrlFormat, $openNewWindow, $widget) {
+ $tagName = htmlspecialchars(trim($matches[1]), ENT_QUOTES, 'UTF-8');
+ $displayName = $prefix . $tagName;
+
+ if ($enableLink == '1' && $widget instanceof Widget_Archive) {
+ // 获取标签链接
+ $tagUrl = '';
+ try {
+ $db = Typecho_Db::get();
+ $tag = $db->fetchRow($db->select()
+ ->from('table.metas')
+ ->where('type = ?', 'tag')
+ ->where('name = ?', $tagName)
+ ->limit(1));
+
+ if ($tag) {
+ // 使用Typecho的标签链接生成方法
+ if (method_exists($widget, 'permalink')) {
+ // 创建临时对象获取标签链接
+ $reflection = new ReflectionClass($widget);
+ $params = $reflection->getProperty('_params');
+ $params->setAccessible(true);
+ $widgetParams = $params->getValue($widget);
+
+ // 临时修改参数获取标签链接
+ $originalParams = $widgetParams;
+ $widgetParams['type'] = 'tag';
+ $widgetParams['slug'] = $tag['slug'];
+
+ // 尝试获取标签链接
+ try {
+ $tagUrl = $widget->permalink;
+ } catch (Exception $e) {
+ // 如果失败,使用自定义格式
+ $tagSlug = urlencode($tag['slug']);
+ $tagUrl = str_replace('{slug}', $tagSlug, $tagUrlFormat);
+ $tagUrl = Typecho_Common::url($tagUrl, Helper::options()->index);
+ }
+
+ // 恢复原始参数
+ $params->setValue($widget, $originalParams);
+ } else {
+ // 使用自定义格式
+ $tagSlug = urlencode($tag['slug']);
+ $tagUrl = str_replace('{slug}', $tagSlug, $tagUrlFormat);
+ $tagUrl = Typecho_Common::url($tagUrl, Helper::options()->index);
+ }
+ }
+ } catch (Exception $e) {
+ // 出错时不添加链接
+ error_log('CustomInlineTags Error: ' . $e->getMessage());
+ }
+
+ if ($tagUrl) {
+ // 构建链接属性
+ $linkAttributes = sprintf('href="%s" class="%s" data-tag="%s" style="%s" title="查看标签相关文章"',
+ htmlspecialchars($tagUrl),
+ $className,
+ $tagName,
+ $style
+ );
+
+ // 如果启用了新窗口打开,添加target="_blank"
+ if ($openNewWindow == '1') {
+ $linkAttributes .= ' target="_blank"';
+ }
+
+ return sprintf('%s',
+ $linkAttributes,
+ $displayName
+ );
+ }
+ }
+
+ // 如果不启用链接或找不到标签
+ return sprintf(
+ '%s',
+ $className,
+ $tagName,
+ $style,
+ $displayName
+ );
+ },
+ $content
+ );
+
+ return $content;
+ }
+
+ /**
+ * 保存文章时提取标签并保存到数据库
+ */
+ public static function parseTagsOnSave($contents, $widget)
+ {
+ $content = $contents['text'];
+ $tags = array();
+
+ // 从短代码中提取标签
+ preg_match_all('/\[tag\]([^\[\]]+?)\[\/tag\]/', $content, $matches);
+
+ if (!empty($matches[1])) {
+ foreach ($matches[1] as $tag) {
+ $tag = trim($tag);
+ if (!empty($tag) && !in_array($tag, $tags)) {
+ $tags[] = $tag;
+ }
+ }
+ }
+
+ // 如果找到了标签,添加到文章的标签字段
+ if (!empty($tags)) {
+ // 获取现有的标签
+ $existingTags = isset($contents['tags']) ? $contents['tags'] : '';
+ $existingTagsArray = array_filter(array_map('trim', explode(',', $existingTags)));
+
+ // 合并标签并去重
+ $allTags = array_unique(array_merge($existingTagsArray, $tags));
+
+ // 更新标签字段
+ $contents['tags'] = implode(',', $allTags);
+ }
+
+ return $contents;
+ }
+}
\ No newline at end of file