polylang.php
6.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
<?php
/**
* /lib/compatibility/polylang.php
*
* Polylang compatibility features.
*
* @package Relevanssi
* @author Mikko Saari
* @license https://wordpress.org/about/gpl/ GNU General Public License
* @see https://www.relevanssi.com/
*/
add_filter( 'relevanssi_modify_wp_query', 'relevanssi_polylang_filter' );
add_filter( 'relevanssi_where', 'relevanssi_polylang_where_include_terms' );
add_filter( 'relevanssi_hits_filter', 'relevanssi_polylang_term_filter' );
/**
* Removes the Polylang language filters.
*
* If the Polylang allow all option ('relevanssi_polylang_all_languages') is
* enabled this removes the Polylang language filter. By default Polylang
* filters the languages using a taxonomy query.
*
* @param object $query WP_Query object we need to clean up.
*/
function relevanssi_polylang_filter( $query ) {
$polylang_allow_all = get_option( 'relevanssi_polylang_all_languages' );
if ( 'on' === $polylang_allow_all ) {
$ok_queries = array();
if ( ! isset( $query->tax_query ) ) {
// No tax query set, backing off.
return;
}
if ( ! isset( $query->tax_query->queries ) || ! is_array( $query->tax_query->queries ) ) {
// No tax query set, backing off.
return;
}
foreach ( $query->tax_query->queries as $tax_query ) {
if ( isset( $tax_query['taxonomy'] ) && 'language' !== $tax_query['taxonomy'] ) {
// Not a language tax query.
$ok_queries[] = $tax_query;
}
}
$query->tax_query->queries = $ok_queries;
if ( isset( $query->query_vars['tax_query'] ) ) {
// Tax queries can be here as well, so let's sweep this one too.
$ok_queries = array();
foreach ( $query->query_vars['tax_query'] as $tax_query ) {
if ( isset( $tax_query['taxonomy'] ) ) {
if ( 'language' !== $tax_query['taxonomy'] ) {
$ok_queries[] = $tax_query;
}
} else {
// Relation parameter most likely.
$ok_queries[] = $tax_query;
}
}
$query->query_vars['tax_query'] = $ok_queries;
}
if ( isset( $query->query_vars['taxonomy'] ) && 'language' === $query->query_vars['taxonomy'] ) {
// Another way to set the taxonomy.
unset( $query->query_vars['taxonomy'] );
unset( $query->query_vars['term'] );
}
}
return $query;
}
/**
* Allows taxonomy terms in language-restricted searches.
*
* This is a bit of a hack, where the language taxonomy WHERE clause is modified
* on the go to allow all posts with the post ID -1 (which means taxonomy terms
* and users). This may break suddenly in updates, but I haven't come up with a
* better way so far.
*
* @param string $where The WHERE clause to modify.
*
* @return string The WHERE clause with additional filtering included.
*
* @since 2.1.6
*/
function relevanssi_polylang_where_include_terms( $where ) {
global $wpdb;
$current_language = substr( get_locale(), 0, 2 );
if ( function_exists( 'pll_current_language' ) ) {
$current_language = pll_current_language();
}
$languages = get_terms( array( 'taxonomy' => 'language' ) );
$language_id = 0;
foreach ( $languages as $language ) {
if (
! is_wp_error( $language ) &&
$language instanceof WP_Term &&
$language->slug === $current_language
) {
$language_id = intval( $language->term_id );
break;
}
}
// Language ID should now have current language ID.
if ( 0 !== $language_id ) {
// Do a simple search-and-replace to modify the query.
$where = preg_replace( '/\s+/', ' ', $where );
$where = preg_replace( '/\(\s/', '(', $where );
$where = str_replace(
"AND relevanssi.doc IN (SELECT DISTINCT(tr.object_id) FROM {$wpdb->prefix}term_relationships AS tr WHERE tr.term_taxonomy_id IN ($language_id))",
"AND (relevanssi.doc IN ( SELECT DISTINCT(tr.object_id) FROM {$wpdb->prefix}term_relationships AS tr WHERE tr.term_taxonomy_id IN ($language_id)) OR (relevanssi.doc = -1))",
$where
);
}
return $where;
}
/**
* Filters out taxonomy terms in the wrong language.
*
* If all languages are not allowed, this filter goes through the results and
* removes the taxonomy terms in the wrong language. This can't be done in the
* original query because the term language information is slightly hard to
* find.
*
* @param array $hits The found posts are in $hits[0].
*
* @return array The $hits array with the unwanted posts removed.
*
* @since 2.1.6
*/
function relevanssi_polylang_term_filter( $hits ) {
$polylang_allow_all = get_option( 'relevanssi_polylang_all_languages' );
if ( 'on' !== $polylang_allow_all ) {
$current_language = substr( get_locale(), 0, 2 );
if ( function_exists( 'pll_current_language' ) ) {
$current_language = pll_current_language();
}
$accepted_hits = array();
foreach ( $hits[0] as $hit ) {
$original_hit = $hit;
if ( is_numeric( $hit ) ) {
// In case "fields" is set to "ids", fetch the post object we need.
$original_hit = $hit;
$hit = get_post( $hit );
}
if ( ! isset( $hit->post_content ) && isset( $hit->ID ) ) {
// The "fields" is set to "id=>parent".
$original_hit = $hit;
$hit = get_post( $hit->ID );
}
if ( isset( $hit->ID ) && -1 === $hit->ID && isset( $hit->term_id ) ) {
$term_id = intval( $hit->term_id );
$translations = pll_get_term_translations( $term_id );
if (
isset( $translations[ $current_language ] ) &&
$translations[ $current_language ] === $term_id
) {
$accepted_hits[] = $original_hit;
}
} else {
$accepted_hits[] = $original_hit;
}
}
$hits[0] = $accepted_hits;
}
return $hits;
}
/**
* Returns the term_taxonomy_id matching the Polylang language based on locale.
*
* @param string $locale The locale string for the language.
*
* @return int The term_taxonomy_id for the language; 0 if nothing is found.
*/
function relevanssi_get_language_term_taxonomy_id( $locale ) {
global $wpdb, $relevanssi_language_term_ids;
if ( isset( $relevanssi_language_term_ids[ $locale ] ) ) {
return $relevanssi_language_term_ids[ $locale ];
}
$languages = $wpdb->get_results(
"SELECT term_taxonomy_id, description FROM $wpdb->term_taxonomy " .
"WHERE taxonomy = 'language'"
);
$term_id = 0;
foreach ( $languages as $row ) {
$description = unserialize( $row->description ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions
if ( $description['locale'] === $locale ) {
$term_id = $row->term_taxonomy_id;
break;
}
}
$relevanssi_language_term_ids[ $locale ] = $term_id;
return $term_id;
}