PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13.1
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13.1
1.8.13.1 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 All 212 releases
charitable / includes / admin / campaign-builder / panels / class-design.php

class-design.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.13.1, at includes/admin/campaign-builder/panels/class-design.php

1,321 lines 55.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Design class management panel.
4 *
5 * @package Charitable
6 * @author David Bisset
7 * @copyright Copyright (c) 2023, WP Charitable LLC
8 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9 * @since 1.8.0
10 * @version 1.8.0
11 */
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 if ( ! class_exists( 'Charitable_Builder_Panel_Design' ) ) :
18
19 /**
20 * Design class management panel.
21 *
22 * @package Charitable
23 * @author David Bisset
24 * @copyright Copyright (c) 2023, WP Charitable LLC
25 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
26 * @since 1.8.0
27 * @version 1.8.0
28 */
29 class Charitable_Builder_Panel_Design extends Charitable_Builder_Panel {
30
31 /**
32 * Form data and settings.
33 *
34 * @since 1.8.0
35 *
36 * @var array
37 */
38 public $campaign_data;
39
40 /**
41 * Template addon labels data.
42 *
43 * @since 1.8.0
44 *
45 * @var array
46 */
47 private $addon_labels;
48
49 /**
50 * All systems go.
51 *
52 * @since 1.8.0
53 */
54 public function init() {
55
56 // Define panel information.
57 $this->name = esc_html__( 'Design', 'charitable' );
58 $this->slug = 'design';
59 $this->icon = 'panel_design.svg';
60 $this->order = 20;
61 $this->sidebar = true;
62
63 add_action( 'charitable_builder_fields', [ $this, 'fields' ] );
64 add_action( 'charitable_builder_fields_options', [ $this, 'fields_options' ] );
65 add_action( 'charitable_builder_preview', [ $this, 'preview' ] );
66
67 // Template for Campaign builder previews.
68 add_action( 'charitable_builder_print_footer_scripts', [ $this, 'design_preview_templates' ] );
69 }
70
71 /**
72 * Enqueue assets for the Design panel.
73 *
74 * @since 1.8.0
75 */
76 public function enqueues() {
77
78 $min = charitable_get_min_suffix();
79
80 wp_enqueue_script(
81 'charitable-builder-drag-fields',
82 charitable()->get_path( 'directory', false ) . "assets/js/campaign-builder/drag-fields{$min}.js",
83 [ 'charitable-builder' ],
84 charitable()->get_version(),
85 true
86 );
87 }
88
89 /**
90 * Output the Field panel sidebar.
91 *
92 * @since 1.8.0
93 */
94 public function panel_sidebar() {
95
96 // This should never be called unless we are on the campaign builder page.
97 if ( ! campaign_is_campaign_builder_admin_page() ) {
98 return;
99 }
100 ?>
101 <ul class="charitable-tabs charitable-clear">
102
103 <li class="charitable-tab" id="add-layout">
104 <a href="#" class="active">
105 <?php esc_html_e( 'Add Layout', 'charitable' ); ?>
106 </a>
107 </li>
108
109 <li class="charitable-tab" id="layout-options">
110 <a href="#">
111 <?php esc_html_e( 'Layout Options', 'charitable' ); ?>
112 </a>
113 </li>
114
115 </ul>
116
117
118 <?php
119
120 $display_tour_divs = Charitable_Campaign_Builder::get_instance()->display_tour_divs();
121
122 if ( $display_tour_divs ) :
123 ?>
124
125 <div id="charitable-tour-block-1" class="charitable-tour-block"></div>
126 <div id="charitable-tour-block-2" class="charitable-tour-block"></div>
127 <div id="charitable-tour-block-3" class="charitable-tour-block"></div>
128
129 <?php endif; ?>
130
131 <div class="charitable-add-fields charitable-tab-content">
132 <?php do_action( 'charitable_builder_fields', $this->campaign_data ); ?>
133 </div>
134
135 <div id="charitable-field-options" class="charitable-field-options charitable-tab-content">
136 <?php do_action( 'charitable_builder_fields_options', $this->campaign_data ); ?>
137 </div>
138
139 <?php
140 }
141
142 /**
143 * Output the Field panel primary content.
144 *
145 * @since 1.8.0
146 */
147 public function panel_content() {
148
149 // todo: think if there is campaign data to load if this is a brand new campaign?
150
151 $template_id = isset( $this->campaign_data['template_id'] ) ? esc_attr( $this->campaign_data['template_id'] ) : charitable_campaign_builder_default_template();
152 $campaign_id = isset( $this->campaign_data['campaign_id'] ) ? esc_attr( $this->campaign_data['campaign_id'] ) : false;
153 $campaign_title = isset( $this->campaign_data['title'] ) ? esc_html( $this->campaign_data['title'] ) : esc_html( $this->campaign->post_title );
154
155 $builder_template = new Charitable_Campaign_Builder_Templates();
156 $template_data = $builder_template->get_template_data( $template_id );
157
158 /* get status */
159 $campaign = $campaign_id ? charitable_get_campaign( $campaign_id ) : false;
160 $status = $campaign ? $campaign->get_status() : false;
161 if ( 'finished' === $status && $campaign->has_goal() ) {
162 $status = $campaign->has_achieved_goal() ? 'successful' : 'unsuccessful';
163 }
164 $campaign_status = $campaign ? '<mark class="charitable-builder-status-' . esc_attr( $status ) . '">' . $status . '</mark>' : false;
165
166 /* establish any classes to add to preview wrap upon load */
167 $preview_wrap_classes = array( 'charitable-preview-wrap' );
168 if ( ! empty( $this->campaign_data['layout']['advanced']['show_field_names'] ) && 'hide' === $this->campaign_data['layout']['advanced']['show_field_names'] ) {
169 $preview_wrap_classes[] = 'charitable-preview-hide-field-names';
170 }
171 if ( ! empty( $this->campaign_data['layout']['advanced']['preview_mode'] ) && 'minimum' === $this->campaign_data['layout']['advanced']['preview_mode'] ) {
172 $preview_wrap_classes[] = 'charitable-preview-minimum-preview';
173 }
174 $preview_wrap_classes = trim( implode( ' ', $preview_wrap_classes ) );
175 ?>
176
177 <div class="<?php echo esc_attr( $preview_wrap_classes ); ?>">
178
179 <div class="charitable-preview charitable-builder-template-<?php echo esc_attr( $template_id ); ?>">
180
181 <div class="charitable-preview-top-bar">
182 <div class="charitable-preview-top-bar-inner-left">
183 <h2 class="charitable-form-name">
184 <?php echo esc_html( stripslashes( $campaign_title ) ); ?>
185 </h2>
186 </div>
187 <div class="charitable-preview-top-bar-inner-right">
188 <?php if ( 0 !== intval( $campaign_id ) && $campaign_status && 'draft' !== $campaign_status ) : ?>
189 <span class="charitable-view-campaign-external-link"><a href="<?php echo esc_url( get_permalink( $campaign_id ) ); ?>" target="_blank" title="View Campaign Page"><?php /* <i class="fa fa-eye"></i> */ ?></a></span>
190 <?php endif; ?>
191 </div>
192 </div>
193
194 <div class="charitable-no-design-holder charitable-hidden"></div>
195
196 <div class="charitable-design-wrap" id="charitable-design-wrap">
197 <?php do_action( 'charitable_builder_preview', $this->campaign ); ?>
198 </div>
199
200 <?php
201 // This action is documented in includes/class-frontend.php.
202 do_action( 'charitable_display_submit_after', $this->campaign_data, 'submit' ); // phpcs:ignore Charitable.PHP.ValidateHooks.InvalidHookName
203
204 ?>
205
206 <?php charitable_builder_debug_data( $this->campaign_data ); ?>
207 </div>
208
209 </div>
210
211 <?php
212 }
213
214 /**
215 * Builder field buttons.
216 *
217 * @since 1.8.0
218 * @param array $campaign_data Campaign Data.
219 */
220 public function fields( $campaign_data = false ) {
221
222 $fields = [
223 'recommended' => [
224 'group_name' => esc_html__( 'Recommended', 'charitable' ),
225 'description' => false,
226 'fields' => [],
227 ],
228 'standard' => [
229 'group_name' => esc_html__( 'Standard', 'charitable' ),
230 'description' => false,
231 'fields' => [],
232 ],
233 'pro' => [
234 'group_name' => esc_html__( 'Pro', 'charitable' ),
235 'description' => false,
236 'fields' => [],
237 ],
238 ];
239
240 /**
241 * Allows developers to modify content of the the Add Field tab.
242 *
243 * With this filter developers can add their own fields or even fields groups.
244 *
245 * @since 1.8.0
246 *
247 * @param array $fields {
248 * Design data multidimensional array.
249 *
250 * @param array $recommended Recommended fields group.
251 * @param string $group_name Group name.
252 * @param array $fields Design array.
253 *
254 * @param array $standard Standard fields group.
255 * @param string $group_name Group name.
256 * @param array $fields Design array.
257 *
258 * @param array $pro Pro fields group.
259 * @param string $group_name Group name.
260 * @param array $fields Design array.
261 * }
262 */
263
264 $fields = apply_filters( 'charitable_builder_design_buttons', $fields );
265
266 // If there is campaign data, make a list of fields already in use which might determine what CSS classes (etC) gets passed to the buttons on the left.
267 $fields_in_template = array();
268 if ( false !== $campaign_data ) {
269 if ( ! empty( $campaign_data['layout']['rows'] ) ) {
270 foreach ( $campaign_data['layout']['rows'] as $row ) {
271 if ( ! empty( $row['fields'] ) ) {
272 $fields_in_template = array_merge( $fields_in_template, $row['fields'] );
273 }
274 }
275 }
276 }
277
278 $donation_form_display = charitable_get_option( 'donation_form_display' );
279
280 // Output the buttons.
281 foreach ( $fields as $id => $group ) {
282
283 usort( $group['fields'], [ $this, 'field_order' ] );
284
285 echo '<div class="charitable-add-fields-group charitable-add-fields-group-' . esc_attr( $id ) . '">';
286
287 echo '<a href="#" class="charitable-add-fields-heading charitable-add-fields-heading-' . esc_attr( $id ) . '" data-group="' . esc_attr( $id ) . '">';
288
289 echo '<span>' . esc_html( $group['group_name'] ) . '</span>';
290
291 if ( $group['description'] ) :
292 echo '<span class="charitable-group-description"><small>' . esc_html( $group['description'] ) . '</small></span>';
293 endif;
294
295 echo '<i class="fa fa-angle-down charitable-toggleable-group"></i>';
296
297 echo '</a>';
298
299 echo '<div class="charitable-group-rows"><div class="charitable-add-fields-buttons">';
300
301 foreach ( $group['fields'] as $field ) {
302
303 // If we are loading an already established campaign template, then the 'is the add button disabled' needs/should try to happen in the PHP rendering side.
304 $add_field_button_classes = array( 'charitable-add-fields-button' );
305 $maybe_disable_add_button = $this->maybe_disable_add_button( $field['type'], $fields_in_template, $campaign_data, $donation_form_display );
306
307 if ( ! empty( $campaign_data ) && false !== $maybe_disable_add_button ) {
308 $add_field_button_classes[] = 'charitable-disabled';
309
310 if ( strlen( $maybe_disable_add_button ) > 1 ) {
311 $add_field_button_classes[] = 'charitable-disabled' . $maybe_disable_add_button;
312 }
313 }
314
315 $add_field_button_classes[] = 'charitable-has-field';
316
317 /**
318 * Attributes of the form field button on the Add Design tab in the Campaign Builder.
319 *
320 * @since 1.8.0
321 *
322 * @param array $attributes Field attributes.
323 * @param array $field Field data.
324 * @param array $form_data Form data.
325 */
326 $atts = apply_filters(
327 'charitable_builder_field_button_attributes',
328 [
329 'id' => 'charitable-add-fields-' . $field['type'],
330 'class' => $add_field_button_classes,
331 'data' => [
332 'field-type' => $field['type'],
333 'field-icon' => $field['icon'],
334 ],
335 'font-prefix' => 'fa',
336 'atts' => [],
337 ],
338 $field,
339 $this->campaign_data,
340 $fields_in_template
341 );
342
343 if ( ! empty( $field['class'] ) ) {
344 $atts['class'][] = $field['class'];
345 }
346
347 echo '<div class="charitable-add-fields-button-wrap">';
348
349 // Deal with recommended checkmarks.
350 if ( 'recommended' === $id ) {
351 $checked_or_not = ( 'recommended' === $id && in_array( $field['type'], $fields_in_template, true ) ) ? 'checked' : 'unchecked';
352 echo '<div class="charitable-check ' . $checked_or_not . '"></div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
353 }
354
355 echo '<button ' . charitable_html_attributes( $atts['id'], $atts['class'], $atts['data'], $atts['atts'] ) . '>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
356 if ( $field['icon'] ) {
357 echo '<i class="' . esc_attr( $atts['font-prefix'] ) . ' ' . esc_attr( $field['icon'] ) . '"></i> ';
358 }
359 echo esc_html( $field['name'] );
360 echo '</button>';
361
362 echo '</div>';
363 }
364
365 echo '</div>
366 </div>';
367
368 echo '</div>';
369 }
370 }
371
372 /**
373 * Determine if we need to disable an add field button in the builder (left).
374 *
375 * @since 1.8.0
376 *
377 * @param string $button_type The type of button to check.
378 * @param bool $fields_in_template Whether the fields are in the template.
379 * @param bool $campaign_data The campaign data.
380 * @param bool $donation_form_display Whether the donation form is displayed.
381 */
382 public function maybe_disable_add_button( $button_type = '', $fields_in_template = false, $campaign_data = false, $donation_form_display = false ) {
383
384 if ( '' === trim( $button_type ) || false === $fields_in_template ) {
385 return false;
386 }
387
388 // If "modal" is set to true and the field is a form or donate amount, immedately reject because these elements shouldn't be available when the donation form is a modal.
389 if ( 'modal' === $donation_form_display ) {
390 if ( $button_type === 'donation-form' || $button_type === 'donate-amount' ) {
391 return '-modal';
392 }
393 } elseif ( 'same_page' === $donation_form_display ) {
394 if ( $button_type === 'donation-form' || $button_type === 'donate-amount' || $button_type === 'donate-button' ) {
395 return '-same_page';
396 }
397 }
398
399 // check the field deny list.
400 $deny_list = array(
401 'donation-form' => array(
402 'donate-button' => 0,
403 'donation-form' => 0,
404 'donate-amount' => 0,
405 ),
406 'donate-button' => array(
407 'donation-form' => 0,
408 ),
409 'donate-amount' => array(
410 'donation-form' => 0,
411 ),
412 );
413
414 // for example: donate-amount should be enabled unless donation form is present.
415 foreach ( $deny_list as $field_exists => $fields_to_check ) {
416 foreach ( $fields_to_check as $field_to_check => $field_amount_limit ) {
417 // if the key of the sub array isn't 'donate-amount' skip this.
418 if ( $field_to_check !== $button_type ) {
419 continue;
420 }
421
422 // ok, we found 'donate-amount' but 'donation-form' doesn't exist, so skip this.
423 if ( ! in_array( $field_exists, $fields_in_template, true ) ) {
424 continue;
425 }
426
427 $vals = array_count_values( $fields_in_template );
428
429 // ok if donation form exists determine how many 'donate-amount' are allowed to exist before disabling the add field in the builder.
430 if ( isset( $vals[ $field_to_check ] ) && $field_amount_limit <= $vals[ $field_to_check ] ) {
431 return true;
432 }
433 }
434 }
435
436 return false;
437 }
438
439 /**
440 * Editor Field Options.
441 *
442 * @since 1.8.0
443 */
444 public function fields_options() {
445
446 // Check to make sure the form actually has fields created already.
447 if ( empty( $this->campaign_data['design'] ) ) {
448 $this->general_design_options();
449
450 return;
451 }
452
453 $fields = $this->campaign_data['design'];
454
455 foreach ( $fields as $field ) {
456
457 $class = apply_filters( 'charitable_builder_field_option_class', '', $field );
458
459 printf( '<div class="charitable-design-option charitable-design-option-%s %s" id="charitable-design-option-%d" data-design-id="%d">', sanitize_html_class( $field['type'] ), charitable_sanitize_classes( $class ), (int) $field['id'], (int) $field['id'] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
460
461 printf( '<input type="hidden" name="fields[%d][id]" value="%d" class="charitable-design-option-hidden-id">', (int) $field['id'], (int) $field['id'] );
462
463 printf( '<input type="hidden" name="fields[%d][type]" value="%s" class="charitable-design-option-hidden-type">', (int) $field['id'], esc_attr( $field['type'] ) );
464
465 do_action( "charitable_builder_design_options_{$field['type']}", $field );
466
467 echo '</div>';
468 }
469 }
470
471 /**
472 * Generate HTML for hidden inputs from given data.
473 *
474 * @since 1.8.0
475 *
476 * @param array $data Field array data.
477 * @param string $name Input name prefix.
478 */
479 private function generate_hidden_inputs( $data = [], $name = '' ) {
480
481 if ( ! is_array( $data ) || empty( $data ) ) {
482 return;
483 }
484
485 foreach ( $data as $key => $value ) {
486 if ( $key === 'id' ) {
487 continue;
488 }
489
490 $key = ! empty( $data['id'] ) ? sprintf( '[%s][%s]', $data['id'], $key ) : sprintf( '[%s]', $key );
491
492 if ( ! empty( $name ) ) {
493 $key = trim( $name ) . $key;
494 }
495
496 if ( is_array( $value ) ) {
497 $this->generate_hidden_inputs( $value, $key );
498 } else {
499 printf( "<input type='hidden' name='%s' value='%s' />", esc_attr( $key ), esc_attr( $value ) );
500 }
501 }
502 }
503
504 /**
505 * No fields options markup.
506 *
507 * @since 1.6.0
508 */
509 public function no_design_options() {
510
511 printf(
512 '<p class="no-design charitable-alert charitable-alert-warning">%s</p>',
513 esc_html__( 'You don\'t have any fields yet.', 'charitable' )
514 );
515 }
516
517 /**
518 * No fields preview placeholder markup.
519 *
520 * @since 1.8.0
521 */
522 public function no_design_preview() {
523 }
524
525 /**
526 * No fields options markup.
527 *
528 * @since 1.8.0
529 */
530 public function general_design_options() {
531
532 // layout options
533 // -> general.
534 // -> advanced.
535
536 $tabs = isset( $this->campaign_data['tabs'] ) ? $this->campaign_data['tabs'] : false;
537 $max_tab_title_length = apply_filters( 'charitable_builder_design_tab_title_length', 20 );
538
539 ?>
540
541 <!-- sub tab -->
542 <div class="charitable-layout-options-tab charitable-layout-options-tab-general active" id="">
543 <a href="#" class="charitable-group-toggle charitable-layout-options-group-toggle"><?php echo esc_html__( 'General', 'charitable' ); ?></a>
544 <!-- container -->
545 <div class="charitable-layout-options-group-inner">
546
547 <div class="charitable-select-field-notice"><?php echo esc_html__( 'Select a field in the preview area to set it\'s settings.', 'charitable' ); ?></div>
548 <?php
549
550 if ( ! empty( $this->campaign_data['layout']['rows'] ) ) :
551
552 foreach ( $this->campaign_data['layout']['rows'] as $row_id => $row ) :
553
554 // header.
555 if ( isset( $row['fields'] ) ) {
556
557 $row_type = $row['type'];
558
559 if ( 'row' === $row_type || 'header' === $row_type ) {
560
561 foreach ( $row['fields'] as $field_id => $field_type ) {
562
563 $type = 'Charitable_Field_' . str_replace( ' ', '_', ( ucwords( str_replace( '-', ' ', $field_type ) ) ) );
564
565 if ( class_exists( $type ) ) :
566 $class = new $type();
567 if ( method_exists( $class, 'settings_display' ) ) {
568 echo $class->settings_display( $field_id, $this->campaign_data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
569 }
570 endif;
571 }
572 } elseif ( 'tabs' === $row_type ) {
573
574 foreach ( $row['tabs'] as $tab_id => $tab ) {
575
576 foreach ( $tab as $field_id_key => $field_id ) {
577
578 $field_type = $this->campaign_data['layout']['rows'][ $row_id ]['fields'][ $field_id ];
579
580 $type = 'Charitable_Field_' . str_replace( ' ', '_', ( ucwords( str_replace( '-', ' ', $field_type ) ) ) );
581
582 if ( class_exists( $type ) ) :
583 $class = new $type();
584 if ( method_exists( $class, 'settings_display' ) ) {
585 echo $class->settings_display( $field_id, $this->campaign_data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
586 }
587 endif;
588 }
589 }
590 }
591 }
592
593 endforeach;
594
595 endif;
596 ?>
597 </div>
598 </div> <!-- end tab -->
599
600 <!-- sub tab -->
601 <div class="charitable-layout-options-tab charitable-layout-options-tab-tabs" id="">
602 <a href="#" class="charitable-group-toggle charitable-layout-options-tabs-toggle"><?php echo esc_html__( 'Tabs', 'charitable' ); ?></a>
603 <!-- container -->
604 <div class="charitable-layout-options-group-inner class-design">
605
606 <?php $enable_tabs = isset( $this->campaign_data['layout']['advanced']['enable_tabs'] ) && '' !== trim( $this->campaign_data['layout']['advanced']['enable_tabs'] ) ? $this->campaign_data['layout']['advanced']['enable_tabs'] : 'enabled'; ?>
607
608 <div data-field-id="" id="charitable-group-row-design-layout-options-tabs-enable" class="charitable-panel-field charitable-panel-field-toggle " data-ajax-label="enable_tabs">
609 <span class="charitable-toggle-control">
610 <input type="checkbox" id="charitable-panel-field-settings-charitable-campaign-enable-tabs" name="layout__advanced__enable_tabs" data-advanced-field-id="enable_tabs" value="disabled" <?php checked( $enable_tabs, 'disabled' ); ?> />
611 <label class="charitable-toggle-control-icon" for="charitable-panel-field-settings-charitable-campaign-enable-tabs"></label>
612 <label for="charitable-panel-field-settings-charitable-campaign-enable-tabs"><?php echo esc_html__( 'Hide All Tabs.', 'charitable' ); ?> </label>
613 <?php echo charitable_get_tooltip_html( __( 'Turn this on to remove tabs from your campaign page.', 'charitable' ), 'tooltipstered' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
614 </span>
615 </div>
616
617 <hr />
618
619 <!-- group -->
620 <div class="charitable-group charitable-layout-options-tab-group charitable-closed charitable-new-tab hidden" data-group_id="2">
621 <div class="charitable-general-layout-heading" data-group="general-layout-tab">
622 <a href="#" class="charitable-draggable"><i class="fa fa-bars"></i></a>
623 <span>[ <?php echo esc_html__( 'New Tab', 'charitable' ); ?> ]</span>
624 <a href="#" class="charitable-toggleable-group"><i class="fa fa-angle-down charitable-angle-down"></i></a>
625 <a href="#" class="charitable-tab-group-delete" title="Delete Tab"><i class="fa fa-trash-o" aria-hidden="true"></i></a>
626
627 </div>
628 <!-- rows -->
629 <div class="charitable-group-rows">
630 <!-- row -->
631 <div class="charitable-group-row charitable-tab-title-row" id="tabs_xxx_row_title" data-field-id="">
632 <label for=""><?php echo esc_html__( 'Title', 'charitable' ); ?>
633 <?php echo charitable_get_tooltip_html( __( 'Title appears on the tab in the tab navigation.', 'charitable' ), 'tooltipstered' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
634 <input type="text" class="" id="tabs_xxx_title" name="tabs__xxx__title" value="" placeholder="<?php echo esc_html__( 'Tab Title', 'charitable' ); ?> " maxlength="<?php echo intval( $max_tab_title_length ); ?>">
635 </div>
636 <div class="charitable-group-row charitable-tab-title-row" id="tabs_xxx_row_visible_nav" data-tab-id="">
637 <span class="charitable-toggle-control">
638 <input type="checkbox" id="tabs_xxx_visible_nav" class="charitable-settings-tab-visible-nav" name="tabs__xxx__visible_nav" value="invisible" />
639 <label class="charitable-toggle-control-icon" for="tabs_xxx_visible_nav"></label>
640 <label for="tabs_xxx_visible_nav"><?php echo esc_html__( 'Hide tab navigation.', 'charitable' ); ?></label>
641 <?php echo charitable_get_tooltip_html( __( 'Hide the tab in the navigation bar (only if you have one tab in your design).', 'charitable' ), 'tooltipstered' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
642 </span>
643 </div>
644 </div>
645 <!-- end rows -->
646 </div> <!-- end group -->
647 <?php
648
649 // This outputs the tab interface in layout options -> tabs.
650
651 if ( $tabs ) {
652
653 $counter = 0;
654
655 $number_of_tabs = count( $tabs );
656 $hide_tab_nav_disabled = $number_of_tabs > 1 ? 'disabled="disabled"' : false;
657
658 foreach ( $tabs as $tab_id => $tab_info ) :
659
660 $group_id = ( strtolower( $tab_id ) === 'campaign' ) ? 0 : $tab_id;
661 $group_name_var = ( $tab_id === 'campaign' ) ? $group_id : $group_id;
662 $group_title = isset( $tab_info['title'] ) && '' !== trim( $tab_info['title'] ) ? $tab_info['title'] : '[ New Tab ]';
663 $group_header = ( $tab_id === 'campaign' ) ? 'Campaign' : $group_title;
664 $group_desc = isset( $tab_info['desc'] ) && '' !== trim( $tab_info['desc'] ) ? $tab_info['desc'] : false;
665 $group_classes = isset( $tab_info['title'] ) && '' !== trim( $tab_info['title'] ) ? false : 'charitable-new-tab';
666 $data_group = ( $tab_id === 'campaign' ) ? 'general-layout-tab' : 'general-layout-tab';
667 $active = $counter === 0 ? 'active' : false;
668 $closed = $counter === 0 ? 'charitable-open' : 'charitable-closed';
669 $arrow_icon = ! $active ? 'fa fa-angle-down charitable-angle-right' : 'fa fa-angle-down charitable-angle-down';
670 $type = ( isset( $tab_info['type'] ) && '' !== trim( $tab_info['type'] ) ) ? $tab_info['type'] : 'html';
671 $row_class = 'html' !== $type ? 'hidden' : false;
672
673 $visible_nav = ! empty( $tab_info['visible_nav'] ) && 'invisible' === $tab_info['visible_nav'] ? 'checked="checked"' : '';
674 $visible_nav_checked = ! empty( $tab_info['visible_nav'] ) && 'invisible' === $tab_info['visible_nav'] ? 'checked="checked"' : '';
675 $visible_nav_checked = ( false !== $hide_tab_nav_disabled ) ? '' : $visible_nav_checked;
676 $disabled_css = ( false !== $hide_tab_nav_disabled ) ? 'charitable-disabled' : false;
677
678 ?>
679
680 <!-- group -->
681 <div class="charitable-group charitable-layout-options-tab-group <?php echo esc_attr( $group_classes ); ?> <?php echo esc_attr( $closed ); ?> <?php echo esc_attr( $active ); ?>" data-group_id="<?php echo esc_attr( $group_id ); ?>">
682 <div class="charitable-general-layout-heading" data-group="<?php echo esc_attr( $data_group ); ?>">
683 <a href="#" class="charitable-draggable"><i class="fa fa-bars"></i></a>
684 <span><?php echo esc_html( $group_header ); ?></span>
685 <a href="#" class="charitable-toggleable-group"><i class="<?php echo esc_attr( $arrow_icon ); ?>"></i></a>
686 <a href="#" class="charitable-tab-group-delete" title="Delete Tab"><i class="fa fa-trash-o" aria-hidden="true"></i></a>
687
688 </div>
689 <!-- rows -->
690 <div class="charitable-group-rows">
691 <!-- row -->
692 <div class="charitable-group-row charitable-tab-title-row" id="row_tabs__<?php echo esc_attr( $group_name_var ); ?>__title" data-tab-id="<?php echo esc_attr( $group_name_var ); ?>">
693 <label for=""><?php echo esc_html__( 'Title', 'charitable' ); ?> <?php echo charitable_get_tooltip_html( false, 'tooltipstered' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
694 <input type="text" class="" id="" name="tabs__<?php echo esc_attr( $group_name_var ); ?>__title" value="<?php echo esc_attr( $group_title ); ?>" placeholder="" maxlength="<?php echo intval( $max_tab_title_length ); ?>">
695 </div>
696 <div class="charitable-group-row charitable-tab-title-row" id="row_tabs__<?php echo esc_attr( $group_name_var ); ?>__visible_nav" data-tab-id="<?php echo esc_attr( $group_name_var ); ?>">
697 <span class="charitable-toggle-control">
698 <input type="checkbox" id="charitable-panel-field-settings-charitable-campaign-<?php echo esc_attr( $group_name_var ); ?>__visible_nav" class="charitable-settings-tab-visible-nav"
699 name="tabs__<?php echo esc_attr( $group_name_var ); ?>__visible_nav" value="invisible" <?php echo esc_attr( $visible_nav_checked ); ?> />
700 <label class="charitable-toggle-control-icon" for="charitable-panel-field-settings-charitable-campaign-<?php echo esc_attr( $group_name_var ); ?>__visible_nav"></label>
701 <label class="<?php echo esc_attr( $disabled_css ); ?>" for="charitable-panel-field-settings-charitable-campaign-<?php echo esc_attr( $group_name_var ); ?>__visible_nav"><?php echo esc_html__( 'Hide tab navigation.', 'charitable' ); ?></label>
702 <?php echo charitable_get_tooltip_html( __( 'Hide the tab in the navigation bar (only if you have one tab in your design).', 'charitable' ), 'tooltipstered' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
703 </span>
704 </div>
705 <!-- row -->
706 </div>
707 <!-- end rows -->
708 </div> <!-- end group -->
709
710 <?php ++$counter; ?>
711
712 <?php
713 endforeach;
714
715 }
716
717 ?>
718 <!-- button -->
719 <button class="charitable-tab-groups-add charitable-btn charitable-btn-sm"><?php echo esc_html__( '+ Add New Tab', 'charitable' ); ?></button>
720 <!-- end button -->
721 </div> <!-- end container -->
722 </div> <!-- end tab -->
723
724 <?php
725
726 $tab_style = isset( $this->campaign_data['layout']['advanced']['tab_style'] ) && '' !== trim( $this->campaign_data['layout']['advanced']['tab_style'] ) ? $this->campaign_data['layout']['advanced']['tab_style'] : 'boxed';
727 $tab_size = isset( $this->campaign_data['layout']['advanced']['tab_size'] ) && '' !== trim( $this->campaign_data['layout']['advanced']['tab_size'] ) ? $this->campaign_data['layout']['advanced']['tab_size'] : 'medium';
728 $preview_mode = isset( $this->campaign_data['layout']['advanced']['preview_mode'] ) && '' !== trim( $this->campaign_data['layout']['advanced']['preview_mode'] ) ? $this->campaign_data['layout']['advanced']['preview_mode'] : 'normal';
729
730 $show_field_names_default = charitable_show_field_names_by_default() ? 'show' : 'hide';
731 $show_field_names = isset( $this->campaign_data['layout']['advanced']['show_field_names'] ) && '' !== trim( $this->campaign_data['layout']['advanced']['show_field_names'] ) ? $this->campaign_data['layout']['advanced']['show_field_names'] : $show_field_names_default;
732
733 // todo: filter these.
734
735 $theme_color_primary = isset( $this->campaign_data['layout']['advanced']['theme_color_primary'] ) && '' !== trim( $this->campaign_data['layout']['advanced']['theme_color_primary'] ) ? $this->campaign_data['layout']['advanced']['theme_color_primary'] : '';
736 $theme_color_secondary = isset( $this->campaign_data['layout']['advanced']['theme_color_secondary'] ) && '' !== trim( $this->campaign_data['layout']['advanced']['theme_color_secondary'] ) ? $this->campaign_data['layout']['advanced']['theme_color_secondary'] : '';
737 $theme_color_tertiary = isset( $this->campaign_data['layout']['advanced']['theme_color_tertiary'] ) && '' !== trim( $this->campaign_data['layout']['advanced']['theme_color_tertiary'] ) ? $this->campaign_data['layout']['advanced']['theme_color_tertiary'] : '';
738 $theme_color_button = isset( $this->campaign_data['layout']['advanced']['theme_color_button'] ) && '' !== trim( $this->campaign_data['layout']['advanced']['theme_color_button'] ) ? $this->campaign_data['layout']['advanced']['theme_color_button'] : '';
739
740 // tab enabled/disabled.
741 $enable_tabs_css = isset( $this->campaign_data['layout']['advanced']['enable_tabs'] ) && '' !== trim( $this->campaign_data['layout']['advanced']['enable_tabs'] ) ? 'disabled' : '';
742
743 ?>
744
745 <!-- sub tab -->
746 <div class="charitable-layout-options-tab charitable-layout-options-tab-advanced" id="">
747 <a href="#" class="charitable-group-toggle charitable-layout-options-group-toggle"><?php echo esc_html__( 'Advanced', 'charitable' ); ?> </a>
748 <!-- container -->
749 <div class="charitable-layout-options-group-inner">
750 <!-- group -->
751 <div class="charitable-group charitable-layout-options-advanced-group">
752 <!-- rows -->
753 <div class="charitable-group-rows row-first">
754 <!-- row -->
755 <div class="charitable-group-row" id="charitable-group-row-design-layout-options-advanced-tab-style">
756 <label for="charitable-design-layout-options-advanced-tab-style"><?php echo esc_html__( 'Tab Style', 'charitable' ); ?> <?php echo charitable_get_tooltip_html( esc_html__( 'Overall tab size in the template.', 'charitable' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
757 </label>
758 <select class="charitable-design-layout-options-advanced-tab-style <?php echo esc_attr( $enable_tabs_css ); ?>" id="charitable-design-layout-options-advanced-tab-style" name="layout__advanced__tab_style" data-advanced-field-id="tab_style" <?php echo esc_attr( $enable_tabs_css ); ?>>
759 <option value="boxed" <?php selected( $tab_style, 'boxed' ); ?>><?php echo esc_html__( 'Boxed', 'charitable' ); ?></option>
760 <option value="rounded" <?php selected( $tab_style, 'rounded' ); ?>><?php echo esc_html__( 'Rounded', 'charitable' ); ?></option>
761 <option value="minimum" <?php selected( $tab_style, 'minimum' ); ?>><?php echo esc_html__( 'Minimum', 'charitable' ); ?></option>
762 </select>
763 </div>
764 <!-- row -->
765 <div class="charitable-group-row" id="charitable-group-row-design-layout-options-advanced-tab-size">
766 <label for="charitable-design-layout-options-advanced-tab-size"><?php echo esc_html__( 'Tab Size', 'charitable' ); ?> <?php echo charitable_get_tooltip_html( esc_html__( 'Overall text size inside the tab.', 'charitable' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
767 </label>
768 <select class="charitable-design-layout-options-advanced-tab-size <?php echo esc_attr( $enable_tabs_css ); ?>" id="charitable-design-layout-options-advanced-tab-size" name="layout__advanced__tab_size" data-advanced-field-id="tab_size" <?php echo esc_attr( $enable_tabs_css ); ?>>
769 <option value="small" <?php selected( $tab_size, 'small' ); ?>><?php echo esc_html__( 'Small', 'charitable' ); ?></option>
770 <option value="medium" <?php selected( $tab_size, 'medium' ); ?>><?php echo esc_html__( 'Medium', 'charitable' ); ?></option>
771 <option value="large" <?php selected( $tab_size, 'large' ); ?>><?php echo esc_html__( 'Large', 'charitable' ); ?></option>
772 </select>
773 </div>
774 <!-- row -->
775 <div class="charitable-group-row" id="charitable-group-row-design-layout-options-advanced-show-field-names">
776 <label for="charitable-design-layout-options-advanced-show-field-names"><?php echo esc_html__( 'Field Names', 'charitable' ); ?> <?php echo charitable_get_tooltip_html( esc_html__( 'Show the text that shows the field types in the preview area..', 'charitable' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
777 </label>
778 <select class="charitable-design-layout-options-show-field-names" id="charitable-design-layout-options-show-field-names" name="layout__advanced__show_field_names" data-advanced-field-id="show_field_names">
779 <option value="show" <?php selected( $show_field_names, 'show' ); ?>><?php echo esc_html__( 'Show', 'charitable' ); ?></option>
780 <option value="hide" <?php selected( $show_field_names, 'hide' ); ?>><?php echo esc_html__( 'Hide', 'charitable' ); ?></option>
781 </select>
782 </div>
783 <!-- row -->
784 <div class="charitable-group-row" id="charitable-group-row-design-layout-options-advanced-preview-mode">
785 <label for="charitable-design-layout-options-advanced-preview-mode"><?php echo esc_html__( 'Preview Mode', 'charitable' ); ?> <?php echo charitable_get_tooltip_html( esc_html__( 'Show the text that shows the field types in the preview area..', 'charitable' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
786 </label>
787 <select class="charitable-design-layout-options-preview-mode" id="charitable-design-layout-options-preview-mode" name="layout__advanced__preview_mode" data-advanced-field-id="preview_mode">
788 <option value="normal" <?php selected( $preview_mode, 'normal' ); ?>><?php echo esc_html__( 'Normal', 'charitable' ); ?></option>
789 <option value="minimum" <?php selected( $preview_mode, 'minimum' ); ?>><?php echo esc_html__( 'Minimum', 'charitable' ); ?></option>
790 </select>
791 </div>
792 <!-- row -->
793 <div class="charitable-group-row" id="charitable-group-row-design-layout-options-advanced-theme-colors">
794
795 <label for="charitable-design-layout-options-advanced-theme-colors"><?php echo esc_html__( 'Theme Colors', 'charitable' ); ?> <?php echo charitable_get_tooltip_html( esc_html__( 'Adjust the primary colors of the theme.', 'charitable' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
796 </label>
797
798 <div class="charitable-group-row">
799
800 <div class="charitable-design-layout-options-advanced-theme-color coloris-layout primary" data-label="<?php echo esc_html__( 'Primary:', 'charitable' ); ?>">
801 <label for="layout__advanced__theme_color_primary"><?php echo esc_html__( 'Primary', 'charitable' ); ?></label>
802 <input type="text" class="coloris instance2 primary" name="layout__advanced__theme_color_primary" data-label="primary" value="<?php echo esc_attr( $theme_color_primary ); ?>" />
803 <!-- <a class="reset-link" href="#"><?php echo esc_html__( 'Reset', 'charitable' ); ?></a> -->
804 </div>
805 <div class="charitable-design-layout-options-advanced-theme-color coloris-layout secondary" data-label="<?php echo esc_html__( 'Secondary:', 'charitable' ); ?>">
806 <label for="layout__advanced__theme_color_secondary"><?php echo esc_html__( 'Secondary', 'charitable' ); ?></label>
807 <input type="text" class="coloris instance2 secondary" name="layout__advanced__theme_color_secondary" data-label="secondary" value="<?php echo esc_attr( $theme_color_secondary ); ?>" />
808 <!-- <a class="reset-link" href="#"><?php echo esc_html__( 'Reset', 'charitable' ); ?></a> -->
809 </div>
810 <div class="charitable-design-layout-options-advanced-theme-color coloris-layout tertiary" data-label="<?php echo esc_html__( 'Tertiary:', 'charitable' ); ?>">
811 <label for="layout__advanced__theme_color_tertiary"><?php echo esc_html__( 'Tertiary', 'charitable' ); ?></label>
812 <input type="text" class="coloris instance2 tertiary" name="layout__advanced__theme_color_tertiary" data-label="tertiary" value="<?php echo esc_attr( $theme_color_tertiary ); ?>" />
813 <!-- <a class="reset-link" href="#"><?php echo esc_html__( 'Reset', 'charitable' ); ?></a> -->
814 </div>
815 <div class="charitable-design-layout-options-advanced-theme-color coloris-layout button-color" data-label="<?php echo esc_html__( 'Button:', 'charitable' ); ?>">
816 <label for="layout__advanced__theme_color_button"><?php echo esc_html__( 'Button', 'charitable' ); ?></label>
817 <input type="text" class="coloris instance2 button-color" name="layout__advanced__theme_color_button" data-label="button" value="<?php echo esc_attr( $theme_color_button ); ?>" />
818 <!-- <a class="reset-link" href="#"><?php echo esc_html__( 'Reset', 'charitable' ); ?></a> -->
819 </div>
820 </div>
821
822 </div>
823 <!-- row -->
824 </div>
825 <!-- end rows -->
826 </div>
827 </div> <!-- end container -->
828 </div> <!-- end tab -->
829
830 <?php
831 }
832
833 /**
834 * Returns the starting HTML element for a given template type.
835 *
836 * @since 1.8.0
837 *
838 * @param string $type The type of template element to retrieve.
839 * @param int $counter The counter for the template element.
840 * @param string $additional_css Additional CSS classes to add to the template element.
841 * @param array $campaign_data An array of campaign data to pass to the template element.
842 * @return string The starting HTML element for the given template type.
843 */
844 public function get_template_element_start( $type = 'row', $counter = 1, $additional_css = '', $campaign_data = array(), $background_image = '', $locked = false ) {
845
846 ob_start();
847
848 $counter = intval( $counter );
849 $type = esc_attr( $type );
850
851 $row_bg_url = '' !== $background_image ? esc_url( $background_image ) : '';
852 $row_style_attr = '' !== $row_bg_url ? ' style="background-image:url(\'' . $row_bg_url . '\');"' : '';
853 $row_locked_css = $locked ? ' is-locked' : '';
854 $row_locked_attr = $locked ? ' data-row-locked="1"' : '';
855 $row_bg_css = '' !== $row_bg_url ? ' has-background-image' : '';
856
857 switch ( $type ) {
858 case 'header':
859 ?>
860 <!-- charitable header start -->
861 <header id="charitable-preview-header-<?php echo intval( $counter ); ?>"<?php echo $row_locked_attr; // phpcs:ignore ?> class="charitable-preview-header <?php echo esc_attr( $additional_css ); ?><?php echo esc_attr( $row_bg_css . $row_locked_css ); ?>"<?php echo $row_style_attr; // phpcs:ignore ?>>
862 <div class="row" data-row-id="<?php echo intval( $counter ); ?>" data-row-type="<?php echo esc_attr( $type ); ?>" data-row-css="<?php echo esc_attr( $additional_css ); ?>">
863 <?php
864 break;
865
866 case 'tabs':
867 $enable_tabs_css = isset( $campaign_data['layout']['advanced']['enable_tabs'] ) && '' !== trim( $campaign_data['layout']['advanced']['enable_tabs'] ) ? 'disabled' : '';
868 ?>
869 <!-- charitable tabs start -->
870 <article id="charitable-preview-tab-container" class="charitable-preview-tab-container <?php echo $enable_tabs_css; ?>"> <?php // phpcs:ignore ?>
871 <a href="#" class="charitable-hover-button charitable-field-edit" title="<?php echo esc_html__( 'Edit Area', 'charitable' ); ?>"><i class="fa fa-pencil"></i></a>
872 <?php
873 break;
874
875 default:
876 // likely a row.
877 ?>
878 <!-- charitable row/default start -->
879 <div id="charitable-preview-row-<?php echo $counter; ?>"<?php echo $row_locked_attr; // phpcs:ignore ?> class="charitable-preview-row <?php echo $additional_css; // phpcs:ignore ?><?php echo esc_attr( $row_bg_css . $row_locked_css ); ?>"<?php echo $row_style_attr; // phpcs:ignore ?>>
880 <div class="row" data-row-id="<?php echo $counter; ?>" data-row-type="<?php echo esc_attr( $type ); ?>" data-row-css="<?php echo $additional_css; // phpcs:ignore ?>">
881 <?php
882 break;
883 }
884
885 return ob_get_clean();
886 }
887
888 /**
889 * Create closing HTML tags based on the type.
890 *
891 * @since 1.8.0
892 *
893 * @param string $type The type of template element to retrieve.
894 * @param int $counter The counter for the template element.
895 * @return string The closing HTML element for the given template type.
896 */
897 public function get_template_element_end( $type = 'row', $counter = 1 ) {
898
899 ob_start();
900
901 switch ( $type ) {
902 case 'header':
903 ?>
904 </div>
905 </header>
906 <!-- charitable header end -->
907 <?php
908 break;
909
910 case 'tabs':
911 ?>
912 </article>
913 <!-- charitable tabs end -->
914 <?php
915 break;
916
917 default:
918 // likely a row.
919 ?>
920 </div>
921 </div>
922 <!-- charitable row/default end -->
923 <?php
924 break;
925 }
926
927 return ob_get_clean();
928 }
929
930 /**
931 * Generate preview of campaign in the admin campaign builder (right side).
932 *
933 * @since 1.8.0
934 */
935 public function preview() {
936
937 if ( ! is_admin() ) {
938 return;
939 }
940
941 $builder_template = new Charitable_Campaign_Builder_Templates();
942
943 ob_start();
944
945 $rows = (array) isset( $this->campaign_data['layout'] ) && ! empty( $this->campaign_data['layout']['rows'] ) ? $this->campaign_data['layout']['rows'] : array();
946 $theme = ! empty( $rows ) && ! empty( $this->campaign_data['template_id'] ) ? $builder_template->get_template_data( $this->campaign_data['template_id'] ) : false;
947
948 /*
949 * Apply the template's own description for a brand-new campaign, exactly as the
950 * settings panel does (1.8.13.1).
951 *
952 * Without this, the two disagreed: the panel seeded the description box from the
953 * template while this paint did not, so for any template shipping a description
954 * that differs from its description FIELD's `content`,
955 * Charitable_Field_Campaign_Description::render() took the `content` fallback here
956 * and the description branch there. The preview showed one text on page load and
957 * switched to the other the moment the field was clicked.
958 *
959 * New campaigns only, and render-only -- see
960 * Charitable_Campaign_Builder_Templates::maybe_apply_template_description() for why
961 * a campaign that has ever been saved is never touched.
962 */
963 if ( ! empty( $this->campaign_data['template_id'] ) ) {
964 $this->campaign_data = $builder_template->maybe_apply_template_description(
965 $this->campaign_data,
966 $this->campaign_data['template_id']
967 );
968 }
969
970 $element_counter = 0;
971 $column_counter = 0;
972 $section_counter = 0;
973 $last_field_id = 0;
974
975 ?>
976
977 <div class="charitable-campaign-preview container">
978
979 <?php
980
981 if ( ! empty( $rows ) ) :
982
983 foreach ( $rows as $row_id => $row ) :
984
985 $additional_css = ! empty( $row['css_class'] ) ? esc_attr( $row['css_class'] ) : '';
986 $row_bg_image = ! empty( $row['background_image'] ) ? $row['background_image'] : '';
987 $row_locked = ! empty( $row['locked'] );
988
989 echo $this->get_template_element_start( $row['type'], intval( $row_id ), esc_html( $additional_css ), $this->campaign_data, $row_bg_image, $row_locked ); // phpcs:ignore
990
991 foreach ( $row['columns'] as $column_id => $column ) :
992
993 echo '<!-- column START -->';
994
995 echo '<div data-column-id="' . intval( $column_counter ) . '" class="column charitable-field-column">';
996
997 if ( ! empty( $column['sections'] ) ) {
998
999 $section_css_class = 'charitable-field-target-inactive';
1000 $is_section_empty = true;
1001
1002 // do a initial look to see if all sections in this column have no fields, and add the default CSS class accordingly.
1003 foreach ( $column['sections'] as $section_id => $section ) {
1004 $is_section_empty = ( $section['type'] === 'tabs' ) || ( $section['type'] === 'fields' && ! empty( $section['fields'] ) ) ? false : $is_section_empty;
1005 }
1006
1007 foreach ( $column['sections'] as $section_id => $section ) {
1008
1009 echo '<!-- section START -->';
1010
1011 $section_css_class = $is_section_empty ? 'charitable-field-target' : 'charitable-field-target-inactive';
1012 $section_css_class = ( ! empty( $row['css_class'] ) && strpos( $row['css_class'], 'no-field-target' ) !== false ) ? false : $section_css_class;
1013 $section_css_class_no_wrap = empty( $row['css_class'] ) || strpos( $row['css_class'], 'no-field-wrap' ) === false ? ' charitable-field-wrap' : '';
1014 $section_css_class_no_wrap = ( $section['type'] === 'tabs' ) ? '' : $section_css_class_no_wrap;
1015
1016 echo '<div data-section-id="' . intval( $section_counter ) . '" data-section-type="' . esc_attr( $section['type'] ) . '" class="section charitable-field-section ' . esc_attr( $section_css_class ) . ' ' . esc_attr( $section_css_class_no_wrap ) . '">';
1017
1018 echo '<div class="charitable-drag-new-block-here"><p>Drag New Block Here.</p></div>';
1019
1020 switch ( $section['type'] ) {
1021 case 'fields':
1022 $this->render_fields( $section['fields'], $theme, $this->campaign_data, $row['fields'], $row_locked );
1023 break;
1024 case 'header':
1025 $this->render_fields( $section['fields'], $theme, $this->campaign_data, $row['fields'], $row_locked );
1026 break;
1027 case 'tabs':
1028 echo $this->get_template_element_start( 'tabs', null, null, $this->campaign_data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1029 echo $builder_template->get_template_tab_nav( $section['tabs'], $theme, $this->campaign_data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1030 $last_field_id = $builder_template->get_template_tab_content( $section['tabs'], $theme, $this->campaign_data, $row['fields'], $last_field_id );
1031 echo $this->get_template_element_end( 'tabs' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1032 break;
1033 default:
1034 do_action( 'charitable_campaign_builder_preview_section_' . $section['type'], $section, $row, $theme, $this->campaign_data );
1035 break;
1036 }
1037
1038 ++$section_counter;
1039
1040 echo '</div>';
1041
1042 echo '<!-- section END -->';
1043
1044 }
1045 } else {
1046
1047 $section_css_class = ( empty( $row['css_class'] ) || strpos( $row['css_class'], 'no-field-target' ) === false ) ? 'charitable-field-target' : false;
1048
1049 echo '<div data-section-id="' . intval( $section_counter ) . '" data-section-type="fields" class="section charitable-field-section charitable-field-wrap ' . esc_attr( $section_css_class ) . '">';
1050
1051 echo '<div class="charitable-drag-new-block-here"><p>Drag New Block Here.</p></div>';
1052
1053 ++$section_counter;
1054
1055 echo '</div>';
1056
1057 echo '<!-- section END -->';
1058
1059 }
1060
1061 ++$column_counter;
1062
1063 echo '</div>';
1064
1065 echo '<!-- column END -->';
1066
1067 endforeach;
1068
1069 echo $this->get_template_element_end( $row['type'], intval( $element_counter ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1070
1071 ++$element_counter;
1072
1073 endforeach;
1074
1075 endif;
1076
1077 ?>
1078
1079 </div>
1080
1081 <?php
1082
1083 $preview = ob_get_clean();
1084
1085 echo $preview; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1086 }
1087
1088 /**
1089 * Create fields for preview area based on an array, usually for a column of the layout.
1090 *
1091 * @since 1.8.0
1092 *
1093 * @param array $fields Fields.
1094 * @param array $theme Theme data.
1095 * @param array $campaign_data Campaign data.
1096 * @param array $row_field_data Row data.
1097 *
1098 * @return string
1099 */
1100 public function render_fields( $fields, $theme, $campaign_data, $row_field_data, $row_locked = false ) {
1101
1102 if ( empty( $fields ) ) {
1103 return;
1104 }
1105
1106 foreach ( $fields as $key => $field_id ) :
1107
1108 $field_type = is_array( $row_field_data ) && ! empty( $row_field_data[ $field_id ] ) ? esc_attr( $row_field_data[ $field_id ] ) : esc_attr( $key );
1109 $field_type_data = $campaign_data['fields'][ $field_id ];
1110
1111 $type = 'Charitable_Field_' . str_replace( ' ', '_', ( ucwords( str_replace( '-', ' ', $field_type ) ) ) );
1112
1113 if ( class_exists( $type ) ) :
1114
1115 $class = new $type();
1116
1117 $field_settings = is_array( $field_type_data ) ? $field_type_data : array();
1118
1119 // define a default photo for the photo type block if it's passed from the theme JSON data.
1120 if ( $field_type == 'photo' && ! empty( $field_settings['default'] ) && ! empty( $theme['meta']['slug'] ) ) {
1121
1122 $campaign_template_slug = esc_attr( $theme['meta']['slug'] );
1123
1124 // if the "default" parameter for the photo is passed then we attempt to pull that photo.
1125 $default_filename = ! empty( $field_type_data['default'] ) ? esc_html( $field_type_data['default'] ) : 'photo.jpg';
1126 $theme_thumbnail = ( false !== $default_filename ) && $campaign_template_slug ? charitable()->get_path( 'assets', true ) . 'images/campaign-builder/templates/' . $campaign_template_slug . '/' . $default_filename : false;
1127
1128 // see if the thumbnail or default photo exists.
1129 if ( false !== $theme_thumbnail && file_exists( $theme_thumbnail ) ) {
1130 $field_settings['default'] = charitable()->get_path( 'assets', false ) . 'images/campaign-builder/templates/' . $campaign_template_slug . '/' . $default_filename;
1131 }
1132 }
1133
1134 // Expand template-relative filenames for the campaign-hero block.
1135 if ( $field_type === 'campaign-hero' && ! empty( $theme['meta']['slug'] ) ) {
1136 $campaign_template_slug = esc_attr( $theme['meta']['slug'] );
1137 foreach ( array( 'background_image', 'avatar_image' ) as $img_key ) {
1138 if ( ! empty( $field_settings[ $img_key ] ) ) {
1139 $image_value = $field_settings[ $img_key ];
1140 $image_basename = basename( $image_value );
1141 if ( $image_basename === $image_value ) {
1142 $asset_path = charitable()->get_path( 'assets', true ) . 'images/campaign-builder/templates/' . $campaign_template_slug . '/' . $image_basename;
1143 if ( file_exists( $asset_path ) ) {
1144 $field_settings[ $img_key ] = charitable()->get_path( 'assets', false ) . 'images/campaign-builder/templates/' . $campaign_template_slug . '/' . $image_basename;
1145 }
1146 }
1147 }
1148 }
1149 }
1150
1151 $field_settings['id'] = $field_id;
1152
1153 $charitable_field_css_classes = array(
1154 'charitable-field',
1155 'charitable-field-' . $field_type,
1156 $class->can_be_edited ? 'charitable-can-edit' : 'charitable-no-edit',
1157 $class->can_be_duplicated ? 'charitable-can-duplicate' : 'charitable-no-duplicate',
1158 $class->can_be_deleted ? 'charitable-can-delete' : 'charitable-no-delete',
1159 );
1160
1161 if ( $row_locked ) {
1162 $charitable_field_css_classes[] = 'charitable-field-not-draggable';
1163 }
1164
1165 echo '<div class="' . implode( ' ', $charitable_field_css_classes ) . '" id="charitable-field-' . intval( $field_id ) . '" data-field-id="' . intval( $field_id ) . '" data-field-type="' . esc_attr( $field_type ) . '" data-field-max="' . esc_attr( $class->max_allowed ) . '" style="">'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1166 if ( $class->can_be_edited ) :
1167 echo '<a href="#" class="charitable-field-edit" data-type="' . esc_attr( $class->edit_type ) . '" data-section="' . esc_attr( $class->edit_section ) . '" data-edit-field-id="' . esc_attr( $class->edit_field_id ) . '" title="' . esc_attr( $class->edit_label ) . '"><i class="fa fa-pencil"></i></a>';
1168 endif;
1169 if ( $class->can_be_duplicated && ! $row_locked ) :
1170 echo '<a href="#" class="charitable-field-duplicate" title="Duplicate Field"><i class="fa fa-files-o" aria-hidden="true"></i></a>';
1171 endif;
1172 if ( $class->can_be_deleted && ! $row_locked ) :
1173 echo '<a href="#" class="charitable-field-delete" title="Delete Field"><i class="fa fa-trash-o"></i></a>';
1174 endif;
1175
1176 echo $class->field_preview( $field_settings, $campaign_data, $field_id, $theme ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1177 echo '</div>';
1178
1179 else :
1180
1181 $builder_template = new Charitable_Campaign_Builder_Templates();
1182
1183 $builder_template->render_missing_addon_field_preview( $field_type, $field_id, $field_type_data, $campaign_data );
1184
1185 endif;
1186
1187 endforeach;
1188 }
1189
1190 /**
1191 * Get addoon field label.
1192 *
1193 * @since 1.8.0
1194 * @param string $field_type Field type.
1195 *
1196 * @return array
1197 */
1198 public function get_addon_field_label( $field_type = false ) {
1199
1200 $field_type_labels = $this->get_addon_field_labels();
1201
1202 if ( array_key_exists( $field_type, $field_type_labels ) ) {
1203 return esc_html( $field_type_labels[ $field_type ]['field_label'] );
1204 }
1205
1206 // Try a variation.
1207 if ( array_key_exists( 'charitable-' . $field_type, $field_type_labels ) ) {
1208 return esc_html( $field_type_labels[ 'charitable-' . $field_type ]['field_label'] );
1209 }
1210
1211 // Try a variation.
1212 if ( array_key_exists( 'charitable-' . $field_type . 's', $field_type_labels ) ) {
1213 return esc_html( $field_type_labels[ 'charitable-' . $field_type . 's' ]['field_label'] );
1214 }
1215
1216 return false;
1217 }
1218
1219 /**
1220 * Get addoon label.
1221 *
1222 * @since 1.8.0
1223 * @param string $field_type Field type.
1224 *
1225 * @return array
1226 */
1227 public function get_addon_label( $field_type = false ) {
1228
1229 $field_type_labels = $this->get_addon_field_labels();
1230
1231 if ( array_key_exists( $field_type, $field_type_labels ) ) {
1232 return esc_html( $field_type_labels[ $field_type ]['addon_label'] );
1233 }
1234
1235 return false;
1236 }
1237
1238 /**
1239 * Get addoon field labels.
1240 *
1241 * @since 1.8.0
1242 *
1243 * @return array
1244 */
1245 public function get_addon_field_labels() {
1246
1247 $this->addon_labels = apply_filters(
1248 'charitable_campaign_builder_addon_labels',
1249 array(
1250 'ambassadors-team' => array(
1251 'field_label' => 'Team Field',
1252 'addon_label' => 'Ambassadors Addon',
1253 'url' => false,
1254 'plan' => 'pro',
1255 ),
1256 'updates-main' => array(
1257 'field_label' => 'Updates Field',
1258 'addon_label' => 'Simple Updates Addon',
1259 'url' => false,
1260 'plan' => 'pro',
1261 ),
1262 'comments-main' => array(
1263 'field_label' => 'Comments Field',
1264 'addon_label' => 'Comments Addon',
1265 'url' => false,
1266 'plan' => 'pro',
1267 ),
1268 )
1269 );
1270
1271 return $this->addon_labels;
1272 }
1273
1274 /**
1275 * Sort Add Field buttons by order provided.
1276 *
1277 * @since 1.8.0
1278 *
1279 * @param array $a First item.
1280 * @param array $b Second item.
1281 *
1282 * @return array
1283 */
1284 public function field_order( $a, $b ) {
1285
1286 return $a['order'] - $b['order'];
1287 }
1288
1289 /**
1290 * Tab Empty Notice.
1291 *
1292 * @since 1.8.0
1293 */
1294 public function tab_empty_notice() {
1295
1296 return sprintf(
1297 /* translators: 1: Template ID */
1298 '<p class="empty-tab-notice">' . __( 'This tab is empty. Drag a block from the left into this area or ', 'charitable' ) . '<br/><strong><a href="%1$s" class="charitable-configure-tab-settings">' . __( 'configure tab settings', 'charitable' ) . '</a></strong>.</p>',
1299 '#'
1300 );
1301 }
1302
1303 /**
1304 * No Empty Notice.
1305 *
1306 * @since 1.8.0
1307 */
1308 public function no_tab_empty_notice() {
1309
1310 return sprintf(
1311 /* translators: 1: Template ID */
1312 '<p class="empty-tab-notice">' . __( 'There are no tabs yet for this template. You can ', 'charitable' ) . '<br/><strong><a href="%1$s" class="charitable-configure-tab-settings">' . __( 'configure tab settings', 'charitable' ) . '</a> to add a new tab</strong>.</p>',
1313 '#'
1314 );
1315 }
1316 }
1317
1318 endif;
1319
1320 new Charitable_Builder_Panel_Design();
1321