PluginProbe ʕ •ᴥ•ʔ
Shortcodes and extra features for Phlox theme / 2.17.14
Shortcodes and extra features for Phlox theme v2.17.14
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 4 years ago controls 2 years ago module.php 3 years ago
module.php
508 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 if ( version_compare( ELEMENTOR_VERSION, '3.5.0', '>=' ) ) {
332 $controls_manager->register( new $class_name() );
333 } else {
334 $controls_manager->register_control( $control_type, new $class_name() );
335 }
336
337 }
338
339 }
340 }
341
342 }
343
344 private function extract_post_type( $data ) {
345
346 if ( ! empty( $data['query'] ) && ! empty( $data['query']['post_type'] ) ) {
347 return $data['query']['post_type'];
348 }
349
350 return $data['object_type'];
351 }
352
353 /**
354 * get_term_name_with_parents
355 * @param \WP_Term $term
356 * @param int $max
357 *
358 * @return string
359 */
360 private function get_term_name_with_parents( \WP_Term $term, $max = 3 ) {
361 if ( 0 === $term->parent ) {
362 return $term->name;
363 }
364 $separator = is_rtl() ? ' < ' : ' > ';
365 $test_term = $term;
366 $names = [];
367 while ( $test_term->parent > 0 ) {
368 $test_term = get_term_by( 'term_taxonomy_id', $test_term->parent );
369 if ( ! $test_term ) {
370 break;
371 }
372 $names[] = $test_term->name;
373 }
374
375 $names = array_reverse( $names );
376 if ( count( $names ) < ( $max ) ) {
377 return implode( $separator, $names ) . $separator . $term->name;
378 }
379
380 $name_string = '';
381 for ( $i = 0; $i < ( $max - 1 ); $i++ ) {
382 $name_string .= $names[ $i ] . $separator;
383 }
384 return $name_string . '...' . $separator . $term->name;
385 }
386
387 /**
388 * get post name with parents
389 * @param \WP_Post $post
390 * @param int $max
391 *
392 * @return string
393 */
394 private function get_post_name_with_parents( $post, $max = 3 ) {
395 if ( 0 === $post->post_parent ) {
396 return $post->post_title;
397 }
398 $separator = is_rtl() ? ' < ' : ' > ';
399 $test_post = $post;
400 $names = [];
401 while ( $test_post->post_parent > 0 ) {
402 $test_post = get_post( $test_post->post_parent );
403 if ( ! $test_post ) {
404 break;
405 }
406 $names[] = $test_post->post_title;
407 }
408
409 $names = array_reverse( $names );
410 if ( count( $names ) < ( $max ) ) {
411 return implode( $separator, $names ) . $separator . $post->post_title;
412 }
413
414 $name_string = '';
415 for ( $i = 0; $i < ( $max - 1 ); $i++ ) {
416 $name_string .= $names[ $i ] . $separator;
417 }
418 return $name_string . '...' . $separator . $post->post_title;
419 }
420
421 public function get_query_args( $control_id, $settings ) {
422
423 $controls_manager = Plugin::instance()->controls_manager;
424
425 /** @var Group_Control_Posts $posts_query */
426 $posts_query = $controls_manager->get_control_groups( Group_Control_Posts::get_type() );
427
428 return $posts_query->get_query_args( $control_id, $settings );
429 }
430
431 /**
432 * @param \ElementorPro\Base\Base_Widget $widget
433 * @param string $name
434 * @param array $query_args
435 * @param array $fallback_args
436 *
437 * @return \WP_Query
438 */
439 public function get_query( $widget, $name, $query_args = [], $fallback_args = [] ) {
440 $prefix = $name . '_';
441 $post_type = $widget->get_settings( $prefix . 'post_type' );
442 include_once( __DIR__ . '/classes/elementor-post-query.php' );
443 if ( 'related' === $post_type ) {
444 include_once( __DIR__ . '/classes/elementor-related-query.php' );
445 $elementor_query = new Elementor_Related_Query( $widget, $name, $query_args, $fallback_args );
446 } else {
447 $elementor_query = new Elementor_Post_Query( $widget, $name, $query_args );
448 }
449 return $elementor_query->get_query();
450 }
451
452 public function fix_query_offset( &$query ) {
453 if ( ! empty( $query->query_vars['offset_to_fix'] ) ) {
454 if ( $query->is_paged ) {
455 $query->query_vars['offset'] = $query->query_vars['offset_to_fix'] + ( ( $query->query_vars['paged'] - 1 ) * $query->query_vars['posts_per_page'] );
456 } else {
457 $query->query_vars['offset'] = $query->query_vars['offset_to_fix'];
458 }
459 }
460 }
461
462 public static function fix_query_found_posts( $found_posts, $query ) {
463 $offset_to_fix = $query->get( 'offset_to_fix' );
464
465 if ( $offset_to_fix ) {
466 $found_posts -= $offset_to_fix;
467 }
468
469 return $found_posts;
470 }
471
472 /**
473 * @param Ajax $ajax_manager
474 */
475 public function register_ajax_actions( $ajax_manager ) {
476 $ajax_manager->register_ajax_action( 'query_control_value_titles', [ $this, 'ajax_posts_control_value_titles' ] );
477 $ajax_manager->register_ajax_action( 'panel_posts_control_filter_autocomplete', [ $this, 'ajax_posts_filter_autocomplete' ] );
478 }
479
480 public function localize_settings( $settings ) {
481 $settings = array_replace_recursive( $settings, [
482 'i18n' => [
483 'all' => __( 'All', 'auxin-elements' ),
484 ],
485 ] );
486
487 return $settings;
488 }
489
490 protected function add_actions() {
491 add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_actions' ] );
492
493 if ( version_compare( ELEMENTOR_VERSION, '3.5.0', '>=' ) ) {
494 add_action( 'elementor/controls/register', [ $this, 'register_controls' ] );
495 } else {
496 add_action( 'elementor/controls/controls_registered', [ $this, 'register_controls' ] );
497 }
498
499 add_filter( 'auxin/core_elements/editor/localize_settings', [ $this, 'localize_settings' ] );
500
501 /**
502 * @see https://codex.wordpress.org/Making_Custom_Queries_using_Offset_and_Pagination
503 */
504 add_action( 'pre_get_posts', [ $this, 'fix_query_offset' ], 1 );
505 add_filter( 'found_posts', [ $this, 'fix_query_found_posts' ], 1, 2 );
506 }
507 }
508