Skip to content

Commit 5e4501f

Browse files
committed
Add WPML/Polylang support, related-articles fallback, and CPT/URL fixes
- Language_Handler: add get_current_language() and get_translated_term_id() for WPML and Polylang - Display: include language slug in cache keys so multilingual sites don't share cached output - Widgets: resolve stored term/product IDs to the current language before querying - Related: fall back to sibling sections (same product, different section) when primary query returns nothing - wzkb_get_kb_url(): prefer get_post_type_archive_link() over the manual slug construction - CPT: pass suppress_filters => false to both get_posts() calls
1 parent 22e829e commit 5e4501f

8 files changed

Lines changed: 127 additions & 16 deletions

‎includes/class-cpt.php‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -371,10 +371,11 @@ public static function maybe_query_kb_article( $query ) {
371371
// Check if there's a regular post with this slug first.
372372
$regular_post = get_posts(
373373
array(
374-
'name' => $post_name,
375-
'post_type' => 'post',
376-
'post_status' => 'publish',
377-
'posts_per_page' => 1,
374+
'name' => $post_name,
375+
'post_type' => 'post',
376+
'post_status' => 'publish',
377+
'posts_per_page' => 1,
378+
'suppress_filters' => false,
378379
)
379380
);
380381

@@ -386,10 +387,11 @@ public static function maybe_query_kb_article( $query ) {
386387
// No regular post found, check if there's a KB article with this slug.
387388
$kb_post = get_posts(
388389
array(
389-
'name' => $post_name,
390-
'post_type' => 'wz_knowledgebase',
391-
'post_status' => 'publish',
392-
'posts_per_page' => 1,
390+
'name' => $post_name,
391+
'post_type' => 'wz_knowledgebase',
392+
'post_status' => 'publish',
393+
'posts_per_page' => 1,
394+
'suppress_filters' => false,
393395
)
394396
);
395397

‎includes/frontend/class-display.php‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace WebberZone\Knowledge_Base\Frontend;
99

10+
use WebberZone\Knowledge_Base\Frontend\Language_Handler;
1011
use WebberZone\Knowledge_Base\Util\Cache;
1112
use WebberZone\Knowledge_Base\Util\Helpers;
1213

@@ -228,7 +229,8 @@ public static function fetch_terms( $taxonomy, $query_args = array(), $meta_quer
228229

229230
if ( $cache_enabled ) {
230231
// Create a transient-based cache key for non-term-specific queries.
231-
$transient_key = 'wzkb_fetch_terms_' . md5( wp_json_encode( $args ) );
232+
$lang = Language_Handler::get_current_language();
233+
$transient_key = 'wzkb_fetch_terms_' . md5( wp_json_encode( $args ) . '_' . $lang );
232234

233235
// Try to get from transient cache first.
234236
$cached_terms = get_transient( $transient_key );
@@ -577,8 +579,10 @@ public static function get_term_posts( $term ): \WP_Query {
577579

578580
// Support caching to speed up retrieval.
579581
if ( $cache_enabled ) {
580-
$meta_key = Cache::get_key( $args );
581-
$query = Cache::get( $term->term_id, $meta_key );
582+
$lang = Language_Handler::get_current_language();
583+
$cache_key_args = $lang ? array_merge( $args, array( 'lang' => $lang ) ) : $args;
584+
$meta_key = Cache::get_key( $cache_key_args );
585+
$query = Cache::get( $term->term_id, $meta_key );
582586
}
583587

584588
if ( empty( $query ) ) {

‎includes/frontend/class-language-handler.php‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
/**
1818
* Language handler class.
1919
*
20+
* Handles i18n, WPML integration, and Polylang integration.
21+
*
2022
* @since 2.3.0
2123
*/
2224
class Language_Handler {
@@ -40,4 +42,55 @@ public function __construct() {
4042
public static function load_plugin_textdomain() {
4143
load_plugin_textdomain( 'knowledgebase', false, WZKB_PLUGIN_DIR . '/languages/' );
4244
}
45+
46+
/**
47+
* Translate a term ID to the current language.
48+
*
49+
* Widget and shortcode settings store the term ID saved by the admin in the
50+
* default language. On a non-default-language page the stored ID must be
51+
* resolved to the equivalent term in the current language before use.
52+
*
53+
* @since 3.0.0
54+
*
55+
* @param int $term_id Term ID in the default language.
56+
* @param string $taxonomy Taxonomy slug.
57+
* @return int Translated term ID, or the original if no translation exists.
58+
*/
59+
public static function get_translated_term_id( int $term_id, string $taxonomy ): int {
60+
if ( ! $term_id ) {
61+
return $term_id;
62+
}
63+
64+
// WPML.
65+
if ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
66+
return (int) apply_filters( 'wpml_object_id', $term_id, $taxonomy, true );
67+
}
68+
69+
// Polylang.
70+
if ( defined( 'POLYLANG_VERSION' ) ) {
71+
$translated = pll_get_term( $term_id );
72+
return $translated ? (int) $translated : $term_id;
73+
}
74+
75+
return $term_id;
76+
}
77+
78+
/**
79+
* Return the current language slug, or an empty string when no multilingual plugin is active.
80+
*
81+
* @since 3.0.0
82+
*
83+
* @return string Language slug (e.g. 'en', 'fr') or '' if not multilingual.
84+
*/
85+
public static function get_current_language(): string {
86+
if ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
87+
return (string) apply_filters( 'wpml_current_language', '' );
88+
}
89+
90+
if ( defined( 'POLYLANG_VERSION' ) ) {
91+
return (string) pll_current_language();
92+
}
93+
94+
return '';
95+
}
4396
}

‎includes/frontend/class-related.php‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,48 @@ public static function get_related_articles_query( $args = array() ) {
166166
self::sort_query_by_relevance( $query, $category_ids, $tag_ids, $args );
167167
}
168168

169+
// Fallback: if no results and the post has categories, widen the search to
170+
// sibling sections — other sections belonging to the same product.
171+
if ( 0 === $query->post_count && ! empty( $category_ids ) ) {
172+
$products = get_the_terms( $post, 'wzkb_product' );
173+
$product_ids = ( $products && ! is_wp_error( $products ) ) ? wp_list_pluck( $products, 'term_id' ) : array();
174+
175+
$sibling_args = $related_args;
176+
177+
if ( ! empty( $product_ids ) ) {
178+
// Multi-product: restrict to the same product, exclude the current section.
179+
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
180+
$sibling_args['tax_query'] = array(
181+
'relation' => 'AND',
182+
array(
183+
'taxonomy' => 'wzkb_product',
184+
'field' => 'term_id',
185+
'terms' => $product_ids,
186+
),
187+
array(
188+
'taxonomy' => 'wzkb_category',
189+
'field' => 'term_id',
190+
'terms' => $category_ids,
191+
'operator' => 'NOT IN',
192+
),
193+
);
194+
} else {
195+
// Single-product: all sections are siblings — exclude only the current section.
196+
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
197+
$sibling_args['tax_query'] = array(
198+
array(
199+
'taxonomy' => 'wzkb_category',
200+
'field' => 'term_id',
201+
'terms' => $category_ids,
202+
'operator' => 'NOT IN',
203+
),
204+
);
205+
}
206+
207+
$query = new \WP_Query( $sibling_args );
208+
self::sort_query_by_relevance( $query, $category_ids, $tag_ids, $args );
209+
}
210+
169211
/**
170212
* Filters the cache TTL for related article queries.
171213
*

‎includes/functions.php‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,11 @@ function wzkb_get_kb_url() {
209209
return home_url( '/' );
210210
}
211211

212+
$archive_link = get_post_type_archive_link( 'wz_knowledgebase' );
213+
if ( $archive_link ) {
214+
return $archive_link;
215+
}
216+
212217
$kb_slug = \wzkb_get_option( 'kb_slug', 'knowledgebase' );
213218
return home_url( "/{$kb_slug}/" );
214219
}

‎includes/widgets/class-articles-widget.php‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace WebberZone\Knowledge_Base\Widgets;
99

1010
use WebberZone\Knowledge_Base\Frontend\Display;
11+
use WebberZone\Knowledge_Base\Frontend\Language_Handler;
1112

1213
// If this file is called directly, abort.
1314
if ( ! defined( 'WPINC' ) ) {
@@ -171,10 +172,11 @@ public function widget( $args, $instance ) {
171172

172173
// Handle product_id if set.
173174
if ( ! empty( $instance['product_id'] ) ) {
174-
$kb_args['product'] = (int) $instance['product_id'];
175+
$kb_args['product'] = Language_Handler::get_translated_term_id( (int) $instance['product_id'], 'wzkb_product' );
175176
$list_of_posts = Display::get_knowledge_base_loop( 0, 1, true, $kb_args );
176177
} elseif ( ! empty( $instance['term_id'] ) ) {
177-
$term = get_term( $instance['term_id'], 'wzkb_category' );
178+
$term_id = Language_Handler::get_translated_term_id( (int) $instance['term_id'], 'wzkb_category' );
179+
$term = get_term( $term_id, 'wzkb_category' );
178180

179181
if ( empty( $term ) || is_wp_error( $term ) ) {
180182
return;

‎includes/widgets/class-products-widget.php‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace WebberZone\Knowledge_Base\Widgets;
99

1010
use WebberZone\Knowledge_Base\Frontend\Display;
11+
use WebberZone\Knowledge_Base\Frontend\Language_Handler;
1112

1213
if ( ! defined( 'WPINC' ) ) {
1314
die;
@@ -116,7 +117,7 @@ public function widget( $args, $instance ) {
116117

117118
$title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : '';
118119
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
119-
$product_id = ! empty( $instance['product_id'] ) ? (int) $instance['product_id'] : 0;
120+
$product_id = Language_Handler::get_translated_term_id( ! empty( $instance['product_id'] ) ? (int) $instance['product_id'] : 0, 'wzkb_product' );
120121
$depth = isset( $instance['depth'] ) ? (int) $instance['depth'] : -1;
121122

122123
$output = '';

‎includes/widgets/class-sections-widget.php‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
namespace WebberZone\Knowledge_Base\Widgets;
99

10+
use WebberZone\Knowledge_Base\Frontend\Language_Handler;
11+
1012
// If this file is called directly, abort.
1113
if ( ! defined( 'WPINC' ) ) {
1214
die;
@@ -165,8 +167,8 @@ public function widget( $args, $instance ) {
165167
/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
166168
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
167169

168-
$product_id = isset( $instance['product_id'] ) ? (int) $instance['product_id'] : 0;
169-
$term_id = ! empty( $instance['term_id'] ) ? (int) $instance['term_id'] : 0;
170+
$product_id = Language_Handler::get_translated_term_id( isset( $instance['product_id'] ) ? (int) $instance['product_id'] : 0, 'wzkb_product' );
171+
$term_id = Language_Handler::get_translated_term_id( ! empty( $instance['term_id'] ) ? (int) $instance['term_id'] : 0, 'wzkb_category' );
170172

171173
$arguments = array(
172174
'is_widget' => 1,

0 commit comments

Comments
 (0)