PluginProbe
CartFlows – Funnel Builder & Checkout Plugin for WooCommerce / 3.3.0
CartFlows – Funnel Builder & Checkout Plugin for WooCommerce v3.3.0
3.3.0 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.1 trunk 1.0.4 1.1.0 1.1.0.1 1.1.1 1.1.10 1.1.11 1.1.12 1.1.13 1.1.14 1.1.15 1.1.16 1.1.17 1.1.18 1.1.19 1.1.2 All 162 releases
cartflows / modules / flow / classes / class-cartflows-step-post-type.php

class-cartflows-step-post-type.php in CartFlows – Funnel Builder & Checkout Plugin for WooCommerce 3.3.0, at modules/flow/classes/class-cartflows-step-post-type.php

551 lines 15.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Step post type.
4 *
5 * @package CartFlows
6 */
7
8 // Exit if accessed directly.
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12 /**
13 * Initialization
14 *
15 * @since 1.0.0
16 */
17 class Cartflows_Step_Post_Type {
18
19
20 /**
21 * Member Variable
22 *
23 * @var instance
24 */
25 private static $instance;
26
27 /**
28 * Member Variable
29 *
30 * @var body_classes
31 */
32 private $body_classes = array();
33
34 /**
35 * Initiator
36 */
37 public static function get_instance() {
38 if ( ! isset( self::$instance ) ) {
39 self::$instance = new self();
40 }
41 return self::$instance;
42 }
43
44 /**
45 * Constructor
46 */
47 public function __construct() {
48
49 add_action( 'init', array( $this, 'step_post_type' ) );
50 add_action( 'init', array( $this, 'add_wp_templates_support' ) );
51 add_filter( 'post_updated_messages', array( $this, 'post_update_messages' ) );
52
53 add_filter( 'wp_unique_post_slug', array( $this, 'prevent_slug_duplicates' ), 10, 6 );
54
55 add_filter( 'template_include', array( $this, 'load_page_template' ), 90 );
56 add_action( 'template_redirect', array( $this, 'query_fix' ), 3 );
57
58 add_action( 'admin_init', array( $this, 'disallowed_admin_all_steps_view' ) );
59 }
60
61 /**
62 * Trys to load page.php for a header, footer or part theme layout.
63 *
64 * @since 1.0.0
65 * @param string $template The current template to be loaded.
66 * @return string
67 */
68 public function load_page_template( $template ) {
69
70 global $post;
71
72 if ( 'string' == gettype( $template ) && is_object( $post ) && CARTFLOWS_STEP_POST_TYPE === $post->post_type ) {
73
74 /**
75 * Remove Next/Prev Navigation
76 * add_filter('next_post_link', '__return_empty_string');
77 * add_filter('previous_post_link', '__return_empty_string');
78 *
79 * $page = locate_template( array( 'page.php' ) );
80 *
81 * if ( ! empty( $page ) ) {
82 * return $page;
83 * }
84 */
85
86 /* Remove Next / Previous Rel Link */
87 remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10 );
88 add_filter( 'next_post_rel_link', '__return_empty_string' );
89 add_filter( 'previous_post_rel_link', '__return_empty_string' );
90
91 $page_template = Cartflows_Helper::get_current_page_template();
92
93 $file = '';
94
95 switch ( $page_template ) {
96
97 case 'cartflows-default':
98 $file = CARTFLOWS_FLOW_DIR . 'templates/template-default.php';
99 $this->body_classes[] = $page_template;
100 break;
101 case 'cartflows-canvas':
102 $file = CARTFLOWS_FLOW_DIR . 'templates/template-canvas.php';
103 $this->body_classes[] = $page_template;
104 break;
105 default:
106 /**
107 * Remove Next/Prev Navigation
108 */
109 add_filter( 'next_post_link', '__return_empty_string' );
110 add_filter( 'previous_post_link', '__return_empty_string' );
111
112 $page = locate_template( array( 'page.php' ) );
113
114 if ( ! empty( $page ) ) {
115 $file = $page;
116 }
117
118 break;
119
120 /**
121 * Default:
122 * $file = CARTFLOWS_FLOW_DIR . 'templates/template-default.php';
123 * $this->body_classes[] = 'cartflows-default';
124 * break;
125 */
126 }
127
128 $file = apply_filters( 'cartflows_page_template_file', $file );
129 $this->body_classes = apply_filters( 'cartflows_page_template_body_classes', $this->body_classes );
130
131
132 // Just to be safe, we check if the file exist first.
133 if ( file_exists( $file ) ) {
134
135 /* Add Body Class */
136 add_filter( 'body_class', array( $this, 'body_class' ) );
137
138 if ( apply_filters( 'cartflows_allow_to_change_page_template', true ) ) {
139 $template = $file;
140 }
141 return $template;
142 } else {
143 // File path intentionally not disclosed for security.
144 return $template;
145 }
146 }
147
148 return $template;
149 }
150
151 /**
152 * Body classes.
153 *
154 * @since 1.0.0
155 * @param array $classes Body classes.
156 * @return array
157 */
158 public function body_class( $classes = array() ) {
159
160 $classes = array_merge( $classes, $this->body_classes );
161
162 return $classes;
163 }
164
165 /**
166 * Create custom post type
167 */
168 public function step_post_type() {
169
170 $labels = array(
171 'name' => esc_html_x( 'Steps', 'flow step general name', 'cartflows' ),
172 'singular_name' => esc_html_x( 'Step', 'flow step singular name', 'cartflows' ),
173 'search_items' => esc_html__( 'Search Steps', 'cartflows' ),
174 'all_items' => esc_html__( 'All Steps', 'cartflows' ),
175 'edit_item' => esc_html__( 'Edit Step', 'cartflows' ),
176 'view_item' => esc_html__( 'View Step', 'cartflows' ),
177 'add_new' => esc_html__( 'Add New', 'cartflows' ),
178 'update_item' => esc_html__( 'Update Step', 'cartflows' ),
179 'add_new_item' => esc_html__( 'Add New', 'cartflows' ),
180 'new_item_name' => esc_html__( 'New Step Name', 'cartflows' ),
181 );
182
183 $permalink_settings = Cartflows_Helper::get_permalink_settings();
184
185 $args = array(
186 'labels' => $labels,
187 'public' => true,
188 'query_var' => true,
189 'can_export' => true,
190 'exclude_from_search' => true,
191 'show_ui' => true,
192 'show_in_menu' => false,
193 'show_in_admin_bar' => true,
194 'show_in_rest' => current_user_can( 'edit_posts' ),
195 'supports' => array( 'title', 'editor', 'elementor', 'revisions' ),
196 'capability_type' => 'post',
197 'capabilities' => array(
198 'create_posts' => 'do_not_allow', // Prior to Wordpress 4.5, this was false.
199 ),
200 'map_meta_cap' => true,
201 );
202
203 if ( isset( $permalink_settings['permalink_structure'] ) && ! empty( $permalink_settings['permalink_structure'] ) ) {
204 $args['rewrite'] = array(
205 'slug' => $permalink_settings['permalink_structure'],
206 'with_front' => false,
207 );
208
209 } elseif ( isset( $permalink_settings['permalink'] ) && ! empty( $permalink_settings['permalink'] ) ) {
210
211 $args['rewrite'] = array(
212 'slug' => $permalink_settings['permalink'],
213 'with_front' => false,
214 );
215 }
216
217 register_post_type( CARTFLOWS_STEP_POST_TYPE, $args );
218
219 // Step Type.
220 $args = array(
221 'label' => __( 'Step Type', 'cartflows' ),
222 'public' => false,
223 'rewrite' => false,
224 'hierarchical' => false,
225 );
226
227 register_taxonomy( CARTFLOWS_TAXONOMY_STEP_TYPE, CARTFLOWS_STEP_POST_TYPE, $args );
228
229 // Step Flow.
230 $args = array(
231 'label' => __( 'Step Flow', 'cartflows' ),
232 'public' => false,
233 'rewrite' => false,
234 'hierarchical' => false,
235 );
236
237 register_taxonomy( CARTFLOWS_TAXONOMY_STEP_FLOW, CARTFLOWS_STEP_POST_TYPE, $args );
238
239 if ( is_admin() ) {
240 /**
241 * Register 'Elementor' & 'Beaver Builder' site types.
242 *
243 * @see self::add_terms();
244 */
245 $taxonomy = CARTFLOWS_TAXONOMY_STEP_TYPE;
246
247 $terms = array(
248 array(
249 'name' => __( 'Landing', 'cartflows' ),
250 'slug' => 'landing',
251 'args' => array(
252 'slug' => 'landing',
253 ),
254 ),
255 array(
256 'name' => __( 'Optin', 'cartflows' ),
257 'slug' => 'optin',
258 'args' => array(
259 'slug' => 'optin',
260 ),
261 ),
262 array(
263 'name' => __( 'Checkout', 'cartflows' ),
264 'slug' => 'checkout',
265 'args' => array(
266 'slug' => 'checkout',
267 ),
268 ),
269 array(
270 'name' => __( 'Thank You', 'cartflows' ),
271 'slug' => 'thankyou',
272 'args' => array(
273 'slug' => 'thankyou',
274 ),
275 ),
276 array(
277 'name' => __( 'Upsell', 'cartflows' ),
278 'slug' => 'upsell',
279 'args' => array(
280 'slug' => 'upsell',
281 ),
282 ),
283 array(
284 'name' => __( 'Downsell', 'cartflows' ),
285 'slug' => 'downsell',
286 'args' => array(
287 'slug' => 'downsell',
288 ),
289 ),
290 );
291
292 $this->add_terms( $taxonomy, $terms );
293
294 }
295 }
296
297 /**
298 * Add WordPress templates.
299 *
300 * Adds Cartflows templates to steps
301 *
302 * @since 1.0.0
303 * @access public
304 */
305 public function add_wp_templates_support() {
306 add_filter( 'theme_' . CARTFLOWS_STEP_POST_TYPE . '_templates', array( $this, 'add_page_templates' ), 99, 4 );
307 }
308
309 /**
310 * Add page templates.
311 *
312 * @since 1.0.0
313 * @access public
314 *
315 * @param array $page_templates Array of page templates.
316 *
317 * @param object $wp_theme wp theme.
318 * @param object $post post.
319 *
320 * @return array Page templates.
321 */
322 public function add_page_templates( $page_templates, $wp_theme, $post ) {
323
324 $cartflows_templates = array(
325 'cartflows-default' => _x( 'CartFlows — Boxed', 'cartflows' ),
326 'cartflows-canvas' => _x( 'Template for Page Builders', 'cartflows' ),
327 );
328
329 if ( apply_filters( 'cartflows_show_all_page_templates', false ) ) {
330 $cartflows_templates = array_merge( $cartflows_templates, $page_templates );
331 }
332
333 return $cartflows_templates;
334 }
335
336 /**
337 * Query fixe throwing error on 404 page due our post type changes.
338 * We are setting post_type as empty array to fix the issue.
339 * Ther error was throwing due to redirect_canonical function
340 * This fix is apply for 404 page only.
341 *
342 * Also redirects disabled steps to the next enabled step in the flow.
343 */
344 public function query_fix() {
345
346 global $wp_query, $post;
347
348 if ( $wp_query->is_404() ) {
349 $wp_query->set( 'post_type', array() );
350 } elseif ( ! empty( $post->ID ) && CARTFLOWS_STEP_POST_TYPE == $post->post_type && wcf()->utils->is_step_disabled( $post->ID ) ) {
351 $flow_id = (int) wcf()->utils->get_flow_id_from_step_id( $post->ID );
352 $steps = get_post_meta( $flow_id, 'wcf-steps', true );
353 $next_step_url = '';
354 if ( is_array( $steps ) && ! empty( $steps ) ) {
355
356 // Locate the current step first. Scanning the list from the top always
357 // returned step 1, so disabling step 3 of 5 sent the visitor backwards.
358 $current_index = -1;
359
360 foreach ( $steps as $index => $step ) {
361 if ( isset( $step['id'] ) && intval( $post->ID ) === intval( $step['id'] ) ) {
362 $current_index = $index;
363 break;
364 }
365 }
366
367 // Prefer the next enabled step after the current one. If every later step
368 // is disabled too, wrap around so the visitor is never left on a disabled
369 // page. An unknown current step leaves $current_index at -1, which scans
370 // the whole flow from the start.
371 $search_order = array_merge(
372 array_slice( $steps, $current_index + 1 ),
373 array_slice( $steps, 0, $current_index + 1 )
374 );
375
376 foreach ( $search_order as $step ) {
377 if ( isset( $step['id'] ) && intval( $post->ID ) !== intval( $step['id'] ) && ! wcf()->utils->is_step_disabled( $step['id'] ) ) {
378 $next_step_url = get_permalink( $step['id'] );
379 break;
380 }
381 }
382 }
383
384 if ( $next_step_url ) {
385 wp_safe_redirect( $next_step_url );
386 exit;
387 }
388 }
389 }
390
391 /**
392 * Prevent slug duplicated
393 *
394 * @param string $slug post slug.
395 * @param int $post_ID post id.
396 * @param string $post_status post status.
397 * @param string $post_type post type.
398 * @param int $post_parent post parent id.
399 * @param string $original_slug original slug.
400 * @return string
401 */
402 public function prevent_slug_duplicates( $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug ) {
403
404 $check_post_types = array(
405 'post',
406 'page',
407 CARTFLOWS_STEP_POST_TYPE,
408 );
409
410 if ( ! in_array( $post_type, $check_post_types, true ) ) {
411 return $slug;
412 }
413
414 if ( CARTFLOWS_STEP_POST_TYPE == $post_type ) {
415 // Saving a post, check for duplicates in POST or PAGE post types.
416 $post_match = get_page_by_path( $slug, 'OBJECT', 'post' );
417 $page_match = get_page_by_path( $slug, 'OBJECT', 'page' );
418
419 if ( $post_match || $page_match ) {
420 $slug .= '-2';
421 }
422 } else {
423
424 // Saving a POST or PAGE, check for duplicates in CARTFLOWS_STEP_POST_TYPE post type.
425 $custom_post_type_match = get_page_by_path( $slug, 'OBJECT', CARTFLOWS_STEP_POST_TYPE );
426
427 if ( $custom_post_type_match ) {
428 $slug .= '-2';
429 }
430 }
431
432 return $slug;
433 }
434
435 /**
436 * Add Update messages for any custom post type
437 *
438 * @param array $messages Array of default messages.
439 */
440 public function post_update_messages( $messages ) {
441
442 $custom_post_type = get_post_type( get_the_ID() );
443
444 if ( CARTFLOWS_STEP_POST_TYPE == $custom_post_type ) {
445
446 $obj = get_post_type_object( $custom_post_type );
447 $singular_name = $obj->labels->singular_name;
448 $messages[ $custom_post_type ] = array(
449 0 => '', // Unused. Messages start at index 1.
450 /* translators: %s: singular custom post type name */
451 1 => sprintf( __( '%s updated.', 'cartflows' ), $singular_name ),
452 /* translators: %s: singular custom post type name */
453 2 => sprintf( __( 'Custom %s updated.', 'cartflows' ), $singular_name ),
454 /* translators: %s: singular custom post type name */
455 3 => sprintf( __( 'Custom %s deleted.', 'cartflows' ), $singular_name ),
456 /* translators: %s: singular custom post type name */
457 4 => sprintf( __( '%s updated.', 'cartflows' ), $singular_name ),
458 /* translators: %1$s: singular custom post type name ,%2$s: date and time of the revision */
459 5 => isset( $_GET['revision'] ) ? sprintf( __( '%1$s restored to revision from %2$s', 'cartflows' ), $singular_name, wp_post_revision_title( (int) $_GET['revision'], false ) ) : false, //phpcs:ignore WordPress.Security.NonceVerification.Recommended
460 /* translators: %s: singular custom post type name */
461 6 => sprintf( __( '%s published.', 'cartflows' ), $singular_name ),
462 /* translators: %s: singular custom post type name */
463 7 => sprintf( __( '%s saved.', 'cartflows' ), $singular_name ),
464 /* translators: %s: singular custom post type name */
465 8 => sprintf( __( '%s submitted.', 'cartflows' ), $singular_name ),
466 /* translators: %s: singular custom post type name */
467 9 => sprintf( __( '%s scheduled for.', 'cartflows' ), $singular_name ),
468 /* translators: %s: singular custom post type name */
469 10 => sprintf( __( '%s draft updated.', 'cartflows' ), $singular_name ),
470 );
471 }
472
473 return $messages;
474 }
475
476 /**
477 * Add Terms for Taxonomy.
478 *
479 * => Example.
480 *
481 * $taxonomy = '{taxonomy}';
482 * $terms = array(
483 * array(
484 * 'name' => 'Landing',
485 * 'slug' => 'landing',
486 * ),
487 * array(
488 * 'name' => 'Checkout',
489 * 'slug' => 'checkout',
490 * ),
491 * );
492 *
493 * self::add_terms( $taxonomy, $terms );
494 *
495 * @since 1.0.0
496 * @param string $taxonomy Taxonomy Name.
497 * @param array $terms Terms list.
498 * @return void
499 */
500 public function add_terms( $taxonomy = '', $terms = array() ) {
501
502 foreach ( $terms as $key => $term ) {
503
504 $term_exist = term_exists( $term['slug'], $taxonomy );
505
506 if ( empty( $term_exist ) ) {
507
508 /**
509 * Add additional args if passed from request.
510 *
511 * @see https://codex.wordpress.org/Function_Reference/wp_insert_term
512 */
513 if ( array_key_exists( 'args', $term ) ) {
514 wp_insert_term( $term['name'], $taxonomy, $term['args'] );
515 } else {
516
517 $term['args'] = array( $term['slug'] );
518
519 wp_insert_term( $term['name'], $taxonomy, $term['args'] );
520 }
521 }
522 }
523 }
524
525 /**
526 * Redirect admin pages.
527 *
528 * @return void
529 */
530 public function disallowed_admin_all_steps_view() {
531
532 global $pagenow;
533
534 // Check current admin page. If step post type view redirect it to flow.
535 if ( 'edit.php' === $pagenow && isset( $_GET['post_type'] ) && CARTFLOWS_STEP_POST_TYPE === $_GET['post_type'] ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
536
537 if ( isset( $_GET['debug'] ) && 'true' === sanitize_text_field( $_GET['debug'] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
538 return;
539 }
540
541 wp_safe_redirect( admin_url( 'edit.php?post_type=' . CARTFLOWS_FLOW_POST_TYPE ) );
542 exit;
543 }
544 }
545 }
546
547 /**
548 * Kicking this off by calling 'get_instance()' method
549 */
550 Cartflows_Step_Post_Type::get_instance();
551