PluginProbe
Polylang / 3.7.3
Polylang v3.7.3
3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 3.0.3 All 233 releases
polylang / include / query.php

query.php in Polylang 3.7.3, at include/query.php

235 lines 6.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Polylang
4 */
5
6 /**
7 * A class to manipulate the language query var in WP_Query
8 *
9 * @since 2.2
10 */
11 class PLL_Query {
12 /**
13 * @var PLL_Model
14 */
15 public $model;
16
17 /**
18 * @var WP_Query
19 */
20 public $query;
21
22 /**
23 * Constructor
24 *
25 * @since 2.2
26 *
27 * @param WP_Query $query Reference to the WP_Query object.
28 * @param PLL_Model $model Instance of PLL_Model.
29 */
30 public function __construct( &$query, &$model ) {
31 $this->query = &$query;
32 $this->model = &$model;
33 }
34
35 /**
36 * Checks if the query already includes a language taxonomy.
37 *
38 * @since 3.0
39 *
40 * @param array $qvars WP_Query query vars.
41 * @return bool
42 */
43 protected function is_already_filtered( $qvars ) {
44 if ( isset( $qvars['lang'] ) ) {
45 return true;
46 }
47
48 if ( ! empty( $qvars['tax_query'] ) && is_array( $qvars['tax_query'] ) ) {
49 foreach ( $qvars['tax_query'] as $tax_query ) {
50 if ( isset( $tax_query['taxonomy'] ) && 'language' === $tax_query['taxonomy'] ) {
51 return true;
52 }
53 }
54 }
55
56 return false;
57 }
58
59 /**
60 * Check if translated taxonomy is queried
61 * Compatible with nested queries introduced in WP 4.1
62 *
63 * @see https://wordpress.org/support/topic/tax_query-bug
64 *
65 * @since 1.7
66 *
67 * @param array $tax_queries An array of tax queries.
68 * @return bool
69 */
70 protected function have_translated_taxonomy( $tax_queries ) {
71 if ( is_array( $tax_queries ) ) {
72 foreach ( $tax_queries as $tax_query ) {
73 if ( isset( $tax_query['taxonomy'] ) && $this->model->is_translated_taxonomy( $tax_query['taxonomy'] ) && ! ( isset( $tax_query['operator'] ) && 'NOT IN' === $tax_query['operator'] ) ) {
74 return true;
75 }
76
77 // Nested queries
78 elseif ( is_array( $tax_query ) && $this->have_translated_taxonomy( $tax_query ) ) {
79 return true;
80 }
81 }
82 }
83
84 return false;
85 }
86
87 /**
88 * Get queried taxonomies
89 *
90 * @since 2.2
91 *
92 * @return array queried taxonomies
93 */
94 public function get_queried_taxonomies() {
95 return ! empty( $this->query->tax_query->queried_terms ) ? array_keys( wp_list_filter( $this->query->tax_query->queried_terms, array( 'operator' => 'NOT IN' ), 'NOT' ) ) : array();
96 }
97
98 /**
99 * Sets the language in query.
100 * Optimized for (and requires) WP 3.5+.
101 *
102 * @since 2.2
103 * @since 3.3 Accepts now an array of languages.
104 *
105 * @param PLL_Language|PLL_Language[] $languages Language object(s).
106 * @return void
107 */
108 public function set_language( $languages ) {
109 if ( ! is_array( $languages ) ) {
110 $languages = array( $languages );
111 }
112
113 $tt_ids = array();
114 foreach ( $languages as $language ) {
115 $tt_ids[] = $language->get_tax_prop( 'language', 'term_taxonomy_id' );
116 }
117
118 // Defining directly the tax_query (rather than setting 'lang' avoids transforming the query by WP).
119 $lang_query = array(
120 'taxonomy' => 'language',
121 'field' => 'term_taxonomy_id', // Since WP 3.5
122 'terms' => $tt_ids,
123 'operator' => 'IN',
124 );
125
126 $tax_query = &$this->query->query_vars['tax_query'];
127
128 if ( isset( $tax_query['relation'] ) && 'OR' === $tax_query['relation'] ) {
129 $tax_query = array(
130 $lang_query,
131 $tax_query,
132 'relation' => 'AND',
133 );
134 } elseif ( is_array( $tax_query ) ) {
135 // The tax query is expected to be *always* an array, but it seems that 3rd parties fill it with a string
136 // Causing a fatal error if we don't check it.
137 // See https://wordpress.org/support/topic/fatal-error-2947/
138 $tax_query[] = $lang_query;
139 } elseif ( empty( $tax_query ) ) {
140 // Supposing the tax query has been wrongly filled with an empty string
141 $tax_query = array( $lang_query );
142 }
143 }
144
145 /**
146 * Adds the language in the query after it has checked that it won't conflict with other query vars.
147 *
148 * @since 2.2
149 *
150 * @param PLL_Language|false $lang Language.
151 * @return void
152 */
153 public function filter_query( $lang ) {
154 $qvars = &$this->query->query_vars;
155
156 if ( ! $this->is_already_filtered( $qvars ) ) {
157 $taxonomies = array_intersect( $this->model->get_translated_taxonomies(), get_taxonomies( array( '_builtin' => false ) ) );
158
159 foreach ( $taxonomies as $tax ) {
160 $tax_object = get_taxonomy( $tax );
161 if ( ! empty( $tax_object ) && ! empty( $qvars[ $tax_object->query_var ] ) ) {
162 return;
163 }
164 }
165
166 if ( ! empty( $qvars['tax_query'] ) && $this->have_translated_taxonomy( $qvars['tax_query'] ) ) {
167 return;
168 }
169
170 // Filter queries according to the requested language
171 if ( ! empty( $lang ) ) {
172 $taxonomies = $this->get_queried_taxonomies();
173
174 if ( $taxonomies && ( empty( $qvars['post_type'] ) || 'any' === $qvars['post_type'] ) ) {
175 foreach ( $taxonomies as $taxonomy ) {
176 $tax_object = get_taxonomy( $taxonomy );
177 if ( ! empty( $tax_object ) && $this->model->is_translated_post_type( $tax_object->object_type ) ) {
178 $this->set_language( $lang );
179 break;
180 }
181 }
182 } elseif ( empty( $qvars['post_type'] ) || $this->model->is_translated_post_type( $qvars['post_type'] ) ) {
183 $this->set_language( $lang );
184 }
185 }
186 } else {
187 $this->maybe_set_language_for_or_relation();
188
189 // Do not filter untranslatable post types such as nav_menu_item
190 if ( isset( $qvars['post_type'] ) && ! $this->model->is_translated_post_type( $qvars['post_type'] ) && ( empty( $qvars['tax_query'] ) || ! $this->have_translated_taxonomy( $qvars['tax_query'] ) ) ) {
191 unset( $qvars['lang'] );
192 }
193
194 // Unset 'all' query var (mainly for admin language filter).
195 if ( isset( $qvars['lang'] ) && 'all' === $qvars['lang'] ) {
196 unset( $qvars['lang'] );
197 }
198 }
199 }
200
201 /**
202 * Sets the language correctly if the current query is a 'OR' relation,
203 * since WordPress merges the language with the other query vars when the relation is OR.
204 *
205 * @since 3.3
206 *
207 * @return void
208 */
209 protected function maybe_set_language_for_or_relation() {
210 if ( ! $this->query->tax_query instanceof WP_Tax_Query ) {
211 return;
212 }
213
214 if ( 'OR' !== $this->query->tax_query->relation ) {
215 return;
216 }
217
218 if ( ! isset( $this->query->tax_query->queried_terms['language'] ) ) {
219 return;
220 }
221
222 $langs = $this->query->tax_query->queried_terms['language']['terms'];
223 if ( is_string( $langs ) ) {
224 $langs = explode( ',', $langs );
225 }
226 $langs = array_map( array( $this->model, 'get_language' ), $langs );
227 $langs = array_filter( $langs );
228
229 if ( ! empty( $langs ) ) {
230 $this->set_language( $langs );
231 unset( $this->query->query_vars['lang'] ); // Unset the language query var otherwise WordPress would add the language query by slug in WP_Query::parse_tax_query().
232 }
233 }
234 }
235