Home › Toolset Professional Support › [Resolved] Search / filter a multilingual list of posts by languages
Problem:
What I would need is a condition that avoid the code running in the View blocks preview only but I did not find any until now.
Solution:
You can use function WP_Screen::is_block_editor() to check if it is the block editor is loading on the current screen, see WP document:
Relevant Documentation:
https://developer.wordpress.org/reference/classes/wp_screen/is_block_editor/
This is the technical support forum for Toolset - a suite of plugins for developing WordPress sites without writing PHP.
Everyone can read this forum, but only Toolset clients can post in it. Toolset support works 6 days per week, 19 hours per day.
Sun | Mon | Tue | Wed | Thu | Fri | Sat |
---|---|---|---|---|---|---|
- | 9:00 – 13:00 | 9:00 – 13:00 | 9:00 – 13:00 | 9:00 – 13:00 | 9:00 – 13:00 | - |
- | 14:00 – 18:00 | 14:00 – 18:00 | 14:00 – 18:00 | 14:00 – 18:00 | 14:00 – 18:00 | - |
Supporter timezone: Asia/Hong_Kong (GMT+08:00)
This topic contains 14 replies, has 2 voices.
Last updated by caroleM-4 3 years, 5 months ago.
Assisted by: Luo Yang.
Hello,
I am actually working on a website on which I have to display lists of custom post types regardless of the page language but allowing users to filter posts by one of the languages (actually only two but may increase in the future).
As the lists have to display all posts and their translated taxonomies by default I did set the post type in WPML to "Translatable - use translation if available or fallback to default language", even though the post are not translated, as this is the only setting that correctly displays the taxonomies for posts that are not in the page language inside view blocks.
That's working well for displaying all posts but I now need to allow users to filter them by language or, if not possible, create alternate views displaying only posts in one selected language on which I can redirect users that do not want to see all posts. I also need to display the select field values and taxonomies in the page language whatever the list is multilingual or not.
So here are my questions :
1) Is there a way to add a language select (or languages checkboxes) to the search form ? That would be the best for me so even if some coding is needed I would be glad to give it a try.
2) Is there a way to display posts of one language only in a view block when post type set to "Translatable - use translation if available or fallback to default language" ?
I tried using :
function wpml_custom_query( $query ) {
if( is_page('xyz') ) {
$query->query_vars['suppress_filters'] = false;
}
}
add_action( 'pre_get_posts', 'wpml_custom_query' );
But it does not work or at least not for the view blocks.
3) Is there a way to have select field values displaying in the page language even for posts from another language ? I found that taxonomies are displaying correctly if both post type and taxonomy are set to "Translatable - use translation if available or fallback to default language" but I did not find how to get the same result for select fields which translations are managed in string translations.
Thanks in advance for your help.
I just noticed that what I thought was working is not actually on pages in the default language where I get only posts from the default language if post type set to "Translatable - use translation if available or fallback to default language".
I tried setting the post type to "Not translatable". It's working for the posts that are all showing even on default language page but taxonomies (which are all translated of course) do not display for posts that are not in the page language this on both languages.
I thought I could solve that by adding just before the view block :
remove_filter( 'get_terms_args', array( $sitepress, 'get_terms_args_filter' ), 10 );
remove_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ), 1 );
remove_filter( 'terms_clauses', array( $sitepress, 'terms_clauses' ), 10 );
But that does not work whatever I set In WPML for the taxonomy translation.
I finally ended up setting the post type to "Translatable - use translation if available or fallback to default language" and adding :
function wpml_custom_query( $query ) {
$query->query_vars['suppress_filters'] = true;
}
add_action( 'pre_get_posts', 'wpml_custom_query' );
It seems to be the only way to get all posts regardless of language with taxonomies displaying correctly in view blocks. Unfortunately that does not really help me for the pages that have to display post of one language only and it does not solve the problem of the select field values that still display on the post language.
Really hope you will be able to help me with that because it's getting me mad.
Sorry for that but I have to add one more update as I noticed that whatever I use in WPML settings, the taxonomy filter in search form will only retrieve posts attached to the default language taxonomy term on the default language pages.
On the other side posts attached to the taxonomy term and its translation are retrieved when filtering by a taxonomy term on the secondary language page if both custom post type and custom taxonomy are set to "Translatable - use translation if available or fallback to default language".
I really need to be able at least to display all post regardless of language with a custom search including taxonomy filtering that retrieves all posts from both the taxonomy selected and its translation (or source) whatever the language of the page.
If that works for pages of the secondary language, there should be a way to have it work the same way on the default language pages, no ?
Thanks in advance for your help and patience.
Hello,
There are not such kind of built-in features within Toolset plugins. For example, in English version page, you can only display posts of same language(English), and I don't think it is good idea to use custom codes and display other language posts, it will conduct unexpected problems, just like you mentioned above.
In your case, I suggest you add the Language switcher shortcode into the search form, so user can switch to different language easily, see WPML document:
https://wpml.org/documentation/support/wpml-coding-api/shortcodes/#wpml_language_switcher
Thanks for the feedback but our customer really wants to have a multilingual searchable list of posts as we manage to get it working on the actual website :
hidden link (default language page)
hidden link (secondary language page)
It's logical if we look at the context, the website allows users of a multilingual country to post ads in the two main languages and as they also may be interested in ads in both languages, they have to be able to run a search through all ads regardless of languages.
On the actual version which is mainly custom coding, I solved the problem by suppressing the filter in the query and, for the taxonomy filtering, getting both languages terms together before running the query. Something like :
$search_categories = array();
$search_category_de = apply_filters( 'wpml_object_id', $search_category, 'company_category', true, 'de' );
$search_categories[] = $search_category_de;
$search_category_fr = apply_filters( 'wpml_object_id', $search_category, 'company_category', true, 'fr' );
$search_categories[] = $search_category_fr;
$args['tax_query'] = array(
array(
'taxonomy' => 'company_category',
'field' => 'term_id',
'terms' => $search_categories,
'compare' => 'IN'
),
);
}
$search_category being the value I get from the custom search form.
I am actually migrating this website to a Toolset / WPML / Divi combination in order to make it easier to maintain and more secure but I know I won't be able to do without custom coding as I need to keep the same functionalities. My goal in fact is to reduce the custom coding part as much as possible, but not to completely avoid it which is not realistic in this context, and to keep it inside Toolset as long as I can to ease the work of those who will have to dig in it after me.
So maybe the solution for me would be to modify the tax query via pre_get_posts in order to implement a similar solution to the one I used before, so I can still use standard Toolset views and search form while keeping the flexibility needed in this case.
I found a ticket wich gives me some hint about the way I could achieve it : https://toolset.com/forums/topic/specify-and-condition-for-custom-search-filter-taxonomy-in-wordpress-archive/). I am not very used to the pre_get_posts thing so it may take me a bit of time but I should be able to get it working in the end, no ?
If you have another idea or can help me a bit with that one, it would be great but I understand it's out of support's scope so I'll fully understand if you can't.
Thanks for the feedback but our customer really wants to have a multilingual searchable list of posts as we manage to get it working on the actual website :
hidden link (default language page)
hidden link (secondary language page)
It's logical if we look at the context, the website allows users of a multilingual country to post ads in the two main languages and as they also may be interested in ads in both languages, they have to be able to run a search through all ads regardless of languages.
On the actual version which is mainly custom coding, I solved the problem by suppressing the filter in the query and, for the taxonomy filtering, getting both languages terms together before running the query. Something like :
$search_categories = array();
$search_category_de = apply_filters( 'wpml_object_id', $search_category, 'company_category', true, 'de' );
$search_categories[] = $search_category_de;
$search_category_fr = apply_filters( 'wpml_object_id', $search_category, 'company_category', true, 'fr' );
$search_categories[] = $search_category_fr;
$args['tax_query'] = array(
array(
'taxonomy' => 'company_category',
'field' => 'term_id',
'terms' => $search_categories,
'compare' => 'IN'
),
);
}
$search_category being the value I get from the custom search form.
I am actually migrating this website to a Toolset / WPML / Divi combination in order to make it easier to maintain and more secure but I know I won't be able to do without custom coding as I need to keep the same functionalities. My goal in fact is to reduce the custom coding part as much as possible, but not to completely avoid it which is not realistic in this context, and to keep it inside Toolset as long as I can to ease the work of those who will have to dig in it after me.
So maybe the solution for me would be to modify the tax query via pre_get_posts in order to implement a similar solution to the one I used before, so I can still use standard Toolset views and search form while keeping the flexibility needed in this case.
I found a ticket wich gives me some hint about the way I could achieve it : https://toolset.com/forums/topic/specify-and-condition-for-custom-search-filter-taxonomy-in-wordpress-archive/). I am not very used to the pre_get_posts thing so it may take me a bit of time but I should be able to get it working in the end, no ?
If you have another idea or can help me a bit with that one, it would be great but I understand it's out of support's scope so I'll fully understand if you can't.
Thanks for the feedback but our customer really wants to have a multilingual searchable list of posts as we manage to get it working on the actual website :
hidden link (default language page)
hidden link (secondary language page)
It's logical if we look at the context, the website allows users of a multilingual country to post ads in the two main languages and as they also may be interested in ads in both languages, they have to be able to run a search through all ads regardless of languages.
On the actual version which is mainly custom coding, I solved the problem by suppressing the filter in the query and, for the taxonomy filtering, getting both languages terms together before running the query. Something like :
$search_categories = array(); $search_category_de = apply_filters( 'wpml_object_id', $search_category, 'company_category', true, 'de' ); $search_categories[] = $search_category_de; $search_category_fr = apply_filters( 'wpml_object_id', $search_category, 'company_category', true, 'fr' ); $search_categories[] = $search_category_fr; $args['tax_query'] = array( array( 'taxonomy' => 'company_category', 'field' => 'term_id', 'terms' => $search_categories, 'compare' => 'IN' ), ); }
$search_category being the value I get from the custom search form.
I am actually migrating this website to a Toolset / WPML / Divi combination in order to make it easier to maintain and more secure but I know I won't be able to do without custom coding as I need to keep the same functionalities. My goal in fact is to reduce the custom coding part as much as possible, but not to completely avoid it which is not realistic in this context, and to keep it inside Toolset as long as I can to ease the work of those who will have to dig in it after me.
So maybe the solution for me would be to modify the tax query via pre_get_posts in order to implement a similar solution to the one I used before, so I can still use standard Toolset views and search form while keeping the flexibility needed in this case.
I found a ticket wich gives me some hint about the way I could achieve it : https://toolset.com/forums/topic/specify-and-condition-for-custom-search-filter-taxonomy-in-wordpress-archive/). I am not very used to the pre_get_posts thing so it may take me a bit of time but I should be able to get it working in the end, no ?
If you have another idea or can help me a bit with that one, it would be great but I understand it's out of support's scope so I'll fully understand if you can't.
Sorry for the multiple posts, I got errors when submitting and thought it was not 🙁
I gave a try to the pre_get_posts thing and managed to modify one of the tax_query correctly but unfortunately it seems it's not the good one.
Here is the code I used :
function wpml_custom_query( $query ) { $query->query_vars['suppress_filters'] = true; $tax_query = $query->get( 'tax_query' ); if ( (!empty( $tax_query )) && ($tax_query[0]['taxonomy'] == 'company_category') ){ $selected_terms = $tax_query[0]['terms']; $wanted_terms = array(); foreach($selected_terms as $selected_term) { $de_term = apply_filters( 'wpml_object_id', $selected_term, 'company_category', true, 'de' ); $wanted_terms[] = $de_term; $fr_term = apply_filters( 'wpml_object_id', $selected_term, 'company_category', true, 'fr' ); $wanted_terms[] = $fr_term; } $tax_query[0]['terms'] = $wanted_terms; $query->set( 'tax_query', $tax_query ); } } add_action( 'pre_get_posts', 'wpml_custom_query' );
A dump of $query after setting the new tax_query shows it has an effect but it also shows there is another tax_query wich is not affected :
object(WP_Query)#33494 (48) { ["query"]=> array(17) { ["post_type"]=> array(1) { [0]=> string(7) "company" } ["paged"]=> string(1) "1" ["suppress_filters"]=> bool(false) ["ignore_sticky_posts"]=> bool(true) ["ep_integrate"]=> bool(false) ["posts_per_page"]=> int(20) ["wpv_original_limit"]=> int(-1) ["wpv_original_offset"]=> int(0) ["wpv_original_posts_per_page"]=> int(20) ["tax_query"]=> array(2) { [0]=> array(5) { ["taxonomy"]=> string(16) "company_category" ["field"]=> string(2) "id" ["terms"]=> array(1) { [0]=> int(49) } ["operator"]=> string(2) "IN" ["include_children"]=> bool(true) } ["relation"]=> string(3) "AND" } ["meta_query"]=> array(2) { [0]=> array(4) { ["key"]=> string(12) "wpcf-ad-type" ["value"]=> string(2) "34" ["type"]=> string(4) "CHAR" ["compare"]=> string(1) "=" } ["relation"]=> string(3) "AND" } ["post_status"]=> array(2) { [0]=> string(7) "publish" [1]=> string(7) "private" } ["orderby"]=> string(4) "date" ["order"]=> string(4) "desc" ["wpv_orderby"]=> string(4) "date" ["wpv_order"]=> string(4) "desc" ["wpv_query"]=> bool(true) } ["query_vars"]=> array(67) { ["post_type"]=> array(1) { [0]=> string(7) "company" } ["paged"]=> int(1) ["suppress_filters"]=> bool(true) ["ignore_sticky_posts"]=> bool(true) ["ep_integrate"]=> bool(false) ["posts_per_page"]=> int(20) ["wpv_original_limit"]=> int(-1) ["wpv_original_offset"]=> int(0) ["wpv_original_posts_per_page"]=> int(20) ["tax_query"]=> array(2) { [0]=> array(5) { ["taxonomy"]=> string(16) "company_category" ["field"]=> string(2) "id" ["terms"]=> array(2) { [0]=> int(49) [1]=> int(97) } ["operator"]=> string(2) "IN" ["include_children"]=> bool(true) } ["relation"]=> string(3) "AND" } ["meta_query"]=> array(2) { [0]=> array(4) { ["key"]=> string(12) "wpcf-ad-type" ["value"]=> string(2) "34" ["type"]=> string(4) "CHAR" ["compare"]=> string(1) "=" } ["relation"]=> string(3) "AND" } ["post_status"]=> array(2) { [0]=> string(7) "publish" [1]=> string(7) "private" } ["orderby"]=> string(4) "date" ["order"]=> string(4) "desc" ["wpv_orderby"]=> string(4) "date" ["wpv_order"]=> string(4) "desc" ["wpv_query"]=> bool(true) ["error"]=> string(0) "" ["m"]=> string(0) "" ["p"]=> int(0) ["post_parent"]=> string(0) "" ["subpost"]=> string(0) "" ["subpost_id"]=> string(0) "" ["attachment"]=> string(0) "" ["attachment_id"]=> int(0) ["name"]=> string(0) "" ["pagename"]=> string(0) "" ["page_id"]=> int(0) ["second"]=> string(0) "" ["minute"]=> string(0) "" ["hour"]=> string(0) "" ["day"]=> int(0) ["monthnum"]=> int(0) ["year"]=> int(0) ["w"]=> int(0) ["category_name"]=> string(0) "" ["tag"]=> string(0) "" ["cat"]=> string(0) "" ["tag_id"]=> string(0) "" ["author"]=> string(0) "" ["author_name"]=> string(0) "" ["feed"]=> string(0) "" ["tb"]=> string(0) "" ["meta_key"]=> string(0) "" ["meta_value"]=> string(0) "" ["preview"]=> string(0) "" ["s"]=> string(0) "" ["sentence"]=> string(0) "" ["title"]=> string(0) "" ["fields"]=> string(0) "" ["menu_order"]=> string(0) "" ["embed"]=> string(0) "" ["category__in"]=> array(0) { } ["category__not_in"]=> array(0) { } ["category__and"]=> array(0) { } ["post__in"]=> array(0) { } ["post__not_in"]=> array(0) { } ["post_name__in"]=> array(0) { } ["tag__in"]=> array(0) { } ["tag__not_in"]=> array(0) { } ["tag__and"]=> array(0) { } ["tag_slug__in"]=> array(0) { } ["tag_slug__and"]=> array(0) { } ["post_parent__in"]=> array(0) { } ["post_parent__not_in"]=> array(0) { } ["author__in"]=> array(0) { } ["author__not_in"]=> array(0) { } } ["tax_query"]=> object(WP_Tax_Query)#33455 (6) { ["queries"]=> array(2) { [0]=> array(5) { ["taxonomy"]=> string(16) "company_category" ["terms"]=> array(1) { [0]=> int(49) } ["field"]=> string(2) "id" ["operator"]=> string(2) "IN" ["include_children"]=> bool(true) } ["relation"]=> string(3) "AND" } ["relation"]=> string(3) "AND" ["table_aliases":protected]=> array(0) { } ["queried_terms"]=> array(1) { ["company_category"]=> array(2) { ["terms"]=> array(1) { [0]=> int(49) } ["field"]=> string(2) "id" } } ["primary_table"]=> NULL ["primary_id_column"]=> NULL } ["meta_query"]=> bool(false) ["date_query"]=> bool(false) ["post_count"]=> int(0) ["current_post"]=> int(-1) ["in_the_loop"]=> bool(false) ["comment_count"]=> int(0) ["current_comment"]=> int(-1) ["found_posts"]=> int(0) ["max_num_pages"]=> int(0) ["max_num_comment_pages"]=> int(0) ["is_single"]=> bool(false) ["is_preview"]=> bool(false) ["is_page"]=> bool(false) ["is_archive"]=> bool(true) ["is_date"]=> bool(false) ["is_year"]=> bool(false) ["is_month"]=> bool(false) ["is_day"]=> bool(false) ["is_time"]=> bool(false) ["is_author"]=> bool(false) ["is_category"]=> bool(false) ["is_tag"]=> bool(false) ["is_tax"]=> bool(true) ["is_search"]=> bool(false) ["is_feed"]=> bool(false) ["is_comment_feed"]=> bool(false) ["is_trackback"]=> bool(false) ["is_home"]=> bool(false) ["is_privacy_policy"]=> bool(false) ["is_404"]=> bool(false) ["is_embed"]=> bool(false) ["is_paged"]=> bool(false) ["is_admin"]=> bool(false) ["is_attachment"]=> bool(false) ["is_singular"]=> bool(false) ["is_robots"]=> bool(false) ["is_favicon"]=> bool(false) ["is_posts_page"]=> bool(false) ["is_post_type_archive"]=> bool(false) ["query_vars_hash":"WP_Query":private]=> string(32) "e0daef1eb5eb8ec214f1e073890b97a5" ["query_vars_changed":"WP_Query":private]=> bool(false) ["thumbnails_cached"]=> bool(false) ["stopwords":"WP_Query":private]=> NULL ["compat_fields":"WP_Query":private]=> array(2) { [0]=> string(15) "query_vars_hash" [1]=> string(18) "query_vars_changed" } ["compat_methods":"WP_Query":private]=> array(2) { [0]=> string(16) "init_query_flags" [1]=> string(15) "parse_tax_query" } }
Can you help me spot where I got wrong ?
As you mentioned above in post:
https://toolset.com/forums/topic/search-filter-a-multilingual-list-of-posts-by-languages/#post-2138725
we manage to get it working on the actual website :
hidden link (default language page)
hidden link (secondary language page)
So you just need to setup a form field in the custom search form, pass URL parameter "lang" to result page, you can try WPML shortcode [wpml_language_form_field], see the same WPML document I mentioned above:
https://wpml.org/documentation/support/wpml-coding-api/shortcodes/#wpml_language_switcher
For other custom codes:
A dump of $query after setting the new tax_query shows it has an effect but it also shows there is another tax_query wich is not affected ...
Please try to setup the $priority in your custom codes, for example:
add_action( 'pre_get_posts', 'wpml_custom_query', 999 );
More help:
https://developer.wordpress.org/reference/functions/add_action/
$priority
(int) (Optional) Used to specify the order in which the functions associated with a particular action are executed.
Thanks for the feedback.
Adding the priority did not change anything but I finally found a way to get the default multilingual list I needed, displaying all posts regardless of languages when no taxonomy is selected, and posts of default and translated taxonomies when a taxonomy is selected, that whatever the page language is.
Here is the code is used :
function disable_wpml_filtering( $query_args ) { global $sitepress; remove_filter( 'get_terms_args', array( $sitepress, 'get_terms_args_filter' ), 10 ); remove_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ), 1 ); remove_filter( 'terms_clauses', array( $sitepress, 'terms_clauses' ), 10 ); $query_args['suppress_filters'] = true; if(!empty($query_args['tax_query']) && $query_args['tax_query'][0]['taxonomy'] == 'company_category') { $selected_terms = $query_args['tax_query'][0]['terms']; $wanted_terms = array(); foreach($selected_terms as $selected_term) { $de_term = apply_filters( 'wpml_object_id', $selected_term, 'company_category', true, 'de' ); $wanted_terms[] = $de_term; $fr_term = apply_filters( 'wpml_object_id', $selected_term, 'company_category', true, 'fr' ); $wanted_terms[] = $fr_term; } $query_args['tax_query'][0]['terms'] = $wanted_terms; } return $query_args; } add_filter( 'wpv_filter_query', 'disable_wpml_filtering', 10, 3 ); function restore_wpml_filtering( $query) { global $sitepress; add_filter( 'get_terms_args', array( $sitepress, 'get_terms_args_filter' ), 10, 2 ); add_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ), 1, 1 ); add_filter( 'terms_clauses', array( $sitepress, 'terms_clauses' ), 10, 4 ); return $query; } add_filter( 'wpv_filter_query_post_process', 'restore_wpml_filtering', 10, 3 );
It works like a charm whatever parameters are set in WPML for post type which allowed me to use "Translatable - only show translated items" for the post types for which I also need to have filtered list.
As to exclude the pages I need to keep filtered, I added a custom checkbox to pages in order to be able to use it as a condition. I then wrapped the code of the first function in :
$post_id = get_the_ID(); $exception_check = get_post_meta($post_id, 'wpcf-not_multilingual', true); if ($exception_check != 1) { }
There is just an inconvenience to this method, it's causing errors that prevent saving when editing a page on wich a view is integrated if I set the snippet to also run in AJAX call. I guess that's caused by the view blocks preview but I did not find how to exclude it while keeping the code running in frontend AJAX calls.
Maybe you can help me with this last point ?
What error do you get when editing a page on wich a view is integrated?
For the question:
how to exclude it while keeping the code running in frontend AJAX calls.
You can check if it is not in admin side with WP function is_admin()
https://developer.wordpress.org/reference/functions/is_admin/
And check if it is doing AJAX call with WP function wp_doing_ajax()
https://developer.wordpress.org/reference/functions/wp_doing_ajax/
The snippet is already set to run only on frontend and Ajax calls but I still tried to add a !is_admin() condition. It does solve the edit problem but the code does not run anymore on the frontend either if Ajax refresh is used. I found that very strange and can't tell you why but I made several test that confirm it.
As for using wp_doing_ajax() in the condition, it won't help me avoid backend Ajax calls while keeping the code running in frontend ones.
What I would need is a condition that avoid the code running in the View blocks preview only but I did not find any until now.
Anyway if there is no way to fix that, I simply won't use Ajax refresh, it's not essential.
You can use function WP_Screen::is_block_editor() to check if it is the block editor is loading on the current screen, see WP document:
https://developer.wordpress.org/reference/classes/wp_screen/is_block_editor/
Great, that did the trick. Thanks a lot for your help and have a nice weekend.