'eppro_form_nonce',
'search' => 'eppro_live_search',
'post_grid' => 'eppro_post_grid',
'popup_view' => 'eppro_popup_view',
'woo_products' => 'eppro_woo_products',
];
// phpcs:ignore WordPress.Security.NonceVerification.Missing -- This endpoint issues nonces and performs no action.
$kind = isset( $_POST['kind'] ) ? sanitize_key( wp_unslash( $_POST['kind'] ) ) : '';
if ( ! isset( $actions[ $kind ] ) ) {
wp_send_json_error( [], 400 );
}
nocache_headers();
wp_send_json_success( [ 'nonce' => wp_create_nonce( $actions[ $kind ] ) ] );
}
/**
* One badge style for the whole Elementor panel: the "EPP" mark on the
* plugin's widget tiles and on every control section the plugin adds
* (see EPPRO_Elementor_Helper::panel_label()).
*/
public static function enqueue_editor_badge(): void {
$css = '
.eppro-panel-badge,
#elementor-panel-category-eppro-elements .elementor-element-wrapper::after {
display: inline-block;
background: linear-gradient(135deg, #7c3aed, #6d28d9);
color: #fff;
font-size: 9px;
font-weight: 700;
line-height: 1.4;
letter-spacing: .5px;
padding: 1px 6px;
border-radius: 20px;
vertical-align: middle;
box-shadow: 0 1px 4px rgba(124, 58, 237, .35);
}
.eppro-panel-badge { margin-inline-start: 4px; }
#elementor-panel-category-eppro-elements .elementor-element-wrapper {
position: relative;
overflow: visible !important;
}
#elementor-panel-category-eppro-elements .elementor-element-wrapper::after {
content: "EPP";
position: absolute;
top: 5px;
inset-inline-end: 5px;
pointer-events: none;
z-index: 1;
}
';
wp_add_inline_style( 'elementor-editor', $css );
}
// -------------------------------------------------------------------------
// Register — called early so handles exist before Elementor renders
// -------------------------------------------------------------------------
public static function register_all(): void {
static $done = false;
if ( $done ) return;
$done = true;
/* ── Swiper: bundled local copy (assets/vendor/swiper/) ──────────────
* No CDN fallback — WordPress.org plugin guidelines prohibit loading
* scripts from external CDNs without explicit user consent.
* Files: swiper-bundle.min.css and swiper-bundle.min.js
* Source: https://swiperjs.com (MIT licence, GPL-compatible)
* ─────────────────────────────────────────────────────────────────── */
if ( ! wp_style_is( 'swiper', 'registered' ) ) {
$local_css_path = EPPRO_PATH . 'assets/vendor/swiper/swiper-bundle.min.css';
if ( file_exists( $local_css_path ) ) {
wp_register_style( 'swiper', EPPRO_URL . 'assets/vendor/swiper/swiper-bundle.min.css', [], '11.1' );
} else {
add_action( 'admin_notices', static function () {
echo '
Essential Pro Pack: ' .
esc_html__( 'Missing vendor file: assets/vendor/swiper/swiper-bundle.min.css. Carousel widgets may not display correctly. Please reinstall the plugin.', 'admore-widgets-suite' ) .
'
';
} );
wp_register_style( 'swiper', false, [], '11.1' );
}
}
if ( ! wp_script_is( 'swiper', 'registered' ) ) {
$local_js_path = EPPRO_PATH . 'assets/vendor/swiper/swiper-bundle.min.js';
if ( file_exists( $local_js_path ) ) {
wp_register_script( 'swiper', EPPRO_URL . 'assets/vendor/swiper/swiper-bundle.min.js', [], '11.1', true );
} else {
add_action( 'admin_notices', static function () {
echo 'Essential Pro Pack: ' .
esc_html__( 'Missing vendor file: assets/vendor/swiper/swiper-bundle.min.js. Carousel widgets will not function. Please reinstall the plugin.', 'admore-widgets-suite' ) .
'
';
} );
wp_register_script( 'swiper', false, [], '11.1', true );
}
}
/* ── Global shared (always loaded on any EPP page) ── */
wp_register_style(
'eppro-global',
EPPRO_URL . 'assets/css/frontend.css',
[],
eppro_asset_ver( 'assets/css/frontend.css' )
);
wp_register_script(
'eppro-main-script',
EPPRO_URL . 'assets/js/frontend.js',
[ 'jquery' ],
eppro_asset_ver( 'assets/js/frontend.js' ),
true
);
// Localise at registration so EPPRO is available wherever the script is printed.
self::localize_script();
/* ── Per-widget CSS ── */
self::register_widget_style( 'eppro-btn', 'widgets/advanced-button/assets/css/style.css' );
self::register_widget_style( 'eppro-adv-faq', 'widgets/advanced-faq/assets/css/style.css' );
self::register_widget_style( 'eppro-form', 'widgets/form/assets/css/style.css' );
self::register_widget_style( 'eppro-mega-menu', 'widgets/mega-menu/assets/css/style.css' );
self::register_widget_style( 'eppro-advanced-slider', 'widgets/advanced-slider/assets/css/style.css', [ 'swiper' ] );
self::register_widget_style( 'eppro-advanced-search', 'widgets/advanced-search/assets/css/style.css' );
self::register_widget_style( 'eppro-breadcrumbs', 'widgets/breadcrumbs/assets/css/style.css' );
self::register_widget_style( 'eppro-advanced-tabs', 'widgets/advanced-tabs/assets/css/style.css' );
self::register_widget_style( 'eppro-pricing-table', 'widgets/pricing-table/assets/css/style.css' );
self::register_widget_style( 'eppro-gallery-pro', 'widgets/gallery-pro/assets/css/style.css' );
self::register_widget_style( 'eppro-post-grid', 'widgets/post-grid/assets/css/style.css' );
self::register_widget_style( 'eppro-off-canvas', 'widgets/off-canvas/assets/css/style.css' );
self::register_widget_style( 'eppro-stats-counter', 'widgets/stats-counter/assets/css/style.css' );
self::register_widget_style( 'eppro-before-after', 'widgets/before-after/assets/css/style.css' );
self::register_widget_style( 'eppro-logo-grid', 'widgets/logo-grid/assets/css/style.css', [ 'swiper' ] );
self::register_widget_style( 'eppro-team-member', 'widgets/team-member/assets/css/style.css' );
self::register_widget_style( 'eppro-icon-box', 'widgets/icon-box/style.css' );
self::register_widget_style( 'eppro-image-box', 'widgets/image-box/style.css' );
self::register_widget_style( 'eppro-timeline', 'widgets/timeline/style.css' );
/* ── New widget styles ── */
self::register_widget_style( 'eppro-fancy-heading', 'widgets/fancy-heading/style.css' );
self::register_widget_style( 'eppro-image-carousel', 'widgets/image-carousel/style.css', [ 'swiper' ] );
self::register_widget_style( 'eppro-lottie', 'widgets/lottie/style.css' );
self::register_widget_style( 'eppro-pie-chart', 'widgets/pie-chart/style.css' );
self::register_widget_style( 'eppro-author-box', 'widgets/author-box/style.css' );
self::register_widget_style( 'eppro-related-posts', 'widgets/related-posts/style.css' );
self::register_widget_style( 'eppro-google-map', 'widgets/google-map/style.css' );
self::register_widget_style( 'eppro-woo-products', 'widgets/woo-products/style.css' );
self::register_widget_style( 'eppro-woo-mini-cart', 'widgets/woo-mini-cart/style.css' );
self::register_widget_style( 'eppro-woo-add-to-cart', 'widgets/woo-add-to-cart/style.css' );
self::register_widget_style( 'eppro-post-comments', 'widgets/post-comments/style.css' );
self::register_widget_style( 'eppro-site-logo', 'widgets/site-logo/style.css' );
self::register_widget_style( 'eppro-nav-menu', 'widgets/nav-menu/style.css' );
self::register_widget_style( 'eppro-site-title', 'widgets/site-title/style.css' );
self::register_widget_style( 'eppro-site-tagline', 'widgets/site-tagline/style.css' );
self::register_widget_style( 'eppro-post-title', 'widgets/post-title/style.css' );
self::register_widget_style( 'eppro-post-content', 'widgets/post-content/style.css' );
self::register_widget_style( 'eppro-post-featured-image', 'widgets/post-featured-image/style.css' );
self::register_widget_style( 'eppro-post-excerpt', 'widgets/post-excerpt/style.css' );
self::register_widget_style( 'eppro-post-meta', 'widgets/post-meta/style.css' );
self::register_widget_style( 'eppro-archive-title', 'widgets/archive-title/style.css' );
self::register_widget_style( 'eppro-archive-description', 'widgets/archive-description/style.css' );
self::register_widget_style( 'eppro-post-navigation', 'widgets/post-navigation/style.css' );
/* ── Previously unregistered widget styles ── */
self::register_widget_style( 'eppro-animated-heading', 'widgets/animated-heading/assets/css/style.css' );
self::register_widget_style( 'eppro-countdown-timer', 'widgets/countdown-timer/assets/css/style.css' );
self::register_widget_style( 'eppro-flip-box', 'widgets/flip-box/style.css' );
self::register_widget_style( 'eppro-hotspot', 'widgets/hotspot/style.css' );
self::register_widget_style( 'eppro-price-list', 'widgets/price-list/style.css' );
self::register_widget_style( 'eppro-progress-bar', 'widgets/progress-bar/style.css' );
self::register_widget_style( 'eppro-social-icons', 'widgets/social-icons/style.css' );
self::register_widget_style( 'eppro-testimonial', 'widgets/testimonial/assets/css/style.css', [ 'swiper' ] );
self::register_widget_style( 'eppro-video', 'widgets/video/style.css' );
/* ── Per-widget JS (loaded on-demand via get_script_depends) ── */
wp_register_script(
'eppro-form-script',
EPPRO_URL . 'widgets/form/assets/js/form.js',
[ 'jquery', 'eppro-main-script' ],
eppro_asset_ver( 'widgets/form/assets/js/form.js' ),
true
);
wp_register_script(
'eppro-mega-menu-script',
EPPRO_URL . 'widgets/mega-menu/assets/js/mega-menu.js',
[ 'jquery', 'eppro-main-script' ],
eppro_asset_ver( 'widgets/mega-menu/assets/js/mega-menu.js' ),
true
);
wp_register_script(
'eppro-faq-script',
EPPRO_URL . 'widgets/advanced-faq/assets/js/faq.js',
[ 'jquery', 'eppro-main-script' ],
eppro_asset_ver( 'widgets/advanced-faq/assets/js/faq.js' ),
true
);
wp_register_script(
'eppro-extensions',
EPPRO_URL . 'assets/js/extensions.js',
[ 'jquery', 'eppro-main-script' ],
eppro_asset_ver( 'assets/js/extensions.js' ),
true
);
wp_register_script(
'eppro-advanced-slider-script',
EPPRO_URL . 'widgets/advanced-slider/assets/js/slider.js',
[ 'jquery', 'swiper', 'eppro-main-script' ],
eppro_asset_ver( 'widgets/advanced-slider/assets/js/slider.js' ),
true
);
wp_register_script(
'eppro-advanced-search-script',
EPPRO_URL . 'widgets/advanced-search/assets/js/search.js',
[ 'jquery', 'eppro-main-script' ],
eppro_asset_ver( 'widgets/advanced-search/assets/js/search.js' ),
true
);
wp_register_script(
'eppro-advanced-tabs',
EPPRO_URL . 'widgets/advanced-tabs/assets/js/tabs.js',
[ 'jquery', 'eppro-main-script' ],
eppro_asset_ver( 'widgets/advanced-tabs/assets/js/tabs.js' ),
true
);
wp_register_script(
'eppro-pricing-table-script',
EPPRO_URL . 'widgets/pricing-table/assets/js/pricing.js',
[ 'jquery', 'eppro-main-script' ],
eppro_asset_ver( 'widgets/pricing-table/assets/js/pricing.js' ),
true
);
wp_register_script(
'eppro-gallery-pro-script',
EPPRO_URL . 'widgets/gallery-pro/assets/js/gallery.js',
[ 'jquery', 'eppro-main-script' ],
eppro_asset_ver( 'widgets/gallery-pro/assets/js/gallery.js' ),
true
);
wp_register_script(
'eppro-post-grid-script',
EPPRO_URL . 'widgets/post-grid/assets/js/post-grid.js',
[ 'jquery', 'eppro-main-script' ],
eppro_asset_ver( 'widgets/post-grid/assets/js/post-grid.js' ),
true
);
wp_register_script(
'eppro-off-canvas',
EPPRO_URL . 'widgets/off-canvas/assets/js/script.js',
[ 'jquery', 'eppro-main-script' ],
eppro_asset_ver( 'widgets/off-canvas/assets/js/script.js' ),
true
);
wp_register_script(
'eppro-stats-counter',
EPPRO_URL . 'widgets/stats-counter/assets/js/script.js',
[ 'jquery', 'eppro-main-script' ],
eppro_asset_ver( 'widgets/stats-counter/assets/js/script.js' ),
true
);
wp_register_script(
'eppro-before-after',
EPPRO_URL . 'widgets/before-after/assets/js/script.js',
[ 'jquery', 'eppro-main-script' ],
eppro_asset_ver( 'widgets/before-after/assets/js/script.js' ),
true
);
wp_register_script(
'eppro-logo-grid',
EPPRO_URL . 'widgets/logo-grid/assets/js/script.js',
[ 'jquery', 'swiper', 'eppro-main-script' ],
eppro_asset_ver( 'widgets/logo-grid/assets/js/script.js' ),
true
);
wp_register_script(
'eppro-timeline-script',
EPPRO_URL . 'widgets/timeline/script.js',
[],
eppro_asset_ver( 'widgets/timeline/script.js' ),
true
);
/* ── New widget scripts ── */
wp_register_script( 'eppro-image-carousel-script', EPPRO_URL . 'widgets/image-carousel/script.js', [ 'swiper' ], eppro_asset_ver( 'widgets/image-carousel/script.js' ), true );
// lottie-web: MIT licensed, bundled locally (see assets/vendor/lottie/README.txt)
wp_register_script( 'lottie-web', EPPRO_URL . 'assets/vendor/lottie/lottie.min.js', [], '5.12.2', true );
wp_register_script( 'eppro-lottie-script', EPPRO_URL . 'widgets/lottie/script.js', [ 'lottie-web' ], eppro_asset_ver( 'widgets/lottie/script.js' ), true );
wp_register_script( 'eppro-pie-chart-script', EPPRO_URL . 'widgets/pie-chart/script.js', [], eppro_asset_ver( 'widgets/pie-chart/script.js' ), true );
wp_register_script( 'eppro-woo-mini-cart-script', EPPRO_URL . 'widgets/woo-mini-cart/script.js', [ 'jquery' ], eppro_asset_ver( 'widgets/woo-mini-cart/script.js' ), true );
wp_register_script( 'eppro-nav-menu-script', EPPRO_URL . 'widgets/nav-menu/script.js', [ 'jquery' ], eppro_asset_ver( 'widgets/nav-menu/script.js' ), true );
wp_register_script( 'eppro-team-member-script', EPPRO_URL . 'widgets/team-member/assets/js/script.js', [], eppro_asset_ver( 'widgets/team-member/assets/js/script.js' ), true );
wp_register_script( 'eppro-woo-products-script', EPPRO_URL . 'widgets/woo-products/script.js', [ 'jquery', 'eppro-main-script' ], eppro_asset_ver( 'widgets/woo-products/script.js' ), true );
wp_localize_script( 'eppro-woo-products-script', 'epproWooProducts', [
'close' => __( 'Close', 'admore-widgets-suite' ),
'loading' => __( 'Loading…', 'admore-widgets-suite' ),
'error' => __( 'Sorry, this product could not be loaded.', 'admore-widgets-suite' ),
] );
/* ── Previously unregistered widget scripts ── */
wp_register_script( 'eppro-animated-heading-script', EPPRO_URL . 'widgets/animated-heading/assets/js/animated-heading.js', [], eppro_asset_ver( 'widgets/animated-heading/assets/js/animated-heading.js' ), true );
wp_register_script( 'eppro-countdown-timer-script', EPPRO_URL . 'widgets/countdown-timer/assets/js/countdown.js', [], eppro_asset_ver( 'widgets/countdown-timer/assets/js/countdown.js' ), true );
wp_register_script( 'eppro-progress-bar-script', EPPRO_URL . 'widgets/progress-bar/script.js', [], eppro_asset_ver( 'widgets/progress-bar/script.js' ), true );
wp_register_script( 'eppro-testimonial-script', EPPRO_URL . 'widgets/testimonial/assets/js/testimonial.js', [ 'jquery', 'swiper' ], eppro_asset_ver( 'widgets/testimonial/assets/js/testimonial.js' ), true );
wp_register_script( 'eppro-hotspot-script', EPPRO_URL . 'widgets/hotspot/script.js', [ 'jquery' ], eppro_asset_ver( 'widgets/hotspot/script.js' ), true );
wp_register_script( 'eppro-video-script', EPPRO_URL . 'widgets/video/script.js', [ 'jquery' ], eppro_asset_ver( 'widgets/video/script.js' ), true );
// Defer scroll-triggered / visual-enhancement scripts (WP 6.3+ strategy API).
// These are purely progressive-enhancement — deferring them frees the main
// thread earlier without any visible impact.
$defer_scripts = [
'eppro-stats-counter',
'eppro-pie-chart-script',
'eppro-lottie-script',
'eppro-timeline-script',
'eppro-team-member-script',
];
foreach ( $defer_scripts as $handle ) {
wp_script_add_data( $handle, 'strategy', 'defer' );
}
}
// -------------------------------------------------------------------------
// Enqueue global assets (only on pages where Elementor frontend renders)
// -------------------------------------------------------------------------
public static function enqueue_global(): void {
static $done = false;
if ( $done ) return;
$done = true;
self::register_all();
wp_enqueue_style( 'eppro-global' );
wp_enqueue_script( 'eppro-main-script' );
wp_enqueue_script( 'eppro-extensions' );
self::add_customizer_inline_css();
}
// -------------------------------------------------------------------------
// Helpers
// -------------------------------------------------------------------------
private static function register_widget_style( string $handle, string $relative_path, array $deps = [] ): void {
$full_deps = array_merge( [ 'eppro-global' ], $deps );
wp_register_style( $handle, EPPRO_URL . $relative_path, $full_deps, eppro_asset_ver( $relative_path ) );
}
/**
* Public data for the frontend. Never add plugin settings here: this is
* printed on every page, and the settings contain the CAPTCHA secret key.
*/
private static function localize_script(): void {
wp_localize_script( 'eppro-main-script', 'EPPRO', [
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'homeUrl' => trailingslashit( home_url() ),
] );
}
private static function add_customizer_inline_css(): void {
$custom = class_exists( 'EPPRO_Customizer' ) ? EPPRO_Customizer::get_settings() : [];
if ( empty( $custom ) ) return;
$css = ':root{';
$map = [
'input_bg' => '--eppro-input-bg',
'input_color' => '--eppro-input-color',
'btn_bg' => '--eppro-btn-bg',
'btn_color' => '--eppro-btn-color',
'card_bg' => '--eppro-card-bg',
];
foreach ( $map as $key => $var ) {
if ( ! empty( $custom[ $key ] ) ) {
$css .= $var . ':' . esc_attr( $custom[ $key ] ) . ';';
}
}
if ( ! empty( $custom['radius'] ) ) {
$css .= '--eppro-radius:' . intval( $custom['radius'] ) . 'px;';
}
$css .= '}';
wp_add_inline_style( 'eppro-global', wp_strip_all_tags( $css ) );
}
}