Skip to content

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

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

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 );
			}
		}

This comment was marked as resolved.

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>
@swissspidy swissspidy marked this pull request as ready for review March 3, 2026 09:20
@swissspidy swissspidy requested a review from a team as a code owner March 3, 2026 09:21
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