Wordpress remove parent category in URL (Domain mapping) - wordpress

The following code allow me to remove parent category for my primary domain post.
My problem is that I am using a third party plugin in order to map a second domain in my author name.
domain1.com PRIMARY DOMAIN
domain2.com MAPPED DOMAIN
Permalink structure :
domain1.com/me/cat/subcat/postname => domain2.com/cat/subcat/postname
So basically, domain1.com/me MAP TO domain2.com and it's Working good this way
BUT if I remove cat slug and let only subcat like this (with the script) :
domain1.com/me/subcat/postname WORKING
domain2.com/subcat/postname NOT WORKING (ERR_TOO_MANY_REDIRECTS)
Script to remove parent slug in URL
add_filter( 'post_link', 'remove_parent_category', 10, 3 );
function remove_parent_category( $permalink, $post, $leavename )
{
$cats = get_the_category( $post->ID );
if ( $cats ) {
usort( $cats, '_usort_terms_by_ID' );
$category = $cats[0]->slug;
if ( $parent = $cats[0]->parent ) {
// Find parent categories and replace them in the link
$parentcats = get_category_parents( $parent, false, '/', true );
$permalink = str_replace( $parentcats, '', $permalink );
}
}
return $permalink;
}

Take a look at plugin like WP remove category base You might hook up to query_vars, category_link, request, category_rewrite_rules to accomplish that.

Related

how to change edit url with "Id" to edit url with "Slug" in Wordpress

I have this is WordPress Post editing Url:
https://example.com/wp-admin/post.php?post=ID&action=edit
and I want to change it to Slug Not the ID Like This:
https://example.com/wp-admin/post.php?post=Slug&action=edit
I was trying to edit the post with this Url but is not working:
https://example.com/wp-admin/post.php?post=MyPostSlug&action=edit
In order to change the edit post link structure, you can use the get_edit_post_link filter like so:
add_filter( 'get_edit_post_link', 'so_73914075_get_edit_post_link', 10, 3);
function so_73914075_get_edit_post_link($link, $post_id, $context) {
$post = get_post( $post_id );
if ( ! in_array( $post->post_type, array( 'post', 'page' ) ) ) {
return $link;
}
$post_type_object = get_post_type_object( $post->post_type );
if ( 'revision' === $post->post_type ) {
$action = '';
} elseif ( 'display' === $context ) {
$action = '&action=edit';
} else {
$action = '&action=edit';
}
if ( 'display' === $context ) {
$post_type = '&post-type=' . $post->post_type;
} else {
$post_type = '&post-type=' . $post->post_type;
}
$custom_edit_link = str_replace( '?post=%d', '?post-name=%s', $post_type_object->_edit_link );
return admin_url( sprintf( $custom_edit_link . $action . $post_type, $post->post_name ) );
}
This will change the edit links for regular posts and pages to something like this:
https://example.com/wp-admin/post.php?post-name=the-post-slug&action=edit&post-type=post
WARNING: make sure you limit this to only the post types you need to change the URL for. Making this change global will almost surely
have unintended effects over other plugins
However, making the admin panel actually load the edit screen is not that easy.
Looking at the source code of the wp-admin/post.php file, you will see that there is no way to hook into the flow and populate the $post_id variable with the post id matching the slug you are sending through.
That means you have 2 options:
RECOMMENDED Update the edit link to whatever format you want and then create an admin redirect function that pulls the slug from the initial URL and redirects to the actual edit page with the ?post=%d in it.
NOT RECOMMENDED Create a new admin edit page that will understand your URL structure and include the wp-admin/post.php after the code that pulls the $post_id based on the slug.
The 2nd method might come with lots of extra code you need to write to cover all the cases and all the instances a post reaches the post.php in the admin panel

WP Custom url structure for categories

Update:
To clarify my answer.
Problem is that I have YoastSEO plugin and that plugin is responsible for generating sitemap. What I want is to redirect second and third level subcategories (listed in sitemap) to corresponding top level category with url structure as specified.
What I want to is to generate custom url for wp post categories.
Example:
Categories structure is as following:
Cat1
|_Cat2
|_ Cat3
Wordpress generates following url structure for categories:
//host/category/cat1/cat2/cat3
but what I want to achieve is following:\n
//host/category/cat1/?l2cat=cat2&l3cat=cat3
any help is welcome and appriciated
So the URL you're trying to achieve is actually going to the "cat1" page as far as WP is concerned. Adding Cat2 and Cat3 as query parameters means that you will have to handle these yourself when the page loads, you're not on the page that represents "cat3" anymore. In your first URL, "cat1" and "cat2" are just part of the URL - you're actually ON "cat3". You can certainly do that if that's what you're intending...
What you would want to do is add_query_var for cat2 and cat3. Then in the template that shows cat1 - you can change the content displayed by getting those terms.
I would caution against it... I'm not an SEO expert, but what you now have is a page with a single canonical URL that actually represents 3 completely different terms based on the query parameters.
Maybe I misunderstood the question? But the URL structure you outline above looks like what you're trying to achieve is some kind of archive page that filters by several categories, and not the actual URL to the cat3 term display, which your first URL represents.
function term_link_filter( $url, $term, $taxonomy ) {
$chunks = array_filter(explode('/', $url));
$cat = home_url() . '/' . $taxonomy . '/' . $chunks[4];
$cat = $chunks[5] ? add_query_arg( 'l2cat', $chunks[5], $cat ) : $cat;
$cat = $chunks[6] ? add_query_arg( 'l3cat', $chunks[6], $cat ) : $cat;
return $cat;
}
add_filter('term_link', 'term_link_filter', 10, 3);
Note:
Problem is that I have YoastSEO plugin and that plugin is responsible for generating sitemap. What I want is to redirect second and third level subcategories to corresponding top level category with url structure as specified.
solution. Not elegant.
/* Generate sub categories redirect logic */
function subcategories_redirect() {
/* Example
'/category/first_level_cateogry/second_level_category/third_level_category'
=> '/category/first_level_category?l2cat=second_level_category&l3cat=third_level_category',
*/
$get_top_categories = get_top_categories();
$category_array = array();
foreach( $get_top_categories as $category ) {
$args = array(
'hide_empty' => 0,
'child_of' => $category->term_id,
'taxonomy' => 'category'
);
$term_children = get_categories($args);
foreach ( $term_children as $child ) {
// Cheap and dirty
$category_ancestors = get_ancestors($child->term_id, 'category');
$level_2_category = $level_3_category = "";
if (count($category_ancestors) == 1 ) {
$level_2_category = '?l2cat=' . $child->slug;
} elseif (count($category_ancestors) == 2) {
$tmp = get_category($category_ancestors[0]);
$level_2_category = '?l2cat=' . $tmp->slug;
$level_3_category = '&l3cat=' . $child->slug;
}
$category_array[] = array( ($child->slug) => ('/category/' . $category->slug . '/' . $level_2_category . $level_3_category) );
}
}
$flat_category_array = array_merge(...$category_array);
foreach( $flat_category_array as $category => $url ){
if( is_category( $category ) ) {
$url = site_url( $url );
wp_safe_redirect( $url, 301 );
exit();
}
}
}
add_action('template_redirect', 'subcategories_redirect');

Breadcrumbs on product page don't reflect current url/slug when using multiple categories for product

My Wordpress site uses Woocommerce for products to sell. But when you assign multiple product categories to a product and visit the product page (with Product Permalinks set to Shop base with category), something unexpected is happening. The breadcrumb link to the (parent) category is always the same one and does not reflect the navigated url. (This is the same problem as described here.)
Problem in summary:
Navigate to
Breadcrumb link
Expected breadcrumb link
/shop/category-1/sample-product/
category-2
category-1
/shop/category-2/sample-product/
category-2
category-2
I found no real answer on any source that fixes this. (I think it should be fixed, but some might say it's for SEO reasons, preventing duplicate site contents.) So to help anyone searching for the answer, here it is:
What's going (wr)on(g)?
The breadcrumbs on the product page are produced by the woocommerce_breadcrumb() function. Which in turn gets it through WC_Breadcrumb->generate().
Traversing further in the code, you end up inside the add_crumbs_single() function where the woocommerce_breadcrumb_product_terms_args filter is applied to the ordering of the product terms fetch. (See wp_get_post_terms and WP_Term_Query::__construct() for more info on this.)
It's clear from the code, that they prioritize the term with the highest parent value, in other words, the term with the latest added parent in the database.
Solution 1
Since this will always be the same for this product, you might want to add a filter to your theme's function.php (or using a custom plugin) that will overwrite this behavior. I got mine working using this:
function prioritize_current_url_cat_in_breadcrumbs( $args ) {
// Only if we're on a product page..
if ( is_product() ) {
// ..and there's a product category slug in the navigated url..
$product_cat_slug = get_query_var( 'product_cat', '' );
if ( ! empty($product_cat_slug) ) {
// ..which we can find
$product_cat = get_term_by( 'slug', $product_cat_slug, 'product_cat', ARRAY_A );
if ( ! empty($product_cat) ) {
// Then only get that current product category to start the breadcrumb trail
$args['term_taxonomy_id'] = $product_cat['term_taxonomy_id'];
}
}
}
return $args;
}
add_filter( 'woocommerce_breadcrumb_product_terms_args', 'prioritize_current_url_cat_in_breadcrumbs' );
The rest of the add_crumbs_single() function will take care of traversing the category's parents etc up 'till Home.
Solution 2
Alternatively, you could use the woocommerce_breadcrumb_main_term filter to change the 'main term' used for the breadcrumb trail. The filter function receives 2 arguments: the main term (as WP_Term) and an array of WP_Terms with all product categories found. And it returns one term, so you can search through the array and pick the right one you want to start the breadcrumbs with.
function prioritize_current_url_cat( $first_term, $all_terms ) {
if ( is_product() ) {
$product_cat_slug = get_query_var( 'product_cat', '' );
if ( ! empty($product_cat_slug) ) {
// Get the WP_Term with the current slug
$filtered_terms = array_values( array_filter($all_terms, function($v) use ($product_cat_slug) {
return $v->slug === $product_cat_slug;
}) );
if ( ! empty($filtered_terms) ) {
return $filtered_terms[0];
}
}
}
// Fallback to default
return $first_term;
}
add_filter( 'woocommerce_breadcrumb_main_term', 'prioritize_current_url_cat', 10, 2 );
Hope this helps anyone searching for hours and working through lines of source code..!
Extra: Fix permalinks on archive pages as well
For tackling the same problem on the product archive pages, you can hook into the post_type_link filter and pre-emptively replace the %product_cat% part of the permalink with the correct slug like so:
/**
* Set product link slugs to match the page context,
* for products with multiple associated categories.
*
* For example:
* when viewing Category A, use '/category-a/this-product/'
* when viewing Category B, use '/category-b/this-product/'
*/
function my_plugin_product_url_use_current_cat( $post_link, $post, $leavename, $sample ) {
// Get current term slug (used in page url)
$current_product_term_slug = get_query_var( 'product_cat', '' );
if ( empty ( $current_product_term_slug ) ) {
return $post_link;
}
if ( is_product_category() ) {
// Get current term object
$current_product_term = get_term_by( 'slug', $current_product_term_slug, 'product_cat' );
if ( FALSE === $current_product_term ) {
return $post_link;
}
// Get all terms associated with product
$all_product_terms = get_the_terms( $post->ID, 'product_cat' );
// Filter terms, taking only relevant terms for current term
$matching_or_descendant_terms = array_filter( array_map( function( $term ) use ( $current_product_term ) {
// Return term if it is the current term
if ( $term->term_id === $current_product_term->term_id ) {
return [ TRUE, $term ];
}
// Return term if one of its ancestors is the current term (highest hierarchy first)
$parent_terms = array_reverse( get_ancestors( $term->term_id, 'product_cat' ) );
foreach ( $parent_terms as $parent_term_id ) {
if ( $parent_term_id === $current_product_term->term_id ) {
return [ FALSE, $term ];
}
}
// Leave out all others
return NULL;
}, $all_product_terms ) );
if ( count( $matching_or_descendant_terms ) > 0 ) {
// Sort terms (directly associated first, descendants next)
usort( $matching_or_descendant_terms, function( $a, $b ) {
if ( $a[0] === $b[0] ) {
return 0;
} else if ( TRUE === $a[0] ) {
return -1;
} else {
return 1;
}
} );
// Get entire slug (including ancestors)
$slug = get_term_parents_list( $matching_or_descendant_terms[0][1]->term_id, 'product_cat', [
'format' => 'slug',
'separator' => '/',
'link' => false,
'inclusive' => true,
] );
// Set url slug to closest child term of current term
// or current term (if directly associated)
$post_link = str_replace('%product_cat%/', $slug, $post_link);
}
} else if ( is_product() ) {
$post_link = str_replace('%product_cat%', $current_product_term_slug, $post_link);
}
return $post_link;
}
add_filter( 'post_type_link', 'my_plugin_product_url_use_current_cat', 10, 4 );
Explanation
As #Markos mentioned, we tried to figure out the most logical and intuitive way to do this.
Basically, it checks if the current product category (slug from the url) is directly associated with the displayed product. If so, use that slug for the link to the product page. (Using one of the solutions above, the breadcrumbs reflect the url path for intuitive navigation.)
If the current viewed product category is not directly associated with the product, it looks for the first matching descendant (sub) category and uses that slug for the link to the product page.
This way, the user always sees how they came on the current product page and can easily navigate back to the category.
Note: If this snippet doesn't change anything, try an earlier hook priority and/or check whether the $post_link variable contains the %product_cat% template part.
After a lengthy chat with Philip and troubleshooting scenarios when a shop has multiple layers of categories (thank you Philip) I found the following approach for the permalinks working for me.
function my_plugin_product_url_use_current_cat( $post_link, $post, $leavename, $sample ) {
if ( is_product_category() || is_product() ) {
$product_cat_slug = get_query_var( 'product_cat', '' );
// get all the category of products
$terms = get_the_terms ( $post->ID, 'product_cat' );
foreach($terms as $term){
$term_slug = $term->slug;
// check if category page belongs to the category of the product
if($term_slug == $product_cat_slug){
$post_link = str_replace('%product_cat%', $term_slug, $post_link);
return $post_link;
}
// or category page is a parent category of the product
else{
$all_parents = get_ancestors($term->term_id, 'product_cat');
foreach($all_parents as $cat_id){
$cat_term = get_term( $cat_id, 'product_cat' );
if($cat_term->slug == $product_cat_slug){
$post_link = str_replace('%product_cat%', $term_slug, $post_link);
return $post_link;
}
}
}
}
}
return $post_link;
}
add_filter( 'post_type_link', 'my_plugin_product_url_use_current_cat', 9, 4 );

Rewrite rules for EDD product page

I want my url changes depending on the term of taxonomy category_download custom post types download.
Example:
I have 2 categories:
– plugins
– themes
I wish I had a url for my single download:
/plugins/name_of_download/
AND
/themes/name_of_download/
Try adding this code to your themes functions.php file,
function __custom_messagetypes_link( $link, $term, $taxonomy )
{
if ( $taxonomy == 'plugins' ){
return str_replace( 'plugins/', '', $link );
}
else if ( $taxonomy == 'themes' ){
return str_replace( 'themes/', '', $link );
}
else{
return $link;
}
}
add_filter( 'term_link', '__custom_messagetypes_link', 10, 3 );
I am assuming the used slug, May be you have to change the your taxonomy slug if these are different.
If have any problem you can freely ask, Thanks,

Wordpress category hierarchy - sub category but parent permalink

I have a Wordpress blog. There are more categories. Category hierarchy like below.
Technology News
Mobile News
Internet News
...
in address bar it shown like
site.com/category/technology-news/internet-news
but I want to see at address bar like below
site.com/category/internet-news
so how can I show a sub category as parent category. Remember it's still a sub category actually.
Go into Settings -> Permalinks. Select "Custom Structure" and paste this line in.
/%category%/%postname%/
Next, open your themes functions.php file and drop in the following code.
add_filter( 'post_link', 'remove_parent_cats_from_link', 10, 3 );
function remove_parent_cats_from_link( $permalink, $post, $leavename ) {
$cats = get_the_category( $post->ID );
if ( $cats ) {
usort( $cats, '_usort_terms_by_ID' );
$category = $cats[0]->slug;
if ( $parent = $cats[0]->parent ) {
$parentcats = get_category_parents( $parent, false, '/', true );
$permalink = str_replace( $parentcats, '', $permalink );
}
}
return $permalink;
}

Resources