From 1144256540046c8fef7c9bda5714e4fba00cfe9d Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Tue, 6 Jan 2026 15:04:35 -0700 Subject: [PATCH 01/23] feat: add support for displaying tags as labels --- includes/class-newspack.php | 3 + includes/tag-labels/class-tag-labels.php | 202 +++++++++++++++++++++++ src/other-scripts/tag-labels/index.js | 11 ++ 3 files changed, 216 insertions(+) create mode 100644 includes/tag-labels/class-tag-labels.php create mode 100644 src/other-scripts/tag-labels/index.js diff --git a/includes/class-newspack.php b/includes/class-newspack.php index 26aab9a957..47d50e65af 100644 --- a/includes/class-newspack.php +++ b/includes/class-newspack.php @@ -235,6 +235,9 @@ private function includes() { // Filter by authors in the Posts page. include_once NEWSPACK_ABSPATH . 'includes/author-filter/class-author-filter.php'; + // Display tags as labels. + include_once NEWSPACK_ABSPATH . 'includes/tag-labels/class-tag-labels.php'; + // Load the general Newspack UI front-end styles. include_once NEWSPACK_ABSPATH . 'includes/class-newspack-ui.php'; include_once NEWSPACK_ABSPATH . 'includes/class-newspack-ui-icons.php'; diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php new file mode 100644 index 0000000000..99350125ce --- /dev/null +++ b/includes/tag-labels/class-tag-labels.php @@ -0,0 +1,202 @@ +term_id ) { + return false; + } + return (bool) ( true == get_term_meta( $term->term_id, self::TAG_LABEL_META_KEY, true ) ); + } + + /** + * Given a term, return the flag (text) of its label and + * the link to the term archive. + * + * Will return null if label isn't enabled for the term. + * + * @param WP_Term $term Term to check. + * + * @return array|null As ['flag' => FLAG_NAME, 'link' => TERM_LINK]. + */ + public static function get_tag_label_for_term( $term ) { + if ( ! $term || ! $term->term_id || ! self::is_tag_label( $term ) ) { + return null; + } + + // A little fancy in case someone wants to give a tag a + // falsy label flag. Empty string still gets default value. + $term_label_flag = get_term_meta( $term->term_id, self::TAG_LABEL_FLAG_META_KEY, true ); + $term_label_flag = isset( $term_label_flag ) ? ( ( '' !== $term_label_flag ) ? $term_label_flag : $term->name ) : $term->name; + + $term_label_link = get_term_link( $term->term_id ); + + return [ + 'flag' => $term_label_flag, + 'link' => $term_label_link, + ]; + } + + /** + * Given a post ID, grab array of tag labels (if any) for it. + * + * @param int $post_id Post ID. + * + * @return array Elements as ['flag' => FLAG_NAME, 'link' => TERM_LINK]. + */ + public static function get_labels_for_post( $post_id ) { + $post_terms = get_the_terms( $post_id, 'post_tag' ); + + if ( ! $post_terms ) { + return []; + } + + return array_filter( + array_map( + function( $term ) { + return self::get_tag_label_for_term( $term ); + }, + $post_terms + ) + ); + } + + /** + * Initialize hooks. + */ + public static function init() { + add_action( 'post_tag_term_edit_form_top', array( __CLASS__, 'enqueue_scripts' ) ); + + add_action( 'post_tag_edit_form_fields', [ __CLASS__, 'edit_term' ] ); + add_action( 'edited_post_tag', [ __CLASS__, 'save_term' ] ); + } + + /** + * Enqueues js script + * + * @return void + */ + public static function enqueue_scripts() { + wp_enqueue_script( + 'newspack_tag_labels', + Newspack::plugin_url() . '/dist/other-scripts/tag-labels.js', + [ 'jquery' ], + NEWSPACK_PLUGIN_VERSION, + true + ); + } + + /** + * Add term edit fields. + * + * Toggle to determine if the term is a label. + * Also, override for flag (text used on label). + * + * @param WP_Term $term The current WP_Term object. + */ + public static function edit_term( $term ) { + $is_label = self::is_tag_label( $term ); + + $label = self::get_tag_label_for_term( $term ); + $label_flag = $label ? $label['flag'] : $term->name; + ?> + + + + + > +

+ +

+ + + + + + name === $label_flag ) { + echo ' value=""'; + } else { + echo ' value="' . esc_attr( $label_flag ) . '"'; + } + + if ( ! $is_label ) { + echo ' disabled'; } + ?> + > +

+ +

+ + + Date: Thu, 8 Jan 2026 13:31:12 -0700 Subject: [PATCH 02/23] fix: apply suggestions from Copilot code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- includes/tag-labels/class-tag-labels.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index 99350125ce..a02d21ae96 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -24,7 +24,7 @@ class Tag_Labels { const TAG_LABEL_FLAG_META_KEY = '_label_flag'; - // TODO: Helper functions for themes to get array of labels + flags. + // Helper functions for themes to get arrays of labels and flags. /** * Given a term, check if labels are enabled for it. * @@ -36,7 +36,7 @@ public static function is_tag_label( $term ) { if ( ! $term || ! $term->term_id ) { return false; } - return (bool) ( true == get_term_meta( $term->term_id, self::TAG_LABEL_META_KEY, true ) ); + return (bool) ( true === get_term_meta( $term->term_id, self::TAG_LABEL_META_KEY, true ) ); } /** @@ -57,7 +57,9 @@ public static function get_tag_label_for_term( $term ) { // A little fancy in case someone wants to give a tag a // falsy label flag. Empty string still gets default value. $term_label_flag = get_term_meta( $term->term_id, self::TAG_LABEL_FLAG_META_KEY, true ); - $term_label_flag = isset( $term_label_flag ) ? ( ( '' !== $term_label_flag ) ? $term_label_flag : $term->name ) : $term->name; + if ( ! isset( $term_label_flag ) || '' === $term_label_flag ) { + $term_label_flag = $term->name; + } $term_label_link = get_term_link( $term->term_id ); @@ -86,8 +88,8 @@ public static function get_labels_for_post( $post_id ) { function( $term ) { return self::get_tag_label_for_term( $term ); }, - $post_terms - ) + $post_terms + ) ); } From 0fe60fb10fdf8f7f1fc211670db676d98ac09034 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 8 Jan 2026 14:42:52 -0700 Subject: [PATCH 03/23] fix: cleanup; Copilot suggestions --- includes/tag-labels/class-tag-labels.php | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index a02d21ae96..599a2f8272 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -127,17 +127,21 @@ public static function enqueue_scripts() { * @param WP_Term $term The current WP_Term object. */ public static function edit_term( $term ) { + $checkbox_id = self::TAG_LABEL_META_KEY; $is_label = self::is_tag_label( $term ); $label = self::get_tag_label_for_term( $term ); $label_flag = $label ? $label['flag'] : $term->name; + + $input_label_flag = ( $term->name === $label_flag ) ? '' : $label_flag; ?> name === $label_flag ) { - echo ' value=""'; - } else { - echo ' value="' . esc_attr( $label_flag ) . '"'; - } - if ( ! $is_label ) { echo ' disabled'; } ?> @@ -184,6 +184,9 @@ public static function save_term( $term_id ) { // See wp-admin/edit-tag-form.php for where this is set. check_admin_referer( 'update-tag_' . $term_id ); + if ( ! current_user_can( 'edit_term', $term_id ) ) { + return; } + // Save label data if label is enabled; otherwise kill it. if ( ! empty( $_POST[ self::TAG_LABEL_META_KEY ] ) ) { update_term_meta( $term_id, self::TAG_LABEL_META_KEY, true ); From 36e8403906f356c622cf2f4b8eb88b0a5377d43e Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 8 Jan 2026 15:00:44 -0700 Subject: [PATCH 04/23] fix: tweaks; Copilot suggestions --- includes/tag-labels/class-tag-labels.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index 599a2f8272..ae72daa113 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -36,7 +36,7 @@ public static function is_tag_label( $term ) { if ( ! $term || ! $term->term_id ) { return false; } - return (bool) ( true === get_term_meta( $term->term_id, self::TAG_LABEL_META_KEY, true ) ); + return (bool) ( true == get_term_meta( $term->term_id, self::TAG_LABEL_META_KEY, true ) ); // Meta value is 1 when enabled; use less-strict equivalence here. } /** @@ -185,7 +185,8 @@ public static function save_term( $term_id ) { check_admin_referer( 'update-tag_' . $term_id ); if ( ! current_user_can( 'edit_term', $term_id ) ) { - return; } + return; + } // Save label data if label is enabled; otherwise kill it. if ( ! empty( $_POST[ self::TAG_LABEL_META_KEY ] ) ) { From 2b427beae1341ed2b4f5b54be60bda8520f1f0ba Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Fri, 9 Jan 2026 10:42:43 -0700 Subject: [PATCH 05/23] chore: clean up comments --- includes/tag-labels/class-tag-labels.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index ae72daa113..d5c3070002 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -7,8 +7,6 @@ namespace Newspack; -// TODO: Semaphore to only init once. - defined( 'ABSPATH' ) || exit; /** From 25214593507568213aa22c97565a4eb717bcbfc0 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Tue, 13 Jan 2026 13:55:39 -0700 Subject: [PATCH 06/23] fix: incorporate feedback on names, outdated variables --- includes/tag-labels/class-tag-labels.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index d5c3070002..8b8ad97daa 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -17,9 +17,8 @@ class Tag_Labels { /** * Key names. */ - const TAG_LABEL_SLUG = 'label'; - const TAG_LABEL_META_KEY = '_label_enabled'; - const TAG_LABEL_FLAG_META_KEY = '_label_flag'; + const TAG_LABEL_META_KEY = '_np_label_enabled'; + const TAG_LABEL_FLAG_META_KEY = '_np_label_flag'; // Helper functions for themes to get arrays of labels and flags. @@ -34,7 +33,7 @@ public static function is_tag_label( $term ) { if ( ! $term || ! $term->term_id ) { return false; } - return (bool) ( true == get_term_meta( $term->term_id, self::TAG_LABEL_META_KEY, true ) ); // Meta value is 1 when enabled; use less-strict equivalence here. + return ! empty( get_term_meta( $term->term_id, self::TAG_LABEL_META_KEY, true ) ); } /** From ae531b4acba72d0848c87327773df91d5a4e06c0 Mon Sep 17 00:00:00 2001 From: Thomas Guillot Date: Fri, 16 Jan 2026 11:12:53 +0000 Subject: [PATCH 07/23] feat: rename settings; display flag_meta_key only if checkbox is checked --- includes/tag-labels/class-tag-labels.php | 10 +++++----- src/other-scripts/tag-labels/index.js | 21 ++++++++++++++++----- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index 8b8ad97daa..68417bf626 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -133,7 +133,7 @@ public static function edit_term( $term ) { $input_label_flag = ( $term->name === $label_flag ) ? '' : $label_flag; ?> - + >

- +

- - + > + >

- +

diff --git a/src/other-scripts/tag-labels/index.js b/src/other-scripts/tag-labels/index.js index 57f1d374b1..c320a2fc06 100644 --- a/src/other-scripts/tag-labels/index.js +++ b/src/other-scripts/tag-labels/index.js @@ -1,11 +1,22 @@ /* globals jQuery */ ( function ( $ ) { - $( '.newspack-label-enable input[type="checkbox"]' ).on( 'change', function () { - if ( $( this ).is( ':checked' ) ) { - $( '.newspack-label-setting input' ).prop( 'disabled', false ); + function toggleLabelSetting() { + const checkbox = $( '.newspack-label-enable input[type="checkbox"]' ); + const labelSettingRow = $( '.newspack-label-setting' ); + + if ( checkbox.is( ':checked' ) ) { + labelSettingRow.show(); + labelSettingRow.find( 'input' ).prop( 'disabled', false ); } else { - $( '.newspack-label-setting input' ).prop( 'disabled', true ); + labelSettingRow.hide(); + labelSettingRow.find( 'input' ).prop( 'disabled', true ); } - } ); + } + + // Set initial state on page load. + toggleLabelSetting(); + + // Update on checkbox change. + $( '.newspack-label-enable input[type="checkbox"]' ).on( 'change', toggleLabelSetting ); } )( jQuery ); From 75786a1b5ba873d235da57637259dc46fcdcaa63 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Tue, 20 Jan 2026 16:12:19 -0700 Subject: [PATCH 08/23] refactor: accept WP_Post object or post ID, as is done elsewhere --- includes/tag-labels/class-tag-labels.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index 68417bf626..3735383250 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -69,11 +69,16 @@ public static function get_tag_label_for_term( $term ) { /** * Given a post ID, grab array of tag labels (if any) for it. * - * @param int $post_id Post ID. + * @param int|WP_Post|null $post Post to check. * - * @return array Elements as ['flag' => FLAG_NAME, 'link' => TERM_LINK]. + * @return array|null Elements as ['flag' => FLAG_NAME, 'link' => TERM_LINK]. */ - public static function get_labels_for_post( $post_id ) { + public static function get_labels_for_post( $post ) { + if ( ! $post ) { + return null; + } + + $post_id = ( is_a( 'WP_POST', $post ) ? $post->ID : (int) $post ); $post_terms = get_the_terms( $post_id, 'post_tag' ); if ( ! $post_terms ) { From 62cd9c7b598ca87e9553e8349c6bc4c17641e069 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 22 Jan 2026 15:35:40 -0700 Subject: [PATCH 09/23] feat: add support for setting tag labels on term creation --- includes/tag-labels/class-tag-labels.php | 90 +++++++++++++++++++++--- 1 file changed, 79 insertions(+), 11 deletions(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index 3735383250..28a5e9ba1d 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -99,10 +99,14 @@ function( $term ) { * Initialize hooks. */ public static function init() { + add_action( 'post_tag_pre_add_form', array( __CLASS__, 'enqueue_scripts' ) ); add_action( 'post_tag_term_edit_form_top', array( __CLASS__, 'enqueue_scripts' ) ); + add_action( 'post_tag_add_form_fields', [ __CLASS__, 'add_term' ] ); add_action( 'post_tag_edit_form_fields', [ __CLASS__, 'edit_term' ] ); - add_action( 'edited_post_tag', [ __CLASS__, 'save_term' ] ); + + add_action( 'created_post_tag', [ __CLASS__, 'save_new_term' ] ); + add_action( 'edited_post_tag', [ __CLASS__, 'save_existing_term' ] ); } /** @@ -121,7 +125,45 @@ public static function enqueue_scripts() { } /** - * Add term edit fields. + * Term creation fields. + * + * Toggle to determine if the term is a label. + * Also, override for flag (text used on label). + */ + public static function add_term() { + $checkbox_id = self::TAG_LABEL_META_KEY; + ?> +
+ + +

+ +

+
+ + Date: Fri, 23 Jan 2026 17:06:46 -0700 Subject: [PATCH 10/23] refactor: upstream handles nonce verification; handling here breaks our unit tests --- includes/tag-labels/class-tag-labels.php | 37 ++---------------------- 1 file changed, 3 insertions(+), 34 deletions(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index 28a5e9ba1d..9948fd6d86 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -105,8 +105,8 @@ public static function init() { add_action( 'post_tag_add_form_fields', [ __CLASS__, 'add_term' ] ); add_action( 'post_tag_edit_form_fields', [ __CLASS__, 'edit_term' ] ); - add_action( 'created_post_tag', [ __CLASS__, 'save_new_term' ] ); - add_action( 'edited_post_tag', [ __CLASS__, 'save_existing_term' ] ); + add_action( 'created_post_tag', [ __CLASS__, 'save_term' ] ); + add_action( 'edited_post_tag', [ __CLASS__, 'save_term' ] ); } /** @@ -218,7 +218,7 @@ public static function edit_term( $term ) { Date: Fri, 23 Jan 2026 17:12:47 -0700 Subject: [PATCH 11/23] refactor: upstream handles nonce verification; handling here breaks our unit tests --- includes/tag-labels/class-tag-labels.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index 9948fd6d86..66e345898d 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -224,7 +224,7 @@ public static function edit_term( $term ) { * * @param int $term_id Term ID. */ - private static function save_term( $term_id ) { + public static function save_term( $term_id ) { // Save label data if label is enabled; otherwise kill it. if ( ! empty( $_POST[ self::TAG_LABEL_META_KEY ] ) ) { From 31e8baf7a75a149be5a91712e2b6715e11f96177 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Fri, 23 Jan 2026 18:25:33 -0700 Subject: [PATCH 12/23] fix: reversed function parameters --- includes/tag-labels/class-tag-labels.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index 66e345898d..9464c9ff6e 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -78,7 +78,7 @@ public static function get_labels_for_post( $post ) { return null; } - $post_id = ( is_a( 'WP_POST', $post ) ? $post->ID : (int) $post ); + $post_id = ( is_a( $post, 'WP_Post' ) ? $post->ID : (int) $post ); $post_terms = get_the_terms( $post_id, 'post_tag' ); if ( ! $post_terms ) { From 77c21e3b4cbda441a58a169ea8a4884116302764 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Fri, 23 Jan 2026 18:32:01 -0700 Subject: [PATCH 13/23] refactor: renamed 'is_tag_label' to 'has_label' --- includes/tag-labels/class-tag-labels.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index 9464c9ff6e..a577847c2b 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -29,7 +29,7 @@ class Tag_Labels { * * @return bool */ - public static function is_tag_label( $term ) { + public static function has_label( $term ) { if ( ! $term || ! $term->term_id ) { return false; } @@ -47,7 +47,7 @@ public static function is_tag_label( $term ) { * @return array|null As ['flag' => FLAG_NAME, 'link' => TERM_LINK]. */ public static function get_tag_label_for_term( $term ) { - if ( ! $term || ! $term->term_id || ! self::is_tag_label( $term ) ) { + if ( ! $term || ! $term->term_id || ! self::has_label( $term ) ) { return null; } @@ -172,7 +172,7 @@ public static function add_term() { */ public static function edit_term( $term ) { $checkbox_id = self::TAG_LABEL_META_KEY; - $is_label = self::is_tag_label( $term ); + $is_label = self::has_label( $term ); $label = self::get_tag_label_for_term( $term ); $label_flag = $label ? $label['flag'] : $term->name; From 53597d50ff6ea2ce1044ae7f8dc81f062caa90dc Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Fri, 23 Jan 2026 18:34:49 -0700 Subject: [PATCH 14/23] fix: apply Copilot suggestion Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- includes/tag-labels/class-tag-labels.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index a577847c2b..ede975db50 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -151,7 +151,7 @@ public static function add_term() { aria-describedby="-description" type="text" name="" - placeholder="Enter custom label text" + placeholder="" value="" disabled > From b8b0e0f886e8915d2ddfa768738c23b75077d3b9 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Mon, 9 Mar 2026 01:17:16 -0700 Subject: [PATCH 15/23] refactor: centralized HTML generation function and interface to `newspack-plugin` --- includes/tag-labels/class-tag-labels.php | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index ede975db50..835d1851db 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -95,6 +95,55 @@ function( $term ) { ); } + /** + * Generates HTML for given tag labels. + * + * @param array $labels Labels to display. + * @param bool $links Whether to include links to tag archives. + * @param array $outer_classes Classes to apply to the outer container. + * @param array $inner_classes Classes to apply to the inner container. + * @param string $outer_element HTML element to use for the outer container. + * + * @return string Tag labels as HTML. + */ + public static function generate_html( $labels = null, $links = true, $outer_classes = array( 'tag-labels' ), $inner_classes = array( 'tag-label', 'flag' ), $outer_element = 'span' ) { + if ( empty( $labels ) ) { + return ''; + } + + $outer_element = in_array( $outer_element, [ 'span', 'div' ], true ) ? $outer_element : 'span'; + + $labels_html = ''; + $labels_html .= '<' . $outer_element . ' class="' . join( ' ', array_map( 'esc_attr', $outer_classes ) ) . '">'; + foreach ( $labels as $label ) { + if ( $links && isset( $label['flag'] ) && $label['link'] ) { + $labels_html .= ''; + } elseif ( isset( $label['flag'] ) ) { + $labels_html .= '' . esc_html( $label['flag'] ) . ''; + } + } + $labels_html .= ''; + + return $labels_html; + } + + /** + * Outputs HTML for given tag labels. + * + * @param array $labels Labels to display. + * @param bool $links Whether to include links to tag archives. + * @param string $outer_element HTML element to use for the outer container. + * + * @return void + */ + public static function display( $labels = null, $links = true, $outer_element = 'span' ) { + if ( empty( $labels ) ) { + return; + } + + echo wp_kses_post( self::generate_html( $labels, $links, array( 'tag-labels', 'cat-links' ), array( 'tag-label', 'flag' ), $outer_element ) . ' ' ); + } + /** * Initialize hooks. */ From f52c9441b740dcca774f20d8d2512fa356693b90 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Wed, 11 Mar 2026 22:29:08 -0700 Subject: [PATCH 16/23] fix: add capabilities test --- includes/tag-labels/class-tag-labels.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index 835d1851db..77e6b37225 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -274,6 +274,9 @@ public static function edit_term( $term ) { * @param int $term_id Term ID. */ public static function save_term( $term_id ) { + if ( ! current_user_can( 'manage_categories' ) ) { + return; + } // Save label data if label is enabled; otherwise kill it. if ( ! empty( $_POST[ self::TAG_LABEL_META_KEY ] ) ) { From 43e70eedb59fbc04fedf75fce9888e8787f6bb83 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Mon, 30 Mar 2026 12:54:04 -0700 Subject: [PATCH 17/23] fix: populate `id` attributes to improve usability --- includes/tag-labels/class-tag-labels.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index 77e6b37225..a71cd79fc8 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -187,6 +187,7 @@ public static function add_term() { @@ -199,6 +200,7 @@ public static function add_term() { Date: Mon, 30 Mar 2026 12:56:50 -0700 Subject: [PATCH 18/23] fix: handle potential `WP_Error`, as suggested by Copilot --- includes/tag-labels/class-tag-labels.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index a71cd79fc8..efda7fc1c8 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -59,6 +59,9 @@ public static function get_tag_label_for_term( $term ) { } $term_label_link = get_term_link( $term->term_id ); + if ( is_wp_error( $term_label_link ) ) { + return null; + } return [ 'flag' => $term_label_flag, @@ -81,7 +84,7 @@ public static function get_labels_for_post( $post ) { $post_id = ( is_a( $post, 'WP_Post' ) ? $post->ID : (int) $post ); $post_terms = get_the_terms( $post_id, 'post_tag' ); - if ( ! $post_terms ) { + if ( empty( $post_terms ) || is_wp_error( $post_terms ) ) { return []; } From 626bcc5cfb1e6f3ca963f7f68be89824334c61ab Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Mon, 30 Mar 2026 13:06:53 -0700 Subject: [PATCH 19/23] fix: do not clear `_np_label_flag` when labels disabled --- includes/tag-labels/class-tag-labels.php | 1 - 1 file changed, 1 deletion(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index efda7fc1c8..2c1a8b0cd1 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -297,7 +297,6 @@ public static function save_term( $term_id ) { } } else { delete_term_meta( $term_id, self::TAG_LABEL_META_KEY ); - delete_term_meta( $term_id, self::TAG_LABEL_FLAG_META_KEY ); } } // phpcs:enable WordPress.Security.NonceVerification.Missing From 849d7c85cdf48b952a39f88474a0875e9fc7a50e Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Mon, 25 May 2026 22:38:46 -0700 Subject: [PATCH 20/23] refactor: drop dead isset() check on get_term_meta result --- includes/tag-labels/class-tag-labels.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index 2c1a8b0cd1..b4168325c6 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -54,7 +54,7 @@ public static function get_tag_label_for_term( $term ) { // A little fancy in case someone wants to give a tag a // falsy label flag. Empty string still gets default value. $term_label_flag = get_term_meta( $term->term_id, self::TAG_LABEL_FLAG_META_KEY, true ); - if ( ! isset( $term_label_flag ) || '' === $term_label_flag ) { + if ( '' === $term_label_flag ) { $term_label_flag = $term->name; } From cdcc843ba76ac9671e5031dd120598d032fe70fe Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Mon, 25 May 2026 23:57:46 -0700 Subject: [PATCH 21/23] fix: scope save_term to this UI's form submissions via nonce --- includes/tag-labels/class-tag-labels.php | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index b4168325c6..a4e003e3b7 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -213,6 +213,7 @@ public static function add_term() {

+ + Date: Tue, 26 May 2026 00:20:59 -0700 Subject: [PATCH 22/23] style: wrap edit_term nonce in tr/td for valid HTML inside form-table --- includes/tag-labels/class-tag-labels.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index a4e003e3b7..a581aeb159 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -272,7 +272,7 @@ public static function edit_term( $term ) {

- + Date: Tue, 26 May 2026 00:28:56 -0700 Subject: [PATCH 23/23] fix: preserve _np_label_flag in edit form across enable/disable cycles --- includes/tag-labels/class-tag-labels.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/includes/tag-labels/class-tag-labels.php b/includes/tag-labels/class-tag-labels.php index a581aeb159..560aa8ca4d 100644 --- a/includes/tag-labels/class-tag-labels.php +++ b/includes/tag-labels/class-tag-labels.php @@ -229,10 +229,10 @@ public static function edit_term( $term ) { $checkbox_id = self::TAG_LABEL_META_KEY; $is_label = self::has_label( $term ); - $label = self::get_tag_label_for_term( $term ); - $label_flag = $label ? $label['flag'] : $term->name; - - $input_label_flag = ( $term->name === $label_flag ) ? '' : $label_flag; + // Read the stored flag directly so the input value survives disable→re-enable cycles — + // get_tag_label_for_term() returns null when has_label() is false, which would hide it. + $stored_flag = get_term_meta( $term->term_id, self::TAG_LABEL_FLAG_META_KEY, true ); + $input_label_flag = ( '' === $stored_flag || $term->name === $stored_flag ) ? '' : $stored_flag; ?>