PluginProbe ʕ •ᴥ•ʔ
Hustle – Email Marketing, Lead Generation, Optins, Popups / 7.8.9
Hustle – Email Marketing, Lead Generation, Optins, Popups v7.8.9
7.8.14 7.8.14.1 7.8.13 7.8.13.1 trunk 3.0 3.1 3.1.1 3.1.2 3.1.3 3.1.4 4.3.2 4.4.4 4.4.5 4.4.5.1 4.4.5.4 4.6 4.6.1.1 4.6.1.4 4.7.0.2 4.7.0.3 4.7.0.7 4.7.0.9 4.7.1.0 4.7.1.1 4.8.0.0 5.0.0 5.0.1 5.0.1.1 5.0.1.2 5.1 5.1.1 5.1.2 5.1.3 5.1.3.1 5.1.3.2 5.1.4 5.1.5 6.0 6.0.1 6.0.2 6.0.3 6.0.4.2 6.0.5 6.0.6.1 6.0.7 6.0.8.1 6.0.9 7.0.0.1 7.0.2 7.0.3 7.0.4 7.1.0 7.1.1 7.2.0 7.2.1 7.3.0 7.3.1 7.3.3 7.3.5 7.3.6 7.3.7 7.4.0 7.4.1 7.4.11 7.4.13 7.4.13.1 7.4.2 7.4.3 7.4.4 7.4.5 7.4.5.1 7.4.5.2 7.4.6 7.4.7 7.5.0 7.6.0 7.6.1 7.6.3 7.6.4 7.6.6 7.7.0 7.7.1 7.8.0 7.8.1 7.8.10 7.8.10.1 7.8.10.2 7.8.11 7.8.12 7.8.12.1 7.8.2 7.8.3 7.8.4 7.8.5 7.8.6 7.8.7 7.8.8 7.8.9 7.8.9.1 7.8.9.2 7.8.9.3
wordpress-popup / inc / class-hustle-module-page-abstract.php
wordpress-popup / inc Last commit date
display-conditions 3 years ago front 10 months ago helpers 10 months ago metas 3 years ago multisite 3 years ago palettes 3 years ago provider 3 years ago providers 10 months ago templates 3 years ago update 3 years ago class-hustle-admin-page-abstract.php 10 months ago class-hustle-black-friday-campaign.php 7 months ago class-hustle-condition-factory.php 6 years ago class-hustle-cross-sell.php 10 months ago class-hustle-dashboard-admin.php 3 years ago class-hustle-data.php 3 years ago class-hustle-db.php 2 years ago class-hustle-installer.php 4 years ago class-hustle-meta.php 3 years ago class-hustle-module-admin.php 10 months ago class-hustle-module-collection.php 3 years ago class-hustle-module-page-abstract.php 2 years ago class-hustle-notifications.php 3 years ago class-hustle-settings-admin.php 3 years ago class-hustle-tutorials-page.php 4 years ago class-hustle-wp-dashboard-page.php 3 years ago hustle-deletion.php 3 years ago hustle-embedded-admin.php 3 years ago hustle-entries-admin.php 3 years ago hustle-entry-model.php 3 years ago hustle-general-data-protection.php 3 years ago hustle-init.php 7 months ago hustle-mail.php 3 years ago hustle-migration.php 3 years ago hustle-model.php 3 years ago hustle-module-model.php 10 months ago hustle-module-widget-legacy.php 3 years ago hustle-module-widget.php 3 years ago hustle-modules-common-admin-ajax.php 10 months ago hustle-popup-admin.php 3 years ago hustle-providers-admin.php 3 years ago hustle-providers.php 3 years ago hustle-settings-admin-ajax.php 3 years ago hustle-settings-page.php 3 years ago hustle-slidein-admin.php 3 years ago hustle-sshare-admin.php 3 years ago hustle-sshare-model.php 3 years ago hustle-tracking-model.php 3 years ago opt-in-geo.php 10 months ago opt-in-utils.php 3 years ago opt-in-wpmudev-api.php 3 years ago
class-hustle-module-page-abstract.php
1354 lines
1 <?php
2 /**
3 * File for Hustle_Module_Page_Abstract class.
4 *
5 * @package Hustle
6 * @since 4.0.1
7 */
8
9 /**
10 * Class Hustle_Module_Page.
11 * Base model for the listing pages and their wizards.
12 *
13 * @since 4.0.1
14 */
15 abstract class Hustle_Module_Page_Abstract extends Hustle_Admin_Page_Abstract {
16
17 /**
18 * Edit page slug defined by WordPress when registering the page.
19 *
20 * @since 4.3.1
21 * @var string
22 */
23 private $page_edit_slug;
24
25 /**
26 * Wizard page slug assigned by us.
27 *
28 * @since 4.0.1
29 * @var string
30 */
31 protected $page_edit;
32
33 /**
34 * Wizard page title.
35 *
36 * @since 4.0.1
37 * @var string
38 */
39 protected $page_edit_title;
40
41 /**
42 * Capability required for the wizard page to be available.
43 *
44 * @since 4.0.1
45 * @var string
46 */
47 protected $page_edit_capability;
48
49 /**
50 * Path to the wizard's template page relative to the 'views' folder.
51 *
52 * @since 4.0.1
53 * @var string
54 */
55 protected $page_edit_template_path;
56
57 /**
58 * Current module. Only set on wizards when the module exists.
59 *
60 * @since 4.0.3
61 * @var integer
62 */
63 protected $module = false;
64
65 /**
66 * Count of the active module of the current type.
67 *
68 * @since 4.2.0
69 * @var integer
70 */
71 private $module_count_type;
72
73 /**
74 * Module type this page belongs to.
75 *
76 * @since 4.2.0
77 * @var string
78 */
79 public $module_type;
80
81 /**
82 * Established the properties for the page.
83 *
84 * @since 4.0.1
85 */
86 protected function init() {
87
88 $this->set_page_properties();
89
90 $this->page_menu_title = $this->page_title;
91
92 $this->page = Hustle_Data::get_listing_page_by_module_type( $this->module_type );
93
94 $this->page_capability = 'hustle_edit_module';
95
96 $this->page_edit = Hustle_Data::get_wizard_page_by_module_type( $this->module_type );
97
98 $this->page_edit_capability = 'hustle_edit_module';
99
100 /* translators: module's type */
101 $this->page_edit_title = sprintf( esc_html__( 'New %s', 'hustle' ), Opt_In_Utils::get_module_type_display_name( $this->module_type ) );
102
103 add_filter( 'submenu_file', array( $this, 'admin_submenu_file' ), 10, 2 );
104
105 add_action( 'admin_head', array( $this, 'hide_unwanted_submenus' ) );
106
107 // Admin-menu-editor compatibility.
108 add_action( 'admin_menu_editor-menu_replaced', array( $this, 'hide_unwanted_submenus' ) );
109
110 // Actions to perform when the current page is the listing or the wizard page.
111 if ( ! empty( $this->current_page ) && ( $this->current_page === $this->page || $this->current_page === $this->page_edit ) ) {
112 $this->on_listing_and_wizard_actions();
113 }
114
115 }
116
117 /**
118 * Set up the page's own properties
119 * Like the current module type, page title, path to the listing page and wizard page template.
120 *
121 * @since 4.0.2
122 */
123 abstract protected function set_page_properties();
124
125 /**
126 * Actions to be performed on Dashboard page.
127 *
128 * @since 4.0.4
129 */
130 protected function on_listing_and_wizard_actions() {
131
132 if ( $this->page_edit === $this->current_page ) {
133 $this->on_wizard_only_actions();
134 } else {
135 $this->on_listing_only_actions();
136 }
137 }
138
139 /**
140 * Actions to run on listing pages only
141 *
142 * @since 4.2.0
143 */
144 private function on_listing_only_actions() {
145 add_filter( 'removable_query_args', array( $this, 'maybe_remove_paged' ) );
146 add_action( 'admin_enqueue_scripts', array( $this, 'register_listing_scripts' ), 99 );
147 }
148
149 /**
150 * Remove paged get attribute if there isn't a module and it's not the first page
151 *
152 * @since 4.0.0
153 * @param array $removable_query_args URL query args to be removed.
154 * @return array
155 */
156 public function maybe_remove_paged( $removable_query_args ) {
157 $paged = filter_input( INPUT_GET, 'paged', FILTER_VALIDATE_INT );
158 $module_type = $this->module_type;
159
160 if ( $paged && 1 !== $paged && $module_type ) {
161 $args = array(
162 'module_type' => $module_type,
163 'page' => $paged,
164 );
165 $entries_per_page = Hustle_Settings_Admin::get_per_page( 'module' );
166 $modules = Hustle_Module_Collection::instance()->get_all( null, $args, $entries_per_page );
167 if ( empty( $modules ) ) {
168 $_SERVER['REQUEST_URI'] = remove_query_arg( 'paged' );
169 $removable_query_args[] = 'paged';
170 unset( $_GET['paged'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
171 }
172 }
173
174 if ( $module_type ) {
175 self::maybe_view_stats( $module_type );
176 }
177
178 return $removable_query_args;
179 }
180
181 /**
182 * Change pagination page to the relevant one for View Stats links
183 *
184 * @param string $module_type Module type.
185 */
186 private static function maybe_view_stats( $module_type ) {
187 $module_id = filter_input( INPUT_GET, 'view-stats', FILTER_VALIDATE_INT );
188 if ( ! $module_id ) {
189 return;
190 }
191 $module_id = (string) $module_id;
192 $args = array(
193 'module_type' => $module_type,
194 'fields' => 'ids',
195 );
196 $entries_per_page = Hustle_Settings_Admin::get_per_page( 'module' );
197 $modules = Hustle_Module_Collection::instance()->get_all( null, $args );
198 $i = array_search( $module_id, $modules, true );
199 if ( false === $i ) {
200 return;
201 }
202
203 $paged = ceil( ( $i + 1 ) / $entries_per_page );
204 if ( 1 < $paged ) {
205 $_GET['paged'] = $paged;
206 }
207 }
208
209 /**
210 * Actions to run on wizard pages only
211 *
212 * @since 4.0.3
213 */
214 private function on_wizard_only_actions() {
215
216 // Set the current module on Wizards, abort if invalid.
217 $module_id = filter_input( INPUT_GET, 'id', FILTER_VALIDATE_INT );
218 $module = Hustle_Module_Collection::instance()->return_model_from_id( $module_id );
219
220 if ( is_wp_error( $module ) ) {
221 // Redirect asap.
222 add_action( 'admin_init', array( $this, 'redirect_module_not_found' ) );
223 return;
224 }
225
226 $this->module = $module;
227
228 // Scripts for all wizards.
229 add_action( 'admin_enqueue_scripts', array( $this, 'register_wizard_scripts' ) );
230
231 if ( Hustle_Module_Model::SOCIAL_SHARING_MODULE !== $this->module_type ) {
232
233 // Scripts for non ssharing wizards.
234 add_action( 'admin_enqueue_scripts', array( $this, 'register_non_sshare_wizard_scripts' ) );
235
236 // Allow rich editor in.
237 add_filter( 'user_can_richedit', '__return_true' );
238
239 // Set up all the filters and buttons for tinymce editors.
240 $this->set_up_tinymce();
241
242 // Add hustle's button to tinymce editor.
243 add_filter( 'mce_buttons', array( $this, 'register_tinymce_buttons' ) );
244
245 add_filter( 'mce_external_plugins', array( $this, 'add_hustle_tinymce_button_and_remove_externals' ) );
246 }
247 }
248
249 /**
250 * Scripts used in all wizards
251 * They used to be enqueued by Hustle_Module_Admin.
252 *
253 * @since 4.2.0
254 */
255 public function register_wizard_scripts() {
256
257 wp_enqueue_script( 'jquery-ui-sortable' );
258
259 wp_enqueue_script( 'fast_wistia', '//fast.wistia.com/assets/external/E-v1.js', array(), '1', true );
260
261 self::add_color_picker();
262 }
263
264 /**
265 * Scripts used in all listings.
266 * They used to be enqueued by Hustle_Module_Admin.
267 *
268 * @since 4.2.0
269 */
270 public function register_listing_scripts() {
271
272 wp_enqueue_script(
273 'chartjs',
274 Opt_In::$plugin_url . 'assets/js/vendor/chartjs/chart.min.js',
275 array(),
276 '2.7.2',
277 true
278 );
279 }
280
281 /**
282 * Register the scripts used in wizards, but not in the Ssharing one
283 * Scripts used to be enqueued by Hustle_Module_Admin.
284 *
285 * @since 4.2.0
286 */
287 public function register_non_sshare_wizard_scripts() {
288
289 wp_enqueue_script( 'thickbox' );
290 wp_enqueue_media();
291 wp_enqueue_script( 'media-upload' );
292
293 Opt_In_Utils::maybe_add_scripts_for_ie();
294
295 // Datepicker and timpicker for automated email in optins.
296 wp_enqueue_script( 'jquery-ui-datepicker' );
297 wp_enqueue_script(
298 'jquery-ui-timepicker',
299 Opt_In::$plugin_url . 'assets/js/vendor/jquery.timepicker.min.js',
300 array( 'jquery' ),
301 '1.3.5',
302 true
303 );
304
305 wp_enqueue_style(
306 'jquery-ui-timepicker',
307 Opt_In::$plugin_url . 'assets/css/jquery.timepicker.min.css',
308 array(),
309 '1.3.5'
310 );
311
312 // Register moment.js and its timezone extension.
313 // Used for schedule, to calculate time with timezones on client side.
314 wp_enqueue_script(
315 'hustle-moment',
316 Opt_In::$plugin_url . 'assets/js/vendor/moment.min.js',
317 array( 'jquery' ),
318 Opt_In::VERSION,
319 true
320 );
321
322 wp_enqueue_script(
323 'hustle-moment-timezone',
324 Opt_In::$plugin_url . 'assets/js/vendor/moment-timezone-with-data.min.js',
325 array( 'hustle-moment' ),
326 Opt_In::VERSION,
327 true
328 );
329 }
330
331 /**
332 * Removing all MCE external plugins which often break our pages and add Hustle's button
333 *
334 * @since 3.0.8
335 * @param array $external_plugins External plugins.
336 * @return array
337 */
338 public function add_hustle_tinymce_button_and_remove_externals( $external_plugins ) {
339 remove_all_filters( 'mce_external_plugins' );
340
341 $external_plugins = array();
342 $external_plugins['hustle'] = Opt_In::$plugin_url . 'assets/js/vendor/tiny-mce-button.js';
343 add_action( 'admin_footer', array( $this, 'add_tinymce_variables' ) );
344
345 return $external_plugins;
346 }
347
348 /**
349 * Add the current fields to the editor's selector
350 *
351 * @since 3.0.8
352 */
353 public function add_tinymce_variables() {
354
355 $var_button = array();
356 $saved_fields = $this->module->get_form_fields();
357 $var_button = array();
358
359 if ( is_array( $saved_fields ) && ! empty( $saved_fields ) ) {
360 $fields = array();
361 $ignored_fields = Hustle_Entry_Model::ignored_fields();
362
363 foreach ( $saved_fields as $field_name => $data ) {
364 if ( ! in_array( $data['type'], $ignored_fields, true ) ) {
365 $fields[ $field_name ] = esc_html( $data['label'] );
366 }
367 }
368
369 // Add Unsubscribe Link.
370 $fields['hustle_unsubscribe_link'] = esc_html__( 'Unsubscribe Link', 'hustle' );
371
372 $available_editors = array( 'success_message', 'email_body' );
373
374 /**
375 * Print JS details for the custom TinyMCE "Insert Variable" button
376 *
377 * @see assets/js/vendor/tiny-mce-button.js
378 */
379 $var_button = array(
380 /* translators: Plugin name */
381 'button_title' => sprintf( __( 'Add %s Fields', 'hustle' ), Opt_In_Utils::get_plugin_name() ),
382 'fields' => $fields,
383 'available_editors' => $available_editors,
384 );
385 }
386
387 printf(
388 '<script>window.hustleData = %s;</script>',
389 wp_json_encode( $var_button )
390 );
391 }
392
393 /**
394 * Register hustle's button for tinymce
395 *
396 * @since 4.0.0
397 * @since 4.2.0 Moved from Hustle_Module_Admin to this class.
398 *
399 * @param array $buttons Registered buttons.
400 * @return array
401 */
402 public function register_tinymce_buttons( $buttons ) {
403 array_unshift( $buttons, 'hustlefields' );
404 return $buttons;
405 }
406
407 /**
408 * Register the listing page and its wizard
409 *
410 * @return void
411 */
412 public function register_admin_menu() {
413 parent::register_admin_menu();
414
415 $this->page_edit_slug = add_submenu_page( 'hustle', $this->page_edit_title, $this->page_edit_title, $this->page_edit_capability, $this->page_edit, array( $this, 'render_edit_page' ) );
416
417 add_action( 'load-' . $this->page_edit_slug, array( $this, 'current_page_loaded' ) );
418 }
419
420 /**
421 * Get the arguments used when rendering the main page.
422 *
423 * @since 4.0.1
424 * @return array
425 */
426 protected function get_page_template_args() {
427
428 $entries_per_page = Hustle_Settings_Admin::get_per_page( 'module' );
429
430 $capability = array(
431 'hustle_create' => current_user_can( 'hustle_create' ),
432 'hustle_access_emails' => current_user_can( 'hustle_access_emails' ),
433 );
434
435 // Don't use filter_input() here, because of see Hustle_Module_Admin::maybe_remove_paged function.
436 $paged = ! empty( $_GET['paged'] ) ? (int) $_GET['paged'] : 1; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
437
438 $args = array(
439 'module_type' => $this->module_type,
440 'page' => $paged,
441 'filter' => array( 'can_edit' => true ),
442 );
443
444 $search = filter_input( INPUT_GET, 'q' );
445 if ( $search ) {
446 $args['filter']['q'] = $search;
447 }
448
449 $modules = Hustle_Module_Collection::instance()->get_all(
450 null,
451 $args,
452 $entries_per_page
453 );
454
455 $active_modules = Hustle_Module_Collection::instance()->get_all(
456 true,
457 array(
458 'module_type' => $this->module_type,
459 'count_only' => true,
460 )
461 );
462
463 return array(
464 'total' => $this->get_total_count_modules_current_type(),
465 'active' => $active_modules,
466 'modules' => $modules,
467 'is_free' => Opt_In_Utils::is_free(),
468 'capability' => $capability,
469 'entries_per_page' => $entries_per_page,
470 'message' => filter_input( INPUT_GET, 'message', FILTER_SANITIZE_SPECIAL_CHARS ),
471 'sui' => $this->get_sui_summary_config( '' ),
472 );
473 }
474
475 /**
476 * Hide module's edit pages from the submenu on dashboard.
477 *
478 * @since 4.0.1
479 */
480 public function hide_unwanted_submenus() {
481 remove_submenu_page( 'hustle', $this->page_edit );
482 }
483
484 /**
485 * Highlight submenu's parent on admin page.
486 *
487 * @since 4.0.1
488 *
489 * @param string $submenu_file The submenu file.
490 * @param string $parent_file The submenu item's parent file.
491 *
492 * @return string
493 */
494 public function admin_submenu_file( $submenu_file, $parent_file ) {
495 global $plugin_page;
496
497 if ( 'hustle' !== $parent_file ) {
498 return $submenu_file;
499 }
500
501 if ( $this->page_edit === $plugin_page ) {
502 $submenu_file = $this->page;
503 }
504
505 return $submenu_file;
506 }
507
508 /**
509 * Redirect to the listing page when in wizard and the module wasn't found.
510 *
511 * @since 4.0.0
512 */
513 public function redirect_module_not_found() {
514
515 // We're on wizard, but the current module isn't valid. Aborting.
516 $url = add_query_arg(
517 array(
518 'page' => $this->page,
519 'show-notice' => 'error',
520 'notice' => 'module-not-found',
521 'notice-close' => 'false',
522 ),
523 'admin.php'
524 );
525
526 wp_safe_redirect( $url );
527 exit;
528 }
529
530 /**
531 * Add data to the current json array.
532 *
533 * @since 4.3.1
534 *
535 * @return array
536 */
537 protected function get_vars_to_localize() {
538 $current_array = parent::get_vars_to_localize();
539
540 // Wizard page only.
541 if ( $this->module ) {
542
543 $data = $this->module->get_data();
544 $module_metas = $this->module->get_module_metas_as_array();
545
546 $current_array = $this->register_visibility_conditions_js_vars( $current_array );
547
548 $current_array += $this->get_wizard_js_variables_to_localize();
549
550 $current_array['current'] = array_merge(
551 $module_metas,
552 array(
553 'is_optin' => 'optin' === $this->module->module_mode,
554 'listing_page' => $this->page,
555 'wizard_page' => $this->page_edit,
556 'section' => $this->get_current_section(),
557 'data' => $data,
558 'shortcode_id' => $this->module->get_shortcode_id(),
559 )
560 );
561
562 $type_capitalized = Opt_In_Utils::get_module_type_display_name( $this->module_type, false, true );
563 $type_lowercase = Opt_In_Utils::get_module_type_display_name( $this->module_type );
564
565 $messages = array(
566 'module_error' => esc_html__( "Couldn't save your module settings because there were some errors on {page} tab(s). Please fix those errors and try again.", 'hustle' ),
567 'module_error_reload' => esc_html__( 'Something went wrong. Please reload this page and try saving again', 'hustle' ),
568 'module_created' => /* translators: 1. module type capitalized, 2. module type in lowercase */ sprintf( esc_html__( '%1$s created successfully. Get started by adding content to your new %2$s below.', 'hustle' ), $type_capitalized, $type_lowercase ), // only when 'is_new'.
569 );
570
571 $current_array['single_module_action_nonce'] = wp_create_nonce( 'hustle_single_action' );
572
573 $current_array['messages'] = array_merge( $current_array['messages'], $messages );
574
575 // Listing page only.
576 } elseif ( $this->page === $this->current_page ) {
577
578 $current_array['current'] = array(
579 'wizard_page' => $this->page_edit,
580 'module_type' => $this->module_type,
581 );
582
583 $current_array['labels'] = array(
584 'submissions' => Hustle_Module_Model::SOCIAL_SHARING_MODULE !== $this->module_type
585 ? /* translators: number of conversions */ esc_html__( '%d Conversions', 'hustle' )
586 : /* translators: number of shares */ esc_html__( '%d Shares', 'hustle' ),
587 /* translators: number of views */
588 'views' => esc_html__( '%d Views', 'hustle' ),
589 );
590
591 // Also defined in dashboard.
592 $current_array['single_module_action_nonce'] = wp_create_nonce( 'hustle_single_action' );
593
594 $total_modules = $this->get_total_count_modules_current_type();
595 $module_not_found_message = esc_html__( "Oops! The module you are looking for doesn't exist.", 'hustle' );
596
597 if ( 0 < $total_modules && current_user_can( 'hustle_create' ) ) {
598 $module_not_found_message .= sprintf(
599 /* translators: 1. opening 'a' tag for adding a new module, 2. closing 'a' tag, 3. opening 'a' tag for importing */
600 esc_html__( ' You can %1$screate%2$s a new module or %3$simport%2$s an existing module.', 'hustle' ),
601 '<a href="#" class="hustle-create-module">',
602 '</a>',
603 '<a href="#" class="hustle-import-module-button">'
604 );
605 }
606
607 $messages = array(
608 'module_imported' => esc_html__( 'Module successfully imported.', 'hustle' ),
609 'module_duplicated' => esc_html__( 'Module successfully duplicated.', 'hustle' ),
610 'module_tracking_reset' => esc_html__( "Module's tracking data successfully reset.", 'hustle' ),
611 'module_purge_emails' => esc_html__( "Module's Email List successfully purged.", 'hustle' ),
612 'module-not-found' => $module_not_found_message,
613 );
614
615 $current_array['messages'] = array_merge( $current_array['messages'], $messages );
616 }
617
618 // Both Wizard and Listing pages.
619 $current_array['messages']['days_and_months'] = array(
620 'days_full' => Hustle_Time_Helper::get_week_days(),
621 'days_short' => Hustle_Time_Helper::get_week_days( 'short' ),
622 'days_min' => Hustle_Time_Helper::get_week_days( 'min' ),
623 'months_full' => Hustle_Time_Helper::get_months(),
624 'months_short' => Hustle_Time_Helper::get_months( 'short' ),
625 );
626
627 $current_array['module_tabs'] = array(
628 'services' => esc_html__( 'Services', 'hustle' ),
629 'display' => esc_html__( 'Display Options', 'hustle' ),
630 );
631
632 return $current_array;
633 }
634
635 /**
636 * Include the visibility conditions variables required in js side.
637 * These used to be registered in Hustle_Module_Admin before 4.0.3.
638 *
639 * @since 4.0.3
640 *
641 * @param array $vars Current registered variables.
642 * @return array
643 */
644 private function register_visibility_conditions_js_vars( $vars ) {
645
646 $post_ids = array();
647 $page_ids = array();
648 $tag_ids = array();
649 $cat_ids = array();
650 $wc_cat_ids = array();
651 $wc_tag_ids = array();
652 $tags = array();
653 $cats = array();
654 $wc_cats = array();
655 $wc_tags = array();
656
657 $module = new Hustle_Module_Model( filter_input( INPUT_GET, 'id', FILTER_VALIDATE_INT ) );
658 if ( ! is_wp_error( $module ) ) {
659 $settings = $module->get_visibility()->to_array();
660
661 $post_ids = $this->get_conditions_ids( $settings, 'posts' );
662 $page_ids = $this->get_conditions_ids( $settings, 'pages' );
663 $tag_ids = $this->get_conditions_ids( $settings, 'tags' );
664 $cat_ids = $this->get_conditions_ids( $settings, 'categories' );
665 if ( Opt_In_Utils::is_woocommerce_active() ) {
666 $wc_cat_ids = $this->get_conditions_ids( $settings, 'wc_categories' );
667 $wc_tag_ids = $this->get_conditions_ids( $settings, 'wc_tags' );
668 }
669 }
670
671 if ( $tag_ids ) {
672 $tags = array_map(
673 array( $this, 'terms_to_select2_data' ),
674 get_categories(
675 array(
676 'hide_empty' => false,
677 'include' => $tag_ids,
678 'taxonomy' => 'post_tag',
679 )
680 )
681 );
682 }
683
684 if ( $cat_ids ) {
685 $cats = array_map(
686 array( $this, 'terms_to_select2_data' ),
687 get_categories(
688 array(
689 'include' => $cat_ids,
690 'hide_empty' => false,
691 )
692 )
693 );
694 }
695
696 if ( $wc_cat_ids ) {
697 $wc_cats = array_map(
698 array( $this, 'terms_to_select2_data' ),
699 get_categories(
700 array(
701 'include' => $wc_cat_ids,
702 'hide_empty' => false,
703 'taxonomy' => 'product_cat',
704 )
705 )
706 );
707 }
708
709 if ( $wc_tag_ids ) {
710 $wc_tags = array_map(
711 array( $this, 'terms_to_select2_data' ),
712 get_categories(
713 array(
714 'include' => $wc_tag_ids,
715 'hide_empty' => false,
716 'taxonomy' => 'product_tag',
717 )
718 )
719 );
720 }
721
722 $posts = Opt_In_Utils::get_select2_data( 'post', $post_ids );
723
724 $pages = Opt_In_Utils::get_select2_data( 'page', $page_ids );
725
726 /**
727 * Add all custom post types
728 */
729 $post_types = array();
730 $cpts = get_post_types(
731 array(
732 'public' => true,
733 '_builtin' => false,
734 ),
735 'objects'
736 );
737 foreach ( $cpts as $cpt ) {
738
739 // Skip ms_invoice.
740 if ( 'ms_invoice' === $cpt->name ) {
741 continue;
742 }
743
744 $cpt_ids = $this->get_conditions_ids( $settings, $cpt->name );
745
746 $cpt_array['name'] = $cpt->name;
747 $cpt_array['label'] = $cpt->label;
748 $cpt_array['data'] = Opt_In_Utils::get_select2_data( $cpt->name, $cpt_ids );
749
750 $post_types[ $cpt->name ] = $cpt_array;
751 }
752
753 $vars['cats'] = $cats;
754 $vars['wc_cats'] = $wc_cats;
755 $vars['wc_tags'] = $wc_tags;
756 $vars['tags'] = $tags;
757 $vars['posts'] = $posts;
758 $vars['post_types'] = $post_types;
759 $vars['pages'] = $pages;
760
761 $vars['countries'] = Opt_In_Utils::get_countries();
762 $vars['roles'] = Opt_In_Utils::get_user_roles();
763 $vars['templates'] = Opt_In_Utils::hustle_get_page_templates();
764
765 $vars['type_singular_lower'] = Opt_In_Utils::get_module_type_display_name( $this->module_type );
766
767 // Visibility conditions titles, labels and bodies.
768 $vars['messages']['conditions'] = array(
769 'visitor_logged_in' => __( 'Logged in status', 'hustle' ),
770 'shown_less_than' => __( 'Number of times visitor has seen this module', 'hustle' ),
771 'only_on_mobile' => __( "Visitor's Device", 'hustle' ),
772 'from_specific_ref' => __( 'Referrer', 'hustle' ),
773 'from_search_engine' => __( 'Source of Arrival', 'hustle' ),
774 'on_specific_url' => __( 'Specific URL', 'hustle' ),
775 'on_specific_browser' => __( "Visitor's Browser", 'hustle' ),
776 'visitor_has_never_commented' => __( 'Visitor Commented Before', 'hustle' ),
777 'not_in_a_country' => __( "Visitor's Country", 'hustle' ),
778 'on_specific_roles' => __( 'User Roles', 'hustle' ),
779 'wp_conditions' => __( 'Static Pages', 'hustle' ),
780 'archive_pages' => __( 'Archive Pages', 'hustle' ),
781 'on_specific_templates' => __( 'Page Templates', 'hustle' ),
782 'user_registration' => __( 'After Registration', 'hustle' ),
783 'page_404' => __( '404 page', 'hustle' ),
784 'posts' => __( 'Posts', 'hustle' ),
785 'pages' => __( 'Pages', 'hustle' ),
786 'categories' => __( 'Categories', 'hustle' ),
787 'tags' => __( 'Tags', 'hustle' ),
788 'wc_pages' => __( 'WooCommerce Pages', 'hustle' ),
789 'wc_categories' => __( 'WooCommerce Categories', 'hustle' ),
790 'wc_tags' => __( 'WooCommerce Tags', 'hustle' ),
791 'wc_archive_pages' => __( 'WooCommerce Archives', 'hustle' ),
792 'wc_static_pages' => __( 'WooCommerce Static Pages', 'hustle' ),
793 'cookie_set' => __( 'Browser Cookie', 'hustle' ),
794 );
795
796 $vars['messages']['condition_labels'] = array(
797 'mobile_only' => __( 'Mobile only', 'hustle' ),
798 'desktop_only' => __( 'Desktop only', 'hustle' ),
799 'any_conditions' => __( '{number} condition(s)', 'hustle' ),
800 'number_views' => '< {number}',
801 'number_views_more' => '> {number}',
802 'any' => __( 'Any', 'hustle' ),
803 'all' => __( 'All', 'hustle' ),
804 'no' => __( 'No', 'hustle' ),
805 'none' => __( 'None', 'hustle' ),
806 'true' => __( 'True', 'hustle' ),
807 'false' => __( 'False', 'hustle' ),
808 'logged_in' => __( 'Logged in', 'hustle' ),
809 'logged_out' => __( 'Logged out', 'hustle' ),
810 'only_these' => __( 'Only {number}', 'hustle' ),
811 'except_these' => __( 'All except {number}', 'hustle' ),
812 'reg_date' => __( 'Day {number} ', 'hustle' ),
813 'immediately' => __( 'Immediately', 'hustle' ),
814 'forever' => __( 'Forever', 'hustle' ),
815 'cookie_anything' => __( '{name} is anything', 'hustle' ),
816 'cookie_doesnt_exist' => __( '{name} does not exist', 'hustle' ),
817 'cookie_value' => __( '{name} {value_condition} {value}', 'hustle' ),
818 );
819
820 $vars['wp_conditions'] = array(
821 'is_front_page' => __( 'Front page', 'hustle' ),
822 'is_404' => __( '404 page', 'hustle' ),
823 'is_search' => __( 'Search results', 'hustle' ),
824 );
825
826 $vars['wc_static_pages'] = array(
827 'is_cart' => __( 'Cart', 'hustle' ),
828 'is_checkout' => __( 'Checkout', 'hustle' ),
829 'is_order_received' => __( 'Order Received', 'hustle' ),
830 'is_account_page' => __( 'My account', 'hustle' ),
831 );
832
833 $vars['archive_pages'] = array(
834 'is_category' => __( 'Category archive', 'hustle' ),
835 'is_tag' => __( 'Tag archive', 'hustle' ),
836 'is_author' => __( 'Author archive', 'hustle' ),
837 'is_date' => __( 'Date archive', 'hustle' ),
838 'is_post_type_archive' => __( 'Custom post archive', 'hustle' ),
839 );
840
841 $vars['wc_archive_pages'] = array(
842 'is_shop' => __( 'Shop', 'hustle' ),
843 'is_product_category' => __( 'Product Category', 'hustle' ),
844 'is_product_tag' => __( 'Product Tag', 'hustle' ),
845 );
846
847 $vars['less_than_expiration'] = array(
848 1 => __( 'Day', 'hustle' ),
849 7 => __( 'Week', 'hustle' ),
850 30 => __( 'Month', 'hustle' ),
851 365 => __( 'Year', 'hustle' ),
852 );
853
854 $vars['wp_cookie_set'] = array(
855 'anything' => __( 'is anything', 'hustle' ),
856 'equals' => __( 'equals', 'hustle' ),
857 'contains' => __( 'contains', 'hustle' ),
858 'matches_pattern' => __( 'matches a pattern', 'hustle' ),
859 'doesnt_equals' => __( 'does not equals', 'hustle' ),
860 'doesnt_contain' => __( 'does not contain', 'hustle' ),
861 'doesnt_match_pattern' => __( 'does not match a pattern', 'hustle' ),
862 'less_than' => __( 'is less than', 'hustle' ),
863 'less_equal_than' => __( 'is less or equal to', 'hustle' ),
864 'greater_than' => __( 'is greater than', 'hustle' ),
865 'greater_equal_than' => __( 'is greater or equal to', 'hustle' ),
866 );
867
868 $vars['roles'] = Opt_In_Utils::get_user_roles();
869 $vars['browsers'] = Opt_In_Utils::get_browsers();
870 $vars['countries'] = Opt_In_Utils::get_countries();
871 $vars['templates'] = Opt_In_Utils::hustle_get_page_templates();
872
873 return $vars;
874 }
875
876 /**
877 * Gets the JS variables to be localized in Wizard for non-ssharing modules.
878 * This method is overwritten in Hustle_Sshare_Admin.
879 *
880 * @since 4.3.0
881 *
882 * @return array
883 */
884 protected function get_wizard_js_variables_to_localize() {
885 $is_optin = Hustle_Module_Model::OPTIN_MODE === $this->module->module_mode;
886
887 $variables = array(
888 'form_fields' => $this->get_form_fields_js_vars(),
889 'schedule' => $this->get_schedule_js_vars(),
890 'palettes' => Hustle_Palettes_Helper::get_all_palettes( $is_optin ),
891 'integrations' => array(
892 'action_nonce' => wp_create_nonce( 'hustle_provider_action' ), // Also defined in integrations.
893 'fetching_list' => esc_html__( 'Fetching integration list…', 'hustle' ),
894 ),
895 'typography' => array(
896 'global_font_applied' => esc_html__( 'Your font was correctly applied to all elements', 'hustle' ),
897 'fetch_nonce' => wp_create_nonce( 'hustle_fetch_font_families' ),
898 ),
899 'media_uploader' => array(
900 'select_or_upload' => esc_html__( 'Select or Upload Image', 'hustle' ),
901 'use_this_image' => esc_html__( 'Use this image', 'hustle' ),
902 ),
903 'triggers' => array(
904 'immediately_tag' => esc_html__( 'Immediately', 'hustle' ),
905 'seconds' => esc_html__( 'seconds', 'hustle' ),
906 'minutes' => esc_html__( 'minutes', 'hustle' ),
907 'hours' => esc_html__( 'hours', 'hustle' ),
908 /* translators: 1. {time} tag to replace, 2. {unit} tag to replace */
909 'delayed_tag' => sprintf( esc_html__( 'Delay %1$s %2$s', 'hustle' ), '{time}', '{unit}' ),
910 /* translators: {value}% tag to replace */
911 'scroll_percentage_tag' => sprintf( esc_html__( '%s page scroll', 'hustle' ), '{value}%' ),
912 /* translators: {value} tag to replace */
913 'scroll_element_tag' => sprintf( esc_html__( 'Scroll to %s', 'hustle' ), '{value}' ),
914 ),
915 );
916
917 $variables['defaults'] = $this->get_defaults_settings();
918
919 return $variables;
920 }
921
922 /**
923 * Return default design settings
924 *
925 * @return array
926 */
927 private function get_defaults_settings() {
928 $defaults = $this->module->get_design()->get_border_spacing_shadow_defaults( 'desktop' );
929 $defaults += $this->module->get_design()->get_typography_defaults( 'desktop' );
930 $defaults += $this->module->get_design()->get_border_spacing_shadow_defaults( 'mobile' );
931 $defaults += $this->module->get_design()->get_typography_defaults( 'mobile' );
932
933 $design_settings = $this->module->get_design()->to_array();
934 if ( ! empty( $design_settings['base_template'] ) ) {
935 // Return template settings if the module was created based on one.
936 $templates_helper = new Hustle_Templates_Helper();
937 $template_settings = $templates_helper->get_template( $design_settings['base_template'], $this->module->module_mode );
938 if ( ! empty( $template_settings['design'] ) ) {
939 $defaults = array_merge( $defaults, $template_settings['design'] );
940 }
941 }
942
943 if ( ! empty( $design_settings['base_template'] ) ) {
944 $defaults['base_template'] = $design_settings['base_template'];
945 }
946
947 return $defaults;
948 }
949
950 /**
951 * Include the form fields variables required in js side.
952 * These used to be registered in Hustle_Module_Admin before 4.0.3.
953 *
954 * @since 4.0.3
955 *
956 * @return array
957 */
958 private function get_form_fields_js_vars() {
959 $renderer = $this->get_renderer();
960
961 $no_fields_notice_args = array(
962 array(
963 'type' => 'inline_notice',
964 'icon' => 'info',
965 'value' => __( 'You don\'t have any {field_type} field in your opt-in form.', 'hustle' ),
966 ),
967 );
968
969 $variables = array(
970 'no_fields_of_type_notice' => $renderer->get_html_for_options( $no_fields_notice_args, true ),
971 'is_required' => __( '{field} is required.', 'hustle' ),
972 'cant_empty' => __( 'This field can\'t be empty.', 'hustle' ),
973 'url_required_error_message' => __( 'Your website url is required.', 'hustle' ),
974 'required_error_message' => __( 'Your {field} is required.', 'hustle' ),
975 'date_validation_message' => __( 'Please enter a valid date.', 'hustle' ),
976 'time_validation_message' => __( 'Please enter a valid time.', 'hustle' ),
977 'validation_message' => __( 'Please enter a valid {field}.', 'hustle' ),
978 'recaptcha_error_message' => __( 'reCAPTCHA verification failed. Please try again.', 'hustle' ),
979 'recaptcha_validation_message' => __( 'reCAPTCHA verification failed. Please try again.', 'hustle' ),
980 'gdpr_required_error_message' => __( 'Please accept the terms and try again.', 'hustle' ),
981 /* translators: 1. opening 'a' tag, 2. closing 'a' tag */
982 'gdpr_message' => sprintf( __( 'I\'ve read and accept the %1$sterms & conditions%2$s', 'hustle' ), '<a href="#">', '</a>' ),
983 'label' => array(
984 'placeholder' => __( 'Enter placeholder here', 'hustle' ),
985 'name_label' => __( 'Name', 'hustle' ),
986 'name_placeholder' => __( 'E.g. John', 'hustle' ),
987 'email_label' => __( 'Email Address', 'hustle' ),
988 'enail_placeholder' => __( 'E.g. john@doe.com', 'hustle' ),
989 'phone_label' => __( 'Phone Number', 'hustle' ),
990 'phone_placeholder' => __( 'E.g. +1 300 400 500', 'hustle' ),
991 'address_label' => __( 'Address', 'hustle' ),
992 'address_placeholder' => '',
993 'hidden_label' => __( 'Hidden Field', 'hustle' ),
994 'hidden_placeholder' => '',
995 'url_label' => __( 'Website', 'hustle' ),
996 'url_placeholder' => __( 'E.g. https://example.com', 'hustle' ),
997 'text_label' => __( 'Text', 'hustle' ),
998 'text_placeholder' => __( 'E.g. Enter your nick name', 'hustle' ),
999 'number_label' => __( 'Number', 'hustle' ),
1000 'number_placeholder' => __( 'E.g. 1', 'hustle' ),
1001 'datepicker_label' => __( 'Date', 'hustle' ),
1002 'datepicker_placeholder' => __( 'Choose date', 'hustle' ),
1003 'timepicker_label' => __( 'Time', 'hustle' ),
1004 'timepicker_placeholder' => '',
1005 'recaptcha_label' => 'reCAPTCHA',
1006 'recaptcha_placeholder' => '',
1007 'gdpr_label' => __( 'GDPR', 'hustle' ),
1008 ),
1009 'recaptcha_badge_replacement' => sprintf(
1010 /* translators: 1: closing 'a' tag, 2: opening privacy 'a' tag, 3: opening terms 'a' tag */
1011 __( 'This site is protected by reCAPTCHA and the Google %2$sPrivacy Policy%1$s and %3$sTerms of Service%1$s apply.', 'hustle' ),
1012 '</a>',
1013 '<a href="https://policies.google.com/privacy" target="_blank">',
1014 '<a href="https://policies.google.com/terms" target="_blank">'
1015 ),
1016 );
1017
1018 return $variables;
1019 }
1020
1021 /**
1022 * Includes the variables used for the Schedule functionality.
1023 *
1024 * @since 4.3.0
1025 *
1026 * @return array
1027 */
1028 private function get_schedule_js_vars() {
1029 $type_lowercase = Opt_In_Utils::get_module_type_display_name( $this->module_type );
1030
1031 return array(
1032 'wp_gmt_offset' => get_option( 'gmt_offset' ),
1033 'new_schedule_set' => sprintf(
1034 /* translators: 1. module type in lowercase */
1035 esc_html__( 'Successfully added a schedule for your %1$s. However, make sure to save changes and publish your %1$s for it to start appearing as per your schedule.', 'hustle' ),
1036 esc_html( $type_lowercase )
1037 ),
1038 'months' => Hustle_Time_Helper::get_months(),
1039 'week_days' => Hustle_Time_Helper::get_week_days( 'short' ),
1040 'meridiem' => Hustle_Time_Helper::get_meridiam_periods(),
1041 );
1042 }
1043
1044 /**
1045 * Gets the conditions ID.
1046 *
1047 * @since 3.0.7
1048 * @since 4.0.3 moved from Hustle_Modules_Admin to here.
1049 *
1050 * @param array $settings Display settings.
1051 * @param string $type posts|pages|tags|categories|{cpt}.
1052 * @return array
1053 */
1054 private function get_conditions_ids( $settings, $type ) {
1055 $ids = array();
1056 if ( ! empty( $settings['conditions'] ) ) {
1057 foreach ( $settings['conditions'] as $conditions ) {
1058 if ( ! empty( $conditions[ $type ] )
1059 && ( ! empty( $conditions[ $type ][ $type ] )
1060 || ! empty( $conditions[ $type ]['selected_cpts'] ) ) ) {
1061 $new_ids = ! empty( $conditions[ $type ][ $type ] )
1062 ? $conditions[ $type ][ $type ]
1063 : $conditions[ $type ]['selected_cpts'];
1064
1065 $ids = array_merge( $ids, $new_ids );
1066 }
1067 }
1068 }
1069
1070 return array_unique( $ids );
1071 }
1072
1073 /**
1074 * Converts term object to usable object for select2
1075 *
1076 * @since 4.0.3 moved from Hustle_Modules_Admin to here.
1077 * @param stdClass $term Term.
1078 * @return stdClass
1079 */
1080 public static function terms_to_select2_data( $term ) {
1081 $obj = new stdClass();
1082 $obj->id = $term->term_id;
1083 $obj->text = $term->name;
1084 return $obj;
1085 }
1086
1087 /**
1088 * Render the module's wizard page.
1089 *
1090 * @since 4.0.1
1091 */
1092 public function render_edit_page() {
1093
1094 $template_args = $this->get_page_edit_template_args();
1095 $allowed = Opt_In_Utils::is_user_allowed( 'hustle_edit_module', $template_args['module_id'] );
1096 if ( ! $allowed ) {
1097 wp_die( esc_html__( 'Sorry, you are not allowed to access this page.' ), 403 );
1098 }
1099
1100 if ( Hustle_Module_Model::SOCIAL_SHARING_MODULE !== $this->module_type ) {
1101 wp_enqueue_editor();
1102 }
1103
1104 $main_class = $this->get_sui_wrap_class();
1105
1106 ?>
1107 <main class="<?php echo esc_attr( $main_class ); ?>">
1108
1109 <?php
1110 $renderer = $this->get_renderer();
1111 $renderer->render( $this->page_edit_template_path, $template_args );
1112 ?>
1113
1114 </main>
1115 <?php
1116 }
1117
1118 /**
1119 * Get the args for the wizard page.
1120 *
1121 * @since 4.0.1
1122 * @return array
1123 */
1124 protected function get_page_edit_template_args() {
1125 return array(
1126 'section' => $this->get_current_section( 'content' ),
1127 'module_id' => $this->module->module_id,
1128 'module' => $this->module,
1129 'is_active' => (bool) $this->module->active,
1130 'is_optin' => ( 'optin' === $this->module->module_mode ),
1131 );
1132 }
1133
1134 /**
1135 * Gets the count of the modules (both active and non active) of the current type.
1136 *
1137 * @since 4.2.0
1138 * @return int
1139 */
1140 private function get_total_count_modules_current_type() {
1141
1142 if ( is_null( $this->module_count_type ) ) {
1143 $args = array(
1144 'module_type' => $this->module_type,
1145 'count_only' => true,
1146 );
1147 $search = filter_input( INPUT_GET, 'q' );
1148 if ( $search ) {
1149 $args['filter']['q'] = $search;
1150 }
1151 $this->module_count_type = Hustle_Module_Collection::instance()->get_all(
1152 null,
1153 $args
1154 );
1155 }
1156 return $this->module_count_type;
1157 }
1158
1159 /**
1160 * Get data needed for rendering the tracking charts in the listing pages
1161 * Retrieved via AJAX.
1162 *
1163 * @since 4.0.4
1164 * @since 4.2.0 Moved from Hustle_Module_Model to this class, and $module_id param added.
1165 *
1166 * @param int $module_id ID of the requested module.
1167 */
1168 public static function get_tracking_charts_markup( $module_id ) {
1169
1170 $module = Hustle_Model::get_module( $module_id );
1171 if ( is_wp_error( $module ) ) {
1172 return '';
1173 }
1174
1175 $tracking_model = Hustle_Tracking_Model::get_instance();
1176 $total_module_conversions = $tracking_model->count_tracking_data( $module_id, 'all_conversion' );
1177 $total_module_views = $tracking_model->count_tracking_data( $module_id, 'view' );
1178 $last_entry_time = $tracking_model->get_latest_conversion_time_by_module_id( $module_id );
1179 $rate = $total_module_views ? round( ( $total_module_conversions * 100 ) / $total_module_views, 1 ) : 0;
1180 $module_sub_types = $module->get_sub_types( true );
1181
1182 $multiple_charts = array();
1183
1184 // Get each sub type's tracking data if the module type has sub types.
1185 if ( ! empty( $module_sub_types ) ) {
1186
1187 foreach ( $module_sub_types as $slug => $display_name ) {
1188
1189 $subtype = $module->module_type . '_' . $slug;
1190 $views = $tracking_model->count_tracking_data( $module_id, 'view', $subtype );
1191 $conversions = $tracking_model->count_tracking_data( $module_id, 'all_conversion', $subtype );
1192 $conversion_rate = $views ? round( ( $conversions * 100 ) / $views, 1 ) : 0;
1193
1194 $multiple_charts[ $slug ] = array(
1195 'display_name' => $display_name,
1196 'last_entry_time' => $tracking_model->get_latest_conversion_time_by_module_id( $module_id, $subtype ),
1197 'views' => $views,
1198 'conversions' => $conversions,
1199 'conversion_rate' => $conversion_rate,
1200 );
1201 }
1202 }
1203
1204 $render_arguments = array(
1205 'module' => $module,
1206 'total_module_views' => $total_module_views,
1207 'total_module_conversions' => $total_module_conversions,
1208 'tracking_types' => $module->get_tracking_types(),
1209 'last_entry_time' => $last_entry_time,
1210 'rate' => $rate,
1211 );
1212
1213 if ( $module->get_content()->has_cta() ) {
1214 $notice_for_old_data = $tracking_model->has_old_tracking_data( $module_id );
1215 $render_arguments['notice_for_old_data'] = $notice_for_old_data;
1216 }
1217
1218 ob_start();
1219
1220 $renderer = new Hustle_Layout_Helper();
1221
1222 // ELEMENT: Tracking data.
1223 $renderer->render(
1224 'admin/commons/sui-listing/elements/tracking-data',
1225 array(
1226 'render_arguments' => $render_arguments,
1227 'multiple_charts' => $multiple_charts,
1228 )
1229 );
1230
1231 $html = ob_get_clean();
1232
1233 $charts_data = self::get_charts_data( array_keys( $module_sub_types ), $total_module_views, $module );
1234
1235 $data = array(
1236 'html' => $html,
1237 'charts_data' => $charts_data,
1238 );
1239
1240 return $data;
1241 }
1242
1243 /**
1244 * Get tracking data for building charts on listing page
1245 *
1246 * @since 4.0.4
1247 * @since 4.2.0 Move from Hustle_Module_Model to this class. $module param added.
1248 *
1249 * @param array $sub_types Module's sub types.
1250 * @param int $views Module's views count.
1251 * @param Hustle_Model $module Instance of the module to get the charts data for.
1252 * @return array
1253 */
1254 private static function get_charts_data( $sub_types, $views, Hustle_Model $module ) {
1255
1256 $sql_month_start_date = date( 'Y-m-d H:i:s', strtotime( '-30 days midnight' ) );// phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
1257 $tracking_model = Hustle_Tracking_Model::get_instance();
1258 $days_array = array();
1259 $default_array = array();
1260
1261 for ( $h = 30; $h >= 0; $h-- ) {
1262 $time = strtotime( '-' . $h . ' days' );
1263 $date = date( 'Y-m-d', $time );// phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
1264 $default_array[ $date ] = 0;
1265 $days_array[] = date( 'M j, Y', $time );// phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
1266 }
1267
1268 $sub_types[] = 'overall';
1269 $conversion_types = array( 'all' );
1270
1271 if ( Hustle_Module_Model::SOCIAL_SHARING_MODULE !== $module->module_type ) {
1272 $conversion_types[] = 'cta';
1273 $conversion_types[] = 'cta_2';
1274
1275 if ( Hustle_Module_Model::OPTIN_MODE === $module->module_mode ) {
1276 $conversion_types[] = 'optin';
1277 }
1278 }
1279
1280 $data = array();
1281 foreach ( $sub_types as $sub_type ) {
1282
1283 $chart_container_id = sprintf(
1284 'hustle-%1$s-%2$s-stats--%3$s',
1285 $module->module_type,
1286 $module->module_id,
1287 $sub_type
1288 );
1289 $data[ $sub_type ] = array(
1290 'id' => $chart_container_id,
1291 'days' => $days_array,
1292 );
1293
1294 foreach ( $conversion_types as $conversion_type ) {
1295
1296 $last_month_conversions = $tracking_model->get_form_latest_tracking_data_count_grouped_by_day( $module->module_id, $sql_month_start_date, $conversion_type . '_conversion', $module->module_type, $sub_type );
1297 $last_month_views = $tracking_model->get_form_latest_tracking_data_count_grouped_by_day( $module->module_id, $sql_month_start_date, 'view', $module->module_type, $sub_type );
1298
1299 if ( ! $last_month_conversions ) {
1300 $submissions_data = $default_array;
1301 } else {
1302 $submissions_array = wp_list_pluck( $last_month_conversions, 'tracked_count', 'date_created' );
1303 $submissions_data = array_merge( $default_array, array_intersect_key( $submissions_array, $default_array ) );
1304 }
1305
1306 if ( ! $last_month_views ) {
1307 $views_data = $default_array;
1308 } else {
1309 $views_array = wp_list_pluck( $last_month_views, 'tracked_count', 'date_created' );
1310 $views_data = array_merge( $default_array, array_intersect_key( $views_array, $default_array ) );
1311 }
1312
1313 $query_sub_type = 'overall' === $sub_type ? null : $module->module_type . '_' . $sub_type;
1314 $query_conversion_type = $conversion_type . '_conversion';
1315 $sub_type_conversions = $tracking_model->count_tracking_data( $module->module_id, $query_conversion_type, $query_sub_type );
1316
1317 $data[ $sub_type ][ $conversion_type ] = array(
1318 'conversions_count' => $sub_type_conversions,
1319 'conversion_rate' => $views ? round( ( $sub_type_conversions * 100 ) / $views, 1 ) : 0,
1320 'conversions' => array_values( $submissions_data ),
1321 );
1322 }
1323
1324 $data[ $sub_type ]['views'] = array_values( $views_data );
1325 $data[ $sub_type ]['conversions'] = array_values( $submissions_data );
1326 }
1327
1328 return $data;
1329 }
1330
1331 /**
1332 * Returns whether the current module is optin.
1333 * This method should be only used in Wizard pages
1334 * because $this->module is only defined within Wizards.
1335 *
1336 * @since 4.3.0
1337 * @return boolean
1338 */
1339 public function is_optin_module() {
1340 return ! empty( $this->module ) && 'optin' === $this->module->module_mode;
1341 }
1342
1343 /**
1344 * Gets the font family names.
1345 * Used for rendering the selects.
1346 *
1347 * @since 4.3.0
1348 * @return array
1349 */
1350 public function get_font_families() {
1351 return Hustle_Meta_Base_Design::get_font_families_names();
1352 }
1353 }
1354