PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13
1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 1.7.0.9 All 211 releases
charitable / templates / campaign / builder / content.php

content.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.13, at templates/campaign/builder/content.php

762 lines 35.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Displays the campaign content created by the campaign builder, starting in 1.8.0.
4 *
5 * Override this template by copying it to yourtheme/charitable/campaign/builder/content.php
6 *
7 * @author WP Charitable LLC
8 * @package Charitable/Templates/Campaign
9 * @since 1.8.0
10 * @version 1.8.0
11 * @version 1.8.8.6
12 */
13
14 // Exit if accessed directly.
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit;
17 }
18
19 // Data related to the template (and therefore the defining layout) to be used.
20
21 $charitable_campaign = $view_args['campaign']; // Charitable_Campaign Instance of `Charitable_Campaign`.
22
23 /*
24 * Whether to honour the ?charitable_campaign_preview argument.
25 *
26 * That argument is unauthenticated and names an arbitrary post ID, so it is only trusted
27 * for a user who can edit that specific campaign. Without this check, appending
28 * ?charitable_campaign_preview=<other campaign id> to ANY campaign URL replaced the
29 * rendered campaign's whole builder payload with that other campaign's, which gave two
30 * real problems:
31 *
32 * - An unpublished campaign's headline, story and images leaked to any Contributor. The
33 * render gate further down tests edit_posts, a site-wide primitive every Contributor
34 * holds, not a per-campaign capability.
35 * - A published campaign's content rendered under a different campaign's URL for
36 * anonymous visitors, including its donation ask. That link is hand-outable and any
37 * full-page cache that ignores unknown query args will store it against the wrong URL.
38 *
39 * Both were reachable before 1.8.12.4 for the 24 hours a preview transient lives after
40 * each builder save; the saved-revision fallback added below would otherwise have made
41 * them permanent.
42 *
43 * edit_post (singular) is the meta capability. The campaign post type is registered with
44 * capability_type 'campaign' and map_meta_cap true, so WordPress maps it onto
45 * edit_campaign / edit_others_campaigns for the specific post. This mirrors the check
46 * Campaign_Builder_Preview::is_preview_page() already makes.
47 *
48 * When the check fails the argument is ignored completely and the normal view_args path
49 * renders the campaign the caller actually asked for.
50 */
51 $charitable_preview_id = empty( $_GET['charitable_campaign_preview'] ) ? 0 : absint( $_GET['charitable_campaign_preview'] ); //phpcs:ignore
52 $charitable_can_preview = $charitable_preview_id
53 && Charitable::CAMPAIGN_POST_TYPE === get_post_type( $charitable_preview_id )
54 && charitable_current_user_can( 'edit_post', $charitable_preview_id );
55
56 if ( $charitable_can_preview ) {
57 // get the transient that is storing the temp settings information, as this is what we will use to display the preview.
58 $charitable_campaign_data = get_transient( 'charitable_campaign_preview_' . $charitable_preview_id );
59
60 /*
61 * The transient carries the builder's *unsaved* changes and is written only by the
62 * builder's save AJAX. Every other route to a preview arrives without it:
63 *
64 * - the Preview action on a draft in the Campaigns list table,
65 * - WordPress's own preview_post_link for a campaign,
66 * - any preview more than DAY_IN_SECONDS after the last builder save,
67 * - an object cache that has evicted the entry (HelpScout #11576).
68 *
69 * With no fallback the whole render proceeded on false, which produced an empty
70 * campaign body and logged a warning for every read of ['id']. Fall back to the
71 * saved revision, which is what the preview notice already tells the user it is
72 * showing.
73 */
74 if ( empty( $charitable_campaign_data ) ) {
75 $charitable_campaign_data = get_post_meta( $charitable_preview_id, 'campaign_settings_v2', true );
76 }
77 } else {
78 $charitable_campaign_data = empty( $view_args['campaign_data'] ) && ! empty( $view_args['id'] ) ? get_post_meta( intval( $view_args['id'] ), 'campaign_settings_v2', true ) : $view_args['campaign_data'];
79 }
80
81 // A brand-new campaign has neither transient nor saved meta, so either branch can still
82 // yield a non-array. Normalise before anything indexes it.
83 if ( ! is_array( $charitable_campaign_data ) ) {
84 $charitable_campaign_data = array();
85 }
86
87 $charitable_template_data = isset( $view_args['template'] ) && is_array( $view_args['template'] ) ? $view_args['template'] : array();
88 $charitable_template_id = isset( $charitable_campaign_data['template_id'] ) && ! empty( $charitable_campaign_data['template_id'] ) ? sanitize_key( $charitable_campaign_data['template_id'] ) : charitable_campaign_builder_default_template();
89 $charitable_template_layout = isset( $charitable_template_data['layout'] ) ? $charitable_template_data['layout'] : array();
90
91 if ( is_admin() ) {
92
93 // Check if Elementor is installed and activated.
94 if ( ! did_action( 'elementor/loaded' ) ) {
95 return;
96 }
97
98 // load the Campaign Builder Preview class.
99 require_once charitable()->get_path( 'includes', true ) . 'admin/campaign-builder/class-campaign-builder-preview.php';
100
101 $charitable_assets_dir = charitable()->get_path( 'assets', false );
102 $charitable_min = charitable_get_min_suffix();
103
104 if ( charitable_is_debug( 'elementor' ) ) {
105 echo 'Charitable Elementor template id is ' . esc_html( $charitable_template_id );
106 }
107
108 // Directly link and load the CSS files.
109 $charitable_version = charitable_is_break_cache() ? charitable()->get_version() . '.' . time() : charitable()->get_version();
110 $charitable_css_theme_file = $charitable_assets_dir . 'css/campaign-builder/themes/frontend/' . $charitable_template_id . '.php';
111
112 echo '<link rel="stylesheet" id="charitable-campaign-theme-' . esc_attr( $charitable_template_id ) . '-css" href="' . esc_url( $charitable_css_theme_file ) . '" media="all" />'; //phpcs:ignore
113 echo '<link rel="stylesheet" id="charitable-campaign-theme-base-css" href="' . esc_url( $charitable_assets_dir . 'css/campaign-builder/themes/frontend/base' . $charitable_min . '.css' ) . '" media="all" />'; //phpcs:ignore
114
115 // Add inline CSS to prevent clicks on '.charitable-campaign-wrapper'.
116 echo '<style type="text/css">.charitable-campaign-wrapper { pointer-events: none; }</style>';
117 }
118
119 /* preview page check */
120 $charitable_content_preview = new Campaign_Builder_Preview();
121 $charitable_is_preview_page = $charitable_content_preview->is_preview_page();
122
123 /* tabs */
124 $charitable_enabled_tabs = isset( $charitable_campaign_data['layout']['advanced']['enable_tabs'] ) && 'disabled' === trim( $charitable_campaign_data['layout']['advanced']['enable_tabs'] ) ? false : true;
125
126
127 /* The Setup */
128
129 /*
130 * $charitable_campaign, $charitable_campaign_data, $charitable_template_data,
131 * $charitable_template_id and $charitable_template_layout are all resolved at the top of
132 * this file and are still current here. Nothing between there and this point reassigns
133 * $view_args or $_GET, or writes the preview transient or the campaign's post meta. The
134 * is_admin() branch only reads them and echoes stylesheet links, assigning nothing but four
135 * locals of its own; Campaign_Builder_Preview's constructor does query the database via
136 * is_preview_page() before registering its hooks, but it touches none of this scope.
137 * Verified at runtime across the draft-preview, published-preview and front-end paths.
138 *
139 * This block previously recomputed four of the five from scratch - everything except
140 * $charitable_template_data, which was and still is assigned exactly once above. That
141 * duplicate is where the second copy of the preview-transient read lived, and why the
142 * transient fix originally had to be written twice.
143 */
144
145 /*
146 * Resolve the campaign's post ID independently of the campaign data payload. The three post
147 * lookups below need nothing but the ID, and sourcing it from inside the payload is what
148 * made them warn whenever the payload was missing.
149 *
150 * $view_args['id'] comes first because it is the campaign the caller actually asked for.
151 * The payload's own 'id' is the least trustworthy source: it is written once at save time
152 * and copied verbatim thereafter, so a WXR import, a staging-to-production migration or a
153 * duplicate-post plugin can leave it pointing at an unrelated post, and the status of THAT
154 * post would then decide whether this campaign renders.
155 *
156 * $charitable_preview_id is used only when $charitable_can_preview passed, so the
157 * unauthenticated query argument cannot steer this either.
158 *
159 * Stays 0 only when there is no global post either, since get_the_ID() would otherwise have
160 * supplied it. The status gate below has an explicit branch for that case rather than
161 * relying on get_post_status( 0 ), which returns false with no post to fall back to.
162 */
163 $charitable_campaign_post_id = ! empty( $view_args['id'] ) ? intval( $view_args['id'] ) : 0;
164
165 if ( 0 === $charitable_campaign_post_id && ! empty( $charitable_campaign_data['id'] ) ) {
166 $charitable_campaign_post_id = intval( $charitable_campaign_data['id'] );
167 }
168
169 if ( 0 === $charitable_campaign_post_id && $charitable_can_preview ) {
170 $charitable_campaign_post_id = $charitable_preview_id;
171 }
172
173 if ( 0 === $charitable_campaign_post_id ) {
174 $charitable_campaign_post_id = intval( get_the_ID() );
175 }
176
177 /* Template Related */
178
179 $charitable_template_parent_id = ( isset( $charitable_template_data['meta']['parent_theme'] ) && ! empty( $charitable_template_data['meta']['parent_theme'] ) ) ? esc_attr( $charitable_template_data['meta']['parent_theme'] ) : false;
180 $charitable_template_wrap_css = false !== $charitable_template_parent_id ? 'template-' . $charitable_template_parent_id : '';
181 $charitable_template_wrap_css .= false !== $charitable_template_id ? ' template-' . $charitable_template_id : '';
182 $charitable_template_wrap_css .= ! empty( $view_args['campaign_data']['settings']['general']['form_css_class'] ) ? ' ' . esc_attr( $view_args['campaign_data']['settings']['general']['form_css_class'] ) : false;
183 $charitable_template_wrap_css .= 'draft' === get_post_status( $charitable_campaign_post_id ) ? ' is-charitable-preview' : false; // this to give a css class only when the campaign is previewed.
184
185 /* Layout Related */
186
187 $charitable_row_counter = 0;
188
189 $charitable_rows = (array) isset( $charitable_campaign_data['layout'] ) && ! empty( $charitable_campaign_data['layout']['rows'] ) ? $charitable_campaign_data['layout']['rows'] : array();
190
191 /* css: wrap and containers */
192
193 $charitable_css_classes = array();
194 $charitable_css_classes['container-wrap'] = 'charitable-campaign-wrap ' . trim( $charitable_template_wrap_css );
195 $charitable_css_classes['container-wrap'] .= ! empty( $view_args['id'] ) ? ' charitable-campaign-wrap-id-' . intval( $view_args['id'] ) : '';
196 $charitable_css_classes = apply_filters( 'charitable_builder_campaign_content_css_classes', $charitable_css_classes, $charitable_template_data, $charitable_campaign_data );
197 $charitable_css_classes_output = implode( ' ', $charitable_css_classes );
198
199 // Get the post status - if this is a draft, we will display a notice to the admin or author, and not show this to the public.
200 $charitable_post_status = get_post_status( $charitable_campaign_post_id );
201 $charitable_post_author = get_post_field( 'post_author', $charitable_campaign_post_id );
202
203 /*
204 * Statuses that are not publicly published. These render only for the campaign's author or
205 * a user who can edit that campaign, and carry the "not published yet" notice on the front
206 * end.
207 *
208 * 'pending' and 'future' were missing before 1.8.12.4, so a campaign in either status
209 * rendered nothing at all - the builder's preview page showed its notice bar above an empty
210 * body. That became reachable once the Preview button stopped swallowing those statuses.
211 * 'private' is deliberately not in this list: it is published but restricted, so it is
212 * handled below with the read_post capability instead.
213 */
214 $charitable_unpublished_statuses = array( 'draft', 'pending', 'future' );
215
216 /*
217 * Whether the current user is the campaign's author.
218 *
219 * get_post_field() returns post_author as a *string*, while get_current_user_id() returns an
220 * int, so the previous `$charitable_post_author === get_current_user_id()` could never match
221 * and every check below fell through to the capability test alone. Comparing as integers is
222 * plainly the intent (see the comments on each branch), and restores author access.
223 *
224 * The get_current_user_id() > 0 guard is load-bearing: a campaign whose post_author is 0 or
225 * NULL would otherwise compare equal to a logged-out visitor's user ID of 0 and expose an
226 * unpublished campaign publicly.
227 */
228 $charitable_is_campaign_author = get_current_user_id() > 0 && (int) $charitable_post_author === get_current_user_id();
229
230 /*
231 * Only display the message if the viewer isn't viewing a preview from the campaign builder
232 * (maybe they are viewing this via shortcode on the frontend, etc.).
233 *
234 * Keyed off $charitable_can_preview rather than the raw query argument: a request carrying
235 * ?charitable_campaign_preview for a campaign the user cannot edit is an ordinary page view,
236 * not a preview, so it should still get the notice.
237 */
238 if ( ! $charitable_can_preview && ( false === $charitable_post_status || in_array( $charitable_post_status, $charitable_unpublished_statuses, true ) ) ) :
239
240 // if the user is the author of the post OR if they have permissions to view drafts, show the notice.
241 if ( $charitable_is_campaign_author || current_user_can( 'edit_posts' ) ) {
242 ?>
243 <div class="charitable-notice charitable-notice-info">
244 <?php
245 /*
246 * Status-neutral wording. This branch now covers pending and future as well as
247 * draft, so the previous "currently in draft mode" was inaccurate for a campaign
248 * awaiting review or scheduled. The draft-specific strings it replaces are no
249 * longer referenced.
250 */
251 ?>
252 <p style="margin: 0;"><?php esc_html_e( 'This campaign has not been published yet. Only you can see it, and some functionality (like donation forms, donation buttons, etc.) might be disabled.', 'charitable' ); ?></p>
253 </div>
254 <?php
255 } else {
256 // show a generic message to the public.
257 ?>
258 <div class="charitable-notice charitable-notice-info">
259 <p style="margin: 0;"><?php esc_html_e( 'This campaign has not been published yet.', 'charitable' ); ?></p>
260 </div>
261 <?php
262 }
263
264 endif;
265
266 /*
267 * Whether to render the campaign at all, and to whom.
268 *
269 * - 'publish' is public.
270 * - The unpublished states render for the author, or for a user who can edit THAT campaign.
271 * - 'private' is published but access-restricted, so it asks whether the user can read that
272 * specific post rather than whether they can edit campaigns generally.
273 * - No resolvable post means there is nothing to disclose, so this keeps the pre-1.8.12.4
274 * site-wide edit_posts test rather than inventing a per-post check with no post.
275 * - Everything else - trash, auto-draft, inherit, and any status a third party registers -
276 * renders nothing, as before.
277 *
278 * These use the singular edit_post / read_post META capabilities against
279 * $charitable_campaign_post_id, not the plural edit_posts / read_private_posts primitives.
280 * The campaign post type registers capability_type 'campaign' with map_meta_cap true, so
281 * WordPress maps them onto edit_campaign / edit_others_campaigns / read_private_campaigns
282 * for that one post. The plural forms were wrong twice over: edit_posts is held by every
283 * Contributor for every campaign on the site, and read_private_posts is a *posts* primitive
284 * that says nothing about campaigns, so a core Editor would have passed it while WordPress's
285 * own read_post check on the campaign would have denied them.
286 */
287 if ( 'publish' === $charitable_post_status ) {
288 $charitable_can_view_campaign = true;
289 } elseif ( false === $charitable_post_status || 0 === $charitable_campaign_post_id ) {
290 $charitable_can_view_campaign = $charitable_is_campaign_author || charitable_current_user_can( 'edit_posts' );
291 } elseif ( 'private' === $charitable_post_status ) {
292 $charitable_can_view_campaign = $charitable_is_campaign_author || charitable_current_user_can( 'read_post', $charitable_campaign_post_id );
293 } elseif ( in_array( $charitable_post_status, $charitable_unpublished_statuses, true ) ) {
294 $charitable_can_view_campaign = $charitable_is_campaign_author || charitable_current_user_can( 'edit_post', $charitable_campaign_post_id );
295 } else {
296 $charitable_can_view_campaign = false;
297 }
298
299 if ( $charitable_can_view_campaign ) :
300
301 /**
302 * Add something before the campaign builder content.
303 *
304 * @since 1.8.0
305 *
306 * @param $campaign Charitable_Campaign Instance of `Charitable_Campaign`.
307 */
308 do_action( 'charitable_builder_campaign_content_before', $charitable_campaign_data );
309
310 /**
311 * Add something before the campaign content.
312 *
313 * @since 1.8.0
314 *
315 * @param $campaign Charitable_Campaign Instance of `Charitable_Campaign`.
316 */
317 do_action( 'charitable_campaign_content_before', $charitable_campaign );
318
319 ?>
320
321 <div class="<?php echo esc_attr( $charitable_css_classes_output ); ?>">
322
323 <div class="charitable-campaign-container">
324
325 <?php
326
327 foreach ( $charitable_rows as $charitable_row_id => $charitable_row ) :
328
329 $charitable_row_type = ! empty( $charitable_row['type'] ) ? esc_attr( $charitable_row['type'] ) : false;
330
331 $charitable_row_css = array(
332 'charitable-campaign-row',
333 'charitable-campaign-row-type-' . $charitable_row_type,
334 );
335 $charitable_additional_css = ! empty( $charitable_row['css_class'] ) ? esc_attr( $charitable_row['css_class'] ) : '';
336 if ( '' !== $charitable_additional_css ) {
337 $charitable_row_css[] = $charitable_additional_css;
338 }
339
340 $charitable_row_bg = ! empty( $charitable_row['background_image'] ) ? esc_url( $charitable_row['background_image'] ) : '';
341 $charitable_row_style = '' !== $charitable_row_bg ? ' style="background-image:url(\'' . $charitable_row_bg . '\');"' : '';
342 $charitable_row_locked = ! empty( $charitable_row['locked'] ) ? ' data-row-locked="1"' : '';
343
344 if ( '' !== $charitable_row_bg ) {
345 $charitable_row_css[] = 'has-background-image';
346 }
347 if ( ! empty( $charitable_row['locked'] ) ) {
348 $charitable_row_css[] = 'is-locked';
349 }
350
351 $charitable_row_css_classes = apply_filters(
352 'charitable_campaign_row_css',
353 $charitable_row_css,
354 $charitable_row,
355 $charitable_template_id,
356 $charitable_campaign_data
357 );
358
359 if ( 'row' === $charitable_row_type || 'header' === $charitable_row_type ) :
360 ?>
361
362 <?php echo '<!-- row START -->'; ?>
363
364 <div id="charitable-template-row-<?php echo intval( $charitable_row_id ); ?>" data-row-id="<?php echo intval( $charitable_row_id ); ?>" data-row-type="<?php echo esc_attr( $charitable_row_type ); ?>"<?php echo $charitable_row_locked; // phpcs:ignore ?> class="<?php echo implode( ' ', array_map( 'esc_attr', $charitable_row_css_classes ) ); ?>"<?php echo $charitable_row_style; // phpcs:ignore ?>>
365
366 <?php
367
368 if ( ! empty( $charitable_row['columns'] ) ) :
369
370 $charitable_column_counter = 0;
371
372 foreach ( $charitable_row['columns'] as $charitable_column_id => $charitable_column ) :
373
374 $charitable_column_css_classes = apply_filters(
375 'charitable_campaign_column_css',
376 array(
377 'charitable-campaign-column',
378 'charitable-campaign-column-' . $charitable_column_id,
379 ),
380 $charitable_column,
381 $charitable_template_id,
382 $charitable_campaign_data
383 );
384
385
386 echo '<!-- column START -->';
387
388 echo '<div data-column-id="' . intval( $charitable_column_id ) . '" class="' . implode( ' ', array_map( 'esc_attr', $charitable_column_css_classes ) ) . '">';
389
390 $charitable_section_counter = 0;
391
392 foreach ( $charitable_column['sections'] as $charitable_section ) :
393
394 echo '<!-- section START -->';
395
396 echo '<div data-section-id="' . intval( $charitable_section_counter ) . '" data-section-type="' . esc_attr( $charitable_section['type'] ) . '" class="section charitable-field-section">';
397
398 $charitable_section_type = ! empty( $charitable_section['type'] ) ? esc_attr( $charitable_section['type'] ) : 'fields';
399
400 if ( 'tabs' === $charitable_section_type ) {
401
402 // Did the user disable tabs entirely?
403 $charitable_enable_tabs = ( ! empty( $charitable_campaign_data['layout']['advanced']['enable_tabs'] ) && $charitable_campaign_data['layout']['advanced']['enable_tabs'] === 'disabled' ) ? false : true;
404
405 if ( false !== $charitable_enable_tabs ) {
406
407
408 // If there is campaign data, make a list of fields already in use which might determine if we show any tabs or not.
409 $charitable_fields_in_tabs = array();
410
411 if ( ! empty( $charitable_section['tabs'] ) ) {
412 foreach ( $charitable_section['tabs'] as $charitable_section_tab ) {
413 if ( ! empty( $charitable_section_tab['fields'] ) ) {
414 $charitable_fields_in_tabs = array_merge( $charitable_fields_in_tabs, $charitable_section_tab['fields'] );
415 }
416 }
417 }
418
419 // If there are no fields in any tabs, don't show the tabs.
420 if ( empty( $charitable_fields_in_tabs ) ) {
421 continue;
422 }
423
424 $charitable_tab_tabs = (array) isset( $charitable_section['tabs'] ) && ! empty( $charitable_section['tabs'] ) ? $charitable_section['tabs'] : array();
425 $charitable_tab_order = isset( $charitable_campaign_data['tab_order'] ) && ! empty( $charitable_campaign_data['tab_order'] ) ? $charitable_campaign_data['tab_order'] : array();
426 $charitable_tab_style = isset( $charitable_campaign_data['layout']['advanced']['tab_style'] ) && '' !== trim( $charitable_campaign_data['layout']['advanced']['tab_style'] ) ? $charitable_campaign_data['layout']['advanced']['tab_style'] : 'medium';
427 $charitable_tab_size = isset( $charitable_campaign_data['layout']['advanced']['tab_size'] ) && '' !== trim( $charitable_campaign_data['layout']['advanced']['tab_size'] ) ? $charitable_campaign_data['layout']['advanced']['tab_size'] : 'medium';
428 $charitable_css_class = isset( $charitable_campaign_data['layout']['advanced']['enable_tabs'] ) && 'disabled' === trim( $charitable_campaign_data['layout']['advanced']['enable_tabs'] ) ? 'disabled' : false;
429
430 // sort a multidimensional array matching the same order of keys as another multidimensional array.
431 if ( ! empty( $charitable_tab_order ) ) {
432 $charitable_temp_tab_tabs = array();
433 foreach ( $charitable_tab_order as $charitable_order_id => $charitable_tab_id ) {
434 if ( isset( $charitable_tab_tabs[ $charitable_tab_id ] ) ) {
435 $charitable_temp_tab_tabs[ $charitable_tab_id ] = $charitable_tab_tabs[ $charitable_tab_id ];
436 }
437 }
438 $charitable_tab_tabs = $charitable_temp_tab_tabs;
439 }
440
441 ?>
442 <article>
443 <?php
444 // Check if all tabs should be hidden (1.8.8.2)
445 $charitable_all_tabs_hidden = true;
446 $charitable_visible_tabs_count = 0;
447 foreach ( $charitable_tab_tabs as $charitable_tab_id => $charitable_tab_fields ) {
448 $charitable_tab_info = $charitable_campaign_data['tabs'][ $charitable_tab_id ];
449 if ( empty( $charitable_tab_info['visible_nav'] ) || $charitable_tab_info['visible_nav'] !== 'invisible' ) {
450 $charitable_all_tabs_hidden = false;
451 $charitable_visible_tabs_count++;
452 }
453 }
454
455 // Only show navigation if there are multiple visible tabs (hide for single tab)
456 if ( ! $charitable_all_tabs_hidden && $charitable_visible_tabs_count > 1 ) :
457 ?>
458 <nav class="charitable-campaign-nav charitable-tab-style-<?php echo esc_attr( $charitable_tab_style ); ?> charitable-tab-size-<?php echo esc_attr( $charitable_tab_size ); ?>">
459 <ul>
460 <?php if ( ! empty( $charitable_tab_tabs ) ) : ?>
461
462 <?php
463
464 $charitable_counter = 1;
465
466 foreach ( $charitable_tab_tabs as $charitable_tab_id => $charitable_tab_fields ) :
467
468 $charitable_tab_info = $charitable_campaign_data['tabs'][ $charitable_tab_id ];
469
470 $charitable_tab_type = isset( $charitable_tab_info['type'] ) && ! empty( $charitable_tab_info['type'] ) ? ( $charitable_tab_info['type'] ) : false;
471 $charitable_tab_title = isset( $charitable_tab_info['title'] ) && ! empty( $charitable_tab_info['title'] ) ? ( $charitable_tab_info['title'] ) : false;
472 $charitable_tab_desc = isset( $charitable_tab_info['desc'] ) && ! empty( $charitable_tab_info['desc'] ) ? ( $charitable_tab_info['desc'] ) : false;
473 $charitable_css_class = 'tab_type_' . $charitable_tab_type . ' ';
474 $charitable_css_class = ( $charitable_counter === 1 ) ? 'active' : false;
475
476
477 ?><li id="tab_<?php echo intval( $charitable_tab_id ); ?>_title" data-tab-id="<?php echo intval( $charitable_tab_id ); ?>" data-tab-type="<?php echo esc_attr( $charitable_tab_type ); ?>" class="tab_title <?php echo esc_attr( $charitable_css_class ); ?>"><a href="#"><?php echo esc_html( $charitable_tab_title ); ?></a></li><?php //phpcs:ignore
478
479 ++$charitable_counter;
480
481 endforeach;
482
483 ?>
484
485 <?php endif; ?>
486
487 </ul>
488 </nav>
489 <?php endif; // end if not all tabs hidden ?>
490 <div class="tab-content">
491
492 <ul class="charitable-tabs">
493
494 <?php if ( ! empty( $charitable_tab_tabs ) ) : ?>
495
496 <?php
497
498 $charitable_counter = 1;
499
500 foreach ( $charitable_tab_tabs as $charitable_tab_id => $charitable_tab_fields ) :
501
502 $charitable_tab_info = $charitable_campaign_data['tabs'][ $charitable_tab_id ];
503
504 $charitable_tab_type = isset( $charitable_tab_info['type'] ) && ! empty( $charitable_tab_info['type'] ) ? ( $charitable_tab_info['type'] ) : false;
505 $charitable_tab_title = isset( $charitable_tab_info['title'] ) && ! empty( $charitable_tab_info['title'] ) ? ( $charitable_tab_info['title'] ) : false;
506 $charitable_tab_desc = isset( $charitable_tab_info['desc'] ) && ! empty( $charitable_tab_info['desc'] ) ? ( $charitable_tab_info['desc'] ) : false;
507 $charitable_css_class = 'tab_type_' . $charitable_tab_type . ' ';
508 $charitable_css_class .= ( $charitable_counter === 1 ) ? 'active' : false;
509
510
511 ?>
512 <li id="tab_<?php echo intval( $charitable_tab_id ); ?>_content" class="tab_content_item <?php echo esc_attr( $charitable_css_class ); ?>" data-tab-type="<?php echo esc_attR( $charitable_tab_type ); ?>" data-tab-id="<?php echo esc_attr( $charitable_tab_id ); ?>">
513
514 <div class="charitable-tab-wrap">
515
516 <?php
517
518 $charitable_tab_tabs = (array) isset( $charitable_section['tabs'] ) && ! empty( $charitable_section['tabs'][ $charitable_tab_id ] ) ? $charitable_section['tabs'][ $charitable_tab_id ] : array();
519
520 if ( ! empty( $charitable_tab_tabs['fields'] ) ) :
521
522 $charitable_tab_fields_types = isset( $charitable_row['fields'] ) ? $charitable_row['fields'] : array();
523
524 foreach ( $charitable_tab_tabs['fields'] as $charitable_tab_field_id => $charitable_tab_field_type_id ) :
525
526 $charitable_tab_field_data = ! empty( $charitable_campaign_data['fields'][ $charitable_tab_field_type_id ] ) ? $charitable_campaign_data['fields'][ $charitable_tab_field_type_id ] : false;
527 $charitable_tab_field_type = ! empty( $charitable_row['fields'][ $charitable_tab_field_type_id ] ) ? $charitable_row['fields'][ $charitable_tab_field_type_id ] : false;
528
529 $charitable_field_class = 'Charitable_Field_' . str_replace( ' ', '_', ( ucwords( str_replace( '-', ' ', $charitable_tab_field_type ) ) ) );
530
531 if ( class_exists( $charitable_field_class ) ) :
532
533 $charitable_class = new $charitable_field_class();
534 $charitable_class->field_display( $charitable_tab_field_type, $charitable_tab_field_data, $charitable_campaign_data, $charitable_is_preview_page, $charitable_tab_field_id );
535
536 endif;
537
538
539 endforeach;
540
541 endif;
542
543 ?>
544 </div>
545
546 </li>
547
548 <?php
549
550 ++$charitable_counter;
551
552 endforeach;
553 ?>
554
555 <?php endif; ?>
556 </ul>
557 </div>
558 </article>
559
560 <?php } // end if tabs ?>
561
562 <?php
563
564
565 } elseif ( 'fields' === $charitable_section_type ) {
566
567 $charitable_field_types_data = $charitable_row['fields'];
568
569 foreach ( $charitable_section['fields'] as $charitable_key => $charitable_field_id ) :
570
571 $charitable_field_data = ! empty( $charitable_campaign_data['fields'][ $charitable_field_id ] ) ? $charitable_campaign_data['fields'][ $charitable_field_id ] : false;
572 $charitable_field_type = false !== $charitable_field_data && isset( $charitable_field_types_data[ $charitable_field_id ] ) ? sanitize_key( $charitable_field_types_data[ $charitable_field_id ] ) : false;
573 $charitable_field_class = 'Charitable_Field_' . str_replace( ' ', '_', ( ucwords( str_replace( '-', ' ', $charitable_field_type ) ) ) );
574
575 if ( class_exists( $charitable_field_class ) ) :
576
577 $charitable_class = new $charitable_field_class();
578 $charitable_class->field_display( $charitable_field_type, $charitable_field_data, $charitable_campaign_data, $charitable_is_preview_page, $charitable_field_id, $charitable_template_data );
579
580 endif;
581
582 endforeach;
583
584 }
585
586 ++$charitable_section_counter;
587
588 echo '</div>';
589
590 echo '<!-- section END -->';
591
592 endforeach;
593
594 ++$charitable_column_counter;
595
596 ?>
597
598 </div>
599
600 <?php
601
602 echo '<!-- column END -->';
603
604 endforeach;
605
606 endif;
607
608 ?>
609
610 </div>
611
612 <?php echo '<!-- row END -->'; ?>
613
614 <?php
615
616 elseif ( $charitable_enabled_tabs && 'tabs' === $charitable_row_type ) :
617
618 // Did the user disable tabs entirely?
619 $charitable_enable_tabs = ( ! empty( $charitable_campaign_data['layout']['advanced']['enable_tabs'] ) && $charitable_campaign_data['layout']['advanced']['enable_tabs'] === 'disabled' ) ? false : true;
620
621 if ( false === $charitable_enable_tabs ) {
622 continue;
623 }
624
625 $charitable_row_tabs = isset( $charitable_row['tabs'] ) ? $charitable_row['tabs'] : false;
626 $charitable_tab_style = isset( $charitable_campaign_data['layout']['advanced']['tab_style'] ) && '' !== trim( $charitable_campaign_data['layout']['advanced']['tab_style'] ) ? $charitable_campaign_data['layout']['advanced']['tab_style'] : 'medium';
627 $charitable_tab_size = isset( $charitable_campaign_data['layout']['advanced']['tab_size'] ) && '' !== trim( $charitable_campaign_data['layout']['advanced']['tab_size'] ) ? $charitable_campaign_data['layout']['advanced']['tab_style'] : 'medium';
628 $charitable_css_class = isset( $charitable_campaign_data['layout']['advanced']['enable_tabs'] ) && 'disabled' === trim( $charitable_campaign_data['layout']['advanced']['enable_tabs'] ) ? 'disabled' : false;
629
630 ?>
631
632 <article>
633 <nav class="charitable-campaign-nav charitable-tab-style-<?php echo esc_attr( $charitable_tab_style ); ?> charitable-tab-size-<?php echo esc_attr( $charitable_tab_size ); ?>">
634 <ul>
635 <?php if ( $charitable_row_tabs ) : ?>
636 <?php
637
638 $charitable_counter = 1;
639
640 foreach ( $charitable_row_tabs as $charitable_tab_id => $charitable_tab_fields ) :
641
642 $charitable_tab_info = $charitable_campaign_data['tabs'][ $charitable_tab_id ];
643
644 $charitable_tab_type = isset( $charitable_tab_info['type'] ) && ! empty( $charitable_tab_info['type'] ) ? ( $charitable_tab_info['type'] ) : false;
645 $charitable_tab_title = isset( $charitable_tab_info['title'] ) && ! empty( $charitable_tab_info['title'] ) ? ( $charitable_tab_info['title'] ) : false;
646 $charitable_tab_desc = isset( $charitable_tab_info['desc'] ) && ! empty( $charitable_tab_info['desc'] ) ? ( $charitable_tab_info['desc'] ) : false;
647 $charitable_css_class = 'tab_type_' . $charitable_tab_type . ' ';
648 $charitable_css_class = ( $charitable_counter === 1 ) ? 'active' : false;
649
650
651 ?>
652 <li id="tab_<?php echo intval( $charitable_tab_id ); ?>_title" data-tab-id="<?php echo intval( $charitable_tab_id ); ?>" data-tab-type="<?php echo esc_attr( $charitable_tab_type ); ?>" class="tab_title <?php echo esc_attr( $charitable_css_class ); ?>"><a href="#"><?php echo esc_html( $charitable_tab_title ); ?></a></li>
653 <?php
654
655 ++$charitable_counter;
656
657 endforeach;
658 ?>
659
660 <?php endif; ?>
661 </ul>
662 </nav>
663 <div class="tab-content">
664 <ul>
665 <?php
666
667 if ( $charitable_row_tabs ) :
668
669 $charitable_counter = 1;
670
671 foreach ( $charitable_row_tabs as $charitable_tab_id => $charitable_tab_fields ) :
672
673 $charitable_tab_info = $charitable_campaign_data['tabs'][ $charitable_tab_id ];
674
675 $charitable_tab_type = isset( $charitable_tab_info['type'] ) && ! empty( $charitable_tab_info['type'] ) ? ( $charitable_tab_info['type'] ) : false;
676 $charitable_tab_title = isset( $charitable_tab_info['title'] ) && ! empty( $charitable_tab_info['title'] ) ? ( $charitable_tab_info['title'] ) : false;
677 $charitable_tab_desc = isset( $charitable_tab_info['desc'] ) && ! empty( $charitable_tab_info['desc'] ) ? ( $charitable_tab_info['desc'] ) : false;
678 $charitable_css_class = 'tab_type_' . $charitable_tab_type . ' ';
679 $charitable_css_class .= ( $charitable_counter === 1 ) ? 'active' : false;
680
681
682 ?>
683 <li id="tab_<?php echo intval( $charitable_tab_id ); ?>_content" class="tab_content_item <?php echo esc_attr( $charitable_css_class ); ?>" data-tab-type="<?php echo esc_attr( $charitable_tab_type ); ?>" data-tab-id="<?php echo intval( $charitable_tab_id ); ?>">
684
685 <div class="charitable-tab-wrap">
686
687 <?php
688
689 $charitable_tab_field_info = isset( $charitable_row['fields'] ) ? $charitable_row['fields'] : false;
690
691 if ( false !== $charitable_tab_field_info ) :
692
693 $charitable_tab_fields_types = isset( $charitable_row['fields'] ) ? $charitable_row['fields'] : array();
694
695 foreach ( $charitable_tab_fields as $charitable_tab_field_id => $charitable_tab_field_type_id ) :
696
697 $charitable_tab_field_data = ! empty( $charitable_campaign_data['fields'][ $charitable_tab_field_type_id ] ) ? $charitable_campaign_data['fields'][ $charitable_tab_field_type_id ] : false;
698 $charitable_tab_field_type = ! empty( $charitable_row['fields'][ $charitable_tab_field_type_id ] ) ? $charitable_row['fields'][ $charitable_tab_field_type_id ] : false;
699
700 $charitable_field_class = 'Charitable_Field_' . str_replace( ' ', '_', ( ucwords( str_replace( '-', ' ', $charitable_tab_field_type ) ) ) );
701
702 if ( class_exists( $charitable_field_class ) ) :
703
704 $charitable_class = new $charitable_field_class();
705 $charitable_class->field_display( $charitable_tab_field_type, $charitable_tab_field_data, $charitable_campaign_data, $charitable_is_preview_page, $charitable_tab_field_id );
706
707 endif;
708
709 endforeach;
710
711 endif;
712
713 ?>
714 </div>
715
716 </li>
717
718 <?php
719
720 ++$charitable_counter;
721
722 endforeach;
723 ?>
724
725 <?php endif; ?>
726 </ul>
727 </div>
728 </article>
729
730 <?php
731
732 endif;
733
734 endforeach;
735
736 ?>
737
738 </div>
739 </div>
740
741 <?php
742
743 /**
744 * Add something after the campaign content.
745 *
746 * @since 1.8.0
747 *
748 * @param $campaign Charitable_Campaign Instance of `Charitable_Campaign`.
749 */
750 do_action( 'charitable_builder_campaign_content_after', $charitable_campaign_data );
751
752 /**
753 * Add something before the campaign content.
754 *
755 * @since 1.8.0
756 *
757 * @param $campaign Charitable_Campaign Instance of `Charitable_Campaign`.
758 */
759 do_action( 'charitable_campaign_content_after', $charitable_campaign );
760
761 endif;
762