Compare commits
3 commits
308dd0ca88
...
26db8c41a4
| Author | SHA1 | Date | |
|---|---|---|---|
| 26db8c41a4 | |||
|
|
558d029bc5 | ||
|
|
7b1dad3287 |
4 changed files with 3375 additions and 0 deletions
|
|
@ -19,6 +19,11 @@ if [ ! -d "$TARGET_DIR" ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# 生成 .pot 翻译模板
|
||||
echo "🌐 生成 .pot 翻译模板..."
|
||||
mkdir -p "$SOURCE_DIR/languages"
|
||||
wp i18n make-pot "$SOURCE_DIR" "$SOURCE_DIR/languages/wpmind.pot" --domain=wpmind --skip-audit --quiet
|
||||
|
||||
# 同步文件 (排除 .git 目录)
|
||||
echo "📦 同步文件..."
|
||||
sudo rsync -av --delete \
|
||||
|
|
|
|||
266
includes/class-wenpai-updater.php
Normal file
266
includes/class-wenpai-updater.php
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
<?php
|
||||
/**
|
||||
* WenPai 插件更新器
|
||||
*
|
||||
* 为文派系插件提供自建更新服务支持。
|
||||
* 通过文派云桥 (WenPai Bridge) 检查插件更新,
|
||||
* 利用 WordPress 5.8+ 的 Update URI 机制。
|
||||
*
|
||||
* 当 wp-china-yes 插件激活并启用集中更新时,
|
||||
* 此更新器会通过 wenpai_updater_override filter 自动让位。
|
||||
*
|
||||
* @package WenPai
|
||||
* @version 1.0.0
|
||||
* @requires WordPress 5.8+
|
||||
* @requires PHP 7.4+
|
||||
* @link https://feicode.com/WenPai-org
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( class_exists( 'WenPai_Updater' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
class WenPai_Updater {
|
||||
|
||||
/**
|
||||
* 更新器版本号。
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const VERSION = '1.1.0';
|
||||
|
||||
/**
|
||||
* 云桥 API 地址。
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const API_URL = 'https://updates.wenpai.net/api/v1';
|
||||
|
||||
/**
|
||||
* 插件主文件 basename(如 wpslug/wpslug.php)。
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $plugin_file;
|
||||
|
||||
/**
|
||||
* 插件 slug(如 wpslug)。
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $slug;
|
||||
|
||||
/**
|
||||
* 当前插件版本。
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $version;
|
||||
|
||||
/**
|
||||
* 初始化更新器。
|
||||
*
|
||||
* @param string $plugin_file 插件主文件路径(plugin_basename 格式)。
|
||||
* @param string $version 当前插件版本号。
|
||||
*/
|
||||
public function __construct( string $plugin_file, string $version ) {
|
||||
$this->plugin_file = $plugin_file;
|
||||
$this->slug = dirname( $plugin_file );
|
||||
$this->version = $version;
|
||||
|
||||
// 检查是否被 wp-china-yes 集中更新接管
|
||||
$is_overridden = apply_filters(
|
||||
'wenpai_updater_override',
|
||||
false,
|
||||
$this->slug
|
||||
);
|
||||
|
||||
if ( ! $is_overridden ) {
|
||||
$this->register_hooks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册 WordPress hooks。
|
||||
*/
|
||||
private function register_hooks(): void {
|
||||
// Update URI: https://updates.wenpai.net 触发此 filter
|
||||
add_filter(
|
||||
'update_plugins_updates.wenpai.net',
|
||||
[ $this, 'check_update' ],
|
||||
10,
|
||||
4
|
||||
);
|
||||
|
||||
// 插件详情弹窗
|
||||
add_filter( 'plugins_api', [ $this, 'plugin_info' ], 20, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查插件更新。
|
||||
*
|
||||
* WordPress 在检查更新时,对声明了 Update URI 的插件
|
||||
* 触发 update_plugins_{hostname} filter。
|
||||
*
|
||||
* @param array|false $update 当前更新数据。
|
||||
* @param array $plugin_data 插件头信息。
|
||||
* @param string $plugin_file 插件文件路径。
|
||||
* @param string[] $locales 语言列表。
|
||||
* @return object|false 更新数据或 false。
|
||||
*/
|
||||
public function check_update( $update, array $plugin_data, string $plugin_file, array $locales ) {
|
||||
if ( $plugin_file !== $this->plugin_file ) {
|
||||
return $update;
|
||||
}
|
||||
|
||||
$response = $this->api_request( 'update-check', [
|
||||
'plugins' => [
|
||||
$this->plugin_file => [
|
||||
'Version' => $this->version,
|
||||
],
|
||||
],
|
||||
] );
|
||||
|
||||
if ( is_wp_error( $response ) || empty( $response['plugins'][ $this->plugin_file ] ) ) {
|
||||
return $update;
|
||||
}
|
||||
|
||||
$data = $response['plugins'][ $this->plugin_file ];
|
||||
|
||||
return (object) [
|
||||
'id' => $data['id'] ?? '',
|
||||
'slug' => $data['slug'] ?? $this->slug,
|
||||
'plugin' => $this->plugin_file,
|
||||
'version' => $data['version'] ?? '',
|
||||
'new_version' => $data['version'] ?? '',
|
||||
'url' => $data['url'] ?? '',
|
||||
'package' => $data['package'] ?? '',
|
||||
'icons' => $data['icons'] ?? [],
|
||||
'banners' => $data['banners'] ?? [],
|
||||
'requires' => $data['requires'] ?? '',
|
||||
'tested' => $data['tested'] ?? '',
|
||||
'requires_php' => $data['requires_php'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件详情弹窗数据。
|
||||
*
|
||||
* 当用户在 WP 后台点击"查看详情"时触发。
|
||||
*
|
||||
* @param false|object|array $result 当前结果。
|
||||
* @param string $action API 动作。
|
||||
* @param object $args 请求参数。
|
||||
* @return false|object 插件信息或 false。
|
||||
*/
|
||||
public function plugin_info( $result, string $action, object $args ) {
|
||||
if ( 'plugin_information' !== $action ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ( ! isset( $args->slug ) || $args->slug !== $this->slug ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$response = $this->api_request( "plugins/{$this->slug}/info" );
|
||||
|
||||
if ( ! is_wp_error( $response ) && ! isset( $response['error'] ) && ! empty( $response['name'] ) ) {
|
||||
$info = new stdClass();
|
||||
$info->name = $response['name'];
|
||||
$info->slug = $response['slug'] ?? $this->slug;
|
||||
$info->version = $response['version'] ?? '';
|
||||
$info->author = $response['author'] ?? '';
|
||||
$info->homepage = $response['homepage'] ?? '';
|
||||
$info->download_link = $response['download_link'] ?? '';
|
||||
$info->requires = $response['requires'] ?? '';
|
||||
$info->tested = $response['tested'] ?? '';
|
||||
$info->requires_php = $response['requires_php'] ?? '';
|
||||
$info->last_updated = $response['last_updated'] ?? '';
|
||||
$info->icons = $response['icons'] ?? [];
|
||||
$info->banners = $response['banners'] ?? [];
|
||||
$info->sections = $response['sections'] ?? [];
|
||||
$info->external = true;
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
// API 不可用或插件未注册时,用本地插件头信息兜底
|
||||
$plugin_path = WP_PLUGIN_DIR . '/' . $this->plugin_file;
|
||||
if ( ! file_exists( $plugin_path ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'get_plugin_data' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
|
||||
$plugin_data = get_plugin_data( $plugin_path );
|
||||
|
||||
$info = new stdClass();
|
||||
$info->name = $plugin_data['Name'] ?? $this->slug;
|
||||
$info->slug = $this->slug;
|
||||
$info->version = $this->version;
|
||||
$info->author = $plugin_data['AuthorName'] ?? '';
|
||||
$info->homepage = $plugin_data['PluginURI'] ?? '';
|
||||
$info->requires = $plugin_data['RequiresWP'] ?? '';
|
||||
$info->requires_php = $plugin_data['RequiresPHP'] ?? '';
|
||||
$info->sections = [
|
||||
'description' => $plugin_data['Description'] ?? '',
|
||||
];
|
||||
$info->external = true;
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 向云桥 API 发送请求。
|
||||
*
|
||||
* @param string $endpoint API 端点(不含 /api/v1/ 前缀)。
|
||||
* @param array|null $body POST 请求体(null 则用 GET)。
|
||||
* @return array|WP_Error 解码后的响应或错误。
|
||||
*/
|
||||
private function api_request( string $endpoint, ?array $body = null ) {
|
||||
$url = self::API_URL . '/' . ltrim( $endpoint, '/' );
|
||||
|
||||
$args = [
|
||||
'timeout' => 10,
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
];
|
||||
|
||||
if ( null !== $body ) {
|
||||
$args['headers']['Content-Type'] = 'application/json';
|
||||
$args['body'] = wp_json_encode( $body );
|
||||
$response = wp_remote_post( $url, $args );
|
||||
} else {
|
||||
$response = wp_remote_get( $url, $args );
|
||||
}
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$code = wp_remote_retrieve_response_code( $response );
|
||||
if ( 200 !== $code ) {
|
||||
return new WP_Error(
|
||||
'wenpai_bridge_error',
|
||||
sprintf( 'WenPai Bridge API returned %d', $code )
|
||||
);
|
||||
}
|
||||
|
||||
$data = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
if ( ! is_array( $data ) ) {
|
||||
return new WP_Error(
|
||||
'wenpai_bridge_parse_error',
|
||||
'Invalid JSON response from WenPai Bridge'
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
3096
languages/wpmind.pot
Normal file
3096
languages/wpmind.pot
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -12,6 +12,7 @@
|
|||
* Domain Path: /languages
|
||||
* Requires at least: 6.4
|
||||
* Requires PHP: 8.1
|
||||
* Update URI: https://updates.wenpai.net
|
||||
*
|
||||
* @package WPMind
|
||||
*/
|
||||
|
|
@ -38,6 +39,9 @@ if ( ! defined( 'WPMIND_PLUGIN_DIR' ) ) {
|
|||
if ( ! defined( 'WPMIND_PLUGIN_URL' ) ) {
|
||||
define( 'WPMIND_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
|
||||
}
|
||||
if ( ! defined( 'WPMIND_PLUGIN_BASENAME' ) ) {
|
||||
define( 'WPMIND_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
|
||||
}
|
||||
// Alias for module compatibility.
|
||||
if ( ! defined( 'WPMIND_PATH' ) ) {
|
||||
define( 'WPMIND_PATH', WPMIND_PLUGIN_DIR );
|
||||
|
|
@ -736,5 +740,9 @@ spl_autoload_register( function ( string $class ): void {
|
|||
}
|
||||
} );
|
||||
|
||||
// 加载 WenPai 更新器(跨插件共享组件,不走 PSR-4)
|
||||
require_once WPMIND_PLUGIN_DIR . 'includes/class-wenpai-updater.php';
|
||||
new \WenPai_Updater( WPMIND_PLUGIN_BASENAME, WPMIND_VERSION );
|
||||
|
||||
// 加载 Provider 注册模块
|
||||
require_once WPMIND_PLUGIN_DIR . 'includes/Providers/register.php';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue