feat(ai): 后台摘要生成与 SEO 设置文案补齐

独立 SEO 框增加 AI 生成摘要写入 excerpt;全局 SEO schema 补充 AI 开关说明与提示词占位。
This commit is contained in:
2026-07-12 15:41:18 +08:00
parent b36186da65
commit 8fe708bf1e
4 changed files with 267 additions and 60 deletions
@@ -64,17 +64,17 @@ class AKSRT_Admin_Schema_Global {
'option_key' => 'aksrt_settings',
'groups' => [
['key' => 'basic', 'title' => 'SEO基础', 'fields' => [
['key' => 'seo_enabled', 'label' => '启用核心SEO优化', 'type' => 'switch', 'default' => true],
['key' => 'seo_ai_enabled', 'label' => 'AI生成SEO内容', 'type' => 'switch', 'default' => false],
['key' => 'seo_connector', 'label' => 'SEO连接符', 'type' => 'input', 'default' => '-'],
['key' => 'seo_enabled', 'label' => '启用核心SEO优化', 'type' => 'switch', 'default' => true, 'help' => '关闭后主题不再输出 SEO head 标签。'],
['key' => 'seo_ai_enabled', 'label' => 'AI生成SEO内容', 'type' => 'switch', 'default' => false, 'help' => '开启后文章/分类独立 SEO 框显示 AI 生成按钮;需配置 AI 连接(WP Connectors 或扩展 → AI 连接配置)。', 'dependsOn' => ['key' => 'seo_enabled', 'value' => true]],
['key' => 'seo_connector', 'label' => 'SEO连接符', 'type' => 'input', 'default' => '-', 'help' => 'AI 生成标题时用于追加站点名。'],
['key' => 'seo_title', 'label' => 'SEO标题(title)', 'type' => 'textarea', 'default' => ''],
['key' => 'seo_keywords', 'label' => 'SEO关键字(keywords)', 'type' => 'textarea', 'default' => ''],
['key' => 'seo_description', 'label' => 'SEO描述(description)', 'type' => 'textarea', 'default' => ''],
]],
['key' => 'ai-seo', 'title' => 'AI SEO', 'fields' => [
['key' => 'ai_seo_title_prompt', 'label' => '标题提示词', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'seo_ai_enabled', 'value' => true]],
['key' => 'ai_seo_keywords_prompt', 'label' => '关键词提示词', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'seo_ai_enabled', 'value' => true]],
['key' => 'ai_seo_description_prompt', 'label' => '描述提示词', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'seo_ai_enabled', 'value' => true]],
['key' => 'ai-seo', 'title' => 'AI SEO 提示词', 'fields' => [
['key' => 'ai_seo_title_prompt', 'label' => '标题提示词', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'seo_ai_enabled', 'value' => true], 'help' => '留空使用内置 Zibll 风格默认提示词。'],
['key' => 'ai_seo_keywords_prompt', 'label' => '关键词提示词', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'seo_ai_enabled', 'value' => true], 'help' => '留空使用内置默认。'],
['key' => 'ai_seo_description_prompt', 'label' => '描述提示词', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'seo_ai_enabled', 'value' => true], 'help' => '留空使用内置默认。'],
]],
['key' => 'baidu', 'title' => '百度SEO', 'fields' => [
['key' => 'seo_baidu_push', 'label' => '百度链接自动提交', 'type' => 'switch', 'default' => false],
+46 -10
View File
@@ -57,7 +57,8 @@ class AKSRT_SEO_Meta_Box {
$keywords = (string) get_post_meta($post->ID, self::META_KEYWORDS, true);
$description = (string) get_post_meta($post->ID, self::META_DESCRIPTION, true);
$ai_btn = $this->render_ai_button('post', (int) $post->ID);
$ai_btn = $this->render_ai_button('post', (int) $post->ID);
$summary_btn = $this->render_summary_button((int) $post->ID);
?>
<div class="aksrt-seo-meta-box">
<p>
@@ -73,6 +74,12 @@ class AKSRT_SEO_Meta_Box {
<textarea class="widefat" rows="3" id="aksrt_seo_description" name="aksrt_seo_description"><?php echo esc_textarea($description); ?></textarea>
<span class="description"><?php esc_html_e('建议 50–150 字。', 'aksrt'); ?><?php echo $ai_btn; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
</p>
<?php if ($summary_btn !== '') : ?>
<p class="aksrt-ai-summary-row">
<span class="description"><?php esc_html_e('写作辅助:根据正文生成摘要并填入「摘要」字段(不自动保存)。', 'aksrt'); ?></span>
<?php echo $summary_btn; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
</p>
<?php endif; ?>
</div>
<?php
}
@@ -200,24 +207,30 @@ class AKSRT_SEO_Meta_Box {
'ai' => [
'available' => !empty($status['available']),
'seo_ai_enabled' => !empty($seo['seo_ai_enabled']) && !empty($seo['seo_enabled']),
'write_assist' => !empty($status['available']),
],
'i18n' => [
'generating' => __('生成中…', 'aksrt'),
'generate' => __('AI 生成 SEO', 'aksrt'),
'success' => __('已填入 SEO 字段,请检查后更新保存', 'aksrt'),
'failed' => __('生成失败', 'aksrt'),
'needSave' => __('请先保存后再生成 SEO', 'aksrt'),
'notAvailable' => __('AI 未配置或未启用', 'aksrt'),
'generating' => __('生成中…', 'aksrt'),
'generate' => __('AI 生成 SEO', 'aksrt'),
'generateSummary' => __('AI 生成摘要', 'aksrt'),
'success' => __('已填入 SEO 字段,请检查后更新保存', 'aksrt'),
'summarySuccess' => __('已填入摘要字段,请检查后更新保存', 'aksrt'),
'failed' => __('生成失败', 'aksrt'),
'needSave' => __('请先保存后再生成 SEO', 'aksrt'),
'needContent' => __('请先填写正文内容', 'aksrt'),
'notAvailable' => __('AI 未配置或未启用', 'aksrt'),
'noExcerptField' => __('未找到摘要字段,请展开「摘要」面板', 'aksrt'),
],
]);
wp_add_inline_style('wp-admin', '
.aksrt-ai-seo-button{display:inline-block;margin-left:8px;vertical-align:middle}
.aksrt-ai-seo-generate{cursor:pointer}
.aksrt-ai-seo-generate.is-loading{opacity:.6;pointer-events:none}
.aksrt-ai-seo-generate,.aksrt-ai-summary-generate{cursor:pointer}
.aksrt-ai-seo-generate.is-loading,.aksrt-ai-summary-generate.is-loading{opacity:.6;pointer-events:none}
.aksrt-ai-seo-msg{display:block;margin-top:6px;font-size:12px}
.aksrt-ai-seo-msg.is-error{color:#b32d2e}
.aksrt-ai-seo-msg.is-ok{color:#007017}
.aksrt-ai-summary-row{margin-top:8px;padding-top:8px;border-top:1px solid #eee}
');
}
@@ -230,7 +243,7 @@ class AKSRT_SEO_Meta_Box {
$available = class_exists('AKSRT_AI') && AKSRT_AI::get_instance()->is_available();
$disabled = (!$available || $id <= 0) ? ' disabled' : '';
$title = !$available
? esc_attr__('请先配置 AI 连接(扩展 → AI 辅助 或 WP Connectors)', 'aksrt')
? esc_attr__('请先配置 AI 连接(扩展 → AI 连接配置 或 WP Connectors)', 'aksrt')
: ($id <= 0 ? esc_attr__('请先保存后再生成', 'aksrt') : '');
return sprintf(
@@ -242,4 +255,27 @@ class AKSRT_SEO_Meta_Box {
esc_html__('AI 生成 SEO', 'aksrt')
);
}
/**
* 后台「AI 生成摘要」→ 写入 WP 摘要字段(#excerpt / 块编辑器)。
*/
private function render_summary_button(int $post_id): string {
$available = class_exists('AKSRT_AI') && AKSRT_AI::get_instance()->is_available();
if (!$available) {
return '';
}
$disabled = $post_id <= 0 ? ' disabled' : '';
$title = $post_id <= 0
? esc_attr__('请先保存后再生成', 'aksrt')
: esc_attr__('根据正文生成摘要,填入摘要框', 'aksrt');
return sprintf(
'<span class="aksrt-ai-seo-button"><button type="button" class="button aksrt-ai-summary-generate"%s data-post-id="%d" title="%s">%s</button></span>',
$disabled,
$post_id,
$title,
esc_html__('AI 生成摘要', 'aksrt')
);
}
}