PluginProbe
Polylang / 3.7.7
Polylang v3.7.7
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
← All changes | include/query.php +100 -66 2.73.7.7 View file →
@@ -1,5 +1,8 @@
1 1 <?php
2 +/**
3 + * @package Polylang
4 + */
2 5
3 6 /**
4 7 * A class to manipulate the language query var in WP_Query
5 8 *
@@ -5,31 +8,17 @@
5 8 *
6 9 * @since 2.2
7 10 */
8 11 class PLL_Query {
12 + /**
13 + * @var PLL_Model
14 + */
15 + public $model;
9 16
10 - protected static $excludes = array(
11 - 'p',
12 - 'post_parent',
13 - 'attachment',
14 - 'attachment_id',
15 - 'name',
16 - 'pagename',
17 - 'page_id',
18 - 'category_name',
19 - 'tag',
20 - 'tag_id',
21 - 'cat',
22 - 'category__in',
23 - 'category__and',
24 - 'post__in',
25 - 'post_name__in',
26 - 'tag__in',
27 - 'tag__and',
28 - 'tag_slug__in',
29 - 'tag_slug__and',
30 - 'post_parent__in',
31 - );
17 + /**
18 + * @var WP_Query
19 + */
20 + public $query;
32 21
33 22 /**
34 23 * Constructor
35 24 *
@@ -34,10 +23,10 @@
34 23 * Constructor
35 24 *
36 25 * @since 2.2
37 26 *
38 - * @param array $query Reference to the WP_Query object
39 - * @param object $model
27 + * @param WP_Query $query Reference to the WP_Query object.
28 + * @param PLL_Model $model Instance of PLL_Model.
40 29 */
41 30 public function __construct( &$query, &$model ) {
42 31 $this->query = &$query;
43 32 $this->model = &$model;
@@ -43,8 +32,32 @@
43 32 $this->model = &$model;
44 33 }
45 34
46 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 + /**
47 60 * Check if translated taxonomy is queried
48 61 * Compatible with nested queries introduced in WP 4.1
49 62 *
50 63 * @see https://wordpress.org/support/topic/tax_query-bug
@@ -50,9 +63,9 @@
50 63 * @see https://wordpress.org/support/topic/tax_query-bug
51 64 *
52 65 * @since 1.7
53 66 *
54 - * @param array $tax_queries
67 + * @param array $tax_queries An array of tax queries.
55 68 * @return bool
56 69 */
57 70 protected function have_translated_taxonomy( $tax_queries ) {
58 71 if ( is_array( $tax_queries ) ) {
@@ -78,25 +91,36 @@
78 91 *
79 92 * @return array queried taxonomies
80 93 */
81 94 public function get_queried_taxonomies() {
82 - return isset( $this->query->tax_query->queried_terms ) ? array_keys( wp_list_filter( $this->query->tax_query->queried_terms, array( 'operator' => 'NOT IN' ), 'NOT' ) ) : array();
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();
83 96 }
84 97
85 98 /**
86 - * Sets the language in query
87 - * Optimized for ( needs ) WP 3.5+
99 + * Sets the language in query.
100 + * Optimized for (and requires) WP 3.5+.
88 101 *
89 102 * @since 2.2
103 + * @since 3.3 Accepts now an array of languages.
90 104 *
91 - * @param object $lang
105 + * @param PLL_Language|PLL_Language[] $languages Language object(s).
106 + * @return void
92 107 */
93 - public function set_language( $lang ) {
94 - // Defining directly the tax_query ( rather than setting 'lang' avoids transforming the query by WP )
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).
95 119 $lang_query = array(
96 120 'taxonomy' => 'language',
97 121 'field' => 'term_taxonomy_id', // Since WP 3.5
98 - 'terms' => $lang->term_taxonomy_id,
122 + 'terms' => $tt_ids,
99 123 'operator' => 'IN',
100 124 );
101 125
102 126 $tax_query = &$this->query->query_vars['tax_query'];
@@ -103,9 +127,9 @@
103 127
104 128 if ( isset( $tax_query['relation'] ) && 'OR' === $tax_query['relation'] ) {
105 129 $tax_query = array(
106 130 $lang_query,
107 - array( $tax_query ),
131 + $tax_query,
108 132 'relation' => 'AND',
109 133 );
110 134 } elseif ( is_array( $tax_query ) ) {
111 135 // The tax query is expected to be *always* an array, but it seems that 3rd parties fill it with a string
@@ -118,50 +142,24 @@
118 142 }
119 143 }
120 144
121 145 /**
122 - * Add the language in query after it has checked that it won't conflict with other query vars
146 + * Adds the language in the query after it has checked that it won't conflict with other query vars.
123 147 *
124 148 * @since 2.2
125 149 *
126 - * @param object $lang Language
150 + * @param PLL_Language|false $lang Language.
151 + * @return void
127 152 */
128 153 public function filter_query( $lang ) {
129 154 $qvars = &$this->query->query_vars;
130 155
131 - if ( ! isset( $qvars['lang'] ) ) {
132 - /**
133 - * Filter the query vars which disable the language filter in a query
134 - *
135 - * @since 2.3.5
136 - *
137 - * @param array $excludes Query vars excluded from the language filter
138 - * @param object $query WP Query
139 - * @param object $lang Language
140 - */
141 - $excludes = apply_filters( 'pll_filter_query_excluded_query_vars', self::$excludes, $this->query, $lang );
142 -
143 - // Do not filter the query if the language is already specified in another way
144 - foreach ( $excludes as $k ) {
145 - if ( ! empty( $qvars[ $k ] ) ) {
146 - // Specific case for 'cat' as it can contain negative values
147 - if ( 'cat' === $k ) {
148 - foreach ( explode( ',', $qvars['cat'] ) as $cat ) {
149 - if ( $cat > 0 ) {
150 - return;
151 - }
152 - }
153 - } else {
154 - return;
155 - }
156 - }
157 - }
158 -
156 + if ( ! $this->is_already_filtered( $qvars ) ) {
159 157 $taxonomies = array_intersect( $this->model->get_translated_taxonomies(), get_taxonomies( array( '_builtin' => false ) ) );
160 158
161 159 foreach ( $taxonomies as $tax ) {
162 - $tax = get_taxonomy( $tax );
163 - if ( ! empty( $qvars[ $tax->query_var ] ) ) {
160 + $tax_object = get_taxonomy( $tax );
161 + if ( ! empty( $tax_object ) && ! empty( $qvars[ $tax_object->query_var ] ) ) {
164 162 return;
165 163 }
166 164 }
167 165
@@ -175,9 +173,9 @@
175 173
176 174 if ( $taxonomies && ( empty( $qvars['post_type'] ) || 'any' === $qvars['post_type'] ) ) {
177 175 foreach ( $taxonomies as $taxonomy ) {
178 176 $tax_object = get_taxonomy( $taxonomy );
179 - if ( $this->model->is_translated_post_type( $tax_object->object_type ) ) {
177 + if ( ! empty( $tax_object ) && $this->model->is_translated_post_type( $tax_object->object_type ) ) {
180 178 $this->set_language( $lang );
181 179 break;
182 180 }
183 181 }
@@ -185,8 +183,10 @@
185 183 $this->set_language( $lang );
186 184 }
187 185 }
188 186 } else {
187 + $this->maybe_set_language_for_or_relation();
188 +
189 189 // Do not filter untranslatable post types such as nav_menu_item
190 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 191 unset( $qvars['lang'] );
192 192 }
@@ -194,7 +194,41 @@
194 194 // Unset 'all' query var (mainly for admin language filter).
195 195 if ( isset( $qvars['lang'] ) && 'all' === $qvars['lang'] ) {
196 196 unset( $qvars['lang'] );
197 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().
198 232 }
199 233 }
200 234 }