PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.11.3
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.11.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 / class-campaign-embed-wizard.php

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

496 lines 11.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class that sets up the WordPress Campaign Builder Wizard.
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.1
11 */
12
13 // Exit if accessed directly.
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 if ( ! class_exists( 'Charitable_Campaign_Embed_Wizard' ) ) :
19
20 /**
21 * Embed Form in a Page wizard.
22 *
23 * @since 1.8.0
24 */
25 class Charitable_Campaign_Embed_Wizard {
26
27 /**
28 * One is the loneliest number that you'll ever do.
29 *
30 * @since 1.8.0
31 *
32 * @var object
33 */
34 private static $instance;
35
36 /**
37 * Max search results count of 'Select Page' dropdown.
38 *
39 * @since 1.8.0
40 *
41 * @var int
42 */
43 const MAX_SEARCH_RESULTS_DROPDOWN_PAGES_COUNT = 20;
44
45 /**
46 * Post statuses of pages in 'Select Page' dropdown.
47 *
48 * @since 1.8.0
49 *
50 * @var string[]
51 */
52 const POST_STATUSES_OF_DROPDOWN_PAGES = [ 'publish', 'pending' ];
53
54 /**
55 * Main Instance.
56 *
57 * @since 1.8.0
58 *
59 * @return Charitable_Builder
60 */
61 public static function get_instance() {
62
63 if ( ! isset( self::$instance ) && ! ( self::$instance instanceof Charitable_Campaign_Builder ) ) {
64
65 self::$instance = new Charitable_Campaign_Embed_Wizard();
66
67 add_action( 'admin_init', [ self::$instance, 'init' ], 10 );
68 }
69
70 return self::$instance;
71 }
72
73 /**
74 * Create object instance.
75 *
76 * @since 1.8.0
77 */
78 private function __construct() {
79 }
80
81 /**
82 * Initialize class.
83 *
84 * @since 1.8.0
85 */
86 public function init() {
87
88 // Campaign Embed Wizard should load only in the Campaign Builder and on the Edit/Add Page screen.
89 if (
90 ! $this->campaign_is_campaign_builder_admin_page( 'builder' ) &&
91 ! wp_doing_ajax() &&
92 ! $this->is_campaign_embed_page()
93 ) {
94
95 return;
96 }
97
98 $this->hooks();
99 }
100
101 /**
102 * Determine if we are on the campaign builder admin page
103 *
104 * @since 1.8.0
105 * @version 1.8.9.1
106 */
107 public function campaign_is_campaign_builder_admin_page() {
108
109 // phpcs:ignore WordPress.Security.NonceVerification.Missing
110 if ( isset( $_POST['campaign_id'] ) ) {
111 return true;
112 }
113
114 // phpcs:disable WordPress.Security.NonceVerification.Recommended
115 if ( ! isset( $_GET['page'] ) || sanitize_text_field( wp_unslash( $_GET['page'] ) ) !== 'charitable-campaign-builder' ) {
116 return false;
117 } else {
118 return true;
119 }
120 // phpcs:enable WordPress.Security.NonceVerification.Recommended
121 }
122
123 /**
124 * Register hooks.
125 *
126 * @since 1.8.0
127 */
128 public function hooks() {
129
130 add_action( 'admin_enqueue_scripts', [ $this, 'enqueues' ] );
131 add_action( 'admin_footer', [ $this, 'output' ] );
132 add_filter( 'default_title', [ $this, 'embed_page_title' ], 10, 2 );
133 add_filter( 'default_content', [ $this, 'embed_page_content' ], 10, 2 );
134 add_action( 'wp_ajax_campaign_admin_campaign_embed_wizard_embed_page_url', [ $this, 'get_embed_page_url_ajax' ] );
135 add_action( 'wp_ajax_campaign_admin_campaign_embed_wizard_clear_meta', [ $this, 'ajax_delete_meta' ] );
136 add_action( 'wp_ajax_campaign_admin_campaign_embed_wizard_search_pages_choicesjs', [ $this, 'get_search_result_pages_ajax' ] );
137 }
138
139 /**
140 * Enqueue assets.
141 *
142 * @since 1.8.0
143 */
144 public function enqueues() {
145
146 // $min = campaign_get_min_suffix();
147 $min = false;
148
149 wp_enqueue_style(
150 'campaign-admin-campaign-embed-wizard',
151 charitable()->get_path( 'directory', false ) . 'assets/css/campaign-builder/campaign-embed-wizard.css',
152 null,
153 '4.7.0'
154 );
155
156 wp_enqueue_script(
157 'campaign-admin-campaign-embed-wizard',
158 charitable()->get_path( 'directory', false ) . 'assets/js/campaign-builder/campaign-embed-wizard.js',
159 [ 'jquery', 'underscore' ],
160 '4.2.6'
161 );
162
163 wp_localize_script(
164 'campaign-admin-campaign-embed-wizard',
165 'campaign_admin_campaign_embed_wizard',
166 [
167 'nonce' => wp_create_nonce( 'campaign_admin_campaign_embed_wizard_nonce' ),
168 'is_edit_page' => (int) $this->is_campaign_embed_page( 'edit' ),
169 ]
170 );
171 }
172
173 /**
174 * Output HTML.
175 *
176 * @since 1.8.0
177 * @version 1.8.1
178 *
179 * @return void
180 */
181 public function output() {
182
183 // We don't need to output tooltip if it's not an embed flow.
184 if ( $this->is_campaign_embed_page() && ! $this->get_meta() ) {
185 return;
186 }
187
188 $template = $this->is_campaign_embed_page() ? charitable()->get_path( 'directory', true ) . 'includes/admin/campaign-builder/campaign-embed-wizard/tooltip.php' : charitable()->get_path( 'directory', true ) . 'includes/admin/campaign-builder/campaign-embed-wizard/popup.php';
189 $view_args = [];
190
191 if ( ! $this->is_campaign_embed_page() ) {
192 $args['user_can_edit_pages'] = current_user_can( 'edit_pages' );
193 $args['dropdown_pages'] = $this->get_select_dropdown_pages_html();
194 }
195
196 include $template;
197 }
198
199 /**
200 * Check if the current page is a campaign embed page.
201 *
202 * @since 1.8.0
203 *
204 * @param string $type Type of the embed page to check. Can be '', 'add' or 'edit'. By default is empty string.
205 *
206 * @return boolean
207 */
208 public function is_campaign_embed_page( $type = '' ) {
209
210 global $pagenow;
211
212 $type = $type === 'add' || $type === 'edit' ? $type : '';
213
214 if (
215 $pagenow !== 'post.php' &&
216 $pagenow !== 'post-new.php'
217 ) {
218 return false;
219 }
220
221 // phpcs:disable WordPress.Security.NonceVerification.Recommended
222 $post_id = empty( $_GET['post'] ) ? 0 : (int) $_GET['post'];
223 $post_type = empty( $_GET['post_type'] ) ? '' : sanitize_key( $_GET['post_type'] );
224 $action = empty( $_GET['action'] ) ? 'add' : sanitize_key( $_GET['action'] );
225 // phpcs:enable
226
227 if ( $pagenow === 'post-new.php' &&
228 ( empty( $post_type ) || $post_type !== 'page' )
229 ) {
230 return false;
231 }
232
233 if (
234 $pagenow === 'post.php' &&
235 ( empty( $post_id ) || get_post_type( $post_id ) !== 'page' )
236 ) {
237 return false;
238 }
239
240 $meta = $this->get_meta();
241 $embed_page = ! empty( $meta['embed_page'] ) ? (int) $meta['embed_page'] : 0;
242
243 if ( 'add' === $action && 0 === $embed_page && $type !== 'edit' ) {
244 return true;
245 }
246
247 if ( ! empty( $post_id ) && $embed_page === $post_id && $type !== 'add' ) {
248 return true;
249 }
250
251 return false;
252 }
253
254 /**
255 * Set user's embed meta data.
256 *
257 * @since 1.8.0
258 *
259 * @param array $data Data array to set.
260 */
261 public function set_meta( $data ) {
262
263 update_user_meta( get_current_user_id(), 'campaign_admin_campaign_embed_wizard', $data );
264 }
265
266 /**
267 * Get user's embed meta data.
268 *
269 * @since 1.8.0
270 *
271 * @return array User's embed meta data.
272 */
273 public function get_meta() {
274
275 return get_user_meta( get_current_user_id(), 'campaign_admin_campaign_embed_wizard', true );
276 }
277
278 /**
279 * Delete user's embed meta data.
280 *
281 * @since 1.8.0
282 */
283 public function delete_meta() {
284
285 delete_user_meta( get_current_user_id(), 'campaign_admin_campaign_embed_wizard' );
286 }
287
288 /**
289 * Delete meta via ajax.
290 *
291 * @since 1.8.1
292 */
293 public function ajax_delete_meta() {
294
295 check_admin_referer( 'campaign_admin_campaign_embed_wizard_nonce' );
296
297 $this->delete_meta();
298
299 wp_send_json_success();
300 }
301
302 /**
303 * Get embed page URL via AJAX.
304 *
305 * @since 1.8.0
306 */
307 public function get_embed_page_url_ajax() {
308
309 check_admin_referer( 'campaign_admin_campaign_embed_wizard_nonce' );
310
311 $page_id = ! empty( $_POST['pageId'] ) ? absint( $_POST['pageId'] ) : 0;
312
313 if ( ! empty( $page_id ) ) {
314 $url = get_edit_post_link( $page_id, '' );
315 $meta = [
316 'embed_page' => $page_id,
317 ];
318 } else {
319 $url = add_query_arg( 'post_type', 'page', admin_url( 'post-new.php' ) );
320 $meta = [
321 'embed_page' => 0,
322 'embed_page_title' => ! empty( $_POST['pageTitle'] ) ? sanitize_text_field( wp_unslash( $_POST['pageTitle'] ) ) : '',
323 ];
324 }
325
326 $meta['form_id'] = ! empty( $_POST['formId'] ) ? absint( $_POST['formId'] ) : 0;
327
328 $this->set_meta( $meta );
329
330 wp_send_json_success( $url );
331 }
332
333 /**
334 * Set default title for the new page.
335 *
336 * @since 1.8.0
337 *
338 * @param string $post_title Default post title.
339 * @param \WP_Post $post Post object.
340 *
341 * @return string New default post title.
342 */
343 public function embed_page_title( $post_title, $post ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
344
345 $meta = $this->get_meta();
346
347 $this->delete_meta();
348
349 return empty( $meta['embed_page_title'] ) ? $post_title : $meta['embed_page_title'];
350 }
351
352 /**
353 * Embed the campaign to the new page.
354 *
355 * @since 1.8.0
356 *
357 * @param string $post_content Default post content.
358 * @param \WP_Post $post Post object.
359 *
360 * @return string Embedding string (shortcode or GB component code).
361 */
362 public function embed_page_content( $post_content, $post ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
363
364 $meta = $this->get_meta();
365
366 $campaign_id = ! empty( $meta['form_id'] ) ? $meta['form_id'] : 0;
367 $page_id = ! empty( $meta['embed_page'] ) ? $meta['embed_page'] : 0;
368
369 if ( ! empty( $page_id ) || empty( $campaign_id ) ) {
370 return $post_content;
371 }
372
373 if ( charitable_is_gutenberg_active() ) {
374 $pattern = '<!-- wp:create-block/campaignblock {"campaignID":"%d"} /-->';
375 } else {
376 $pattern = '[campaign id="%d"]';
377 }
378
379 return sprintf( $pattern, absint( $campaign_id ) );
380 }
381
382 /**
383 * Generate select with pages which are available to edit for current user.
384 *
385 * @since 1.8.0
386 *
387 * @return string
388 */
389 private function get_select_dropdown_pages_html() {
390
391 $dropdown_pages = charitable_campaign_search_posts(
392 '',
393 [
394 'count' => self::MAX_SEARCH_RESULTS_DROPDOWN_PAGES_COUNT,
395 'post_status' => self::POST_STATUSES_OF_DROPDOWN_PAGES,
396 ]
397 );
398
399 if ( empty( $dropdown_pages ) ) {
400 return '';
401 }
402
403 $total_pages = 0;
404 $wp_count_pages = (array) wp_count_posts( 'page' );
405
406 foreach ( $wp_count_pages as $page_status => $pages_count ) {
407 if ( in_array( $page_status, self::POST_STATUSES_OF_DROPDOWN_PAGES, true ) ) {
408 $total_pages += $pages_count;
409 }
410 }
411
412 $return_this = charitable_settings_select_callback(
413 [
414 'id' => 'campaign-embed-wizard-choicesjs-select-pages',
415 'type' => 'select',
416 'choicesjs' => true,
417 'options' => wp_list_pluck( $dropdown_pages, 'post_title', 'ID' ),
418 'data' => [
419 'use_ajax' => $total_pages > self::MAX_SEARCH_RESULTS_DROPDOWN_PAGES_COUNT,
420 ],
421 ]
422 );
423
424 return $return_this;
425 }
426
427 /**
428 * Get search result pages for ChoicesJS via AJAX.
429 *
430 * @since 1.8.0
431 */
432 public function get_search_result_pages_ajax() {
433
434 // Run a security check.
435 if ( ! check_ajax_referer( 'campaign_admin_campaign_embed_wizard_nonce', false, false ) ) {
436 wp_send_json_error(
437 [
438 'msg' => esc_html__( 'Your session expired. Please reload the builder.', 'charitable' ),
439 ]
440 );
441 }
442
443 if ( ! array_key_exists( 'search', $_GET ) ) {
444 wp_send_json_error(
445 [
446 'msg' => esc_html__( 'Incorrect usage of this operation.', 'charitable' ),
447 ]
448 );
449 }
450
451 $result_pages = campaign_search_pages_for_dropdown(
452 sanitize_text_field( wp_unslash( $_GET['search'] ) ),
453 [
454 'count' => self::MAX_SEARCH_RESULTS_DROPDOWN_PAGES_COUNT,
455 'post_status' => self::POST_STATUSES_OF_DROPDOWN_PAGES,
456 ]
457 );
458
459 if ( empty( $result_pages ) ) {
460 wp_send_json_error( [] );
461 }
462
463 wp_send_json_success( $result_pages );
464 }
465
466 /**
467 * Excludes pages from dropdown which user can't edit.
468 *
469 * @since 1.8.0
470 * @deprecated 1.8.0
471 *
472 * @param WP_Post[] $pages Array of page objects.
473 *
474 * @return WP_Post[]|false Array of filtered pages or false.
475 */
476 public function remove_inaccessible_pages( $pages ) {
477
478 _deprecated_function( __METHOD__, '1.8.0 of the Campaign plugin' );
479
480 if ( ! $pages ) {
481 return $pages;
482 }
483
484 foreach ( $pages as $key => $page ) {
485 if ( ! current_user_can( 'edit_page', $page->ID ) ) {
486 unset( $pages[ $key ] );
487 }
488 }
489
490 return $pages;
491 }
492 }
493
494
495 endif;
496