|
|
<?php
|
|
|
/**
|
|
|
* SEO TDK 配置功能
|
|
|
* 支持设置不同页面的 SEO Title、Description、Keywords
|
|
|
*/
|
|
|
|
|
|
// 防止直接访问
|
|
|
if (!defined('ABSPATH')) {
|
|
|
exit;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 初始化 SEO 功能
|
|
|
*/
|
|
|
class NenghuiSEO {
|
|
|
|
|
|
public function __construct() {
|
|
|
add_action('init', array($this, 'init'));
|
|
|
}
|
|
|
|
|
|
public function init() {
|
|
|
// 添加后台菜单
|
|
|
add_action('admin_menu', array($this, 'add_admin_menu'));
|
|
|
|
|
|
// 添加文章和页面的SEO字段
|
|
|
add_action('add_meta_boxes', array($this, 'add_seo_meta_boxes'));
|
|
|
add_action('save_post', array($this, 'save_seo_meta_data'));
|
|
|
|
|
|
// 前端输出SEO标签
|
|
|
add_action('wp_head', array($this, 'output_seo_tags'), 1);
|
|
|
|
|
|
// 移除WordPress默认的title标签
|
|
|
remove_action('wp_head', '_wp_render_title_tag', 1);
|
|
|
|
|
|
// 注册设置
|
|
|
add_action('admin_init', array($this, 'register_settings'));
|
|
|
|
|
|
// 添加样式
|
|
|
add_action('admin_enqueue_scripts', array($this, 'admin_styles'));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 添加后台管理菜单
|
|
|
*/
|
|
|
public function add_admin_menu() {
|
|
|
add_menu_page(
|
|
|
'SEO设置',
|
|
|
'SEO设置',
|
|
|
'manage_options',
|
|
|
'nenghui-seo',
|
|
|
array($this, 'admin_page'),
|
|
|
'dashicons-search',
|
|
|
30
|
|
|
);
|
|
|
|
|
|
// 添加子菜单
|
|
|
add_submenu_page(
|
|
|
'nenghui-seo',
|
|
|
'全局SEO设置',
|
|
|
'全局设置',
|
|
|
'manage_options',
|
|
|
'nenghui-seo',
|
|
|
array($this, 'admin_page')
|
|
|
);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 注册设置选项
|
|
|
*/
|
|
|
public function register_settings() {
|
|
|
// 全局SEO设置
|
|
|
register_setting('nenghui_seo_global', 'nenghui_seo_global_title');
|
|
|
register_setting('nenghui_seo_global', 'nenghui_seo_global_description');
|
|
|
register_setting('nenghui_seo_global', 'nenghui_seo_global_keywords');
|
|
|
register_setting('nenghui_seo_global', 'nenghui_seo_separator');
|
|
|
register_setting('nenghui_seo_global', 'nenghui_seo_home_title');
|
|
|
register_setting('nenghui_seo_global', 'nenghui_seo_home_description');
|
|
|
register_setting('nenghui_seo_global', 'nenghui_seo_home_keywords');
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 添加后台样式
|
|
|
*/
|
|
|
public function admin_styles($hook) {
|
|
|
if (strpos($hook, 'nenghui-seo') !== false || $hook == 'post.php' || $hook == 'post-new.php') {
|
|
|
echo '<style>
|
|
|
.seo-meta-box { background: #fff; border: 1px solid #ccd0d4; box-shadow: 0 1px 1px rgba(0,0,0,.04); }
|
|
|
.seo-field { margin-bottom: 15px; }
|
|
|
.seo-field label { display: block; font-weight: 600; margin-bottom: 5px; }
|
|
|
.seo-field input, .seo-field textarea { width: 100%; padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px; }
|
|
|
.seo-field textarea { height: 80px; resize: vertical; }
|
|
|
.seo-field .description { font-size: 13px; color: #666; margin-top: 5px; }
|
|
|
.seo-preview { background: #f9f9f9; padding: 15px; border-radius: 4px; margin-top: 15px; }
|
|
|
.seo-preview h4 { margin: 0 0 10px 0; color: #333; }
|
|
|
.seo-title-preview { color: #1a0dab; font-size: 18px; text-decoration: none; }
|
|
|
.seo-url-preview { color: #006621; font-size: 14px; margin: 2px 0; }
|
|
|
.seo-desc-preview { color: #545454; font-size: 13px; line-height: 1.4; }
|
|
|
.char-count { float: right; font-size: 12px; color: #666; }
|
|
|
.char-count.warning { color: #d63638; }
|
|
|
</style>';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 后台管理页面
|
|
|
*/
|
|
|
public function admin_page() {
|
|
|
if (isset($_POST['submit'])) {
|
|
|
// 保存设置
|
|
|
update_option('nenghui_seo_global_title', sanitize_text_field($_POST['global_title']));
|
|
|
update_option('nenghui_seo_global_description', sanitize_textarea_field($_POST['global_description']));
|
|
|
update_option('nenghui_seo_global_keywords', sanitize_text_field($_POST['global_keywords']));
|
|
|
update_option('nenghui_seo_separator', sanitize_text_field($_POST['separator']));
|
|
|
update_option('nenghui_seo_home_title', sanitize_text_field($_POST['home_title']));
|
|
|
update_option('nenghui_seo_home_description', sanitize_textarea_field($_POST['home_description']));
|
|
|
update_option('nenghui_seo_home_keywords', sanitize_text_field($_POST['home_keywords']));
|
|
|
|
|
|
echo '<div class="notice notice-success"><p>设置已保存!</p></div>';
|
|
|
}
|
|
|
|
|
|
// 获取当前设置
|
|
|
$global_title = get_option('nenghui_seo_global_title', get_bloginfo('name'));
|
|
|
$global_description = get_option('nenghui_seo_global_description', get_bloginfo('description'));
|
|
|
$global_keywords = get_option('nenghui_seo_global_keywords', '');
|
|
|
$separator = get_option('nenghui_seo_separator', '-');
|
|
|
$home_title = get_option('nenghui_seo_home_title', '');
|
|
|
$home_description = get_option('nenghui_seo_home_description', '');
|
|
|
$home_keywords = get_option('nenghui_seo_home_keywords', '');
|
|
|
|
|
|
?>
|
|
|
<div class="wrap">
|
|
|
<h1>SEO 全局设置</h1>
|
|
|
<form method="post" action="">
|
|
|
<?php wp_nonce_field('nenghui_seo_nonce'); ?>
|
|
|
|
|
|
<table class="form-table">
|
|
|
<tr>
|
|
|
<th scope="row">标题分隔符</th>
|
|
|
<td>
|
|
|
<select name="separator">
|
|
|
<option value="-" <?php selected($separator, '-'); ?>>- (横线)</option>
|
|
|
<option value="|" <?php selected($separator, '|'); ?>>| (竖线)</option>
|
|
|
<option value="_" <?php selected($separator, '_'); ?>>_ (下划线)</option>
|
|
|
<option value="·" <?php selected($separator, '·'); ?>>· (中点)</option>
|
|
|
</select>
|
|
|
<p class="description">用于分隔页面标题和网站名称</p>
|
|
|
</td>
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
<th scope="row">全局网站标题</th>
|
|
|
<td>
|
|
|
<input type="text" name="global_title" value="<?php echo esc_attr($global_title); ?>" class="regular-text" />
|
|
|
<p class="description">网站的全局标题,会出现在所有页面标题的后面</p>
|
|
|
</td>
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
<th scope="row">全局网站描述</th>
|
|
|
<td>
|
|
|
<textarea name="global_description" rows="3" class="large-text"><?php echo esc_textarea($global_description); ?></textarea>
|
|
|
<p class="description">网站的全局描述,用于没有设置单独描述的页面</p>
|
|
|
</td>
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
<th scope="row">全局关键词</th>
|
|
|
<td>
|
|
|
<input type="text" name="global_keywords" value="<?php echo esc_attr($global_keywords); ?>" class="large-text" />
|
|
|
<p class="description">网站的全局关键词,用逗号分隔</p>
|
|
|
</td>
|
|
|
</tr>
|
|
|
</table>
|
|
|
|
|
|
<h2>首页专用设置</h2>
|
|
|
<table class="form-table">
|
|
|
<tr>
|
|
|
<th scope="row">首页标题</th>
|
|
|
<td>
|
|
|
<input type="text" name="home_title" value="<?php echo esc_attr($home_title); ?>" class="large-text" />
|
|
|
<p class="description">首页专用标题,留空则使用全局标题</p>
|
|
|
</td>
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
<th scope="row">首页描述</th>
|
|
|
<td>
|
|
|
<textarea name="home_description" rows="3" class="large-text"><?php echo esc_textarea($home_description); ?></textarea>
|
|
|
<p class="description">首页专用描述,留空则使用全局描述</p>
|
|
|
</td>
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
<th scope="row">首页关键词</th>
|
|
|
<td>
|
|
|
<input type="text" name="home_keywords" value="<?php echo esc_attr($home_keywords); ?>" class="large-text" />
|
|
|
<p class="description">首页专用关键词,留空则使用全局关键词</p>
|
|
|
</td>
|
|
|
</tr>
|
|
|
</table>
|
|
|
|
|
|
<?php submit_button('保存设置'); ?>
|
|
|
</form>
|
|
|
</div>
|
|
|
<?php
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 添加文章和页面的SEO元框
|
|
|
*/
|
|
|
public function add_seo_meta_boxes() {
|
|
|
$post_types = array('post', 'page', 'products', 'cases', 'download_center', 'faq');
|
|
|
|
|
|
foreach ($post_types as $post_type) {
|
|
|
add_meta_box(
|
|
|
'nenghui_seo_meta',
|
|
|
'SEO 设置',
|
|
|
array($this, 'seo_meta_box_callback'),
|
|
|
$post_type,
|
|
|
'normal',
|
|
|
'high'
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* SEO元框回调函数
|
|
|
*/
|
|
|
public function seo_meta_box_callback($post) {
|
|
|
wp_nonce_field('nenghui_seo_meta_nonce', 'nenghui_seo_meta_nonce_field');
|
|
|
|
|
|
$seo_title = get_post_meta($post->ID, '_nenghui_seo_title', true);
|
|
|
$seo_description = get_post_meta($post->ID, '_nenghui_seo_description', true);
|
|
|
$seo_keywords = get_post_meta($post->ID, '_nenghui_seo_keywords', true);
|
|
|
|
|
|
?>
|
|
|
<div class="seo-meta-box">
|
|
|
<div class="seo-field">
|
|
|
<label for="seo_title">SEO 标题</label>
|
|
|
<input type="text" id="seo_title" name="seo_title" value="<?php echo esc_attr($seo_title); ?>" maxlength="60" />
|
|
|
<span class="char-count" id="title-count">0/60</span>
|
|
|
<div class="description">建议长度:50-60个字符,留空则使用文章标题</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="seo-field">
|
|
|
<label for="seo_description">SEO 描述</label>
|
|
|
<textarea id="seo_description" name="seo_description" maxlength="160"><?php echo esc_textarea($seo_description); ?></textarea>
|
|
|
<span class="char-count" id="desc-count">0/160</span>
|
|
|
<div class="description">建议长度:120-160个字符,留空则自动提取文章摘要</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="seo-field">
|
|
|
<label for="seo_keywords">SEO 关键词</label>
|
|
|
<input type="text" id="seo_keywords" name="seo_keywords" value="<?php echo esc_attr($seo_keywords); ?>" />
|
|
|
<div class="description">多个关键词用逗号分隔,建议3-5个关键词</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="seo-preview">
|
|
|
<h4>搜索结果预览</h4>
|
|
|
<div class="seo-title-preview" id="preview-title"><?php echo esc_html($seo_title ?: $post->post_title); ?></div>
|
|
|
<div class="seo-url-preview"><?php echo esc_url(get_permalink($post->ID)); ?></div>
|
|
|
<div class="seo-desc-preview" id="preview-desc"><?php echo esc_html($seo_description ?: wp_trim_words($post->post_content, 20)); ?></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<script>
|
|
|
jQuery(document).ready(function($) {
|
|
|
function updateCharCount(input, counter, max) {
|
|
|
var length = $(input).val().length;
|
|
|
$(counter).text(length + '/' + max);
|
|
|
if (length > max * 0.9) {
|
|
|
$(counter).addClass('warning');
|
|
|
} else {
|
|
|
$(counter).removeClass('warning');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
function updatePreview() {
|
|
|
var title = $('#seo_title').val() || '<?php echo esc_js($post->post_title); ?>';
|
|
|
var desc = $('#seo_description').val() || '<?php echo esc_js(wp_trim_words($post->post_content, 20)); ?>';
|
|
|
$('#preview-title').text(title);
|
|
|
$('#preview-desc').text(desc);
|
|
|
}
|
|
|
|
|
|
$('#seo_title').on('input', function() {
|
|
|
updateCharCount(this, '#title-count', 60);
|
|
|
updatePreview();
|
|
|
}).trigger('input');
|
|
|
|
|
|
$('#seo_description').on('input', function() {
|
|
|
updateCharCount(this, '#desc-count', 160);
|
|
|
updatePreview();
|
|
|
}).trigger('input');
|
|
|
});
|
|
|
</script>
|
|
|
<?php
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 保存SEO元数据
|
|
|
*/
|
|
|
public function save_seo_meta_data($post_id) {
|
|
|
if (!isset($_POST['nenghui_seo_meta_nonce_field']) ||
|
|
|
!wp_verify_nonce($_POST['nenghui_seo_meta_nonce_field'], 'nenghui_seo_meta_nonce')) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (!current_user_can('edit_post', $post_id)) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (isset($_POST['seo_title'])) {
|
|
|
update_post_meta($post_id, '_nenghui_seo_title', sanitize_text_field($_POST['seo_title']));
|
|
|
}
|
|
|
|
|
|
if (isset($_POST['seo_description'])) {
|
|
|
update_post_meta($post_id, '_nenghui_seo_description', sanitize_textarea_field($_POST['seo_description']));
|
|
|
}
|
|
|
|
|
|
if (isset($_POST['seo_keywords'])) {
|
|
|
update_post_meta($post_id, '_nenghui_seo_keywords', sanitize_text_field($_POST['seo_keywords']));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 前端输出SEO标签
|
|
|
*/
|
|
|
public function output_seo_tags() {
|
|
|
$title = $this->get_seo_title();
|
|
|
$description = $this->get_seo_description();
|
|
|
$keywords = $this->get_seo_keywords();
|
|
|
|
|
|
// 输出标题
|
|
|
echo '<title>' . esc_html($title) . '</title>' . "\n";
|
|
|
|
|
|
// 输出描述
|
|
|
if ($description) {
|
|
|
echo '<meta name="description" content="' . esc_attr($description) . '" />' . "\n";
|
|
|
}
|
|
|
|
|
|
// 输出关键词
|
|
|
if ($keywords) {
|
|
|
echo '<meta name="keywords" content="' . esc_attr($keywords) . '" />' . "\n";
|
|
|
}
|
|
|
|
|
|
// Open Graph 标签
|
|
|
echo '<meta property="og:title" content="' . esc_attr($title) . '" />' . "\n";
|
|
|
if ($description) {
|
|
|
echo '<meta property="og:description" content="' . esc_attr($description) . '" />' . "\n";
|
|
|
}
|
|
|
echo '<meta property="og:url" content="' . esc_url($this->get_current_url()) . '" />' . "\n";
|
|
|
echo '<meta property="og:type" content="' . (is_single() ? 'article' : 'website') . '" />' . "\n";
|
|
|
|
|
|
// Twitter Card 标签
|
|
|
echo '<meta name="twitter:card" content="summary" />' . "\n";
|
|
|
echo '<meta name="twitter:title" content="' . esc_attr($title) . '" />' . "\n";
|
|
|
if ($description) {
|
|
|
echo '<meta name="twitter:description" content="' . esc_attr($description) . '" />' . "\n";
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取SEO标题
|
|
|
*/
|
|
|
private function get_seo_title() {
|
|
|
$separator = get_option('nenghui_seo_separator', '-');
|
|
|
$global_title = get_option('nenghui_seo_global_title', get_bloginfo('name'));
|
|
|
|
|
|
if (is_home() || is_front_page()) {
|
|
|
$home_title = get_option('nenghui_seo_home_title');
|
|
|
return $home_title ?: $global_title;
|
|
|
}
|
|
|
|
|
|
if (is_singular()) {
|
|
|
global $post;
|
|
|
$custom_title = get_post_meta($post->ID, '_nenghui_seo_title', true);
|
|
|
if ($custom_title) {
|
|
|
return $custom_title;
|
|
|
}
|
|
|
return $post->post_title . ' ' . $separator . ' ' . $global_title;
|
|
|
}
|
|
|
|
|
|
if (is_category()) {
|
|
|
$category = get_queried_object();
|
|
|
return $category->name . ' ' . $separator . ' ' . $global_title;
|
|
|
}
|
|
|
|
|
|
if (is_tag()) {
|
|
|
$tag = get_queried_object();
|
|
|
return $tag->name . ' ' . $separator . ' ' . $global_title;
|
|
|
}
|
|
|
|
|
|
if (is_archive()) {
|
|
|
return get_the_archive_title() . ' ' . $separator . ' ' . $global_title;
|
|
|
}
|
|
|
|
|
|
if (is_search()) {
|
|
|
return '搜索: ' . get_search_query() . ' ' . $separator . ' ' . $global_title;
|
|
|
}
|
|
|
|
|
|
if (is_404()) {
|
|
|
return '页面未找到 ' . $separator . ' ' . $global_title;
|
|
|
}
|
|
|
|
|
|
return $global_title;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取SEO描述
|
|
|
*/
|
|
|
private function get_seo_description() {
|
|
|
$global_description = get_option('nenghui_seo_global_description', get_bloginfo('description'));
|
|
|
|
|
|
if (is_home() || is_front_page()) {
|
|
|
$home_description = get_option('nenghui_seo_home_description');
|
|
|
return $home_description ?: $global_description;
|
|
|
}
|
|
|
|
|
|
if (is_singular()) {
|
|
|
global $post;
|
|
|
$custom_description = get_post_meta($post->ID, '_nenghui_seo_description', true);
|
|
|
if ($custom_description) {
|
|
|
return $custom_description;
|
|
|
}
|
|
|
|
|
|
// 自动提取摘要
|
|
|
if ($post->post_excerpt) {
|
|
|
return wp_trim_words($post->post_excerpt, 25);
|
|
|
}
|
|
|
|
|
|
return wp_trim_words(strip_tags($post->post_content), 25);
|
|
|
}
|
|
|
|
|
|
if (is_category()) {
|
|
|
$category = get_queried_object();
|
|
|
return $category->description ?: $global_description;
|
|
|
}
|
|
|
|
|
|
if (is_tag()) {
|
|
|
$tag = get_queried_object();
|
|
|
return $tag->description ?: $global_description;
|
|
|
}
|
|
|
|
|
|
return $global_description;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取SEO关键词
|
|
|
*/
|
|
|
private function get_seo_keywords() {
|
|
|
$global_keywords = get_option('nenghui_seo_global_keywords');
|
|
|
|
|
|
if (is_home() || is_front_page()) {
|
|
|
$home_keywords = get_option('nenghui_seo_home_keywords');
|
|
|
return $home_keywords ?: $global_keywords;
|
|
|
}
|
|
|
|
|
|
if (is_singular()) {
|
|
|
global $post;
|
|
|
$custom_keywords = get_post_meta($post->ID, '_nenghui_seo_keywords', true);
|
|
|
if ($custom_keywords) {
|
|
|
return $custom_keywords;
|
|
|
}
|
|
|
|
|
|
// 自动提取标签作为关键词
|
|
|
$tags = get_the_tags($post->ID);
|
|
|
if ($tags) {
|
|
|
$tag_names = array();
|
|
|
foreach ($tags as $tag) {
|
|
|
$tag_names[] = $tag->name;
|
|
|
}
|
|
|
return implode(', ', $tag_names);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return $global_keywords;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取当前页面URL
|
|
|
*/
|
|
|
private function get_current_url() {
|
|
|
global $wp;
|
|
|
return home_url(add_query_arg(array(), $wp->request));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 初始化SEO功能
|
|
|
new NenghuiSEO();
|