Skip to content

Add wp term prune command to remove terms with 0 or 1 published posts#586

Draft
Copilot wants to merge 5 commits intomainfrom
copilot/prune-terms-with-low-posts
Draft

Add wp term prune command to remove terms with 0 or 1 published posts#586
Copilot wants to merge 5 commits intomainfrom
copilot/prune-terms-with-low-posts

Conversation

Copy link
Contributor

Copilot AI commented Mar 2, 2026

  • Add prune method to Term_Command class in src/Term_Command.php
  • Update class-level docblock to include prune example
  • Add "term prune" to the commands list in composer.json
  • Create features/term-prune.feature with Behat tests
  • Run linting and code style checks - all pass
  • Run static analysis (PHPStan) - no errors
  • Address code review feedback (removed unreachable else block, renamed variable)
  • Combine the two separate foreach loops over $args into a single loop
  • Remove unused $prunable variable
Original prompt

This section details on the original issue you should resolve

<issue_title>Prune terms with one or less published posts</issue_title>
<issue_description>On large sites with thousands of tags or other terms, it would be helpful to have wp term prune to delete terms with one or less published posts.</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@swissspidy swissspidy added the command:term Related to 'term' command label Mar 2, 2026
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Copilot AI changed the title [WIP] Add wp term prune to delete terms with one or less published posts Add wp term prune command to remove terms with 0 or 1 published posts Mar 2, 2026
@swissspidy swissspidy requested a review from Copilot March 2, 2026 16:21
@swissspidy

This comment was marked as resolved.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a valuable wp term prune command for cleaning up unused or barely-used terms, which is particularly useful for large sites. The implementation is solid and is accompanied by a comprehensive set of Behat tests covering various scenarios. My review includes a single, significant suggestion to refactor the prune method. The proposed changes aim to improve performance by using a more efficient database query, enhance code readability by consolidating loops, and increase robustness by handling a potential edge case during term deletion. Overall, this is a great addition.

Comment on lines 725 to 785
foreach ( $args as $taxonomy ) {
if ( ! taxonomy_exists( $taxonomy ) ) {
WP_CLI::error( "Taxonomy {$taxonomy} doesn't exist." );
}
}

$dry_run = (bool) Utils\get_flag_value( $assoc_args, 'dry-run', false );

foreach ( $args as $taxonomy ) {
$terms = get_terms(
[
'taxonomy' => $taxonomy,
'hide_empty' => false,
]
);

// This should never happen because of the taxonomy_exists check above.
if ( is_wp_error( $terms ) ) {
WP_CLI::warning( "Could not retrieve terms for taxonomy {$taxonomy}." );
continue;
}

/**
* @var \WP_Term[] $terms
*/

$total = 0;
$successes = 0;
$errors = 0;

foreach ( $terms as $term ) {
if ( $term->count > 1 ) {
continue;
}

++$total;

if ( $dry_run ) {
WP_CLI::log( "Would delete {$taxonomy} {$term->term_id}." );
++$successes;
continue;
}

$result = wp_delete_term( $term->term_id, $taxonomy );

if ( is_wp_error( $result ) ) {
WP_CLI::warning( $result );
++$errors;
} elseif ( $result ) {
WP_CLI::log( "Deleted {$taxonomy} {$term->term_id}." );
++$successes;
}
}

if ( $dry_run ) {
$term_word = Utils\pluralize( 'term', $successes );
WP_CLI::success( "{$successes} {$taxonomy} {$term_word} would be pruned." );
} else {
Utils\report_batch_operation_results( 'term', 'prune', $total, $successes, $errors );
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The prune function can be refactored for better performance, readability, and robustness.

  1. Performance: Instead of fetching all terms with get_terms() and then filtering them in PHP, it's more efficient to query the database directly for only the term IDs that need to be pruned (i.e., those with a count of 1 or less). This will significantly improve performance on sites with a large number of terms.
  2. Readability: The two separate foreach loops iterating over $args can be combined into a single loop. You can perform the taxonomy_exists() check at the beginning of each iteration before proceeding with the pruning logic for that taxonomy.
  3. Robustness: The wp_delete_term() function returns false if the term to be deleted doesn't exist. This edge case (which could happen in a race condition) should be handled by issuing a warning, similar to how the term delete command behaves.

Here is a suggested refactoring that applies these improvements:

        global $wpdb;

		$dry_run = (bool) Utils\get_flag_value( $assoc_args, 'dry-run', false );

		foreach ( $args as $taxonomy ) {
			if ( ! taxonomy_exists( $taxonomy ) ) {
				WP_CLI::error( "Taxonomy {$taxonomy} doesn't exist." );
			}

			$term_ids_to_prune = $wpdb->get_col(
				$wpdb->prepare(
					"SELECT term_id FROM {$wpdb->term_taxonomy} WHERE taxonomy = %s AND count <= 1",
					$taxonomy
				)
			);

			$total     = count( $term_ids_to_prune );
			$successes = 0;
			$errors    = 0;

			if ( $total > 0 ) {
				foreach ( $term_ids_to_prune as $term_id ) {
					if ( $dry_run ) {
						WP_CLI::log( "Would delete {$taxonomy} {$term_id}." );
						++$successes;
						continue;
					}

					$result = wp_delete_term( $term_id, $taxonomy );

					if ( is_wp_error( $result ) ) {
						WP_CLI::warning( $result );
						++$errors;
					} elseif ( $result ) {
						WP_CLI::log( "Deleted {$taxonomy} {$term_id}." );
						++$successes;
					} else {
						WP_CLI::warning( "Term {$term_id} in taxonomy {$taxonomy} doesn't exist." );
					}
				}
			}

			if ( $dry_run ) {
				$term_word = Utils\pluralize( 'term', $successes );
				WP_CLI::success( "{$successes} {$taxonomy} {$term_word} would be pruned." );
			} else {
				Utils\report_batch_operation_results( 'term', 'prune', $total, $successes, $errors );
			}
		}

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new wp term prune subcommand to help bulk-remove low-usage terms (0–1 posts) from one or more taxonomies, with optional dry-run behavior for previewing deletions.

Changes:

  • Adds Term_Command::prune() to find and delete terms with count <= 1, plus --dry-run support.
  • Registers term prune in composer.json so the command is discoverable by WP-CLI.
  • Adds Behat coverage for prune behavior across several scenarios (0 posts, 1 post, 2+ posts, dry-run, invalid taxonomy, multi-taxonomy).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/Term_Command.php Implements the new wp term prune subcommand and its CLI output paths (dry-run vs delete).
features/term-prune.feature Adds end-to-end Behat scenarios validating prune behavior and error handling.
composer.json Registers the new command in the commands list.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

swissspidy and others added 2 commits March 2, 2026 17:52
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

command:term Related to 'term' command

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Prune terms with one or less published posts

3 participants