PluginProbe ʕ •ᴥ•ʔ
Shortcodes and extra features for Phlox theme / 2.5.13
Shortcodes and extra features for Phlox theme v2.5.13
2.17.21 2.17.20 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.6 1.0.9 1.1.0 1.3.0 1.3.1 1.3.10 1.3.14 1.3.2 1.3.3 1.3.6 1.4.0 1.4.1 1.4.2 1.5.0 1.5.2 1.6.0 1.6.2 1.6.4 1.7.0 1.7.2 2.10.0 2.10.1 2.10.3 2.10.5 2.10.7 2.10.8 2.10.9 2.11.0 2.11.1 2.11.2 2.12.0 2.14.0 2.15.0 2.15.2 2.15.4 2.15.5 2.15.6 2.15.7 2.15.8 2.15.9 2.16.0 2.16.1 2.16.2 2.16.3 2.16.4 2.17.0 2.17.1 2.17.12 2.17.13 2.17.14 2.17.15 2.17.16 2.17.2 2.17.3 2.17.4 2.17.5 2.17.6 2.17.8 2.17.9 2.4.12 2.4.13 2.4.14 2.4.16 2.4.18 2.4.19 2.4.9 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.14 2.5.15 2.5.16 2.5.17 2.5.19 2.5.2 2.5.20 2.5.3 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.10 2.6.12 2.6.13 2.6.14 2.6.15 2.6.16 2.6.17 2.6.19 2.6.2 2.6.20 2.6.4 2.6.5 2.6.7 2.7.0 2.7.1 2.7.10 2.7.11 2.7.12 2.7.13 2.7.14 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.9 2.9.0 2.9.12 2.9.14 2.9.15 2.9.16 2.9.17 2.9.18 2.9.19 2.9.2 2.9.20 2.9.21 2.9.22 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 2.9.8
auxin-elements / includes / elementor / modules / query-control / module.php
auxin-elements / includes / elementor / modules / query-control Last commit date
classes 6 years ago controls 6 years ago module.php 6 years ago
module.php
498 lines
1 <?php
2 namespace Auxin\Plugin\CoreElements\Elementor\Modules\QueryControl;
3
4 use Elementor\Controls_Manager;
5 use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
6 use Elementor\Widget_Base;
7 use Elementor\Core\Base\Module AS Module_Base;
8 use Auxin\Plugin\CoreElements\Elementor\Modules\QueryControl\Controls\Group_Control_Posts;
9 use Auxin\Plugin\CoreElements\Elementor\Modules\QueryControl\Controls\Group_Control_Query;
10 use Auxin\Plugin\CoreElements\Elementor\Modules\QueryControl\Controls\Group_Control_Related;
11 use Auxin\Plugin\CoreElements\Elementor\Modules\QueryControl\Classes\Elementor_Post_Query;
12 use Auxin\Plugin\CoreElements\Elementor\Modules\QueryControl\Classes\Elementor_Related_Query;
13 use Auxin\Plugin\CoreElements\Elementor\Modules\QueryControl\Controls\Query;
14 use Elementor\Plugin;
15
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit; // Exit if accessed directly
18 }
19
20 class Module extends Module_Base {
21
22 public static $displayed_ids = [];
23
24 public function __construct() {
25 $this->add_actions();
26 }
27
28 public static function add_to_avoid_list( $ids ) {
29 self::$displayed_ids = array_merge( self::$displayed_ids, $ids );
30 }
31
32 public static function get_avoid_list_ids() {
33 return self::$displayed_ids;
34 }
35
36 public static function add_exclude_controls( $widget ) {
37
38 $widget->add_control(
39 'exclude',
40 [
41 'label' => __( 'Exclude', 'auxin-elements' ),
42 'type' => Controls_Manager::SELECT2,
43 'multiple' => true,
44 'options' => [
45 'current_post' => __( 'Current Post', 'auxin-elements' ),
46 'manual_selection' => __( 'Manual Selection', 'auxin-elements' ),
47 ],
48 'label_block' => true,
49 ]
50 );
51
52 $widget->add_control(
53 'exclude_ids',
54 [
55 'label' => __( 'Search & Select', 'auxin-elements' ),
56 'type' => 'aux-query',
57 'post_type' => '',
58 'options' => [],
59 'label_block' => true,
60 'multiple' => true,
61 'filter_type' => 'by_id',
62 'condition' => [
63 'exclude' => 'manual_selection',
64 ],
65 ]
66 );
67
68 $widget->add_control(
69 'avoid_duplicates',
70 [
71 'label' => __( 'Avoid Duplicates', 'auxin-elements' ),
72 'type' => Controls_Manager::SWITCHER,
73 'default' => '',
74 'description' => __( 'Set to Yes to avoid duplicate posts from showing up on the page. This only affects the frontend.', 'auxin-elements' ),
75 ]
76 );
77
78 }
79
80 public function get_name() {
81 return 'query-control';
82 }
83
84 private function search_taxonomies( $query_params, $data ) {
85 $by_field = $this->extract_term_by_field( $data );
86 $terms = get_terms( $query_params );
87
88 global $wp_taxonomies;
89
90 $results = [];
91
92 foreach ( $terms as $term ) {
93 $term_name = $this->get_term_name_with_parents( $term );
94 if ( ! empty( $data['include_type'] ) ) {
95 $text = $wp_taxonomies[ $term->taxonomy ]->labels->name . ': ' . $term_name;
96 } else {
97 $text = $term_name;
98 }
99
100 $results[] = [
101 'id' => $term->{$by_field},
102 'text' => $text,
103 ];
104 }
105
106 return $results;
107
108 }
109
110 /**
111 * @param array $data
112 *
113 * @return string
114 */
115 private function extract_term_by_field( $data ) {
116 if ( ! empty( $data['query'] ) && ! empty( $data['query']['by_field'] ) ) {
117 return $data['query']['by_field'];
118 }
119
120 return 'term_taxonomy_id';
121 }
122
123 /**
124 * @param array $data
125 *
126 * @return array
127 * @throws \Exception
128 */
129 public function ajax_posts_filter_autocomplete( array $data ) {
130 if ( empty( $data['filter_type'] ) || empty( $data['q'] ) ) {
131 throw new \Exception( 'Bad Request' );
132 }
133
134 $results = [];
135
136 switch ( $data['filter_type'] ) {
137 case 'taxonomy':
138 $query_params = [
139 'taxonomy' => $this->extract_post_type( $data ),
140 'search' => $data['q'],
141 'hide_empty' => false,
142 ];
143
144 $results = $this->search_taxonomies( $query_params, $data );
145
146 break;
147
148 case 'cpt_taxonomies':
149 $post_type = $this->extract_post_type( $data );
150
151 $taxonomies = get_object_taxonomies( $post_type );
152
153 $query_params = [
154 'taxonomy' => $taxonomies,
155 'search' => $data['q'],
156 'hide_empty' => false,
157 ];
158
159 $results = $this->search_taxonomies( $query_params, $data );
160
161 break;
162
163 case 'by_id':
164 case 'post':
165 $query_params = [
166 'post_type' => $this->extract_post_type( $data ),
167 's' => $data['q'],
168 'posts_per_page' => -1,
169 ];
170
171 if ( 'attachment' === $query_params['post_type'] ) {
172 $query_params['post_status'] = 'inherit';
173 }
174
175 $query = new \WP_Query( $query_params );
176
177 foreach ( $query->posts as $post ) {
178 $post_type_obj = get_post_type_object( $post->post_type );
179 if ( ! empty( $data['include_type'] ) ) {
180 $text = $post_type_obj->labels->name . ': ' . $post->post_title;
181 } else {
182 $text = ( $post_type_obj->hierarchical ) ? $this->get_post_name_with_parents( $post ) : $post->post_title;
183 }
184
185 $results[] = [
186 'id' => $post->ID,
187 'text' => $text,
188 ];
189 }
190 break;
191
192 case 'author':
193 $query_params = [
194 'who' => 'authors',
195 'has_published_posts' => true,
196 'fields' => [
197 'ID',
198 'display_name',
199 ],
200 'search' => '*' . $data['q'] . '*',
201 'search_columns' => [
202 'user_login',
203 'user_nicename',
204 ],
205 ];
206
207 $user_query = new \WP_User_Query( $query_params );
208
209 foreach ( $user_query->get_results() as $author ) {
210 $results[] = [
211 'id' => $author->ID,
212 'text' => $author->display_name,
213 ];
214 }
215 break;
216 default:
217 $results = apply_filters( 'auxin/core_elements/query_control/get_autocomplete/' . $data['filter_type'], [], $data );
218 }
219
220 return [
221 'results' => $results,
222 ];
223 }
224
225 public function ajax_posts_control_value_titles( $request ) {
226 $ids = (array) $request['id'];
227
228 $results = [];
229
230 switch ( $request['filter_type'] ) {
231 case 'cpt_taxonomies':
232 case 'taxonomy':
233 $by_field = $this->extract_term_by_field( $request );
234 $terms = get_terms(
235 [
236 $by_field => $ids,
237 'hide_empty' => false,
238 ]
239 );
240
241 global $wp_taxonomies;
242 foreach ( $terms as $term ) {
243 $term_name = $this->get_term_name_with_parents( $term );
244 if ( ! empty( $request['include_type'] ) ) {
245 $text = $wp_taxonomies[ $term->taxonomy ]->labels->name . ': ' . $term_name;
246 } else {
247 $text = $term_name;
248 }
249 $results[ $term->{$by_field} ] = $text;
250 }
251 break;
252
253 case 'by_id':
254 case 'post':
255 $query = new \WP_Query(
256 [
257 'post_type' => 'any',
258 'post__in' => $ids,
259 'posts_per_page' => -1,
260 ]
261 );
262
263 foreach ( $query->posts as $post ) {
264 $results[ $post->ID ] = $post->post_title;
265 }
266 break;
267
268 case 'author':
269 $query_params = [
270 'who' => 'authors',
271 'has_published_posts' => true,
272 'fields' => [
273 'ID',
274 'display_name',
275 ],
276 'include' => $ids,
277 ];
278
279 $user_query = new \WP_User_Query( $query_params );
280
281 foreach ( $user_query->get_results() as $author ) {
282 $results[ $author->ID ] = $author->display_name;
283 }
284 break;
285 default:
286 $results = apply_filters( 'auxin/core_elements/query_control/get_value_titles/' . $request['filter_type'], [], $request );
287 }
288
289 return $results;
290 }
291
292 public function register_controls() {
293 $controls_manager = Plugin::$instance->controls_manager;
294
295 $controls = array(
296 'aux-query'=> array(
297 'file' => __DIR__ . '/controls/query.php',
298 'class' => 'Controls\Query',
299 'type' => 'single'
300 ),
301 'aux-posts'=> array(
302 'file' => __DIR__ . '/controls/group-control-posts.php',
303 'class' => 'Controls\Group_Control_Posts',
304 'type' => 'group'
305 ),
306 'aux-query-group'=> array(
307 'file' => __DIR__ . '/controls/group-control-query.php',
308 'class' => 'Controls\Group_Control_Query',
309 'type' => 'group'
310 ),
311 'aux-related-query'=> array(
312 'file' => __DIR__ . '/controls/group-control-related.php',
313 'class' => 'Controls\Group_Control_Related',
314 'type' => 'group'
315 )
316 );
317
318 foreach ( $controls as $control_type => $control_info ) {
319 if( ! empty( $control_info['file'] ) && ! empty( $control_info['class'] ) ){
320 include_once( $control_info['file'] );
321
322 if( class_exists( $control_info['class'] ) ){
323 $class_name = $control_info['class'];
324 } elseif( class_exists( __NAMESPACE__ . '\\' . $control_info['class'] ) ){
325 $class_name = __NAMESPACE__ . '\\' . $control_info['class'];
326 }
327
328 if( $control_info['type'] === 'group' ){
329 $controls_manager->add_group_control( $control_type, new $class_name() );
330 } else {
331 $controls_manager->register_control( $control_type, new $class_name() );
332 }
333
334 }
335 }
336
337 }
338
339 private function extract_post_type( $data ) {
340
341 if ( ! empty( $data['query'] ) && ! empty( $data['query']['post_type'] ) ) {
342 return $data['query']['post_type'];
343 }
344
345 return $data['object_type'];
346 }
347
348 /**
349 * get_term_name_with_parents
350 * @param \WP_Term $term
351 * @param int $max
352 *
353 * @return string
354 */
355 private function get_term_name_with_parents( \WP_Term $term, $max = 3 ) {
356 if ( 0 === $term->parent ) {
357 return $term->name;
358 }
359 $separator = is_rtl() ? ' < ' : ' > ';
360 $test_term = $term;
361 $names = [];
362 while ( $test_term->parent > 0 ) {
363 $test_term = get_term_by( 'term_taxonomy_id', $test_term->parent );
364 if ( ! $test_term ) {
365 break;
366 }
367 $names[] = $test_term->name;
368 }
369
370 $names = array_reverse( $names );
371 if ( count( $names ) < ( $max ) ) {
372 return implode( $separator, $names ) . $separator . $term->name;
373 }
374
375 $name_string = '';
376 for ( $i = 0; $i < ( $max - 1 ); $i++ ) {
377 $name_string .= $names[ $i ] . $separator;
378 }
379 return $name_string . '...' . $separator . $term->name;
380 }
381
382 /**
383 * get post name with parents
384 * @param \WP_Post $post
385 * @param int $max
386 *
387 * @return string
388 */
389 private function get_post_name_with_parents( $post, $max = 3 ) {
390 if ( 0 === $post->post_parent ) {
391 return $post->post_title;
392 }
393 $separator = is_rtl() ? ' < ' : ' > ';
394 $test_post = $post;
395 $names = [];
396 while ( $test_post->post_parent > 0 ) {
397 $test_post = get_post( $test_post->post_parent );
398 if ( ! $test_post ) {
399 break;
400 }
401 $names[] = $test_post->post_title;
402 }
403
404 $names = array_reverse( $names );
405 if ( count( $names ) < ( $max ) ) {
406 return implode( $separator, $names ) . $separator . $post->post_title;
407 }
408
409 $name_string = '';
410 for ( $i = 0; $i < ( $max - 1 ); $i++ ) {
411 $name_string .= $names[ $i ] . $separator;
412 }
413 return $name_string . '...' . $separator . $post->post_title;
414 }
415
416 public function get_query_args( $control_id, $settings ) {
417
418 $controls_manager = Plugin::$instance->controls_manager;
419
420 /** @var Group_Control_Posts $posts_query */
421 $posts_query = $controls_manager->get_control_groups( Group_Control_Posts::get_type() );
422
423 return $posts_query->get_query_args( $control_id, $settings );
424 }
425
426 /**
427 * @param \ElementorPro\Base\Base_Widget $widget
428 * @param string $name
429 * @param array $query_args
430 * @param array $fallback_args
431 *
432 * @return \WP_Query
433 */
434 public function get_query( $widget, $name, $query_args = [], $fallback_args = [] ) {
435 $prefix = $name . '_';
436 $post_type = $widget->get_settings( $prefix . 'post_type' );
437 include_once( __DIR__ . '/classes/elementor-post-query.php' );
438 if ( 'related' === $post_type ) {
439 include_once( __DIR__ . '/classes/elementor-related-query.php' );
440 $elementor_query = new Elementor_Related_Query( $widget, $name, $query_args, $fallback_args );
441 } else {
442 $elementor_query = new Elementor_Post_Query( $widget, $name, $query_args );
443 }
444 return $elementor_query->get_query();
445 }
446
447 public function fix_query_offset( &$query ) {
448 if ( ! empty( $query->query_vars['offset_to_fix'] ) ) {
449 if ( $query->is_paged ) {
450 $query->query_vars['offset'] = $query->query_vars['offset_to_fix'] + ( ( $query->query_vars['paged'] - 1 ) * $query->query_vars['posts_per_page'] );
451 } else {
452 $query->query_vars['offset'] = $query->query_vars['offset_to_fix'];
453 }
454 }
455 }
456
457 public static function fix_query_found_posts( $found_posts, $query ) {
458 $offset_to_fix = $query->get( 'offset_to_fix' );
459
460 if ( $offset_to_fix ) {
461 $found_posts -= $offset_to_fix;
462 }
463
464 return $found_posts;
465 }
466
467 /**
468 * @param Ajax $ajax_manager
469 */
470 public function register_ajax_actions( $ajax_manager ) {
471 $ajax_manager->register_ajax_action( 'query_control_value_titles', [ $this, 'ajax_posts_control_value_titles' ] );
472 $ajax_manager->register_ajax_action( 'panel_posts_control_filter_autocomplete', [ $this, 'ajax_posts_filter_autocomplete' ] );
473 }
474
475 public function localize_settings( $settings ) {
476 $settings = array_replace_recursive( $settings, [
477 'i18n' => [
478 'all' => __( 'All', 'auxin-elements' ),
479 ],
480 ] );
481
482 return $settings;
483 }
484
485 protected function add_actions() {
486 add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_actions' ] );
487 add_action( 'elementor/controls/controls_registered', [ $this, 'register_controls' ] );
488
489 add_filter( 'auxin/core_elements/editor/localize_settings', [ $this, 'localize_settings' ] );
490
491 /**
492 * @see https://codex.wordpress.org/Making_Custom_Queries_using_Offset_and_Pagination
493 */
494 add_action( 'pre_get_posts', [ $this, 'fix_query_offset' ], 1 );
495 add_filter( 'found_posts', [ $this, 'fix_query_found_posts' ], 1, 2 );
496 }
497 }
498