PluginProbe
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management / 1.5.0
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management v1.5.0
1.6.0 1.5.1 1.5.0 1.4.0 1.3.0 trunk 0.0.1 1.0.0 1.1.0 1.1.1 1.1.2 1.2.0
suredonation / inc / page-builders / page-builders.php

page-builders.php in SureDonation – Donation Forms, Fundraising Campaigns & Donor Management 1.5.0, at inc/page-builders/page-builders.php

160 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Page Builders bootstrap.
4 *
5 * Wires up SureDonation's page-builder integrations (Elementor and Bricks) and
6 * exposes the shared post-list helpers their controls use.
7 *
8 * @package SureDonation
9 * @since 1.2.0
10 */
11
12 namespace SureDonation\Inc\Page_Builders;
13
14 use SureDonation\Inc\Campaigns\Campaign_Cpt;
15 use SureDonation\Inc\Page_Builders\Bricks\Service_Provider as Bricks_Service_Provider;
16 use SureDonation\Inc\Page_Builders\Elementor\Service_Provider as Elementor_Service_Provider;
17 use SureDonation\Inc\Post_Types\Donation_Form;
18 use SureDonation\Inc\Traits\Get_Instance;
19
20 if ( ! defined( 'ABSPATH' ) ) {
21 exit; // Exit if accessed directly.
22 }
23
24 /**
25 * Page_Builders class.
26 *
27 * @since 1.2.0
28 */
29 class Page_Builders {
30 use Get_Instance;
31
32 /**
33 * Constructor — boot each page-builder provider (they self-gate on the
34 * builder being active).
35 *
36 * @since 1.2.0
37 */
38 public function __construct() {
39 Elementor_Service_Provider::get_instance();
40 Bricks_Service_Provider::get_instance();
41 }
42
43 /**
44 * Published campaigns as a `[ id => "Title #id" ]` map for builder controls.
45 *
46 * @since 1.2.0
47 * @return array<int|string, string>
48 */
49 public static function get_campaign_options() {
50 return self::get_post_options(
51 Campaign_Cpt::POST_TYPE,
52 __( 'Select a campaign', 'suredonation' ),
53 'suredonation_page_builder_campaign_options'
54 );
55 }
56
57 /**
58 * Published donation forms as a `[ id => "Title" ]` map for builder controls.
59 *
60 * Labels are the bare form title — no `#id` suffix (an untitled form still
61 * falls back to `(no title) #id` so it stays identifiable).
62 *
63 * @since 1.2.0
64 * @return array<int|string, string>
65 */
66 public static function get_donation_form_options() {
67 return self::get_post_options(
68 Donation_Form::POST_TYPE,
69 __( 'Select a donation form', 'suredonation' ),
70 'suredonation_page_builder_form_options',
71 false
72 );
73 }
74
75 /**
76 * Published donation forms linked to a single campaign as a
77 * `[ id => "Title" ]` map for builder controls.
78 *
79 * Mirrors the Gutenberg donation-form block, whose form selector is scoped to
80 * the chosen campaign (REST `/forms?campaign_id=`). Builders without a native
81 * dependent-dropdown (Elementor free) register one such control per campaign
82 * and gate it on the campaign selection to reproduce that behaviour.
83 *
84 * @since 1.2.0
85 * @param int $campaign_id Campaign whose forms to list.
86 * @return array<int|string, string>
87 */
88 public static function get_campaign_form_options( $campaign_id ) {
89 return self::format_post_options(
90 Donation_Form::get_forms_by_campaign( $campaign_id ),
91 __( 'Select a donation form', 'suredonation' ),
92 false
93 );
94 }
95
96 /**
97 * Build a `[ id => label ]` options map of published posts of a type, with a
98 * leading empty "select" entry.
99 *
100 * @since 1.2.0
101 * @param string $post_type Post type slug.
102 * @param string $placeholder Leading empty-option label.
103 * @param non-empty-string $filter Filter applied to the query args.
104 * @param bool $append_id Whether to append `#id` to each label (disambiguates duplicate titles).
105 * @return array<int|string, string>
106 */
107 private static function get_post_options( $post_type, $placeholder, $filter, $append_id = true ) {
108 $query_args = [
109 'post_type' => $post_type,
110 'posts_per_page' => -1,
111 'post_status' => 'publish',
112 'orderby' => 'title',
113 'order' => 'ASC',
114 ];
115
116 // $filter is one of this plugin's own prefixed hook names (suredonation_page_builder_*).
117 $filtered = apply_filters( $filter, $query_args ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
118
119 // House convention: never trust a filter's return shape blindly.
120 $query_args = is_array( $filtered ) ? $filtered : $query_args;
121
122 return self::format_post_options( get_posts( $query_args ), $placeholder, $append_id );
123 }
124
125 /**
126 * Turn a list of posts into a `[ id => label ]` options map with a leading
127 * empty "select" entry.
128 *
129 * @since 1.2.0
130 * @param array<int, \WP_Post|mixed> $posts Posts to format.
131 * @param string $placeholder Leading empty-option label.
132 * @param bool $append_id Whether to append `#id` to each label (disambiguates duplicate titles).
133 * @return array<int|string, string>
134 */
135 private static function format_post_options( array $posts, $placeholder, $append_id ) {
136 $options = [ '' => $placeholder ];
137
138 foreach ( $posts as $post ) {
139 if ( ! $post instanceof \WP_Post ) {
140 continue;
141 }
142 // Decode entities (wptexturize turns "-" into &#8211; via get_the_title)
143 // — builder controls escape option labels, so entities would render
144 // literally in the dropdown.
145 $title = trim( html_entity_decode( wp_strip_all_tags( (string) get_the_title( $post ) ), ENT_QUOTES, 'UTF-8' ) );
146 if ( '' === $title ) {
147 /* translators: %d: post ID. */
148 $title = sprintf( __( '(no title) #%d', 'suredonation' ), $post->ID );
149
150 // The fallback already carries the id — never double it up.
151 $options[ $post->ID ] = $title;
152 continue;
153 }
154 $options[ $post->ID ] = $append_id ? sprintf( '%1$s #%2$d', $title, $post->ID ) : $title;
155 }
156
157 return $options;
158 }
159 }
160