Files
wordpress-theme-aksrt/inc/classes/extensions/class-aksrt-search-push.php
T
kate522 ce1c13b947 refactor(classes): organize inc/classes into domain folders
Move ~94 root class shells and root *-traits into domain directories
(core, auth, user, credits, content, payment/gateways, forum, shop,
sms, ai, messages, extensions, widgets, settings, admin). Update
bootstrap require paths, co-locate traits with owners, fix forum/user
relative requires, drop duplicate shop controller requires, and wire
home-modules load. Path-only; class names and init order unchanged.
2026-07-17 11:11:57 +08:00

238 lines
7.9 KiB
PHP

<?php
/**
* AKSRT Search Push Service
*
* 提供搜索引擎主动推送能力。当前支持百度推送。
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
class AKSRT_Search_Push {
private static $instance = null;
public static function get_instance(): self {
if (null === self::$instance) self::$instance = new self();
return self::$instance;
}
/**
* 绑定运行时钩子:发布/更新主动推送 + 前台自动推送 JS。
*/
public function init(): void {
add_action('transition_post_status', [$this, 'on_transition_post_status'], 10, 3);
add_action('wp_footer', [$this, 'output_auto_push_script'], 99);
}
/**
* 文章发布/更新时主动推送链接到百度。
*
* @param string $new_status 新状态。
* @param string $old_status 旧状态。
* @param WP_Post $post 文章对象。
*/
public function on_transition_post_status(string $new_status, string $old_status, $post): void {
if (!($post instanceof WP_Post)) {
return;
}
if ($new_status !== 'publish') {
return;
}
if (wp_is_post_revision($post->ID) || wp_is_post_autosave($post->ID)) {
return;
}
// 仅推送公开可索引的内容类型。
$allowed = function_exists('aksrt_searchable_post_types')
? aksrt_searchable_post_types()
: ['post'];
if (!in_array($post->post_type, $allowed, true)) {
return;
}
$config = $this->get_config();
if (empty($config['baidu_push_enabled'])) {
return;
}
$is_new = $old_status !== 'publish';
if ($is_new && empty($config['baidu_push_on_publish'])) {
return;
}
if (!$is_new && empty($config['baidu_push_on_update'])) {
return;
}
$this->push_url((string) get_permalink($post));
}
/**
* 前台输出百度自动推送 JS(由 wp_footer 调用)。
*/
public function output_auto_push_script(): void {
if (is_admin()) {
return;
}
$script = $this->get_auto_push_script();
if ($script !== '') {
echo $script; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped — 固定常量脚本,无用户输入
}
}
/**
* 推送单条 URL 到百度
*
* @param string $url 待推送的完整 URL
* @return array{success: bool, message: string, result: array}
*/
public function push_url(string $url): array {
$config = $this->get_config();
if (empty($config['baidu_push_enabled'])) {
return ['success' => false, 'message' => __('百度推送未启用', 'aksrt'), 'result' => []];
}
$token = (string) ($config['baidu_push_token'] ?? '');
if ($token === '') {
return ['success' => false, 'message' => __('推送 Token 未配置', 'aksrt'), 'result' => []];
}
$api_url = "http://data.zz.baidu.com/urls?site=" . rawurlencode(home_url('/')) . "&token={$token}";
$response = wp_remote_post($api_url, [
'timeout' => 10,
'headers' => ['Content-Type' => 'text/plain'],
'body' => $url,
]);
if (is_wp_error($response)) {
$this->log('error', $url, $response->get_error_message());
return ['success' => false, 'message' => $response->get_error_message(), 'result' => []];
}
$body = json_decode(wp_remote_retrieve_body($response), true);
$status = wp_remote_retrieve_response_code($response);
if ($status === 200 && isset($body['success'])) {
$this->log('success', $url, wp_json_encode($body));
return ['success' => true, 'message' => __('推送成功', 'aksrt'), 'result' => $body];
}
$err_msg = $body['message'] ?? ($body['error'] ?? sprintf('HTTP %d', $status));
$this->log('error', $url, $err_msg);
return ['success' => false, 'message' => $err_msg, 'result' => $body ?? []];
}
/**
* 批量推送 URL
*
* @param string[] $urls
* @return array{success: int, failed: int, results: array}
*/
public function push_batch(array $urls): array {
$config = $this->get_config();
$batch_size = max(1, min(500, (int) ($config['baidu_push_batch_size'] ?? 50)));
$success = 0;
$failed = 0;
$results = [];
$chunks = array_chunk($urls, $batch_size);
foreach ($chunks as $chunk) {
$token = (string) ($config['baidu_push_token'] ?? '');
$api_url = "http://data.zz.baidu.com/urls?site=" . rawurlencode(home_url('/')) . "&token={$token}";
$body_str = implode("\n", $chunk);
$response = wp_remote_post($api_url, [
'timeout' => 15,
'headers' => ['Content-Type' => 'text/plain'],
'body' => $body_str,
]);
if (is_wp_error($response)) {
$failed += count($chunk);
$results[] = ['error' => $response->get_error_message()];
continue;
}
$body = json_decode(wp_remote_retrieve_body($response), true);
if (isset($body['success'])) {
$success += (int) ($body['success'] ?? 0);
$failed += (int) ($body['not_same_site'] ?? 0) + (int) ($body['not_valid'] ?? 0);
} else {
$failed += count($chunk);
}
$results[] = $body ?? [];
}
return ['success' => $success, 'failed' => $failed, 'results' => $results];
}
/**
* 获取自动推送 JS 代码
*/
public function get_auto_push_script(): string {
$config = $this->get_config();
if (empty($config['baidu_push_enabled']) || empty($config['baidu_push_auto'])) {
return '';
}
$site_url = home_url('/');
return <<<SCRIPT
<script>
(function(){
var bp = document.createElement('script');
var curProtocol = window.location.protocol.split(':')[0];
if (curProtocol === 'https') {
bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
} else {
bp.src = 'http://push.zhanzhang.baidu.com/push.js';
}
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(bp, s);
})();
</script>
SCRIPT;
}
/**
* 获取服务运行时状态
*/
public function get_status(): array {
$config = $this->get_config();
$enabled = !empty($config['baidu_push_enabled']);
$token = (string) ($config['baidu_push_token'] ?? '');
$missing = [];
if ($enabled && $token === '') {
$missing[] = 'baidu_push_token';
}
return [
'enabled' => $enabled,
'provider' => 'baidu',
'configured' => $enabled && $token !== '',
'available' => $enabled && $token !== '',
'verified' => !empty($config['baidu_push_verified']),
'transport' => 'http_api',
'missing_fields' => $missing,
'auto_push' => !empty($config['baidu_push_auto']),
'on_publish' => !empty($config['baidu_push_on_publish']),
'on_update' => !empty($config['baidu_push_on_update']),
'batch_size' => max(1, (int) ($config['baidu_push_batch_size'] ?? 50)),
];
}
private function get_config(): array {
if (class_exists('AKSRT_Settings')) {
return AKSRT_Settings::get_search_push_settings();
}
return ['baidu_push_enabled' => false];
}
private function log(string $level, string $url, string $message): void {
if (!defined('WP_DEBUG') || !WP_DEBUG) return;
error_log(sprintf('[AKSRT Search Push] [%s] URL: %s — %s', $level, $url, $message));
}
}