使用 Change Permalink Helper 解决修改固定链接后的问题

使用 Change Permalink Helper 解决修改固定链接后的问题

本文章中使用的 Change Permalink Helper 为修改版本,请注意 今天根据 Yoast!SEO 进行 SEO 优化处理的时候修改了 Wordpress 的固定链接。然后不出意外的:

本文章中使用的 Change Permalink Helper 为修改版本,请注意

今天根据 Yoast!SEO 进行 SEO 优化处理的时候修改了 Wordpress 的固定链接。然后不出意外的:

404 Not Found

这可不是什么好消息,死链对于 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

Comment