PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.65
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.65
51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 51.1.45 51.1.46 51.1.47 51.1.49 All 37 releases
king-addons / includes / widgets / TB_Related_Posts / TB_Related_Posts.php

TB_Related_Posts.php in King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder 51.1.65, at includes/widgets/TB_Related_Posts/TB_Related_Posts.php

547 lines 16.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Theme Builder Related Posts widget (Free).
4 *
5 * @package King_Addons
6 */
7
8 namespace King_Addons;
9
10 use Elementor\Controls_Manager;
11 use Elementor\Group_Control_Typography;
12 use Elementor\Widget_Base;
13 use WP_Query;
14
15 if (!defined('ABSPATH')) {
16 exit;
17 }
18
19 /**
20 * Displays related posts grid.
21 */
22 class TB_Related_Posts extends Widget_Base
23 {
24 /**
25 * Widget slug.
26 *
27 * @return string
28 */
29 public function get_name(): string
30 {
31 return 'king-addons-tb-related-posts';
32 }
33
34 /**
35 * Widget title.
36 *
37 * @return string
38 */
39 public function get_title(): string
40 {
41 return esc_html__('TB - Related Posts', 'king-addons');
42 }
43
44 /**
45 * Widget icon.
46 *
47 * @return string
48 */
49 public function get_icon(): string
50 {
51 return 'eicon-posts-grid';
52 }
53
54 /**
55 * Style dependencies.
56 *
57 * @return array<int, string>
58 */
59 public function get_style_depends(): array
60 {
61 return [KING_ADDONS_ASSETS_UNIQUE_KEY . '-tb-related-posts-style'];
62 }
63
64 /**
65 * Script dependencies.
66 *
67 * @return array<int, string>
68 */
69 public function get_script_depends(): array
70 {
71 return [KING_ADDONS_ASSETS_UNIQUE_KEY . '-tb-related-posts-script'];
72 }
73
74 /**
75 * Categories.
76 *
77 * @return array<int, string>
78 */
79 public function get_categories(): array
80 {
81 return ['king-addons'];
82 }
83
84 /**
85 * Keywords.
86 *
87 * @return array<int, string>
88 */
89 public function get_keywords(): array
90 {
91 return ['related', 'posts', 'grid', 'theme builder', 'king-addons'];
92 }
93
94 public function get_custom_help_url()
95 {
96 return 'mailto:bug@kingaddons.com?subject=Bug Report - King Addons&body=Please describe the issue';
97 }
98
99 /**
100 * Register controls.
101 *
102 * @return void
103 */
104 public function register_controls(): void
105 {
106 $this->register_content_controls(false);
107 $this->register_style_controls(false);
108 $this->register_pro_notice_controls();
109 }
110
111 /**
112 * Render output.
113 *
114 * @return void
115 */
116 public function render(): void
117 {
118 $settings = $this->get_settings_for_display();
119 $this->render_output($settings, false);
120 }
121
122 /**
123 * Content controls.
124 *
125 * @param bool $is_pro Whether Pro controls are enabled.
126 *
127 * @return void
128 */
129 protected function register_content_controls(bool $is_pro): void
130 {
131 $this->start_controls_section(
132 'kng_content_section',
133 [
134 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Query', 'king-addons'),
135 'tab' => Controls_Manager::TAB_CONTENT,
136 ]
137 );
138
139 $this->add_control(
140 'kng_source',
141 [
142 'label' => esc_html__('Source', 'king-addons'),
143 'type' => Controls_Manager::SELECT,
144 'default' => 'categories',
145 'options' => [
146 'categories' => esc_html__('Same Categories', 'king-addons'),
147 'tags' => $is_pro ? esc_html__('Same Tags', 'king-addons') : sprintf(__('Same Tags %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
148 'taxonomy' => $is_pro ? esc_html__('Same Taxonomy', 'king-addons') : sprintf(__('Same Taxonomy %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
149 ],
150 ]
151 );
152
153 $this->add_control(
154 'kng_taxonomy_slug',
155 [
156 'label' => esc_html__('Taxonomy Slug', 'king-addons'),
157 'type' => Controls_Manager::TEXT,
158 'placeholder' => esc_html__('portfolio_cat', 'king-addons'),
159 'condition' => [
160 'kng_source' => 'taxonomy',
161 ],
162 'classes' => $is_pro ? '' : 'king-addons-pro-control',
163 ]
164 );
165
166 $this->add_control(
167 'kng_posts_per_page',
168 [
169 'label' => esc_html__('Posts Per Page', 'king-addons'),
170 'type' => Controls_Manager::NUMBER,
171 'min' => 1,
172 'max' => 12,
173 'default' => 3,
174 ]
175 );
176
177 $this->add_control(
178 'kng_order',
179 [
180 'label' => esc_html__('Order', 'king-addons'),
181 'type' => Controls_Manager::SELECT,
182 'default' => 'date',
183 'options' => [
184 'date' => esc_html__('Date', 'king-addons'),
185 'rand' => esc_html__('Random', 'king-addons'),
186 'comment_count' => $is_pro ? esc_html__('Comment Count', 'king-addons') : sprintf(__('Comment Count %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
187 ],
188 ]
189 );
190
191 $this->add_control(
192 'kng_exclude_current',
193 [
194 'label' => esc_html__('Exclude Current Post', 'king-addons'),
195 'type' => Controls_Manager::SWITCHER,
196 'return_value' => 'yes',
197 'default' => 'yes',
198 ]
199 );
200
201 $this->add_control(
202 'kng_fallback',
203 [
204 'label' => $is_pro ?
205 esc_html__('Fallback', 'king-addons') :
206 sprintf(__('Fallback %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
207 'type' => Controls_Manager::SELECT,
208 'default' => 'hide',
209 'options' => [
210 'hide' => esc_html__('Hide Widget', 'king-addons'),
211 'latest' => esc_html__('Show Latest Posts', 'king-addons'),
212 ],
213 'classes' => $is_pro ? '' : 'king-addons-pro-control',
214 ]
215 );
216
217 $this->end_controls_section();
218
219 $this->start_controls_section(
220 'kng_layout_section',
221 [
222 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Layout', 'king-addons'),
223 'tab' => Controls_Manager::TAB_CONTENT,
224 ]
225 );
226
227 $this->add_responsive_control(
228 'kng_columns',
229 [
230 'label' => esc_html__('Columns', 'king-addons'),
231 'type' => Controls_Manager::SLIDER,
232 'size_units' => ['px'],
233 'range' => [
234 'px' => ['min' => 1, 'max' => 4, 'step' => 1],
235 ],
236 'default' => [
237 'size' => 3,
238 'unit' => 'px',
239 ],
240 ]
241 );
242
243 $this->add_control(
244 'kng_show_image',
245 [
246 'label' => esc_html__('Show Featured Image', 'king-addons'),
247 'type' => Controls_Manager::SWITCHER,
248 'return_value' => 'yes',
249 'default' => 'yes',
250 ]
251 );
252
253 $this->add_control(
254 'kng_show_title',
255 [
256 'label' => esc_html__('Show Title', 'king-addons'),
257 'type' => Controls_Manager::SWITCHER,
258 'return_value' => 'yes',
259 'default' => 'yes',
260 ]
261 );
262
263 $this->add_control(
264 'kng_show_meta',
265 [
266 'label' => esc_html__('Show Meta', 'king-addons'),
267 'type' => Controls_Manager::SWITCHER,
268 'return_value' => 'yes',
269 'default' => 'yes',
270 ]
271 );
272
273 $this->add_control(
274 'kng_show_excerpt',
275 [
276 'label' => esc_html__('Show Excerpt', 'king-addons'),
277 'type' => Controls_Manager::SWITCHER,
278 'return_value' => 'yes',
279 'default' => '',
280 ]
281 );
282
283 $this->add_control(
284 'kng_show_button',
285 [
286 'label' => esc_html__('Show Read More', 'king-addons'),
287 'type' => Controls_Manager::SWITCHER,
288 'return_value' => 'yes',
289 'default' => '',
290 ]
291 );
292
293 $this->end_controls_section();
294 }
295
296 /**
297 * Style controls.
298 *
299 * @param bool $is_pro Whether Pro controls are enabled.
300 *
301 * @return void
302 */
303 protected function register_style_controls(bool $is_pro): void
304 {
305 $this->start_controls_section(
306 'kng_style_section',
307 [
308 'label' => esc_html__('Style', 'king-addons'),
309 'tab' => Controls_Manager::TAB_STYLE,
310 ]
311 );
312
313 $this->add_group_control(
314 Group_Control_Typography::get_type(),
315 [
316 'name' => 'kng_title_typography',
317 'label' => esc_html__('Title Typography', 'king-addons'),
318 'selector' => '{{WRAPPER}} .king-addons-tb-related-posts__title',
319 ]
320 );
321
322 $this->add_group_control(
323 Group_Control_Typography::get_type(),
324 [
325 'name' => 'kng_meta_typography',
326 'label' => esc_html__('Meta Typography', 'king-addons'),
327 'selector' => '{{WRAPPER}} .king-addons-tb-related-posts__meta',
328 ]
329 );
330
331 $this->add_control(
332 'kng_title_color',
333 [
334 'label' => esc_html__('Title Color', 'king-addons'),
335 'type' => Controls_Manager::COLOR,
336 'selectors' => [
337 '{{WRAPPER}} .king-addons-tb-related-posts__title a' => 'color: {{VALUE}};',
338 ],
339 ]
340 );
341
342 $this->add_control(
343 'kng_meta_color',
344 [
345 'label' => esc_html__('Meta Color', 'king-addons'),
346 'type' => Controls_Manager::COLOR,
347 'selectors' => [
348 '{{WRAPPER}} .king-addons-tb-related-posts__meta' => 'color: {{VALUE}};',
349 ],
350 ]
351 );
352
353 $this->add_responsive_control(
354 'kng_gap',
355 [
356 'label' => esc_html__('Grid Gap', 'king-addons'),
357 'type' => Controls_Manager::SLIDER,
358 'size_units' => ['px'],
359 'range' => [
360 'px' => ['min' => 0, 'max' => 60],
361 ],
362 'default' => [
363 'size' => 16,
364 'unit' => 'px',
365 ],
366 'selectors' => [
367 '{{WRAPPER}} .king-addons-tb-related-posts__grid' => 'gap: {{SIZE}}{{UNIT}};',
368 ],
369 ]
370 );
371
372 $this->end_controls_section();
373 }
374
375 /**
376 * Pro upsell.
377 *
378 * @return void
379 */
380 protected function register_pro_notice_controls(): void
381 {
382 if (king_addons_freemius()->can_use_premium_code__premium_only()) {
383 return;
384 }
385
386 Core::renderProFeaturesSection(
387 $this,
388 '',
389 Controls_Manager::RAW_HTML,
390 'tb-related-posts',
391 [
392 'Tag or custom taxonomy sources',
393 'Comment count ordering and fallbacks',
394 'Advanced hover and overlay styles',
395 ]
396 );
397 }
398
399 /**
400 * Render output helper.
401 *
402 * @param array<string, mixed> $settings Settings.
403 * @param bool $is_pro Whether Pro is enabled.
404 *
405 * @return void
406 */
407 protected function render_output(array $settings, bool $is_pro): void
408 {
409 $post = get_post();
410 if (!$post instanceof \WP_Post) {
411 return;
412 }
413
414 $query = $this->build_query($post, $settings, $is_pro);
415 if (!$query->have_posts()) {
416 if ($is_pro && 'latest' === ($settings['kng_fallback'] ?? 'hide')) {
417 wp_reset_postdata();
418 $fallback_args = [
419 'post_type' => get_post_type($post),
420 'posts_per_page' => (int) ($settings['kng_posts_per_page'] ?? 3),
421 'post__not_in' => ('yes' === ($settings['kng_exclude_current'] ?? 'yes')) ? [$post->ID] : [],
422 ];
423 $query = new WP_Query($fallback_args);
424 }
425 }
426
427 if (!$query->have_posts()) {
428 wp_reset_postdata();
429 return;
430 }
431
432 $columns = isset($settings['kng_columns']['size']) ? max(1, (int) $settings['kng_columns']['size']) : 3;
433
434 echo '<div class="king-addons-tb-related-posts" style="--kng-related-columns:' . esc_attr((string) $columns) . '">';
435 echo '<div class="king-addons-tb-related-posts__grid">';
436 while ($query->have_posts()) {
437 $query->the_post();
438 $this->render_card($settings);
439 }
440 echo '</div></div>';
441
442 wp_reset_postdata();
443 }
444
445 /**
446 * Build query.
447 *
448 * @param \WP_Post $post Current post.
449 * @param array $settings Settings.
450 * @param bool $is_pro Pro flag.
451 *
452 * @return WP_Query
453 */
454 protected function build_query(\WP_Post $post, array $settings, bool $is_pro): WP_Query
455 {
456 $args = [
457 'post_type' => get_post_type($post),
458 'posts_per_page' => (int) ($settings['kng_posts_per_page'] ?? 3),
459 'ignore_sticky_posts' => true,
460 ];
461
462 if ('yes' === ($settings['kng_exclude_current'] ?? 'yes')) {
463 $args['post__not_in'] = [$post->ID];
464 }
465
466 $orderby = $settings['kng_order'] ?? 'date';
467 if ('comment_count' === $orderby && !$is_pro) {
468 $orderby = 'date';
469 }
470 $args['orderby'] = $orderby;
471
472 $source = $settings['kng_source'] ?? 'categories';
473 $tax_query = [];
474 if ('categories' === $source) {
475 $terms = wp_get_post_categories($post->ID);
476 if (!empty($terms)) {
477 $tax_query[] = [
478 'taxonomy' => 'category',
479 'field' => 'term_id',
480 'terms' => $terms,
481 ];
482 }
483 } elseif ('tags' === $source && $is_pro) {
484 $terms = wp_get_post_tags($post->ID, ['fields' => 'ids']);
485 if (!empty($terms)) {
486 $tax_query[] = [
487 'taxonomy' => 'post_tag',
488 'field' => 'term_id',
489 'terms' => $terms,
490 ];
491 }
492 } elseif ('taxonomy' === $source && $is_pro && !empty($settings['kng_taxonomy_slug'])) {
493 $slug = sanitize_key($settings['kng_taxonomy_slug']);
494 $terms = wp_get_object_terms($post->ID, $slug, ['fields' => 'ids']);
495 if (!empty($terms) && !is_wp_error($terms)) {
496 $tax_query[] = [
497 'taxonomy' => $slug,
498 'field' => 'term_id',
499 'terms' => $terms,
500 ];
501 }
502 }
503
504 if (!empty($tax_query)) {
505 $args['tax_query'] = $tax_query;
506 }
507
508 return new WP_Query($args);
509 }
510
511 /**
512 * Render card.
513 *
514 * @param array<string, mixed> $settings Settings.
515 *
516 * @return void
517 */
518 protected function render_card(array $settings): void
519 {
520 echo '<article class="king-addons-tb-related-posts__item">';
521
522 if ('yes' === ($settings['kng_show_image'] ?? 'yes') && has_post_thumbnail()) {
523 echo '<a class="king-addons-tb-related-posts__thumb" href="' . esc_url(get_permalink()) . '">';
524 the_post_thumbnail('medium');
525 echo '</a>';
526 }
527
528 if ('yes' === ($settings['kng_show_title'] ?? 'yes')) {
529 echo '<h3 class="king-addons-tb-related-posts__title"><a href="' . esc_url(get_permalink()) . '">' . esc_html(get_the_title()) . '</a></h3>';
530 }
531
532 if ('yes' === ($settings['kng_show_meta'] ?? 'yes')) {
533 echo '<div class="king-addons-tb-related-posts__meta">' . esc_html(get_the_date()) . ' · ' . esc_html(get_the_author()) . '</div>';
534 }
535
536 if ('yes' === ($settings['kng_show_excerpt'] ?? '')) {
537 echo '<div class="king-addons-tb-related-posts__excerpt">' . esc_html(wp_trim_words(get_the_excerpt(), 18, '')) . '</div>';
538 }
539
540 if ('yes' === ($settings['kng_show_button'] ?? '')) {
541 echo '<a class="king-addons-tb-related-posts__button" href="' . esc_url(get_permalink()) . '">' . esc_html__('Read more', 'king-addons') . '</a>';
542 }
543
544 echo '</article>';
545 }
546 }
547