WordPress从自己服务器更新插件、主题

如果您正在开发待售插件,这将很有帮助,如果你不是开发者,那可以划走了。wordpress支持了从自己服务器更新我们自己的插件、主题,而无需将其托管至wordpress。下面,我们就详细介绍其部署方法,帮助像我一样需要的人。

插件

插件主要用到三个过滤钩子:

1、plugins_api (插件信息,这里用来更改插件信息的,对于更新没有任何鸟用)

2、site_transient_update_plugins (临时缓存,这里用来更新插件)

3、upgrader_process_complete (更新完成执行,这里用来清理缓存‎)

示例插件代码(你可以将其放到你的插件代码中,然后修改info.json的地址即可,我的示例插件目录结构是这样的[kekc_cn_-update-plugin/kekc_cn_-update-plugin.php]):

<?php
/*
 * Plugin name: 自定义服务器更新插件示例
 * Description: 自定义服务器更新插件示例,实现从插件从自己服务器更新插件
 * Version: 1.0
 * Author: KEKC
 * Author URI: https://www.kekc.cn
 * License: GPL
 */

/**/


defined( 'ABSPATH' ) || exit;


if( ! class_exists( 'kekc_cn_UpdateChecker' ) ) {

	class kekc_cn_UpdateChecker{

		public $plugin_slug;
		public $version;
		public $cache_key;
		public $cache_allowed;

		public function __construct() {

			$this->plugin_slug = plugin_basename( __DIR__ );
			$this->version = '1.0';
			$this->cache_key = 'kekc_cn__custom_upd';
			$this->cache_allowed = false;

			add_filter( 'plugins_api', array( $this, 'info' ), 20, 3 );
			add_filter( 'site_transient_update_plugins', array( $this, 'update' ) );
			add_action( 'upgrader_process_complete', array( $this, 'purge' ), 10, 2 );

		}

		public function request(){

			$remote = get_transient( $this->cache_key );

			if( false === $remote || ! $this->cache_allowed ) {

				$remote = wp_remote_get(
					'https://www.kekc.cn/wp-content/uploads/updater/info.json',
					array(
						'timeout' => 10,
						'headers' => array(
							'Accept' => 'application/json'
						)
					)
				);

				if(
					is_wp_error( $remote )
					|| 200 !== wp_remote_retrieve_response_code( $remote )
					|| empty( wp_remote_retrieve_body( $remote ) )
				) {
					return false;
				}

				set_transient( $this->cache_key, $remote, DAY_IN_SECONDS );

			}

			$remote = json_decode( wp_remote_retrieve_body( $remote ) );

			return $remote;

		}


		function info( $res, $action, $args ) {

			// print_r( $action );
			// print_r( $args );

			// 如果你现在没有得到插件信息,就什么都不要做
			if( 'plugin_information' !== $action ) {
				return $res;
			}

			// 检查是不是我们要更新的插件
			if( $this->plugin_slug !== $args->slug ) {
				return $res;
			}

			// 获取更新信息
			$remote = $this->request();

			if( ! $remote ) {
				return $res;
			}

			$res = new stdClass();

			$res->name = $remote->name;
			$res->slug = $remote->slug;
			$res->version = $remote->version;
			$res->tested = $remote->tested;
			$res->requires = $remote->requires;
			$res->author = $remote->author;
			$res->author_profile = $remote->author_profile;
			$res->download_link = $remote->download_url;
			$res->trunk = $remote->download_url;
			$res->requires_php = $remote->requires_php;
			$res->last_updated = $remote->last_updated;

			$res->sections = array(
				'description' => $remote->sections->description,
				'installation' => $remote->sections->installation,
				'changelog' => $remote->sections->changelog
			);

			if( ! empty( $remote->banners ) ) {
				$res->banners = array(
					'low' => $remote->banners->low,
					'high' => $remote->banners->high
				);
			}

			return $res;

		}

		public function update( $transient ) {

			if ( empty($transient->checked ) ) {
				return $transient;
			}

			$remote = $this->request();

			if(
				$remote
				&& version_compare( $this->version, $remote->version, '<' )
				&& version_compare( $remote->requires, get_bloginfo( 'version' ), '<' )
				&& version_compare( $remote->requires_php, PHP_VERSION, '<' )
			) {
				$res = new stdClass();
				$res->slug = $this->plugin_slug;
				$res->plugin = plugin_basename( __FILE__ ); // kekc_cn_-update-plugin/kekc_cn_-update-plugin.php
				$res->new_version = $remote->version;
				$res->tested = $remote->tested;
				$res->package = $remote->download_url;

				$transient->response[ $res->plugin ] = $res;

	    }

			return $transient;

		}

		public function purge(){

			if (
				$this->cache_allowed
				&& 'update' === $options['action']
				&& 'plugin' === $options[ 'type' ]
			) {
				// 只需在安装新的插件版本时清理缓存。
				delete_transient( $this->cache_key );
			}

		}


	}

	new kekc_cn_UpdateChecker();

}

上面的插件呢,还用到一个info.json文件,是储存在服务器的,主要是用来存放插件信息的,其内容为:

{
	"name" : "自定义服务器更新插件示例",
	"slug" : "kekc_cn-update-checker",
	"author" : "<a href='https://www.kekc.cn'>kekc</a>",
	"author_profile" : "http://profiles.wordpress.org/kekc",
	"version" : "2.0",
	"download_url" : "https://www.kekc.cn/wp-content/uploads/updater/kekc_cn-update-checker.zip",
	"requires" : "3.0",
	"tested" : "5.8",
	"requires_php" : "5.3",
	"last_updated" : "2021-01-30 02:10:00",
	"sections" : {
		"description" : "这个简单的插件什么都不做,只从自定义服务器上获取更新。",
		"installation" : "点击激活按钮,就可以了。",
		"changelog" : "<h4>版本1.0</h4><ul><li>修复BUG</li><li>首次发布。</li></ul>"
	},
	"banners" : {
		"low" : "https://www.kekc.cn/wp-content/uploads/updater/banner-772x250.jpg",
		"high" : "https://www.kekc.cn/wp-content/uploads/updater/banner-1544x500.jpg"
	}
}

info.json里面的download_url是更新的插件地址,注意插件的目录结构需要和之前的插件一致,两个banner图自备。

主题

使用到的钩子

1、site_transient_update_themes (其实这个钩子和上面的site_transient_update_plugins是一样的)

不考虑性能,我们的代码可以这样:

<?php
add_filter( 'site_transient_update_themes', 'kekc_cn_update_themes' );

function kekc_cn_update_themes( $transient ) {

	// 得到主题文件夹名称,如果你不是在主题中插入我们的代码请更改此项,比如你的主题有子主题,请自己测试一下
	$stylesheet = get_template();


	// 获得本地主题的版本号
	$theme = wp_get_theme();
	//$theme = wp_get_theme( $stylesheet );//更新子主题试试这个,但可能会在更新过程中导致主题重复,你们自己测试一下。
	$version = $theme->get( 'Version' );


	// 获取远程的主题信息
	$remote = wp_remote_get(
		'https://www.kekc.cn/wp-content/uploads/theme-updater/info.json',
		array(
			'timeout' => 10,
			'headers' => array(
				'Accept' => 'application/json'
			)
		)
	);

	// 判断有没有正常获取到远程的主题信息
	if(
		is_wp_error( $remote )
		|| 200 !== wp_remote_retrieve_response_code( $remote )
		|| empty( wp_remote_retrieve_body( $remote ) )
	) {
		return $transient;
	}

	// 对响应body进行json编码
	$remote = json_decode( wp_remote_retrieve_body( $remote ) );
	
	if( ! $remote ) {
		return $transient; // who knows, maybe JSON is not valid
	}
	
	$data = array(
		'theme' => $stylesheet,
		'url' => $remote->details_url,
		'requires' => $remote->requires,
		'requires_php' => $remote->requires_php,
		'new_version' => $remote->version,
		'package' => $remote->download_url,
	);

	// 检查版本号[插件版本、wordpress版本、PHP版本]
	if(
		$remote
		&& version_compare( $version, $remote->version, '<' )
		&& version_compare( $remote->requires, get_bloginfo( 'version' ), '<' )
		&& version_compare( $remote->requires_php, PHP_VERSION, '<' )
	) {

		$transient->response[ $stylesheet ] = $data;

	} else {

		$transient->no_update[ $stylesheet ] = $data;

	}

	return $transient;

}

上面的代码,每次访问管理员面板都会重新从我们的更新服务器上获取更新,所有管理页面的加载速度都开始变慢。我们可以缓存一下,使用set_transient,代码为:

<?php
if( false == $remote = get_transient( 'kekc-theme-update'.$version ) ) {
	
	// 获取远程主题信息
	$remote = wp_remote_get(
		'https://rudrastyh.com/wp-content/uploads/theme-updater/info.json',
		array(
			'timeout' => 10,
			'headers' => array(
				'Accept' => 'application/json'
			)
		)
	);

	// 获取失败就暂停操作
	if(
		is_wp_error( $remote )
		|| 200 !== wp_remote_retrieve_response_code( $remote )
		|| empty( wp_remote_retrieve_body( $remote ) )
	) {
		return $transient;
	}

	$remote = json_decode( wp_remote_retrieve_body( $remote ) );

	if( ! $remote ) {
		return $transient; // 也许JSON是无效的?
	}
		
	set_transient( 'kekc-theme-update'.$version, $remote, HOUR_IN_SECONDS ); //HOUR_IN_SECONDS是1小时,还有其他的,比如DAY_IN_SECONDS(相当于86400),这里可以放秒数

}

info.json可以用PHP来返回,毕竟PHP可以返回任何文件类型:

<?php
$update = array(
	'version' => '2.0',
	'details_url' => 'https://www.kekc.cn/themes/kekc_cn-theme/changelog.html',
	'download_url' => ''
);

if( ! empty( $_GET[ 'license_key' ] ) && license_check_logic( $_GET[ 'license_key' ] ) {
	$update[ 'download_url' ] = 'https://www.kekc.cn/themes/kekc_cn-theme/2.0.zip';
}

header( 'Content-Type: application/json' );
echo json_encode( $update );

结语

其实吧,都非常简单,我的代码都感觉用多了,你可以参照我写的自己重写一下。或者你觉得都太累,你可以参照GitHub上的一个项目(plugin-update-checker),来从自己服务器上更新插件和主题,请忽略项目名称,他是支持插件和主题的。

学完我上面的代码,你甚至可以试试实现一个wordpress主题、插件商店。

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享