PluginProbe
UiCore Elements – Free widgets and templates for Elementor / 1.3.17
UiCore Elements – Free widgets and templates for Elementor v1.3.17
1.3.17 1.3.16 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 All 41 releases
uicore-elements / includes / utils / post-component.php

post-component.php in UiCore Elements – Free widgets and templates for Elementor 1.3.17, at includes/utils/post-component.php

1,383 lines 50.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace UiCoreElements\Utils;
4
5 use Elementor\Controls_Manager;
6 use Elementor\Icons_Manager;
7 use Elementor\Plugin;
8
9 use UiCoreElements\Helper;
10 use UiCoreElements\Controls\Query;
11 use UiCoreElements\Controls\Post_Filter;
12
13 use Elementor\Group_Control_Background;
14 use Elementor\Group_Control_Border;
15 use Elementor\Group_Control_Box_Shadow;
16 use Elementor\Group_Control_Typography;
17 use Elementor\Includes\Widgets\Traits\Button_Trait;
18 use UiCoreElements\Utils\Meta_Trait;
19
20 defined('ABSPATH') || exit();
21
22 /**
23 * Post Component
24 *
25 * @since 1.0.4
26 */
27
28 trait Post_Trait
29 {
30
31 use Button_Trait,
32 Meta_Trait;
33
34 // Control Register Content functions
35 function TRAIT_register_post_item_controls($section = true)
36 {
37 if ($section) {
38 $this->start_controls_section(
39 'section_item_content',
40 [
41 'label' => esc_html__('Item', 'uicore-elements'),
42 ]
43 );
44 }
45 $this->add_control(
46 'box_style',
47 [
48 'label' => __('Item Style', 'uicore-elements'),
49 'type' => Controls_Manager::SELECT,
50 'default' => 'classic',
51 'options' => [
52 'classic' => __('Classic', 'uicore-elements'),
53 'split' => __('Split', 'uicore-elements'),
54 'overlay' => __('Overlay', 'uicore-elements'),
55 ],
56 'render_type' => 'template',
57 'prefix_class' => 'ui-e-apg-',
58 ]
59 );
60 $this->add_control(
61 'split_mobile',
62 [
63 'label' => __('Use Classic Layout on Mobile' . UICORE_ELEMENTS_NEW_OPTION, 'uicore-elements'), // TODO: remove badge, at least 2, releases after 1.3.15
64 'type' => Controls_Manager::SWITCHER,
65 'default' => 'ui-e-apg-split-not-phone',
66 'return_value' => 'ui-e-apg-split-not-phone',
67 'prefix_class' => '',
68 'condition' => [
69 'box_style' => 'split',
70 ],
71 ]
72 );
73 $this->add_control(
74 'image',
75 [
76 'label' => __('Image', 'uicore-elements'),
77 'type' => Controls_Manager::SWITCHER,
78 'separator' => 'before',
79 'default' => 'yes'
80 ]
81 );
82 $this->add_control(
83 'image_size_select',
84 [
85 'label' => __('Image Size', 'uicore-elements'),
86 'type' => Controls_Manager::SELECT,
87 'default' => 'uicore-medium',
88 'options' => Helper::get_images_sizes(),
89 'separator' => 'after',
90 'condition' => [
91 'image' => 'yes',
92 ]
93 ]
94 );
95 $this->add_control(
96 'title',
97 [
98 'label' => __('Title', 'uicore-elements'),
99 'type' => Controls_Manager::SWITCHER,
100 'default' => 'yes'
101 ]
102 );
103 $this->add_control(
104 'title_tag',
105 [
106 'label' => __('HTML Tag', 'uicore-elements'),
107 'type' => Controls_Manager::SELECT,
108 'default' => 'h4',
109 'options' => Helper::get_title_tags(),
110 'separator' => 'after',
111 'condition' => [
112 'title' => 'yes',
113 ]
114 ]
115 );
116 $this->add_control(
117 'excerpt',
118 [
119 'label' => __('Excerpt', 'uicore-elements'),
120 'type' => Controls_Manager::SWITCHER,
121 'default' => 'yes'
122 ]
123 );
124 $this->add_control(
125 'excerpt_trim',
126 [
127 'label' => __('Excerpt Length (words)', 'uicore-elements'),
128 'type' => Controls_Manager::NUMBER,
129 'min' => 5,
130 'max' => 100,
131 'step' => 1,
132 'default' => 55,
133 'separator' => 'after',
134 'condition' => array(
135 'excerpt' => 'yes',
136 ),
137 ]
138 );
139 $this->add_control(
140 'show_button',
141 [
142 'label' => __('Read More Button', 'uicore-elements'),
143 'type' => Controls_Manager::SWITCHER,
144 'default' => 'no'
145 ]
146 );
147 $this->add_control(
148 'global_link',
149 [
150 'label' => __('Global Wrapper Link', 'uicore-elements'),
151 'type' => Controls_Manager::SWITCHER,
152 'default' => 'no',
153 'condition' => [
154 'box_style' => 'overlay'
155 ]
156 ]
157 );
158
159 if ($section) {
160 $this->end_controls_section();
161 }
162 }
163 function TRAIT_register_post_button_controls($section = true)
164 {
165 if ($section) {
166 $this->start_controls_section(
167 'section_button_content',
168 [
169 'label' => esc_html__('Button', 'uicore-elements'),
170 'condition' => array(
171 'show_button' => 'yes',
172 ),
173 ]
174 );
175 }
176
177 $this->register_button_content_controls(
178 [
179 'section_condition' => [
180 'show_button' => 'yes'
181 ],
182 'button_default_text' => 'Read More'
183 ]
184 );
185 $this->remove_control('button_type');
186 $this->remove_control('link');
187 $this->remove_control('button_css_id');
188 $this->remove_control('size');
189 $this->remove_control('align');
190
191 if ($section) {
192 $this->end_controls_section();
193 }
194 }
195 /**
196 * Register Post Meta Controls.
197 *
198 * @param bool $section. Print section or not.
199 * @param bool $product_metas. If true, will only print options that relates with products.
200 */
201 function TRAIT_register_post_meta_controls($section = true, $product_metas = false)
202 {
203 if ($section) {
204 $this->start_controls_section(
205 'section_extra_item_content',
206 [
207 'label' => esc_html__('Meta', 'uicore-elements'),
208 ]
209 );
210 }
211
212 $this->add_control(
213 'top_meta',
214 [
215 'label' => esc_html__('Top Meta', 'uicore-elements'),
216 'type' => \Elementor\Controls_Manager::REPEATER,
217 'fields' => $this->get_meta_content_controls($product_metas),
218 'default' => [
219 [
220 'type' => $product_metas ? 'product sale' : 'category'
221 ],
222 ],
223 'title_field' => '<span style="text-transform: capitalize">{{{ type }}}</span>',
224 'prevent_empty' => false,
225 'separator' => 'before'
226 ]
227 );
228 $this->add_control(
229 'before_title_meta',
230 [
231 'label' => esc_html__('Before Title Meta', 'uicore-elements'),
232 'type' => \Elementor\Controls_Manager::REPEATER,
233 'fields' => $this->get_meta_content_controls($product_metas),
234 'default' => [
235 [
236 'type' => $product_metas ? 'none' : 'author'
237 ],
238 ],
239 'title_field' => '<span style="text-transform: capitalize">{{{ type }}}</span>',
240 'prevent_empty' => false,
241 'separator' => 'before',
242 ]
243 );
244 $this->add_control(
245 'after_title_meta',
246 [
247 'label' => esc_html__('After Title Meta', 'uicore-elements'),
248 'type' => \Elementor\Controls_Manager::REPEATER,
249 'fields' => $this->get_meta_content_controls($product_metas),
250 'default' => [
251 [
252 'type' => $product_metas ? 'product price' : 'date'
253 ],
254 ],
255 'title_field' => '<span style="text-transform: capitalize">{{{ type }}}</span>',
256 'prevent_empty' => false,
257 'separator' => 'before',
258 ]
259 );
260 $this->add_control(
261 'bottom_meta',
262 [
263 'label' => esc_html__('Bottom Meta', 'uicore-elements'),
264 'type' => \Elementor\Controls_Manager::REPEATER,
265 'fields' => $this->get_meta_content_controls($product_metas),
266 'default' => [
267 [
268 'type' => $product_metas ? 'none' : 'none'
269 ],
270 ],
271 'title_field' => '<span style="text-transform: capitalize">{{{ type }}}</span>',
272 'prevent_empty' => false,
273 'separator' => 'before',
274 ]
275 );
276 if ($section) {
277 $this->end_controls_section();
278 }
279 }
280 function TRAIT_register_post_query_controls($section = true)
281 {
282
283 // In some contexts, such as theme-builder, our custom controls are not available
284 if (! class_exists('UiCoreElements\Controls\Post_Filter')) {
285 require_once UICORE_ELEMENTS_INCLUDES . '/controls/class-post-filter-control.php';
286 }
287
288 if ($section) {
289 $this->start_controls_section(
290 'section_post_grid_def',
291 [
292 'label' => esc_html__('Query', 'uicore-elements'),
293 ]
294 );
295 }
296
297 $this->add_group_control(
298 Post_Filter::get_type(),
299 [
300 'name' => 'posts-filter',
301 'label' => esc_html__('Posts', 'uicore-elements'),
302 'description' => esc_html__('Current Query Settings > Reading', 'uicore-elements'),
303 ]
304 );
305 $this->add_control(
306 'item_order',
307 [
308 'label' => esc_html__('Item Order', 'uicore-elements'),
309 'type' => Controls_Manager::SELECT,
310 'options' => [
311 'ASC' => esc_html__('Ascending', 'uicore-elements'),
312 'DESC' => esc_html__('Descending', 'uicore-elements'),
313 ],
314 'default' => 'DESC',
315 ]
316 );
317 $this->add_control(
318 'item_order_by',
319 [
320 'label' => esc_html__('Item Order By', 'uicore-elements'),
321 'type' => Controls_Manager::SELECT,
322 'options' => [
323 'date' => esc_html__('Date', 'uicore-elements'),
324 'modified' => esc_html__('Modified Date', 'uicore-elements'),
325 'title' => esc_html__('Title', 'uicore-elements'),
326 'rand' => esc_html__('Random', 'uicore-elements'),
327 'comment_count' => esc_html__('Comments Count', 'uicore-elements'),
328 'menu_order' => esc_html__('Menu Order', 'uicore-elements'),
329 ],
330 'default' => 'date',
331 ]
332 );
333 $this->add_control(
334 'item_limit',
335 [
336 'label' => esc_html__('Item Limit', 'uicore-elements'),
337 'type' => Controls_Manager::SLIDER,
338 'reder_type' => 'template',
339 'range' => [
340 'px' => [
341 'min' => -1,
342 'max' => 100,
343 ],
344 ],
345 'default' => [
346 'size' => 3,
347 ],
348 'condition' => array(
349 'posts-filter_post_type!' => 'current',
350 ),
351 ]
352 );
353
354 $this->add_control(
355 'offset',
356 [
357 'label' => esc_html__('Query Offset', 'uicore-elements'),
358 'type' => Controls_Manager::SLIDER,
359 'render_type' => 'template',
360 'range' => [
361 'px' => [
362 'min' => -1,
363 'max' => 10,
364 ],
365 ],
366 'default' => [
367 'size' => 0,
368 ],
369 'condition' => [
370 'pagination_type' => 'numbers',
371 ]
372 ]
373 );
374
375 $this->add_control(
376 'offset_alert',
377 [
378 'type' => Controls_Manager::ALERT,
379 'alert_type' => 'info',
380 'content' => esc_html__('Offset is disabled with Load More pagination.', 'uicore-elements'),
381 'condition' => [
382 'pagination_type!' => 'numbers',
383 ]
384 ]
385 );
386
387 $this->add_control(
388 'sticky',
389 [
390 'label' => esc_html__('Sticky Posts', 'uicore-elements'),
391 'type' => Controls_Manager::SWITCHER,
392 'label_on' => esc_html__('Show', 'uicore-elements'),
393 'label_off' => esc_html__('Hide', 'uicore-elements'),
394 'description' => esc_html__('Sticky posts works only on the front-end.', 'uicore-elements'),
395 'return_value' => 1,
396 'default' => 0,
397 'condition' => [
398 'pagination!' => 'yes',
399 ],
400 ]
401 );
402
403 if ($section) {
404 $this->end_controls_section();
405 }
406 }
407
408 // Control Register Styles functions
409 function TRAIT_register_post_item_style_controls($section = true, $active_tab = false)
410 {
411 if ($section) {
412 $this->start_controls_section(
413 'section_style_item',
414 [
415 'label' => __('Item Style', 'uicore-elements'),
416 'tab' => Controls_Manager::TAB_STYLE,
417 ]
418 );
419 }
420
421 $this->start_controls_tabs(
422 'item_border_shadow'
423 );
424
425 $this->start_controls_tab(
426 'item_bs_normal_tab',
427 [
428 'label' => esc_html__('Normal', 'uicore-elements'),
429 ]
430 );
431 $this->add_group_control(
432 Group_Control_Background::get_type(),
433 [
434 'name' => 'content_bg',
435 'types' => ['classic', 'gradient'],
436 'selector' => '{{WRAPPER}} .ui-e-item article',
437 ]
438 );
439 $this->add_group_control(
440 Group_Control_Border::get_type(),
441 [
442 'name' => 'item_border',
443 'selector' => '{{WRAPPER}} .ui-e-item article',
444 ]
445 );
446 $this->add_group_control(
447 Group_Control_Box_Shadow::get_type(),
448 [
449 'name' => 'item_shadow',
450 'selector' => '{{WRAPPER}} .ui-e-item article',
451 ]
452 );
453 $this->end_controls_tab();
454
455 $this->start_controls_tab(
456 'item_bs_hover_tab',
457 [
458 'label' => esc_html__('Hover', 'uicore-elements'),
459 ]
460 );
461 $this->add_group_control(
462 Group_Control_Background::get_type(),
463 [
464 'name' => 'content_bg_hover',
465 'types' => ['classic', 'gradient'],
466 'selector' => '{{WRAPPER}} .ui-e-item:hover article',
467 ]
468 );
469 $this->add_group_control(
470 Group_Control_Border::get_type(),
471 [
472 'name' => 'item_border_hover',
473 'selector' => '{{WRAPPER}} .ui-e-item:hover article',
474 ]
475 );
476 $this->add_group_control(
477 Group_Control_Box_Shadow::get_type(),
478 [
479 'name' => 'item_shadow_hover',
480 'selector' => '{{WRAPPER}} .ui-e-item:hover article',
481 ]
482 );
483 $this->end_controls_tab();
484
485 if ($active_tab) {
486 $this->start_controls_tab(
487 'item_bs_active_tab',
488 [
489 'label' => esc_html__('Active', 'uicore-elements'),
490 ]
491 );
492 $this->add_group_control(
493 Group_Control_Border::get_type(),
494 [
495 'name' => 'item_border_active',
496 'selector' => '{{WRAPPER}} .ui-e-item.ui-e-active article',
497 ]
498 );
499 $this->add_group_control(
500 Group_Control_Box_Shadow::get_type(),
501 [
502 'name' => 'item_shadow_active',
503 'selector' => '{{WRAPPER}} .ui-e-item.ui-e-active article',
504 ]
505 );
506 $this->end_controls_tab();
507 }
508
509 $this->end_controls_tabs();
510
511 $this->add_control(
512 'item_padding',
513 [
514 'label' => esc_html__('Padding', 'uicore-elements'),
515 'type' => Controls_Manager::DIMENSIONS,
516 'size_units' => ['px', 'em', 'rem', '%'],
517 'separator' => 'before',
518 'selectors' => [
519 '{{WRAPPER}} .ui-e-item article' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
520 ],
521 'condition' => array(
522 'box_style!' => 'overlay',
523 ),
524 ]
525
526 );
527 $this->add_control(
528 'item_radius',
529 [
530 'label' => esc_html__('Border Radius', 'uicore-elements'),
531 'type' => Controls_Manager::DIMENSIONS,
532 'selectors' => [
533 '{{WRAPPER}} ' => '--ui-e-border-radius: {{TOP}}px {{RIGHT}}px {{BOTTOM}}px {{LEFT}}px;'
534 ],
535 ]
536 );
537
538 if ($section) {
539 $this->end_controls_section();
540 }
541 }
542 function TRAIT_register_post_content_style_controls($section = true)
543 {
544 if ($section) {
545 $this->start_controls_section(
546 'section_style_content',
547 [
548 'label' => __('Content Style', 'uicore-elements'),
549 'tab' => Controls_Manager::TAB_STYLE,
550 ]
551 );
552 }
553 $this->add_responsive_control(
554 'image_size',
555 [
556 'label' => __('Image Height (%)', 'uicore-elements'),
557 'type' => Controls_Manager::NUMBER,
558 'min' => 1,
559 'max' => 500,
560 'step' => 1,
561 'default' => 57,
562 'selectors' => [
563 '{{WRAPPER}} .ui-e-post-top' => '--ui-e-img-size: {{VALUE}}',
564 ],
565 'condition' => [
566 'masonry!' => 'ui-e-maso',
567 ],
568 ]
569 );
570 $this->add_responsive_control(
571 'image_position',
572 [
573 'label' => __('Image Position', 'uicore-elements'),
574 'type' => Controls_Manager::SELECT,
575 'default' => 'center center',
576 'tablet_default' => '',
577 'mobile_default' => '',
578 'options' => [
579 '' => esc_html__('Default', 'uicore-elements'),
580 'left top' => esc_html__('Left Top', 'uicore-elements'),
581 'left center' => esc_html__('Left Center', 'uicore-elements'),
582 'left bottom' => esc_html__('Left Bottom', 'uicore-elements'),
583 'center top' => esc_html__('Center Top', 'uicore-elements'),
584 'center center' => esc_html__('Center Center', 'uicore-elements'),
585 'center bottom' => esc_html__('Center Bottom', 'uicore-elements'),
586 'right top' => esc_html__('Right Top', 'uicore-elements'),
587 'right center' => esc_html__('Right Center', 'uicore-elements'),
588 'right bottom' => esc_html__('Right Bottom', 'uicore-elements'),
589 ],
590 'selectors' => [
591 '{{WRAPPER}} .ui-e-post-img' => 'background-position: {{VALUE}}',
592 ],
593 ]
594 );
595 $this->add_responsive_control(
596 'image_fit',
597 [
598 'label' => __('Image Fit', 'uicore-elements'),
599 'type' => Controls_Manager::SELECT,
600 'default' => 'cover',
601 'tablet_default' => '',
602 'mobile_default' => '',
603 'options' => [
604 '' => esc_html__('Default', 'uicore-elements'),
605 'cover' => esc_html__('Cover', 'uicore-elements'),
606 'contain' => esc_html__('Contain', 'uicore-elements'),
607 'auto' => esc_html__('Auto', 'uicore-elements'),
608 ],
609 'selectors' => [
610 '{{WRAPPER}} .ui-e-post-img' => 'background-size: {{VALUE}}',
611 ],
612 ]
613 );
614 $this->add_control(
615 'image_radius',
616 [
617 'label' => esc_html__('Border Radius', 'uicore-elements'),
618 'type' => Controls_Manager::DIMENSIONS,
619 'size_units' => ['px', 'em', '%'],
620 'selectors' => [
621 '{{WRAPPER}} .ui-e-post-top' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}px {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
622 ],
623 'condition' => array(
624 'box_style!' => 'overlay',
625 ),
626 ]
627 );
628 $this->add_group_control(
629 Group_Control_Box_Shadow::get_type(),
630 [
631 'name' => 'image_shadow',
632 'label' => esc_html__('Box Shadow', 'uicore-elements'),
633 'selector' => '{{WRAPPER}} .ui-e-post-top',
634 'condition' => array(
635 'box_style!' => 'overlay',
636 ),
637 ]
638 );
639 $this->add_responsive_control(
640 'content_alignment',
641 [
642 'label' => esc_html__('Content Alignment', 'uicore-elements'),
643 'type' => Controls_Manager::CHOOSE,
644 'options' => [
645 'start' => [
646 'title' => esc_html__('Left', 'uicore-elements'),
647 'icon' => 'eicon-text-align-left',
648 ],
649 'center' => [
650 'title' => esc_html__('Center', 'uicore-elements'),
651 'icon' => 'eicon-text-align-center',
652 ],
653 'end' => [
654 'title' => esc_html__('Right', 'uicore-elements'),
655 'icon' => 'eicon-text-align-right',
656 ],
657 'stretch' => [
658 'title' => esc_html__('Justified', 'uicore-elements'),
659 'icon' => 'eicon-text-align-justify',
660 ],
661 ],
662 'selectors_dictionary' => [
663 'left' => 'start',
664 ],
665 'default' => is_rtl() ? 'end' : 'start',
666 'selectors' => [
667 '{{WRAPPER}} .ui-e-post-content' => 'align-items: {{VALUE}}; text-align: {{VALUE}};',
668 ],
669 ]
670 );
671 $this->add_control(
672 'title_color',
673 [
674 'label' => esc_html__('Title Color', 'uicore-elements'),
675 'type' => Controls_Manager::COLOR,
676 'default' => '',
677 'separator' => 'before',
678 'selectors' => [
679 '{{WRAPPER}} .ui-e-post-title' => 'color: {{VALUE}};',
680 ],
681 ]
682 );
683 $this->add_control(
684 'title_hcolor',
685 [
686 'label' => esc_html__('Title Hover Color', 'uicore-elements'),
687 'type' => Controls_Manager::COLOR,
688 'default' => '',
689 'selectors' => [
690 '{{WRAPPER}} .ui-e-post-title:hover' => 'color: {{VALUE}};',
691 ],
692 ]
693 );
694 $this->add_group_control(
695 Group_Control_Typography::get_type(),
696 [
697 'name' => 'title_typography',
698 'label' => esc_html__('Title Typography', 'uicore-elements'),
699 'selector' => '{{WRAPPER}} .ui-e-post-title',
700 ]
701 );
702 $this->add_responsive_control(
703 'title_gap',
704 [
705 'label' => __('Title Top Space', 'uicore-elements'),
706 'type' => Controls_Manager::SLIDER,
707 'size_units' => ['em'],
708 'separator' => 'after',
709 'range' => [
710 'px' => [
711 'min' => 0,
712 'max' => 3,
713 'step' => 0.1,
714 ],
715 ],
716 'default' => [
717 'unit' => 'em',
718 'size' => 1.2,
719 ],
720 'selectors' => [
721 '{{WRAPPER}} .ui-e-post-title' => 'margin-top: {{SIZE}}em;',
722 ],
723 ]
724 );
725 $this->add_control(
726 'text_color',
727 [
728 'label' => esc_html__('Excerpt Color', 'uicore-elements'),
729 'type' => Controls_Manager::COLOR,
730 'default' => '',
731 'selectors' => [
732 '{{WRAPPER}} .ui-e-post-text' => 'color: {{VALUE}};',
733 ],
734 ]
735 );
736 $this->add_group_control(
737 Group_Control_Typography::get_type(),
738 [
739 'name' => 'text_typography',
740 'label' => esc_html__('Excerpt Typography', 'uicore-elements'),
741 'selector' => '{{WRAPPER}} .ui-e-post-text',
742 ]
743 );
744 $this->add_responsive_control(
745 'text_gap',
746 [
747 'label' => __('Excerpt Top Space', 'uicore-elements'),
748 'type' => Controls_Manager::SLIDER,
749 'size_units' => ['em'],
750 'separator' => 'after',
751 'range' => [
752 'px' => [
753 'min' => 0,
754 'max' => 3,
755 'step' => 0.1,
756 ],
757 ],
758 'default' => [
759 'unit' => 'em',
760 'size' => 0.8,
761 ],
762 'selectors' => [
763 '{{WRAPPER}} .ui-e-post-text' => 'margin-top: {{SIZE}}em;',
764 ],
765 ]
766 );
767 $this->add_group_control(
768 Group_Control_Background::get_type(),
769 [
770 'name' => 'content_background',
771 'selector' => '{{WRAPPER}} .ui-e-post-content',
772 ]
773 );
774 $this->add_group_control(
775 Group_Control_Background::get_type(),
776 [
777 'name' => 'content_background_hover',
778 'selector' => '{{WRAPPER}} .ui-e-item:hover .ui-e-post-content',
779 'fields_options' => [
780 'background' => [
781 'label' => esc_html__('Hover Background', 'uicore-elements'),
782 ],
783 ],
784 'condition' => [
785 'box_style' => 'overlay',
786 ]
787 ]
788 );
789 $this->add_responsive_control(
790 'content_padding',
791 [
792 'label' => esc_html__('Content Padding', 'uicore-elements'),
793 'type' => Controls_Manager::DIMENSIONS,
794 'size_units' => ['px', 'em', '%'],
795 'selectors' => [
796 '{{WRAPPER}} .ui-e-post-content' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
797 ]
798 ]
799 );
800 $this->add_control(
801 'content_radius',
802 [
803 'label' => esc_html__('Content Border Radius', 'uicore-elements'),
804 'type' => Controls_Manager::DIMENSIONS,
805 'selectors' => [
806 '{{WRAPPER}} .ui-e-post-content' => 'border-radius: {{TOP}}px {{RIGHT}}px {{BOTTOM}}px {{LEFT}}px;'
807 ],
808 'condition' => array(
809 'box_style!' => 'overlay',
810 ),
811 ]
812 );
813 $this->add_control(
814 'content_gap',
815 [
816 'label' => __('Content Space', 'uicore-elements'),
817 'type' => Controls_Manager::SLIDER,
818 'size_units' => ['em'],
819 'separator' => 'after',
820 'range' => [
821 'px' => [
822 'min' => 0,
823 'max' => 3,
824 'step' => 0.1,
825 ],
826 ],
827 'default' => [
828 'unit' => 'em',
829 'size' => 0,
830 ],
831 'selectors' => [
832 '{{WRAPPER}} ' => '--ui-e-content-space: {{SIZE}}em;',
833 ],
834 'condition' => array(
835 'box_style!' => 'overlay',
836 ),
837 ]
838 );
839
840 if ($section) {
841 $this->end_controls_section();
842 }
843 }
844 function TRAIT_register_post_button_style_controls($section = true)
845 {
846 if ($section) {
847 $this->start_controls_section(
848 'section_button_style',
849 [
850 'label' => esc_html__('Button Style', 'uicore-elements'),
851 'tab' => Controls_Manager::TAB_STYLE,
852 'condition' => array(
853 'show_button' => 'yes',
854 ),
855 ]
856 );
857 }
858 $this->add_responsive_control(
859 'button_align',
860 [
861 'label' => esc_html__('Alignment', 'uicore-elements'),
862 'type' => Controls_Manager::CHOOSE,
863 'options' => [
864 'start' => [
865 'title' => esc_html__('Left', 'uicore-elements'),
866 'icon' => 'eicon-text-align-left',
867 ],
868 'center' => [
869 'title' => esc_html__('Center', 'uicore-elements'),
870 'icon' => 'eicon-text-align-center',
871 ],
872 'end' => [
873 'title' => esc_html__('Right', 'uicore-elements'),
874 'icon' => 'eicon-text-align-right',
875 ],
876 'normal' => [
877 'title' => esc_html__('Justified', 'uicore-elements'),
878 'icon' => 'eicon-text-align-justify',
879 ],
880 ],
881 'default' => 'start',
882 'selectors' => [
883 '{{WRAPPER}} .ui-e-readmore' => 'align-self: {{VALUE}};',
884 ],
885
886 ]
887 );
888 $this->register_button_style_controls(
889 [
890 'section_condition' => [
891 'show_button' => 'yes'
892 ]
893 ]
894 );
895 // Remove button alignment from Elementor button traits because (seens to be a bug), updating Selector CSS with update_control(), don't work as expected with responsiveness
896 $this->remove_responsive_control('align');
897
898 $this->TRAIT_register_post_specific_controls('button_gap');
899
900 if ($section) {
901 $this->end_controls_section();
902 }
903 }
904 function TRAIT_register_post_meta_style_controls($section = true)
905 {
906 if ($section) {
907 $this->start_controls_section(
908 'section_style_extra_content',
909 [
910 'label' => __('Meta Style', 'uicore-elements'),
911 'tab' => Controls_Manager::TAB_STYLE,
912 ]
913 );
914 }
915 $this->start_controls_tabs('style_extra_tabs');
916 $this->start_controls_tab(
917 'style_top_tab',
918 [
919 'label' => esc_html__('Top', 'uicore-elements'),
920 ]
921 );
922 $this->get_meta_style_controls('top');
923 $this->end_controls_tab();
924
925 $this->start_controls_tab(
926 'style_before_title_tab',
927 [
928 'label' => esc_html__('Before Title', 'uicore-elements'),
929 ]
930 );
931 $this->get_meta_style_controls('before_title');
932 $this->end_controls_tab();
933
934 $this->start_controls_tab(
935 'style_after_title_tab',
936 [
937 'label' => esc_html__('After Title', 'uicore-elements'),
938 ]
939 );
940 $this->get_meta_style_controls('after_title');
941 $this->end_controls_tab();
942
943 $this->start_controls_tab(
944 'style_bottom_tab',
945 [
946 'label' => esc_html__('Bottom', 'uicore-elements'),
947 ]
948 );
949 $this->get_meta_style_controls('bottom');
950 $this->end_controls_tab();
951 $this->end_controls_tabs();
952
953 if ($section) {
954 $this->end_controls_section();
955 }
956 }
957 function TRAIT_register_post_animation_controls()
958 {
959 $this->add_control(
960 'anim_image',
961 [
962 'label' => __('Image Hover Animation', 'uicore-elements'),
963 'type' => Controls_Manager::SELECT,
964 'label_block' => true,
965 'default' => 'ui-e-img-anim-zoom',
966 'options' => [
967 '' => __('None', 'uicore-elements'),
968 'ui-e-img-anim-zoom' => __('Zoom', 'uicore-elements'),
969 ],
970 'prefix_class' => '',
971 ]
972 );
973 $this->add_control(
974 'anim_meta',
975 [
976 'label' => __('Meta Hover Animation', 'uicore-elements'),
977 'type' => Controls_Manager::SELECT,
978 'label_block' => true,
979 'default' => '',
980 'options' => [
981 '' => __('None', 'uicore-elements'),
982 'ui-e-meta-anim-show' => __('Show', 'uicore-elements'),
983 ],
984 'prefix_class' => '',
985 ]
986 );
987 $this->add_control(
988 'important_note',
989 [
990 'label' => esc_html__('Important Note', 'uicore-elements'),
991 'type' => \Elementor\Controls_Manager::RAW_HTML,
992 'raw' => '<div class="elementor-control-field-description" style="margin-top: -7px;">' . esc_html__('This works only for Below Title Meta.', 'uicore-elements') . '</div>',
993 'show_label' => false,
994 'condition' => array(
995 'box_style' => 'overlay',
996 ),
997 ]
998 );
999 $this->add_control(
1000 'anim_title',
1001 [
1002 'label' => __('Title Hover Animation', 'uicore-elements'),
1003 'type' => Controls_Manager::SELECT,
1004 'label_block' => true,
1005 'default' => '',
1006 'options' => [
1007 '' => __('None', 'uicore-elements'),
1008 'ui-e-title-anim-underline' => __('Underline', 'uicore-elements'),
1009 'ui-e-title-anim-show' => __('Show', 'uicore-elements'),
1010 ],
1011 'prefix_class' => '',
1012 ]
1013 );
1014 $this->add_control(
1015 'anim_content',
1016 [
1017 'label' => __('Content Hover Animation', 'uicore-elements'),
1018 'type' => Controls_Manager::SELECT,
1019 'label_block' => true,
1020 'default' => '',
1021 'options' => [
1022 '' => __('None', 'uicore-elements'),
1023 'ui-e-content-anim-show' => __('Show', 'uicore-elements'),
1024 ],
1025 'prefix_class' => '',
1026 'condition' => array(
1027 'box_style' => 'overlay',
1028 ),
1029 ]
1030 );
1031 $this->add_control(
1032 'anim_btn',
1033 [
1034 'label' => __('Button Hover Animation', 'uicore-elements'),
1035 'type' => Controls_Manager::SELECT,
1036 'label_block' => true,
1037 'default' => '',
1038 'options' => [
1039 '' => __('None', 'uicore-elements'),
1040 'ui-e-btn-anim-show' => __('Show', 'uicore-elements'),
1041 ],
1042 'prefix_class' => '',
1043 'condition' => [
1044 'show_button' => 'yes',
1045 ],
1046 ]
1047 );
1048 }
1049 /**
1050 * Registers specific controls that can't be registered in blocks because of diferent use by different widgets or some other reason.
1051 * TODO: update to the use injection control, a better approach.
1052 *
1053 * @param string $control The control to register.
1054 * @return void
1055 */
1056 function TRAIT_register_post_specific_controls($control)
1057 {
1058 switch ($control) {
1059 case 'button_gap':
1060 $this->add_control(
1061 'button_gap',
1062 [
1063 'label' => __('Button Top Space', 'uicore-elements'),
1064 'type' => Controls_Manager::SLIDER,
1065 'size_units' => ['em'],
1066 'range' => [
1067 'px' => [
1068 'min' => 0,
1069 'max' => 3,
1070 'step' => 0.1,
1071 ],
1072 ],
1073 'default' => [
1074 'unit' => 'em',
1075 'size' => 0.8,
1076 ],
1077 'selectors' => [
1078 '{{WRAPPER}} .elementor-button' => 'margin-top: {{SIZE}}em;',
1079 ],
1080 ]
1081 );
1082 break;
1083 }
1084 }
1085
1086 /**
1087 * Returns the proper query args for a given post type.
1088 *
1089 * @param array $settings Elementor controls settings.
1090 * @param object $default_query The default query object. Used to tell if is a frontend or rest api request.
1091 *
1092 * @return void Don't return anything, but sets the query object to $_query variable that can be accessed by the widget.
1093 */
1094 function TRAIT_query_posts($settings, $default_query)
1095 {
1096 $post_type = $settings['posts-filter_post_type'];
1097
1098 if ($post_type === 'related') {
1099 $current_post_id = $settings['__current_post_id'] ?? [];
1100 $this->_query = Helper::get_related_ajax(
1101 Query::get_queried_page($settings),
1102 $settings['item_limit']['size'],
1103 $current_post_id
1104 );
1105 } else {
1106 $query_args = Query::get_query_args('posts-filter', $settings);
1107
1108 if ($post_type === 'current') {
1109
1110 // Makes sure widget will render some posts at editor screen
1111 if ($this->is_edit_mode()) {
1112 $query_args['post_type'] = 'post';
1113 } else {
1114 $query_args = $default_query;
1115
1116 /// TODO: very likely commit `38c618c` on Elements repo make this fallback useless. Test it
1117 // Post type fallback for APG
1118 if (isset($default_query['post_type']) || isset($default_query['query']['post_type'])) {
1119 $post_type = $default_query['post_type'] ?? $default_query['query']['post_type'];
1120 } else {
1121 $post_type = 'post';
1122 }
1123
1124 // Set pagination
1125 $query_args['paged'] = Query::get_queried_page($settings);
1126
1127
1128 // current bug: clicking `all` on `portfolio` archive post type brings `post` type posts
1129
1130 // Set tax filters for filter component, if enabled
1131 $queried_filters = Query::get_queried_filters($settings, $post_type, 'posts-filter');
1132 $query_args['tax_query'] = empty($queried_filters['tax_query'])
1133 ? []
1134 : $queried_filters['tax_query'];
1135 }
1136
1137 // Set products per page
1138 $query_args['posts_per_page'] = Helper::get_framework_visible_posts($post_type);
1139 }
1140
1141 if ($post_type === 'portfolio') {
1142 $query_args['orderby'] = 'menu_order date';
1143 }
1144
1145 $this->_query = new \WP_Query($query_args);
1146 }
1147 }
1148
1149 // Render functions
1150 function get_post_image()
1151 {
1152 if ($this->is_option('image', 'yes', '!==')) {
1153 return;
1154 }
1155
1156 $pic_id = get_post_thumbnail_id();
1157 if (!$pic_id)
1158 return;
1159 $size = $this->get_settings_for_display('image_size_select') ?? 'uicore-medium';
1160 ?>
1161 <a class="ui-e-post-img-wrapp"
1162 href="<?php echo esc_url(get_permalink()); ?>"
1163 title="<?php echo esc_attr__('View Post:', 'uicore-elements') . the_title_attribute(['echo' => false]); ?>">
1164
1165 <?php if ($this->get_settings_for_display('masonry') === 'ui-e-maso') { ?>
1166 <?php the_post_thumbnail($size, ['class' => 'ui-e-post-img']); ?>
1167 <?php } else { ?>
1168 <div class="ui-e-post-img" style="background-image:url(<?php echo esc_url(wp_get_attachment_image_url($pic_id, $size)); ?>)"></div>
1169 <?php } ?>
1170 </a>
1171 <?php
1172
1173 }
1174 function get_post_title(string $tag)
1175 {
1176 if ($this->is_option('title', 'yes', '!==')) {
1177 return;
1178 }
1179 ?>
1180 <a href="<?php echo esc_url(get_permalink()); ?>" title="<?php echo esc_attr__('View Post:', 'uicore-elements') . esc_html(the_title_attribute(['echo' => false])); ?>">
1181 <<?php echo Helper::esc_tag($tag); ?> class="ui-e-post-title">
1182 <span> <?php echo esc_html(get_the_title()); ?> </span>
1183 </<?php echo Helper::esc_tag($tag); ?>>
1184 </a>
1185 <?php
1186 }
1187 function get_post_meta($position, $product_id = null)
1188 {
1189 $meta_list = $this->get_settings_for_display($position . '_meta');
1190 if (!isset($meta_list[0]) || $meta_list[0]['type'] == '') {
1191 return;
1192 }
1193 echo ($position == 'top') ? '<div class="ui-e-post-top-meta">' : '';
1194 echo ($position == 'after_title') ? '<div class="ui-e-meta-wrapp">' : '';
1195 echo '<div class="ui-e-post-meta ui-e-' . esc_attr($position) . '">';
1196 foreach ($meta_list as $meta) {
1197 if ($meta['type'] != 'none') {
1198 $this->display_meta($meta, $product_id);
1199
1200 if (next($meta_list) && $this->get_settings_for_display($position . '_meta_separator')) {
1201 echo '<span class="ui-e-separator">' . esc_html($this->get_settings_for_display($position . '_meta_separator')) . '</span>';
1202 }
1203 }
1204 }
1205 echo '</div>';
1206 echo ($position == 'top' || $position == 'after_title') ? '</div>' : '';
1207 }
1208 /**
1209 * Render the post read more button.
1210 *
1211 * @param int $index The loop index.
1212 *
1213 * @return void
1214 */
1215 function TRAIT_get_button($index)
1216 {
1217 $settings = $this->get_settings_for_display();
1218
1219 // Render att slugs
1220 $button_slug = 'button_' . $index;
1221 $content_slug = 'content-wrapper_' . $index;
1222 $icon_slug = 'icon-align_' . $index;
1223 $text_slug = 'text_' . $index;
1224
1225 $this->add_render_attribute($button_slug, [
1226 'class' => ['elementor-button-link', 'elementor-button', 'ui-e-readmore'],
1227 'role' => 'button',
1228 ]);
1229
1230 $this->add_render_attribute($content_slug, 'class', 'elementor-button-content-wrapper');
1231
1232 if (!empty($settings['button_css_id'])) {
1233 $this->add_render_attribute($button_slug, 'id', $settings['button_css_id']);
1234 }
1235
1236 if (!empty($settings['size'])) {
1237 $this->add_render_attribute($button_slug, 'class', 'elementor-size-' . $settings['size']);
1238 }
1239
1240 if (!empty($settings['hover_animation'])) {
1241 $this->add_render_attribute($button_slug, 'class', 'elementor-animation-' . $settings['hover_animation']);
1242 }
1243
1244 $btn_classes = isset($settings['icon_align'])
1245 ? ['elementor-button-icon', 'elementor-align-icon-' . $settings['icon_align']]
1246 : 'elementor-button-icon';
1247
1248 $this->add_render_attribute([
1249 $icon_slug => [
1250 'class' => $btn_classes
1251 ],
1252 $text_slug => [
1253 'class' => 'elementor-button-text',
1254 ],
1255 ]);
1256
1257 if (isset($settings['icon_align'])) {
1258 $this->add_render_attribute($content_slug, 'class', 'elementor-button-content');
1259 }
1260
1261 $tbn_content = '<span ' . $this->get_render_attribute_string($content_slug) . '>';
1262
1263 if (!empty($settings['icon']) || !empty($settings['selected_icon']['value'])) {
1264 $tbn_content .= '<span ' . $this->get_render_attribute_string($icon_slug) . '>';
1265 \ob_start();
1266 Icons_Manager::render_icon($settings['selected_icon'], ['aria-hidden' => 'true']);
1267 $tbn_content .= \ob_get_clean();
1268 $tbn_content .= '</span>';
1269 }
1270
1271 $tbn_content .= '<span ' . $this->get_render_attribute_string($text_slug) . '>';
1272 $tbn_content .= $settings['text'];
1273 $tbn_content .= '</span> </span>';
1274
1275 ?>
1276 <a href="<?php echo esc_url(get_permalink()); ?>" <?php $this->print_render_attribute_string($button_slug); ?>>
1277 <?php
1278 //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1279 echo Helper::esc_svg($tbn_content);
1280 ?>
1281 </a>
1282 <?php
1283 }
1284
1285 /**
1286 * Renders a post item with various settings and options.
1287 * Important: any changes here should also be considered to `TRAIT_render_product()` from Product Component.
1288 *
1289 * @param int $index The loop index.
1290 * @param bool $carousel Indicates if the item needs carousel classnames.
1291 * @param bool $legacy Indicates if the item is using legacy classnames.
1292 *
1293 * @return void
1294 */
1295 function TRAIT_render_item($index, $carousel = false, $legacy = false)
1296 {
1297 $settings = $this->get_settings_for_display();
1298 $excerpt_length = $settings['excerpt_trim'];
1299
1300 // Classnames but checking if we the widget is APG (legacy version)
1301 $item_classes = $legacy ? ['ui-e-post-item', 'ui-e-item'] : ['ui-e-item']; // Single item lower wrap class receptor
1302 $hover_item_class = $legacy ? 'anim_item' : 'item_hover_animation'; // item hover animation class
1303
1304 // If widget is not carousel type, we set animations classes directly on item selector
1305 if (!$carousel) {
1306 $item_classes[] = 'ui-e-animations-wrp';
1307 $item_classes[] = $settings['animate_items'] === 'ui-e-grid-animate' ? 'elementor-invisible' : '';
1308 $item_classes[] = $settings[$hover_item_class] !== '' ? $settings[$hover_item_class] : '';
1309 } else {
1310 // Get entrance and item hover animation classes
1311 $entrance = $this->is_option('animate_items', 'ui-e-grid-animate') ? 'elementor-invisible' : '';
1312 $hover = isset($settings[$hover_item_class]) ? $settings[$hover_item_class] : '';
1313 $animations = sprintf('%s %s', $entrance, $hover);
1314
1315 // Check if entrance or hover animation are set
1316 $has_animation = !empty($entrance) || !empty($hover)
1317
1318 // Prints extra wrappers required by the carousel script
1319 ?>
1320 <div class="ui-e-wrp swiper-slide">
1321 <?php if ($has_animation) : ?>
1322 <div class="ui-e-animations-wrp <?php echo esc_attr($animations); ?>">
1323 <?php endif; ?>
1324
1325 <?php } ?>
1326
1327 <div class="<?php echo esc_attr(implode(' ', $item_classes)); ?>">
1328 <article <?php post_class(); ?>>
1329 <div class="ui-e-post-top">
1330 <?php $this->get_post_image(); ?>
1331 <?php $this->get_post_meta('top'); ?>
1332 </div>
1333
1334 <?php if ($this->is_option('global_link', 'yes')) : ?>
1335 <a href="<?php echo esc_url(get_permalink()); ?>"
1336 class="ui-e-global-link"
1337 aria-label="<?php echo esc_attr__('View Post:', 'uicore-elements') . esc_html(the_title_attribute(['echo' => false])); ?>"
1338 title="<?php echo esc_attr__('View Post:', 'uicore-elements') . esc_html(the_title_attribute(['echo' => false])); ?>"> </a>
1339 <?php endif; ?>
1340
1341 <div class="ui-e-post-content">
1342
1343 <?php $this->get_post_meta('before_title'); ?>
1344 <?php
1345 if ($this->is_option('title', 'yes'))
1346 $this->get_post_title($settings['title_tag']);
1347 ?>
1348 <?php $this->get_post_meta('after_title'); ?>
1349 <?php
1350 if ($this->get_settings_for_display('excerpt'))
1351 echo wp_kses_post('<div class="ui-e-post-text">' . wp_trim_words(get_the_excerpt(), $excerpt_length) . '</div>');
1352 ?>
1353 <?php $this->get_post_meta('bottom'); // button
1354 ?>
1355 <?php
1356 if ($this->is_option('show_button', 'yes')) {
1357 // Add match height spacing element if carousel. May look intrusive, but is the simplest method compared
1358 // to absolute positioning or catching last content element to apply margin.
1359 if ($carousel && $this->is_option('match_height', 'yes')) {
1360 ?>
1361 <span class="ui-e-match-height"></span>
1362 <?php
1363 }
1364
1365 if (!isset($settings['button_position']) || empty($settings['button_position'])) {
1366 $this->TRAIT_get_button($index);
1367 }
1368 }
1369 ?>
1370 </div>
1371 </article>
1372 </div>
1373
1374 <?php if ($carousel) { ?>
1375 </div>
1376 <?php if ($has_animation) : ?>
1377 </div>
1378 <?php endif; ?>
1379
1380 <?php }
1381 }
1382 }
1383