chore(repo): track full tests/ and tools/ suites, drop per-file whitelist
This commit is contained in:
@@ -0,0 +1,322 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Scratch harness: render term_aggregation with a fuller WP stub surface
|
||||
* to reproduce the "widget does not work" report. Local-only, not tracked.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
define('ABSPATH', __DIR__ . DIRECTORY_SEPARATOR);
|
||||
}
|
||||
if (!defined('DAY_IN_SECONDS')) {
|
||||
define('DAY_IN_SECONDS', 86400);
|
||||
}
|
||||
|
||||
error_reporting(E_ALL);
|
||||
set_error_handler(static function (int $severity, string $message, string $file, int $line): bool {
|
||||
if (!(error_reporting() & $severity)) {
|
||||
return false;
|
||||
}
|
||||
throw new ErrorException($message, 0, $severity, $file, $line);
|
||||
});
|
||||
|
||||
class WP_Error {
|
||||
public function __construct(private string $code = '', private string $message = '') {}
|
||||
public function get_error_code(): string { return $this->code; }
|
||||
public function get_error_message(): string { return $this->message; }
|
||||
}
|
||||
|
||||
class WP_Post {
|
||||
public int $ID;
|
||||
public function __construct(int $id) { $this->ID = $id; }
|
||||
}
|
||||
|
||||
class WP_Term {
|
||||
public int $term_id;
|
||||
public string $name = '';
|
||||
public string $description = '';
|
||||
public string $taxonomy = 'category';
|
||||
public int $term_taxonomy_id;
|
||||
public function __construct(int $term_id, string $name, string $description = '', string $taxonomy = 'category') {
|
||||
$this->term_id = $term_id;
|
||||
$this->name = $name;
|
||||
$this->description = $description;
|
||||
$this->taxonomy = $taxonomy;
|
||||
$this->term_taxonomy_id = $term_id;
|
||||
}
|
||||
}
|
||||
|
||||
class WP_User {
|
||||
public int $ID;
|
||||
public string $display_name;
|
||||
public function __construct(int $id, string $name) { $this->ID = $id; $this->display_name = $name; }
|
||||
}
|
||||
|
||||
class wpdb {
|
||||
public string $postmeta = 'wp_postmeta';
|
||||
public string $posts = 'wp_posts';
|
||||
public string $term_relationships = 'wp_term_relationships';
|
||||
public function prepare(string $query, ...$args): string {
|
||||
foreach ($args as $arg) {
|
||||
$query = preg_replace('/%[sd]/', is_numeric($arg) ? (string) (int) $arg : "'" . (string) $arg . "'", $query, 1);
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
public function get_var(string $query): ?string {
|
||||
unset($query);
|
||||
return '12345';
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['wpdb'] = new wpdb();
|
||||
|
||||
// Fake posts the stub WP_Query will serve, keyed by expected cat.
|
||||
$GLOBALS['aksrt_harness_posts'] = [
|
||||
['id' => 101, 'title' => '第一篇文章', 'cat' => 5],
|
||||
['id' => 102, 'title' => '第二篇文章', 'cat' => 5],
|
||||
['id' => 103, 'title' => '第三篇文章', 'cat' => 5],
|
||||
['id' => 104, 'title' => '第四篇文章', 'cat' => 5],
|
||||
];
|
||||
$GLOBALS['aksrt_harness_cursor'] = 0;
|
||||
|
||||
class WP_Query {
|
||||
public array $posts = [];
|
||||
public int $found_posts = 0;
|
||||
public function __construct(public array $query_args = []) {
|
||||
$cat_in = (array) ($query_args['category__in'] ?? []);
|
||||
$matched = array_values(array_filter($GLOBALS['aksrt_harness_posts'], static fn(array $p): bool => in_array($p['cat'], $cat_in, true)));
|
||||
$this->found_posts = count($matched);
|
||||
foreach ($matched as $post) {
|
||||
$this->posts[] = new WP_Post($post['id']);
|
||||
$GLOBALS['aksrt_harness_lookup'][$post['id']] = $post;
|
||||
}
|
||||
}
|
||||
public function have_posts(): bool { return $GLOBALS['aksrt_harness_cursor'] < count($this->posts); }
|
||||
public function the_post(): void {
|
||||
$post = $this->posts[$GLOBALS['aksrt_harness_cursor']];
|
||||
$GLOBALS['aksrt_harness_cursor']++;
|
||||
$GLOBALS['aksrt_harness_current_post'] = $GLOBALS['aksrt_harness_lookup'][$post->ID] ?? ['id' => $post->ID, 'title' => '文章' . $post->ID];
|
||||
}
|
||||
}
|
||||
|
||||
function __($text, $domain = null): string { unset($domain); return (string) $text; }
|
||||
function esc_html__($text, $domain = null): string { return esc_html(__($text, $domain)); }
|
||||
function esc_attr__($text, $domain = null): string { return esc_attr(__($text, $domain)); }
|
||||
function esc_html($value): string { return htmlspecialchars((string) $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
|
||||
function esc_attr($value): string { return esc_html($value); }
|
||||
function esc_url_raw($value): string {
|
||||
$value = trim((string) $value);
|
||||
return preg_match('#^(https?://|/)#', $value) ? $value : '';
|
||||
}
|
||||
function esc_url($value): string { return esc_attr(esc_url_raw($value)); }
|
||||
function absint($value): int { return abs((int) $value); }
|
||||
function sanitize_key($value): string { return preg_replace('/[^a-z0-9_\-]/', '', strtolower((string) $value)) ?? ''; }
|
||||
function sanitize_text_field($value): string { return trim(strip_tags((string) $value)); }
|
||||
function sanitize_textarea_field($value): string { return trim(strip_tags((string) $value)); }
|
||||
function sanitize_html_class($value): string { return preg_replace('/[^A-Za-z0-9_-]/', '', (string) $value) ?? ''; }
|
||||
function wp_parse_args($args, array $defaults = []): array { return array_merge($defaults, is_array($args) ? $args : []); }
|
||||
function wp_kses($value, array $allowed): string {
|
||||
unset($allowed);
|
||||
return strip_tags((string) $value, '<i><span><item><b><strong><em><badge><div>');
|
||||
}
|
||||
function wp_kses_post($value): string { return strip_tags((string) $value, '<a><b><br><p><span>'); }
|
||||
function wp_strip_all_tags($value): string { return trim(strip_tags((string) $value)); }
|
||||
function wp_trim_words($text, int $count = 55, string $more = '…'): string {
|
||||
$words = preg_split('/\s+/', trim((string) $text)) ?: [];
|
||||
if (count($words) <= $count) return implode(' ', $words);
|
||||
return implode(' ', array_slice($words, 0, $count)) . $more;
|
||||
}
|
||||
function wp_is_mobile(): bool { return false; }
|
||||
function wp_reset_postdata(): void {}
|
||||
function is_wp_error($value): bool { return $value instanceof WP_Error; }
|
||||
function is_super_admin(): bool { return false; }
|
||||
function is_sticky($id = 0): bool { unset($id); return false; }
|
||||
function current_time(string $type): int { return $type === 'timestamp' ? time() : 0; }
|
||||
function human_time_diff(int $from, int $to = 0): string {
|
||||
unset($to);
|
||||
return (($from % 3600) + 1) . ' 小时';
|
||||
}
|
||||
function get_avatar_url($id, array $args = []): string { return 'https://example.test/avatar-' . (int) $id . '.jpg'; }
|
||||
function get_post_meta($id, $key = '', $single = false) { unset($id, $key, $single); return ''; }
|
||||
function get_term_meta(int $term_id, string $key, bool $single = false) {
|
||||
if ($key === 'aksrt_category_cover_id') {
|
||||
return $term_id === 5 ? 55 : 0;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
function wp_get_attachment_url(int $id): string { return $id === 55 ? 'https://example.test/cover-cat-5.jpg' : ''; }
|
||||
function get_posts(array $args): array {
|
||||
unset($args);
|
||||
return [102];
|
||||
}
|
||||
function get_the_post_thumbnail_url($post = null, string $size = 'post-thumbnail') {
|
||||
unset($post, $size);
|
||||
return 'https://example.test/thumb-cat-8.jpg';
|
||||
}
|
||||
function get_terms(array $args): array {
|
||||
unset($args);
|
||||
return [new WP_Term(5, '技术分享', '这里是分类描述文本'), new WP_Term(8, '生活记录', '')];
|
||||
}
|
||||
function get_term(int $term_id, string $taxonomy = '') {
|
||||
unset($taxonomy);
|
||||
return match ($term_id) {
|
||||
5 => new WP_Term(5, '技术分享', '这里是分类描述文本'),
|
||||
8 => new WP_Term(8, '生活记录', ''),
|
||||
default => new WP_Error('invalid_term', 'Term not found'),
|
||||
};
|
||||
}
|
||||
function get_term_link(WP_Term $term) {
|
||||
return 'https://example.test/cat-' . $term->term_id;
|
||||
}
|
||||
function get_the_ID(): int { return (int) ($GLOBALS['aksrt_harness_current_post']['id'] ?? 0); }
|
||||
function get_the_title($id = 0): string {
|
||||
unset($id);
|
||||
return (string) ($GLOBALS['aksrt_harness_current_post']['title'] ?? '');
|
||||
}
|
||||
function get_permalink($id = 0): string { return 'https://example.test/post-' . (int) ($id ?: get_the_ID()); }
|
||||
function get_the_excerpt($id = 0): string { unset($id); return '这是摘要'; }
|
||||
function get_post_field($field, $id = 0, $context = 'display') {
|
||||
unset($context);
|
||||
return $field === 'post_author' ? 1 : '';
|
||||
}
|
||||
function get_userdata($id): ?WP_User { return $id > 0 ? new WP_User((int) $id, '作者' . (int) $id) : null; }
|
||||
function get_the_time($format, $id = 0): string { unset($format, $id); return '2026-09-01 10:00:00'; }
|
||||
function get_the_modified_time($format, $id = 0): string { unset($format, $id); return '2026-09-04 10:00:00'; }
|
||||
function get_the_category($id = 0): array { unset($id); return [new WP_Term(5, '技术分享')]; }
|
||||
function get_the_tags($id = 0) { unset($id); return []; }
|
||||
function get_comments_number($id = 0): int { unset($id); return 3; }
|
||||
function get_comments_link($id = 0): string { return get_permalink($id) . '#comments'; }
|
||||
function comments_open($id = 0): bool { unset($id); return true; }
|
||||
function get_post_type($id = 0): string { unset($id); return 'post'; }
|
||||
function has_post_format($formats, $id = 0): bool { unset($formats, $id); return false; }
|
||||
function aksrt_get_pay_meta($post = null): array { unset($post); return ['pay_type' => 'no', 'price' => 0]; }
|
||||
function aksrt_get_post_views($id = 0): int { return (int) ($id % 90) + 10; }
|
||||
function aksrt_get_post_likes($id = 0): int { return (int) ($id % 7); }
|
||||
function aksrt_get_post_favorites($id = 0): int { return (int) ($id % 5); }
|
||||
function aksrt_resource_card_badge_text($id = 0): string { unset($id); return ''; }
|
||||
function aksrt_format_number($num): string { return (string) $num; }
|
||||
function aksrt_is_lazy(string $key, bool $default = false): bool { unset($key); return $default; }
|
||||
function aksrt_get_lazy_thumb(string $size = ''): string { unset($size); return 'https://example.test/lazy.svg'; }
|
||||
function aksrt_get_lazy_attr(string $type, string $src, string $class = '', string $lazy_src = ''): string {
|
||||
$url = $lazy_src !== '' ? $lazy_src : $src;
|
||||
return ' class="' . esc_attr($class) . '" src="' . esc_url($url) . '" data-src="' . esc_url($src) . '" data-lazy-type="' . esc_attr($type) . '"';
|
||||
}
|
||||
function aksrt_renderer_resolve_images($post_id, array $cfg): array {
|
||||
unset($post_id, $cfg);
|
||||
return ['primary' => '', 'has_real' => false, 'gallery' => [], 'slides' => [], 'is_slide' => false, 'video_url' => ''];
|
||||
}
|
||||
|
||||
// --- full pipeline stubs (AssetManager / SchemaWidget / registry) ---
|
||||
function wp_register_style(...$args): void { unset($args); }
|
||||
function wp_register_script(...$args): void { unset($args); }
|
||||
function wp_enqueue_style(...$args): void { unset($args); }
|
||||
function wp_enqueue_script(...$args): void { unset($args); }
|
||||
function wp_add_inline_script(...$args): void { unset($args); }
|
||||
function rest_url(string $path = ''): string { return 'https://example.test/wp-json/' . $path; }
|
||||
function get_template_directory(): string { return dirname(__DIR__, 2); }
|
||||
function get_template_directory_uri(): string { return 'https://example.test/theme'; }
|
||||
function wp_json_encode($value): string { return (string) json_encode($value, JSON_UNESCAPED_UNICODE); }
|
||||
function esc_textarea($value): string { return esc_html($value); }
|
||||
function checked($actual, $expected = true, bool $display = true): string {
|
||||
$result = $actual == $expected ? 'checked="checked"' : '';
|
||||
if ($display) echo $result;
|
||||
return $result;
|
||||
}
|
||||
function selected($actual, $expected = true, bool $display = true): string {
|
||||
$result = $actual == $expected ? 'selected="selected"' : '';
|
||||
if ($display) echo $result;
|
||||
return $result;
|
||||
}
|
||||
|
||||
class WP_Widget {
|
||||
public string $id_base = '';
|
||||
public string $id = '';
|
||||
public int $number = 0;
|
||||
public function __construct(string $id_base = '') { $this->id_base = $id_base; }
|
||||
public function get_field_name(string $field): string { return 'widget-' . $this->id_base . '[' . $this->number . '][' . $field . ']'; }
|
||||
public function get_field_id(string $field): string { return 'widget-' . $this->id_base . '-' . $this->number . '-' . $field; }
|
||||
public function _set(int $number): void { $this->number = $number; $this->id = $this->id_base . '-' . $number; }
|
||||
}
|
||||
|
||||
require dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||
require dirname(__DIR__, 2) . '/inc/helpers/aksrt-graphic-card.php';
|
||||
require dirname(__DIR__, 2) . '/inc/helpers/aksrt-widgets-markup.php';
|
||||
require dirname(__DIR__, 2) . '/inc/helpers/posts-renderer/post-data.php';
|
||||
|
||||
use AKSRT\WidgetSystem\Renderers\ContentRenderer;
|
||||
|
||||
$instance = [
|
||||
'term_id' => [5, 8],
|
||||
'pc_row' => 2,
|
||||
'orderby' => 'modified',
|
||||
'order' => 'desc',
|
||||
'count' => 4,
|
||||
'target_blank' => false,
|
||||
'obs_animation' => '',
|
||||
'animation_repeat' => false,
|
||||
];
|
||||
|
||||
try {
|
||||
$html = ContentRenderer::render('term_aggregation', $instance);
|
||||
echo "=== RENDER OK ===\n";
|
||||
echo $html;
|
||||
echo "\n=== END ===\n";
|
||||
} catch (Throwable $e) {
|
||||
echo '=== FATAL: ' . get_class($e) . ': ' . $e->getMessage() . ' @ ' . $e->getFile() . ':' . $e->getLine() . "\n";
|
||||
echo $e->getTraceAsString() . "\n";
|
||||
}
|
||||
|
||||
// Single-term variant (is_row=false) + animation variant.
|
||||
try {
|
||||
$GLOBALS['aksrt_harness_cursor'] = 0;
|
||||
$single = ContentRenderer::render('term_aggregation', array_merge($instance, ['term_id' => [5], 'obs_animation' => 'fade']));
|
||||
echo "=== SINGLE OK (len=" . strlen($single) . ") ===\n";
|
||||
echo $single . "\n";
|
||||
} catch (Throwable $e) {
|
||||
echo '=== SINGLE FATAL: ' . get_class($e) . ': ' . $e->getMessage() . ' @ ' . $e->getFile() . ':' . $e->getLine() . "\n";
|
||||
}
|
||||
|
||||
// Full pipeline: registry -> definition -> normalize(raw form input '5,8') -> FrontendRenderer.
|
||||
try {
|
||||
$definitions = \AKSRT\WidgetSystem\WidgetRegistry::all();
|
||||
echo "=== REGISTRY: term_aggregation present = " . (isset($definitions['term_aggregation']) ? 'yes' : 'NO') . " ===\n";
|
||||
$definition = $definitions['term_aggregation'];
|
||||
$widget = new \AKSRT\WidgetSystem\SchemaWidget($definition);
|
||||
$widget->_set(2);
|
||||
$normalized = $definition->normalize(['term_id' => '5,8']);
|
||||
echo "=== NORMALIZED term_id = " . json_encode($normalized['term_id']) . " ===\n";
|
||||
$GLOBALS['aksrt_harness_cursor'] = 0;
|
||||
ob_start();
|
||||
\AKSRT\WidgetSystem\FrontendRenderer::render(
|
||||
$definition,
|
||||
['before_widget' => '<section class="w">', 'after_widget' => '</section>'],
|
||||
$normalized,
|
||||
$widget
|
||||
);
|
||||
$full = (string) ob_get_clean();
|
||||
echo "=== FULL PATH OK (len=" . strlen($full) . ") ===\n";
|
||||
echo $full . "\n";
|
||||
|
||||
// Empty selection must render nothing at all.
|
||||
ob_start();
|
||||
\AKSRT\WidgetSystem\FrontendRenderer::render($definition, ['before_widget' => '<section>', 'after_widget' => '</section>'], $definition->normalize([]), $widget);
|
||||
$empty = (string) ob_get_clean();
|
||||
echo "=== EMPTY SELECTION OUTPUT len=" . strlen($empty) . " ===\n";
|
||||
|
||||
// Admin form HTML for the terms field (what the widgets screen renders).
|
||||
ob_start();
|
||||
$widget->render_full_form($definition->normalize(['term_id' => '5,8']));
|
||||
$form = (string) ob_get_clean();
|
||||
if (preg_match('/<div class="aksrt-widget-field aksrt-widget-field--terms".*?<\/div>\s*<\/div>\s*<\/div>/s', $form, $m)) {
|
||||
echo "=== TERMS FIELD HTML ===\n" . $m[0] . "\n";
|
||||
}
|
||||
echo "=== FORM contains hidden terms value name = " . (strpos($form, 'name="widget-aksrt_widget_term_aggregation[2][term_id]"') !== false ? 'yes' : 'NO') . " ===\n";
|
||||
echo "=== FORM hidden value = ";
|
||||
preg_match('/class="aksrt-widget-terms__value"[^>]*value="([^"]*)"/', $form, $v);
|
||||
echo ($v[1] ?? '(not found)') . " ===\n";
|
||||
} catch (Throwable $e) {
|
||||
echo '=== FULL PATH FATAL: ' . get_class($e) . ': ' . $e->getMessage() . ' @ ' . $e->getFile() . ':' . $e->getLine() . "\n";
|
||||
echo $e->getTraceAsString() . "\n";
|
||||
}
|
||||
Reference in New Issue
Block a user