| 1 |
<?php |
| 2 |
/** |
| 3 |
* Abstract class of source base |
| 4 |
* |
| 5 |
* @package |
| 6 |
*/ |
| 7 |
namespace WPFunnels\TemplateLibrary; |
| 8 |
|
| 9 |
use WPFunnels\Wpfnl; |
| 10 |
use WPFunnels\Wpfnl_functions; |
| 11 |
|
| 12 |
abstract class Wpfnl_Source_Base |
| 13 |
{ |
| 14 |
abstract public function get_source(); |
| 15 |
|
| 16 |
abstract public function get_funnels($arg = []); |
| 17 |
|
| 18 |
abstract public function get_funnel($template_id); |
| 19 |
|
| 20 |
abstract public function get_data(array $args); |
| 21 |
|
| 22 |
abstract public function import_funnel($args = []); |
| 23 |
|
| 24 |
abstract public function import_step($args = []); |
| 25 |
|
| 26 |
|
| 27 |
/** |
| 28 |
* After funnel import |
| 29 |
* redirect to new funnel edit url |
| 30 |
* |
| 31 |
* @param $payload |
| 32 |
* |
| 33 |
* @return array |
| 34 |
* @since 1.0.0 |
| 35 |
*/ |
| 36 |
public function after_funnel_creation($payload) |
| 37 |
{ |
| 38 |
$funnel = Wpfnl::$instance->funnel_store; |
| 39 |
$funnel->set_id($payload['funnelID']); |
| 40 |
$funnel->set_steps_order(); |
| 41 |
|
| 42 |
// rearrange steps order |
| 43 |
$funnel_data = get_post_meta( $payload['funnelID'], 'funnel_data', true ); |
| 44 |
$funnel_data = $funnel_data ? $funnel_data : get_post_meta( $payload['funnelID'], '_funnel_data', true ); |
| 45 |
|
| 46 |
// Handle if funnel_data is JSON string |
| 47 |
if (is_string($funnel_data)) { |
| 48 |
$funnel_data = json_decode($funnel_data, true); |
| 49 |
} |
| 50 |
|
| 51 |
$imported_steps = isset($payload['importedSteps']) ? $payload['importedSteps'] : []; |
| 52 |
|
| 53 |
// Check if this is a Store Checkout funnel - check both payload flag AND funnel meta |
| 54 |
$is_store_checkout_flag = isset($payload['is_store_checkout']) && $payload['is_store_checkout'] == 'true'; |
| 55 |
$funnel_type = get_post_meta($payload['funnelID'], '_wpfnl_funnel_type', true); |
| 56 |
$is_store_checkout = $is_store_checkout_flag && ($funnel_type === 'store_checkout'); |
| 57 |
// For Store Checkout, get all steps and filter to only checkout and thankyou |
| 58 |
// This handles cases where frontend sends all steps or some steps were created before validation |
| 59 |
if ($is_store_checkout) { |
| 60 |
// Get all steps actually created for this funnel |
| 61 |
$all_funnel_steps = get_posts([ |
| 62 |
'post_type' => WPFNL_STEPS_POST_TYPE, |
| 63 |
'post_parent' => $payload['funnelID'], |
| 64 |
'posts_per_page' => -1, |
| 65 |
'post_status' => 'any', |
| 66 |
'fields' => 'ids', |
| 67 |
]); |
| 68 |
|
| 69 |
|
| 70 |
$filtered_steps = []; |
| 71 |
foreach ($all_funnel_steps as $step_id) { |
| 72 |
$step_type = get_post_meta($step_id, '_step_type', true); |
| 73 |
if (in_array($step_type, ['checkout', 'thankyou'])) { |
| 74 |
$filtered_steps[] = $step_id; |
| 75 |
} else { |
| 76 |
wp_delete_post($step_id, true); |
| 77 |
} |
| 78 |
} |
| 79 |
|
| 80 |
// If query found no steps, use the imported_steps from payload and filter those |
| 81 |
if (empty($all_funnel_steps) && !empty($imported_steps)) { |
| 82 |
foreach ($imported_steps as $step_id) { |
| 83 |
if ($step_id > 0) { |
| 84 |
$step_type = get_post_meta($step_id, '_step_type', true); |
| 85 |
if (in_array($step_type, ['checkout', 'thankyou'])) { |
| 86 |
$filtered_steps[] = $step_id; |
| 87 |
} else { |
| 88 |
// Delete steps that shouldn't be in Store Checkout |
| 89 |
wp_delete_post($step_id, true); |
| 90 |
} |
| 91 |
} |
| 92 |
} |
| 93 |
} |
| 94 |
|
| 95 |
$imported_steps = $filtered_steps; |
| 96 |
} |
| 97 |
|
| 98 |
// update the funnel metadata with newly created step |
| 99 |
$this->save_steps_meta_data( $payload['funnelID'], $imported_steps ); |
| 100 |
|
| 101 |
// Persist the store checkout step ID so the public-facing override can use it |
| 102 |
if ( $is_store_checkout ) { |
| 103 |
require_once WPFNL_DIR . 'includes/core/woocommerce/class-wpfnl-store-checkout-override.php'; |
| 104 |
\WPFunnels\WooCommerce\Wpfnl_Store_Checkout_Override::save_checkout_step_id( $payload['funnelID'] ); |
| 105 |
} |
| 106 |
|
| 107 |
// Filter drawflow data for Store Checkout to remove non-checkout/thankyou nodes |
| 108 |
if ($is_store_checkout) { |
| 109 |
|
| 110 |
if ($funnel_data && is_array($funnel_data) && isset($funnel_data['drawflow']['Home']['data'])) { |
| 111 |
$node_data = $funnel_data['drawflow']['Home']['data']; |
| 112 |
$filtered_nodes = $this->filter_store_checkout_nodes($node_data, $imported_steps); |
| 113 |
$funnel_data['drawflow']['Home']['data'] = $filtered_nodes; |
| 114 |
update_post_meta($payload['funnelID'], 'funnel_data', $funnel_data); |
| 115 |
update_post_meta($payload['funnelID'], '_funnel_data', $funnel_data); |
| 116 |
} |
| 117 |
} |
| 118 |
|
| 119 |
// Filter drawflow data for Sales funnels to remove upsell/downsell nodes |
| 120 |
$is_sales_funnel = isset($payload['goal']) && $payload['goal'] === 'sales'; |
| 121 |
if ($is_sales_funnel && !$is_store_checkout) { |
| 122 |
if ($funnel_data && is_array($funnel_data) && isset($funnel_data['drawflow']['Home']['data'])) { |
| 123 |
$node_data = $funnel_data['drawflow']['Home']['data']; |
| 124 |
$filtered_nodes = $this->filter_sales_funnel_nodes($node_data, $imported_steps); |
| 125 |
$funnel_data['drawflow']['Home']['data'] = $filtered_nodes; |
| 126 |
update_post_meta($payload['funnelID'], 'funnel_data', $funnel_data); |
| 127 |
update_post_meta($payload['funnelID'], '_funnel_data', $funnel_data); |
| 128 |
} |
| 129 |
} |
| 130 |
|
| 131 |
// Reinitialize the funnel data if Pro is not active and template contains downsell |
| 132 |
// This removes downsell nodes from the canvas for free users |
| 133 |
$is_pro_active = apply_filters( 'wpfunnels/is_pro_license_activated', false ); |
| 134 |
if ( !$is_pro_active && !$is_store_checkout && $funnel_data && is_array($funnel_data) && isset($funnel_data['drawflow']['Home']['data']) ) { |
| 135 |
$node_data = $funnel_data['drawflow']['Home']['data']; |
| 136 |
$filter_data = $this->filter_node_data($node_data); |
| 137 |
$funnel_data['drawflow']['Home']['data'] = $filter_data; |
| 138 |
update_post_meta($payload['funnelID'],'funnel_data', $funnel_data); |
| 139 |
update_post_meta($payload['funnelID'],'_funnel_data', $funnel_data); |
| 140 |
} |
| 141 |
|
| 142 |
$redirect_link = add_query_arg( |
| 143 |
[ |
| 144 |
'page' => WPFNL_EDIT_FUNNEL_SLUG, |
| 145 |
'id' => $payload['funnelID'], |
| 146 |
'step_id' => $funnel->get_first_step_id(), |
| 147 |
], |
| 148 |
admin_url('admin.php') |
| 149 |
); |
| 150 |
|
| 151 |
// Flush rewrite rules so newly created funnel/step permalinks resolve immediately. |
| 152 |
flush_rewrite_rules(); |
| 153 |
|
| 154 |
return [ |
| 155 |
'success' => true, |
| 156 |
'redirectLink' => $redirect_link, |
| 157 |
]; |
| 158 |
} |
| 159 |
|
| 160 |
|
| 161 |
/** |
| 162 |
* Update funnel metadata with newly created steps |
| 163 |
* |
| 164 |
* @param $funnel_id |
| 165 |
* @param $imported_steps |
| 166 |
* @since 3.1.2 |
| 167 |
*/ |
| 168 |
private function save_steps_meta_data( $funnel_id, $imported_steps ) { |
| 169 |
if ( !$funnel_id || empty( $imported_steps ) ) { |
| 170 |
return; |
| 171 |
} |
| 172 |
$steps = []; |
| 173 |
$identifier = []; |
| 174 |
foreach ( $imported_steps as $step_id ) { |
| 175 |
$step_title = get_the_title( $step_id ); |
| 176 |
$step_type = get_post_meta( $step_id, '_step_type', true ); |
| 177 |
$identifier[] = $step_id; |
| 178 |
$steps[] = array( |
| 179 |
'id' => $step_id, |
| 180 |
'step_type' => $step_type, |
| 181 |
'name' => $step_title |
| 182 |
); |
| 183 |
} |
| 184 |
$first_step_id = $this->get_first_step_id( $funnel_id, $steps ); |
| 185 |
update_post_meta( $funnel_id, '_steps_order', $steps ); |
| 186 |
update_post_meta( $funnel_id, '_steps', $steps ); |
| 187 |
update_post_meta( $funnel_id, '_first_step', $first_step_id ); |
| 188 |
|
| 189 |
$this->update_funnel_identifier( $funnel_id, $identifier ); |
| 190 |
} |
| 191 |
|
| 192 |
|
| 193 |
/** |
| 194 |
* Filter and reinitialize the drawflow data for freemium |
| 195 |
* template. This reinitialization takes place if and only if |
| 196 |
* free user import the freemium template. |
| 197 |
* |
| 198 |
* @param $steps_array |
| 199 |
* @return array |
| 200 |
* @since 3.1.2 |
| 201 |
*/ |
| 202 |
private function filter_node_data( $steps_array ) { |
| 203 |
|
| 204 |
if ( empty($steps_array) ) { |
| 205 |
return $steps_array; |
| 206 |
} |
| 207 |
$filtered_array = []; |
| 208 |
$thank_you_found = false; |
| 209 |
foreach ($steps_array as $key => $step) { |
| 210 |
// Skip downsell steps |
| 211 |
if ( $step['data']['step_type'] === 'downsell') { |
| 212 |
continue; |
| 213 |
} |
| 214 |
|
| 215 |
// If it's a thankyou step and hasn't been found before, add it |
| 216 |
if ($step['data']['step_type'] === 'thankyou' && !$thank_you_found) { |
| 217 |
$filtered_array[$key] = $step; |
| 218 |
$thank_you_found = true; |
| 219 |
} |
| 220 |
|
| 221 |
// If it's not an downsell, or the first thankyou, add it |
| 222 |
if ( ( $step['data']['step_type'] !== 'downsell' && !$thank_you_found) || in_array($step['data']['step_type'], array('landing', 'checkout', 'upsell' )) ) { |
| 223 |
$filtered_array[$key] = $step; |
| 224 |
} |
| 225 |
} |
| 226 |
|
| 227 |
// Find the checkout and thankyou steps |
| 228 |
$checkout_id = null; |
| 229 |
$thank_you_id = null; |
| 230 |
$upsell_id = null; |
| 231 |
$upsell_step_id = null; |
| 232 |
|
| 233 |
foreach ($filtered_array as $key => $step) { |
| 234 |
if ($step['data']['step_type'] === 'checkout') { |
| 235 |
$checkout_id = $key; |
| 236 |
} elseif ($step['data']['step_type'] === 'thankyou') { |
| 237 |
$thank_you_id = $key; |
| 238 |
} elseif ($step['data']['step_type'] === 'upsell') { |
| 239 |
$upsell_id = $key; |
| 240 |
$upsell_step_id = $step['data']['step_id']; |
| 241 |
} |
| 242 |
} |
| 243 |
|
| 244 |
// Only rebuild connections if a checkout step exists. |
| 245 |
// For lead funnels (landing → thankyou), there is no checkout step, |
| 246 |
// so $checkout_id would be null. In that case, original connections |
| 247 |
// are already correct since no downsell nodes were removed. |
| 248 |
if ( $checkout_id !== null ) { |
| 249 |
if( $upsell_id === null ) { |
| 250 |
// Update inputs of thankyou and outputs of checkout |
| 251 |
$filtered_array[$thank_you_id]['inputs'] = [ |
| 252 |
'input_1' => [ |
| 253 |
'connections' => [ |
| 254 |
[ |
| 255 |
'node' => $checkout_id, |
| 256 |
'input' => 'output_1' |
| 257 |
] |
| 258 |
] |
| 259 |
] |
| 260 |
]; |
| 261 |
|
| 262 |
$filtered_array[$checkout_id]['outputs'] = [ |
| 263 |
'output_1' => [ |
| 264 |
'connections' => [ |
| 265 |
[ |
| 266 |
'node' => $thank_you_id, |
| 267 |
'output' => 'input_1' |
| 268 |
] |
| 269 |
] |
| 270 |
] |
| 271 |
]; |
| 272 |
}else{ |
| 273 |
$filtered_array[$upsell_id]['inputs'] = [ |
| 274 |
'input_1' => [ |
| 275 |
'connections' => [ |
| 276 |
[ |
| 277 |
'node' => $checkout_id, |
| 278 |
'input' => 'output_1' |
| 279 |
] |
| 280 |
] |
| 281 |
] |
| 282 |
]; |
| 283 |
|
| 284 |
$filtered_array[$upsell_id]['outputs'] = [ |
| 285 |
'output_1' => [ |
| 286 |
'connections' => [ |
| 287 |
[ |
| 288 |
'node' => $thank_you_id, |
| 289 |
'output' => 'input_1' |
| 290 |
] |
| 291 |
] |
| 292 |
] |
| 293 |
]; |
| 294 |
|
| 295 |
$filtered_array[$checkout_id]['outputs'] = [ |
| 296 |
'output_1' => [ |
| 297 |
'connections' => [ |
| 298 |
[ |
| 299 |
'node' => $upsell_id, |
| 300 |
'output' => 'input_1' |
| 301 |
] |
| 302 |
] |
| 303 |
] |
| 304 |
]; |
| 305 |
|
| 306 |
// Update inputs of thankyou and outputs of checkout |
| 307 |
$filtered_array[$thank_you_id]['inputs'] = [ |
| 308 |
'input_1' => [ |
| 309 |
'connections' => [ |
| 310 |
[ |
| 311 |
'node' => $upsell_id, |
| 312 |
'input' => 'output_1' |
| 313 |
] |
| 314 |
] |
| 315 |
] |
| 316 |
]; |
| 317 |
|
| 318 |
delete_post_meta( $upsell_step_id, '_wpfnl_maybe_enable_condition' ); |
| 319 |
} |
| 320 |
} |
| 321 |
|
| 322 |
|
| 323 |
return $filtered_array; |
| 324 |
} |
| 325 |
|
| 326 |
|
| 327 |
/** |
| 328 |
* Get the first step id of the funnel |
| 329 |
* |
| 330 |
* @param $funnel_id |
| 331 |
* @param $steps |
| 332 |
* @return mixed|void|null |
| 333 |
* @since 3.1.2 |
| 334 |
*/ |
| 335 |
private function get_first_step_id( $funnel_id, $steps ) { |
| 336 |
if ( !$funnel_id || empty( $steps ) ) { |
| 337 |
return; |
| 338 |
} |
| 339 |
foreach ($steps as $step) { |
| 340 |
if ( !isset($step['step_id']) ) { |
| 341 |
continue; |
| 342 |
} |
| 343 |
if ($step['step_type'] === 'landing') { |
| 344 |
return $step['step_id']; |
| 345 |
} elseif ($step['step_type'] === 'checkout') { |
| 346 |
return $step['step_id']; |
| 347 |
} |
| 348 |
} |
| 349 |
|
| 350 |
// If neither landing nor checkout exists |
| 351 |
return null; |
| 352 |
} |
| 353 |
|
| 354 |
|
| 355 |
/** |
| 356 |
* Update the funnel identifier data |
| 357 |
* |
| 358 |
* @param $funnel_id |
| 359 |
* @param $identifier |
| 360 |
* @since 3.1.2 |
| 361 |
*/ |
| 362 |
private function update_funnel_identifier( $funnel_id, $identifier ) { |
| 363 |
if ( !$funnel_id || empty( $identifier ) ) { |
| 364 |
return; |
| 365 |
} |
| 366 |
$identifier_json = get_post_meta($funnel_id, 'funnel_identifier', true); |
| 367 |
$identifier_json = preg_replace('/\: *([0-9]+\.?[0-9e+\-]*)/', ':"\\1"', $identifier_json); |
| 368 |
$identifier_data = json_decode( $identifier_json, true ); |
| 369 |
|
| 370 |
if (is_array($identifier_data)) { |
| 371 |
foreach ($identifier_data as $key => $data) { |
| 372 |
if ( !in_array( $data, $identifier ) ) { |
| 373 |
unset($identifier_data[$key]); |
| 374 |
} |
| 375 |
} |
| 376 |
$funnel_identifier_json = json_encode($identifier_data, JSON_UNESCAPED_SLASHES); |
| 377 |
update_post_meta($funnel_id, 'funnel_identifier', $funnel_identifier_json); |
| 378 |
} |
| 379 |
} |
| 380 |
|
| 381 |
|
| 382 |
/** |
| 383 |
* Filter drawflow nodes for Store Checkout - only keep checkout and thankyou |
| 384 |
* |
| 385 |
* @param $steps_array |
| 386 |
* @param $imported_steps |
| 387 |
* @return array |
| 388 |
* @since 3.5.0 |
| 389 |
*/ |
| 390 |
private function filter_store_checkout_nodes( $steps_array, $imported_steps ) { |
| 391 |
if ( empty($steps_array) ) { |
| 392 |
return $steps_array; |
| 393 |
} |
| 394 |
|
| 395 |
$filtered_array = []; |
| 396 |
$checkout_id = null; |
| 397 |
$thankyou_id = null; |
| 398 |
|
| 399 |
// Only keep checkout and thankyou nodes |
| 400 |
// NOTE: Don't filter by step_id match because canvas has old template IDs, not new DB IDs |
| 401 |
// Just filter by step_type - the step IDs will be updated by update_step_id_in_funnel_data_and_identifier |
| 402 |
foreach ($steps_array as $key => $step) { |
| 403 |
$step_type = isset($step['data']['step_type']) ? $step['data']['step_type'] : ''; |
| 404 |
$step_id = isset($step['data']['step_id']) ? $step['data']['step_id'] : 0; |
| 405 |
|
| 406 |
// Keep only checkout and thankyou regardless of step_id |
| 407 |
if (in_array($step_type, ['checkout', 'thankyou'])) { |
| 408 |
$filtered_array[$key] = $step; |
| 409 |
|
| 410 |
if ($step_type === 'checkout') { |
| 411 |
$checkout_id = $key; |
| 412 |
} elseif ($step_type === 'thankyou') { |
| 413 |
$thankyou_id = $key; |
| 414 |
} |
| 415 |
} |
| 416 |
} |
| 417 |
|
| 418 |
// Update connections: checkout -> thankyou |
| 419 |
if ($checkout_id !== null && $thankyou_id !== null) { |
| 420 |
$filtered_array[$checkout_id]['outputs'] = [ |
| 421 |
'output_1' => [ |
| 422 |
'connections' => [ |
| 423 |
[ |
| 424 |
'node' => $thankyou_id, |
| 425 |
'output' => 'input_1' |
| 426 |
] |
| 427 |
] |
| 428 |
] |
| 429 |
]; |
| 430 |
|
| 431 |
$filtered_array[$thankyou_id]['inputs'] = [ |
| 432 |
'input_1' => [ |
| 433 |
'connections' => [ |
| 434 |
[ |
| 435 |
'node' => $checkout_id, |
| 436 |
'input' => 'output_1' |
| 437 |
] |
| 438 |
] |
| 439 |
] |
| 440 |
]; |
| 441 |
} |
| 442 |
|
| 443 |
return $filtered_array; |
| 444 |
} |
| 445 |
|
| 446 |
/** |
| 447 |
* Filter drawflow nodes for sales funnels to only include landing, checkout, and thankyou |
| 448 |
* Remove upsell and downsell nodes |
| 449 |
* |
| 450 |
* @param array $steps_array |
| 451 |
* @param array $imported_steps |
| 452 |
* @return array |
| 453 |
* @since 3.7.0 |
| 454 |
*/ |
| 455 |
private function filter_sales_funnel_nodes( $steps_array, $imported_steps ) { |
| 456 |
if ( empty($steps_array) ) { |
| 457 |
return $steps_array; |
| 458 |
} |
| 459 |
|
| 460 |
$filtered_array = []; |
| 461 |
$landing_id = null; |
| 462 |
$checkout_id = null; |
| 463 |
$thankyou_id = null; |
| 464 |
|
| 465 |
// Only keep landing, checkout, and thankyou nodes |
| 466 |
foreach ($steps_array as $key => $step) { |
| 467 |
$step_type = isset($step['data']['step_type']) ? $step['data']['step_type'] : ''; |
| 468 |
|
| 469 |
// Keep only landing, checkout, and thankyou - exclude upsell and downsell |
| 470 |
if (in_array($step_type, ['landing', 'checkout', 'thankyou'])) { |
| 471 |
$filtered_array[$key] = $step; |
| 472 |
|
| 473 |
if ($step_type === 'landing') { |
| 474 |
$landing_id = $key; |
| 475 |
} elseif ($step_type === 'checkout') { |
| 476 |
$checkout_id = $key; |
| 477 |
} elseif ($step_type === 'thankyou') { |
| 478 |
$thankyou_id = $key; |
| 479 |
} |
| 480 |
} |
| 481 |
} |
| 482 |
|
| 483 |
// Update connections: landing -> checkout -> thankyou |
| 484 |
if ($landing_id !== null && $checkout_id !== null && $thankyou_id !== null) { |
| 485 |
// Landing page outputs to checkout |
| 486 |
$filtered_array[$landing_id]['outputs'] = [ |
| 487 |
'output_1' => [ |
| 488 |
'connections' => [ |
| 489 |
[ |
| 490 |
'node' => $checkout_id, |
| 491 |
'output' => 'input_1' |
| 492 |
] |
| 493 |
] |
| 494 |
] |
| 495 |
]; |
| 496 |
|
| 497 |
// Checkout receives from landing and outputs to thankyou |
| 498 |
$filtered_array[$checkout_id]['inputs'] = [ |
| 499 |
'input_1' => [ |
| 500 |
'connections' => [ |
| 501 |
[ |
| 502 |
'node' => $landing_id, |
| 503 |
'input' => 'output_1' |
| 504 |
] |
| 505 |
] |
| 506 |
] |
| 507 |
]; |
| 508 |
$filtered_array[$checkout_id]['outputs'] = [ |
| 509 |
'output_1' => [ |
| 510 |
'connections' => [ |
| 511 |
[ |
| 512 |
'node' => $thankyou_id, |
| 513 |
'output' => 'input_1' |
| 514 |
] |
| 515 |
] |
| 516 |
] |
| 517 |
]; |
| 518 |
|
| 519 |
// Thankyou receives from checkout |
| 520 |
$filtered_array[$thankyou_id]['inputs'] = [ |
| 521 |
'input_1' => [ |
| 522 |
'connections' => [ |
| 523 |
[ |
| 524 |
'node' => $checkout_id, |
| 525 |
'input' => 'output_1' |
| 526 |
] |
| 527 |
] |
| 528 |
] |
| 529 |
]; |
| 530 |
} |
| 531 |
|
| 532 |
return $filtered_array; |
| 533 |
} |
| 534 |
|
| 535 |
|
| 536 |
/** |
| 537 |
* After funnel import |
| 538 |
* redirect to new funnel edit url |
| 539 |
* |
| 540 |
* @param $payload |
| 541 |
* |
| 542 |
* @return array |
| 543 |
* @since 1.0.0 |
| 544 |
*/ |
| 545 |
public function after_step_creation($payload) |
| 546 |
{ |
| 547 |
$redirect_link = add_query_arg( |
| 548 |
[ |
| 549 |
'page' => WPFNL_EDIT_FUNNEL_SLUG, |
| 550 |
'id' => $payload['funnelID'], |
| 551 |
'step_id' => $payload['stepID'], |
| 552 |
], |
| 553 |
admin_url('admin.php') |
| 554 |
); |
| 555 |
return [ |
| 556 |
'success' => true, |
| 557 |
'redirectLink' => $redirect_link, |
| 558 |
]; |
| 559 |
} |
| 560 |
|
| 561 |
|
| 562 |
/** |
| 563 |
* Get steps order |
| 564 |
* |
| 565 |
* @param $funnel_flow_data |
| 566 |
* |
| 567 |
* @return array |
| 568 |
* |
| 569 |
* @since 2.2.6 |
| 570 |
*/ |
| 571 |
private function get_steps_order( $funnel_flow_data ) { |
| 572 |
$drawflow = $funnel_flow_data['drawflow']; |
| 573 |
$nodes = array(); |
| 574 |
$step_order = array(); |
| 575 |
$first_node_id = ''; |
| 576 |
$start_node = array(); |
| 577 |
|
| 578 |
|
| 579 |
if( isset( $drawflow['Home']['data'] ) ) { |
| 580 |
$drawflow_data = $drawflow['Home']['data']; |
| 581 |
|
| 582 |
/** |
| 583 |
* If has only one step, that only step will be the first step, no conditions should be checked. |
| 584 |
* just return the step order |
| 585 |
*/ |
| 586 |
if( 1 === count( $drawflow_data ) ) { |
| 587 |
$node_id = array_keys($drawflow_data)[0]; |
| 588 |
$data = $drawflow_data[$node_id]; |
| 589 |
$step_data = $data['data']; |
| 590 |
$step_id = $step_data['step_id']; |
| 591 |
$step_type = $step_data['step_type']; |
| 592 |
$step_order[] = array( |
| 593 |
'id' => $step_id, |
| 594 |
'step_type' => $step_type, |
| 595 |
'name' => sanitize_text_field( get_the_title( $step_id ) ), |
| 596 |
); |
| 597 |
return $step_order; |
| 598 |
|
| 599 |
} |
| 600 |
|
| 601 |
/** |
| 602 |
* First we will find the first node (the node which has only output connection but no input connection will be considered as first node) and the list of nodes array which has the |
| 603 |
* Step information includes output connection and input connection and it will be stored on $nodes |
| 604 |
*/ |
| 605 |
foreach ( $drawflow_data as $key => $data ) { |
| 606 |
$step_data = $data['data']; |
| 607 |
$step_type = $step_data['step_type']; |
| 608 |
$step_id = $step_type !== 'conditional' ? $step_data['step_id'] : 0; |
| 609 |
if( |
| 610 |
(isset( $data['outputs']['output_1']['connections'] ) && count( $data['outputs']['output_1']['connections'] ) ) || |
| 611 |
(isset( $data['inputs']['input_1']['connections'] ) && count($data['inputs']['input_1']['connections']) ) |
| 612 |
) { |
| 613 |
|
| 614 |
if('conditional' === $step_type) { |
| 615 |
continue; |
| 616 |
} |
| 617 |
|
| 618 |
/** |
| 619 |
* A starting node is a node which has only output connection but not any input connection. |
| 620 |
* If the step is landing, then there should not be any input connection for this step. so we will only consider the output connection for landing only. |
| 621 |
* For other step types (checkout, offer, thankyou), we will check if the step has any output connection and no input connection. |
| 622 |
*/ |
| 623 |
if( 'landing' === $step_type ) { |
| 624 |
if ( |
| 625 |
isset($data['outputs']['output_1']['connections']) && count($data['outputs']['output_1']['connections']) && |
| 626 |
(isset( $data['inputs'] ) && count($data['inputs']) == 0 ) |
| 627 |
) { |
| 628 |
$start_node = array( |
| 629 |
'id' => $step_id, |
| 630 |
'step_type' => $step_type, |
| 631 |
'name' => sanitize_text_field(get_the_title($step_id)), |
| 632 |
); |
| 633 |
} |
| 634 |
} else { |
| 635 |
if ( |
| 636 |
isset($data['outputs']['output_1']['connections']) && count($data['outputs']['output_1']['connections']) && |
| 637 |
(isset($data['inputs']['input_1']['connections']) && count($data['inputs']['input_1']['connections']) === 0) |
| 638 |
) { |
| 639 |
$start_node = array( |
| 640 |
'id' => $step_id, |
| 641 |
'step_type' => $step_type, |
| 642 |
'name' => sanitize_text_field(get_the_title($step_id)), |
| 643 |
); |
| 644 |
} else { |
| 645 |
$step_order[] = array( |
| 646 |
'id' => $step_id, |
| 647 |
'step_type' => $step_type, |
| 648 |
'name' => sanitize_text_field(get_the_title($step_id)), |
| 649 |
); |
| 650 |
} |
| 651 |
} |
| 652 |
} |
| 653 |
} |
| 654 |
$step_order = $this->array_insert($step_order, $start_node, 0); |
| 655 |
} |
| 656 |
return $step_order; |
| 657 |
} |
| 658 |
|
| 659 |
|
| 660 |
/** |
| 661 |
* Array insert element on position |
| 662 |
* |
| 663 |
* @param $original |
| 664 |
* @param $inserted |
| 665 |
* @param int $position |
| 666 |
* |
| 667 |
* @return mixed |
| 668 |
*/ |
| 669 |
private function array_insert(&$original, $inserted, $position) { |
| 670 |
array_splice($original, $position, 0, array($inserted)); |
| 671 |
return $original; |
| 672 |
} |
| 673 |
|
| 674 |
} |
| 675 |
|