I am using the plugin Polylang in WordPress and trying to do the following:
The Goal Avoid the default behaviour of Polylang of creating category translations when a post gets duplicated using Polylang duplication featured. Only categories that already have translations should be transferred to the duplicated post.
How I am doing so far
I am using the pll_copy_taxonomies()
in my functions to fire the code and using pll_get_term()
to identify which categories have translations, and finally transferring only those ones using wp_set_object_terms()
(I've also tried wp_set_post_terms() and wp_set_post_categories() which generate same effect here).
The problem So, the code does transfer only the existing categories without creating new translations. But when I have a duplicated post and I eventually delete the original post, the categories of the original post that don't have any translations will start duplicating themselves to the hundreds. Each copied category will have the slug like exampleslug-1, exampleslug-2, exampleslug-3 ... exampleslug-176...
It seems Polylang handles categories in a different way and when I am doing it without Polylang functions it creates this bug, I can't figure out.
add_filter('pll_copy_taxonomies', 'donotsync', 10, 5);
function donotsync($taxonomies, $sync, $from, $to, $lang) {
//Bail early if not WP built-in posts
if ('post' !== get_post_type($from)) {
return $taxonomies;
}
//*** Get the post categories and transfer only the ones already translated
//*** PROBLEM: This seems to work, but when the article with the default language gets eventually deleted, WP starts duplicating hundreds of copys of the categories from that post that don't have translations yet. Without this block of code, the categories aren't transferred and there's no error.
$post_categories = get_the_category($from);
foreach ($post_categories as $key => $terms) {
$category_id = $terms->term_id;
//Check if Polylang function exists
if (function_exists('pll_get_term')) {
//Check if translation for the category already exists and than transfer it to the duplicated post
$term_translation = pll_get_term($category_id, $lang);
if (!empty($term_translation)) {
wp_set_object_terms($to, $term_translation, 'category', true);
}
}
}
//Remove taxonomy sync
unset($taxonomies['category']);
return $taxonomies;
}
I actually found the solution myself. The problem was I wasn't using the given $taxonomies
from the pll_copy_taxonomies
filter to create the loop. Looking up at the plugin files I realized how it was done.
I also added to transfer the Yoast SEO primary category if it is translated:
if (function_exists('yoast_get_primary_term_id')) {$primary_category = yoast_get_primary_term_id('category', $from);}
if ($primary_category == $term){update_post_meta($to,'_yoast_wpseo_primary_category',$term_translation);}
And to also transfer each tag if it is translated:
//Get the tag terms
foreach ($taxonomies as $tax) {
if ($tax == 'post_tag') {
if ($terms = get_the_terms($from, $tax)) {
$terms = array_map('intval', wp_list_pluck($terms, 'term_id'));
foreach ($terms as $term) {
//Check if Polylang function exists
if (function_exists('pll_get_term')) {
//Filter terms with translations only
if ($term_translation = pll_get_term($term, $lang)) {
//Transfer only terms with translations
wp_set_object_terms($to, $term_translation, $tax, true);
}
}
}
}
Below is the full working code
add_filter('pll_copy_taxonomies', 'donotsync', 10, 5);
function donotsync($taxonomies, $sync, $from, $to, $lang) {
//Bail early if not WP built-in posts
if ('post' !== get_post_type($from)) {
return $taxonomies;
}
//Check if primary category is set using Yoast SEO
if (function_exists('yoast_get_primary_term_id')) {$primary_category = yoast_get_primary_term_id('category', $from);}
//Get the category terms
foreach ($taxonomies as $tax) {
if ($tax == 'category') {
if ($terms = get_the_terms($from, $tax)) {
$terms = array_map('intval', wp_list_pluck($terms, 'term_id'));
foreach ($terms as $term) {
//Check if Polylang function exists
if (function_exists('pll_get_term')) {
//Filter terms with translations only
if ($term_translation = pll_get_term($term, $lang)) {
//Transfer only terms with translations
wp_set_object_terms($to, $term_translation, $tax, true);
//Transfer the primary category if it is translated
if ($primary_category == $term){update_post_meta($to,'_yoast_wpseo_primary_category',$term_translation);}
}
}
}
}
}
}
//Get the tag terms
foreach ($taxonomies as $tax) {
if ($tax == 'post_tag') {
if ($terms = get_the_terms($from, $tax)) {
$terms = array_map('intval', wp_list_pluck($terms, 'term_id'));
foreach ($terms as $term) {
//Check if Polylang function exists
if (function_exists('pll_get_term')) {
//Filter terms with translations only
if ($term_translation = pll_get_term($term, $lang)) {
//Transfer only terms with translations
wp_set_object_terms($to, $term_translation, $tax, true);
}
}
}
}
}
}
//Remove taxonomy sync
unset($taxonomies['category']);
unset($taxonomies['post_tag']);
return $taxonomies;
}