Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save richardbuff/2962942da5266795faac1eda2d48d792 to your computer and use it in GitHub Desktop.
Save richardbuff/2962942da5266795faac1eda2d48d792 to your computer and use it in GitHub Desktop.
WP-CLI - Set all parent / ancestor categories for a WooCommerce product - WP-CLI custom command
<?php
// If a child category for WooCommerce Product is set, but the parent/grandparent/etc category is not set,
// running this will also set all the ancestor categories (parent, grandparent, etc...)
if ( defined('WP_CLI') && WP_CLI ) { //Check to make sure WP_CLI is running. This way our code isn't loaded on normal site visits.
/**
* Class EA_Set_All_Ancestor_Cats_For_A_Product
*/
class EA_Set_All_Ancestor_Cats_For_A_Product extends WP_CLI_Command {
public $step = 1;
public $per_step = 100;
public $post_count = 0;
public $max_num_pages = 0;
private $product_category_id = 0;
private $complete = false;
private $wc_product_taxonomy_slug = "product_cat";
public function __invoke( $args, $assoc_args ) {
list( $product_cat_id ) = $args;
$this->product_category_id = intval( $product_cat_id ); // <-- convert to integer so that term_exists works later as it needs an integer as input
// Value Checking - Verify the number is integer and greater than 0
if( false == filter_var( $this->product_category_id, FILTER_VALIDATE_INT ) || $this->product_category_id < 1 ) {
WP_CLI::error( 'You must specify a positive integer greater than zero.' );
return;
}
// Value Checking - Verify this is a valid term in the product_cat taxonomy
if( false == term_exists( $this->product_category_id, $this->wc_product_taxonomy_slug) ){
// invalid id so list the current root cat ids at the command line to make it easy on the user
WP_CLI::runcommand( 'term list product_cat --parent=0 --fields=id,name,slug --format=table' );
WP_CLI::error( 'A valid product category ID was not provided. Try again using one of the above product category/term IDs.' );
return;
}
// Count all posts that are using the passed product category ID
$args = array(
'posts_per_page' => -1,
'post_type' => 'product',
'fields' => 'ids',
'post_status' => 'any', // <-- we need to get the 'draft' ones too
'tax_query' => array(
array(
'taxonomy' => $this->wc_product_taxonomy_slug,
'field' => 'term_id', // Possible values are 'term_id', 'name', 'slug' or term_taxonomy_id'. Default value is 'term_id'.
'terms' => $this->product_category_id,
'include_children' => true // MUST BE A BOOLEAN NOT A STRING - switch this to false when you want to test how many are really there vs should be there
)
),
// 'no_found_rows' => true,
// 'update_post_term_cache' => false
);
$post_ids = new WP_Query( $args );
$this->post_count = count( $post_ids->posts );
// always round up.
// 80 total posts / 100 posts per step = .8 -> round this up to one page
// 120 total posts / 100 posts per step = 1.2 -> round this up to two pages
$this->max_num_pages = ceil( $this->post_count / $this->per_step );
wp_reset_postdata();
WP_CLI::line( 'Found ' . $this->post_count . ' posts' );
// WP_CLI::error('Wrapping up early for debugging reasons.');
while( false === $this->complete ){
$this->process_step();
} // end while
} // end function
private function process_step(){
// check to see if we've exceeded the pages
if( $this->max_num_pages < $this->step ){
$this->complete = true;
WP_CLI::line( 'We have exceeded the number of pages. Ending.' );
return;
} // end if
$args = array(
'posts_per_page' => $this->per_step,
'paged' => $this->step,
'post_type' => 'product',
'no_found_rows' => true,
'update_post_term_cache' => false,
'post_status' => 'any', // <-- we need to get the 'draft' ones too
'tax_query' => array(
array(
'taxonomy' => $this->wc_product_taxonomy_slug,
'field' => 'term_id', // Possible values are 'term_id', 'name', 'slug' or term_taxonomy_id'. Default value is 'term_id'.
'terms' => $this->product_category_id,
)
),
);
$my_query = new WP_Query( $args );
if( $my_query->have_posts() ):
while ( $my_query->have_posts() ) : $my_query->the_post();
WP_CLI::line(); // blank line for readability in terminal
global $post;
$terms = wp_get_object_terms( $post->ID, $this->wc_product_taxonomy_slug );
WP_CLI::line( $my_query->current_post . ' - Post ID: ' . $post->ID . ' || Post Title: ' . get_the_title($post->ID) . ' || Currently has these terms: ' . join( ', ', wp_list_pluck( $terms, 'name' ) ) );
foreach ( $terms as $term ) {
// Note this isn't super efficient probably. We could check to make sure the term
// ancestors weren't already asigned to the post but the overhead should matter
// too much running this via WP-CLI and only running it on thousands of products
// and not 10s of thousands
$ancestor_terms = get_ancestors( $term->term_id, $this->wc_product_taxonomy_slug );
if ( ! empty( $ancestor_terms ) ) {
wp_set_object_terms( $post->ID, $ancestor_terms, $this->wc_product_taxonomy_slug, true );
WP_CLI::line( 'Term name: ' . $term->name . ' || Term ID: ' . $term->term_id . ' > Ancestors added were: ' . join( ', ', $ancestor_terms ) );
} else {
WP_CLI::line( 'Term name: ' . $term->name . ' || Term ID: ' . $term->term_id . ' > Ancestors array was empty, must be a top level term' );
} // end if
} // end foreach
// Leave this off if dealing with thousands of posts
// WP_CLI::line( 'Updated post with ID ' . get_the_ID() );
endwhile;
// increment our step
WP_CLI::line( 'Completed Step #' . $this->step);
$this->step++;
else:
WP_CLI::line( 'ERROR! Query returned no posts!' );
endif;
wp_reset_postdata();
} // end function
} // end class
WP_CLI::add_command( 'setancestorcategoriesforproducts', 'EA_Set_All_Ancestor_Cats_For_A_Product' );
}// end if
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment