PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.49
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.49
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.49, at includes/widgets/TB_Related_Posts/TB_Related_Posts.php

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