Changeset 3156386
- Timestamp:
- 09/23/2024 01:47:57 PM (18 months ago)
- Location:
- boostbox
- Files:
-
- 3 added
- 20 edited
-
assets/blueprints/blueprint.json (modified) (3 diffs)
-
assets/blueprints/boostbox-blueprint-playground-demo-content.xml (added)
-
assets/screenshot-1.jpg (added)
-
assets/screenshot-2.jpg (modified) (previous)
-
assets/screenshot-3.jpg (modified) (previous)
-
assets/screenshot-4.jpg (modified) (previous)
-
assets/screenshot-5.jpg (modified) (previous)
-
assets/screenshot-6.jpg (added)
-
trunk/README.md (modified) (1 diff)
-
trunk/README.txt (modified) (4 diffs)
-
trunk/admin/boostbox-admin-settings.php (modified) (1 diff)
-
trunk/admin/class-boostbox-admin.php (modified) (2 diffs)
-
trunk/admin/css/boostbox-admin.css (modified) (3 diffs)
-
trunk/admin/css/boostbox-admin.min.css (modified) (1 diff)
-
trunk/admin/js/boostbox-admin.js (modified) (2 diffs)
-
trunk/admin/metaboxes/boostbox-display-settings.php (modified) (5 diffs)
-
trunk/admin/metaboxes/boostbox-popup-settings.php (modified) (2 diffs)
-
trunk/boostbox.php (modified) (2 diffs)
-
trunk/includes/boostbox-helper-functions.php (modified) (2 diffs)
-
trunk/includes/class-boostbox.php (modified) (1 diff)
-
trunk/public/boostbox-popups.php (modified) (1 diff)
-
trunk/public/class-boostbox-public.php (modified) (3 diffs)
-
trunk/public/js/boostbox-public.js (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
boostbox/assets/blueprints/blueprint.json
r3061236 r3156386 1 1 { 2 "landingPage": " \/wp-admin\//",2 "landingPage": "/wp-admin/post-new.php?post_type=boostbox_popups", 3 3 "preferredVersions": { 4 4 "php": "8.0", 5 "wp": "6. 3"5 "wp": "6.4.3" 6 6 }, 7 7 "phpExtensionBundles": [ … … 13 13 "username": "admin", 14 14 "password": "password" 15 },16 {17 "step": "installTheme",18 "themeZipFile": {19 "resource": "wordpress.org\/themes",20 "slug": "ollie"21 }22 15 }, 23 16 { … … 32 25 }, 33 26 { 27 "step": "installTheme", 28 "themeZipFile": { 29 "resource": "wordpress.org\/themes", 30 "slug": "olliewp" 31 } 32 }, 33 { 34 34 "step": "importFile", 35 35 "file": { -
boostbox/trunk/README.md
r3021397 r3156386 1 # BoostBox by Devio Digital1 # BoostBox Plugin for WordPress 2 2 3 3 :rocket: Increase conversion rates, customer retention and revenue. 4 4 5 Build popups for lead generation, content promotion and more usingthe core WordPress editor.5 **BoostBox** is a WordPress plugin designed to create flexible and customizable popups, modals, and content overlays within the core WordPress editor. 6 6 7 Easily style your popups, modals, and content overlays in the editor you are already used to. No more trying to learn *another popup plugin* and their unique design experience.7 Without requiring additional design interfaces or tools, **BoostBox** integrates seamlessly with the editor you're already familiar with, offering the ability to build effective and targeted popups to improve engagement, conversions, and overall website functionality. 8 8 9 With **BoostBox**, the type of popup you build is limitless. 9 No more trying to learn *another popup plugin* and their unique design experience :sunglasses: 10 10 11 * Generate email signups 12 * Giveaway free downloads 13 * Build a sales funnel 14 * Showcase featured products 15 * Promote upcoming events 16 * ... and more! 11 ## Key Features 17 12 18 ### FSE popup builder for WordPress 13 :white_check_mark: Build popups directly within the WordPress editor using blocks, columns, groups, and patterns. 14 :white_check_mark: Style and configure each popup with custom animation and targeting options. 15 :white_check_mark: Display popups to capture leads, promote content, showcase products, drive sales funnels, and more. 19 16 20 The **BoostBox** plugin was created to give website owners the ability to create popups within the WordPress core editor, and it succeeds flawlessly in this mission. 17 ### Custom Popup Types 18 With **BoostBox**, you have the flexibility to create a variety of popup types for different needs: 21 19 22 Using WordPress blocks, columns, groups and your favorite patterns, the style possibilities for the popups you build with the **BoostBox** plugin are endless. 20 :email: **Email Signups**: Capture and grow your email list with targeted popups. 21 :camera: **Product Showcases**: Highlight featured products or services to boost conversions. 22 :calendar: **Event Promotion**: Promote upcoming events or announcements with ease. 23 :money_with_wings: **Lead Generation**: Build custom forms and popups to attract leads. 24 :dart: **Custom Campaigns**: Tailor popups to your specific goals with advanced targeting. 25 26 ### Full-Site Editing (FSE) Integration 27 **BoostBox** takes full advantage of WordPress's Full-Site Editing (FSE) capabilities. By leveraging WordPress blocks and patterns, you can design popups that align with your site's theme and branding. 28 29 There's no need to use third-party popup builders — **BoostBox** integrates natively with the WordPress editor, ensuring a seamless and familiar experience. 30 31 ## Settings Overview 32 33 ### General Settings 34 - **Display Location**: Choose where your popups appear, such as center on the screen, across the entire top, or a box in the bottom right. 35 - **Max Width**: Set an optional max-width for popups to ensure they fit your design needs. 36 - **Cookie Days**: Configure the cookie expiration to control when users will see the popup again (overrides the global setting). 37 38 ### Animation Settings 39 - **Type**: Choose from several animation options (none, fade in, slide up, slide down, slide left, slide right, pop swirl and anvil). 40 - **Animation Speed**: Set the speed of the animation in milliseconds to match your design preferences. 41 42 ### Targeting Options 43 - **General**: Target popups sitewide, on home pages, search results, 404 pages and blog indexes. 44 - **Custom Post Types**: Display popups across all content for specific custom post types. 45 - **Post/Page**: Target individual posts or pages for granular control over popup placement. 46 47 ### Trigger Options 48 - **Auto Open**: Show the popup immediately on page load. 49 - **On Scroll**: Trigger the popup when the user scrolls a specific percentage down the page. 50 - **Timer**: Delay the popup for a set time after the page loads. 51 52 ### Close Button Settings 53 - **Location**: Control the placement of the close button (inside, outside, or hidden). 54 - **Color**: Customize the color of the close button to match your design. 55 56 ## Getting Started 57 58 ### Installation 59 1. Upload the **BoostBox** plugin files to the `/wp-content/plugins/boostbox/` directory, install it directly from the WordPress Plugin Repository or by searching for **BoostBox** in your WordPress dashboard. 60 2. Activate the plugin through the 'Plugins' menu in WordPress. 61 3. Navigate to `BoosBox -> Add New` to configure your first popup. -
boostbox/trunk/README.txt
r3148388 r3156386 5 5 Requires at least: 3.0.1 6 6 Tested up to: 6.6.2 7 Stable tag: 1.6.27 Stable tag: 2.0.0 8 8 License: GPLv2 or later 9 9 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 13 13 == Description == 14 14 15 **BoostBox** helps you increase conversion rates, customer retention and revenue. 16 17 Build popups for lead generation, content promotion and more using the core WordPress editor. 18 19 Easily style your popups, modals, and content overlays in the editor you are already used to. No more trying to learn *another popup plugin* and their unique design experience. 20 21 With **BoostBox**, the type of popup you build is limitless. 22 23 * Generate email signups 24 * Giveaway free downloads 25 * Build a sales funnel 15 **BoostBox** is a powerful WordPress plugin designed to increase conversion rates, customer retention, and revenue by offering flexible, customizable popups, modals, and content overlays. 16 17 With **BoostBox**, you can effortlessly build popups directly within the WordPress editor using blocks, columns, groups, and patterns—no need to learn a new interface or design tool. It's a seamless integration with the editor you're already familiar with, enabling you to create targeted popups that drive engagement and conversions. 18 19 Whether you're looking to capture leads, promote events, showcase products, or drive sales, **BoostBox** has you covered. The plugin's versatility allows you to: 20 21 * Capture email signups 26 22 * Showcase featured products 27 23 * Promote upcoming events 24 * Build custom sales funnels 25 * Launch targeted campaigns 28 26 * ... and more! 29 27 30 ### FSE popup builder 31 32 The **BoostBox** plugin was created to give website owners the ability to create popups within the core editor, and it succeeds flawlessly in this mission. 33 34 Using WordPress blocks, columns, groups and patterns, the style possibilities for the popups you build with the **BoostBox** plugin are endless. 28 ### Full-Site Editing (FSE) Integration 29 30 **BoostBox** leverages WordPress Full-Site Editing (FSE) capabilities, enabling you to design popups that perfectly match your site’s branding and layout. Say goodbye to third-party builders—**BoostBox** works natively within WordPress, making popup creation fast and intuitive. 31 32 ### Key Features 33 34 * Create popups, modals, and overlays using WordPress blocks and patterns 35 * Customize animations, display settings, and targeting options 36 * Support for custom post types and granular targeting of specific pages or posts 37 * Multiple trigger options including auto-open, scroll, and timer-based popups 38 * Full control over popup design and placement without leaving the WordPress editor 39 40 **BoostBox** is your go-to plugin for building popups that enhance engagement, increase conversions, and improve overall site functionality—all without adding complexity to your workflow. 35 41 36 42 == Installation == … … 39 45 2. Install and activate the plugin directly in your admin panel 40 46 3. Pat yourself on the back for a job well done :) 47 48 == Frequently Asked Questions == 49 50 = Can I use BoostBox without any coding knowledge? = 51 52 Yes, BoostBox is designed to work seamlessly within the WordPress editor, using the familiar block-based interface. No coding skills are needed to create beautiful, functional popups. 53 54 = What types of popups can I create with BoostBox? = 55 56 BoostBox allows you to create various types of popups including: 57 58 * Email signups 59 * Product showcases 60 * Event promotions 61 * Lead generation forms 62 * Basically, the ideas are only limited to your imagination 63 64 = How can I customize the appearance and behavior of my popups? = 65 66 BoostBox provides a wide range of customization options beyond the actual popup built in the editor, including: 67 68 * Setting max width for the popup 69 * Choosing from various animation styles (fade, slide, pop swirl, and more) 70 * Configuring popup triggers (on page load, scroll, or timer) 71 * Targeting specific pages, posts, or custom post types 72 * Customizing the look and placement of the close button 73 74 = Is BoostBox compatible with other WordPress themes and plugins? = 75 76 Yes, BoostBox is designed to be compatible with most WordPress themes and plugins. It integrates directly with the core WordPress editor, so it should work smoothly across most environments. 41 77 42 78 == Screenshots == … … 47 83 4. BoostBox popup display settings 48 84 5. BoostBox metrics displayed on the Popups screen 85 6. Another example popup using a pattern from the Powder theme 49 86 50 87 == Changelog == 88 89 = 2.0.0 = 90 * Added 2 new AJAX functions for fetching posts in `admin/class-boostbox-admin.php` 91 * Added Trigger options to display settings metabox in `admin/metaboxes/boostbox-display-settings.php` 92 * Added 4 new helper functions in `includes/boostbox-helper-functions.php` 93 * Updated the `boostbox_allowed_tags` function's svg options in `includes/boostbox-helper-functions.php` 94 * Updated JS to include new trigger options in `admin/js/boostbox-admin.js` 95 * Updated localize scripts with code for multiple popups in `public/class-boostbox-public.php` 96 * Updated CSS to include new Trigger tab in `admin/css/boostbox-admin.css` 97 * Updated `boostbox_popup_post_check` to include CPTs and general targets in `includes/boostbox-helper-functions.php` 98 * Updated impression and conversion tracking to work with multiple popups in `public/class-boostbox-public.php` 99 * Updated the public JS to include functionaliy for multiple popups in `public/js/boostbox-public.js` 100 * Updated popup metabox with checkbox option to disable popups on a page-by-page basis in `admin/metaboxes/boostbox-popup-settings.php` 101 * Updated CSS to only enqueue if popups are present on the page in `public/class-boostbox-public.php` 102 * Updated `boostbox_popup_html` to use `wp_footer` instead of `template_redirect` in `public/boostbox-popups.php` 103 * Updated admin JS to only load if you are on the edit screen in `admin/class-boostbox-admin.php` 104 * Optimized the display settings metabox tabbed content in `admin/metaboxes/boostbox-display-settings.php` 105 * General code cleanup throughout multiple files of the plugin 51 106 52 107 = 1.6.2 = -
boostbox/trunk/admin/boostbox-admin-settings.php
r3148388 r3156386 82 82 ); 83 83 84 // Field: Global popup.85 $boostbox_obj->add_field(86 'boostbox_general',87 [88 'id' => 'boostbox_global_popup',89 'type' => 'select',90 'name' => esc_attr__( 'Global popup', 'boostbox' ),91 'desc' => esc_attr__( 'Select the popup used whenever the global option is set on posts/pages', 'boostbox' ),92 'options' => $options,93 ]94 );95 84 // Field: Cookie days. 96 85 $boostbox_obj->add_field( -
boostbox/trunk/admin/class-boostbox-admin.php
r3148388 r3156386 146 146 // Check if you're on the edit screen for the "boostbox_popups" Custom Post Type 147 147 if ( is_admin() && $current_screen && ( 148 in_array( $current_screen->post_type, [ 'boostbox_popups' , 'post', 'page'] ) ||148 in_array( $current_screen->post_type, [ 'boostbox_popups' ] ) || 149 149 ( 'post' === $current_screen->base && 'post-new.php' === $current_screen->id ) 150 150 ) ) { 151 151 // General: Select2 JS. 152 152 wp_enqueue_script( $this->plugin_name . '-select2', plugin_dir_url( __FILE__ ) . 'js/select2.min.js', [ 'jquery' ], $this->version, false ); 153 // General: Admin JS. 154 wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/boostbox-admin.js', [ 'jquery', 'wp-hooks', 'wp-blocks', 'wp-color-picker', 'boostbox-select2' ], $this->version, false ); 155 wp_localize_script( $this->plugin_name, 'script_vars', [ 156 'stylesheet_url' => get_stylesheet_directory_uri(), 157 'popup_id' => json_encode( get_the_ID() ), 158 'metrics_reset_nonce' => wp_create_nonce( 'boostbox_metrics_reset_nonce' ), 159 'ajax_url' => admin_url( 'admin-ajax.php' ) 160 ] ); 153 161 } 154 // General: Admin JS.155 wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/boostbox-admin.js', [ 'jquery', 'wp-hooks', 'wp-blocks', 'wp-color-picker', 'boostbox-select2' ], $this->version, false );156 wp_localize_script( $this->plugin_name, 'script_vars', [157 'stylesheet_url' => get_stylesheet_directory_uri(),158 'popup_id' => json_encode( get_the_ID() ),159 'metrics_reset_nonce' => wp_create_nonce( 'boostbox_metrics_reset_nonce' ),160 ] );161 162 } 162 163 … … 196 197 } 197 198 add_action( 'save_post', 'save_boostbox_popups_block', 10, 2 ); 199 200 /** 201 * Fetch posts by post type 202 * 203 * @since 2.0.0 204 * @return void 205 */ 206 function fetch_posts_by_post_type() { 207 // Get the selected post types (can be multiple). 208 $post_types = isset( $_POST['post_types'] ) ? array_map( 'sanitize_text_field', (array) $_POST['post_types'] ) : []; 209 210 if ( empty( $post_types ) ) { 211 wp_send_json_error( 'No post type selected' ); 212 } 213 214 // Get posts from the selected post types. 215 $args = [ 216 'post_type' => $post_types, 217 'posts_per_page' => -1, 218 ]; 219 220 $posts = get_posts( $args ); 221 222 $output = []; 223 224 // Loop through the posts. 225 foreach ( $posts as $post ) { 226 $output[] = array( 227 'id' => $post->ID, 228 'title' => $post->post_title, 229 ); 230 } 231 232 wp_send_json_success( $output ); 233 } 234 add_action( 'wp_ajax_fetch_posts_by_post_type', 'fetch_posts_by_post_type' ); 235 add_action( 'wp_ajax_nopriv_fetch_posts_by_post_type', 'fetch_posts_by_post_type' ); 236 237 /** 238 * Fetch posts by search 239 * 240 * @since 2.0.0 241 * @return void 242 */ 243 function fetch_posts_by_search() { 244 // Check if the search term exists. 245 $search_term = isset( $_POST['search_term'] ) ? sanitize_text_field( $_POST['search_term'] ) : ''; 246 247 // If search term is empty, return no results. 248 if ( empty( $search_term ) ) { 249 wp_send_json_error( 'No search term provided.' ); 250 } 251 252 // Get all public post types (including custom post types). 253 $post_types = get_post_types( [ 'public' => true ], 'names' ); 254 255 // Fetch posts based on the search term across all post types. 256 $args = [ 257 's' => $search_term, // Search term for post title 258 'post_type' => $post_types, // Search all public post types 259 'posts_per_page' => -1, 260 'post_status' => 'publish', 261 ]; 262 263 $posts = get_posts( $args ); 264 265 $output = []; 266 267 // Loop through the posts and prepare output for Select2. 268 foreach ( $posts as $post ) { 269 $output[] = [ 270 'id' => $post->ID, 271 'text' => $post->post_title, 272 ]; 273 } 274 275 // Return the posts as a JSON response. 276 wp_send_json_success( $output ); 277 } 278 add_action( 'wp_ajax_fetch_posts_by_search', 'fetch_posts_by_search' ); 279 add_action( 'wp_ajax_nopriv_fetch_posts_by_search', 'fetch_posts_by_search' ); -
boostbox/trunk/admin/css/boostbox-admin.css
r3027699 r3156386 1146 1146 .edit-post-meta-boxes-area #boostbox_display_settings .inside #radio2:focus ~ .tabs #second-tab, 1147 1147 .edit-post-meta-boxes-area #boostbox_display_settings .inside #radio3:focus ~ .tabs #third-tab, 1148 .edit-post-meta-boxes-area #boostbox_display_settings .inside #radio4:focus ~ .tabs #fourth-tab { 1148 .edit-post-meta-boxes-area #boostbox_display_settings .inside #radio4:focus ~ .tabs #fourth-tab, 1149 .edit-post-meta-boxes-area #boostbox_display_settings .inside #radio5:focus ~ .tabs #fifth-tab { 1149 1150 } 1150 1151 … … 1181 1182 .edit-post-meta-boxes-area #boostbox_display_settings .inside #radio2:checked ~ .tabs #second-tab, 1182 1183 .edit-post-meta-boxes-area #boostbox_display_settings .inside #radio3:checked ~ .tabs #third-tab, 1183 .edit-post-meta-boxes-area #boostbox_display_settings .inside #radio4:checked ~ .tabs #fourth-tab{ 1184 .edit-post-meta-boxes-area #boostbox_display_settings .inside #radio4:checked ~ .tabs #fourth-tab, 1185 .edit-post-meta-boxes-area #boostbox_display_settings .inside #radio5:checked ~ .tabs #fifth-tab { 1184 1186 background-color: #007cba; 1185 1187 color: #fff; … … 1208 1210 .edit-post-meta-boxes-area #boostbox_display_settings .inside #radio2:checked ~ .panels #second-panel, 1209 1211 .edit-post-meta-boxes-area #boostbox_display_settings .inside #radio3:checked ~ .panels #third-panel, 1210 .edit-post-meta-boxes-area #boostbox_display_settings .inside #radio4:checked ~ .panels #fourth-panel{ 1212 .edit-post-meta-boxes-area #boostbox_display_settings .inside #radio4:checked ~ .panels #fourth-panel, 1213 .edit-post-meta-boxes-area #boostbox_display_settings .inside #radio5:checked ~ .panels #fifth-panel { 1211 1214 display: block; 1212 1215 } -
boostbox/trunk/admin/css/boostbox-admin.min.css
r3027699 r3156386 1 body.boostbox_popups_page_settings{background:#fff}body.boostbox_popups_page_analytics #wpcontent,body.boostbox_popups_page_settings #wpcontent{padding-left:0}body.boostbox_popups_page_analytics ul#adminmenu>li.current>a.current:after,body.boostbox_popups_page_settings ul#adminmenu a.wp-has-current-submenu:after{display:none}.boostbox-field .select2-container{width:100%!important}.clearfix:after,.clearfix:before{content:"";display:table}.clearfix:after{clear:both}.clearfix{zoom:1}.boostbox *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.toplevel_page_analytics #wpcontent,.toplevel_page_boostbox_settings #wpcontent{padding-left:0}.boostbox{overflow:hidden;margin:0}img.icon{width:20px;height:auto}.boostbox .panel-right .theme-image{background:#64717e;padding:2% 2% 0 2%;display:inline-block;width:100%;width:23%}.boostbox .panels{margin:0}.boostbox .panel{display:inline-block;width:100%;padding:4%;background:#fff;font-size:16px;animation:smoothFade .3s;-moz-animation:smoothFade .3s;-webkit-animation:smoothFade .3s;-o-animation:smoothFade .3s}@keyframes smoothFade{from{opacity:0}to{opacity:1}}@-moz-keyframes smoothFade{from{opacity:0}to{opacity:1}}@-webkit-keyframes smoothFade{from{opacity:0}to{opacity:1}}.boostbox .panel-left.visible{display:inline-block;animation:smoothFade .3s;-moz-animation:smoothFade .3s;-webkit-animation:smoothFade .3s;-o-animation:smoothFade .3s}.boostbox .panel-right p{font-size:16px;line-height:1.6}.boostbox .panel a{text-decoration:none}.boostbox .panel hr{height:1px;margin:2em 0;border:0;border-top:solid 2px #e6eaed}.boostbox .panel-left ol,.boostbox .panel-left ul{margin:0 0 5% 0;background:#f5f4f6;padding:5% 5% 5% 8%;list-style-type:square;font-size:19px;line-height:1.8}.boostbox .panel-left ol li,.boostbox .panel-left ul li{border-bottom:dotted 1px #ccc;margin-bottom:20px;padding-bottom:20px}.boostbox .panel-left ol li:last-child,.boostbox .panel-left ul li:last-child{border:none;margin-bottom:0;padding-bottom:0}.boostbox .panel-left .toc li ul{margin-bottom:0;padding-bottom:0;padding-top:3%}.boostbox .panel-left .toc li ul li{list-style:square}.boostbox .panel-left{display:inline-block;display:none;width:63%}.boostbox .panel-left img{max-width:100%;height:auto}.boostbox .panel-left h3{display:inline-block}.boostbox .panel-left h3,.boostbox .panel-right h3,.boostbox .panel-right p:first-child{margin-top:0}.boostbox .panel-right img{max-width:100%}.boostbox .panel-left ul.anchor-nav{padding:5%}.boostbox .anchor-nav li{list-style:none}.boostbox .back-to-top{text-transform:uppercase;font-size:11px;color:#999;position:absolute;right:0;top:8px}.boostbox .panels h3{width:100%;position:relative;padding-right:90px}.boostbox h3 .back-to-top{float:right}.boostbox .panel-right{width:32%;float:right;vertical-align:top}.boostbox .panel-aside{margin-bottom:40px;background:#f5f4f6}.boostbox .panel-aside:last-child{margin-bottom:0}.boostbox .panel-club{padding:0}.boostbox .panel-club .panel-club-inside{padding:30px 40px}.boostbox .panel-club img{padding-bottom:0;width:100%;max-width:100%;height:auto}.boostbox .panel-plugin img{padding:0}.boostbox .panel-aside .club-button{width:100%;text-align:center;line-height:46px;height:48px;margin-top:10px;font-size:15px}.boostbox .panel-aside h4{margin-top:0;font-size:1.1em;line-height:1.4}.boostbox .panel-aside ul{margin-bottom:25px}.boostbox .panel-aside li{list-style-type:square;margin-left:18px}#wpbody-content .boostbox .error,#wpbody-content .boostbox .updated{margin-top:2%}.boostbox .error+.intro-wrap,.boostbox .updated+.intro-wrap{padding-top:2%}.boostbox .intro-wrap{padding:4% 0 0 0;background:#333 url(../images/background.jpg) no-repeat bottom center;background-size:cover;background-attachment:fixed}.boostbox .intro{display:inline-block;width:100%;vertical-align:top;padding:0 50px;margin-bottom:4.5%}.boostbox .intro h3{font-size:40px;line-height:1.2;font-weight:300;margin:0;color:#fff;display:inline-block}.boostbox .devio-digital-logo{max-width:245px;float:right;margin-top:2px;transition:.3s ease;-webkit-backface-visibility:hidden;transform:translateZ(0)}@media only screen and (max-width:800px){.boostbox .devio-digital-logo{float:none;margin-bottom:6%}}.boostbox .devio-digital-logo:hover{transform:scale(1.03)}.boostbox .devio-digital-logo:active{transform:scale(1)}.boostbox .intro h4{color:#868b96;font-weight:400;font-size:18px;line-height:1.6;margin:0}.boostbox .inline-list{display:inline-block;width:100%;margin:0;background:0 0;padding:0 50px}.boostbox .inline-list li{display:inline-block;margin:0}.boostbox .inline-list li:last-child{margin-right:0;padding-right:0}.boostbox .inline-list li a{font-size:18px;text-decoration:none;padding:25px 30px;display:inline-block;color:#fff}.boostbox .inline-list li a::-moz-focus-inner,.boostbox .inline-list li a:active,.boostbox ul.inline-list a:focus{outline:0;border:0;box-shadow:none}.boostbox ul.toc{padding-left:5%}.boostbox .toc li{list-style-type:none}.boostbox .inline-list li.current a{background:#fff;outline:0;border:none;box-shadow:none;border-top-right-radius:3px;border-top-left-radius:3px;color:#76bd43}.boostbox .inline-list li a i{font-size:16px;margin-right:5px}.boostbox #changelog{display:none}.boostbox #install-video{display:none}.boostbox .arrayvideo{padding:3% 0}.boostbox #updates-panel ul{border-bottom:1px dotted #ddd;padding:1% 0 5% 3%;list-style-position:inside;background:0 0}.boostbox #updates-panel li{border-bottom:0;margin-bottom:0;padding-bottom:7px}.boostbox #updates-panel h4{font-size:1.1em;margin:.5em 0}.boostbox #themes.visible+.panel-right{display:none}.boostbox #themes.visible{width:100%}.boostbox .theme-intro{margin-bottom:4.5%;background:#f5f4f6;padding:2%}@media only screen and (max-width:800px){.boostbox .theme-intro{padding:5%;margin-bottom:5%}}.boostbox .theme-intro-left{max-width:60%;display:inline-block}@media only screen and (max-width:1110px){.boostbox .theme-intro-left{max-width:54%}}@media only screen and (max-width:800px){.boostbox .theme-intro-left,.boostbox .theme-intro-right{max-width:100%;width:100%}.boostbox .theme-intro-right{margin-bottom:5%}}.boostbox .theme-intro-left p{font-size:20px;margin-top:0;margin-bottom:0}.boostbox .theme-intro-right{float:right;margin-top:12px}@media only screen and (max-width:800px){.boostbox .theme-intro-right{margin-bottom:0}}.boostbox .theme-intro-right .button-primary{line-height:56px;height:auto;font-size:20px;padding:10px 20px}@media only screen and (max-width:800px){.boostbox .theme-intro-right .button-primary{width:100%;text-align:center}}.boostbox .array-theme{display:inline-block;width:30%;margin-right:5%;margin-bottom:3%;vertical-align:top}.boostbox .theme-list .array-theme:nth-child(3n+3){margin-right:0}@media only screen and (max-width:1100px){.boostbox .theme-list .array-theme{width:47%}.boostbox .theme-list .array-theme:nth-child(2n+2){margin-right:0}.boostbox .theme-list .array-theme:nth-child(3n+3){margin-right:5%}}@media only screen and (max-width:768px){.boostbox .theme-list .array-theme{width:100%}.boostbox .theme-list .array-theme:nth-child(2n+2){margin-right:0}.boostbox .theme-list .array-theme:nth-child(3n+3){margin-right:0}}.boostbox .array-theme .theme-image{max-height:265px;overflow:hidden;width:100%}.boostbox #themes .array-theme h3{margin-bottom:0;padding-right:0;margin-top:1em}.boostbox h4 .button{float:right;background:#5ac779;color:#fff;border-radius:3px;font-size:14px;padding:3px 6px;vertical-align:middle;margin-top:-5px!important}@media only screen and (max-width:768px){.boostbox .intro,.boostbox .panel-left,.boostbox .panel-right,.boostbox .theme-image{width:100%;float:none}.boostbox .intro{padding:0 20px;margin-top:3%;margin-bottom:8%}.boostbox .intro h2{font-size:34px}.boostbox .intro h3{margin-bottom:0}.boostbox .inline-list{margin-bottom:5%;padding:0 20px}.boostbox .inline-list li{width:100%}.boostbox .inline-list li a{width:100%;display:block}.boostbox .panel-right .theme-image{width:100%;margin-bottom:15px;padding:6% 6% 0 6%}.boostbox .enter-license .submit{width:100%}.boostbox .activate{width:100%;float:none;text-align:left;margin-bottom:20px}}.clear:after,.clear:before{content:'';display:table}.clear:after{clear:both}.boostbox .panel-plugin .panel-club-inside{padding:0}.boostbox .panel-plugin ul{margin:0}.boostbox .panel-plugin .cell{padding:30px 40px;border-bottom:solid 1px #e3e3e4;margin:0;list-style:none}.boostbox .panel-plugin .cell:last-child{border-bottom-width:2px}.quick-start ul i{color:#59bb31}.boostbox .step-complete .button-primary{pointer-events:none}.boostbox .panel-title.cell{background:#3e446d;padding:20px 40px;text-align:center}.boostbox .panel-title h3{margin:0;color:#fff;padding:0}.boostbox .panel-title h3 i{margin-right:6px}.boostbox h2{margin-top:0}.boostbox .form-table th{padding-left:0}.boostbox p.wp-caption-text{font-size:16px;margin-top:.5em;text-align:center}.boostbox div[id^=attachment]{max-width:100%!important}.theme-image{max-height:290px;overflow:hidden;border:solid 1px #ddd;border-radius:5px;display:block}.footer-wrap{margin-top:6%}@media only screen and (max-width:768px){.footer-wrap{padding:5%}}.block-footer{margin-top:5%;margin-bottom:3%}.block-footer-column{width:32.8%;display:inline-block;text-align:center;border-right:solid 3px #eceaee;padding:0 3%}@media (max-width:600px){.block-footer-column{width:100%;padding:0;border:none;margin-bottom:40px}}.block-footer-column:last-child{border-right:none}.block-footer-column i{color:#444;font-size:40px;margin-bottom:10px}.boostbox .block-footer-column h3{padding-right:0;margin-bottom:0;font-weight:700;font-size:22px}.boostbox .block-footer-column p{font-size:17px;margin-bottom:1.5em}.block-footer .button-primary{font-size:18px;border-radius:100px;padding:10px 15px;height:auto;font-size:16px}.block-footer .button-primary:active{vertical-align:initial!important;border-top-width:1px!important;color:#fff;background:#76bd43}.visit-title{text-align:center;display:inline-block;width:100%;margin:0}.footer{text-align:center;margin-top:8%}.footer-links a{margin:0 8px;position:relative}.footer a:hover{border-bottom:dotted 1px;color:#24282d}.footer-links a:after{content:"\22C5";position:absolute;right:-14px}.footer-links a:last-child:after{display:none}.block-feature-wrap{margin:0}@media (max-width:875px){.block-feature-wrap{padding-bottom:5%}}.block-feature-wrap h2{margin-bottom:0!important}.block-feature-wrap p{margin-top:1%;margin-bottom:5%}@media (max-width:875px){.block-feature-wrap p{margin-top:3%}}.block-feature-wrap i{color:#c5c0da;font-size:20px}.block-feature{background:#fff;padding:4% 3% 3% 3%;box-shadow:0 2px rgba(38,30,65,.1);border-radius:5px;width:30.6%;vertical-align:top;float:left;margin-right:4%;margin-bottom:4%;transition:.3s ease;-webkit-backface-visibility:hidden;backface-visibility:hidden}#themes .block-feature{background:0 0;padding:0;box-shadow:none;margin-bottom:2%}@media (max-width:600px){.block-feature{padding:8% 4% 3% 4%}}.block-feature:nth-child(3n+1){clear:both}@media only screen and (min-width:600px){.block-feature:nth-child(3n+3){margin-right:0}.block-feature:nth-child(3n+1):nth-last-child(-n+3),.block-feature:nth-child(3n+1):nth-last-child(-n+3)~.post{margin-bottom:0}}@media (max-width:600px){.block-feature{width:100%;margin-right:0;margin-bottom:8%}.block-feature:last-child{margin-bottom:0}}.block-feature .block-feature-icon,.block-feature .block-feature-text{display:inline-block;width:100%;vertical-align:top}.block-feature .block-feature-text{text-align:center}.block-feature .block-feature-text h3{font-weight:700;margin-bottom:15px;padding-right:0}@media (min-width:1000px){.block-feature .block-feature-text h3{font-size:22px}}.block-feature .block-feature-text p{font-size:16px}.block-feature .block-feature-icon{text-align:center;margin-bottom:6%}.block-feature .block-feature-icon img{max-height:110px;border:none}.block-split-left,.block-split-right{display:inline-block;width:49%;vertical-align:top}@media (max-width:600px){.block-split-left,.block-split-right{width:100%}}.block-split-left{padding-right:4%;padding-top:4%;padding-bottom:5%}.block-split-right{background-size:1400px;padding:0 2%;float:right}.block-theme img{border:none!important;display:block}#boostbox-panel.visible+.panel-left+.panel-left+.panel-right,#boostbox-panel.visible+.panel-left+.panel-right{display:none}#boostbox-analytics-panel,#boostbox-panel{width:100%}.gutenberg-notice{background:#f1f0ff;border-radius:5px;padding:15px 20px 20px 20px;border:solid 1px #dbd9f7;margin-bottom:5%}.panel .gutenberg-notice p{font-size:17px;color:#493c8c;line-height:1.4;display:inline}.panel .gutenberg-notice .button-primary{margin-left:15px}.panel .gutenberg-notice .button-primary:active{vertical-align:baseline;border-top-width:1px}@media (max-width:600px){.panel .gutenberg-notice p{display:block}.panel .gutenberg-notice .button-primary{margin-left:0}}.boostbox-analytics-charts,.boostbox-charts{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;flex-basis:100%;width:100%;position:relative}.viewport-main{display:flex;flex-direction:column;flex-wrap:wrap;justify-content:space-between;flex-basis:100%;margin:24px 0;box-shadow:0 0 10px 3px rgba(0,0,0,.05);border:1px solid rgba(0,0,0,.1);border-radius:3px}.viewport-main.two{flex-basis:48%}.viewport-main.three{flex-basis:31.333%}@media (max-width:768px){.viewport-main.three,.viewport-main.two{flex-basis:100%}}.viewport-top{background-color:#fff;border-radius:4px 4px 0 0;height:30px;position:relative}.viewport-top-dot{border-radius:50%;position:absolute;height:9px;width:9px;top:11px}.viewport-top-dot:first-child{background-color:#ff006d;left:10px}.viewport-top-dot:nth-child(2){background-color:#ffca50;left:26px}.viewport-top-dot:nth-child(3){background-color:#57ffd1;left:42px}.viewport-top span.title{position:absolute;line-height:30px;font-size:13px;font-weight:600;text-align:center;width:100%}.viewport-body{background:linear-gradient(180deg,#f7f7f7 0,#fff 19%,#fff);border:0;padding:15px}.section-title{flex-basis:100%}.section-title h2{margin:1em 0!important}.boostbox-field{padding:12px 0}.edit-post-meta-boxes-area #boostbox_display_settings .inside .boostbox-field.hidden{display:none}.edit-post-meta-boxes-area #boostbox_display_settings .inside .boostbox-field.active{display:block}.boostbox-field select{box-sizing:border-box;display:block;margin:0;width:100%}.edit-post-meta-boxes-area #boostbox_display_settings .inside{display:flex;flex-wrap:wrap;justify-content:space-between;flex-direction:row;padding:0;margin-top:0}.edit-post-meta-boxes-area #boostbox_display_settings .inside .boostbox-field{flex-basis:23%;display:flex;flex-wrap:wrap;flex-direction:column;box-sizing:border-box}.edit-post-meta-boxes-area #boostbox_display_settings .inside .boostbox-field p{font-weight:600}@media screen and (max-width:782px){.edit-post-meta-boxes-area #boostbox_display_settings .inside{flex-direction:column}}.edit-post-meta-boxes-area #boostbox_display_settings .inside .radio-tabs{display:flex;flex-flow:row;justify-content:space-between;width:100%;border-top:1px solid #ddd}.edit-post-meta-boxes-area #boostbox_display_settings .inside .radio-tabs .state{position:absolute;left:-10000px}.edit-post-meta-boxes-area #boostbox_display_settings .inside .tabs{display:flex;flex-flow:column;justify-content:space-around;align-self:flex-start;text-align:left;min-width:200px}@media (max-width:620px){.edit-post-meta-boxes-area #boostbox_display_settings .inside .tabs{min-width:auto}}.edit-post-meta-boxes-area #boostbox_display_settings .inside .radio-tabs .tab{flex:none;display:flex;flex-flow:column;padding:0 12px;background-color:transparent;cursor:hand;cursor:pointer}.edit-post-meta-boxes-area #boostbox_display_settings .inside .radio-tabs .tab:hover{background-color:#f0f0f0}.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio1:checked~.tabs #first-tab,.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio2:checked~.tabs #second-tab,.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio3:checked~.tabs #third-tab,.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio4:checked~.tabs #fourth-tab {background-color:#007cba;color:#fff;cursor:default}.edit-post-meta-boxes-area #boostbox_display_settings .inside .tab-label{font-size:14px;line-height:1.4rem;padding:12px;font-weight:600}.edit-post-meta-boxes-area #boostbox_display_settings .inside .radio-tabs .panels{flex:1;border-left:1px solid #ddd}.edit-post-meta-boxes-area #boostbox_display_settings .inside .radio-tabs .panel{display:none;margin:0 24px;padding:12px 0}.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio1:checked~.panels #first-panel,.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio2:checked~.panels #second-panel,.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio3:checked~.panels #third-panel,.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio4:checked~.panels #fourth-panel{display:block}.edit-post-meta-boxes-area #boostbox_display_settings .inside .left{text-align:left}#boostbox_display_settings.closed .inside{display:none}.boostbox-metrics{display:flex;flex-wrap:wrap;justify-content:space-between;flex-direction:row;padding-bottom:6px;margin-bottom:6px;border-bottom:1px solid #ddd}button#reset-metrics{margin-top:6px}1 body.boostbox_popups_page_settings{background:#fff}body.boostbox_popups_page_analytics #wpcontent,body.boostbox_popups_page_settings #wpcontent{padding-left:0}body.boostbox_popups_page_analytics ul#adminmenu>li.current>a.current:after,body.boostbox_popups_page_settings ul#adminmenu a.wp-has-current-submenu:after{display:none}.boostbox-field .select2-container{width:100%!important}.clearfix:after,.clearfix:before{content:"";display:table}.clearfix:after{clear:both}.clearfix{zoom:1}.boostbox *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.toplevel_page_analytics #wpcontent,.toplevel_page_boostbox_settings #wpcontent{padding-left:0}.boostbox{overflow:hidden;margin:0}img.icon{width:20px;height:auto}.boostbox .panel-right .theme-image{background:#64717e;padding:2% 2% 0 2%;display:inline-block;width:100%;width:23%}.boostbox .panels{margin:0}.boostbox .panel{display:inline-block;width:100%;padding:4%;background:#fff;font-size:16px;animation:smoothFade .3s;-moz-animation:smoothFade .3s;-webkit-animation:smoothFade .3s;-o-animation:smoothFade .3s}@keyframes smoothFade{from{opacity:0}to{opacity:1}}@-moz-keyframes smoothFade{from{opacity:0}to{opacity:1}}@-webkit-keyframes smoothFade{from{opacity:0}to{opacity:1}}.boostbox .panel-left.visible{display:inline-block;animation:smoothFade .3s;-moz-animation:smoothFade .3s;-webkit-animation:smoothFade .3s;-o-animation:smoothFade .3s}.boostbox .panel-right p{font-size:16px;line-height:1.6}.boostbox .panel a{text-decoration:none}.boostbox .panel hr{height:1px;margin:2em 0;border:0;border-top:solid 2px #e6eaed}.boostbox .panel-left ol,.boostbox .panel-left ul{margin:0 0 5% 0;background:#f5f4f6;padding:5% 5% 5% 8%;list-style-type:square;font-size:19px;line-height:1.8}.boostbox .panel-left ol li,.boostbox .panel-left ul li{border-bottom:dotted 1px #ccc;margin-bottom:20px;padding-bottom:20px}.boostbox .panel-left ol li:last-child,.boostbox .panel-left ul li:last-child{border:none;margin-bottom:0;padding-bottom:0}.boostbox .panel-left .toc li ul{margin-bottom:0;padding-bottom:0;padding-top:3%}.boostbox .panel-left .toc li ul li{list-style:square}.boostbox .panel-left{display:inline-block;display:none;width:63%}.boostbox .panel-left img{max-width:100%;height:auto}.boostbox .panel-left h3{display:inline-block}.boostbox .panel-left h3,.boostbox .panel-right h3,.boostbox .panel-right p:first-child{margin-top:0}.boostbox .panel-right img{max-width:100%}.boostbox .panel-left ul.anchor-nav{padding:5%}.boostbox .anchor-nav li{list-style:none}.boostbox .back-to-top{text-transform:uppercase;font-size:11px;color:#999;position:absolute;right:0;top:8px}.boostbox .panels h3{width:100%;position:relative;padding-right:90px}.boostbox h3 .back-to-top{float:right}.boostbox .panel-right{width:32%;float:right;vertical-align:top}.boostbox .panel-aside{margin-bottom:40px;background:#f5f4f6}.boostbox .panel-aside:last-child{margin-bottom:0}.boostbox .panel-club{padding:0}.boostbox .panel-club .panel-club-inside{padding:30px 40px}.boostbox .panel-club img{padding-bottom:0;width:100%;max-width:100%;height:auto}.boostbox .panel-plugin img{padding:0}.boostbox .panel-aside .club-button{width:100%;text-align:center;line-height:46px;height:48px;margin-top:10px;font-size:15px}.boostbox .panel-aside h4{margin-top:0;font-size:1.1em;line-height:1.4}.boostbox .panel-aside ul{margin-bottom:25px}.boostbox .panel-aside li{list-style-type:square;margin-left:18px}#wpbody-content .boostbox .error,#wpbody-content .boostbox .updated{margin-top:2%}.boostbox .error+.intro-wrap,.boostbox .updated+.intro-wrap{padding-top:2%}.boostbox .intro-wrap{padding:4% 0 0 0;background:#333 url(../images/background.jpg) no-repeat bottom center;background-size:cover;background-attachment:fixed}.boostbox .intro{display:inline-block;width:100%;vertical-align:top;padding:0 50px;margin-bottom:4.5%}.boostbox .intro h3{font-size:40px;line-height:1.2;font-weight:300;margin:0;color:#fff;display:inline-block}.boostbox .devio-digital-logo{max-width:245px;float:right;margin-top:2px;transition:.3s ease;-webkit-backface-visibility:hidden;transform:translateZ(0)}@media only screen and (max-width:800px){.boostbox .devio-digital-logo{float:none;margin-bottom:6%}}.boostbox .devio-digital-logo:hover{transform:scale(1.03)}.boostbox .devio-digital-logo:active{transform:scale(1)}.boostbox .intro h4{color:#868b96;font-weight:400;font-size:18px;line-height:1.6;margin:0}.boostbox .inline-list{display:inline-block;width:100%;margin:0;background:0 0;padding:0 50px}.boostbox .inline-list li{display:inline-block;margin:0}.boostbox .inline-list li:last-child{margin-right:0;padding-right:0}.boostbox .inline-list li a{font-size:18px;text-decoration:none;padding:25px 30px;display:inline-block;color:#fff}.boostbox .inline-list li a::-moz-focus-inner,.boostbox .inline-list li a:active,.boostbox ul.inline-list a:focus{outline:0;border:0;box-shadow:none}.boostbox ul.toc{padding-left:5%}.boostbox .toc li{list-style-type:none}.boostbox .inline-list li.current a{background:#fff;outline:0;border:none;box-shadow:none;border-top-right-radius:3px;border-top-left-radius:3px;color:#76bd43}.boostbox .inline-list li a i{font-size:16px;margin-right:5px}.boostbox #changelog{display:none}.boostbox #install-video{display:none}.boostbox .arrayvideo{padding:3% 0}.boostbox #updates-panel ul{border-bottom:1px dotted #ddd;padding:1% 0 5% 3%;list-style-position:inside;background:0 0}.boostbox #updates-panel li{border-bottom:0;margin-bottom:0;padding-bottom:7px}.boostbox #updates-panel h4{font-size:1.1em;margin:.5em 0}.boostbox #themes.visible+.panel-right{display:none}.boostbox #themes.visible{width:100%}.boostbox .theme-intro{margin-bottom:4.5%;background:#f5f4f6;padding:2%}@media only screen and (max-width:800px){.boostbox .theme-intro{padding:5%;margin-bottom:5%}}.boostbox .theme-intro-left{max-width:60%;display:inline-block}@media only screen and (max-width:1110px){.boostbox .theme-intro-left{max-width:54%}}@media only screen and (max-width:800px){.boostbox .theme-intro-left,.boostbox .theme-intro-right{max-width:100%;width:100%}.boostbox .theme-intro-right{margin-bottom:5%}}.boostbox .theme-intro-left p{font-size:20px;margin-top:0;margin-bottom:0}.boostbox .theme-intro-right{float:right;margin-top:12px}@media only screen and (max-width:800px){.boostbox .theme-intro-right{margin-bottom:0}}.boostbox .theme-intro-right .button-primary{line-height:56px;height:auto;font-size:20px;padding:10px 20px}@media only screen and (max-width:800px){.boostbox .theme-intro-right .button-primary{width:100%;text-align:center}}.boostbox .array-theme{display:inline-block;width:30%;margin-right:5%;margin-bottom:3%;vertical-align:top}.boostbox .theme-list .array-theme:nth-child(3n+3){margin-right:0}@media only screen and (max-width:1100px){.boostbox .theme-list .array-theme{width:47%}.boostbox .theme-list .array-theme:nth-child(2n+2){margin-right:0}.boostbox .theme-list .array-theme:nth-child(3n+3){margin-right:5%}}@media only screen and (max-width:768px){.boostbox .theme-list .array-theme{width:100%}.boostbox .theme-list .array-theme:nth-child(2n+2){margin-right:0}.boostbox .theme-list .array-theme:nth-child(3n+3){margin-right:0}}.boostbox .array-theme .theme-image{max-height:265px;overflow:hidden;width:100%}.boostbox #themes .array-theme h3{margin-bottom:0;padding-right:0;margin-top:1em}.boostbox h4 .button{float:right;background:#5ac779;color:#fff;border-radius:3px;font-size:14px;padding:3px 6px;vertical-align:middle;margin-top:-5px!important}@media only screen and (max-width:768px){.boostbox .intro,.boostbox .panel-left,.boostbox .panel-right,.boostbox .theme-image{width:100%;float:none}.boostbox .intro{padding:0 20px;margin-top:3%;margin-bottom:8%}.boostbox .intro h2{font-size:34px}.boostbox .intro h3{margin-bottom:0}.boostbox .inline-list{margin-bottom:5%;padding:0 20px}.boostbox .inline-list li{width:100%}.boostbox .inline-list li a{width:100%;display:block}.boostbox .panel-right .theme-image{width:100%;margin-bottom:15px;padding:6% 6% 0 6%}.boostbox .enter-license .submit{width:100%}.boostbox .activate{width:100%;float:none;text-align:left;margin-bottom:20px}}.clear:after,.clear:before{content:'';display:table}.clear:after{clear:both}.boostbox .panel-plugin .panel-club-inside{padding:0}.boostbox .panel-plugin ul{margin:0}.boostbox .panel-plugin .cell{padding:30px 40px;border-bottom:solid 1px #e3e3e4;margin:0;list-style:none}.boostbox .panel-plugin .cell:last-child{border-bottom-width:2px}.quick-start ul i{color:#59bb31}.boostbox .step-complete .button-primary{pointer-events:none}.boostbox .panel-title.cell{background:#3e446d;padding:20px 40px;text-align:center}.boostbox .panel-title h3{margin:0;color:#fff;padding:0}.boostbox .panel-title h3 i{margin-right:6px}.boostbox h2{margin-top:0}.boostbox .form-table th{padding-left:0}.boostbox p.wp-caption-text{font-size:16px;margin-top:.5em;text-align:center}.boostbox div[id^=attachment]{max-width:100%!important}.theme-image{max-height:290px;overflow:hidden;border:solid 1px #ddd;border-radius:5px;display:block}.footer-wrap{margin-top:6%}@media only screen and (max-width:768px){.footer-wrap{padding:5%}}.block-footer{margin-top:5%;margin-bottom:3%}.block-footer-column{width:32.8%;display:inline-block;text-align:center;border-right:solid 3px #eceaee;padding:0 3%}@media (max-width:600px){.block-footer-column{width:100%;padding:0;border:none;margin-bottom:40px}}.block-footer-column:last-child{border-right:none}.block-footer-column i{color:#444;font-size:40px;margin-bottom:10px}.boostbox .block-footer-column h3{padding-right:0;margin-bottom:0;font-weight:700;font-size:22px}.boostbox .block-footer-column p{font-size:17px;margin-bottom:1.5em}.block-footer .button-primary{font-size:18px;border-radius:100px;padding:10px 15px;height:auto;font-size:16px}.block-footer .button-primary:active{vertical-align:initial!important;border-top-width:1px!important;color:#fff;background:#76bd43}.visit-title{text-align:center;display:inline-block;width:100%;margin:0}.footer{text-align:center;margin-top:8%}.footer-links a{margin:0 8px;position:relative}.footer a:hover{border-bottom:dotted 1px;color:#24282d}.footer-links a:after{content:"\22C5";position:absolute;right:-14px}.footer-links a:last-child:after{display:none}.block-feature-wrap{margin:0}@media (max-width:875px){.block-feature-wrap{padding-bottom:5%}}.block-feature-wrap h2{margin-bottom:0!important}.block-feature-wrap p{margin-top:1%;margin-bottom:5%}@media (max-width:875px){.block-feature-wrap p{margin-top:3%}}.block-feature-wrap i{color:#c5c0da;font-size:20px}.block-feature{background:#fff;padding:4% 3% 3% 3%;box-shadow:0 2px rgba(38,30,65,.1);border-radius:5px;width:30.6%;vertical-align:top;float:left;margin-right:4%;margin-bottom:4%;transition:.3s ease;-webkit-backface-visibility:hidden;backface-visibility:hidden}#themes .block-feature{background:0 0;padding:0;box-shadow:none;margin-bottom:2%}@media (max-width:600px){.block-feature{padding:8% 4% 3% 4%}}.block-feature:nth-child(3n+1){clear:both}@media only screen and (min-width:600px){.block-feature:nth-child(3n+3){margin-right:0}.block-feature:nth-child(3n+1):nth-last-child(-n+3),.block-feature:nth-child(3n+1):nth-last-child(-n+3)~.post{margin-bottom:0}}@media (max-width:600px){.block-feature{width:100%;margin-right:0;margin-bottom:8%}.block-feature:last-child{margin-bottom:0}}.block-feature .block-feature-icon,.block-feature .block-feature-text{display:inline-block;width:100%;vertical-align:top}.block-feature .block-feature-text{text-align:center}.block-feature .block-feature-text h3{font-weight:700;margin-bottom:15px;padding-right:0}@media (min-width:1000px){.block-feature .block-feature-text h3{font-size:22px}}.block-feature .block-feature-text p{font-size:16px}.block-feature .block-feature-icon{text-align:center;margin-bottom:6%}.block-feature .block-feature-icon img{max-height:110px;border:none}.block-split-left,.block-split-right{display:inline-block;width:49%;vertical-align:top}@media (max-width:600px){.block-split-left,.block-split-right{width:100%}}.block-split-left{padding-right:4%;padding-top:4%;padding-bottom:5%}.block-split-right{background-size:1400px;padding:0 2%;float:right}.block-theme img{border:none!important;display:block}#boostbox-panel.visible+.panel-left+.panel-left+.panel-right,#boostbox-panel.visible+.panel-left+.panel-right{display:none}#boostbox-analytics-panel,#boostbox-panel{width:100%}.gutenberg-notice{background:#f1f0ff;border-radius:5px;padding:15px 20px 20px 20px;border:solid 1px #dbd9f7;margin-bottom:5%}.panel .gutenberg-notice p{font-size:17px;color:#493c8c;line-height:1.4;display:inline}.panel .gutenberg-notice .button-primary{margin-left:15px}.panel .gutenberg-notice .button-primary:active{vertical-align:baseline;border-top-width:1px}@media (max-width:600px){.panel .gutenberg-notice p{display:block}.panel .gutenberg-notice .button-primary{margin-left:0}}.boostbox-analytics-charts,.boostbox-charts{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;flex-basis:100%;width:100%;position:relative}.viewport-main{display:flex;flex-direction:column;flex-wrap:wrap;justify-content:space-between;flex-basis:100%;margin:24px 0;box-shadow:0 0 10px 3px rgba(0,0,0,.05);border:1px solid rgba(0,0,0,.1);border-radius:3px}.viewport-main.two{flex-basis:48%}.viewport-main.three{flex-basis:31.333%}@media (max-width:768px){.viewport-main.three,.viewport-main.two{flex-basis:100%}}.viewport-top{background-color:#fff;border-radius:4px 4px 0 0;height:30px;position:relative}.viewport-top-dot{border-radius:50%;position:absolute;height:9px;width:9px;top:11px}.viewport-top-dot:first-child{background-color:#ff006d;left:10px}.viewport-top-dot:nth-child(2){background-color:#ffca50;left:26px}.viewport-top-dot:nth-child(3){background-color:#57ffd1;left:42px}.viewport-top span.title{position:absolute;line-height:30px;font-size:13px;font-weight:600;text-align:center;width:100%}.viewport-body{background:linear-gradient(180deg,#f7f7f7 0,#fff 19%,#fff);border:0;padding:15px}.section-title{flex-basis:100%}.section-title h2{margin:1em 0!important}.boostbox-field{padding:12px 0}.edit-post-meta-boxes-area #boostbox_display_settings .inside .boostbox-field.hidden{display:none}.edit-post-meta-boxes-area #boostbox_display_settings .inside .boostbox-field.active{display:block}.boostbox-field select{box-sizing:border-box;display:block;margin:0;width:100%}.edit-post-meta-boxes-area #boostbox_display_settings .inside{display:flex;flex-wrap:wrap;justify-content:space-between;flex-direction:row;padding:0;margin-top:0}.edit-post-meta-boxes-area #boostbox_display_settings .inside .boostbox-field{flex-basis:23%;display:flex;flex-wrap:wrap;flex-direction:column;box-sizing:border-box}.edit-post-meta-boxes-area #boostbox_display_settings .inside .boostbox-field p{font-weight:600}@media screen and (max-width:782px){.edit-post-meta-boxes-area #boostbox_display_settings .inside{flex-direction:column}}.edit-post-meta-boxes-area #boostbox_display_settings .inside .radio-tabs{display:flex;flex-flow:row;justify-content:space-between;width:100%;border-top:1px solid #ddd}.edit-post-meta-boxes-area #boostbox_display_settings .inside .radio-tabs .state{position:absolute;left:-10000px}.edit-post-meta-boxes-area #boostbox_display_settings .inside .tabs{display:flex;flex-flow:column;justify-content:space-around;align-self:flex-start;text-align:left;min-width:200px}@media (max-width:620px){.edit-post-meta-boxes-area #boostbox_display_settings .inside .tabs{min-width:auto}}.edit-post-meta-boxes-area #boostbox_display_settings .inside .radio-tabs .tab{flex:none;display:flex;flex-flow:column;padding:0 12px;background-color:transparent;cursor:hand;cursor:pointer}.edit-post-meta-boxes-area #boostbox_display_settings .inside .radio-tabs .tab:hover{background-color:#f0f0f0}.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio1:checked~.tabs #first-tab,.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio2:checked~.tabs #second-tab,.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio3:checked~.tabs #third-tab,.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio4:checked~.tabs #fourth-tab,.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio5:checked~.tabs #fifth-tab{background-color:#007cba;color:#fff;cursor:default}.edit-post-meta-boxes-area #boostbox_display_settings .inside .tab-label{font-size:14px;line-height:1.4rem;padding:12px;font-weight:600}.edit-post-meta-boxes-area #boostbox_display_settings .inside .radio-tabs .panels{flex:1;border-left:1px solid #ddd}.edit-post-meta-boxes-area #boostbox_display_settings .inside .radio-tabs .panel{display:none;margin:0 24px;padding:12px 0}.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio1:checked~.panels #first-panel,.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio2:checked~.panels #second-panel,.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio3:checked~.panels #third-panel,.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio4:checked~.panels #fourth-panel,.edit-post-meta-boxes-area #boostbox_display_settings .inside #radio5:checked~.panels #fifth-panel{display:block}.edit-post-meta-boxes-area #boostbox_display_settings .inside .left{text-align:left}#boostbox_display_settings.closed .inside{display:none}.boostbox-metrics{display:flex;flex-wrap:wrap;justify-content:space-between;flex-direction:row;padding-bottom:6px;margin-bottom:6px;border-bottom:1px solid #ddd}button#reset-metrics{margin-top:6px} -
boostbox/trunk/admin/js/boostbox-admin.js
r3027699 r3156386 1 jQuery( document).ready(function ($) {1 jQuery(function ($) { 2 2 // Construct the path to the theme.json file. 3 3 const themeJsonPath = script_vars.stylesheet_url + '/theme.json'; … … 66 66 $( '#boostbox_close_icon_placement' ).select2(); 67 67 $( '#boostbox_popup_selected' ).select2(); 68 69 // Initialize Select2 for Custom Post Types. 70 $('#custom_post_types').select2({ 71 placeholder: "Select Post Type(s)" 72 }); 73 74 // Initialize Select2 for General Settings with multiple selection enabled 75 $('#general_field').select2({ 76 placeholder: "Select General Settings", 77 multiple: true // Explicitly enabling multiple 78 }); 79 80 // Initialize Select2 for Posts with AJAX search. 81 $('#posts').select2({ 82 placeholder: "Search and Select Post(s)", 83 ajax: { 84 url: script_vars.ajax_url, 85 method: 'POST', 86 dataType: 'json', 87 delay: 250, // Delay for better performance 88 data: function (params) { 89 return { 90 action: 'fetch_posts_by_search', // AJAX action 91 search_term: params.term // Search term entered by user 92 }; 93 }, 94 processResults: function (response) { 95 if (response.success) { 96 return { 97 results: response.data 98 }; 99 } else { 100 return { 101 results: [] 102 }; 103 } 104 }, 105 cache: true 106 }, 107 minimumInputLength: 3 // Minimum characters before search 108 }); 68 109 69 110 // Reset the metrics when button is clicked in metabox. -
boostbox/trunk/admin/metaboxes/boostbox-display-settings.php
r3148388 r3156386 56 56 wp_create_nonce( plugin_basename( __FILE__ ) ) . '" />'; 57 57 58 echo '<div class="radio-tabs"> 59 60 <input class="state" type="radio" title="' . esc_attr__( 'General', 'boostbox' ) . '" name="input-state" id="radio1" checked /> 61 <input class="state" type="radio" title="' . esc_attr__( 'Animation', 'boostbox' ) . '" name="input-state" id="radio2" /> 62 <input class="state" type="radio" title="' . esc_attr__( 'Trigger', 'boostbox' ) . '" name="input-state" id="radio3" /> 63 <input class="state" type="radio" title="' . esc_attr__( 'Close Button', 'boostbox' ) . '" name="input-state" id="radio4" /> 64 65 <div class="tabs"> 66 <label for="radio1" id="first-tab" class="tab"> 67 <div class="tab-label">' . esc_attr__( 'General', 'boostbox' ) . '</div> 68 </label> 69 <label for="radio2" id="second-tab" class="tab"> 70 <div class="tab-label">' . esc_attr__( 'Animation', 'boostbox' ) . '</div> 71 </label> 72 <label for="radio3" id="third-tab" class="tab"> 73 <div class="tab-label">' . esc_attr__( 'Trigger', 'boostbox' ) . '</div> 74 </label> 75 <label for="radio4" id="fourth-tab" class="tab"> 76 <div class="tab-label">' . esc_attr__( 'Close Button', 'boostbox' ) . '</div> 77 </label> 78 </div> 58 $tabs = [ 59 esc_attr__( 'General', 'boostbox' ), 60 esc_attr__( 'Animation', 'boostbox' ), 61 esc_attr__( 'Target', 'boostbox' ), 62 esc_attr__( 'Trigger', 'boostbox' ), 63 esc_attr__( 'Close Button', 'boostbox' ), 64 ]; 65 66 // Tab label ID names. 67 $tab_labels = ['first', 'second', 'third', 'fourth', 'fifth']; 68 69 echo '<div class="radio-tabs">'; 70 71 $i = 0; 72 73 // Loop through the tabs. 74 foreach ( $tabs as $tab ) { 75 $i++; 76 if ( $i == 1 ) { 77 $checked = 'checked'; 78 } else { 79 $checked = ''; 80 } 81 // Add the tab. 82 echo '<input class="state" type="radio" title="' . esc_html( $tab ) . '" name="input-state" id="radio' . $i . '" ' . $checked . ' />'; 83 } 84 85 echo '<div class="tabs">'; 86 87 $i = 0; 88 89 // Loop through the tabs. 90 foreach ( $tabs as $tab ) { 91 $i++; 92 // Get the current tab's label. 93 $tab_label = isset( $tab_labels[$i - 1] ) ? $tab_labels[$i - 1] : 'tab' . $i; 94 // Add the corresponding label with the dynamic ID. 95 echo '<label for="radio' . $i . '" id="' . $tab_label . '-tab" class="tab"> 96 <div class="tab-label">' . esc_html( $tab ) . '</div> 97 </label>'; 98 } 99 100 echo '</div> 79 101 80 102 <div class="panels"> … … 198 220 199 221 <div id="third-panel" class="panel animated slideInRight">', boostbox_allowed_tags() ); 222 223 echo display_custom_post_type_select(); 224 225 echo wp_kses( '</div> 226 227 <div id="fourth-panel" class="panel animated slideInRight">', boostbox_allowed_tags() ); 200 228 // Create an array of triggers. 201 229 $triggers = [ … … 254 282 echo wp_kses( '</div> 255 283 256 <div id="f ourth-panel" class="panel animated slideInRight">', boostbox_allowed_tags() );284 <div id="fifth-panel" class="panel animated slideInRight">', boostbox_allowed_tags() ); 257 285 // Create an array of placements. 258 286 $placements = [ … … 318 346 function boostbox_display_settings_metabox_save( $post_id, $post ) { 319 347 /** 320 * Verify this came from theour screen and with proper authorization,348 * Verify this came from our screen and with proper authorization, 321 349 * because save_post can be triggered at other times 322 350 */ 323 if ( ! isset( $_POST['boostbox_display_settings_meta_noncename' ] ) || ! wp_verify_nonce( $_POST['boostbox_display_settings_meta_noncename'], plugin_basename( __FILE__ )) ) {351 if ( ! isset( $_POST['boostbox_display_settings_meta_noncename'] ) || ! wp_verify_nonce( $_POST['boostbox_display_settings_meta_noncename'], 'boostbox_display_settings_meta_nonce_action' ) ) { 324 352 return $post->ID; 325 353 } 326 354 327 355 // Is the user allowed to edit the post or page? 328 if ( ! current_user_can( 'edit_post', $post ->ID) ) {356 if ( ! current_user_can( 'edit_post', $post_id ) ) { 329 357 return $post->ID; 358 } 359 360 // Don't save during autosave. 361 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { 362 return $post->ID; 363 } 364 365 // Don't save during post revision. 366 if ( 'revision' === $post->post_type ) { 367 return; 330 368 } 331 369 … … 342 380 $settings_meta['boostbox_scroll_distance'] = filter_input( INPUT_POST, 'boostbox_scroll_distance' ); 343 381 382 // Save custom post types (as an array). 383 if ( isset( $_POST['custom_post_types'] ) ) { 384 $custom_post_types = array_map( 'sanitize_text_field', (array) $_POST['custom_post_types'] ); 385 update_post_meta( $post_id, '_custom_post_types', $custom_post_types ); 386 } else { 387 delete_post_meta( $post_id, '_custom_post_types' ); 388 } 389 390 // Save selected posts (as an array). 391 if ( isset( $_POST['posts'] ) ) { 392 $selected_posts = array_map( 'sanitize_text_field', (array) $_POST['posts'] ); 393 update_post_meta( $post_id, '_selected_posts', $selected_posts ); 394 } else { 395 delete_post_meta( $post_id, '_selected_posts' ); 396 } 397 398 // Save general field (as an array). 399 if ( isset( $_POST['general_field'] ) && is_array( $_POST['general_field'] ) ) { 400 $general_field = array_map( 'sanitize_text_field', $_POST['general_field'] ); // Sanitize each value 401 update_post_meta( $post_id, '_general_field', $general_field ); 402 } else { 403 delete_post_meta( $post_id, '_general_field' ); 404 } 405 344 406 // Save $settings_meta as metadata. 345 407 foreach ( $settings_meta as $key => $value ) { 346 // Bail on post revisions. 347 if ( 'revision' === $post->post_type ) { 348 return; 408 // Check if the value is an array or a single value. 409 $value = is_array( $value ) ? $value : sanitize_text_field( $value ); 410 411 // Check for meta value and either update or add the metadata. 412 if ( get_post_meta( $post_id, $key, false ) ) { 413 update_post_meta( $post_id, $key, $value ); 414 } else { 415 add_post_meta( $post_id, $key, $value ); 349 416 } 350 $value = implode( ',', (array) $value ); 351 // Check for meta value and either update or add the metadata. 352 if ( get_post_meta( $post->ID, $key, false ) ) { 353 update_post_meta( $post->ID, $key, $value ); 354 } else { 355 add_post_meta( $post->ID, $key, $value ); 356 } 357 // Delete the metavalue if blank. 358 if ( ! $value ) { 359 delete_post_meta( $post->ID, $key ); 417 418 // Delete the meta value if blank. 419 if ( empty( $value ) ) { 420 delete_post_meta( $post_id, $key ); 360 421 } 361 422 } -
boostbox/trunk/admin/metaboxes/boostbox-popup-settings.php
r3148388 r3156386 60 60 global $post; 61 61 62 // Nonce name needed to verify where the data originated.62 // Nonce for verification. 63 63 echo '<input type="hidden" name="boostbox_popup_settings_meta_noncename" id="boostbox_popup_settings_meta_noncename" value="' . 64 64 wp_create_nonce( plugin_basename( __FILE__ ) ) . '" />'; 65 65 66 // Args for popups. 67 $args = [ 68 'hierarchical' => 1, 69 'exclude' => '', 70 'include' => '', 71 'meta_key' => '', 72 'meta_value' => '', 73 'authors' => '', 74 'child_of' => 0, 75 'parent' => -1, 76 'exclude_tree' => '', 77 'number' => '', 78 'offset' => 0, 79 'post_type' => 'boostbox_popups', 80 'post_status' => 'publish', 81 'orderby' => 'title', 82 'order' => 'ASC' 83 ]; 66 // Retrieve the current value for disabling the popup. 67 $popup_disabled = get_post_meta( $post->ID, 'boostbox_popup_disabled', true ); 84 68 85 $args = apply_filters( 'boostbox_popup_settings_args', $args ); 86 87 // Get all popups. 88 $popups = get_posts( $args ); 89 90 // Popup selected. 91 $popup_selected = get_post_meta( $post->ID, 'boostbox_popup_selected', true ); 92 93 // Select a Popup: Build the field. 94 $field = '<div class="boostbox-field">'; 95 $field .= '<p>' . esc_attr__( 'Select popup to display', 'boostbox' ) . '</p>'; 96 $field .= '<select id="boostbox_popup_selected" name="boostbox_popup_selected">'; 97 $field .= '<option value="popup_disabled">' . esc_attr__( 'Disable Popup', 'boostbox' ) . '</option>'; 98 $field .= '<option value="">' . esc_attr__( 'Global Popup', 'boostbox' ) . '</option>'; 99 // Loop through popups. 100 if ( ! empty( $popups ) ) { 101 foreach ( $popups as $popup ) { 102 $selected = ''; 103 if ( $popup->ID == $popup_selected ) { 104 $selected = 'selected="selected"'; 105 } 106 $field .= '<option value="' . esc_attr( $popup->ID ) . '" '. $selected .'>' . esc_html( $popup->post_title ) . '</option>'; 107 } 108 } 109 $field .= '</select>'; 110 $field .= '</div>'; 111 112 echo wp_kses( $field, boostbox_allowed_tags() ); 69 // Build the checkbox field. 70 echo '<div class="boostbox-field">'; 71 echo '<label for="boostbox_popup_disabled">'; 72 echo '<input type="checkbox" id="boostbox_popup_disabled" name="boostbox_popup_disabled" value="1" ' . checked( 1, $popup_disabled, false ) . '/>'; 73 echo esc_html__( 'Disable Popups', 'boostbox' ); 74 echo '</label>'; 75 echo '</div>'; 113 76 } 114 77 … … 123 86 function boostbox_popup_settings_metabox_save( $post_id, $post ) { 124 87 125 /** 126 * Verify this came from the our screen and with proper authorization, 127 * because save_post can be triggered at other times 128 */ 88 // Verify this came from our screen and with proper authorization. 129 89 if ( ! isset( $_POST['boostbox_popup_settings_meta_noncename' ] ) || ! wp_verify_nonce( $_POST['boostbox_popup_settings_meta_noncename'], plugin_basename( __FILE__ ) ) ) { 130 90 return $post->ID; 131 91 } 132 92 133 // Is the user allowed to edit the post or page?93 // Check if the user has permission to edit the post/page. 134 94 if ( ! current_user_can( 'edit_post', $post->ID ) ) { 135 95 return $post->ID; 136 96 } 137 97 138 // Popup settings.139 $ settings_meta['boostbox_popup_selected'] = filter_input( INPUT_POST, 'boostbox_popup_selected' );98 // Checkbox value for disabling the popup. 99 $popup_disabled = isset( $_POST['boostbox_popup_disabled'] ) ? 1 : 0; 140 100 141 // Save $settings_meta as metadata. 142 foreach ( $settings_meta as $key => $value ) { 143 // Bail on post revisions. 144 if ( 'revision' === $post->post_type ) { 145 return; 146 } 147 $value = implode( ',', (array) $value ); 148 // Check for meta value and either update or add the metadata. 149 if ( get_post_meta( $post->ID, $key, false ) ) { 150 update_post_meta( $post->ID, $key, $value ); 151 } else { 152 add_post_meta( $post->ID, $key, $value ); 153 } 154 // Delete the metavalue if blank. 155 if ( ! $value ) { 156 delete_post_meta( $post->ID, $key ); 157 } 101 // Update or delete the meta value based on the checkbox state. 102 if ( $popup_disabled ) { 103 update_post_meta( $post->ID, 'boostbox_popup_disabled', $popup_disabled ); 104 } else { 105 delete_post_meta( $post->ID, 'boostbox_popup_disabled' ); 158 106 } 159 107 } -
boostbox/trunk/boostbox.php
r3148388 r3156386 14 14 * Plugin URI: https://deviodigital.com/boostbox-lead-generation-plugin 15 15 * Description: Build popups for lead generation, content promotion and more using the core editor. 16 * Version: 1.6.216 * Version: 2.0.0 17 17 * Author: Devio Digital 18 18 * Author URI: https://deviodigital.com … … 29 29 30 30 // Current plugin version. 31 define( 'BOOSTBOX_VERSION', ' 1.6.2' );31 define( 'BOOSTBOX_VERSION', '2.0.0' ); 32 32 33 33 // Plugin basename. -
boostbox/trunk/includes/boostbox-helper-functions.php
r3148388 r3156386 65 65 // SVG. 66 66 $my_allowed['svg'] = [ 67 'xmlns' => [], 68 'width' => [], 69 'height' => [], 70 'viewbox' => [], 71 'class' => [], 72 'aria-hidden' => [], 73 'aria-labeledby' => [] 67 'xmlns' => [], 68 'width' => [], 69 'height' => [], 70 'viewBox' => [], 71 'stroke-width' => [], 72 'stroke' => [], 73 'fill' => [], 74 'stroke-linecap' => [], 75 'stroke-linejoin' => [], 76 'class' => [], 74 77 ]; 75 78 $my_allowed['path'] = [ 76 'd' => [], 77 'fill' => [] 78 ]; 79 'd' => [], 80 'stroke' => [], 81 'fill' => [], 82 ]; 83 $my_allowed['line'] = [ 84 'x1' => [], 85 'y1' => [], 86 'x2' => [], 87 'y2' => [], 88 'stroke' => [], 89 ]; 90 79 91 return $my_allowed; 80 92 } … … 253 265 return apply_filters( 'boostbox_settings_cookie_days', $cookie_days, $popup_id ); 254 266 } 267 268 /** 269 * Display custom post type and general fields 270 * 271 * @since 2.0.0 272 * @return void 273 */ 274 function display_custom_post_type_select() { 275 global $post; 276 277 // Add nonce field for security. 278 wp_nonce_field( 'boostbox_display_settings_meta_nonce_action', 'boostbox_display_settings_meta_noncename' ); 279 280 // Retrieve previously saved values. 281 $saved_custom_post_types = get_post_meta( $post->ID, '_custom_post_types', true ); 282 $saved_selected_posts = get_post_meta( $post->ID, '_selected_posts', true ); 283 $saved_general_field = get_post_meta( $post->ID, '_general_field', true ); // New general field value 284 285 // Ensure the retrieved values are arrays to avoid issues. 286 $saved_custom_post_types = !empty($saved_custom_post_types) ? (array) $saved_custom_post_types : []; 287 $saved_selected_posts = !empty($saved_selected_posts) ? (array) $saved_selected_posts : []; 288 289 // Get all public post types (including built-in ones). 290 $args = [ 291 'public' => true, 292 ]; 293 $custom_post_types = get_post_types( $args, 'objects' ); 294 295 // General Field (Home Page, Search Results, etc.) 296 $field = '<div class="boostbox-field">'; 297 $field .= '<p><label for="general_field">' . esc_html__( 'General Pages', 'boostbox' ) . ':</label></p>'; 298 $field .= '<select id="general_field" name="general_field[]" multiple>'; // Change to array name 'general_field[]' 299 $general_options = [ 300 'site_wide' => esc_html__( 'Sitewide', 'boostbox' ), 301 'home_page' => esc_html__( 'Home Page', 'boostbox' ), 302 'search_results' => esc_html__( 'Search Results', 'boostbox' ), 303 '404_page' => esc_html__( '404 Page', 'boostbox' ), 304 'posts_archive' => esc_html__( 'Posts Archive', 'boostbox' ), 305 ]; 306 307 // Filter the general options. 308 $general_options = apply_filters( 'boostbox_display_metabox_target_general_options', $general_options ); 309 310 // Populate the general field with the saved value. 311 foreach ( $general_options as $value => $label ) { 312 $selected = in_array( $value, (array) $saved_general_field ) ? 'selected' : ''; // Treat saved value as array 313 $field .= '<option value="' . esc_attr( $value ) . '" ' . $selected . '>' . esc_html( $label ) . '</option>'; 314 } 315 316 $field .= '</select>'; 317 $field .= '</div>'; 318 319 // Custom Post Types Field. 320 $field .= '<div class="boostbox-field">'; 321 $field .= '<p><label for="custom_post_types">' . esc_html__( 'Custom Post Type(s)', 'boostbox' ) . ':</label></p>'; 322 $field .= '<select id="custom_post_types" class="select2" name="custom_post_types[]" multiple>'; 323 $field .= '<option value="">' . esc_html__( 'Select Post Type(s)', 'boostbox' ) . '</option>'; 324 325 // Populate select field with custom post types. 326 foreach ( $custom_post_types as $post_type ) { 327 $selected = in_array( $post_type->name, $saved_custom_post_types ) ? 'selected' : ''; 328 $field .= '<option value="' . esc_attr( $post_type->name ) . '" ' . $selected . '>' . esc_html( $post_type->label ) . '</option>'; 329 } 330 331 $field .= '</select>'; 332 $field .= '</div>'; 333 334 // Posts Field (dynamically loaded via AJAX). 335 $field .= '<div class="boostbox-field">'; 336 $field .= '<p><label for="posts">' . esc_html__( 'Singular Content', 'boostbox' ) . ':</label></p>'; 337 $field .= '<select id="posts" class="select2" name="posts[]" multiple>'; 338 $field .= '<option value="">' . esc_html__( 'Search and Select Post(s)', 'boostbox' ) . '</option>'; 339 340 // Populate the select field for posts with saved values. 341 foreach ( $saved_selected_posts as $post_id ) { 342 $post_title = get_the_title( $post_id ); 343 $field .= '<option value="' . esc_attr( $post_id ) . '" selected>' . esc_html( $post_title ) . '</option>'; 344 } 345 346 $field .= '</select>'; 347 $field .= '</div>'; 348 349 // Filter the fields. 350 $field = apply_filters( 'display_custom_post_type_select_fields', $field ); 351 352 echo $field; 353 } 354 355 /** 356 * Detect the current page context for displaying the popup. 357 * 358 * @since 2.0.0 359 * @return string The detected context for the current page (e.g., 'home_page', 'search_results'). 360 */ 361 function boostbox_detect_page_context() { 362 $context = ''; 363 364 // Detect the page type using standard WordPress conditionals. 365 if ( is_front_page() ) { 366 $context = 'home_page'; 367 } elseif ( is_home() ) { 368 $context = 'posts_archive'; // Default blog post archive. 369 } elseif ( is_search() ) { 370 $context = 'search_results'; 371 } elseif ( is_404() ) { 372 $context = '404_page'; 373 } else { 374 // Get all public post types. 375 $public_post_types = get_post_types( [ 'public' => true ], 'names' ); 376 377 // Loop through each public post type and check if we are viewing a single post or archive of that type. 378 foreach ( $public_post_types as $post_type ) { 379 if ( is_singular( $post_type ) ) { 380 // Dynamically set the context for single post types. 381 $context = 'single_' . $post_type; 382 break; // Exit the loop once a matching post type is found. 383 } elseif ( is_post_type_archive( $post_type ) ) { 384 // Dynamically set the context for custom post type archives. 385 $context = 'archive_' . $post_type; 386 break; // Exit the loop once a matching archive is found. 387 } 388 } 389 } 390 391 // Allow developers to modify or add custom contexts using a filter. 392 return apply_filters( 'boostbox_detect_page_context', $context ); 393 } 394 395 /** 396 * Check if a given post ID is found in the _selected_posts metadata, 397 * matches the general options, or matches custom post types in the boostbox_popups metadata. 398 * 399 * @param int $post_id The ID of the post to check. 400 * 401 * @since 2.0.0 402 * @return array|false An array of boostbox_popups post IDs if found, false otherwise. 403 */ 404 function boostbox_popup_post_check( $post_id ) { 405 // Ensure the $post_id is an integer. 406 $post_id = (int) $post_id; 407 408 $popup_disabled = get_post_meta( $post_id, 'boostbox_popup_disabled', true ); 409 if ( $popup_disabled ) { 410 // Skip showing the popup for this post. 411 return false; 412 } 413 414 // Array to store boostbox_popups post IDs where the $post_id is found. 415 $found_in_popups = []; 416 417 // Get the current page context using the new filterable function. 418 $context = boostbox_detect_page_context(); 419 420 // Query all published posts of type 'boostbox_popups'. 421 $query = new WP_Query( [ 422 'post_type' => 'boostbox_popups', 423 'post_status' => 'publish', 424 'fields' => 'ids', // Only get post IDs to reduce query size. 425 ] ); 426 427 // Loop through the found posts. 428 if ( $query->have_posts() ) { 429 foreach ( $query->posts as $popup_post_id ) { 430 // Get the _selected_posts metadata. 431 $selected_posts = get_post_meta( $popup_post_id, '_selected_posts', true ); 432 433 // Ensure it's always an array. 434 if ( ! is_array( $selected_posts ) ) { 435 $selected_posts = ! empty( $selected_posts ) ? (array) $selected_posts : []; 436 } 437 438 // Convert all post IDs in _selected_posts to integers for reliable comparison. 439 $selected_posts = array_map( 'intval', $selected_posts ); 440 441 // Check if the provided $post_id exists in the selected posts array. 442 if ( in_array( $post_id, $selected_posts, true ) ) { 443 $found_in_popups[] = $popup_post_id; // Store the boostbox_popups post ID. 444 } 445 446 // Get the general options from the _general_field metadata. 447 $popup_general_options = get_post_meta( $popup_post_id, '_general_field', true ); 448 449 // Handle empty or false meta fields to avoid warnings. 450 if ( $popup_general_options === false ) { 451 continue; 452 } 453 454 // Check if the popup should be displayed site-wide. 455 if ( is_array( $popup_general_options ) && in_array( 'site_wide', $popup_general_options, true ) ) { 456 $found_in_popups[] = $popup_post_id; // Add if site-wide is selected. 457 continue; // No need for further checks if it's site-wide. 458 } 459 460 // Check specific page contexts. 461 if ( is_array( $popup_general_options ) && ! empty( $context ) && in_array( $context, $popup_general_options, true ) ) { 462 $found_in_popups[] = $popup_post_id; 463 } else { 464 error_log('Context mismatch: ' . $context . ' not found in ' . print_r($popup_general_options, true)); 465 } 466 467 // Check the current post type against the custom post types saved in the metadata. 468 $custom_post_types = get_post_meta( $popup_post_id, '_custom_post_types', true ); 469 470 if ( is_array( $custom_post_types ) ) { 471 $current_post_type = get_post_type(); 472 473 // Check if the current post type matches any of the saved custom post types in the metadata. 474 if ( in_array( $current_post_type, $custom_post_types, true ) ) { 475 $found_in_popups[] = $popup_post_id; // Add if the current post type matches. 476 } 477 } 478 } 479 } 480 481 // If found in any boostbox_popups posts, return the array of post IDs, otherwise return false. 482 return ! empty( $found_in_popups ) ? array_unique( $found_in_popups ) : false; 483 } 484 485 /** 486 * Build the popup HTML 487 * 488 * @param int $popup_id The ID of the popup to build. 489 * 490 * @since 2.0.0 491 * @return void 492 */ 493 function boostbox_popup_build_html( $popup_id ) { 494 global $content_width; 495 496 // Ensure the $popup_id is an integer. 497 $popup_id = (int) $popup_id; 498 499 // Set popup width from popup meta. 500 $popup_width = 'max-width: ' . get_post_meta( $popup_id, 'boostbox_display_max_width', true ); 501 if ( ! get_post_meta( $popup_id, 'boostbox_display_max_width', true ) ) { 502 $popup_width = get_cover_block_styles( $popup_id ); 503 } 504 $max_width = 'style="' . $popup_width . '"'; 505 506 // Popup position. 507 $popup_position = get_post_meta( $popup_id, 'boostbox_display_location', true ); 508 509 // Popup animation. 510 $popup_animation = get_post_meta( $popup_id, 'boostbox_animation_type', true ); 511 512 // Close icon color and placement. 513 $close_color = get_post_meta( $popup_id, 'boostbox_close_icon_color', true ) ?: '#FFFFFF'; 514 $close_placement = get_post_meta( $popup_id, 'boostbox_close_icon_placement', true ) ?: 'outside'; 515 516 // Close icon (default or custom). 517 $close_icon = apply_filters( 'boostbox_popup_close_icon', '<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-x" width="32" height="32" viewBox="0 0 24 24" stroke-width="1.5" stroke="' . $close_color . '" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" /></svg>', $close_color ); 518 519 // Popup overlay and content classes. 520 $popup_overlay_classes = apply_filters( 'boostbox_popup_overlay_classes', 'boostbox-popup-overlay' ); 521 $popup_content_classes = apply_filters( 'boostbox_popup_content_classes', 'boostbox-popup-content' ); 522 ?> 523 <!-- Popup container with unique data-popup-id --> 524 <div class="<?php esc_attr_e( $popup_overlay_classes ); ?>" role="dialog" data-popup-id="<?php echo esc_attr( $popup_id ); ?>"> 525 <div class="<?php esc_attr_e( $popup_content_classes ); ?> <?php esc_html_e( $popup_position . ' ' . $popup_animation ); ?>"<?php echo wp_kses_post( $max_width ); ?>> 526 <?php 527 // Query args for content. 528 $args = [ 529 'post_type' => 'boostbox_popups', 530 'post_status' => 'publish', 531 'p' => $popup_id, 532 'no_found_rows' => true, 533 'ignore_sticky_posts' => true 534 ]; 535 536 // Build the query. 537 $query = new WP_Query( $args ); 538 539 // Output content. 540 if ( $query->have_posts() ) { 541 while ( $query->have_posts() ) { 542 $query->the_post(); 543 the_content(); 544 } 545 wp_reset_postdata(); 546 } 547 ?> 548 <!-- Close button if not hidden --> 549 <?php if ( $close_placement !== 'hidden' ) { ?> 550 <button class="boostbox-close <?php echo ( $close_placement == 'inside' ) ? 'inside' : ''; ?>"> 551 <?php echo wp_kses( $close_icon, boostbox_allowed_tags() ); ?> 552 </button> 553 <?php } ?> 554 </div> 555 </div> 556 <?php 557 } -
boostbox/trunk/includes/class-boostbox.php
r3148388 r3156386 78 78 public function __construct() { 79 79 $this->plugin_name = 'boostbox'; 80 $this->version = ' 1.6.2';80 $this->version = '2.0.0'; 81 81 82 82 if ( defined( 'BOOSTBOX_VERSION' ) ) { -
boostbox/trunk/public/boostbox-popups.php
r3148388 r3156386 26 26 */ 27 27 function boostbox_popup_html() { 28 global $content_width; 29 // Settings. 30 $settings = get_option( 'boostbox_general' ); 31 // Get the popup ID. 32 $popup_id = get_post_meta( get_the_ID(), 'boostbox_popup_selected', true ); 33 // Check for global popup. 34 if ( '' == $popup_id && '' !== $settings ) { 35 $popup_id = $settings['boostbox_global_popup']; 28 // Check popups for post ID's. 29 $popup_check = boostbox_popup_post_check( get_the_ID() ); 30 31 // Loop through popup checks. 32 foreach ( $popup_check as $popup_id ) { 33 echo boostbox_popup_build_html( $popup_id ); 36 34 } 37 // Bail early?38 if ( ! $popup_id || 'popup_disabled' == $popup_id ) { return; }39 40 // Set popup width from popup meta.41 $popup_width = 'max-width: ' . get_post_meta( $popup_id, 'boostbox_display_max_width', true );42 // Set width based on the first block, or defaults as a fallback.43 if ( ! get_post_meta( $popup_id, 'boostbox_display_max_width', true ) ) {44 $popup_width = get_cover_block_styles( $popup_id );45 }46 // Get the popup max width (if any).47 $max_width = 'style="' . $popup_width . '"';48 // Popup position.49 $popup_position = get_post_meta( $popup_id, 'boostbox_display_location', true );50 // Popup animation.51 $popup_animation = get_post_meta( $popup_id, 'boostbox_animation_type', true );52 // Close icon color.53 $close_color = get_post_meta( $popup_id, 'boostbox_close_icon_color', true );54 if ( ! $close_color ) {55 $close_color = '#FFFFFF';56 }57 // Close icon placement.58 $close_placement = get_post_meta( $popup_id, 'boostbox_close_icon_placement', true );59 if ( ! $close_placement ) {60 $close_placement = 'outside';61 }62 // @TODO set custom icon options in the settings for users to choose from.63 $close_icon = apply_filters( 'boostbox_popup_close_icon', '<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-x" width="32" height="32" viewBox="0 0 24 24" stroke-width="1.5" stroke="' . $close_color . '" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" /></svg>', $close_color );64 // Popup overlay classes.65 $popup_overlay_classes = apply_filters( 'boostbox_popup_overlay_classes', 'boostbox-popup-overlay' );66 // Popup content classes.67 $popup_content_classes = apply_filters( 'boostbox_popup_content_classes', 'boostbox-popup-content' );68 ?>69 <!--Creates the popup body-->70 <div class="<?php esc_attr_e( $popup_overlay_classes ); ?>" role="dialog">71 <!--Creates the popup content-->72 <div class="<?php esc_attr_e( $popup_content_classes ); ?> <?php esc_html_e( $popup_position . ' ' . $popup_animation ); ?>"<?php echo wp_kses_post( $max_width ); ?>>73 <?php74 // Query args.75 $args = [76 'post_type' => 'boostbox_popups',77 'post_status' => 'publish',78 'p' => $popup_id,79 'no_found_rows' => true,80 'ignore_sticky_posts' => true81 ];82 83 // Filter the args.84 $args = apply_filters( 'boostbox_popup_html_wp_query_args', $args );85 86 // Build the query.87 $query = new WP_Query( $args );88 89 // Check if there are any posts.90 if ( $query->have_posts() ) {91 // Loop through the posts.92 while ( $query->have_posts() ) {93 $query->the_post();94 the_content();95 }96 // Restore original post data.97 wp_reset_postdata();98 }99 ?>100 <!--popup's close button-->101 <?php if ( $close_placement !== 'hidden' ) { ?>102 <button class="boostbox-close <?php if ( $close_placement == 'inside' ) { esc_html_e( 'inside' ); } ?>"><?php print_r( $close_icon ); ?></button>103 <?php } ?>104 </div>105 </div>106 <?php107 35 } 108 add_action( ' template_redirect', 'boostbox_popup_html' );36 add_action( 'wp_footer', 'boostbox_popup_html' ); -
boostbox/trunk/public/class-boostbox-public.php
r3148388 r3156386 73 73 */ 74 74 public function enqueue_styles() { 75 // Publc CSS. 76 wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/boostbox-public.min.css', [], $this->version, 'all' ); 75 // Check popups for post ID's. 76 $popup_check = boostbox_popup_post_check( get_the_ID() ); 77 // Ensure that there are popups to process. 78 if ( $popup_check && is_array( $popup_check ) ) { 79 // Publc CSS. 80 wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/boostbox-public.min.css', [], $this->version, 'all' ); 81 } 77 82 } 78 83 … … 84 89 */ 85 90 public function enqueue_scripts() { 86 // Popup ID. 87 $popup_id = get_post_meta( get_the_ID(), 'boostbox_popup_selected', true ); 88 // Milliseconds. 89 $milliseconds = get_post_meta( $popup_id, 'boostbox_display_speed', true ); 90 if ( ! $milliseconds ) { 91 $milliseconds = 0; 91 // Check popups for post ID's. 92 $popup_check = boostbox_popup_post_check( get_the_ID() ); 93 94 // Initialize an array to hold all popup data. 95 $all_popups_data = []; 96 97 // Ensure that there are popups to process. 98 if ( $popup_check && is_array( $popup_check ) ) { 99 // Loop through popup checks. 100 foreach ( $popup_check as $popup_id ) { 101 // Milliseconds. 102 $milliseconds = get_post_meta( $popup_id, 'boostbox_display_speed', true ); 103 if ( ! $milliseconds ) { 104 $milliseconds = 0; 105 } 106 107 // Scroll distance. 108 $scroll_distance = '32px'; 109 if ( get_post_meta( $popup_id, 'boostbox_scroll_distance', true ) ) { 110 $scroll_distance = get_post_meta( $popup_id, 'boostbox_scroll_distance', true ); 111 } 112 113 // Create localized script args for this popup. 114 $popup_data = [ 115 'popup_id' => $popup_id, 116 'milliseconds' => $milliseconds, 117 'cookie_days' => boostbox_settings_cookie_days( $popup_id ), 118 'scroll_distance' => $scroll_distance, 119 'trigger' => get_post_meta( $popup_id, 'boostbox_trigger_type', true ), 120 'close_icon_placement' => get_post_meta( $popup_id, 'boostbox_close_icon_placement', true ), 121 'disable_analytics' => boostbox_settings_disable_analytics() 122 ]; 123 124 // Add the popup data to the array. 125 $all_popups_data[] = $popup_data; 126 } 127 128 // Enqueue the script files. 129 wp_enqueue_script( $this->plugin_name . '-js-cookie', plugin_dir_url( __FILE__ ) . 'js/js.cookie.min.js', [ 'jquery' ], $this->version, false ); 130 wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/boostbox-public.js', [ 'jquery' ], $this->version, false ); 131 132 // Localize the script with all popups' data, AJAX URL, and nonce. 133 wp_localize_script( $this->plugin_name, 'boostbox_settings', [ 134 'ajax_url' => admin_url( 'admin-ajax.php' ), // Localize ajax_url only once 135 'nonce' => wp_create_nonce( 'boostbox_nonce' ), // Localize nonce only once 136 'popups' => $all_popups_data // Add all popups to the popups array 137 ]); 92 138 } 93 // Scroll distance. 94 $scroll_distance = '32px'; 95 if ( get_post_meta( $popup_id, 'boostbox_scroll_distance', true ) ) { 96 $scroll_distance = get_post_meta( $popup_id, 'boostbox_scroll_distance', true ); 97 } 98 // Create localize script args. 99 $localize_args = [ 100 'popup_id' => $popup_id, 101 'milliseconds' => $milliseconds, 102 'cookie_days' => boostbox_settings_cookie_days( $popup_id ), 103 'scroll_distance' => $scroll_distance, 104 'trigger' => get_post_meta( $popup_id, 'boostbox_trigger_type', true ), 105 'close_icon_placement' => get_post_meta( $popup_id, 'boostbox_close_icon_placement', true ), 106 'ajax_url' => admin_url( 'admin-ajax.php' ), 107 'nonce' => wp_create_nonce( 'boostbox_nonce' ), 108 'disable_analytics' => boostbox_settings_disable_analytics() 109 ]; 110 // Filter the args. 111 $localize_args = apply_filters( 'boostbox_localize_scripts_args', $localize_args ); 112 // Public JS. 113 wp_enqueue_script( $this->plugin_name . '-js-cookie', plugin_dir_url( __FILE__ ) . 'js/js.cookie.min.js', [ 'jquery' ], $this->version, false ); 114 wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/boostbox-public.js', [ 'jquery' ], $this->version, false ); 115 wp_localize_script( $this->plugin_name, 'boostbox_settings', $localize_args ); 116 } 117 139 } 140 118 141 } 119 142 … … 127 150 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : ''; 128 151 if ( ! wp_verify_nonce( $nonce, 'boostbox_nonce' ) ) { 129 wp_die( 'Invalid nonce' ); 152 wp_send_json_error('Invalid nonce'); 153 wp_die(); 130 154 } 131 155 132 156 // Get the popup ID from the AJAX request. 133 157 $popup_id = isset( $_POST['popup_id'] ) ? intval( $_POST['popup_id'] ) : 0; 158 if ( $popup_id === 0 ) { 159 wp_send_json_error('Invalid popup ID'); 160 wp_die(); 161 } 134 162 135 163 // Increment view count meta field. 136 164 $current_count = get_post_meta( $popup_id, 'boostbox_popup_impressions', true ); 137 $new_count = (int)$current_count + 1; 138 update_post_meta( $popup_id, 'boostbox_popup_impressions', $new_count ); 139 165 if ( $current_count === '' ) { 166 $current_count = 0; 167 } 168 169 $new_count = (int) $current_count + 1; 170 $updated = update_post_meta( $popup_id, 'boostbox_popup_impressions', $new_count ); 171 172 if ( $updated === false ) { 173 wp_send_json_error('Failed to update post meta'); 174 wp_die(); 175 } 176 177 wp_send_json_success(array('popup_id' => $popup_id, 'new_count' => $new_count)); 140 178 wp_die(); 141 179 } -
boostbox/trunk/public/js/boostbox-public.js
r3035929 r3156386 1 1 jQuery(document).ready(function ($) { 2 // Popup ID. 3 var popupID = boostbox_settings.popup_id; 4 // Trigger type. 5 var triggerType = boostbox_settings.trigger; 6 // Milliseconds. 7 var milliseconds = boostbox_settings.milliseconds; 8 // Disable analytics? 9 var disableAnalytics = boostbox_settings.disable_analytics; 10 // Window inner height. 11 var innerHeight = window.innerHeight; 12 // Check to see if the cookie exists already. 13 var cookieCheck = Cookies.get( 'boostbox_popup_' + popupID + '' ); 2 if (typeof boostbox_settings !== 'undefined' && Array.isArray(boostbox_settings.popups)) { 3 // Loop through each popup's settings. 4 boostbox_settings.popups.forEach(function (popup) { 5 var popupID = popup.popup_id; 14 6 15 // If there's a cookie saved, bail early. 16 if ( cookieCheck != null ) { return; } 7 // Check for existing cookies to see if popup should be skipped. 8 var cookieCheck = Cookies.get('boostbox_popup_' + popupID); 9 if (cookieCheck != null) { 10 console.log('Popup', popupID, 'skipped due to cookie'); 11 return; 12 } 17 13 18 // Trigger - auto open. 19 if ( triggerType === "auto-open" ) { 20 if (!Cookies.get( 'boostbox_popup_' + popupID + '' )) { 14 // Trigger handling (auto-open, on-scroll, time). 15 handlePopupTrigger(popup); 16 17 // Close behavior handling (inside/outside/hide). 18 setupCloseBehavior(popupID, popup.close_icon_placement, popup.cookie_days); 19 20 // Track conversion when any button/link within the popup is clicked. 21 $(".boostbox-popup-overlay[data-popup-id='" + popupID + "']").on("click", ":button:not('.boostbox-close'), button:not('.boostbox-close'), a, input[type='submit'], [role='button']", function () { 22 trackConversion(popupID); 23 }); 24 }); 25 } 26 27 // Function to handle popup triggers. 28 function handlePopupTrigger(popup) { 29 var popupID = popup.popup_id; 30 var triggerType = popup.trigger; 31 var popupClosed = false; 32 33 let popupViewCountIncremented = false; 34 35 if (triggerType === "auto-open" && !Cookies.get('boostbox_popup_' + popupID)) { 36 window.setTimeout(function () { 37 $(".boostbox-popup-overlay[data-popup-id='" + popupID + "']").addClass('active'); 38 incrementPopupViewCount(popupID); 39 }, 0); 40 } 41 42 // Trigger - time. 43 if ( triggerType === "time" && !Cookies.get( 'boostbox_popup_' + popupID + '' )) { 21 44 // Add class after X seconds. 22 45 window.setTimeout(function(){ 23 46 $(".boostbox-popup-overlay").addClass('active'); 24 47 incrementPopupViewCount(); 25 }, 0);48 }, popup.milliseconds); 26 49 } 27 }28 50 29 // Trigger - time. 30 if ( triggerType === "time" ) { 31 if (!Cookies.get( 'boostbox_popup_' + popupID + '' )) { 32 // Add class after X seconds. 33 window.setTimeout(function(){ 34 $(".boostbox-popup-overlay").addClass('active'); 35 incrementPopupViewCount(); 36 }, milliseconds); 37 } 38 } 51 // Trigger - on scroll. 52 if (triggerType === "on-scroll" && !Cookies.get('boostbox_popup_' + popupID)) { 53 // Add class after scrolling X pixels. 54 $(window).scroll(function () { 55 if (!popupClosed && !popupViewCountIncremented) { 56 if (!popupClosed) { 57 var triggerValue = popup.scroll_distance; // Use the popup's specific scroll distance 58 var scrolledY = $(window).scrollTop(); 39 59 40 // Variable to track if the popup is closed41 var popupClosed = false;42 // Set a flag to track whether incrementPopupViewCount has been executed43 let popupViewCountIncremented = false;60 if (!triggerValue) { 61 console.error('Popup scroll_distance is not defined for popup ' + popupID); 62 return; 63 } 44 64 45 // Trigger - on scroll. 46 if (triggerType === "on-scroll" && !Cookies.get('boostbox_popup_' + popupID)) { 47 // Add class after scrolling X pixels. 48 $(window).scroll(function () { 49 if (!popupClosed && !popupViewCountIncremented) { 50 if (!popupClosed) { 51 var triggerValue = boostbox_settings.scroll_distance; 52 var scrolledY = $(window).scrollTop(); 65 var isPercentage = triggerValue.includes('%'); 66 var windowY = isPercentage ? percentageToPixels(triggerValue, innerHeight) : parseInt(triggerValue, 10); 53 67 54 var isPercentage = triggerValue.includes('%'); 55 var windowY = isPercentage ? percentageToPixels(triggerValue, innerHeight) : parseInt(triggerValue, 10); 68 if (scrolledY > windowY) { 69 $(".boostbox-popup-overlay").addClass('active'); 70 incrementPopupViewCount(popupID); 71 popupViewCountIncremented = true; // Set the flag to true. 72 } 73 } 56 74 57 if (scrolledY > windowY) {58 $(".boostbox-popup-overlay").addClass('active');59 incrementPopupViewCount();60 popupViewCountIncremented = true; // Set the flag to true.75 // Function to convert percentage to pixels 76 function percentageToPixels(percentage, containerHeight) { 77 var percent = parseInt(percentage, 10); 78 return (percent / 100) * containerHeight; 61 79 } 62 }63 64 // Function to convert percentage to pixels65 function percentageToPixels(percentage, containerHeight) {66 var percent = parseInt(percentage, 10);67 return (percent / 100) * containerHeight;68 }69 }70 });71 }72 73 // Set the click class used to close the popup.74 if (boostbox_settings.close_icon_placement == 'hidden') {75 var closeClickClass = '.boostbox-popup-overlay';76 } else {77 var closeClickClass = '.boostbox-close';78 }79 80 // Close popup when 'close' button is clicked.81 $(closeClickClass).on("click", function (event) {82 if (boostbox_settings.close_icon_placement == 'hidden') {83 // Check if the clicked element is not within the .boostbox-popup-content class84 if (!$(event.target).closest('.boostbox-popup-content').length) {85 $(".boostbox-popup-overlay").removeClass("active");86 popupClosed = true; // Set the variable to true when the popup is closed.87 var expirationDate = new Date();88 var expirationMilliseconds = expirationDate.getTime() + (boostbox_settings.cookie_days * 24 * 60 * 60 * 1000);89 expirationDate.setTime(expirationMilliseconds);90 Cookies.set('boostbox_popup_' + popupID, 'hidden', { expires: expirationDate });91 }92 } else {93 // Check if the clicked element is .boostbox-close94 $(".boostbox-popup-overlay").removeClass("active");95 popupClosed = true; // Set the variable to true when the popup is closed96 var expirationDate = new Date();97 var expirationMilliseconds = expirationDate.getTime() + (boostbox_settings.cookie_days * 24 * 60 * 60 * 1000);98 expirationDate.setTime(expirationMilliseconds);99 Cookies.set('boostbox_popup_' + popupID, 'hidden', { expires: expirationDate });100 }101 });102 103 // Track conversion when any button/link within the popup is clicked.104 // @TODO figure ways to make the tracking dynamic between buttons, links, form submissions, etc.105 $(".boostbox-popup-overlay").on("click", ":button:not('.boostbox-close'), button:not('.boostbox-close'), a, input[type='submit'], [role='button']", function () {106 trackConversion();107 });108 109 // Get percentage of number.110 function percentage(percent, total) {111 return ((percent/ 100) * total)112 }113 114 // Increment popup view count.115 function incrementPopupViewCount() {116 // Only do this if analytics is not disabled.117 if (!disableAnalytics) {118 // AJAX request to increment view count.119 $.ajax({120 url: boostbox_settings.ajax_url,121 type: 'POST',122 data: {123 action: 'increment_popup_view_count',124 popup_id: popupID,125 nonce: boostbox_settings.nonce,126 },127 success: function (response) {128 // Turned off console log message (for now) @TODO - set up a "debug" option that turns this back on.129 //console.log('[SUCCESS] Impression tracking complete!');130 //console.log(response);131 },132 error: function (error) {133 // Turned off console log message (for now) @TODO - set up a "debug" option that turns this back on.134 //console.log('[ERROR] Impression tracking failed!');135 //console.log(error);136 80 } 137 81 }); … … 139 83 } 140 84 141 // Increment popup conversion count. 142 function trackConversion() { 143 // Only do this if analytics is not disabled. 144 if (!disableAnalytics) { 145 // AJAX request to track conversion. 146 $.ajax({ 147 url: boostbox_settings.ajax_url, 148 type: 'POST', 149 data: { 150 action: 'track_popup_conversion', 151 popup_id: popupID, 152 nonce: boostbox_settings.nonce, 153 }, 154 success: function (response) { 155 // Turned off console log message (for now) @TODO - set up a "debug" option that turns this back on. 156 //console.log('[SUCCESS] Conversion tracking complete!'); 157 //console.log(response); 158 }, 159 error: function (error) { 160 // Turned off console log message (for now) @TODO - set up a "debug" option that turns this back on. 161 //console.log('[ERROR] Conversion tracking failed!'); 162 //console.log(error); 85 // Function to set up the close behavior. 86 function setupCloseBehavior(popupID, closeIconPlacement, cookieDays) { 87 if (closeIconPlacement === 'hidden') { 88 $(document).on("click", ".boostbox-popup-overlay[data-popup-id='" + popupID + "']", function (event) { 89 if ($(event.target).hasClass('boostbox-popup-overlay')) { 90 closePopup(popupID, cookieDays); 163 91 } 92 }); 93 } else { 94 // Close button click handling - specifically target the correct close button. 95 $(".boostbox-popup-overlay[data-popup-id='" + popupID + "'] .boostbox-close").on("click", function () { 96 closePopup(popupID, cookieDays); 164 97 }); 165 98 } 166 99 } 100 101 // Function to close the popup and set a cookie. 102 function closePopup(popupID, cookieDays) { 103 $(".boostbox-popup-overlay[data-popup-id='" + popupID + "']").removeClass("active"); 104 var expirationDate = new Date(); 105 expirationDate.setTime(expirationDate.getTime() + (cookieDays * 24 * 60 * 60 * 1000)); 106 Cookies.set('boostbox_popup_' + popupID, 'hidden', { expires: expirationDate }); 107 } 108 109 // Function to convert percentage to pixels. 110 function percentageToPixels(percentage, containerHeight) { 111 var percent = parseInt(percentage, 10); 112 return (percent / 100) * containerHeight; 113 } 114 115 // Function to increment popup view count. 116 function incrementPopupViewCount(popupID) { 117 $.ajax({ 118 url: boostbox_settings.ajax_url, 119 type: 'POST', 120 data: { 121 action: 'increment_popup_view_count', 122 popup_id: popupID, 123 nonce: boostbox_settings.nonce, 124 }, 125 success: function (response) { 126 //console.log('[SUCCESS] Impression tracking complete for popup ' + popupID + ' ' + response); 127 }, 128 error: function (xhr, status, error) { 129 //console.log('[ERROR] Impression tracking failed for popup ' + popupID); 130 //console.log('XHR:', xhr); 131 //console.log('Status:', status); 132 //console.log('Error:', error); 133 } 134 }); 135 } 136 137 // Function to track conversions. 138 function trackConversion(popupID) { 139 $.ajax({ 140 url: boostbox_settings.ajax_url, 141 type: 'POST', 142 data: { 143 action: 'track_popup_conversion', 144 popup_id: popupID, 145 nonce: boostbox_settings.nonce, 146 }, 147 success: function (response) { 148 //console.log('[SUCCESS] Conversion tracking complete for popup ' + popupID); 149 }, 150 error: function (error) { 151 //console.log('[ERROR] Conversion tracking failed for popup ' + popupID); 152 } 153 }); 154 } 167 155 });
Note: See TracChangeset
for help on using the changeset viewer.