PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.12.7
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.12.7
3.13.3 3.13.2 3.13.1 3.13.0 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.1 3.12.2 3.12.0 3.11.1 3.11.0 3.10.9 3.10.8 3.10.7 3.10.6 2.8.16 All 261 releases
wpfunnels / admin / modules / layout / class-wpfnl-template-layout.php

class-wpfnl-template-layout.php in WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell 3.12.7, at admin/modules/layout/class-wpfnl-template-layout.php

397 lines 12.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPFunnels\Admin\Module\Layout;
4
5 use WPFunnels\Wpfnl;
6 use WPFunnels\Wpfnl_functions;
7
8
9 /**
10 * TemplateLayout class for managing the layout and steps of a funnel in WP Funnels.
11 *
12 * @since 3.2.1
13 */
14 class TemplateLayout {
15
16 /**
17 * Funnel ID.
18 *
19 * @var int
20 * @since 3.2.1
21 */
22 protected $funnel_id;
23
24 /**
25 * Funnel object.
26 *
27 * @var object
28 * @since 3.2.1
29 */
30 protected $funnel;
31
32 /**
33 * Funnel type.
34 *
35 * @var string
36 * @since 3.2.1
37 */
38 protected $funnel_type;
39
40
41 /**
42 * Array of steps.
43 *
44 * @var array
45 * @since 3.2.1
46 */
47 protected $steps_array = [];
48
49 /**
50 * Funnel data.
51 *
52 * @var array
53 * @since 3.2.1
54 */
55 protected $funnel_data = [
56 'drawflow' => [
57 'Home' => [
58 'data' => [
59
60 ]
61
62 ]
63 ]
64 ];
65
66 /**
67 * Constructor to initialize funnel properties.
68 *
69 * @param object $funnel Funnel object.
70 * @param int $funnel_id Funnel ID.
71 * @param string $funnel_type Funnel type.
72 * @param array $steps_array Array of steps.
73 *
74 * @since 3.2.1
75 */
76 public function __construct($funnel, $funnel_id, $funnel_type, $steps_array = []) {
77 $this->funnel = $funnel;
78 $this->funnel_id = $funnel_id;
79 $this->funnel_type = $funnel_type;
80 $this->steps_array = $steps_array;
81 }
82
83
84 /**
85 * Create steps for the funnel.
86 *
87 * @since 3.2.1
88 */
89 public function create_step() {
90 $index = 1;
91 $previous_index = null;
92 if (!empty($this->steps_array)) {
93 foreach ($this->steps_array as $single_step) {
94 $step_index = $this->create_and_prepare_step($single_step, $index, $previous_index);
95 $previous_index = $step_index;
96 $index++;
97 }
98 }
99 }
100
101
102 /**
103 * Create and prepare a step for the funnel.
104 *
105 * @param array $step_info Step information.
106 * @param int $index Step index.
107 * @param int|null $previous_index Previous step index.
108 *
109 * @return int Current step index.
110 *
111 * @since 3.2.1
112 */
113 private function create_and_prepare_step($step_info, $index, $previous_index) {
114 $step = Wpfnl::get_instance()->step_store;
115 $step_id = $step->create_step($this->funnel_id, $step_info['name'], $step_info['value']);
116 $step->set_id($step_id);
117
118 // Prepare step data
119 $step_data = $this->prepare_step_data($step_id, $step_info, $index);
120
121 if ($previous_index !== null) {
122 $step_data['inputs']['input_1']['connections'][] = [
123 'node' => $previous_index,
124 'input' => 'output_1'
125 ];
126 }
127
128 $this->funnel_data['drawflow']['Home']['data'][$index] = $step_data;
129
130 if ($previous_index !== null) {
131 $this->funnel_data['drawflow']['Home']['data'][$previous_index]['outputs']['output_1']['connections'][] = [
132 'node' => $index,
133 'output' => 'input_1'
134 ];
135 }
136
137 // Conditional step settings are a Pro feature — skip for free installs.
138 $is_pro_active = apply_filters( 'wpfunnels/is_pro_license_activated', false );
139 if ( $is_pro_active && isset($step_info['isCondition']) && $step_info['isCondition']) {
140 $this->funnel->update_meta($step_id, '_wpfnl_maybe_enable_condition', 'yes');
141 $this->handle_conditions($step_info, $index);
142 }
143
144
145 return $index;
146 }
147
148
149 /**
150 * Prepare step data.
151 *
152 * @param int $step_id Step ID.
153 * @param array $step_info Step information.
154 * @param int $index Step index.
155 *
156 * @return array Prepared step data.
157 *
158 * @since 3.2.1
159 */
160 private function prepare_step_data($step_id, $step_info, $index) {
161 $outputs = [
162 'output_1' => [
163 'connections' => []
164 ]
165 ];
166
167 if (isset($step_info['isCondition']) && $step_info['isCondition']) {
168 $is_pro_active = apply_filters( 'wpfunnels/is_pro_license_activated', false );
169 if ( $is_pro_active ) {
170 $outputs['output_2'] = [
171 'connections' => []
172 ];
173 }
174 }
175 $edit_post_link = base64_encode(get_edit_post_link($step_id));
176 $view_link = base64_encode(get_the_permalink($step_id));
177 return [
178 'id' => $index,
179 'name' => strtolower($step_info['name']),
180 'data' => [
181 'step_edit_link' => $edit_post_link, // Generate or provide the actual edit link
182 'step_id' => $step_id,
183 'step_type' => strtolower($step_info['value']),
184 'step_view_link' => $view_link, // Generate or provide the actual view link
185 ],
186 'class' => strtolower($step_info['value']),
187 'html' => strtolower($step_info['value']) . $step_id,
188 'typenode' => 'vue',
189 'inputs' => [
190 'input_1' => [
191 'connections' => []
192 ]
193 ],
194 'outputs' => $outputs,
195 'pos_x' => $step_info['pos_x'],
196 'pos_y' => $step_info['pos_y'],
197 ];
198 }
199
200
201 /**
202 * Handle conditions for steps.
203 *
204 * @param array $step_info Step information.
205 * @param int $parent_index Parent step index.
206 *
207 * @since 3.2.1
208 */
209 private function handle_conditions($step_info, $parent_index) {
210 $true_conditions = $step_info['trueCondition'];
211 $false_conditions = $step_info['falseCondition'];
212 $this->create_conditions($true_conditions, $parent_index, 'output_1');
213 $this->create_conditions($false_conditions, $parent_index, 'output_2');
214 }
215
216 private function create_conditions($conditions, $parent_index, $parent_output) {
217 $previous_index = $parent_index;
218 $is_first_condition = true;
219
220 foreach ($conditions as $condition) {
221 $step = Wpfnl::get_instance()->step_store;
222 $step_id = $step->create_step($this->funnel_id, $condition['name'], $condition['value']);
223 $step->set_id($step_id);
224
225 $current_index = count($this->funnel_data['drawflow']['Home']['data']) + 1;
226 $step_data = $this->prepare_step_data($step_id, $condition, $current_index);
227
228 if ($is_first_condition) {
229 $step_data['inputs']['input_1']['connections'][] = [
230 'node' => $parent_index,
231 'input' => $parent_output
232 ];
233 $is_first_condition = false;
234
235 $this->funnel_data['drawflow']['Home']['data'][$previous_index]['outputs'][$parent_output]['connections'][] = [
236 'node' => $current_index,
237 'output' => 'input_1'
238 ];
239
240 } else {
241 $step_data['inputs']['input_1']['connections'][] = [
242 'node' => $previous_index,
243 'input' => 'output_1'
244 ];
245
246 $this->funnel_data['drawflow']['Home']['data'][$previous_index]['outputs']['output_1']['connections'][] = [
247 'node' => $current_index,
248 'output' => 'input_1'
249 ];
250
251 }
252
253 $this->funnel_data['drawflow']['Home']['data'][$current_index] = $step_data;
254
255 if (isset($condition['isCondition']) && $condition['isCondition']) {
256 $this->handle_conditions($condition, $current_index);
257 }
258
259 $previous_index = $current_index;
260 }
261 }
262
263
264 /**
265 * Create conditions for steps.
266 *
267 * @param array $conditions Conditions data.
268 * @param int $parent_index Parent step index.
269 * @param string $parent_output Parent output connection.
270 *
271 * @since 3.2.1
272 */
273 public function save_funnel_data(){
274 $this->funnel->update_meta($this->funnel_id, '_funnel_data', $this->funnel_data);
275 $this->funnel->update_meta($this->funnel_id, 'wpfnls_is_newui_migrated', 'yes');
276 $this->funnel->update_meta($this->funnel_id, 'funnel_identifier', []);
277 $steps_order = $this->get_steps_order($this->funnel_data);
278 $this->funnel->update_meta($this->funnel_id, '_steps', $steps_order);
279 $this->funnel->update_meta($this->funnel_id, '_steps_order', $steps_order);
280 }
281
282
283 /**
284 * Get the order of steps.
285 *
286 * @param array $funnel_data Funnel data.
287 *
288 * @return array Steps order.
289 *
290 * @since 3.2.1
291 */
292 private function get_steps_order($funnel_flow_data)
293 {
294 $drawflow = $funnel_flow_data['drawflow'];
295 $step_order = array();
296 $start_node = array();
297
298 if (isset($drawflow['Home']['data'])) {
299 $drawflow_data = $drawflow['Home']['data'];
300
301 /**
302 * If has only one step, that only step will be the first step, no conditions should be checked.
303 * just return the step order
304 */
305 if (1 === count($drawflow_data)) {
306 $node_id = array_keys($drawflow_data)[0];
307 $data = $drawflow_data[$node_id];
308 $step_data = isset($data['data']) ? $data['data'] : array();
309 $step_type = isset($step_data['step_type']) ? $step_data['step_type'] : '';
310 $step_id = isset($step_data['step_id']) ? $step_data['step_id'] : 0;
311 $step_order[] = array(
312 'id' => $step_id,
313 'step_type' => $step_type,
314 'name' => sanitize_text_field(get_the_title($step_id)),
315 );
316 return $step_order;
317
318 }
319
320 /**
321 * 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
322 * step information includes output connection and input connection and it will be stored on $nodes
323 */
324 foreach ($drawflow_data as $key => $data) {
325 $step_data = $data['data'];
326
327 $step_type = $step_data['step_type'];
328 $step_id = 'conditional' !== $step_type && 'addstep' !== $step_type ? $step_data['step_id'] : 0;
329 if (
330 (isset($data['outputs']['output_1']['connections']) && count($data['outputs']['output_1']['connections'])) ||
331 (isset($data['inputs']['input_1']['connections']) && count($data['inputs']['input_1']['connections']))
332 ) {
333
334 if ('conditional' === $step_type || 'addstep' === $step_type) {
335 continue;
336 }
337
338 /**
339 * A starting node is a node which has only output connection but not any input connection.
340 * 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.
341 * for other step types (checkout, offer, thankyou), we will check if the step has any output connection and no input connection.
342 */
343 if ('landing' === $step_type) {
344 if (
345 isset($data['outputs']['output_1']['connections']) && count($data['outputs']['output_1']['connections']) &&
346 (isset($data['inputs']) && (count($data['inputs']) == 0 || (isset($data['inputs']['input_1']['connections']) && count($data['inputs']['input_1']['connections']) == 0)))
347 ) {
348 $start_node = array(
349 'id' => $step_id,
350 'step_type' => $step_type,
351 'name' => sanitize_text_field(get_the_title($step_id)),
352 );
353 }
354 } else {
355 if (
356 isset($data['outputs']['output_1']['connections']) && count($data['outputs']['output_1']['connections']) &&
357 (isset($data['inputs']['input_1']['connections']) && count($data['inputs']['input_1']['connections']) === 0)
358 ) {
359 $start_node = array(
360 'id' => $step_id,
361 'step_type' => $step_type,
362 'name' => sanitize_text_field(get_the_title($step_id)),
363 );
364 } else {
365 $step_order[] = array(
366 'id' => $step_id,
367 'step_type' => $step_type,
368 'name' => sanitize_text_field(get_the_title($step_id)),
369 );
370 }
371 }
372 }
373 }
374
375 $step_order = $this->array_insert($step_order, $start_node, 0);
376 }
377 return $step_order;
378 }
379
380
381 /**
382 * Array insert element on position
383 *
384 * @param $original
385 * @param $inserted
386 * @param int $position
387 *
388 * @return mixed
389 *
390 * @since 3.2.1
391 */
392 private function array_insert(&$original, $inserted, $position)
393 {
394 array_splice($original, $position, 0, array($inserted));
395 return $original;
396 }
397 }