本文章中使用的 Change Permalink Helper 为修改版本,请注意
今天根据 Yoast!SEO 进行 SEO 优化处理的时候修改了 Wordpress 的固定链接。然后不出意外的:
这可不是什么好消息,死链对于 SEO 的影响巨大,但是 Wordpress 并不会自动重定向旧的固定链接格式到新的永久链接格式。
于是,我从 Wordpress 插件中心找到了 Change Permalink Helper 这个插件,但是,这个插件有两个问题:
- 由于多年没有更新,已经在最新版本的 Wordpress 无法使用了
- 只支持从
文章名
转换到其他固定链接格式 (这不符合我的使用需求,毕竟我是从朴素型
要转换到文章名
格式的
自己动手,丰衣足食
说干就干,开始分析插件,由于此插件使用 GPLv3+ 开源协议,可以在 Wordpress 的 SVN 仓库中找到 CPH 的源代码。
<?php # -*- coding: utf-8 -*-
/**
* Plugin Name: Change Permalink Helper
* Plugin URI: https://wordpress.org/plugins/change-permalink-helper
* Text Domain: change-permalink-helper
* Domain Path: /languages
* Description: It checks the Permalink and redirects to the new URL, if it doesn't exist. It sends the header message "moved permanently 301"
* Version: 1.1.1
* Author: Frank B眉ltge
* Author URI: https://bueltge.de/
* License: GPLv3+
*/
//avoid direct calls to this file, because now WP core and framework has been used
if ( ! function_exists( 'add_action' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
if ( ! class_exists( 'ChangePermalinkHelper' ) ) {
class ChangePermalinkHelper {
/**
* Constructor.
*/
public function __construct() {
add_action( 'plugins_loaded', array( $this, 'onLoad' ) );
}
/**
* I18n possibility, currently only for the translation service on wordpress.org/plugins/change-permalink-helper
*/
public function i18n() {
load_plugin_textdomain( 'change-permalink-helper', false, basename( dirname( __FILE__ ) ) . '/languages' );
}
/**
* Run in the WP environment, only front end.
*/
public function onLoad() {
if ( is_admin() ) {
return;
}
add_action( 'template_redirect', array( $this, 'is404' ) );
}
/**
* Return header message.
*
* @return bool
*/
public function is404() {
if ( ! is_404() ) {
return FALSE;
}
global $wpdb;
// get slug from url, preserve url-parameter
$request_array = explode( '?', $_SERVER['REQUEST_URI'] );
$slug = htmlspecialchars( basename( $request_array[0]) );
$params = isset( $request_array[1]) ? $request_array[1] : null;
$id = $wpdb->get_var(
$wpdb->prepare( "
SELECT ID
FROM $wpdb->posts
WHERE post_name = '%s'
AND post_status = 'publish'
", $slug )
);
if ( $id == null ) {
$url = get_permalink( $id );
if ($params) {
$url .= '?' . $params;
}
header( 'HTTP/1.1 301 Moved Permanently' );
header( 'Location: ' . $url );
return FALSE;
}
return TRUE;
}
} // end class
$ChangePermalinkHelper = new ChangePermalinkHelper();
}
由于 Wordpress 的 API 修改(大概?),header 重定向已经在我的环境下不起作用了。
因此我们要修改为使用 Wordpress 的原生重定向代码:
wp_redirect($url, 301, "Change Permlink Helper");
现在,该插件的重定向已经可以工作了。
但是,还有一个问题:我们需要让插件支持从 朴素型
重定向到其他类型的固定链接格式。
因此,我们需要修改一下 URL 解析部分的代码:
...
// search for post_name
$id = $wpdb->get_var(
$wpdb->prepare( "
SELECT ID
FROM $wpdb->posts
WHERE post_name = '%s'
AND post_status = 'publish'
", $slug )
);
// search for ID
if($id == null){
$id = $wpdb->get_var(
$wpdb->prepare( "
SELECT ID
FROM $wpdb->posts
WHERE ID = '%d'
AND post_status = 'publish'
", $slug )
);
}
...
现在,插件就可以支持朴素型的查找了,但是代价是会多一个 SQL 查询。如果有大佬,可以尝试合并为一个 SQL 查询。不过我的站点流量也不大,多一个查询也无所谓了(
完整成品
<?php # -*- coding: utf-8 -*-
/**
* Plugin Name: Change Permalink Helper
* Plugin URI: https://wordpress.org/plugins/change-permalink-helper
* Text Domain: change-permalink-helper
* Domain Path: /languages
* Description: It checks the Permalink and redirects to the new URL, if it doesn't exist. It sends the header message "moved permanently 301"
* Version: 1.1.1
* Author: Frank Bültge
* Author URI: https://bueltge.de/
* License: GPLv3+
*/
//avoid direct calls to this file, because now WP core and framework has been used
if ( ! function_exists( 'add_action' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
if ( ! class_exists( 'ChangePermalinkHelper' ) ) {
class ChangePermalinkHelper {
/**
* Constructor.
*/
public function __construct() {
add_action( 'plugins_loaded', array( $this, 'onLoad' ) );
}
/**
* I18n possibility, currently only for the translation service on wordpress.org/plugins/change-permalink-helper
*/
public function i18n() {
load_plugin_textdomain( 'change-permalink-helper', false, basename( dirname( __FILE__ ) ) . '/languages' );
}
/**
* Run in the WP environment, only front end.
*/
public function onLoad() {
if ( is_admin() ) {
return;
}
add_action( 'template_redirect', array( $this, 'is404' ) );
}
/**
* Return header message.
*
* @return bool
*/
public function is404() {
if ( ! is_404() ) {
return FALSE;
}
global $wpdb, $wp, $wp_rewrite;
// get slug from url, preserve url-parameter
$request_array = explode( '?', $_SERVER['REQUEST_URI'] );
$slug = htmlspecialchars( basename( $request_array[0]) );
$params = isset( $request_array[1]) ? $request_array[1] : null;
// search for post_name
$id = $wpdb->get_var(
$wpdb->prepare( "
SELECT ID
FROM $wpdb->posts
WHERE post_name = '%s'
AND post_status = 'publish'
", $slug )
);
// search for ID
if($id == null){
$id = $wpdb->get_var(
$wpdb->prepare( "
SELECT ID
FROM $wpdb->posts
WHERE ID = '%d'
AND post_status = 'publish'
", $slug )
);
}
if ( $id ) {
$url = get_permalink( $id );
if ($params) {
$url .= '?' . $params;
}
wp_redirect($url, 301, "Change Permlink Helper");
return FALSE;
}
return TRUE;
}
} // end class
$ChangePermalinkHelper = new ChangePermalinkHelper();
}
成品使用方法
首先安装官方的 Change Permalink Helper,然后使用 Wordpress 的插件编辑器,编辑 change-permalink-helper/change_permalink_helper.php
这个文件,并使用上述的代码替换。
测试环境
时过境迁,本文中的代码不可能一直有用,下面列出本文在撰写时的测试环境
Wordpress:5.8.2
PHP:PHP 8.0 with JIT enabled
MySQL:5.7.34
测试效果
点击这个链接,看看会不会自动跳转吧 :) https://www.ghostchu.com/archives/254