PluginProbe
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder / 51.1.87
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder v51.1.87
51.1.87 51.1.86 51.1.84 51.1.85 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 All 41 releases
← All changes | includes/widgets/Dynamic_Posts_Grid/Dynamic_Posts_Grid.php +335 -29 51.1.14 → 51.1.87 View file →
@@ -22,9 +22,22 @@
22 22 * Features different post types, color coding, and responsive design.
23 23 */
24 24 class Dynamic_Posts_Grid extends Widget_Base
25 25 {
26 + /**
27 + * Allow Pro to fully override widget output without using parent::render().
28 + *
29 + * Pro can return true to indicate it rendered the widget output completely.
30 + *
31 + * @param array<string, mixed> $settings Widget settings for display.
32 + * @return bool Whether Pro rendered output.
33 + */
34 + public function maybe_render_pro(array $settings): bool
35 + {
36 + return false;
37 + }
26 38
39 +
27 40 /**
28 41 * Get widget name.
29 42 *
30 43 * @return string Widget name.
@@ -70,9 +83,12 @@
70 83 * @return array Script dependencies.
71 84 */
72 85 public function get_script_depends(): array
73 86 {
74 - return [KING_ADDONS_ASSETS_UNIQUE_KEY . '-dynamic-posts-grid-script'];
87 + return [
88 + KING_ADDONS_ASSETS_UNIQUE_KEY . '-dompurify-purify.min',
89 + KING_ADDONS_ASSETS_UNIQUE_KEY . '-dynamic-posts-grid-script'
90 + ];
75 91 }
76 92
77 93 /**
78 94 * Get widget categories.
@@ -165,9 +181,12 @@
165 181 </div>',
166 182 ]
167 183 );
168 184
169 - // Post Types
185 + // PRO: Widget Mode Control
186 + $this->add_control_widget_mode();
187 +
188 + // Post Types (shown only in Default mode)
170 189 $this->add_control(
171 190 'kng_dynamic_posts_post_types',
172 191 [
173 192 'label' => esc_html__('Post Types', 'king-addons'),
@@ -175,11 +194,17 @@
175 194 'multiple' => true,
176 195 'options' => $this->get_post_types(),
177 196 'default' => ['post'],
178 197 'description' => esc_html__('Select post types to display', 'king-addons'),
198 + 'condition' => [
199 + 'kng_dynamic_posts_widget_mode' => ['', 'default'],
200 + ],
179 201 ]
180 202 );
181 203
204 + // PRO: Custom Post Types Control
205 + $this->add_control_custom_post_types();
206 +
182 207 // Posts per page
183 208 $this->add_control(
184 209 'kng_dynamic_posts_per_page',
185 210 [
@@ -264,9 +289,9 @@
264 289 ],
265 290 ]
266 291 );
267 292
268 - // Filter taxonomy
293 + // Filter taxonomy (shown only in Default mode)
269 294 $this->add_control(
270 295 'kng_dynamic_posts_filter_taxonomy',
271 296 [
272 297 'label' => esc_html__('Filter Taxonomy', 'king-addons'),
@@ -274,8 +299,9 @@
274 299 'options' => $this->get_taxonomies(),
275 300 'default' => 'category',
276 301 'condition' => [
277 302 'kng_dynamic_posts_enable_filters' => 'yes',
303 + 'kng_dynamic_posts_widget_mode' => ['', 'default'],
278 304 ],
279 305 ]
280 306 );
281 307
@@ -445,10 +471,54 @@
445 471 ],
446 472 ]
447 473 );
448 474
475 + // PRO: Pagination Type Control
476 + $this->add_control_pagination_type();
477 +
478 + // PRO: Scroll Threshold Control
479 + $this->add_control_scroll_threshold();
480 +
449 481 $this->end_controls_section();
450 482
483 + // PRO: CPT Actions Section
484 + $this->start_controls_section(
485 + 'kng_dynamic_posts_cpt_actions_section',
486 + [
487 + 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('CPT Action Types', 'king-addons') . ' ' . esc_html__('(PRO)', 'king-addons'),
488 + 'tab' => Controls_Manager::TAB_CONTENT,
489 + 'condition' => [
490 + 'kng_dynamic_posts_widget_mode' => 'custom_cpt',
491 + ],
492 + ]
493 + );
494 +
495 + // PRO: CPT Actions Control
496 + $this->add_control_cpt_actions();
497 +
498 + $this->end_controls_section();
499 +
500 + // PRO: Meta Fields Section
501 + $this->start_controls_section(
502 + 'kng_dynamic_posts_meta_fields_section',
503 + [
504 + 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Meta Fields', 'king-addons') . ' ' . esc_html__('(PRO)', 'king-addons'),
505 + 'tab' => Controls_Manager::TAB_CONTENT,
506 + ]
507 + );
508 +
509 + // PRO: Show Meta Control
510 + $this->add_control_show_meta();
511 +
512 + // PRO: Meta Fields Control
513 + $this->add_control_meta_fields();
514 +
515 + // Both controls above are Pro-only, so without this the free build shows
516 + // a section header that expands onto an empty panel.
517 + Core::renderUpgradeProSection($this, Controls_Manager::RAW_HTML, 'dynamic-posts-grid', 'kng_dynamic_posts_meta_fields_pro_notice_');
518 +
519 + $this->end_controls_section();
520 +
451 521 // Category Colors Section
452 522 $this->start_controls_section(
453 523 'kng_dynamic_posts_category_colors_section',
454 524 [
@@ -453,8 +523,11 @@
453 523 'kng_dynamic_posts_category_colors_section',
454 524 [
455 525 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Category Colors', 'king-addons'),
456 526 'tab' => Controls_Manager::TAB_CONTENT,
527 + 'condition' => [
528 + 'kng_dynamic_posts_widget_mode' => ['', 'default']
529 + ]
457 530 ]
458 531 );
459 532
460 533 // Get categories dynamically
@@ -461,13 +534,33 @@
461 534 $this->add_dynamic_category_colors();
462 535
463 536 $this->end_controls_section();
464 537
538 + // CPT Colors Section (PRO)
465 539 $this->start_controls_section(
540 + 'kng_dynamic_posts_cpt_colors_section',
541 + [
542 + 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('CPT Colors', 'king-addons'),
543 + 'tab' => Controls_Manager::TAB_CONTENT,
544 + 'condition' => [
545 + 'kng_dynamic_posts_widget_mode' => 'custom_cpt'
546 + ]
547 + ]
548 + );
549 +
550 + // PRO: CPT Colors
551 + $this->add_control_cpt_colors();
552 +
553 + $this->end_controls_section();
554 +
555 + $this->start_controls_section(
466 556 'kng_dynamic_posts_category_button_colors_section',
467 557 [
468 558 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Category Button Colors', 'king-addons'),
469 559 'tab' => Controls_Manager::TAB_CONTENT,
560 + 'condition' => [
561 + 'kng_dynamic_posts_widget_mode' => ['', 'default']
562 + ]
470 563 ]
471 564 );
472 565
473 566 // Dynamic category button colors
@@ -474,10 +567,27 @@
474 567 $this->add_dynamic_category_button_colors();
475 568
476 569 $this->end_controls_section();
477 570
571 + // CPT Button Colors Section (PRO)
572 + $this->start_controls_section(
573 + 'kng_dynamic_posts_cpt_button_colors_section',
574 + [
575 + 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('CPT Button Colors', 'king-addons'),
576 + 'tab' => Controls_Manager::TAB_CONTENT,
577 + 'condition' => [
578 + 'kng_dynamic_posts_widget_mode' => 'custom_cpt'
579 + ]
580 + ]
581 + );
478 582
583 + // PRO: CPT Button Colors
584 + $this->add_control_cpt_button_colors();
479 585
586 + $this->end_controls_section();
587 +
588 +
589 +
480 590 // Category CTAs Section
481 591 $this->start_controls_section(
482 592 'kng_dynamic_posts_ctas_section',
483 593 [
@@ -482,8 +592,11 @@
482 592 'kng_dynamic_posts_ctas_section',
483 593 [
484 594 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Category Button Text', 'king-addons'),
485 595 'tab' => Controls_Manager::TAB_CONTENT,
596 + 'condition' => [
597 + 'kng_dynamic_posts_widget_mode' => ['', 'default']
598 + ]
486 599 ]
487 600 );
488 601
489 602 // Get categories dynamically
@@ -490,8 +603,25 @@
490 603 $this->add_dynamic_category_ctas();
491 604
492 605 $this->end_controls_section();
493 606
607 + // CPT Button Text Section (PRO)
608 + $this->start_controls_section(
609 + 'kng_dynamic_posts_cpt_ctas_section',
610 + [
611 + 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('CPT Button Text', 'king-addons'),
612 + 'tab' => Controls_Manager::TAB_CONTENT,
613 + 'condition' => [
614 + 'kng_dynamic_posts_widget_mode' => 'custom_cpt'
615 + ]
616 + ]
617 + );
618 +
619 + // PRO: CPT Button Text
620 + $this->add_control_cpt_ctas();
621 +
622 + $this->end_controls_section();
623 +
494 624 // Category Icons Section
495 625 $this->start_controls_section(
496 626 'kng_dynamic_posts_icons_section',
497 627 [
@@ -496,8 +626,11 @@
496 626 'kng_dynamic_posts_icons_section',
497 627 [
498 628 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Category Icons', 'king-addons'),
499 629 'tab' => Controls_Manager::TAB_CONTENT,
630 + 'condition' => [
631 + 'kng_dynamic_posts_widget_mode' => ['', 'default']
632 + ]
500 633 ]
501 634 );
502 635
503 636 // Get categories dynamically
@@ -504,8 +637,25 @@
504 637 $this->add_dynamic_category_icons();
505 638
506 639 $this->end_controls_section();
507 640
641 + // CPT Icons Section (PRO)
642 + $this->start_controls_section(
643 + 'kng_dynamic_posts_cpt_icons_section',
644 + [
645 + 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('CPT Icons', 'king-addons'),
646 + 'tab' => Controls_Manager::TAB_CONTENT,
647 + 'condition' => [
648 + 'kng_dynamic_posts_widget_mode' => 'custom_cpt'
649 + ]
650 + ]
651 + );
652 +
653 + // PRO: CPT Icons
654 + $this->add_control_cpt_icons();
655 +
656 + $this->end_controls_section();
657 +
508 658 // Pro Features Section
509 659 if (!king_addons_freemius()->can_use_premium_code__premium_only()) {
510 660 Core::renderProFeaturesSection($this, '', Controls_Manager::RAW_HTML, 'dynamic-posts-grid', [
511 661 'Advanced Query Builder',
@@ -517,8 +667,11 @@
517 667 'Custom Date Range Filters',
518 668 'Author-based Filtering'
519 669 ]);
520 670 }
671 +
672 + // PRO extension point to append content controls without duplicating base controls
673 + // Pro content controls are added via add_control_* method calls above
521 674 }
522 675
523 676 /**
524 677 * Register style controls.
@@ -1422,12 +1575,12 @@
1422 1575 'label' => esc_html__('Button Padding', 'king-addons'),
1423 1576 'type' => Controls_Manager::DIMENSIONS,
1424 1577 'size_units' => ['px', 'em', '%'],
1425 1578 'default' => [
1426 - 'top' => 12,
1427 - 'right' => 16,
1428 - 'bottom' => 12,
1429 - 'left' => 16,
1579 + 'top' => 8,
1580 + 'right' => 12,
1581 + 'bottom' => 8,
1582 + 'left' => 12,
1430 1583 'unit' => 'px',
1431 1584 ],
1432 1585 'selectors' => [
1433 1586 '{{WRAPPER}} .king-addons-dpg-search-btn' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
@@ -3185,9 +3338,9 @@
3185 3338 * Get available post types.
3186 3339 *
3187 3340 * @return array Post types array.
3188 3341 */
3189 - private function get_post_types(): array
3342 + protected function get_post_types(): array
3190 3343 {
3191 3344 $post_types = get_post_types(['public' => true], 'objects');
3192 3345 $options = [];
3193 3346
@@ -3202,9 +3355,9 @@
3202 3355 * Get available taxonomies.
3203 3356 *
3204 3357 * @return array Taxonomies array.
3205 3358 */
3206 - private function get_taxonomies(): array
3359 + protected function get_taxonomies(): array
3207 3360 {
3208 3361 $taxonomies = get_taxonomies(['public' => true], 'objects');
3209 3362 $options = [];
3210 3363
@@ -3217,9 +3370,9 @@
3217 3370
3218 3371 /**
3219 3372 * Add dynamic category color controls.
3220 3373 */
3221 - private function add_dynamic_category_colors(): void
3374 + protected function add_dynamic_category_colors(): void
3222 3375 {
3223 3376 // Get taxonomy from filter settings (default to category)
3224 3377 $taxonomy = 'category';
3225 3378
@@ -3311,9 +3464,9 @@
3311 3464
3312 3465 /**
3313 3466 * Add dynamic category icon controls.
3314 3467 */
3315 - private function add_dynamic_category_icons(): void
3468 + protected function add_dynamic_category_icons(): void
3316 3469 {
3317 3470 // Get taxonomy from filter settings (default to category)
3318 3471 $taxonomy = 'category';
3319 3472
@@ -3503,9 +3656,9 @@
3503 3656
3504 3657 /**
3505 3658 * Add dynamic category CTA controls.
3506 3659 */
3507 - private function add_dynamic_category_ctas(): void
3660 + protected function add_dynamic_category_ctas(): void
3508 3661 {
3509 3662 // Get taxonomy from filter settings (default to category)
3510 3663 $taxonomy = 'category';
3511 3664
@@ -3587,9 +3740,9 @@
3587 3740
3588 3741 /**
3589 3742 * Add dynamic category button color controls.
3590 3743 */
3591 - private function add_dynamic_category_button_colors(): void
3744 + protected function add_dynamic_category_button_colors(): void
3592 3745 {
3593 3746 // Get taxonomy from filter settings (default to category)
3594 3747 $taxonomy = 'category';
3595 3748
@@ -3731,20 +3884,8 @@
3731 3884 ],
3732 3885 ]
3733 3886 );
3734 3887
3735 - $this->add_control(
3736 - 'kng_dynamic_posts_default_button_border_color',
3737 - [
3738 - 'label' => esc_html__('Default Button Border Color', 'king-addons'),
3739 - 'type' => Controls_Manager::COLOR,
3740 - 'default' => 'rgba(0, 0, 0, 0.1)',
3741 - 'selectors' => [
3742 - '{{WRAPPER}} .king-addons-dpg-button' => 'border-color: {{VALUE}};',
3743 - ],
3744 - ]
3745 - );
3746 -
3747 3888 // Category-specific colors
3748 3889 $default_colors = [
3749 3890 ['color' => '#FFFFFF', 'bg' => '#EF4444', 'hover_color' => '#FFFFFF', 'hover_bg' => '#DC2626', 'border' => '#EF4444'], // Red
3750 3891 ['color' => '#FFFFFF', 'bg' => '#3B82F6', 'hover_color' => '#FFFFFF', 'hover_bg' => '#2563EB', 'border' => '#3B82F6'], // Blue
@@ -4022,8 +4163,12 @@
4022 4163 {
4023 4164 $settings = $this->get_settings_for_display();
4024 4165 $widget_id = $this->get_id();
4025 4166
4167 + if ($this->maybe_render_pro($settings)) {
4168 + return;
4169 + }
4170 +
4026 4171 // Query posts
4027 4172 $query_args = [
4028 4173 'post_type' => $settings['kng_dynamic_posts_post_types'],
4029 4174 'posts_per_page' => $settings['kng_dynamic_posts_per_page'],
@@ -4046,8 +4191,9 @@
4046 4191
4047 4192 // Wrapper attributes
4048 4193 $this->add_render_attribute('wrapper', 'class', 'king-addons-dpg-wrapper');
4049 4194 $this->add_render_attribute('wrapper', 'data-widget-id', $widget_id);
4195 + $this->add_render_attribute('wrapper', 'data-widget-mode', 'default'); // Set default mode for Free version
4050 4196 $this->add_render_attribute('wrapper', 'data-posts-per-page', $settings['kng_dynamic_posts_per_page']);
4051 4197 $this->add_render_attribute('wrapper', 'data-post-types', wp_json_encode($settings['kng_dynamic_posts_post_types']));
4052 4198 $this->add_render_attribute('wrapper', 'data-orderby', $settings['kng_dynamic_posts_orderby']);
4053 4199 $this->add_render_attribute('wrapper', 'data-order', $settings['kng_dynamic_posts_order']);
@@ -4056,8 +4202,12 @@
4056 4202
4057 4203 if ($settings['kng_dynamic_posts_enable_filters'] === 'yes') {
4058 4204 $this->add_render_attribute('wrapper', 'data-filter-taxonomy', $settings['kng_dynamic_posts_filter_taxonomy']);
4059 4205 }
4206 +
4207 + // CPT-related attributes (empty for Free version, but needed for JS compatibility)
4208 + $this->add_render_attribute('wrapper', 'data-cpt-actions', '');
4209 + $this->add_render_attribute('wrapper', 'data-cpt-icons', '');
4060 4210 ?>
4061 4211
4062 4212 <div <?php echo $this->get_render_attribute_string('wrapper'); ?>>
4063 4213
@@ -4118,9 +4268,9 @@
4118 4268 </div>
4119 4269 <?php endif; ?>
4120 4270
4121 4271 <!-- Grid Container -->
4122 - <div class="king-addons-dpg-grid" data-columns="<?php echo esc_attr($settings['kng_dynamic_posts_columns']); ?>">
4272 + <div class="king-addons-dpg-grid" data-columns="<?php echo esc_attr($settings['kng_dynamic_posts_columns'] ?? '3'); ?>">
4123 4273 <?php $this->render_posts($posts_query, $settings); ?>
4124 4274 </div>
4125 4275
4126 4276 <?php if ($settings['kng_dynamic_posts_enable_load_more'] === 'yes'): ?>
@@ -4204,11 +4354,9 @@
4204 4354 </div>
4205 4355
4206 4356 <!-- CTA Button -->
4207 4357 <div class="king-addons-dpg-cta">
4208 - <a href="<?php echo esc_url(get_permalink()); ?>" class="king-addons-dpg-button">
4209 - <?php echo esc_html($cta_text); ?>
4210 - </a>
4358 + <?php echo $this->get_cta_button_html($post, $settings, $cta_text); ?>
4211 4359 </div>
4212 4360
4213 4361 </div>
4214 4362
@@ -4214,5 +4362,163 @@
4214 4362
4215 4363 <?php
4216 4364 endwhile;
4217 4365 }
4366 +
4367 + /**
4368 + * Build WP_Query args. Pro overrides to support Custom CPT mode.
4369 + *
4370 + * @param array $settings Widget settings.
4371 + * @return array
4372 + */
4373 + protected function build_query_args(array $settings): array
4374 + {
4375 + return [
4376 + 'post_type' => $settings['kng_dynamic_posts_post_types'],
4377 + 'posts_per_page' => $settings['kng_dynamic_posts_per_page'],
4378 + 'orderby' => $settings['kng_dynamic_posts_orderby'],
4379 + 'order' => $settings['kng_dynamic_posts_order'],
4380 + 'post_status' => 'publish',
4381 + ];
4382 + }
4383 +
4384 + /**
4385 + * Build filter terms data for filter bar. Pro overrides for CPT/tabs.
4386 + *
4387 + * @param array $settings Widget settings.
4388 + * @return array
4389 + */
4390 + protected function get_filter_terms(array $settings): array
4391 + {
4392 + if (($settings['kng_dynamic_posts_enable_filters'] ?? '') !== 'yes') {
4393 + return [];
4394 + }
4395 +
4396 + $taxonomy = $settings['kng_dynamic_posts_filter_taxonomy'] ?? 'category';
4397 + $terms = get_terms([
4398 + 'taxonomy' => $taxonomy,
4399 + 'hide_empty' => true,
4400 + ]);
4401 +
4402 + return is_wp_error($terms) ? [] : $terms;
4403 + }
4404 +
4405 + /**
4406 + * Render filter bar wrapper. Pro overrides for advanced UI.
4407 + *
4408 + * @param array $settings Widget settings.
4409 + * @param array $filter_terms Terms list or structured data.
4410 + */
4411 + protected function render_filter_bar(array $settings, array $filter_terms): void
4412 + {
4413 + if (($settings['kng_dynamic_posts_enable_filters'] ?? '') !== 'yes' && ($settings['kng_dynamic_posts_enable_search'] ?? '') !== 'yes') {
4414 + return;
4415 + }
4416 + ?>
4417 + <div class="king-addons-dpg-filter-bar">
4418 + <div class="king-addons-dpg-filter-header">
4419 + <h2 class="king-addons-dpg-filter-title"><?php echo esc_html($settings['kng_dynamic_posts_filter_title_text'] ?? ''); ?></h2>
4420 + </div>
4421 +
4422 + <div class="king-addons-dpg-filter-controls">
4423 + <?php if (($settings['kng_dynamic_posts_enable_filters'] ?? '') === 'yes' && !empty($filter_terms)): ?>
4424 + <div class="king-addons-dpg-filter-dropdown<?php
4425 + $has_custom = !empty($settings['kng_dynamic_posts_filter_dropdown_use_custom']) && $settings['kng_dynamic_posts_filter_dropdown_use_custom'] === 'yes';
4426 + $has_icon = $has_custom && ($settings['kng_dynamic_posts_filter_dropdown_type'] ?? 'icon') === 'icon' && !empty($settings['kng_dynamic_posts_filter_dropdown_custom_icon']['value'] ?? '');
4427 + $has_image = $has_custom && ($settings['kng_dynamic_posts_filter_dropdown_type'] ?? 'icon') === 'image' && !empty($settings['kng_dynamic_posts_filter_dropdown_custom_image']['url'] ?? '');
4428 + echo ($has_custom && ($has_icon || $has_image)) ? ' has-custom-icon' : '';
4429 + ?>">
4430 + <select class="king-addons-dpg-posts-filter" data-taxonomy="<?php echo esc_attr($settings['kng_dynamic_posts_filter_taxonomy'] ?? 'category'); ?>">
4431 + <option value="*">&nbsp;<?php echo esc_html__('All resources types', 'king-addons'); ?></option>
4432 + <?php foreach ($filter_terms as $term): ?>
4433 + <option value="<?php echo esc_attr($term->slug); ?>"><?php echo esc_html($term->name); ?></option>
4434 + <?php endforeach; ?>
4435 + </select>
4436 + <?php if ($has_icon): ?>
4437 + <span class="dropdown-icon">
4438 + <?php \Elementor\Icons_Manager::render_icon($settings['kng_dynamic_posts_filter_dropdown_custom_icon'], ['class' => 'dropdown-custom-icon']); ?>
4439 + </span>
4440 + <?php elseif ($has_image): ?>
4441 + <span class="dropdown-image">
4442 + <img src="<?php echo esc_url($settings['kng_dynamic_posts_filter_dropdown_custom_image']['url']); ?>" alt="<?php echo esc_attr__('Dropdown icon', 'king-addons'); ?>" />
4443 + </span>
4444 + <?php endif; ?>
4445 + </div>
4446 + <?php endif; ?>
4447 +
4448 + <?php if (($settings['kng_dynamic_posts_enable_search'] ?? '') === 'yes'): ?>
4449 + <div class="king-addons-dpg-search-input">
4450 + <input type="text" class="king-addons-dpg-posts-search" placeholder="<?php echo esc_attr($settings['kng_dynamic_posts_search_placeholder'] ?? ''); ?>">
4451 + <button class="king-addons-dpg-search-btn" type="button">
4452 + <?php if (!empty($settings['kng_dynamic_posts_search_use_custom_icon']) && $settings['kng_dynamic_posts_search_use_custom_icon'] === 'yes' && !empty($settings['kng_dynamic_posts_search_custom_icon']['value'] ?? '')): ?>
4453 + <?php \Elementor\Icons_Manager::render_icon($settings['kng_dynamic_posts_search_custom_icon'], ['class' => 'king-addons-dpg-search-custom-icon']); ?>
4454 + <?php else: ?>
4455 + <svg width="20" height="20" viewBox="0 0 24 24"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" /></svg>
4456 + <?php endif; ?>
4457 + </button>
4458 + </div>
4459 + <?php endif; ?>
4460 + </div>
4461 + </div>
4462 + <?php
4463 + }
4464 +
4465 + /**
4466 + * Render pagination wrapper. Pro overrides for advanced types.
4467 + *
4468 + * @param array $settings
4469 + * @param \WP_Query $posts_query
4470 + */
4471 + protected function render_pagination(array $settings, \WP_Query $posts_query): void
4472 + {
4473 + if (($settings['kng_dynamic_posts_enable_load_more'] ?? '') !== 'yes') {
4474 + return;
4475 + }
4476 + ?>
4477 + <div class="king-addons-dpg-pagination">
4478 + <div class="king-addons-dpg-pagination-info">
4479 + <?php echo esc_html__('Showing', 'king-addons'); ?> <span class="king-addons-dpg-current-count"><?php echo (int) $posts_query->post_count; ?></span> <?php echo esc_html__('of', 'king-addons'); ?> <span class="king-addons-dpg-total-count"><?php echo (int) $posts_query->found_posts; ?></span> <?php echo esc_html__('items', 'king-addons'); ?>
4480 + </div>
4481 + <div class="king-addons-dpg-pagination-loading" style="display: none;">
4482 + <?php echo esc_html($settings['kng_dynamic_posts_loading_text'] ?? 'Loading...'); ?>
4483 + </div>
4484 + <?php if ($posts_query->max_num_pages > 1): ?>
4485 + <button class="king-addons-dpg-load-more-btn" data-page="1" data-max-pages="<?php echo esc_attr($posts_query->max_num_pages); ?>">
4486 + <?php echo esc_html($settings['kng_dynamic_posts_load_more_text'] ?? 'LOAD MORE'); ?>
4487 + </button>
4488 + <?php endif; ?>
4489 + <div class="king-addons-dpg-pagination-finish" style="display: none;">
4490 + <?php echo esc_html__('All items loaded', 'king-addons'); ?>
4491 + </div>
4492 + </div>
4493 + <?php
4494 + }
4495 +
4496 + /**
4497 + * Render CTA button HTML. Pro overrides to inject action button behaviors.
4498 + *
4499 + * @param \WP_Post $post
4500 + * @param array $settings
4501 + * @param string $cta_text
4502 + * @return string
4503 + */
4504 + protected function get_cta_button_html($post, array $settings, string $cta_text): string
4505 + {
4506 + return '<a href="' . esc_url(get_permalink($post)) . '" class="king-addons-dpg-button">' . esc_html($cta_text) . '</a>';
4507 + }
4508 +
4509 + /**
4510 + * Extension points for Pro controls (content/style). Intentionally empty in Free.
4511 + */
4512 + // PRO Control Methods (empty in Free, overridden in Pro)
4513 + public function add_control_widget_mode() {}
4514 + public function add_control_custom_post_types() {}
4515 + public function add_control_pagination_type() {}
4516 + public function add_control_scroll_threshold() {}
4517 + public function add_control_show_meta() {}
4518 + public function add_control_meta_fields() {}
4519 + public function add_control_cpt_actions() {}
4520 + public function add_control_cpt_colors() {}
4521 + public function add_control_cpt_button_colors() {}
4522 + public function add_control_cpt_ctas() {}
4523 + public function add_control_cpt_icons() {}
4218 4524 }