PluginProbe ʕ •ᴥ•ʔ
Hustle – Email Marketing, Lead Generation, Optins, Popups / 7.3.7
Hustle – Email Marketing, Lead Generation, Optins, Popups v7.3.7
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 / front / hustle-module-front.php
wordpress-popup / inc / front Last commit date
non-sshare-styles 5 years ago class-hustle-decorator-non-sshare.php 5 years ago class-hustle-decorator-sshare.php 5 years ago class-hustle-decorator_abstract.php 5 years ago class-hustle-module-preview.php 5 years ago hustle-module-front-ajax.php 5 years ago hustle-module-front.php 5 years ago hustle-module-renderer.php 5 years ago hustle-renderer-abstract.php 5 years ago hustle-renderer-sshare.php 5 years ago
hustle-module-front.php
943 lines
1 <?php
2 class Hustle_Module_Front {
3
4 private $_modules = array();
5
6 /**
7 * Contains the queued modules types as keys, 1 as the value.
8 * Used to queue the required styles only.
9 *
10 * @since 4.0.1
11 * @var array
12 */
13 private $_module_types_to_display = array();
14 private $_non_inline_modules = array();
15 private $_inline_modules = array();
16
17 /**
18 * Array with data about the modules.
19 * This is used to conditionally add scripts.
20 *
21 * @since 4.0.4
22 * @var array
23 */
24 private $modules_data_for_scripts = array();
25
26 private static $the_content_filter_priority = 20;
27
28 const SHORTCODE = 'wd_hustle';
29
30 /**
31 * Hustle_Module_Front constructor.
32 *
33 * @since unknown
34 */
35 public function __construct() {
36
37 // Schedule email cron action.
38 add_action( 'hustle_send_email', array( 'Hustle_Mail', 'send_email' ), 10, 3 );
39 add_action( 'hustle_aweber_token_refresh', array( 'Hustle_Aweber', 'refresh_token' ) );
40
41 $is_preview = filter_input( INPUT_GET, 'hustle_preview', FILTER_VALIDATE_BOOLEAN ) && Opt_In_Utils::is_user_allowed( 'hustle_edit_module' );
42
43 // Don't render Hustle's widgets and shortcodes on preview mode.
44 if ( ! $is_preview ) {
45 $this->register_shortcodes_and_widget();
46 }
47
48 // Abort here if it's admin or widget preview. Only register the shortcodes and widget.
49 if ( is_admin() || isset( $_GET['widgetPreview'] ) ) {
50 return;
51 }
52
53 if ( ! $is_preview ) {
54 $this->prepare_for_front();
55 } else {
56 new Hustle_Module_Preview();
57 }
58 }
59
60 private function prepare_for_front() {
61 Hustle_Provider_Autoload::initiate_providers();
62 Hustle_Provider_Autoload::load_block_editor();
63
64 add_action(
65 'wp_enqueue_scripts',
66 array( $this, 'register_scripts' )
67 );
68
69 // Enqueue it in the footer to overrider all the css that comes with the popup.
70 add_action(
71 'wp_footer',
72 array( $this, 'register_styles' )
73 );
74
75 add_action(
76 'template_redirect',
77 array( $this, 'create_modules' ),
78 0
79 );
80
81 add_action(
82 'wp_footer',
83 array( $this, 'render_non_inline_modules' ),
84 -1
85 );
86
87 add_filter( 'get_the_excerpt', array( $this, 'remove_the_content_filter' ), 9 );
88 add_filter( 'wp_trim_excerpt', array( $this, 'restore_the_content_filter' ) );
89
90 add_filter(
91 'the_content',
92 array( $this, 'show_after_page_post_content' ),
93 self::$the_content_filter_priority
94 );
95
96 // NextGEN Gallery compat.
97 add_filter(
98 'run_ngg_resource_manager',
99 array( $this, 'nextgen_compat' )
100 );
101 }
102
103 /**
104 * Register shortcodes and widget.
105 *
106 * @since 4.3.1
107 *
108 * @return void
109 */
110 private function register_shortcodes_and_widget() {
111 add_action( 'widgets_init', array( $this, 'register_widget' ) );
112 add_shortcode( self::SHORTCODE, array( $this, 'shortcode' ) );
113
114 // Legacy custom content support.
115 add_shortcode(
116 'wd_hustle_cc',
117 array( $this, 'shortcode' )
118 );
119
120 // Legacy social sharing support.
121 add_shortcode(
122 'wd_hustle_ss',
123 array( $this, 'shortcode' )
124 );
125
126 // Unsubscribe shortcode.
127 add_shortcode(
128 'wd_hustle_unsubscribe',
129 array( $this, 'unsubscribe_shortcode' )
130 );
131 }
132
133 /**
134 * Don't apply the_content filter for excerpts.
135 *
136 * @param string $post_excerpt The post's excerpt.
137 */
138 public function remove_the_content_filter( $post_excerpt ) {
139 remove_filter( 'the_content', array( $this, 'show_after_page_post_content' ), self::$the_content_filter_priority );
140
141 return $post_excerpt;
142 }
143
144 public function restore_the_content_filter( $text ) {
145 add_filter( 'the_content', array( $this, 'show_after_page_post_content' ), self::$the_content_filter_priority );
146
147 return $text;
148 }
149
150 public function register_widget() {
151 register_widget( 'Hustle_Module_Widget' );
152 register_widget( 'Hustle_Module_Widget_Legacy' );
153 }
154
155 public function register_scripts() {
156
157 // There aren't any published modules. We don't need scripts.
158 if ( ! count( $this->_modules ) ) {
159 return;
160 }
161
162 $is_on_upfront_builder = class_exists( 'UpfrontThemeExporter' ) && function_exists( 'upfront_exporter_is_running' ) && upfront_exporter_is_running();
163 if ( ! $is_on_upfront_builder ) {
164 if ( is_customize_preview() || isset( $_REQUEST['fl_builder'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
165 if ( ! is_singular() ) {
166 return;
167 }
168 global $post;
169 // Check for shortcode wd_hustle_unsubscribe.
170 if ( ! preg_match( '/wd_hustle_unsubscribe/', $post->post_content ) ) {
171 return;
172 }
173 }
174 }
175
176 // Register popup requirements.
177 $url_suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? 'debug' : 'min';
178 wp_register_script(
179 'hustle_front',
180 Opt_In::$plugin_url . 'assets/js/front.' . $url_suffix . '.js',
181 array( 'jquery', 'underscore' ),
182 Opt_In::VERSION,
183 true
184 );
185
186 $modules = apply_filters( 'hustle_front_modules', $this->_modules );
187 wp_localize_script( 'hustle_front', 'Modules', $modules );
188
189 // force set archive page slug.
190 global $wp;
191 $slug = is_home() && is_front_page() ? 'hustle-front-blog-page' : sanitize_title( $wp->request );
192
193 $vars = apply_filters(
194 'hustle_front_vars',
195 array(
196 'is_admin' => is_admin(),
197 'native_share_enpoints' => Hustle_SShare_Model::get_sharing_endpoints( false ),
198 'ajaxurl' => admin_url( 'admin-ajax.php', is_ssl() ? 'https' : 'http' ),
199 'page_id' => get_queried_object_id(), // Used in many places to decide whether to show the module and cookies.
200 'page_slug' => $slug, // Used in many places to decide whether to show the module and cookies on archive pages.
201 'is_upfront' => class_exists( 'Upfront' ) && isset( $_GET['editmode'] ) && 'true' === $_GET['editmode'], // Used.
202 'script_delay' => apply_filters( 'hustle_lazy_load_script_delay', 3000 ), // to lazyload script for later on added elements
203 )
204 );
205
206 $modules_deps = $this->modules_data_for_scripts;
207
208 // Datepicker. Add translated strings only if some module has a datepicker.
209 if ( ! empty( $modules_deps['datepicker'] ) ) {
210 $vars['days_and_months'] = array(
211 'days_full' => Hustle_Time_Helper::get_week_days(),
212 'days_short' => Hustle_Time_Helper::get_week_days( 'short' ),
213 'days_min' => Hustle_Time_Helper::get_week_days( 'min' ),
214 'months_full' => Hustle_Time_Helper::get_months(),
215 'months_short' => Hustle_Time_Helper::get_months( 'short' ),
216 );
217 }
218 wp_localize_script( 'hustle_front', 'incOpt', $vars );
219
220 do_action( 'hustle_register_scripts' );
221
222 // Queue adblocker if a module requires it.
223 if ( ! empty( $modules_deps['adblocker'] ) ) {
224 wp_enqueue_script(
225 'hustle_front_ads',
226 Opt_In::$plugin_url . 'assets/js/adblock.js',
227 array(),
228 Opt_In::VERSION,
229 true
230 );
231 }
232
233 // Queue recaptchas if required. Only added if the keys are set.
234 if ( ! empty( $modules_deps['recaptcha'] ) ) {
235 $this->add_recaptcha_script( $modules_deps['recaptcha']['language'] );
236 }
237
238 // Queue Pinteres if reuqired.
239 if ( ! empty( $modules_deps['pinterest'] ) ) {
240 wp_enqueue_script(
241 'hustle_sshare_pinterest',
242 '//assets.pinterest.com/js/pinit.js',
243 array(),
244 Opt_In::VERSION,
245 true
246 );
247 }
248
249 self::add_hui_scripts();
250 wp_enqueue_script( 'hustle_front' );
251
252 Opt_In_Utils::maybe_add_scripts_for_ie();
253 }
254
255 /**
256 * Add Hustle UI scripts.
257 * Used for displaying and previewing modules.
258 *
259 * @since 4.0
260 */
261 public static function add_hui_scripts() {
262
263 wp_enqueue_script( 'jquery-ui-core' );
264 wp_enqueue_script( 'jquery-ui-datepicker' );
265
266 // Register Hustle UI functions.
267 wp_register_script(
268 'hui_scripts',
269 Opt_In::$plugin_url . 'assets/hustle-ui/js/hustle-ui.min.js',
270 array( 'jquery' ),
271 Opt_In::VERSION,
272 true
273 );
274
275 wp_enqueue_script( 'hui_scripts' );
276 }
277
278 /**
279 * Enqueue the recaptcha script if recaptcha is globally configured.
280 *
281 * @since 4.0
282 * @since 4.0.3 param $recaptcha_versions and $is_preview added
283 *
284 * @param string $language reCAPTCHA language.
285 * @param bool $is_preview if it's preview.
286 */
287 public static function add_recaptcha_script( $language = '', $is_preview = false, $is_return = false ) {
288
289 $recaptcha_settings = Hustle_Settings_Admin::get_recaptcha_settings();
290
291 if ( empty( $language ) || 'automatic' === $language ) {
292 $language = ! empty( $recaptcha_settings['language'] ) && 'automatic' !== $recaptcha_settings['language']
293 ? $recaptcha_settings['language'] : get_locale();
294 }
295 $script_url = 'https://www.google.com/recaptcha/api.js?render=explicit&hl=' . $language;
296
297 if ( ! $is_return ) {
298 wp_enqueue_script( 'recaptcha', $script_url, array(), false, true );
299
300 } elseif ( $is_preview ) {
301 return $script_url;
302 }
303 }
304
305 /**
306 * Registeres front styles and fonts
307 */
308 public function register_styles() {
309
310 // There aren't any published modules. We don't need styles.
311 if ( ! count( $this->_modules ) ) {
312 return;
313 }
314
315 $is_on_upfront_builder = class_exists( 'UpfrontThemeExporter' ) && function_exists( 'upfront_exporter_is_running' ) && upfront_exporter_is_running();
316
317 if ( ! $is_on_upfront_builder ) {
318 if ( ! $this->has_modules() || isset( $_REQUEST['fl_builder'] ) ) { // CSRF ok.
319 return;
320 }
321 }
322
323 $module_types_to_display = array_keys( $this->_module_types_to_display );
324
325 self::print_front_styles( $module_types_to_display, $this->modules_data_for_scripts );
326 self::print_front_fonts( $this->modules_data_for_scripts['fonts'] );
327 }
328
329 /**
330 * Register and enqueue the required styles according to the given module's types.
331 * The accepted module's types are:
332 * popup, slidein, embedded, social_sharing, optin, informational, floating (ssharing), inline (ssharing).
333 *
334 * @since 4.0
335 * @since 4.0.1 enequeues only the given module's types.
336 * @since 4.2.0 $dependencies param added.
337 *
338 * @param array $module_types_to_display Array with the module's type to be displayed.
339 * @param array $dependencies Array with the module's style dependencies.
340 */
341 public static function print_front_styles( $module_types_to_display = array(), $dependencies = array() ) {
342
343 if ( ! empty( $dependencies['select2'] ) ) {
344 wp_register_style(
345 'select2',
346 Opt_In::$plugin_url . 'assets/css/select2.min.css',
347 array(),
348 '4.0.6'
349 );
350 wp_enqueue_style( 'select2' );
351 }
352
353 wp_register_style(
354 'hustle_icons',
355 Opt_In::$plugin_url . 'assets/hustle-ui/css/hustle-icons.min.css',
356 array(),
357 Opt_In::VERSION
358 );
359 wp_enqueue_style( 'hustle_icons' );
360
361 wp_register_style(
362 'hustle_global',
363 Opt_In::$plugin_url . 'assets/hustle-ui/css/hustle-global.min.css',
364 array(),
365 Opt_In::VERSION
366 );
367 wp_enqueue_style( 'hustle_global' );
368
369 // Informational mode.
370 if ( ! $module_types_to_display || in_array( Hustle_Module_Model::INFORMATIONAL_MODE, $module_types_to_display, true ) ) {
371
372 wp_register_style(
373 'hustle_info',
374 Opt_In::$plugin_url . 'assets/hustle-ui/css/hustle-info.min.css',
375 array(),
376 Opt_In::VERSION
377 );
378 wp_enqueue_style( 'hustle_info' );
379 }
380
381 // Optin mode.
382 if ( ! $module_types_to_display || in_array( Hustle_Module_Model::OPTIN_MODE, $module_types_to_display, true ) ) {
383
384 wp_register_style(
385 'hustle_optin',
386 Opt_In::$plugin_url . 'assets/hustle-ui/css/hustle-optin.min.css',
387 array(),
388 Opt_In::VERSION
389 );
390 wp_enqueue_style( 'hustle_optin' );
391 }
392
393 // Popup type.
394 if ( ! $module_types_to_display || in_array( Hustle_Module_Model::POPUP_MODULE, $module_types_to_display, true ) ) {
395
396 wp_register_style(
397 'hustle_popup',
398 Opt_In::$plugin_url . 'assets/hustle-ui/css/hustle-popup.min.css',
399 array(),
400 Opt_In::VERSION
401 );
402 wp_enqueue_style( 'hustle_popup' );
403 }
404
405 // Slidein type.
406 if ( ! $module_types_to_display || in_array( Hustle_Module_Model::SLIDEIN_MODULE, $module_types_to_display, true ) ) {
407
408 wp_register_style(
409 'hustle_slidein',
410 Opt_In::$plugin_url . 'assets/hustle-ui/css/hustle-slidein.min.css',
411 array(),
412 Opt_In::VERSION
413 );
414 wp_enqueue_style( 'hustle_slidein' );
415 }
416
417 $has_social_sharing_module = in_array( Hustle_Module_Model::SOCIAL_SHARING_MODULE, $module_types_to_display, true );
418 $has_embedded_module = in_array( Hustle_Module_Model::EMBEDDED_MODULE, $module_types_to_display, true );
419
420 // Social share and Embedded both need hustle-inline CSS.
421 if ( ! $module_types_to_display || $has_social_sharing_module || $has_embedded_module ) {
422 wp_register_style(
423 'hustle_inline',
424 Opt_In::$plugin_url . 'assets/hustle-ui/css/hustle-inline.min.css',
425 array(),
426 Opt_In::VERSION
427 );
428 }
429
430 if ( ! $module_types_to_display || $has_embedded_module ) {
431 wp_enqueue_style( 'hustle_inline' );
432 }
433
434 // SSharing type.
435 if ( ! $module_types_to_display || $has_social_sharing_module ) {
436
437 wp_register_style(
438 'hustle_social',
439 Opt_In::$plugin_url . 'assets/hustle-ui/css/hustle-social.min.css',
440 array(),
441 Opt_In::VERSION
442 );
443 wp_enqueue_style( 'hustle_social' );
444
445 // Inline display.
446 if ( ! $module_types_to_display || in_array( Hustle_SShare_Model::INLINE_MODULE, $module_types_to_display, true ) ) {
447
448 wp_enqueue_style( 'hustle_inline' );
449 }
450
451 // Floating display.
452 if ( ! $module_types_to_display || in_array( Hustle_SShare_Model::FLOAT_MODULE, $module_types_to_display, true ) ) {
453
454 wp_register_style(
455 'hustle_float',
456 Opt_In::$plugin_url . 'assets/hustle-ui/css/hustle-float.min.css',
457 array(),
458 Opt_In::VERSION
459 );
460 wp_enqueue_style( 'hustle_float' );
461 }
462 }
463 }
464
465 /**
466 * Enqueues the required Google fonts to be included in front.
467 *
468 * @since unknown
469 * @return void|string
470 */
471 public static function print_front_fonts( $fonts, $is_ajax = false ) {
472 if ( empty( $fonts ) ) {
473 return;
474 }
475
476 $families_args = array();
477 foreach ( $fonts as $font_family => $variations ) {
478 $families_args[] = $font_family . ':' . implode( ',', array_unique( $variations ) );
479 }
480
481 // The final URL must have a 'family' parameter with all font families and variations
482 // formatted like ?family=Tangerine:bold,bolditalic|Inconsolata:italic|Droid+Sans .
483 $google_font_url = add_query_arg(
484 array(
485 'family' => implode( '|', $families_args ),
486 'display' => 'swap',
487 ),
488 'https://fonts.googleapis.com/css'
489 );
490
491 $id = 'hustle-fonts';
492 if ( ! $is_ajax ) {
493 wp_enqueue_style( $id, $google_font_url, array(), '1.0' );
494 } else {
495 // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet
496 return '<link rel="stylesheet" id="' . $id . '" href="' . $google_font_url . '" media="all">';
497 }
498 }
499
500 /**
501 * Enqueue modules to be displayed on Frontend.
502 */
503 public function create_modules() {
504
505 // Retrieve all active modules.
506 $modules = apply_filters( 'hustle_sort_modules', Hustle_Module_Collection::instance()->get_all( true ) );
507 $datepicker_found = false;
508 $recaptcha_found = false;
509 $select2_found = false;
510 $recaptcha_language = '';
511 $enqueue_adblock = false;
512 $pinterest_found = false;
513
514 /**
515 * Disables the load of Google fonts in frontend.
516 *
517 * @since unknown
518 *
519 * @param bool Whether Google fonts should be used.
520 */
521 $use_google_fonts = apply_filters( 'hustle_load_google_fonts', true );
522 $google_fonts = array();
523
524 foreach ( $modules as $module ) {
525
526 if ( ! $module instanceof Hustle_Model || ! $module->active ) {
527 continue;
528 }
529
530 // Check the schedule. Ssharing modules don't have schedules.
531 if ( Hustle_Module_Model::SOCIAL_SHARING_MODULE !== $module->module_type ) {
532 $settings = $module->get_settings();
533 if ( ! $settings->is_currently_scheduled() ) {
534 continue;
535 }
536 }
537
538 $is_non_inline_module = ( Hustle_Module_Model::POPUP_MODULE === $module->module_type || Hustle_Module_Model::SLIDEIN_MODULE === $module->module_type );
539
540 if ( ! $module->get_visibility()->is_allowed_to_display( $module->module_type ) ) {
541
542 // If shortcode is enabled for inline modules, don't abort.
543 // Shortcodes shouldn't follow the visibility conditions.
544 if ( ! $is_non_inline_module ) {
545 $display_options = $module->get_display()->to_array();
546 if ( '1' !== $display_options['shortcode_enabled'] ) {
547 continue;
548 }
549 } else {
550 continue;
551 }
552 }
553
554 // Setting up stuff for all modules except social sharing.
555 if ( Hustle_Module_Model::SOCIAL_SHARING_MODULE !== $module->module_type ) {
556 $module->load();
557
558 // Skip if Google fonts were deativated via hook.
559 if ( $use_google_fonts ) {
560 $google_fonts = array_merge_recursive( $google_fonts, $module->get_google_fonts() );
561 }
562
563 if ( 'optin' === $module->module_mode ) {
564
565 if ( ! $datepicker_found || empty( $recaptcha_language ) ) {
566 $form_fields = $module->get_form_fields();
567
568 // Datepicker.
569 // Check if the module has a datepicker unless we already found one in other modules.
570 // We'll localize some variables if the modules have a datepicker.
571 if ( ! $datepicker_found ) {
572 $field_types = wp_list_pluck( $form_fields, 'type', true );
573 $datepicker_found = in_array( 'datepicker', $field_types, true );
574 }
575
576 // Recaptcha.
577 // Check if the module has a recaptcha to enqueue scripts unless we already found one.
578 // We'll queue the script afterwards.
579 if ( ! empty( $form_fields['recaptcha'] ) && empty( $recaptcha_language ) ) {
580
581 $recaptcha_found = true;
582
583 $recaptcha_field = $form_fields['recaptcha'];
584 // Get only first recaptcha language. Skip if not set or it's "automatic".
585 if ( ! empty( $recaptcha_field['recaptcha_language'] ) && 'automatic' !== $recaptcha_field['recaptcha_language'] ) {
586 $recaptcha_language = $recaptcha_field['recaptcha_language'];
587 }
588 }
589 }
590
591 // Select2.
592 // We're only using select2 for Mailchimp dropdown groups.
593 if ( ! $select2_found ) {
594 $mailchimp_settings = $module->get_provider_settings( 'mailchimp' );
595 if (
596 ! empty( $mailchimp_settings ) &&
597 ! is_null( $mailchimp_settings['group'] ) &&
598 '-1' !== $mailchimp_settings['group'] &&
599 'dropdown' === $mailchimp_settings['group_type']
600 ) {
601 $select2_found = true;
602 }
603 }
604 }
605
606 // For popups and slideins.
607 if ( $is_non_inline_module ) {
608 $this->_non_inline_modules[ $module->module_id ] = $module;
609
610 if ( ! $enqueue_adblock ) {
611
612 $settings = $module->get_settings()->to_array();
613 if (
614 // If Trigger exists.
615 ! empty( $settings['triggers']['trigger'] )
616 // If trigger is adblock.
617 && 'adblock' === $settings['triggers']['trigger']
618 // If on_adblock toggle is enabled.
619 && ! empty( $settings['triggers']['on_adblock'] )
620 ) {
621 $enqueue_adblock = true;
622 }
623 }
624 } elseif ( Hustle_Module_Model::EMBEDDED_MODULE === $module->module_type ) {
625 $this->_inline_modules[ $module->module_id ] = $module;
626 }
627 } else { // Social sharing modules.
628 $ssharing_networks = $module->get_content()->get_social_icons();
629 if (
630 ! empty( $ssharing_networks )
631 && in_array( 'pinterest', array_keys( $ssharing_networks ), true )
632 && empty( $ssharing_networks['pinterest']['link'] )
633 ) {
634 $pinterest_found = true;
635 }
636 $this->_inline_modules[ $module->module_id ] = $module;
637
638 $this->_non_inline_modules[ $module->module_id ] = $module;
639 }
640
641 $this->log_module_type_to_load_styles( $module );
642
643 $this->_modules[] = $module->get_module_data_to_display();
644
645 } // End looping through the modules.
646
647 // Set flag for scripts: datepicker field.
648 if ( $datepicker_found ) {
649 $this->modules_data_for_scripts['datepicker'] = true;
650 }
651
652 // Set flag for scripts: adblocker.
653 if ( $enqueue_adblock ) {
654 $this->modules_data_for_scripts['adblocker'] = true;
655 }
656
657 // Set flag for scripts: select2.
658 if ( $select2_found ) {
659 $this->modules_data_for_scripts['select2'] = true;
660 }
661
662 // Set flag for scripts: recaptcha field.
663 if ( $recaptcha_found ) {
664 $this->modules_data_for_scripts['recaptcha'] = array( 'language' => $recaptcha_language );
665 }
666
667 if ( $pinterest_found ) {
668 $this->modules_data_for_scripts['pinterest'] = true;
669 }
670
671 $this->modules_data_for_scripts['fonts'] = $google_fonts;
672 }
673
674 /**
675 * Store the modules' types to be displayed in order to enqueue
676 * their required styles.
677 * Called within self::create_modules() method.
678 *
679 * @since 4.0.1
680 *
681 * @param Hustle_Model $module Current module to check.
682 */
683 private function log_module_type_to_load_styles( Hustle_Model $module ) {
684
685 // Keep track of the of the modules types and modes to display
686 // in order to queue the required styles only.
687 $this->_module_types_to_display[ $module->module_type ] = 1;
688
689 // Register the module mode for non SSharing modules.
690 if ( Hustle_Module_Model::SOCIAL_SHARING_MODULE !== $module->module_type ) {
691 $this->_module_types_to_display[ $module->module_mode ] = 1;
692
693 } else { // Register the module display type for SSharing modules.
694
695 // Floating display.
696 if (
697 $module->is_display_type_active( Hustle_SShare_Model::FLOAT_MOBILE ) ||
698 $module->is_display_type_active( Hustle_SShare_Model::FLOAT_DESKTOP )
699 ) {
700 $this->_module_types_to_display[ Hustle_SShare_Model::FLOAT_MODULE ] = 1;
701 }
702
703 // Inline display.
704 if (
705 $module->is_display_type_active( Hustle_SShare_Model::INLINE_MODULE ) ||
706 $module->is_display_type_active( Hustle_SShare_Model::WIDGET_MODULE ) ||
707 $module->is_display_type_active( Hustle_SShare_Model::SHORTCODE_MODULE )
708 ) {
709 $this->_module_types_to_display[ Hustle_SShare_Model::INLINE_MODULE ] = 1;
710 }
711 }
712 }
713
714 /**
715 * Check if current page has renderable opt-ins.
716 **/
717 public function has_modules() {
718 $has_modules = ! empty( $this->_non_inline_modules ) || ! empty( $this->_inline_modules );
719 return apply_filters( 'hustle_front_handler', $has_modules );
720 }
721
722 /**
723 * By-pass NextGEN Gallery resource manager
724 *
725 * @return false
726 */
727 public function nextgen_compat() {
728 return false;
729 }
730
731 public function render_non_inline_modules() {
732
733 foreach ( $this->_non_inline_modules as $module ) {
734
735 if ( Hustle_Module_Model::SOCIAL_SHARING_MODULE !== $module->module_type ) {
736 $module->display();
737
738 } elseif ( $module->is_display_type_active( Hustle_SShare_Model::FLOAT_DESKTOP ) || $module->is_display_type_active( Hustle_SShare_Model::FLOAT_MOBILE ) ) {
739 $module->display( Hustle_SShare_Model::FLOAT_MODULE );
740 }
741 }
742 }
743
744 /**
745 * Handles the data for the unsubscribe shortcode
746 *
747 * @since 3.0.5
748 * @param array $atts The values passed through the shortcode attributes
749 * @return string The content to be rendered within the shortcode.
750 */
751 public function unsubscribe_shortcode( $atts ) {
752 $messages = Hustle_Settings_Admin::get_unsubscribe_messages();
753 if ( isset( $_GET['token'] ) && isset( $_GET['email'] ) ) { // WPCS: CSRF ok.
754 $error_message = $messages['invalid_data'];
755 $sanitized_data = Opt_In_Utils::validate_and_sanitize_fields( $_GET ); // WPCS: CSRF ok.
756 $email = $sanitized_data['email'];
757 $nonce = $sanitized_data['token'];
758 // checking if email is valid
759 if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
760 return $error_message;
761 }
762 $entry = new Hustle_Entry_Model();
763 $unsubscribed = $entry->unsubscribe_email( $email, $nonce );
764 if ( $unsubscribed ) {
765 return $messages['successful_unsubscription'];
766 } else {
767 return $error_message;
768 }
769 }
770 // Show all modules' lists by default.
771 $attributes = shortcode_atts( array( 'id' => '-1' ), $atts );
772 $params = array(
773 'ajax_step' => false,
774 'shortcode_attr_id' => $attributes['id'],
775 'messages' => $messages,
776 );
777
778 $renderer = new Hustle_Layout_Helper();
779 $html = $renderer->render( 'general/unsubscribe-form', $params, true );
780 apply_filters( 'hustle_render_unsubscribe_form_html', $html, $params );
781 return $html;
782 }
783
784 /**
785 * Render the modules' wrapper to render the actual module using their shortcodes.
786 *
787 * @since the beginning of time.
788 *
789 * @param array $atts
790 * @param string $content
791 * @return string
792 */
793 public function shortcode( $atts, $content ) {
794 $atts = shortcode_atts(
795 array(
796 'id' => '',
797 'type' => 'embedded',
798 'css_class' => '',
799 ),
800 $atts,
801 self::SHORTCODE
802 );
803
804 if ( empty( $atts['id'] ) ) {
805 return '';
806 }
807
808 $type = $atts['type'];
809
810 // If shortcode type is not embed or sshare.
811 if ( 'embedded' !== $type && 'social_sharing' !== $type ) {
812 // Do not enforce embedded/social_sharing type.
813 $enforce_type = false;
814 } else {
815 // Enforce embedded/social_sharing type.
816 $enforce_type = true;
817 }
818
819 $module_id = Hustle_Model::get_module_id_by_shortcode_id( $atts['id'] );
820
821 $custom_classes = esc_attr( $atts['css_class'] );
822
823 if ( isset( $this->_inline_modules[ $module_id ] ) ) {
824 $module = $this->_inline_modules[ $module_id ];
825
826 if ( ! $module->is_display_type_active( Hustle_Module_Model::SHORTCODE_MODULE ) ) {
827 return '';
828 }
829
830 // Display the module.
831 ob_start();
832
833 $module->display( Hustle_Module_Model::SHORTCODE_MODULE, $custom_classes );
834
835 return ob_get_clean();
836 }
837
838 if ( isset( $this->_non_inline_modules[ $module_id ] ) && ! empty( $content ) ) {
839 $module = $this->_non_inline_modules[ $module_id ];
840
841 // If shortcode click trigger is disabled, print nothing.
842 $settings = $module->get_settings()->to_array();
843 if ( ! isset( $settings['triggers']['enable_on_click_shortcode'] ) || '0' === $settings['triggers']['enable_on_click_shortcode'] ) {
844 return '';
845 }
846
847 return sprintf(
848 '<a href="#" class="%s hustle_module_%s %s" data-id="%s" data-type="%s">%s</a>',
849 'hustle_module_shortcode_trigger',
850 esc_attr( $module->id ),
851 esc_attr( $custom_classes ),
852 esc_attr( $module->id ),
853 esc_attr( $type ),
854 wp_kses_post( $content )
855 );
856 }
857
858 return '';
859 }
860
861 /**
862 * Display inline modules.
863 * Embedded and Social Sharing modules only.
864 *
865 * @since the beginning of time.
866 *
867 * @param $content
868 * @return string
869 */
870 public function show_after_page_post_content( $content ) {
871
872 // Return the content immediately if there are no modules or the page doesn't have a content to embed into.
873 if ( ! count( $this->_inline_modules ) || isset( $_REQUEST['fl_builder'] ) || is_home() || is_archive() ) { // CSRF: ok.
874 return $content;
875 }
876
877 $in_the_loop = in_the_loop();
878
879 /**
880 * Filters whether to skip inline modules because we're not in da loop.
881 * This can also be used to prevent loading the inline modules conditionally.
882 *
883 * @param bool $in_the_loop Returned value from WordPress' in_the_loop() function.
884 * @since 4.2.0
885 */
886 $is_in_da_loop = apply_filters( 'hustle_inline_modules_render_in_the_loop', $in_the_loop );
887
888 // We only render the inline modules in the first call of 'the_content' filter.
889 // Prevent the modules from being printed when they shouldn't and
890 // leaving the page's main content without them.
891 if ( ! $is_in_da_loop ) {
892 return $content;
893 }
894
895 $modules = apply_filters( 'hustle_inline_modules_to_display', $this->_inline_modules );
896
897 foreach ( $modules as $module ) {
898
899 // Skip if "inline" display is disabled.
900 if ( ! $module->is_display_type_active( Hustle_Module_Model::INLINE_MODULE ) ) {
901 continue;
902 }
903
904 $custom_classes = apply_filters( 'hustle_inline_module_custom_classes', '', $module );
905
906 ob_start();
907 $module->display( Hustle_Module_Model::INLINE_MODULE, $custom_classes );
908 $module_markup = ob_get_clean();
909
910 $display = $module->get_display()->to_array();
911 $display_position = $display['inline_position'];
912
913 if ( 'both' === $display_position ) {
914 $content = $module_markup . $content . $module_markup;
915
916 } elseif ( 'above' === $display_position ) {
917 $content = $module_markup . $content;
918
919 } else { // Below.
920 $content .= $module_markup;
921
922 }
923 }
924
925 $is_render_inline_once = true;
926 /**
927 * Filters whether to render the inline modules once.
928 * By default, we only render the inline modules in the first call of 'the_content' filter.
929 * Allow rendering them in following calls of the filter if needed.
930 *
931 * @param bool $is_render_inline_once Whether to render the inline modules in several calls.
932 * @since 4.2.0
933 */
934 $is_render_inline_once = apply_filters( 'hustle_inline_modules_render_once', $is_render_inline_once );
935
936 if ( $is_render_inline_once ) {
937 remove_filter( 'the_content', array( $this, 'show_after_page_post_content' ), self::$the_content_filter_priority );
938 }
939
940 return $content;
941 }
942 }
943