diff --git a/assets/css/admin/links-manager.css b/assets/css/admin/links-manager.css new file mode 100644 index 00000000..9d7f5d61 --- /dev/null +++ b/assets/css/admin/links-manager.css @@ -0,0 +1,30 @@ +/* Keep the native category filter useful even before links are assigned. */ +#cat_id { + min-width: 180px; +} + +/* The pending count lengthens this sortable header beyond WordPress's default 8% column. */ +.wp-list-table th.column-visible { + width: 170px; + min-width: 170px; +} + +.wp-list-table th.column-visible a { + display: inline-flex; + align-items: center; + gap: 4px; + white-space: nowrap; +} + +.wp-list-table th.column-visible a > span { + float: none; +} + +.wp-list-table th.column-visible .sorting-indicators { + display: grid; + flex: 0 0 auto; +} + +.wp-list-table th.column-visible .sorting-indicator { + margin-left: 0; +} diff --git a/src/Admin/LinkManager.php b/src/Admin/LinkManager.php index 867b7e83..6cebeaa8 100644 --- a/src/Admin/LinkManager.php +++ b/src/Admin/LinkManager.php @@ -12,11 +12,56 @@ defined('ABSPATH') || exit; final class LinkManager { public static function init(): void { add_action('admin_bar_menu', [self::class, 'add_toolbar_node'], 999); + add_action('admin_enqueue_scripts', [self::class, 'enqueue_assets']); add_filter('manage_link-manager_columns', [self::class, 'filter_columns']); + add_filter('get_terms_args', [self::class, 'show_empty_categories'], 10, 2); + add_filter('wp_dropdown_cats', [self::class, 'render_empty_category_option'], 10, 2); add_action('manage_link_custom_column', [self::class, 'render_column'], 10, 2); add_action('add_meta_boxes_link', [self::class, 'add_edit_help']); } + public static function enqueue_assets(string $hook): void { + if ($hook !== 'link-manager.php') { + return; + } + $path = get_template_directory() . '/assets/css/admin/links-manager.css'; + if (is_file($path)) { + wp_enqueue_style( + 'jio-links-manager', + get_template_directory_uri() . '/assets/css/admin/links-manager.css', + [], + (string) filemtime($path) + ); + } + } + + /** Include empty link categories in the link-manager filter. */ + public static function show_empty_categories(array $args, array $taxonomies): array { + if (self::is_link_manager_screen() && in_array('link_category', $taxonomies, true)) { + $args['hide_empty'] = false; + } + return $args; + } + + /** Give the category filter a readable option when no categories exist. */ + public static function render_empty_category_option(string $output, array $args): string { + if (!self::is_link_manager_screen() + || ($args['taxonomy'] ?? '') !== 'link_category' + || ($args['name'] ?? '') !== 'cat_id' + || preg_match('/'; + $updated = preg_replace('/(]*>)(\\s*)<\\/select>/i', '$1' . $placeholder . '', $output, 1); + return is_string($updated) ? $updated : $output; + } + + private static function is_link_manager_screen(): bool { + return is_admin() && ($GLOBALS['pagenow'] ?? '') === 'link-manager.php'; + } + public static function add_toolbar_node(\WP_Admin_Bar $admin_bar): void { if (!current_user_can('manage_links')) { return; diff --git a/tests/widget-system/link-manager-admin-contract.test.cjs b/tests/widget-system/link-manager-admin-contract.test.cjs new file mode 100644 index 00000000..dcd2fc58 --- /dev/null +++ b/tests/widget-system/link-manager-admin-contract.test.cjs @@ -0,0 +1,23 @@ +const test = require('node:test') +const assert = require('node:assert/strict') +const fs = require('node:fs') +const path = require('node:path') + +const root = path.resolve(__dirname, '..', '..') +const read = (file) => fs.readFileSync(path.join(root, file), 'utf8') + +test('native link manager explains an empty category filter and keeps visibility sorting inline', () => { + const manager = read('src/Admin/LinkManager.php') + const css = read('assets/css/admin/links-manager.css') + + assert.match(manager, /add_action\('admin_enqueue_scripts', \[self::class, 'enqueue_assets'\]\)/) + assert.match(manager, /add_filter\('get_terms_args', \[self::class, 'show_empty_categories'/) + assert.match(manager, /add_filter\('wp_dropdown_cats', \[self::class, 'render_empty_category_option'/) + assert.match(manager, /\$args\['hide_empty'\] = false/) + assert.match(manager, /暂无链接分类/) + assert.match(manager, /\$hook !== 'link-manager\.php'/) + + assert.match(css, /\.wp-list-table th\.column-visible\s*\{[^}]*min-width:\s*170px/s) + assert.match(css, /\.wp-list-table th\.column-visible a\s*\{[^}]*white-space:\s*nowrap/s) + assert.match(css, /\.sorting-indicators\s*\{[^}]*display:\s*grid/s) +})