This commit is contained in:
2026-07-02 15:54:39 -06:00
commit 9883323161
17470 changed files with 4470592 additions and 0 deletions
@@ -0,0 +1,94 @@
<?php
/**
* Modal Iframe Context Handler
*
* Handles enqueuing the iframe context script and adding modal context detection.
*
* @package GenerateBlocks Pro
*/
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Class GenerateBlocks_Pro_Overlay_Iframe_Context
*
* This class manages the context for modals when they are opened in an iframe.
* It enqueues the necessary scripts and styles, adds body classes, and provides utility methods
* for checking modal context and generating modal edit URLs.
*/
class GenerateBlocks_Pro_Overlay_Iframe_Context {
/**
* Initialize the class.
*/
public function __construct() {
// Don't initialize if overlays are disabled.
if ( ! generateblocks_pro_overlays_enabled() ) {
return;
}
add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_iframe_context_script' ) );
}
/**
* Enqueue iframe context script when editing overlays.
*/
public function enqueue_iframe_context_script() {
// Only in admin area.
if ( ! is_admin() ) {
return;
}
// Check if we're on a post edit screen.
$current_screen = get_current_screen();
if ( ! $current_screen || ! in_array( $current_screen->base, array( 'post', 'post-new' ), true ) ) {
return;
}
// Check if we're editing a overlay.
global $post;
if ( ! $post || 'gblocks_overlay' !== $post->post_type ) {
return;
}
// Check if we're in overlay iframe context.
if ( isset( $_GET['gb_overlay_context'] ) && '1' === $_GET['gb_overlay_context'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$assets = generateblocks_pro_get_enqueue_assets( 'gb-overlay-iframe-context' );
// Enqueue the iframe context script.
wp_enqueue_script(
'gb-overlay-iframe-context',
GENERATEBLOCKS_PRO_DIR_URL . 'dist/overlay-iframe-context.js', // Use built file.
$assets['dependencies'],
$assets['version'],
true
);
// Enqueue the iframe context styles.
wp_enqueue_style(
'gb-overlay-iframe-context',
GENERATEBLOCKS_PRO_DIR_URL . 'dist/overlay-iframe-context.css',
array(),
filemtime( GENERATEBLOCKS_PRO_DIR . 'dist/overlay-iframe-context.css' ) // Use built file.
);
// Add admin body class for overlay context.
add_filter( 'admin_body_class', array( $this, 'add_overlay_context_body_class' ) );
}
}
/**
* Add overlay context body class.
*
* @param string $classes Existing body classes.
* @return string Modified body classes.
*/
public function add_overlay_context_body_class( $classes ) {
return $classes . ' gb-overlay-context';
}
}
// Initialize the class.
new GenerateBlocks_Pro_Overlay_Iframe_Context();
@@ -0,0 +1,138 @@
<?php
/**
* This file displays our block elements on the site.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
/**
* Class GeneratePress_Pro_Template_Post_Type
*/
class GenerateBlocks_Pro_Overlay_Post_Type extends GenerateBlocks_Pro_Singleton {
/**
* Initialize class.
*/
public function init() {
// Don't initialize if overlays are disabled.
if ( ! generateblocks_pro_overlays_enabled() ) {
return;
}
add_action( 'init', [ $this, 'register_post_type' ] );
add_action( 'init', [ $this, 'register_taxonomy' ] );
add_action( 'admin_init', [ $this, 'redirect_admin_view' ] );
}
/**
* Register our custom post type.
*/
public function register_post_type() {
$labels = array(
'name' => _x( 'Overlay Panels', 'post type general name', 'generateblocks-pro' ),
'singular_name' => _x( 'Overlay Panel', 'post type singular name', 'generateblocks-pro' ),
'menu_name' => _x( 'Overlay Panels', 'admin menu', 'generateblocks-pro' ),
'name_admin_bar' => _x( 'Overlay Panel', 'add new on admin bar', 'generateblocks-pro' ),
'add_new' => _x( 'Add New', 'overlay', 'generateblocks-pro' ),
'add_new_item' => __( 'Add New Overlay Panel', 'generateblocks-pro' ),
'new_item' => __( 'New Overlay Panel', 'generateblocks-pro' ),
'edit_item' => __( 'Edit Overlay Panel', 'generateblocks-pro' ),
'view_item' => __( 'View Overlay Panel', 'generateblocks-pro' ),
'all_items' => __( 'All Overlay Panels', 'generateblocks-pro' ),
'search_items' => __( 'Search Overlay Panels', 'generateblocks-pro' ),
'parent_item_colon' => __( 'Parent Overlay Panels:', 'generateblocks-pro' ),
'not_found' => __( 'No overlay panels found.', 'generateblocks-pro' ),
'not_found_in_trash' => __( 'No overlay panels found in Trash.', 'generateblocks-pro' ),
);
// Get the capability for managing overlays.
$manage_cap = GenerateBlocks_Pro_Overlays::get_overlays_capability( 'manage' );
$use_cap = GenerateBlocks_Pro_Overlays::get_overlays_capability( 'use' );
$args = array(
'labels' => $labels,
'supports' => array( 'title', 'editor', 'custom-fields', 'revisions' ),
'hierarchical' => false,
'public' => false,
'publicly_queryable' => false,
'has_archive' => false,
'show_ui' => true,
'show_in_menu' => false,
'exclude_from_search' => true,
'show_in_nav_menus' => false,
'rewrite' => false,
'show_in_admin_bar' => false,
'show_in_rest' => true,
'can_export' => true,
'capability_type' => 'post',
'capabilities' => array(
'read' => $use_cap,
'create_posts' => $manage_cap,
'edit_posts' => $use_cap,
'edit_others_posts' => $manage_cap,
'edit_published_posts' => $manage_cap,
'edit_private_posts' => $manage_cap,
'publish_posts' => $manage_cap,
'delete_posts' => $manage_cap,
'delete_others_posts' => $manage_cap,
'delete_published_posts' => $manage_cap,
'delete_private_posts' => $manage_cap,
'read_private_posts' => $manage_cap,
),
'map_meta_cap' => true,
);
register_post_type( 'gblocks_overlay', $args );
}
/**
* Register taxonomy for overlays.
*/
public function register_taxonomy() {
$labels = array(
'name' => _x( 'Categories', 'taxonomy general name', 'generateblocks-pro' ),
'singular_name' => _x( 'Category', 'taxonomy singular name', 'generateblocks-pro' ),
'search_items' => __( 'Search Categories', 'generateblocks-pro' ),
'all_items' => __( 'All Categories', 'generateblocks-pro' ),
'parent_item' => __( 'Parent Category', 'generateblocks-pro' ),
'parent_item_colon' => __( 'Parent Category:', 'generateblocks-pro' ),
'edit_item' => __( 'Edit Category', 'generateblocks-pro' ),
'update_item' => __( 'Update Category', 'generateblocks-pro' ),
'add_new_item' => __( 'Add New Category', 'generateblocks-pro' ),
'new_item_name' => __( 'New Category Name', 'generateblocks-pro' ),
'menu_name' => __( 'Categories', 'generateblocks-pro' ),
);
$args = array(
'hierarchical' => true,
'labels' => $labels,
'public' => false,
'show_ui' => false,
'show_in_menu' => false,
'show_admin_column' => false,
'query_var' => false,
'rewrite' => false,
'show_in_rest' => true,
'rest_base' => 'overlay-categories',
);
register_taxonomy( 'gblocks_overlay_cat', array( 'gblocks_overlay' ), $args );
}
/**
* Redirect to site editor when viewing site templates.
*/
public function redirect_admin_view() {
global $pagenow;
if ( 'edit.php' === $pagenow && isset( $_GET['post_type'] ) && 'gblocks_overlay' === $_GET['post_type'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
wp_safe_redirect( admin_url( 'admin.php?page=generateblocks-overlay-panels' ) );
exit;
}
}
}
GenerateBlocks_Pro_Overlay_Post_Type::get_instance()->init();
@@ -0,0 +1,386 @@
<?php
/**
* REST API functionality for overlays.
*
* @package GenerateBlocks Pro
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
/**
* Class GenerateBlocks_Pro_Overlay_Rest
*/
class GenerateBlocks_Pro_Overlay_Rest extends GenerateBlocks_Pro_Singleton {
/**
* Initialize class.
*/
public function init() {
// Don't initialize if overlays are disabled.
if ( ! generateblocks_pro_overlays_enabled() ) {
return;
}
add_action( 'rest_api_init', [ $this, 'register_routes' ] );
add_filter( 'rest_prepare_gblocks_overlay', [ $this, 'add_category_to_response' ], 10, 3 );
add_action( 'rest_insert_gblocks_overlay', [ $this, 'handle_category_on_save' ], 10, 3 );
}
/**
* Register REST routes.
*/
public function register_routes() {
register_rest_route(
'generateblocks-pro/overlays/v1',
'/get_modal_categories/',
[
[
'methods' => 'GET',
'callback' => [ $this, 'get_overlay_categories' ],
'permission_callback' => [ $this, 'permissions_check' ],
],
]
);
register_rest_route(
'generateblocks-pro/overlays/v1',
'/manage_category/',
[
[
'methods' => 'POST',
'callback' => [ $this, 'create_category' ],
'permission_callback' => [ $this, 'permissions_check' ],
'args' => [
'name' => [
'required' => true,
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
],
],
],
]
);
register_rest_route(
'generateblocks-pro/overlays/v1',
'/overlays/',
[
[
'methods' => 'GET',
'callback' => [ $this, 'get_overlays' ],
'permission_callback' => [ $this, 'permissions_check' ],
],
]
);
register_rest_route(
'generateblocks-pro/overlays/v1',
'/manage_category/(?P<id>\d+)',
[
[
'methods' => 'POST',
'callback' => [ $this, 'update_category' ],
'permission_callback' => [ $this, 'permissions_check' ],
'args' => [
'id' => [
'required' => true,
'type' => 'integer',
'sanitize_callback' => 'absint',
],
'name' => [
'required' => true,
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
],
],
],
[
'methods' => 'DELETE',
'callback' => [ $this, 'delete_category' ],
'permission_callback' => [ $this, 'permissions_check' ],
'args' => [
'id' => [
'required' => true,
'type' => 'integer',
'sanitize_callback' => 'absint',
],
],
],
]
);
}
/**
* Check if a given request has access to manage categories.
*
* @param WP_REST_Request $request Full data about the request.
* @return bool
*/
public function permissions_check( $request ) {
// For modifying operations, check manage permission.
$request_method = $_SERVER['REQUEST_METHOD'] ?? '';
if ( in_array( $request_method, [ 'POST', 'PUT', 'PATCH', 'DELETE' ], true ) ) {
// Creating, updating, or deleting requires manage permission.
return GenerateBlocks_Pro_Overlays::current_user_can_use_overlays( 'manage' );
}
// Reading/listing only requires use permission.
return GenerateBlocks_Pro_Overlays::current_user_can_use_overlays( 'use' );
}
/**
* Get all overlays.
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_overlays( $request ) {
$can_manage = GenerateBlocks_Pro_Overlays::current_user_can_use_overlays( 'manage' );
$args = [
'post_type' => 'gblocks_overlay',
'posts_per_page' => 100,
'post_status' => $can_manage ? 'any' : 'publish',
'orderby' => 'title',
'order' => 'ASC',
];
$posts = get_posts( $args );
$overlays = [];
foreach ( $posts as $post ) {
if ( ! current_user_can( 'read_post', $post->ID ) ) {
continue;
}
$category_terms = wp_get_post_terms( $post->ID, 'gblocks_overlay_cat', [ 'fields' => 'ids' ] );
$overlay_type = get_post_meta( $post->ID, '_gb_overlay_type', true );
$display_condition = get_post_meta( $post->ID, '_gb_overlay_display_condition', true );
$display_condition_invert = get_post_meta( $post->ID, '_gb_overlay_display_condition_invert', true );
$overlays[] = [
'id' => $post->ID,
'title' => [ 'rendered' => $post->post_title ],
'status' => $post->post_status,
'gblocks_overlay_cat' => ! empty( $category_terms ) ? $category_terms : [],
'overlay_type' => ! empty( $overlay_type ) ? $overlay_type : 'standard',
'display_condition' => ! empty( $display_condition ) ? $display_condition : '',
'display_condition_invert' => ! empty( $display_condition_invert ) ? $display_condition_invert : false,
];
}
return new WP_REST_Response(
[
'success' => true,
'response' => [
'modals' => $overlays,
],
],
200
);
}
/**
* Get all overlay categories.
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_overlay_categories( $request ) {
$terms = get_terms(
[
'taxonomy' => 'gblocks_overlay_cat',
'hide_empty' => false,
]
);
if ( is_wp_error( $terms ) ) {
return $terms;
}
// Add count for each category.
$categories = [];
foreach ( $terms as $term ) {
$categories[] = [
'id' => $term->term_id,
'name' => $term->name,
'slug' => $term->slug,
'count' => $term->count,
];
}
return new WP_REST_Response(
[
'success' => true,
'categories' => $categories,
],
200
);
}
/**
* Create a new category.
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function create_category( $request ) {
$name = $request->get_param( 'name' );
$term = wp_insert_term( $name, 'gblocks_overlay_cat' );
if ( is_wp_error( $term ) ) {
return new WP_Error(
'create_failed',
__( 'Failed to create category.', 'generateblocks-pro' ),
[ 'status' => 400 ]
);
}
$created_term = get_term( $term['term_id'], 'gblocks_overlay_cat' );
return new WP_REST_Response(
[
'success' => true,
'category' => [
'id' => $created_term->term_id,
'name' => $created_term->name,
'slug' => $created_term->slug,
'count' => 0,
],
],
201
);
}
/**
* Update a category.
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function update_category( $request ) {
$id = $request->get_param( 'id' );
$name = $request->get_param( 'name' );
$term = wp_update_term(
$id,
'gblocks_overlay_cat',
[
'name' => $name,
]
);
if ( is_wp_error( $term ) ) {
return new WP_Error(
'update_failed',
__( 'Failed to update category.', 'generateblocks-pro' ),
[ 'status' => 400 ]
);
}
$updated_term = get_term( $id, 'gblocks_overlay_cat' );
return new WP_REST_Response(
[
'success' => true,
'category' => [
'id' => $updated_term->term_id,
'name' => $updated_term->name,
'slug' => $updated_term->slug,
'count' => $updated_term->count,
],
],
200
);
}
/**
* Delete a category.
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function delete_category( $request ) {
$id = $request->get_param( 'id' );
// Check if category is in use.
$term = get_term( $id, 'gblocks_overlay_cat' );
if ( is_wp_error( $term ) ) {
return new WP_Error(
'term_not_found',
__( 'Category not found.', 'generateblocks-pro' ),
[ 'status' => 404 ]
);
}
$result = wp_delete_term( $id, 'gblocks_overlay_cat' );
if ( is_wp_error( $result ) ) {
return new WP_Error(
'delete_failed',
__( 'Failed to delete category.', 'generateblocks-pro' ),
[ 'status' => 400 ]
);
}
return new WP_REST_Response(
[
'success' => true,
'message' => __( 'Category deleted successfully.', 'generateblocks-pro' ),
],
200
);
}
/**
* Add category to REST response.
*
* @param WP_REST_Response $response The response object.
* @param WP_Post $post Post object.
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response
*/
public function add_category_to_response( $response, $post, $request ) {
$category_terms = wp_get_post_terms( $post->ID, 'gblocks_overlay_cat', [ 'fields' => 'ids' ] );
$response->data['gblocks_overlay_cat'] = ! empty( $category_terms ) ? $category_terms : [];
// Add overlay type to response.
$overlay_type = get_post_meta( $post->ID, '_gb_overlay_type', true );
$response->data['overlay_type'] = ! empty( $overlay_type ) ? $overlay_type : 'standard';
// Add display condition to response.
$display_condition = get_post_meta( $post->ID, '_gb_overlay_display_condition', true );
$response->data['display_condition'] = ! empty( $display_condition ) ? $display_condition : '';
// Add display condition invert to response.
$display_condition_invert = get_post_meta( $post->ID, '_gb_overlay_display_condition_invert', true );
$response->data['display_condition_invert'] = ! empty( $display_condition_invert ) ? $display_condition_invert : false;
return $response;
}
/**
* Handle category assignment when saving overlay.
*
* @param WP_Post $post Inserted or updated post object.
* @param WP_REST_Request $request Request object.
* @param bool $creating True when creating a post, false when updating.
*/
public function handle_category_on_save( $post, $request, $creating ) {
if ( isset( $request['gblocks_overlay_cat'] ) ) {
$categories = $request['gblocks_overlay_cat'];
if ( ! is_array( $categories ) ) {
$categories = [ $categories ];
}
// Convert to integers and filter out empty values.
$categories = array_filter( array_map( 'intval', $categories ) );
wp_set_post_terms( $post->ID, $categories, 'gblocks_overlay_cat' );
}
}
}
GenerateBlocks_Pro_Overlay_Rest::get_instance()->init();
@@ -0,0 +1,301 @@
<?php
/**
* This file displays our block elements on the site.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
/**
* Class GeneratePress_Pro_Site_Template
*/
class GenerateBlocks_Pro_Overlay {
/**
* All found templates.
*
* @since 2.5.0
* @var boolean If this post has a parent.
*/
public $templates = [];
/**
* Instance.
*
* @access private
* @var object Instance
*/
private static $instance = null;
/**
* Constructor.
*/
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Try to add active templates.
*
* @since 2.5.0
*
* @param int $post_id The post ID.
*/
public function add_overlay( $post_id ) {
if ( ! $post_id ) {
return;
}
$display_condition = get_post_meta( $post_id, '_gb_overlay_display_condition', true );
$display_conditions = [];
if ( $display_condition ) {
// Check if the condition post exists and is published.
$condition_post = get_post( $display_condition );
if ( $condition_post && 'publish' === $condition_post->post_status ) {
$display_conditions = get_post_meta( $display_condition, '_gb_conditions', true ) ?? [];
}
}
$current_post_id = get_the_ID();
if ( ! $current_post_id && is_admin() ) {
$current_post_id = $_GET['post'] ?? null; // phpcs:ignore -- Input var okay.
}
$show = true;
if ( ! empty( $display_conditions ) ) {
$show = GenerateBlocks_Pro_Conditions::show( $display_conditions );
$invert_condition = GenerateBlocks_Pro_Overlays::get_overlay_meta( $post_id, '_gb_overlay_display_condition_invert' );
// If invert is enabled, flip the result.
if ( $invert_condition ) {
$show = ! $show;
}
}
if ( $show ) {
$this->templates[] = [
'post_id' => $post_id,
'conditions' => $display_conditions,
];
}
}
/**
* Initialize the templates.
*
* @return void
*/
public function init() {
if ( empty( $this->templates ) ) {
return;
}
$overlays = $this->templates;
if ( ! empty( $overlays ) ) {
wp_enqueue_script(
'generateblocks-overlay',
GENERATEBLOCKS_PRO_DIR_URL . 'dist/overlay.js',
[],
GENERATEBLOCKS_PRO_VERSION,
true
);
wp_enqueue_style(
'generateblocks-overlay',
GENERATEBLOCKS_PRO_DIR_URL . 'dist/overlay.css',
[],
GENERATEBLOCKS_PRO_VERSION
);
foreach ( $overlays as $overlay ) {
$custom_part_template = get_post( $overlay['post_id'] );
$custom_part_output = $this->get_overlay( $custom_part_template );
if ( empty( $overlay['conditions'] ) ) {
$this->add_generateblocks_content( $custom_part_template );
} else {
$dynamic_css_priority = apply_filters( 'generateblocks_dynamic_css_priority', 25 );
$inline_css_priority = is_numeric( $dynamic_css_priority ) ? $dynamic_css_priority + 10 : 999;
add_action(
'wp_enqueue_scripts',
function() use ( $custom_part_template ) {
if ( function_exists( 'generateblocks_pro_get_css_from_content' ) ) {
$overlay_css = generateblocks_pro_get_css_from_content( $custom_part_template->post_content );
if ( $overlay_css ) {
wp_add_inline_style( 'generateblocks', $overlay_css );
}
}
},
$inline_css_priority
);
}
$this->add_overlay_to_memory( 'overlay', $overlay['post_id'] );
// Get all meta at once (more readable, same performance).
$meta = GenerateBlocks_Pro_Overlays::get_all_overlay_meta( $overlay['post_id'] );
$overlay_output = function() use ( $custom_part_output, $overlay, $meta ) {
$overlay_content = $custom_part_output;
$overlay_id = $overlay['post_id'] ? 'gb-overlay-' . $overlay['post_id'] : wp_unique_id( 'gb-overlay-' );
// Extract what we need.
$overlay_type = $meta['_gb_overlay_type'];
$trigger_type = $meta['_gb_overlay_trigger_type'];
$backdrop = $meta['_gb_overlay_backdrop'];
$backdrop_color = $meta['_gb_overlay_backdrop_color'];
$backdrop_blur = $meta['_gb_overlay_backdrop_blur'];
$placement = $meta['_gb_overlay_placement'];
$animation_in = $meta['_gb_overlay_animation_in'];
$animation_out = $meta['_gb_overlay_animation_out'];
$animation_duration = $meta['_gb_overlay_animation_duration'];
$animation_target = $meta['_gb_overlay_animation_target'];
$animation_distance = $meta['_gb_overlay_animation_distance'];
$custom_event = $meta['_gb_overlay_custom_event'];
$hide_if_cookies_disabled = $meta['_gb_overlay_hide_if_cookies_disabled'];
$position_to_parent = $meta['_gb_overlay_position_to_parent'];
$hover_buffer = $meta['_gb_overlay_hover_buffer'];
// Conditional meta based on overlay type.
$scroll_percent = 'standard' === $overlay_type ? $meta['_gb_overlay_scroll_percent'] : false;
$time_delay = 'standard' === $overlay_type ? $meta['_gb_overlay_time_delay'] : false;
$allow_cookie = 'standard' === $overlay_type && ( 'exit-intent' === $trigger_type || 'time' === $trigger_type || 'scroll' === $trigger_type || 'custom' === $trigger_type );
$cookie_duration = $allow_cookie ? $meta['_gb_overlay_cookie_duration'] : false;
// Standard overlay specific options.
$close_on_esc = 'standard' === $overlay_type ? $meta['_gb_overlay_close_on_esc'] : true;
$close_on_click_outside = 'standard' === $overlay_type ? $meta['_gb_overlay_close_on_click_outside'] : true;
$disable_page_scroll = 'standard' === $overlay_type ? $meta['_gb_overlay_disable_page_scroll'] : false;
$position = 'standard' === $overlay_type ? $meta['_gb_overlay_position'] : '';
// Width mode applies to all overlay types.
$width_mode = $meta['_gb_overlay_width_mode'];
// Add a filter to allow lazy load for specific overlays.
$should_allow_lazy_load = apply_filters(
'generateblocks_pro_overlay_allow_lazy_load',
false,
$overlay['post_id'],
$meta
);
if ( ! $should_allow_lazy_load && ( 'anchored' === $overlay_type || 'mega-menu' === $overlay_type ) ) {
// Use WP_HTML_Tag_Processor to add loading attributes to images.
if ( class_exists( 'WP_HTML_Tag_Processor' ) ) {
$processor = new WP_HTML_Tag_Processor( $overlay_content );
// Process all img tags.
while ( $processor->next_tag( 'img' ) ) {
// Add fetchpriority if not present.
if ( null === $processor->get_attribute( 'fetchpriority' ) ) {
$processor->set_attribute( 'fetchpriority', 'high' );
}
// Set loading to eager to prevent lazy loading.
$processor->set_attribute( 'loading', 'eager' );
}
$overlay_content = $processor->get_updated_html();
}
}
ob_start();
include plugin_dir_path( __FILE__ ) . 'overlay-template.php';
$overlay_output = ob_get_clean();
echo $overlay_output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output safe.
};
$overlay_type = $meta['_gb_overlay_type'];
if ( 'mega-menu' === $overlay_type ) {
$action_id = 'gb-mega-menu-' . $overlay['post_id'];
add_action( $action_id, $overlay_output );
} else {
add_action( 'wp_footer', $overlay_output );
}
}
}
}
/**
* Get the template content.
*
* @since 2.5.0
*
* @param object $template The template object.
*/
public function get_overlay( $template ) {
if ( ! function_exists( 'do_blocks' ) ) {
return;
}
if ( ! $template || 'gblocks_overlay' !== $template->post_type ) {
return '';
}
if ( 'publish' !== $template->post_status || ! empty( $template->post_password ) ) {
return '';
}
$template_content = $template->post_content;
// Handle embeds for block elements.
global $wp_embed;
if ( is_object( $wp_embed ) && method_exists( $wp_embed, 'autoembed' ) ) {
$template_content = $wp_embed->autoembed( $template_content );
}
return apply_filters(
'generateblocks_overlay_panel',
do_blocks( $template_content ),
$template->ID ?? null
);
}
/**
* Add the template content to the generateblocks_do_content filter.
*
* @since 2.5.0
*
* @param object $template The template object.
*/
private function add_generateblocks_content( $template ) {
add_filter(
'generateblocks_do_content',
function( $content ) use ( $template ) {
return $content . $template->post_content;
}
);
}
/**
* Add a template to the memory.
*
* @since 2.5.0
*
* @param string $type The template type.
* @param int $id The template ID.
*/
private function add_overlay_to_memory( $type, $id ) {
global $gb_overlays;
$gb_overlays[ $id ] = array(
'type' => $type,
'id' => $id,
);
}
}
@@ -0,0 +1,735 @@
<?php
/**
* This file displays our block elements on the site.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
/**
* Class GeneratePress_Pro_Site_Editor
*/
class GenerateBlocks_Pro_Overlays extends GenerateBlocks_Pro_Singleton {
/**
* Initialize the class filters.
*
* @return void
*/
public function init() {
// Don't initialize if overlays are disabled.
if ( ! generateblocks_pro_overlays_enabled() ) {
return;
}
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) );
add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ), 8 );
add_filter( 'block_editor_settings_all', array( $this, 'editor_css' ), 15 );
add_action( 'admin_bar_menu', array( $this, 'add_admin_bar' ), 100 );
add_filter( 'generateblocks_dashboard_tabs', [ $this, 'dashboard_tab' ] );
add_filter( 'generateblocks_dashboard_screens', [ $this, 'dashboard_screen' ] );
add_action( 'init', [ $this, 'register_post_meta' ] );
add_action( 'rest_api_init', [ $this, 'register_rest' ] );
add_action( 'save_post_gblocks_overlay', [ $this, 'save_post' ] );
add_action( 'delete_post', [ $this, 'delete_post' ] );
add_action( 'transition_post_status', [ $this, 'transition_post_status' ], 10, 3 );
}
/**
* Get default values for overlay meta fields.
*
* @return array Default values.
*/
public static function get_meta_defaults() {
return array(
'_gb_overlay_display_condition' => '',
'_gb_overlay_display_condition_invert' => false,
'_gb_overlay_trigger_type' => 'click',
'_gb_overlay_type' => 'standard',
'_gb_overlay_placement' => 'bottom-start',
'_gb_overlay_backdrop' => true,
'_gb_overlay_backdrop_color' => 'rgba(0, 0, 0, 0.5)',
'_gb_overlay_backdrop_blur' => '',
'_gb_overlay_animation_in' => '',
'_gb_overlay_animation_out' => '',
'_gb_overlay_animation_duration' => '',
'_gb_overlay_animation_target' => '',
'_gb_overlay_animation_distance' => '',
'_gb_overlay_scroll_percent' => '',
'_gb_overlay_time_delay' => '',
'_gb_overlay_cookie_duration' => '',
'_gb_overlay_close_on_esc' => true,
'_gb_overlay_close_on_click_outside' => true,
'_gb_overlay_disable_page_scroll' => false,
'_gb_overlay_position' => 'center',
'_gb_overlay_custom_event' => '',
'_gb_overlay_hide_if_cookies_disabled' => false,
'_gb_overlay_position_to_parent' => '',
'_gb_overlay_hover_buffer' => '20',
'_gb_overlay_width_mode' => '',
);
}
/**
* Register our post meta.
*/
public function register_post_meta() {
$defaults = self::get_meta_defaults();
$meta_fields = array(
'_gb_overlay_display_condition' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'_gb_overlay_display_condition_invert' => array(
'type' => 'boolean',
'sanitize_callback' => 'rest_sanitize_boolean',
),
'_gb_overlay_trigger_type' => array(
'type' => 'string',
'sanitize_callback' => function ( $value ) {
$allowed = [ 'click', 'hover', 'both', 'exit-intent', 'scroll', 'time', 'custom' ];
return in_array( $value, $allowed ) ? $value : 'click';
},
),
'_gb_overlay_type' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'_gb_overlay_placement' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'_gb_overlay_backdrop' => array(
'type' => 'boolean',
'sanitize_callback' => 'rest_sanitize_boolean',
),
'_gb_overlay_backdrop_color' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'_gb_overlay_backdrop_blur' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'_gb_overlay_animation_in' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'_gb_overlay_animation_out' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'_gb_overlay_animation_duration' => array(
'type' => 'string',
'sanitize_callback' => function ( $value ) {
return '' === $value ? '' : absint( $value );
},
),
'_gb_overlay_animation_target' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'_gb_overlay_animation_distance' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'_gb_overlay_scroll_percent' => array(
'type' => 'string',
'sanitize_callback' => function ( $value ) {
return '' === $value ? '' : max( 0, min( 100, absint( $value ) ) );
},
),
'_gb_overlay_time_delay' => array(
'type' => 'string',
'sanitize_callback' => function ( $value ) {
return '' === $value ? '' : absint( $value );
},
),
'_gb_overlay_cookie_duration' => array(
'type' => 'string',
'sanitize_callback' => function ( $value ) {
return '' === $value ? '' : absint( $value );
},
),
'_gb_overlay_close_on_esc' => array(
'type' => 'boolean',
'sanitize_callback' => 'rest_sanitize_boolean',
),
'_gb_overlay_close_on_click_outside' => array(
'type' => 'boolean',
'sanitize_callback' => 'rest_sanitize_boolean',
),
'_gb_overlay_disable_page_scroll' => array(
'type' => 'boolean',
'sanitize_callback' => 'rest_sanitize_boolean',
),
'_gb_overlay_position' => array(
'type' => 'string',
'sanitize_callback' => function ( $value ) {
$allowed = [ 'center', 'top-left', 'top-center', 'top-right', 'center-left', 'center-right', 'bottom-left', 'bottom-center', 'bottom-right' ];
return in_array( $value, $allowed ) ? $value : 'center';
},
),
'_gb_overlay_custom_event' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'_gb_overlay_hide_if_cookies_disabled' => array(
'type' => 'boolean',
'sanitize_callback' => 'rest_sanitize_boolean',
),
'_gb_overlay_position_to_parent' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'_gb_overlay_hover_buffer' => array(
'type' => 'string',
'sanitize_callback' => function ( $value ) {
return '' === $value ? '' : max( 0, min( 100, absint( $value ) ) );
},
),
'_gb_overlay_width_mode' => array(
'type' => 'string',
'sanitize_callback' => function ( $value ) {
$allowed = [ '', 'full' ];
return in_array( $value, $allowed ) ? $value : '';
},
),
);
foreach ( $meta_fields as $key => $args ) {
register_post_meta(
'gblocks_overlay',
$key,
array(
'single' => true,
'type' => $args['type'],
'auth_callback' => static function() {
return GenerateBlocks_Pro_Overlays::current_user_can_use_overlays( 'manage' );
},
'sanitize_callback' => $args['sanitize_callback'],
'show_in_rest' => true,
'default' => $defaults[ $key ],
)
);
}
}
/**
* Get overlay meta with proper defaults.
* This uses WordPress's built-in caching, so multiple calls are efficient.
*
* @param int $post_id Post ID.
* @param string $meta_key Meta key.
* @return mixed Meta value or default.
*/
public static function get_overlay_meta( $post_id, $meta_key ) {
$defaults = self::get_meta_defaults();
// Check if meta exists in database.
$meta_exists = metadata_exists( 'post', $post_id, $meta_key );
if ( ! $meta_exists && isset( $defaults[ $meta_key ] ) ) {
// Meta doesn't exist, return default.
return $defaults[ $meta_key ];
}
// Meta exists, get the value.
$value = get_post_meta( $post_id, $meta_key, true );
// For boolean fields, properly convert WordPress storage to boolean.
// WordPress stores: true as '1', false as '' (empty string).
if ( isset( $defaults[ $meta_key ] ) && is_bool( $defaults[ $meta_key ] ) ) {
return '1' === $value;
}
// For string/number fields, if empty and has default, return default.
if ( '' === $value && isset( $defaults[ $meta_key ] ) && ! is_bool( $defaults[ $meta_key ] ) ) {
return $defaults[ $meta_key ];
}
return $value;
}
/**
* Get all overlay meta at once for better performance.
* WordPress caches all meta after first query, but this can be more convenient.
*
* @param int $post_id Post ID.
* @return array All overlay meta with defaults applied.
*/
public static function get_all_overlay_meta( $post_id ) {
$defaults = self::get_meta_defaults();
$meta = array();
foreach ( $defaults as $key => $default ) {
$meta[ $key ] = self::get_overlay_meta( $post_id, $key );
}
return $meta;
}
/**
* Register the REST field for the admin edit URL.
*
* @return void
*/
public function register_rest() {
register_rest_field(
'gblocks_overlay',
'admin_edit_url',
array(
'get_callback' => function ( $post_object ) {
if ( current_user_can( 'edit_post', $post_object['id'] ) ) {
return get_edit_post_link( $post_object['id'], 'raw' );
}
return null;
},
'schema' => array(
'description' => 'Admin URL to edit the post.',
'type' => 'string',
'format' => 'uri',
'context' => array( 'view', 'edit' ),
),
)
);
register_rest_field(
'gblocks_overlay',
'trigger_info',
array(
'get_callback' => function ( $post_object ) {
$trigger_type = self::get_overlay_meta( $post_object['id'], '_gb_overlay_trigger_type' );
// Only return data for interactive overlays.
if ( ! in_array( $trigger_type, array( 'click', 'hover', 'both' ), true ) ) {
return null;
}
return array(
'trigger_type' => $trigger_type,
'is_interactive' => true,
);
},
'schema' => array(
'description' => 'Overlay trigger information for block editor.',
'type' => 'object',
'context' => array( 'view', 'edit' ),
'properties' => array(
'trigger_type' => array(
'type' => 'string',
'enum' => array( 'click', 'hover', 'both' ),
),
'is_interactive' => array(
'type' => 'boolean',
),
),
),
)
);
add_filter( 'rest_gblocks_overlay_collection_params', array( $this, 'increase_overlay_collection_limit' ), 10, 1 );
}
/**
* Increase the per_page limit for overlay collections.
* This is the proper WordPress way to handle this.
*
* @param array $params Collection parameters.
* @return array Modified parameters.
*/
public function increase_overlay_collection_limit( $params ) {
// Increase limit to reasonable amount (not unlimited).
if ( isset( $params['per_page'] ) ) {
$params['per_page']['maximum'] = 200; // Reasonable limit for overlays.
$params['per_page']['default'] = 100; // Keep default reasonable.
}
return $params;
}
/**
* Get the capability required for overlays.
*
* @since 2.4.0
* @param string $context The context: 'use' (select existing) or 'manage' (create/edit/dashboard).
* @return string The capability required.
*/
public static function get_overlays_capability( $context = 'use' ) {
// Default capabilities.
if ( 'manage' === $context ) {
// Can create/edit/access dashboard - default to manage_options.
$capability = 'manage_options';
} else {
// Can select/use existing overlays - anyone who can edit posts.
$capability = 'edit_posts';
}
/**
* Filter the capability required for overlays.
*
* @since 2.4.0
* @param string $capability The capability required.
* @param string $context The context: 'use' or 'manage'.
*/
return apply_filters( 'generateblocks_overlays_capability', $capability, $context );
}
/**
* Check if current user can use overlays.
*
* @since 2.4.0
* @param string $context The context: 'use' (select existing) or 'manage' (create/edit/dashboard).
* @return bool
*/
public static function current_user_can_use_overlays( $context = 'use' ) {
$capability = self::get_overlays_capability( $context );
return current_user_can( $capability );
}
/**
* Add the Site Editor menu item.
*
* @return void
*/
public function admin_menu() {
// Get the required capability.
$capability = self::get_overlays_capability( 'manage' );
// Only add menu if user has permission.
if ( ! current_user_can( $capability ) ) {
return;
}
add_submenu_page(
'generateblocks',
__( 'Overlay Panels', 'generateblocks-pro' ),
__( 'Overlay Panels', 'generateblocks-pro' ),
$capability,
'generateblocks-overlay-panels',
array( $this, 'render_page' ),
4
);
}
/**
* Render the Site Editor page.
*
* @return void
*/
public function render_page() {
// Double-check permission before rendering.
if ( ! self::current_user_can_use_overlays( 'manage' ) ) {
wp_die( esc_html__( 'Sorry, you are not allowed to access this page.', 'generateblocks-pro' ) );
}
?>
<div class="wrap gblocks-dashboard-wrap">
<div class="generateblocks-settings-area generateblocks-overlay-panels-area">
<div id="gblocks-overlays"></div>
</div>
</div>
<?php
}
/**
* Enqueue the admin assets.
*
* @return void
*/
public function enqueue_admin_assets() {
$screen = get_current_screen();
if ( 'generateblocks_page_generateblocks-overlay-panels' !== $screen->id ) {
return;
}
$assets = generateblocks_pro_get_enqueue_assets( 'overlay-dashboard' );
wp_enqueue_script(
'gb-overlay-dashboard',
GENERATEBLOCKS_PRO_DIR_URL . 'dist/overlay-dashboard.js',
$assets['dependencies'],
$assets['version'],
true
);
wp_enqueue_style(
'gb-overlay-dashboard',
GENERATEBLOCKS_PRO_DIR_URL . 'dist/overlay-dashboard.css',
array( 'wp-components', 'generateblocks-pro-dashboard-table' ),
GENERATEBLOCKS_PRO_VERSION
);
wp_localize_script(
'gb-overlay-dashboard',
'gbOverlaysDashboard',
array(
'newOverlayUrl' => admin_url( 'post-new.php?post_type=gblocks_overlay' ),
)
);
}
/**
* Enqueue the block editor assets.
*
* @return void
*/
public function enqueue_block_editor_assets() {
if ( 'gblocks_overlay' !== get_post_type() ) {
return;
}
$assets = generateblocks_pro_get_enqueue_assets( 'overlay-editor' );
wp_enqueue_script(
'gb-overlay-editor',
GENERATEBLOCKS_PRO_DIR_URL . 'dist/overlay-editor.js',
$assets['dependencies'],
$assets['version'],
true
);
wp_enqueue_style(
'gb-overlay-editor',
GENERATEBLOCKS_PRO_DIR_URL . 'dist/overlay-editor.css',
array( 'wp-components' ),
GENERATEBLOCKS_PRO_VERSION
);
wp_localize_script(
'gb-overlay-editor',
'gbOverlayDefaults',
self::get_meta_defaults()
);
}
/**
* This resets the `max-width`, `margin-left`, and `margin-right` properties for our blocks in the editor.
* We have to do this as most themes use `.wp-block` to set a `max-width` and auto margins.
*
* We used to do this directly in the block CSS if those block attributes didn't exist, but this allows us
* to overwrite the reset in the `block_editor_settings_all` filter with a later priority.
*
* @param array $editor_settings The existing editor settings.
*/
public function editor_css( $editor_settings ) {
if ( 'gblocks_overlay' === get_post_type() ) {
$post_id = get_the_ID();
$width_mode = self::get_overlay_meta( $post_id, '_gb_overlay_width_mode' );
$css = '.is-root-container {max-width: calc(100% - 20px);margin-left: auto;margin-right:auto;}';
$css .= '.editor-styles-wrapper {--content-width: 100% !important;}';
// Add width mode specific styles.
if ( 'full' === $width_mode ) {
$css .= '.is-root-container {width: 100%;}';
} else {
$css .= '.is-root-container {width: max-content;min-width: 300px;}';
}
$editor_settings['styles'][] = [ 'css' => $css ];
}
return $editor_settings;
}
/**
* Add the Elementd admin bar item.
*
* @since 2.0.0
*/
public function add_admin_bar() {
if ( ! self::current_user_can_use_overlays( 'manage' ) ) {
return;
}
global $wp_admin_bar;
global $gb_overlays;
$title = __( 'Overlay Panels', 'generateblocks-pro' );
$count = ! empty( $gb_overlays ) ? count( $gb_overlays ) : 0;
// Prevent "Entire Site" Elements from being counted on non-edit pages in the admin.
if ( is_admin() && function_exists( 'get_current_screen' ) ) {
$screen = get_current_screen();
if ( ! isset( $screen->is_block_editor ) || ! $screen->is_block_editor ) {
$count = 0;
}
if ( 'edit' !== $screen->parent_base ) {
$count = 0;
}
}
if ( $count > 0 ) {
$title = sprintf(
/* translators: Active Element count. */
__( 'Overlay Panels (%s)', 'generateblocks-pro' ),
$count
);
}
$wp_admin_bar->add_menu(
array(
'id' => 'gb_overlays-menu',
'title' => $title,
'href' => esc_url( admin_url( 'edit.php?post_type=gblocks_overlay' ) ),
)
);
if ( ! empty( $gb_overlays ) ) {
// Prevent "Entire Site" Elements from being counted on non-edit pages in the admin.
if ( is_admin() && function_exists( 'get_current_screen' ) ) {
$screen = get_current_screen();
if ( ! isset( $screen->is_block_editor ) || ! $screen->is_block_editor ) {
return;
}
if ( 'edit' !== $screen->parent_base ) {
return;
}
}
foreach ( (array) $gb_overlays as $key => $data ) {
$wp_admin_bar->add_menu(
array(
'id' => 'template-' . absint( $data['id'] ),
'parent' => 'gb_overlays-menu',
'title' => get_the_title( $data['id'] ),
'href' => get_edit_post_link( $data['id'] ),
)
);
}
}
}
/**
* Add the Site Editor tab to our Dashboard tabs.
*
* @param array $tabs Existing tabs.
* @return array New tabs.
*/
public function dashboard_tab( $tabs ) {
$screen = get_current_screen();
$tabs['Overlay Panels'] = array(
'name' => __( 'Overlay Panels', 'generateblocks-pro' ),
'url' => admin_url( 'admin.php?page=generateblocks-overlay-panels' ),
'class' => 'generateblocks_page_generateblocks-overlay-panels' === $screen->id ? 'active' : '',
);
return $tabs;
}
/**
* Add the Site Editor tab to our Dashboard screens.
*
* @param array $screens Existing screens.
* @return array New screens.
*/
public function dashboard_screen( $screens ) {
$screens[] = 'generateblocks_page_generateblocks-overlay-panels';
return $screens;
}
/**
* Get all overlays.
*
* @return array
*/
public static function get_overlays() {
// Return empty array if overlays are disabled.
if ( ! generateblocks_pro_overlays_enabled() ) {
return array();
}
$overlays = get_posts(
array(
'post_type' => 'gblocks_overlay',
'posts_per_page' => 500, // phpcs:ignore -- Limit to 500 for performance.
'post_status' => 'publish',
)
);
if ( empty( $overlays ) ) {
return array();
}
return array_map(
function ( $overlay ) {
return array(
'title' => $overlay->post_title,
'id' => $overlay->ID,
'type' => get_post_meta( $overlay->ID, '_gb_overlay_type', true ),
);
},
$overlays
);
}
/**
* Save post callback for overlays.
*
* This is used to clear the dynamic CSS cache when a overlay is saved.
*
* @param int $post_id The post ID being saved.
*/
public function save_post( $post_id ) {
// If this is an autosave, do nothing.
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
// If this is not a overlay post type, do nothing.
if ( get_post_type( $post_id ) !== 'gblocks_overlay' ) {
return;
}
update_option( 'generateblocks_dynamic_css_posts', [] );
// Clear overlay cache when any overlay is saved.
generateblocks_pro_clear_overlay_cache();
}
/**
* Delete post callback for overlays.
*
* @param int $post_id The post ID being deleted.
*/
public function delete_post( $post_id ) {
if ( get_post_type( $post_id ) !== 'gblocks_overlay' ) {
return;
}
// Clear overlay cache when any overlay is deleted.
generateblocks_pro_clear_overlay_cache();
}
/**
* Transition post status callback for overlays.
*
* @param string $new_status New post status.
* @param string $old_status Old post status.
* @param WP_Post $post Post object.
*/
public function transition_post_status( $new_status, $old_status, $post ) {
if ( 'gblocks_overlay' !== $post->post_type ) {
return;
}
// Clear cache when overlay status changes.
if ( $new_status !== $old_status ) {
generateblocks_pro_clear_overlay_cache();
}
}
}
GenerateBlocks_Pro_Overlays::get_instance()->init();
@@ -0,0 +1,180 @@
<?php
/**
* Template partial for overlays.
*
* Variables available:
*
* @param string $overlay_content The content of the overlay.
* @param string $overlay_id The HTML ID attribute for the overlay.
* @param string $overlay_classes The classes for the overlay.
* @param string $overlay_type The type of overlay (standard or anchored).
* @param string $trigger_type The trigger type (click, hover, or both).
* @param string $placement The placement for anchored overlays (e.g., bottom-start).
* @param bool $backdrop Whether to show a backdrop for standard overlays.
* @param string $backdrop_color The backdrop color value.
* @param string $backdrop_blur The backdrop blur value in pixels.
* @param string $animation_in The animation class for overlay entrance.
* @param string $animation_out The animation class for overlay exit.
* @param string $animation_duration The animation duration.
* @param string $animation_target The animation target selector.
* @param string $animation_distance The animation distance.
* @param mixed $scroll_percent The scroll percentage trigger (false to disable).
* @param mixed $time_delay The time delay trigger (false to disable).
* @param mixed $cookie_duration The cookie duration (false to disable).
* @param bool $close_on_esc Whether to close on ESC key (standard overlays).
* @param bool $close_on_click_outside Whether to close on click outside (standard overlays).
* @param bool $disable_page_scroll Whether to disable page scroll when open (standard overlays).
* @param string $position The position for standard overlays.
* @param bool $hide_if_cookies_disabled Whether to hide overlay if cookies are disabled.
* @param string $position_to_parent The selector for positioning anchored overlays.
* @param string $width_mode The width mode for standard overlays ('' or 'full').
*
* @package generateblocks-pro
*/
// Early return if no content.
if ( empty( $overlay_content ) ) {
return;
}
// Setup variables.
$html_id = $overlay_id ? $overlay_id : wp_unique_id( 'gb-overlay-' );
// We want our mega menu overlays to be treated as anchored overlays.
if ( 'mega-menu' === $overlay_type ) {
$overlay_type = 'anchored';
}
$overlay_classes = 'gb-overlay gb-overlay--' . esc_attr( $overlay_type );
// Add position class for standard overlays.
if ( 'standard' === $overlay_type && ! empty( $position ) && 'center' !== $position ) {
$overlay_classes .= ' gb-overlay--' . esc_attr( $position );
}
// Add width mode class for all overlay types.
if ( ! empty( $width_mode ) && 'full' === $width_mode ) {
$overlay_classes .= ' gb-overlay--width-full';
}
// Build data attributes array.
$data_attributes = [
'data-gb-overlay' => '',
'data-gb-overlay-type' => $overlay_type,
'data-gb-overlay-trigger-type' => $trigger_type,
];
// Conditional data attributes.
if ( 'anchored' === $overlay_type && ! empty( $placement ) ) {
$data_attributes['data-gb-overlay-placement'] = $placement;
}
// Position to parent for anchored overlays.
if ( 'anchored' === $overlay_type && ! empty( $position_to_parent ) ) {
$data_attributes['data-gb-overlay-position-to-parent'] = $position_to_parent;
}
// Standard overlay specific attributes.
if ( 'standard' === $overlay_type ) {
// Handle boolean attributes - only add if false (true is default).
if ( false === $close_on_esc ) {
$data_attributes['data-gb-overlay-close-on-esc'] = 'false';
}
if ( false === $close_on_click_outside ) {
$data_attributes['data-gb-overlay-close-on-click-outside'] = 'false';
}
if ( true === $disable_page_scroll ) {
$data_attributes['data-gb-overlay-disable-page-scroll'] = 'true';
}
if ( ! empty( $position ) && 'center' !== $position ) {
$data_attributes['data-gb-overlay-position'] = $position;
}
if ( true === $hide_if_cookies_disabled ) {
$data_attributes['data-gb-overlay-hide-if-cookies-disabled'] = 'true';
}
}
$optional_data_attrs = [
'animation_in' => 'data-gb-overlay-animation-in',
'animation_out' => 'data-gb-overlay-animation-out',
'animation_duration' => 'data-gb-overlay-animation-duration',
'animation_target' => 'data-gb-overlay-animation-target',
'animation_distance' => 'data-gb-overlay-animation-distance',
'hover_buffer' => 'data-gb-overlay-hover-buffer',
];
foreach ( $optional_data_attrs as $var => $attr ) {
if ( ! empty( $$var ) ) {
$data_attributes[ $attr ] = $$var;
}
}
// Handle special case attributes.
if ( 'scroll' === $trigger_type && false !== $scroll_percent && null !== $scroll_percent ) {
$data_attributes['data-gb-overlay-scroll-percent'] = $scroll_percent;
}
if ( 'time' === $trigger_type && false !== $time_delay && null !== $time_delay ) {
$data_attributes['data-gb-overlay-time-delay'] = $time_delay;
}
if ( 'custom' === $trigger_type && ! empty( $custom_event ) ) {
$data_attributes['data-gb-overlay-custom-event'] = $custom_event;
}
if ( 'exit-intent' === $trigger_type || 'time' === $trigger_type || 'scroll' === $trigger_type || 'custom' === $trigger_type ) {
if ( false !== $cookie_duration && null !== $cookie_duration ) {
$data_attributes['data-gb-overlay-cookie-duration'] = $cookie_duration;
}
}
// Build attributes string.
$attributes = [];
foreach ( $data_attributes as $key => $value ) {
if ( '' === $value ) {
$attributes[] = $key;
} else {
$attributes[] = sprintf( '%s="%s"', $key, esc_attr( $value ) );
}
}
// Add ARIA attributes.
$attributes[] = 'role="dialog"';
$attributes[] = 'aria-modal="true"';
$attributes[] = 'aria-hidden="true"';
$attributes_string = implode( ' ', $attributes );
?>
<div
id="<?php echo esc_attr( $html_id ); ?>"
class="<?php echo esc_attr( $overlay_classes ); ?>"
<?php echo $attributes_string; // phpcs:ignore ?>
>
<?php if ( 'standard' === $overlay_type && $backdrop ) : ?>
<?php
$backdrop_styles = [];
if ( ! empty( $backdrop_color ) ) {
$backdrop_styles[] = 'background-color: ' . esc_attr( $backdrop_color );
}
if ( ! empty( $backdrop_blur ) ) {
// Convert to numeric value and add 'px' if not already present.
$blur_value = is_numeric( $backdrop_blur ) ? $backdrop_blur . 'px' : $backdrop_blur;
$backdrop_styles[] = 'backdrop-filter: blur(' . esc_attr( $blur_value ) . ');-webkit-backdrop-filter: blur(' . esc_attr( $blur_value ) . ');';
}
$backdrop_style_string = ! empty( $backdrop_styles ) ? ' style="' . implode( '; ', $backdrop_styles ) . '"' : '';
?>
<div class="gb-overlay__backdrop"<?php echo $backdrop_style_string; // phpcs:ignore ?>></div>
<?php endif; ?>
<div class="gb-overlay__content">
<?php echo $overlay_content; // phpcs:ignore ?>
</div>
</div>
@@ -0,0 +1,111 @@
<?php
/**
* The main site editor module file.
*
* @package GeneratePress Pro
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
$overlays_dir = plugin_dir_path( __FILE__ );
require_once $overlays_dir . 'class-overlays.php';
require_once $overlays_dir . 'class-overlay.php';
require_once $overlays_dir . 'class-overlay-post-type.php';
require_once $overlays_dir . 'class-overlay-iframe-context.php';
require_once $overlays_dir . 'class-overlay-rest.php';
/**
* Get our templates.
*
* @param array $custom_args Custom arguments for the query.
*/
function generateblocks_pro_get_overlays( $custom_args = [] ) {
// Return empty array if overlays are disabled.
if ( ! generateblocks_pro_overlays_enabled() ) {
return array();
}
$args = array(
'post_type' => 'gblocks_overlay',
'no_found_rows' => true,
'post_status' => 'publish',
'numberposts' => 500, // phpcs:ignore
'fields' => 'ids',
'suppress_filters' => false,
'order' => 'ASC',
);
$args = array_merge( $args, $custom_args );
// Prevent Polylang from altering the query.
if ( function_exists( 'pll_get_post_language' ) ) {
$args['lang'] = '';
}
$posts = get_posts( $args );
return $posts;
}
/**
* Clear all overlay transient caches.
*
* @since 1.0.0
*/
function generateblocks_pro_clear_overlay_cache() {
delete_option( 'generateblocks_active_overlays' );
}
add_action( 'wp', 'generateblocks_pro_do_overlays' );
/**
* Execute our Overlay Panels.
*
* @since 2.3.0
*/
function generateblocks_pro_do_overlays() {
// Don't execute overlays if the feature is disabled.
if ( ! generateblocks_pro_overlays_enabled() ) {
return;
}
$cached_overlays = get_option( 'generateblocks_active_overlays', false );
if ( false !== $cached_overlays ) {
$posts = $cached_overlays;
} else {
$posts = generateblocks_pro_get_overlays();
update_option( 'generateblocks_active_overlays', $posts );
}
$instance = GenerateBlocks_Pro_Overlay::get_instance();
foreach ( $posts as $post_id ) {
$post_id = apply_filters( 'generateblocks_overlay_post_id', $post_id );
$instance->add_overlay( $post_id );
}
// Get all of the active templates.
$instance->init();
}
add_filter( 'generateblocks_overlay_panel', 'generateblocks_pro_overlay_content_filters' );
/**
* Apply content filters to our overlay panels.
*
* @since 2.3.0
* @param string $content The overlay panel content.
*/
function generateblocks_pro_overlay_content_filters( $content ) {
$content = shortcode_unautop( $content );
$content = do_shortcode( $content );
if ( function_exists( 'wp_filter_content_tags' ) ) {
$content = wp_filter_content_tags( $content );
} elseif ( function_exists( 'wp_make_content_images_responsive' ) ) {
$content = wp_make_content_images_responsive( $content );
}
return $content;
}