Woocommerce custom Product slug - wordpress

Is there a way to create custom product URL based on the product attributes, I have a product sunglasses which has a couple of attributes tied to it: metal, blue and round, so the current URL is:
website.com/glasses/sunglasses/abram-widana-629/
What I am trying to get is a URL which has those attributes included:
website.com/glasses/sunglasses/abram-widana-meta-blue-round-629/
I would really appreciate if someone would even just point me to the right direction on how to tackle this.

There are two ways to do this, either Manually or Programmatically.
Manually adjusting permalinks:
In your example, you are simply adjusting the product URL to include attributes. This can be achieved manually by editing the permalink on the product itself.
Once the product has been added/saved, you will see the permalink showing directly under the title field like this:
Simply click the Edit button next to it and change it from abram-widana-629 to abram-widana-meta-blue-round-629
Programmatically adding attributes to permalinks:
If you want to try to achieve this permanently for all products you will have to work through the "save_post" filter/hook to add all the attributes to the permalink. The only downfall from this is that you will no longer be able to adjust your individual permalinks for your products as they will simply revert back once you click save.
Below is a code example of how to achieve that:
add_action( 'save_post', 'add_custom_attributes_to_permalink', 10, 3 );
function add_custom_attributes_to_permalink( $post_id, $post, $update ) {
//make sure we are only working with Products
if ($post->post_type != 'product' || $post->post_status == 'auto-draft') {
return;
}
//get the product
$_product = wc_get_product($post_id);
//get the "clean" permalink based on the post title
$clean_permalink = sanitize_title( $post->post_title, $post_id );
//next we get all of the attribute slugs, and separate them with a "-"
$attribute_slugs = array(); //we will be added all the attribute slugs to this array
foreach ($_product->get_attributes(); as $attribute_slug => $attribute_value) {
$attribute_slugs[] = $attribute_value;
}
$attribute_suffix = implode('-', $attribute_slugs);
//then add the attributes to the clean permalink
$full_permalink = $clean_permalink.$attribute_suffix;
// unhook the save post action to avoid a broken loop
remove_action( 'save_post', 'add_custom_attributes_to_permalink', 10, 3 );
// update the post_name (which becomes the permalink)
wp_update_post( array(
'ID' => $post_id,
'post_name' => $full_permalink
));
// re-hook the save_post action
add_action( 'save_post', 'add_custom_attributes_to_permalink', 10, 3 );
}

Related

Using only ID in product url in WooCommerce?

The reason I want to do this is non-English product titles are automatically used in the slug that renders a very long URL with percentage signs, e.g. /product/%e9%97%bb%e7%a8%bf%e5%8f%91%e5%b8%83/, which doesn't look good at all, especially when shared as URLs, sometimes inconveniently lengthy.
So it seems much better to use only product ID in the URLs such as /product/1178/
Searched around and never found anything relevant. Tried Settings > Permalinks > Product permalinks > Custom base = "/product/%post_id%/" but the slug is still appended as /product/1178/%e9%97%bb%e7%a8%bf%e5%8f%91%e5%b8%83/
Is there any way to do this programmatically?
Found this answer, is it to modify it to be used for WooCommerce products so product IDs are used for slugs when creating the product?
This worked for me. Now the product IDs are the product slugs every time I create new products.
add_action( 'save_post_product', 'wpse251743_set_title', 10, 3 );
function wpse251743_set_title ( $post_id ){
//This temporarily removes action to prevent infinite loops
remove_action( 'save_post_product', 'wpse251743_set_title' );
//update title
wp_update_post( array(
'ID' => $post_id,
'post_name' => $post_id, //Wordpress would generate the slug based on the post name
));
//redo action
add_action( 'save_post_product', 'wpse251743_set_title', 10, 3 );
}

I'd like to update the menu_order field by an increment of 1 front end dynamically by product ID?

To update the database field in wordpress I currently have the following in the function.php file.
`$update_args = array(
'ID' => '123',
'menu_order' => '19'
);
$result = wp_update_post($update_args);`
This only updates the product id '123' and sets it to '19'. What I need it to do is update any product id when the page is viewed by an increment of 1 typically as below.
$menu_order++;
Works fine updating fixed values but need it to work dynamically when each product viewed.
Welcome to SO!
Something like this would work:
add_action( 'woocommerce_after_single_product', 'your_prefix_woocommerce_after_single_product' );
function your_prefix_woocommerce_after_single_product( ) {
global $product;
$id = $product->get_id();
// do stuff with the product
}
Add this to your child-theme functions.php.
It only runs on single-product page.

Elementor Pro - Custom Query

I need some help. I am trying to create a custom query for my Custom Posts I created in Wordpress, and using Elementor Pro.
On my post, I added a custom field 'sorting' with a numeric value, which I would like to use to order my posts manually.
However, I cannot seem to get this to work.
I am using the latest Elementor pro version.
And I tried following the instructions as per their page: https://developers.elementor.com/custom-query-filter/
Here is my code I added to my theme's functions.php file
// Showing posts ordered by comment count in Posts Widget
add_action( 'elementor/query/speaker_order', function( $query ) {
// Here we set the query to fetch posts with
// ordered by comments count
$query->set( 'orderby', 'sorting' );
} );
I have added 'speaker_order' as the Query ID in the Elementor Editor.
You are close. There's one thing you left out (if I am grasping what you want to do).
It should look like this:
add_action( 'elementor/query/speaker_order', function( $query ) {
// Here we set the query to fetch posts with
// ordered by comments count
$query->set( 'meta_key', 'sorting' );
$query->set( 'orderby', 'sorting' );
} );
You have to add two more lines of code:
// Showing posts ordered by comment count in Posts Widget
add_action( 'elementor/query/speaker_order', function( $query ) {
$query->set('meta_key','sorting');
$query->set('orderby', 'sorting');
$query->set('orderby','ASC');
});

Dynamic permalinks when creating a post in WordPress

I have a custom post type named houses. Inside my custom post type I have several custom fields which I created using ACF.
What I need to do is to change the permalink when I create a new post.
I would like to use the code and title fields to customize the permalink:
//code + post title
4563312-house-example-1
I'm developing a plugin which controls everything.
Is there a way to intermediate the creation of a post to update its permalink?
Thanks.
After some research, I found an answer related to wp_insert_post_data.
Using wp_insert_post_data, I couldn't get the custom field value, and to achieve that, I had to use another action, save_post instead.
function rci_custom_permalink($post_id) {
$post = get_post($post_id);
if($post->post_type !== 'houses') return;
$code = get_field('code', $post_id);
$post_name = sanitize_title($post->post_title);
$permalink = $code . '-' . $post_name;
// remove the action to not enter in a loop
remove_action('save_post', 'rci_custom_permalink');
// perform the update
wp_update_post(array('ID' => $post_id, 'post_name' => $permalink));
// add the action again
add_action('save_post', 'rci_custom_permalink');
}
add_action('save_post', 'rci_custom_permalink');
PS: Since all these fields are required, I didn't need to check if they are empty or not.
For reference about save_post action:
Plugin API/Action Reference/save post

Getting WordPress to automatically show category permalink for only specific categories

I have searched, here is the closes result.
I am building a new wordpress site. I want most posts to have no category in the URL, simply www.site.com/title. However I do want the blog posts to be separate, so I'd like www.site.com/blog/title. I'd also like the option to add more like that in the future, for only specific categories, not the entire site.
There are many questions similar to this here on stackoverflow but most have 0 replies. Any advice would be great. I've even tried Advanced Permalinks without any luck.
You can simply do that by Setting > Permalinks and add to Common Setting > Custom Structure the value /blog/%postname%/. There you will get the blog post accessible from www.site.com/blog/title.
I cannot understand the first question. By:
I want most posts to have no category in the URL
do you mean to NOT HAVING www.site.com/category/category-name? or not having www.site.com/category/post?
EDIT #1
To answer this:
www.site.com/category/post is what I ONLY want for blog posts with the category of "Blog" > if the category is "Shoes" I don't want the category displayed in the URL. –
First: you can set the Permalink to /%postname%/ so all your post will have site/title therefore accessible from that link
Second: You have to filter the permalink to behave differently for the posts under "Blog" category.
Try this
add_filter( 'post_link', 'custom_permalink', 10, 2 );
function custom_permalink( $permalink, $post ) {
// Get the categories for the post
$categories = wp_get_post_categories( $post->ID );
foreach ( $categories as $cat ) {
$post_cat = get_category( $cat );
$post_cats[] = $post_cat->slug;
}
// Check if the post have 'blog' category
// Assuming that your 'Blog' category slug is 'blog'
// Change 'blog' to match yours
if ( in_array( 'blog',$post_cats ) ) {
$permalink = trailingslashit( home_url( 'blog/' . $post->post_name ) );
}
return $permalink;
}
Third: You have to filter rewrite_rules
add_filter( 'rewrite_rules_array', 'custom_rewrite_rule' );
function custom_rewrite_rule( $rules ) {
$new_rules = array(
'blog/([^/]+)/trackback/?$' => 'index.php?name=$matches[1]&tb=1',
'blog/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$' => 'index.php?name=$matches[1]&feed=$matches[2]',
'blog/([^/]+)/(feed|rdf|rss|rss2|atom)/?$' => 'index.php?name=$matches[1]&feed=$matches[2]',
'blog/([^/]+)/comment-page-([0-9]{1,})/?$' => 'index.php?name=$matches[1]&cpage=$matches[2]',
'blog/([^/]+)(/[0-9]+)?/?$' => 'index.php?name=$matches[1]&page=$matches[2]'
);
$rules = $new_rules + $rules;
return $rules;
}
Go to permalink setting and save the setting to refresh your rewrite rules and make the changes above active
NOTE: Add those functions on your active theme functions.php template
NOTICE: I haven't test it yet but that's the way you change permalink. I did the similar way to change my permalink on archives and search result.

Resources