PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.12.3
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.12.3
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.12.3, at includes/admin/campaign-builder/panels/class-design.php

1,299 lines 54.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 $element_counter = 0;
949 $column_counter = 0;
950 $section_counter = 0;
951 $last_field_id = 0;
952
953 ?>
954
955 <div class="charitable-campaign-preview container">
956
957 <?php
958
959 if ( ! empty( $rows ) ) :
960
961 foreach ( $rows as $row_id => $row ) :
962
963 $additional_css = ! empty( $row['css_class'] ) ? esc_attr( $row['css_class'] ) : '';
964 $row_bg_image = ! empty( $row['background_image'] ) ? $row['background_image'] : '';
965 $row_locked = ! empty( $row['locked'] );
966
967 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
968
969 foreach ( $row['columns'] as $column_id => $column ) :
970
971 echo '<!-- column START -->';
972
973 echo '<div data-column-id="' . intval( $column_counter ) . '" class="column charitable-field-column">';
974
975 if ( ! empty( $column['sections'] ) ) {
976
977 $section_css_class = 'charitable-field-target-inactive';
978 $is_section_empty = true;
979
980 // do a initial look to see if all sections in this column have no fields, and add the default CSS class accordingly.
981 foreach ( $column['sections'] as $section_id => $section ) {
982 $is_section_empty = ( $section['type'] === 'tabs' ) || ( $section['type'] === 'fields' && ! empty( $section['fields'] ) ) ? false : $is_section_empty;
983 }
984
985 foreach ( $column['sections'] as $section_id => $section ) {
986
987 echo '<!-- section START -->';
988
989 $section_css_class = $is_section_empty ? 'charitable-field-target' : 'charitable-field-target-inactive';
990 $section_css_class = ( ! empty( $row['css_class'] ) && strpos( $row['css_class'], 'no-field-target' ) !== false ) ? false : $section_css_class;
991 $section_css_class_no_wrap = empty( $row['css_class'] ) || strpos( $row['css_class'], 'no-field-wrap' ) === false ? ' charitable-field-wrap' : '';
992 $section_css_class_no_wrap = ( $section['type'] === 'tabs' ) ? '' : $section_css_class_no_wrap;
993
994 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 ) . '">';
995
996 echo '<div class="charitable-drag-new-block-here"><p>Drag New Block Here.</p></div>';
997
998 switch ( $section['type'] ) {
999 case 'fields':
1000 $this->render_fields( $section['fields'], $theme, $this->campaign_data, $row['fields'], $row_locked );
1001 break;
1002 case 'header':
1003 $this->render_fields( $section['fields'], $theme, $this->campaign_data, $row['fields'], $row_locked );
1004 break;
1005 case 'tabs':
1006 echo $this->get_template_element_start( 'tabs', null, null, $this->campaign_data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1007 echo $builder_template->get_template_tab_nav( $section['tabs'], $theme, $this->campaign_data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1008 $last_field_id = $builder_template->get_template_tab_content( $section['tabs'], $theme, $this->campaign_data, $row['fields'], $last_field_id );
1009 echo $this->get_template_element_end( 'tabs' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1010 break;
1011 default:
1012 do_action( 'charitable_campaign_builder_preview_section_' . $section['type'], $section, $row, $theme, $this->campaign_data );
1013 break;
1014 }
1015
1016 ++$section_counter;
1017
1018 echo '</div>';
1019
1020 echo '<!-- section END -->';
1021
1022 }
1023 } else {
1024
1025 $section_css_class = ( empty( $row['css_class'] ) || strpos( $row['css_class'], 'no-field-target' ) === false ) ? 'charitable-field-target' : false;
1026
1027 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 ) . '">';
1028
1029 echo '<div class="charitable-drag-new-block-here"><p>Drag New Block Here.</p></div>';
1030
1031 ++$section_counter;
1032
1033 echo '</div>';
1034
1035 echo '<!-- section END -->';
1036
1037 }
1038
1039 ++$column_counter;
1040
1041 echo '</div>';
1042
1043 echo '<!-- column END -->';
1044
1045 endforeach;
1046
1047 echo $this->get_template_element_end( $row['type'], intval( $element_counter ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1048
1049 ++$element_counter;
1050
1051 endforeach;
1052
1053 endif;
1054
1055 ?>
1056
1057 </div>
1058
1059 <?php
1060
1061 $preview = ob_get_clean();
1062
1063 echo $preview; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1064 }
1065
1066 /**
1067 * Create fields for preview area based on an array, usually for a column of the layout.
1068 *
1069 * @since 1.8.0
1070 *
1071 * @param array $fields Fields.
1072 * @param array $theme Theme data.
1073 * @param array $campaign_data Campaign data.
1074 * @param array $row_field_data Row data.
1075 *
1076 * @return string
1077 */
1078 public function render_fields( $fields, $theme, $campaign_data, $row_field_data, $row_locked = false ) {
1079
1080 if ( empty( $fields ) ) {
1081 return;
1082 }
1083
1084 foreach ( $fields as $key => $field_id ) :
1085
1086 $field_type = is_array( $row_field_data ) && ! empty( $row_field_data[ $field_id ] ) ? esc_attr( $row_field_data[ $field_id ] ) : esc_attr( $key );
1087 $field_type_data = $campaign_data['fields'][ $field_id ];
1088
1089 $type = 'Charitable_Field_' . str_replace( ' ', '_', ( ucwords( str_replace( '-', ' ', $field_type ) ) ) );
1090
1091 if ( class_exists( $type ) ) :
1092
1093 $class = new $type();
1094
1095 $field_settings = is_array( $field_type_data ) ? $field_type_data : array();
1096
1097 // define a default photo for the photo type block if it's passed from the theme JSON data.
1098 if ( $field_type == 'photo' && ! empty( $field_settings['default'] ) && ! empty( $theme['meta']['slug'] ) ) {
1099
1100 $campaign_template_slug = esc_attr( $theme['meta']['slug'] );
1101
1102 // if the "default" parameter for the photo is passed then we attempt to pull that photo.
1103 $default_filename = ! empty( $field_type_data['default'] ) ? esc_html( $field_type_data['default'] ) : 'photo.jpg';
1104 $theme_thumbnail = ( false !== $default_filename ) && $campaign_template_slug ? charitable()->get_path( 'assets', true ) . 'images/campaign-builder/templates/' . $campaign_template_slug . '/' . $default_filename : false;
1105
1106 // see if the thumbnail or default photo exists.
1107 if ( false !== $theme_thumbnail && file_exists( $theme_thumbnail ) ) {
1108 $field_settings['default'] = charitable()->get_path( 'assets', false ) . 'images/campaign-builder/templates/' . $campaign_template_slug . '/' . $default_filename;
1109 }
1110 }
1111
1112 // Expand template-relative filenames for the campaign-hero block.
1113 if ( $field_type === 'campaign-hero' && ! empty( $theme['meta']['slug'] ) ) {
1114 $campaign_template_slug = esc_attr( $theme['meta']['slug'] );
1115 foreach ( array( 'background_image', 'avatar_image' ) as $img_key ) {
1116 if ( ! empty( $field_settings[ $img_key ] ) ) {
1117 $image_value = $field_settings[ $img_key ];
1118 $image_basename = basename( $image_value );
1119 if ( $image_basename === $image_value ) {
1120 $asset_path = charitable()->get_path( 'assets', true ) . 'images/campaign-builder/templates/' . $campaign_template_slug . '/' . $image_basename;
1121 if ( file_exists( $asset_path ) ) {
1122 $field_settings[ $img_key ] = charitable()->get_path( 'assets', false ) . 'images/campaign-builder/templates/' . $campaign_template_slug . '/' . $image_basename;
1123 }
1124 }
1125 }
1126 }
1127 }
1128
1129 $field_settings['id'] = $field_id;
1130
1131 $charitable_field_css_classes = array(
1132 'charitable-field',
1133 'charitable-field-' . $field_type,
1134 $class->can_be_edited ? 'charitable-can-edit' : 'charitable-no-edit',
1135 $class->can_be_duplicated ? 'charitable-can-duplicate' : 'charitable-no-duplicate',
1136 $class->can_be_deleted ? 'charitable-can-delete' : 'charitable-no-delete',
1137 );
1138
1139 if ( $row_locked ) {
1140 $charitable_field_css_classes[] = 'charitable-field-not-draggable';
1141 }
1142
1143 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
1144 if ( $class->can_be_edited ) :
1145 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>';
1146 endif;
1147 if ( $class->can_be_duplicated && ! $row_locked ) :
1148 echo '<a href="#" class="charitable-field-duplicate" title="Duplicate Field"><i class="fa fa-files-o" aria-hidden="true"></i></a>';
1149 endif;
1150 if ( $class->can_be_deleted && ! $row_locked ) :
1151 echo '<a href="#" class="charitable-field-delete" title="Delete Field"><i class="fa fa-trash-o"></i></a>';
1152 endif;
1153
1154 echo $class->field_preview( $field_settings, $campaign_data, $field_id, $theme ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1155 echo '</div>';
1156
1157 else :
1158
1159 $builder_template = new Charitable_Campaign_Builder_Templates();
1160
1161 $builder_template->render_missing_addon_field_preview( $field_type, $field_id, $field_type_data, $campaign_data );
1162
1163 endif;
1164
1165 endforeach;
1166 }
1167
1168 /**
1169 * Get addoon field label.
1170 *
1171 * @since 1.8.0
1172 * @param string $field_type Field type.
1173 *
1174 * @return array
1175 */
1176 public function get_addon_field_label( $field_type = false ) {
1177
1178 $field_type_labels = $this->get_addon_field_labels();
1179
1180 if ( array_key_exists( $field_type, $field_type_labels ) ) {
1181 return esc_html( $field_type_labels[ $field_type ]['field_label'] );
1182 }
1183
1184 // Try a variation.
1185 if ( array_key_exists( 'charitable-' . $field_type, $field_type_labels ) ) {
1186 return esc_html( $field_type_labels[ 'charitable-' . $field_type ]['field_label'] );
1187 }
1188
1189 // Try a variation.
1190 if ( array_key_exists( 'charitable-' . $field_type . 's', $field_type_labels ) ) {
1191 return esc_html( $field_type_labels[ 'charitable-' . $field_type . 's' ]['field_label'] );
1192 }
1193
1194 return false;
1195 }
1196
1197 /**
1198 * Get addoon label.
1199 *
1200 * @since 1.8.0
1201 * @param string $field_type Field type.
1202 *
1203 * @return array
1204 */
1205 public function get_addon_label( $field_type = false ) {
1206
1207 $field_type_labels = $this->get_addon_field_labels();
1208
1209 if ( array_key_exists( $field_type, $field_type_labels ) ) {
1210 return esc_html( $field_type_labels[ $field_type ]['addon_label'] );
1211 }
1212
1213 return false;
1214 }
1215
1216 /**
1217 * Get addoon field labels.
1218 *
1219 * @since 1.8.0
1220 *
1221 * @return array
1222 */
1223 public function get_addon_field_labels() {
1224
1225 $this->addon_labels = apply_filters(
1226 'charitable_campaign_builder_addon_labels',
1227 array(
1228 'ambassadors-team' => array(
1229 'field_label' => 'Team Field',
1230 'addon_label' => 'Ambassadors Addon',
1231 'url' => false,
1232 'plan' => 'pro',
1233 ),
1234 'updates-main' => array(
1235 'field_label' => 'Updates Field',
1236 'addon_label' => 'Simple Updates Addon',
1237 'url' => false,
1238 'plan' => 'pro',
1239 ),
1240 'comments-main' => array(
1241 'field_label' => 'Comments Field',
1242 'addon_label' => 'Comments Addon',
1243 'url' => false,
1244 'plan' => 'pro',
1245 ),
1246 )
1247 );
1248
1249 return $this->addon_labels;
1250 }
1251
1252 /**
1253 * Sort Add Field buttons by order provided.
1254 *
1255 * @since 1.8.0
1256 *
1257 * @param array $a First item.
1258 * @param array $b Second item.
1259 *
1260 * @return array
1261 */
1262 public function field_order( $a, $b ) {
1263
1264 return $a['order'] - $b['order'];
1265 }
1266
1267 /**
1268 * Tab Empty Notice.
1269 *
1270 * @since 1.8.0
1271 */
1272 public function tab_empty_notice() {
1273
1274 return sprintf(
1275 /* translators: 1: Template ID */
1276 '<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>',
1277 '#'
1278 );
1279 }
1280
1281 /**
1282 * No Empty Notice.
1283 *
1284 * @since 1.8.0
1285 */
1286 public function no_tab_empty_notice() {
1287
1288 return sprintf(
1289 /* translators: 1: Template ID */
1290 '<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>',
1291 '#'
1292 );
1293 }
1294 }
1295
1296 endif;
1297
1298 new Charitable_Builder_Panel_Design();
1299