When removing terms from a post, delete terms which contain zero post. When updating a post, delete terms which contain zero post.
I have tried the code below, but it doesn't work:
add_filter('wp_remove_object_terms','delete_unused_terms');
function delete_unused_terms($term_ids, $taxonomy) {
foreach ( $term_ids as $term_id ) {
$term = get_term($term_id, $taxonomy);
$term_count = $term->count;
if ($term_count<1) {
wp_delete_term($term_id, $taxonomy);
}
}
}
Unfortunately, there is no wp_remove_object_terms filter.
But there is an action deleted_term_relationships;
Please, try to use
add_action( 'deleted_term_relationships', 'yuor_prefix_update_delete_term_if_empty', 10, 3 );
function yuor_prefix_update_delete_term_if_empty( $object_id, $term_ids, $taxonomy ) {
wp_update_term_count( $term_ids, $taxonomy );
foreach ( $term_ids as $term_id ) {
$term = get_term($term_id, $taxonomy);
$term_count = $term->count;
if ($term_count<1) {
wp_delete_term($term_id, $taxonomy);
}
}
}
Related
I am trying to achieve an order prefix between "Parent Order" and "Sub Orders". Currently I have the order prefix's working for products in specific categories, so 'Merchandise' Categories and products within have the order number prefix 'M' and the Categories and products within 'Coffee' have the prefix 'C', this all works fine, brilliantly see the image attached.
I do have subscription products and single products within the store but I mainly just want the one 'P' to show up for the main order regardless of the category the product is within.
I need and would like help adding for the parent order a 'P' so that I can distinguish between Parent and sub orders, (please see attached image) I cannot for the life of me figure out this function currently my code is this:
add_filter( 'woocommerce_order_number', 'change_woocommerce_order_number' );
function change_woocommerce_order_number( $order_id ) {
$order = wc_get_order( $order_id );
$category = array();
if ( ! empty($order) ) {
foreach ( $order->get_items() as $item_id => $item ) {
$product_id = $item['product_id'];
$terms = get_the_terms ( $product_id, 'product_cat' );
$parent_id = $order->get_parent_id( $parent, 'product_id' );
if ( ! empty($terms) ) {
foreach ( $terms as $term ) {
$category[] = $term->term_id;
}
}
}
}
if ( $parent ) {
$order_id = 'P - '. $order_id;
} else {
if ( in_array( 23, $category ) ) {
$order_id = 'M - '. $order_id;
} else {
if ( in_array( 16, $category ) ) {
$order_id = 'C - '. $order_id;
}
}
return $order_id;
}
}
The 'M' & 'C' work perfectly... just the parent order 'P' does not so instead of a 'P' I have what seems to be a random M or C in the parent order section. All my orders split in categories and this still works as expected (please see image). I mainly just need the 'P' Main Parent order on the left from the image attached
Parent Order Prefix 'P' Location
Thanks in advance.
You are currently returning the order number only within the else statement.
A value should always be returned at the end of the function.
Also the $parent variable is not set and you are getting the parent id the wrong way.
Try this, hope it works.
The get_parent_id() method returns 0 if the function has no parent order.
add_filter( 'woocommerce_order_number', 'change_woocommerce_order_number' );
function change_woocommerce_order_number( $order_id ) {
$order = wc_get_order( $order_id );
$category = array();
if ( ! empty($order) ) {
foreach ( $order->get_items() as $item_id => $item ) {
$product_id = $item['product_id'];
$terms = get_the_terms ( $product_id, 'product_cat' );
if ( ! empty($terms) ) {
foreach ( $terms as $term ) {
$category[] = $term->term_id;
}
}
}
}
$parent_id = $order->get_parent_id();
if ( $parent_id > 0 ) {
if ( in_array( 23, $category ) ) {
$order_id = 'M - '. $order_id;
} else {
if ( in_array( 16, $category ) ) {
$order_id = 'C - '. $order_id;
}
}
} else {
$order_id = 'P - '. $order_id;
}
return $order_id;
}
Also you could optimize the function like this:
// change the WooCommerce order number
add_filter( 'woocommerce_order_number', 'change_woocommerce_order_number' );
function change_woocommerce_order_number( $order_id ) {
$order = wc_get_order( $order_id );
$prefix = '';
$has_cat_id_23 = false;
$has_cat_id_16 = false;
// get the parent order id
$parent_id = $order->get_parent_id();
// if it does not have a parent order it returns the order number with the prefix "P - "
if ( $parent_id == 0 ) {
$prefix = 'P - ';
return $prefix . $order_id;
// otherwise set the prefix to the child orders
} else {
foreach ( $order->get_items() as $item_id => $item ) {
// if the product belongs to the product category with ID 23
if ( has_term( 23, 'product_cat', $item['product_id'] ) ) {
$has_cat_id_23 = true;
break;
}
// if the product belongs to the product category with ID 16
if ( has_term( 16, 'product_cat', $item['product_id'] ) ) {
$has_cat_id_16 = true;
break;
}
}
// if the product belongs to the product category with ID 23 set the prefix "M - "
if ( $has_cat_id_23 ) {
$prefix = 'M - ';
}
// if the product belongs to the product category with ID 16 set the prefix "C - "
if ( $has_cat_id_16 ) {
$prefix = 'C - ';
}
}
return $prefix . $order_id;
}
The code has been tested and works (I didn't install the plugin but actually only used Wordpress and WooCommerce functions and methods). The result will look like:
Try it out and let me know if it works for you too.
I already found a snippet to sort the checkout cart alphabetically. This works perfect but as mentioned I try to sort and group my products by category.
Is there anyone who could tweak the following snippet so it sorts the products by category?
add_action( 'woocommerce_cart_loaded_from_session', 'bbloomer_sort_cart_items_alphabetically' );
function bbloomer_sort_cart_items_alphabetically() {
global $woocommerce;
// READ CART ITEMS
$products_in_cart = array();
foreach ( $woocommerce->cart->cart_contents as $key => $item ) {
$products_in_cart[ $key ] = $item['data']->get_title();
}
// SORT CART ITEMS
natsort( $products_in_cart );
// ASSIGN SORTED ITEMS TO CART
$cart_contents = array();
foreach ( $products_in_cart as $cart_key => $product_title ) {
$cart_contents[ $cart_key ] = $woocommerce->cart->cart_contents[ $cart_key ];
}
$woocommerce->cart->cart_contents = $cart_contents;
}
In order to grouped cart items by categories, add follows code snippet -
function woocommerce_before_cart_contents(){
global $woocommerce;
$cat_wisw_pros = array();
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $cart_item ) {
$product_id = $cart_item['product_id'];
$cat_ids = wp_get_post_terms( $product_id, 'product_cat', array( 'fields' => 'ids' ) );
foreach ( $cat_ids as $id ) {
$cat_wisw_pros[$id][$cart_item_key] = $cart_item;
}
}
ksort( $cat_wisw_pros ); // Cat ID wise sort
$grouped_cart_items = array();
foreach ( $cat_wisw_pros as $cat_id => $cart_items ) {
foreach ( $cart_items as $cart_item_key => $cart_item ) {
if( !array_key_exists( $cart_item_key, $grouped_cart_items ) )
$grouped_cart_items[$cart_item_key] = $cart_item;
}
}
$woocommerce->cart->cart_contents = $grouped_cart_items;
}
add_action( 'woocommerce_before_cart_contents', 'woocommerce_before_cart_contents' );
You should be able to access the category ids with the method get_category_ids() as defined in the class WC_Product
$item['data']->get_category_ids()
but this gives you back an array, so you need to handle getting the id, e.g.
$ids = $item['data']->get_category_ids();
$id = $ids[ 0 ];
and transforming to a string, e.g.
$term_obj = get_term( $id, 'product_cat' );
$name = $term_obj->name;
you could then do
$products_in_cart[ $key ] = $name;
and by the same logic used in the code in your question sort by category.
There are several things to consider though, this does not handle items being in multiple categories, it just gets the first by using index 0. Additionally, this has no extra logic of sorting, if there are multiple products in the same category.
Please note, this is untested and merely an idea of an approach of how this could be handled.
I'm attempting to get the ID of the post I am editing in functions.php for the purpose of dynamically rewriting a custom post type slug.
This is what I'm working with so far.
function change_post_type_slug( $args, $post_type ) {
if ( 'custom_post' == $post_type ) {
global $post;
$location = get_field('custom_field', $post->ID);
$args['rewrite']['slug'] = $location;
}
return $args;
}
add_filter( 'register_post_type_args', 'change_post_type_slug', 10, 2 );
I am not sure if the hook register_post_type_args is firing before I am able to get the ID, or if this is even the best way to go about what I am trying to accomplish. Can't find much out there on the subject.
I was able to get it to work with the following:
function change_post_type_slug( $args, $post_type ) {
if ( 'lead_page' == $post_type ) {
$post_id = $_GET['post'];
$location = get_field('leadpage_location', $post_id);
$args['rewrite']['slug'] = $location->post_name;
}
return $args;
}
add_filter( 'register_post_type_args', 'change_post_type_slug', 10, 2 );
However it resulted in a notice on the front-end:
Notice: Undefined index: post in /path/to/wordpress/functions.php on line 623
Line 623 is $post_id = $_GET['post'];
You should use the updated_postmeta hook for this, as its run every time you update your custom fields.
Then you can update your post data with wp_update_post() function.
add_action( 'updated_postmeta', function( $meta_id, $object_id, $meta_key, $meta_value ) {
if ( 'location' === $meta_key ) {
wp_update_post([
'ID' => $object_id,
'post_name' => $meta_value,
]);
}
}, 10, 4 );
Update:
Try this:
function change_post_types_slug( $args, $post_type ) {
if ( 'your-custom_post' === $post_type ) {
// Check and get the custom post ID
$id = isset($_GET[ 'post' ]) ? $_GET[ 'post' ] : '' ;
// $location = get_field('leadpage_location', $id);
$args['rewrite']['slug'] = 'new-slug-here';
}
return $args;
}
add_filter( 'register_post_type_args', 'change_post_types_slug', 10, 2 );
Try this out:
function change_post_type_slug( $args, $post_type ) {
if ( 'lead_page' === $post_type && is_admin() && $_GET['action'] === 'edit' ) {
$post_id = $_GET['post'];
$location = get_field('leadpage_location', $post_id);
$args['rewrite']['slug'] = $location->post_name;
}
return $args;
}
add_filter( 'register_post_type_args', 'change_post_type_slug', 10, 2 );
It adds two more conditionals, to check if you're on the admin screen and to check of there is a GET parameter of edit. Probably overkill to do is_admin() as well, but now you're super safe.
I have this code:
function add_cert_id_to_notes( $order_id ) {
$order = new WC_Order( $order_id );
$products = $order->get_items();
foreach( $products as $product ){
$product_id = $product['product_id'];
$order->add_order_note( 'First Test: '.$product_id, 0 );
if( in_category('188', $product_id)){
$order->add_order_note( 'Second Test: '.$product_id, 0 );
}
else {
$order->add_order_note( 'Second Test: FAIL', 0 );
}
}
}
Using WooCommerce, but that's not the problem. The issue is with in_category(). I'm not doing this is a standard loop, I've defined my post ID with $product_id.
Problem is, it keeps returning the failure notice I have set up. I've tried with both the category ID and slug and I still get nothing.
I think in_category is only for post's category.
Document says The given categories are checked against the post's categories' term_ids, names and slugs. So it only check for post i think.
Try following function:-
function add_cert_id_to_notes( $order_id )
{
$order = new WC_Order( $order_id );
$products = $order->get_items();
foreach( $products as $product )
{
$categories = array();
$product_id = $product['product_id'];
$order->add_order_note( 'First Test: '.$product_id, 0 );
$terms = wp_get_post_terms( $product_id, 'product_cat' );
foreach ( $terms as $term )
{
$categories[] = $term->term_id;
$categories[] = $term->slug;
}
//if you want to check category slug than you also can use `slug` as $your_cat_id.
//`$term->slug` is also in $categories array..
$your_cat_id = '188';
if ( in_array( $your_cat_id, $categories ) )
{
$order->add_order_note( 'Second Test: '.$product_id, 0 );
} else {
$order->add_order_note( 'Second Test: FAIL', 0 );
}
}
}
I have tested this function and its working...Hope it will work for you..
In a WordPress theme, how do you list all terms associated with a post, and of a certain taxonomy, and only show terms that are children of set term. And set a custom separator?
Put this in your functions.php:
/*
* Get Terms as a list
*/
function get_term_list_not_linked($postID, $tax, $parentTermID, $sep) {
$terms = get_the_terms( $postID, $taxonomy);
if ( $terms && ! is_wp_error( $terms ) ) {
$termList = array();
foreach ( $terms as $term ) {
if($term->parent == $parentTermID) {
$term_list[] = $term->name;
}
}
$termList = join( $separator, $termList);
return $termList;
} else {
return null;
}
}
And then in the theme file, you call it like this:
<?php echo get_term_list_not_linked($postID, $taxonomy, $parentTermID, $separator); ?>
Here is an example that gets all terms in the 'video-type' taxonomy, that are direct-children of the term with ID 5, and separate the terms with a comma and space:
<?php echo get_term_list_not_linked($post->ID, 'video-type', 5, ', '); ?>