JezK
Edit File: Ajax_Handler.php
<?php /** * Class trait Ajax_Handler file * * @package Essential-addons-for-elementor-lite\Traits */ namespace Essential_Addons_Elementor\Traits; use Essential_Addons_Elementor\Classes\AllTraits; use Essential_Addons_Elementor\Classes\Elements_Manager; use Essential_Addons_Elementor\Classes\Helper as HelperClass; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } /** * Essential Addons ajax request handler * * Manage all ajax request for EA * * @class Ajax_Handler * @since 5.0.9 * @package Essential-addons-for-elementor-lite\Traits */ trait Ajax_Handler { //use Template_Query; /** * init_ajax_hooks */ public function init_ajax_hooks() { add_action( 'wp_ajax_load_more', array( $this, 'ajax_load_more' ) ); add_action( 'wp_ajax_nopriv_load_more', array( $this, 'ajax_load_more' ) ); add_action( 'wp_ajax_woo_product_pagination_product', array( $this, 'eael_woo_pagination_product_ajax' ) ); add_action( 'wp_ajax_nopriv_woo_product_pagination_product', array( $this, 'eael_woo_pagination_product_ajax' ) ); add_action( 'wp_ajax_woo_product_pagination', array( $this, 'eael_woo_pagination_ajax' ) ); add_action( 'wp_ajax_nopriv_woo_product_pagination', array( $this, 'eael_woo_pagination_ajax' ) ); add_action( 'wp_ajax_eael_product_add_to_cart', array( $this, 'eael_product_add_to_cart' ) ); add_action( 'wp_ajax_nopriv_eael_product_add_to_cart', array( $this, 'eael_product_add_to_cart' ) ); add_action( 'wp_ajax_eael_ajax_add_to_cart', [ $this, 'eael_ajax_add_to_cart' ] ); add_action( 'wp_ajax_nopriv_eael_ajax_add_to_cart', [ $this, 'eael_ajax_add_to_cart' ] ); add_action( 'wp_ajax_woo_checkout_update_order_review', [ $this, 'woo_checkout_update_order_review' ] ); add_action( 'wp_ajax_nopriv_woo_checkout_update_order_review', [ $this, 'woo_checkout_update_order_review' ] ); add_action( 'wp_ajax_nopriv_eael_product_quickview_popup', [ $this, 'eael_product_quickview_popup' ] ); add_action( 'wp_ajax_eael_product_quickview_popup', [ $this, 'eael_product_quickview_popup' ] ); add_action( 'wp_ajax_nopriv_eael_product_gallery', [ $this, 'ajax_eael_product_gallery' ] ); add_action( 'wp_ajax_eael_product_gallery', [ $this, 'ajax_eael_product_gallery' ] ); add_action( 'wp_ajax_eael_select2_search_post', [ $this, 'select2_ajax_posts_filter_autocomplete' ] ); add_action( 'wp_ajax_eael_select2_get_title', [ $this, 'select2_ajax_get_posts_value_titles' ] ); if ( is_admin() ) { add_action( 'wp_ajax_eael_save_settings_with_ajax', array( $this, 'save_settings' ) ); add_action( 'wp_ajax_eael_clear_cache_files_with_ajax', array( $this, 'clear_cache_files' ) ); add_action( 'wp_ajax_eael_admin_promotion', array( $this, 'eael_admin_promotion' ) ); } add_action( 'wp_ajax_eael_get_token', [ $this, 'eael_get_token' ] ); add_action( 'wp_ajax_nopriv_eael_get_token', [ $this, 'eael_get_token' ] ); add_action( 'eael_before_woo_pagination_product_ajax_start', [ $this, 'eael_yith_wcwl_ajax_disable' ] ); add_action( 'eael_before_ajax_load_more', [ $this, 'eael_yith_wcwl_ajax_disable' ] ); } /** * Ajax Load More * This function is responsible for get the post data. * It will return HTML markup with AJAX call and with normal call. * * @access public * @return false|void of a html markup with AJAX call. * @return array of content and found posts count without AJAX call. * @since 3.1.0 */ public function ajax_load_more() { $ajax = wp_doing_ajax(); //phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended do_action( 'eael_before_ajax_load_more', $_REQUEST ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.NonceVerification.Missing wp_parse_str( $_POST['args'], $args ); // $args comes from the client; coerce ID-list query vars (author__not_in, post__in, …) // to int arrays before they reach WP_Query, else a string payload injects raw SQL. $args = $this->eael_sanitize_query_args( $args ); // NOTE: $args comes from client ($_POST['args']); strip visibility-widening keys (e.g., post_status, perm) to prevent nopriv access to non-public content. unset( $args['post_status'], $args['perm'], $args['suppress_filters'] ); $args['post_status'] = 'publish'; if ( isset( $args['post__in'] ) ) { // Cap to a sane bound to prevent abuse. $args['post__in'] = array_slice( $args['post__in'], 0, 1000 ); } if ( isset( $args['post__not_in'] ) ) { $args['post__not_in'] = array_slice( $args['post__not_in'], 0, 1000 ); } if ( isset( $args['date_query']['relation'] ) ) { $args['date_query']['relation'] = HelperClass::eael_sanitize_relation( $args['date_query']['relation'] ); } if ( empty( $_POST['nonce'] ) ) { $err_msg = __( 'Insecure form submitted without security token', 'essential-addons-for-elementor-lite' ); if ( $ajax ) { wp_send_json_error( $err_msg ); } return false; } if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'load_more' ) && ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'essential-addons-elementor' ) ) { $err_msg = __( 'Security token did not match', 'essential-addons-for-elementor-lite' ); if ( $ajax ) { wp_send_json_error( $err_msg ); } return false; } if ( ! empty( $_POST['page_id'] ) ) { $page_id = intval( $_POST['page_id'], 10 ); } else { $err_msg = __( 'Page ID is missing', 'essential-addons-for-elementor-lite' ); if ( $ajax ) { wp_send_json_error( $err_msg ); } return false; } if ( ! empty( $_POST['widget_id'] ) ) { $widget_id = sanitize_text_field( wp_unslash( $_POST['widget_id'] ) ); } else { $err_msg = __( 'Widget ID is missing', 'essential-addons-for-elementor-lite' ); if ( $ajax ) { wp_send_json_error( $err_msg ); } return false; } $settings = HelperClass::eael_get_widget_settings( $page_id, $widget_id ); if ( empty( $settings ) ) { wp_send_json_error( [ 'message' => __( 'Widget settings are not found. Did you save the widget before using load more??', 'essential-addons-for-elementor-lite' ) ] ); } $settings['eael_widget_id'] = $widget_id; $settings['eael_page_id'] = $page_id; $html = ''; $class = !empty( $_REQUEST['class'] ) ? '\\' . str_replace( '\\\\', '\\', sanitize_text_field( wp_unslash( $_REQUEST['class'] ) ) ) : ''; $page = !empty( $_REQUEST['page'] ) ? absint( $_REQUEST['page'] ) : 1; $args['offset'] = (int) $args['offset'] + ( ( (int) $page - 1 ) * (int) $args['posts_per_page'] ); if ( isset( $_REQUEST['taxonomy'] ) && isset( $_REQUEST['taxonomy']['taxonomy'] ) && $_REQUEST['taxonomy']['taxonomy'] != 'all' ) { $args['tax_query'] = [ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated $this->sanitize_taxonomy_data( $_REQUEST['taxonomy'] ), ]; $relation = isset( $settings['relation_cats_tags'] ) ? $settings['relation_cats_tags'] : 'OR'; $args['tax_query'] = $this->eael_terms_query_multiple( $args['tax_query'], $relation ); } if ( $class == '\Essential_Addons_Elementor\Elements\Post_Grid' ) { $eael_lang_suffix = HelperClass::eael_lang_suffix( $page_id ); $settings['read_more_button_text'] = get_transient( 'eael_post_grid_read_more_button_text_' . $widget_id . $eael_lang_suffix ); $settings['excerpt_expanison_indicator'] = get_transient( 'eael_post_grid_excerpt_expanison_indicator_' . $widget_id . $eael_lang_suffix ); if ( $settings['orderby'] === 'rand' && ! empty( $_REQUEST['post__not_in'] ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $post__not_in = $_REQUEST['post__not_in']; if ( ! empty( $args['post__not_in'] ) ) { $post__not_in = array_merge( $post__not_in, $args['post__not_in'] ); } $args['post__not_in'] = array_map( 'intval', array_unique( $post__not_in ) ); unset( $args['offset'] ); } } if ( $class === '\Essential_Addons_Elementor\Elements\Product_Grid' ) { do_action( 'eael_woo_before_product_loop', $settings['eael_product_grid_style_preset'] ); } if ( $class === '\Essential_Addons_Elementor\Elements\Woo_Product_List' ) { do_action( 'eael/woo-product-list/before-product-loop' ); } // ensure control name compatibility to old code if it is post block if ( $class === '\Essential_Addons_Elementor\Pro\Elements\Post_Block' ) { $settings ['post_block_hover_animation'] = $settings['eael_post_block_hover_animation']; $settings ['show_read_more_button'] = $settings['eael_show_read_more_button']; $settings ['eael_post_block_bg_hover_icon'] = ( isset( $settings['__fa4_migrated']['eael_post_block_bg_hover_icon_new'] ) || empty( $settings['eael_post_block_bg_hover_icon'] ) ) ? $settings['eael_post_block_bg_hover_icon_new']['value'] : $settings['eael_post_block_bg_hover_icon']; $settings ['expanison_indicator'] = $settings['excerpt_expanison_indicator']; } if ( $class === '\Essential_Addons_Elementor\Elements\Post_Timeline' ) { $settings ['expanison_indicator'] = $settings['excerpt_expanison_indicator']; } if ( $class === '\Essential_Addons_Elementor\Pro\Elements\Dynamic_Filterable_Gallery' ) { $settings['eael_section_fg_zoom_icon'] = ( isset( $settings['__fa4_migrated']['eael_section_fg_zoom_icon_new'] ) || empty( $settings['eael_section_fg_zoom_icon'] ) ? $settings['eael_section_fg_zoom_icon_new']['value'] : $settings['eael_section_fg_zoom_icon'] ); $settings['eael_section_fg_link_icon'] = ( isset( $settings['__fa4_migrated']['eael_section_fg_link_icon_new'] ) || empty( $settings['eael_section_fg_link_icon'] ) ? $settings['eael_section_fg_link_icon_new']['value'] : $settings['eael_section_fg_link_icon'] ); $settings['show_load_more_text'] = $settings['eael_fg_loadmore_btn_text']; $settings['layout_mode'] = isset( $settings['layout_mode'] ) ? $settings['layout_mode'] : 'masonry'; // NOTE: Use server-trusted whitelists; ACF gallery needs broader post_status/type for attachments (inherit), but never 'any'—it would expose private/draft posts to unauthenticated users. //NOTE: The inherit status is intentionally allowed to ensure access to attachments, since the same attachment may be associated with both private and public pages. $dfg_safe_post_status = [ 'publish', 'inherit' ]; $dfg_safe_post_types = [ 'attachment' ]; if ( ! empty( $settings['post_type'] ) && is_string( $settings['post_type'] ) ) { if ( 'by_id' === $settings['post_type'] ) { // NOTE: Manual selection allows all public post types (to include ACF gallery parents) but excludes internal types (e.g., revision, oembed_cache, nav_menu_item) that 'any' would expose. $dfg_safe_post_types = array_values( array_unique( array_merge( $dfg_safe_post_types, (array) get_post_types( [ 'public' => true ] ) ) ) ); } else { $dfg_safe_post_types[] = sanitize_key( $settings['post_type'] ); } } if ( ! empty( $args['fetch_acf_image'] ) && 'yes' === $args['fetch_acf_image'] && ! empty( $args['post__in'] ) ) { // SECURITY: previously set to 'any'/'any' which let unauthenticated // callers read drafts/private posts by passing arbitrary post__in IDs. $args['post_status'] = $dfg_safe_post_status; $args['post_type'] = $dfg_safe_post_types; } // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated $exclude_ids = json_decode( html_entity_decode( stripslashes ( $_POST['exclude_ids'] ) ) ); $args['post__not_in'] = ( !empty( $_POST['exclude_ids'] ) ) ? array_map( 'intval', array_unique( (array) $exclude_ids ) ) : array(); $active_term_id = ( !empty( $_POST['active_term_id'] ) ) ? intval( $_POST['active_term_id'] ) : 0; $active_taxonomy = ( !empty( $_POST['active_taxonomy'] ) ) ? sanitize_text_field( wp_unslash( $_POST['active_taxonomy'] ) ) : ''; // Check if this is a hybrid/combined query with ACF gallery // Also check settings for hybrid query flag as backup (in case args encoding failed) $is_hybrid_query = ( ! empty( $args['eael_dfg_enable_combined_query'] ) && 'yes' === $args['eael_dfg_enable_combined_query'] ) || ( ! empty( $settings['eael_dfg_enable_combined_query'] ) && 'yes' === $settings['eael_dfg_enable_combined_query'] && 'yes' === $settings['fetch_acf_image_gallery'] ); if ( $is_hybrid_query && class_exists( 'ACF' ) && ! empty( $settings['eael_acf_gallery_keys'] ) ) { // Build taxonomy map for ACF gallery attachments $taxonomy_map = $this->build_dfg_acf_taxonomy_map( $args, $settings, $active_term_id, $active_taxonomy ); // Store globally for templates global $eael_dfg_attachment_taxonomy_map; $eael_dfg_attachment_taxonomy_map = $taxonomy_map['taxonomy_map']; // Update args with the filtered post IDs if ( ! empty( $taxonomy_map['post_ids'] ) ) { // post_ids here are server-derived (parent post IDs + their ACF // attachment IDs from build_dfg_acf_taxonomy_map), so they are // trustworthy. Still constrain post_type/post_status to the // whitelist so a stale entry can't leak non-public content. $args['post__in'] = $taxonomy_map['post_ids']; $args['post_type'] = $dfg_safe_post_types; $args['post_status'] = $dfg_safe_post_status; $args['tax_query'] = []; $args['orderby'] = 'post__in'; } // Apply exclusions if ( ! empty( $args['post__not_in'] ) && ! empty( $args['post__in'] ) ) { $args['post__in'] = array_values( array_diff( $args['post__in'], array_unique( $args['post__not_in'] ) ) ); } } else { // Standard ACF gallery handling (non-hybrid) if ( ! empty( $args['fetch_acf_image'] ) && 'yes' === $args['fetch_acf_image'] && ! empty( $args['post__in'] ) ) { // SECURITY: same rationale as above — never use 'any'. $args['post_status'] = $dfg_safe_post_status; $args['post_type'] = $dfg_safe_post_types; } if ( ! empty( $args['post__not_in'] ) && ! empty( $args['post__in'] ) ) { $args['post__in'] = array_diff( $args['post__in'], array_unique( $args['post__not_in'] ) ); } if( 0 < $active_term_id && !empty( $active_taxonomy ) && !empty($args['tax_query']) ) { foreach ($args['tax_query'] as $key => $taxonomy) { if (isset($taxonomy['taxonomy']) && $taxonomy['taxonomy'] === $active_taxonomy) { $args['tax_query'][$key]['terms'] = [$active_term_id]; } } } } } $link_settings = [ 'image_link_nofollow' => ! empty( $settings['image_link_nofollow'] ) ? 'rel="nofollow"' : '', 'image_link_target_blank' => ! empty( $settings['image_link_target_blank'] ) ? 'target="_blank"' : '', 'title_link_nofollow' => ! empty( $settings['title_link_nofollow'] ) ? 'rel="nofollow"' : '', 'title_link_target_blank' => ! empty( $settings['title_link_target_blank'] ) ? 'target="_blank"' : '', 'read_more_link_nofollow' => ! empty( $settings['read_more_link_nofollow'] ) ? 'rel="nofollow"' : '', 'read_more_link_target_blank' => ! empty( $settings['read_more_link_target_blank'] ) ? 'target="_blank"' : '', ]; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated $template_info = $this->eael_sanitize_template_param( $_REQUEST['template_info'] ); if ( $template_info ) { if ( $template_info['dir'] === 'theme' ) { $dir_path = $this->retrive_theme_path(); } else if ( $template_info['dir'] === 'pro' ) { $dir_path = sprintf( "%sincludes", EAEL_PRO_PLUGIN_PATH ); } else { $dir_path = sprintf( "%sincludes", EAEL_PLUGIN_PATH ); } $file_path = realpath( sprintf( '%s/Template/%s/%s', $dir_path, $template_info['name'], $template_info['file_name'] ) ); if ( ! $file_path || 0 !== strpos( $file_path, realpath( $dir_path ) ) ) { wp_send_json_error( 'Invalid template', 'invalid_template', 400 ); } if ( $file_path ) { // wp_send_json( $args ); $query = new \WP_Query( $args ); $found_posts = $query->found_posts; $iterator = 0; if ( $query->have_posts() ) { if ( $class === '\Essential_Addons_Elementor\Elements\Product_Grid' && boolval( $settings['show_add_to_cart_custom_text'] ) ) { $add_to_cart_text = [ 'add_to_cart_simple_product_button_text' => $settings['add_to_cart_simple_product_button_text'], 'add_to_cart_variable_product_button_text' => $settings['add_to_cart_variable_product_button_text'], 'add_to_cart_grouped_product_button_text' => $settings['add_to_cart_grouped_product_button_text'], 'add_to_cart_external_product_button_text' => $settings['add_to_cart_external_product_button_text'], 'add_to_cart_default_product_button_text' => $settings['add_to_cart_default_product_button_text'], ]; $this->change_add_woo_checkout_update_order_reviewto_cart_text( $add_to_cart_text ); } // Handle custom add to cart text for Woo_Product_List if ( $class === '\Essential_Addons_Elementor\Elements\Woo_Product_List' && boolval( $settings['eael_product_list_content_footer_add_to_cart_custom_text_show'] ) ) { $add_to_cart_text = [ 'add_to_cart_simple_product_button_text' => $settings['eael_product_list_content_footer_add_to_cart_simple_text'], 'add_to_cart_variable_product_button_text' => $settings['eael_product_list_content_footer_add_to_cart_variable_text'], 'add_to_cart_grouped_product_button_text' => $settings['eael_product_list_content_footer_add_to_cart_grouped_text'], 'add_to_cart_external_product_button_text' => $settings['eael_product_list_content_footer_add_to_cart_external_text'], 'add_to_cart_default_product_button_text' => $settings['eael_product_list_content_footer_add_to_cart_default_text'], ]; $this->change_add_woo_checkout_update_order_reviewto_cart_text( $add_to_cart_text ); } if ( $class === '\Essential_Addons_Elementor\Pro\Elements\Dynamic_Filterable_Gallery' ) { $html .= "<div class='found_posts' style='display: none;'>{$found_posts}</div>"; } while ( $query->have_posts() ) { $query->the_post(); $html .= HelperClass::include_with_variable( $file_path, [ 'settings' => $settings, 'link_settings' => $link_settings, 'iterator' => $iterator ] ); $iterator ++; } } else { $html .= '<p class="no-posts-found">' . esc_html__( 'No posts found!', 'essential-addons-for-elementor-lite' ) . '</p>'; } } } if ( $class === '\Essential_Addons_Elementor\Elements\Product_Grid' ) { do_action( 'eael_woo_after_product_loop', $settings['eael_product_grid_style_preset'] ); } if ( $class === '\Essential_Addons_Elementor\Elements\Woo_Product_List' ) { do_action( 'eael/woo-product-list/after-product-loop' ); } while ( ob_get_status() ) { ob_end_clean(); } if ( function_exists( 'gzencode' ) ) { $response = gzencode( wp_json_encode( $html ) ); header( 'Content-Type: application/json; charset=utf-8' ); header( 'Content-Encoding: gzip' ); header( 'Content-Length: ' . strlen( $response ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $response; } else { echo wp_kses_post( $html ); } wp_die(); } /** * Build taxonomy map for Dynamic Filterable Gallery ACF attachments * Maps attachment IDs to their parent post's taxonomy classes for filtering * * @param array $args Query args * @param array $settings Widget settings * @param int $active_term_id Active filter term ID * @param string $active_taxonomy Active filter taxonomy * @return array Array with 'post_ids' and 'taxonomy_map' */ protected function build_dfg_acf_taxonomy_map( $args, $settings, $active_term_id = 0, $active_taxonomy = '' ) { $_args = $args; $_args['posts_per_page'] = -1; $_args['fields'] = 'ids'; // Restore original post_type from settings (args may have 'any' from hybrid query encoding) if ( ! empty( $settings['post_type'] ) && $settings['post_type'] !== 'by_id' ) { $_args['post_type'] = $settings['post_type']; $_args['post_status'] = 'publish'; } // Remove post__in constraint to get all matching parent posts unset( $_args['post__in'] ); // If filtering by a specific term, apply the filter to parent posts if ( $active_term_id > 0 && ! empty( $active_taxonomy ) ) { $_args['tax_query'] = [ [ 'taxonomy' => $active_taxonomy, 'field' => 'term_id', 'terms' => [ $active_term_id ], ] ]; } $query = new \WP_Query( $_args ); $post_ids = []; $taxonomy_map = []; if ( $query->have_posts() ) { while ( $query->have_posts() ) { $query->the_post(); $parent_post_id = get_the_ID(); // Get parent post's taxonomy classes $parent_taxonomy_classes = $this->get_dfg_post_taxonomy_classes( $parent_post_id, $settings ); // Include parent posts unless hidden if ( ! isset( $settings['eael_gf_hide_parent_items'] ) || 'yes' !== $settings['eael_gf_hide_parent_items'] ) { $post_ids[] = $parent_post_id; } // Get ACF gallery items $acf_gallery = []; if ( ! empty( $settings['eael_acf_gallery_keys'] ) ) { foreach ( $settings['eael_acf_gallery_keys'] as $key ) { $_acf_gallery = get_field( $key, $parent_post_id ); if ( ! empty( $_acf_gallery ) ) { $acf_gallery = array_merge( $_acf_gallery, $acf_gallery ); } } } if ( ! empty( $acf_gallery ) ) { foreach ( $acf_gallery as $item ) { $attachment_id = false; if ( empty( $item['ID'] ) ) { if ( 'integer' === gettype( $item ) ) { $attachment_id = $item; } else if ( 'string' === gettype( $item ) ) { $attachment_id = HelperClass::eael_get_attachment_id_from_url( $item ); } if ( ! $attachment_id ) { continue; } $attachment = get_post( $attachment_id ); if ( ! is_object( $attachment ) || ! isset( $attachment->ID ) ) { continue; } } else { $attachment_id = $item['ID']; } $post_ids[] = $attachment_id; // Map this attachment to its parent's taxonomy classes if ( ! isset( $taxonomy_map[ $attachment_id ] ) ) { $taxonomy_map[ $attachment_id ] = $parent_taxonomy_classes; } else { $taxonomy_map[ $attachment_id ] = array_unique( array_merge( $taxonomy_map[ $attachment_id ], $parent_taxonomy_classes ) ); } } } } } wp_reset_postdata(); return [ 'post_ids' => array_unique( $post_ids ), 'taxonomy_map' => $taxonomy_map ]; } /** * Get taxonomy classes for a post (for DFG ACF gallery parent posts) * * @param int $post_id Post ID * @param array $settings Widget settings * @return array Array of taxonomy slug classes */ protected function get_dfg_post_taxonomy_classes( $post_id, $settings ) { $classes = []; $post_type = get_post_type( $post_id ); // Get all taxonomies for this post type $get_object_taxonomies = get_object_taxonomies( $post_type ); $taxonomies = wp_get_object_terms( $post_id, $get_object_taxonomies, array( "fields" => "slugs" ) ); if ( $taxonomies && ! is_wp_error( $taxonomies ) ) { foreach ( $taxonomies as $taxonomy ) { $classes[] = $taxonomy; } } // Handle category child items $show_category_child_items = ! empty( $settings['category_show_child_items'] ) && 'yes' === $settings['category_show_child_items'] ? 1 : 0; $show_product_cat_child_items = ! empty( $settings['product_cat_show_child_items'] ) && 'yes' === $settings['product_cat_show_child_items'] ? 1 : 0; $category_or_product_cat = ''; if ( 1 === $show_category_child_items && ! empty( $get_object_taxonomies ) && in_array( 'category', $get_object_taxonomies ) ) { $category_or_product_cat = 'category'; } if ( 1 === $show_product_cat_child_items && ! empty( $get_object_taxonomies ) && in_array( 'product_cat', $get_object_taxonomies ) ) { $category_or_product_cat = 'product_cat'; } if ( $category_or_product_cat ) { $terms = get_the_terms( $post_id, $category_or_product_cat ); if ( $terms && ! is_wp_error( $terms ) ) { foreach ( $terms as $term ) { $parent_list = get_term_parents_list( $term->term_id, $category_or_product_cat, array( "format" => "slug", 'separator' => '/', "link" => 0, "inclusive" => 0 ) ); $parent_list = explode( '/', $parent_list ); $classes = array_merge( $classes, array_filter( $parent_list ) ); } } } // Get categories $categories = get_the_category( $post_id ); if ( $categories ) { foreach ( $categories as $category ) { $classes[] = $category->slug; } } // Get tags $tags = wp_get_post_tags( $post_id ); if ( $tags ) { foreach ( $tags as $tag ) { $classes[] = $tag->slug; } } // Get product categories $product_cats = get_the_terms( $post_id, 'product_cat' ); if ( $product_cats && ! is_wp_error( $product_cats ) ) { foreach ( $product_cats as $cat ) { if ( is_object( $cat ) ) { $classes[] = $cat->slug; } } } // Add post name/slug $classes[] = get_post_field( 'post_name', $post_id ); return array_unique( array_filter( $classes ) ); } /** * Woo Pagination Product Ajax * get product list when pagination number/dot click by ajax * * @access public * @return void of a html markup with AJAX call. * @since 3.1.0 */ public function eael_woo_pagination_product_ajax() { check_ajax_referer( 'essential-addons-elementor', 'security' ); do_action( 'eael_before_woo_pagination_product_ajax_start', $_REQUEST ); if ( ! empty( $_POST['page_id'] ) ) { $page_id = intval( $_POST['page_id'], 10 ); } else { $err_msg = __( 'Page ID is missing', 'essential-addons-for-elementor-lite' ); wp_send_json_error( $err_msg ); } if ( ! empty( $_POST['widget_id'] ) ) { $widget_id = sanitize_text_field( wp_unslash( $_POST['widget_id'] ) ); } else { $err_msg = __( 'Widget ID is missing', 'essential-addons-for-elementor-lite' ); wp_send_json_error( $err_msg ); } $settings = HelperClass::eael_get_widget_settings( $page_id, $widget_id ); if ( empty( $settings ) ) { wp_send_json_error( [ 'message' => __( 'Widget settings are not found. Did you save the widget before using load more??', 'essential-addons-for-elementor-lite' ) ] ); } $settings['eael_page_id'] = $page_id; $settings['eael_widget_id'] = $widget_id; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated wp_parse_str( $_REQUEST['args'], $args ); $args = $this->eael_sanitize_query_args( $args ); // Convert WP_Query args to WC_Product_Query args if needed $wc_args = $this->convert_pagination_args_to_wc_product_query( $args, $settings ); if ( isset( $wc_args['date_query']['relation'] ) ) { $wc_args['date_query']['relation'] = HelperClass::eael_sanitize_relation( $wc_args['date_query']['relation'] ); } $paginationNumber = ! empty( $_POST['number'] ) ? absint( $_POST['number'] ) : 1; $paginationLimit = ! empty( $_POST['limit'] ) ? absint( $_POST['limit'] ) : 10; $wc_args['limit'] = $paginationLimit; $wc_args['page'] = $paginationNumber; // Calculate offset for WC_Product_Query if ( $paginationNumber == "1" ) { $paginationOffsetValue = "0"; } else { $paginationOffsetValue = ( $paginationNumber - 1 ) * $paginationLimit; $wc_args['offset'] = $paginationOffsetValue; } // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated $template_info = $this->eael_sanitize_template_param( $_REQUEST['templateInfo'] ); $this->set_widget_name( $template_info['name'] ); $template = realpath( $this->get_template( $template_info['file_name'] ) ); ob_start(); // Use WC_Product_Query for product queries $wc_query = new \WC_Product_Query( $wc_args ); $products = $wc_query->get_products(); // Handle WC_Product_Query results if ( is_object( $products ) && isset( $products->products ) ) { $product_objects = $products->products; } else { $product_objects = $products; } if ( ! empty( $product_objects ) ) { if ( isset( $template_info['name'] ) && $template_info['name'] === 'eicon-woocommerce' && boolval( $settings['show_add_to_cart_custom_text'] ) ){ $add_to_cart_text = [ 'add_to_cart_simple_product_button_text' => $settings['add_to_cart_simple_product_button_text'], 'add_to_cart_variable_product_button_text' => $settings['add_to_cart_variable_product_button_text'], 'add_to_cart_grouped_product_button_text' => $settings['add_to_cart_grouped_product_button_text'], 'add_to_cart_external_product_button_text' => $settings['add_to_cart_external_product_button_text'], 'add_to_cart_default_product_button_text' => $settings['add_to_cart_default_product_button_text'], ]; $this->change_add_woo_checkout_update_order_reviewto_cart_text( $add_to_cart_text ); } // Iterate through WC_Product objects foreach ( $product_objects as $product ) { global $post; $post = get_post( $product->get_id() ); setup_postdata( $post ); include( $template ); } wp_reset_postdata(); } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo ob_get_clean(); wp_die(); } /** * Harden client-supplied WP_Query args parsed from $_POST/$_REQUEST['args']. * * wp_parse_str() yields these as strings, and several WP_Query ID-list vars * are only absint()'d by core when they arrive as an array (e.g. * author__not_in — class-wp-query.php only maps absint inside `if ( is_array() )`). * A string value like "0)and 1=1 -- -" therefore lands raw in the SQL WHERE * clause → blind boolean SQL injection on the nopriv load_more endpoints. * * Coercing each of these to an array of absint both neutralises the payload * and forces core down its already-sanitised array branch. post_status is * intentionally left to each caller (it still overrides to 'publish'). * * @param array $args Parsed query args (by value). * @return array Sanitised args. */ private function eael_sanitize_query_args( $args ) { if ( ! is_array( $args ) ) { return []; } // Vars that must be arrays of post/term/user IDs. $id_list_keys = [ 'author__in', 'author__not_in', 'post__in', 'post__not_in', 'post_parent__in', 'post_parent__not_in', 'category__in', 'category__not_in', 'category__and', 'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', ]; foreach ( $id_list_keys as $key ) { if ( isset( $args[ $key ] ) ) { if ( in_array( $key, [ 'tag_slug__in', 'tag_slug__and' ], true ) ) { $args[ $key ] = array_values( array_filter( array_map( 'sanitize_title', (array) $args[ $key ] ) ) ); } else { $args[ $key ] = array_values( array_filter( array_map( 'absint', (array) $args[ $key ] ) ) ); } } } // Comma-list ID vars: preserve the list but force every token to an int. // (Core already intval()s these, but harden here too for defense-in-depth.) foreach ( [ 'author', 'cat' ] as $key ) { if ( isset( $args[ $key ] ) && ! is_array( $args[ $key ] ) ) { $args[ $key ] = implode( ',', array_filter( array_map( 'absint', explode( ',', (string) $args[ $key ] ) ) ) ); } } // Scalar single-int vars. $int_keys = [ 'tag_id', 'p', 'page_id', 'post_parent', 'offset', 'paged', 'page', 'posts_per_page', 'numberposts', 'menu_order', 'w', 'year', 'monthnum', 'day', 'hour', 'minute', 'second' ]; foreach ( $int_keys as $key ) { if ( isset( $args[ $key ] ) && ! is_array( $args[ $key ] ) ) { $args[ $key ] = (int) $args[ $key ]; } } return $args; } /** * Convert pagination arguments to WC_Product_Query arguments * @param array $args Original arguments from pagination * @param array $settings Widget settings * @return array WC_Product_Query compatible arguments */ private function convert_pagination_args_to_wc_product_query( $args, $settings ) { $wc_args = [ 'paginate' => true, 'return' => 'objects', ]; // Map common WP_Query args to WC_Product_Query args. // NOTE: post_status is deliberately NOT mapped from client $args — status is // derived server-side from the saved widget settings below and capability-clamped, // so an unauthenticated caller cannot request pending/future/draft products. $arg_mapping = [ 'posts_per_page' => 'limit', 'post__in' => 'include', 'post__not_in' => 'exclude', 'author__in' => 'author', 'paged' => 'page', ]; foreach ( $arg_mapping as $wp_key => $wc_key ) { if ( isset( $args[ $wp_key ] ) ) { $wc_args[ $wc_key ] = $args[ $wp_key ]; } } // Handle other common args if ( isset( $args['orderby'] ) ) { $wc_args['orderby'] = $args['orderby']; } if ( isset( $args['order'] ) ) { $wc_args['order'] = $args['order']; } if ( isset( $args['offset'] ) ) { $wc_args['offset'] = $args['offset']; } if ( isset( $args['s'] ) ) { $wc_args['search'] = $args['s']; } // Handle meta_query and tax_query if ( isset( $args['meta_query'] ) ) { $wc_args['meta_query'] = $args['meta_query']; } if ( isset( $args['tax_query'] ) ) { $wc_args['tax_query'] = $args['tax_query']; } // Handle meta_key and meta_value if ( isset( $args['meta_key'] ) ) { if ( ! isset( $wc_args['meta_query'] ) ) { $wc_args['meta_query'] = ['relation' => 'AND']; } $meta_query = [ 'key' => $args['meta_key'], ]; if ( isset( $args['meta_value'] ) ) { $meta_query['value'] = $args['meta_value']; } if ( isset( $args['meta_compare'] ) ) { $meta_query['compare'] = $args['meta_compare']; } $wc_args['meta_query'][] = $meta_query; } // Set product status from settings (handle both Product_Grid and Woo_Product_List), // capability-clamped so non-public statuses never reach unauthenticated viewers. if ( ! empty( $settings['eael_product_grid_products_status'] ) ) { $status_setting = $settings['eael_product_grid_products_status']; } elseif ( ! empty( $settings['eael_product_list_products_status'] ) ) { $status_setting = $settings['eael_product_list_products_status']; } else { $status_setting = [ 'publish' ]; } $wc_args['status'] = HelperClass::eael_validate_product_statuses( $status_setting ); // Set visibility $wc_args['visibility'] = 'visible'; return $wc_args; } /** * Woo Pagination Ajax * Return pagination list for product post type while used Product_Grid widget * * @access public * @return void of a html markup with AJAX call. * @since unknown */ public function eael_woo_pagination_ajax() { check_ajax_referer( 'essential-addons-elementor', 'security' ); if ( ! empty( $_POST['page_id'] ) ) { $page_id = intval( $_POST['page_id'], 10 ); } else { $err_msg = __( 'Page ID is missing', 'essential-addons-for-elementor-lite' ); wp_send_json_error( $err_msg ); } if ( ! empty( $_POST['widget_id'] ) ) { $widget_id = sanitize_text_field( wp_unslash( $_POST['widget_id'] ) ); } else { $err_msg = __( 'Widget ID is missing', 'essential-addons-for-elementor-lite' ); wp_send_json_error( $err_msg ); } $settings = HelperClass::eael_get_widget_settings( $page_id, $widget_id ); if ( empty( $settings ) ) { wp_send_json_error( [ 'message' => __( 'Widget settings are not found. Did you save the widget before using load more??', 'essential-addons-for-elementor-lite' ) ] ); } $settings['eael_page_id'] = $page_id; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated wp_parse_str( $_REQUEST['args'], $args ); $args = $this->eael_sanitize_query_args( $args ); if ( isset( $args['date_query']['relation'] ) ) { $args['date_query']['relation'] = HelperClass::eael_sanitize_relation( $args['date_query']['relation'] ); } $paginationNumber = ! empty( $_POST['number'] ) ? absint( $_POST['number'] ) : 1; $paginationLimit = ! empty( $_POST['limit'] ) ? absint( $_POST['limit'] ) : 10; $pagination_Count = intval( $args['total_post'] ); $pagination_Paginationlist = ceil( $pagination_Count / $paginationLimit ); $last = ceil( $pagination_Paginationlist ); $paginationprev = $paginationNumber - 1; $paginationnext = $paginationNumber + 1; if ( $paginationNumber > 1 ) { $paginationprev; } if ( $paginationNumber < $last ) { $paginationnext; } $adjacents = "2"; $next_label = sanitize_text_field( $settings['pagination_next_label'] ); $prev_label = sanitize_text_field( $settings['pagination_prev_label'] ); $settings['eael_widget_name'] = ! empty( $_REQUEST['template_name'] ) ? realpath( sanitize_file_name( wp_unslash( $_REQUEST['template_name'] ) ) ) : ''; $setPagination = ""; if ( $pagination_Paginationlist > 0 ) { $setPagination .= "<ul class='page-numbers'>"; if ( 1 < $paginationNumber ) { $setPagination .= "<li class='pagitext'><a href='javascript:void(0);' class='page-numbers' data-pnumber='" . esc_attr( $paginationprev ) . "' >" . esc_html( $prev_label ) . "</a></li>"; } if ( $pagination_Paginationlist < 7 + ( $adjacents * 2 ) ) { for ( $pagination = 1; $pagination <= $pagination_Paginationlist; $pagination ++ ) { $active = ( $paginationNumber == $pagination ) ? 'current' : ''; $setPagination .= sprintf( "<li><a href='javascript:void(0);' id='post' class='page-numbers %s' data-pnumber='%2\$d'>%2\$d</a></li>", esc_attr( $active ), esc_html( $pagination ) ); } } else if ( $pagination_Paginationlist > 5 + ( $adjacents * 2 ) ) { if ( $paginationNumber < 1 + ( $adjacents * 2 ) ) { for ( $pagination = 1; $pagination <= 4 + ( $adjacents * 2 ); $pagination ++ ) { $active = ( $paginationNumber == $pagination ) ? 'current' : ''; $setPagination .= sprintf( "<li><a href='javascript:void(0);' id='post' class='page-numbers %s' data-pnumber='%2\$d'>%2\$d</a></li>", esc_attr( $active ), esc_html( $pagination ) ); } $setPagination .= "<li class='pagitext dots'>...</li>"; $setPagination .= sprintf( "<li><a href='javascript:void(0);' id='post' class='page-numbers %s' data-pnumber='%2\$d'>%2\$d</a></li>", esc_attr( $active ), esc_html( $pagination ) ); } elseif ( $pagination_Paginationlist - ( $adjacents * 2 ) > $paginationNumber && $paginationNumber > ( $adjacents * 2 ) ) { $active = ''; $setPagination .= sprintf( "<li><a href='javascript:void(0);' id='post' class='page-numbers %s' data-pnumber='%2\$d'>%2\$d</a></li>", esc_attr( $active ), 1 ); $setPagination .= "<li class='pagitext dots'>...</li>"; for ( $pagination = $paginationNumber - $adjacents; $pagination <= $paginationNumber + $adjacents; $pagination ++ ) { $active = ( $paginationNumber == $pagination ) ? 'current' : ''; $setPagination .= sprintf( "<li><a href='javascript:void(0);' id='post' class='page-numbers %s' data-pnumber='%2\$d'>%2\$d</a></li>", esc_attr( $active ), esc_html( $pagination ) ); } $setPagination .= "<li class='pagitext dots'>...</li>"; $setPagination .= sprintf( "<li><a href='javascript:void(0);' id='post' class='page-numbers %s' data-pnumber='%2\$d'>%2\$d</a></li>", esc_attr( $active ), esc_html( $last ) ); } else { $active = ''; $setPagination .= sprintf( "<li><a href='javascript:void(0);' id='post' class='page-numbers %s' data-pnumber='%2\$d'>%2\$d</a></li>", esc_attr( $active ), 1 ); $setPagination .= "<li class='pagitext dots'>...</li>"; for ( $pagination = $last - ( 2 + ( $adjacents * 2 ) ); $pagination <= $last; $pagination ++ ) { $active = ( $paginationNumber == $pagination ) ? 'current' : ''; $setPagination .= sprintf( "<li><a href='javascript:void(0);' id='post' class='page-numbers %s' data-pnumber='%2\$d'>%2\$d</a></li>", esc_attr( $active ), esc_html( $pagination ) ); } } } else { for ( $pagination = 1; $pagination <= $pagination_Paginationlist; $pagination ++ ) { $active = ( $paginationNumber == $pagination ) ? 'current' : ''; $setPagination .= sprintf( "<li><a href='javascript:void(0);' id='post' class='page-numbers %s' data-pnumber='%2\$d'>%2\$d</a></li>", esc_attr( $active ), esc_html( $pagination ) ); } } if ( $paginationNumber < $pagination_Paginationlist ) { $setPagination .= "<li class='pagitext'><a href='javascript:void(0);' class='page-numbers' data-pnumber='" . esc_attr( $paginationnext ) . "' > " . esc_html( $next_label ) . " </a></li>"; } $setPagination .= "</ul>"; } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $setPagination; wp_die(); } /** * Product Add to Cart * added product in cart through ajax * * @access public * @return void of a html markup with AJAX call. * @since unknown */ public function eael_product_add_to_cart() { check_ajax_referer( 'essential-addons-elementor', 'security' ); $ajax = wp_doing_ajax(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated $cart_items = isset( $_POST['cart_item_data'] ) ? $_POST['cart_item_data'] : []; $variation = []; if ( ! empty( $cart_items ) ) { foreach ( $cart_items as $key => $value ) { if ( preg_match( "/^attribute*/", $value['name'] ) ) { $variation[ $value['name'] ] = sanitize_text_field( wp_unslash( $value['value'] ) ); } } } if ( isset( $_POST['product_data'] ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated foreach ( $_POST['product_data'] as $item ) { $product_id = isset( $item['product_id'] ) ? sanitize_text_field( wp_unslash( $item['product_id'] ) ) : 0; $variation_id = isset( $item['variation_id'] ) ? sanitize_text_field( wp_unslash( $item['variation_id'] ) ) : 0; $quantity = isset( $item['quantity'] ) ? sanitize_text_field( wp_unslash( $item['quantity'] ) ) : 0; if ( $variation_id ) { WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation ); } else { WC()->cart->add_to_cart( $product_id, $quantity ); } } } wp_send_json_success(); } /** * Woo Checkout Update Order Review * return order review data * * @access public * @return void * @since 4.0.0 */ public function woo_checkout_update_order_review() { check_ajax_referer( 'essential-addons-elementor', 'security' ); // phpcs:disable $setting = $_POST['orderReviewData']; $shipping_data = empty ( $_POST['shippingData'] ) ? WC()->session->get('chosen_shipping_methods') : [wc_clean( $_POST['shippingData'] )]; //Mondial Relay plugin integration do_action( 'eael_mondialrelay_order_after_shipping' ); WC()->session->set( 'chosen_shipping_methods', $shipping_data ); // Required for Avatax (and standard WC) to trigger calculation if ( isset( $_POST['post_data'] ) ) { $_POST['woocommerce_checkout_update_totals'] = 1; do_action( 'woocommerce_checkout_update_order_review', $_POST['post_data'] ); } // Force is_checkout() to be true so plugins like Avatax display the correct message add_filter( 'woocommerce_is_checkout', '__return_true' ); ob_start(); AllTraits::checkout_order_review_default( $setting ); $woo_checkout_update_order_review = ob_get_clean(); // phpcs:enable wp_send_json( array( 'order_review' => $woo_checkout_update_order_review, ) ); } /** * Eael Product Quick View Popup * Retrieve product quick view data * * @access public * @return void * @since 4.0.0 */ public function eael_product_quickview_popup() { //check nonce check_ajax_referer( 'essential-addons-elementor', 'security' ); $widget_id = ! empty( $_POST['widget_id'] ) ? sanitize_key( wp_unslash( $_POST['widget_id'] ) ) : ''; $product_id = ! empty( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0; $page_id = ! empty( $_POST['page_id'] ) ? absint( $_POST['page_id'] ) : 0; if ( $widget_id == '' && $product_id == '' && $page_id == '' ) { wp_send_json_error(); } global $post, $product; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound $product = wc_get_product( $product_id ); $post = get_post( $product_id ); // SECURITY FIX: Verify product exists and is visible if ( ! $product || ! $product->is_visible() ) { wp_send_json_error( __( 'Product not found or not accessible', 'essential-addons-for-elementor-lite' ) ); } // Also verify post status for non-admin users $post = get_post( $product_id ); if ( ! current_user_can( 'edit_post', $product_id ) && $post->post_status !== 'publish' ) { wp_send_json_error( __( 'Product not found or not accessible', 'essential-addons-for-elementor-lite' ) ); } // Block password-protected products for users who cannot edit them if ( ! current_user_can( 'edit_post', $product_id ) && post_password_required( $post ) ) { wp_send_json_error( __( 'Product not found or not accessible', 'essential-addons-for-elementor-lite' ) ); } setup_postdata( $post ); $settings = $this->eael_get_widget_settings( $page_id, $widget_id ); ob_start(); HelperClass::eael_product_quick_view( $product, $settings, $widget_id ); $data = ob_get_clean(); wp_reset_postdata(); wp_send_json_success( $data ); } /** * Ajax Eael Product Gallery * Retrieve product quick view data * * @access public * @return false|void * @since 4.0.0 */ public function ajax_eael_product_gallery() { $ajax = wp_doing_ajax(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.NonceVerification.Missing wp_parse_str( $_POST['args'], $args ); $args = $this->eael_sanitize_query_args( $args ); $args['post_status'] = 'publish'; $args['offset'] = $args['offset'] ?? 0; if ( isset( $args['date_query']['relation'] ) ) { $args['date_query']['relation'] = HelperClass::eael_sanitize_relation( $args['date_query']['relation'] ); } if ( empty( $_POST['nonce'] ) ) { $err_msg = __( 'Insecure form submitted without security token', 'essential-addons-for-elementor-lite' ); if ( $ajax ) { wp_send_json_error( $err_msg ); } return false; } if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'eael_product_gallery' ) ) { $err_msg = __( 'Security token did not match', 'essential-addons-for-elementor-lite' ); if ( $ajax ) { wp_send_json_error( $err_msg ); } return false; } if ( ! empty( $_POST['page_id'] ) ) { $page_id = intval( $_POST['page_id'], 10 ); } else { $err_msg = __( 'Page ID is missing', 'essential-addons-for-elementor-lite' ); if ( $ajax ) { wp_send_json_error( $err_msg ); } return false; } if ( ! empty( $_POST['widget_id'] ) ) { $widget_id = sanitize_text_field( wp_unslash( $_POST['widget_id'] ) ); } else { $err_msg = __( 'Widget ID is missing', 'essential-addons-for-elementor-lite' ); if ( $ajax ) { wp_send_json_error( $err_msg ); } return false; } $settings = HelperClass::eael_get_widget_settings( $page_id, $widget_id ); if ( empty( $settings ) ) { wp_send_json_error( [ 'message' => __( 'Widget settings are not found. Did you save the widget before using load more??', 'essential-addons-for-elementor-lite' ) ] ); } if ( $widget_id == '' && $page_id == '' ) { wp_send_json_error(); } $settings['eael_widget_id'] = $widget_id; $settings['eael_page_id'] = $page_id; $page = !empty( $_REQUEST['page'] ) ? absint( $_REQUEST['page'] ) : 1; $args['offset'] = (int) $args['offset'] + ( ( (int) $page - 1 ) * (int) $args['posts_per_page'] ); if ( isset( $_REQUEST['taxonomy'] ) && isset( $_REQUEST['taxonomy']['taxonomy'] ) && $_REQUEST['taxonomy']['taxonomy'] != 'all' ) { $args['tax_query'] = [ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $this->sanitize_taxonomy_data( $_REQUEST['taxonomy'] ), ]; $relation = isset( $settings['relation_cats_tags'] ) ? $settings['relation_cats_tags'] : 'OR'; if ( 'and' === strtolower( $relation ) ) { if ( 'product_cat' === $_REQUEST['taxonomy']['taxonomy'] && ! empty( $settings['eael_product_gallery_tags'] ) ) { $args['tax_query'][] = [ 'taxonomy' => 'product_tag', 'field' => 'term_id', 'terms' => $settings['eael_product_gallery_tags'], 'operator' => 'IN', ]; } if ( 'product_tag' === $_REQUEST['taxonomy']['taxonomy'] && ! empty( $settings['eael_product_gallery_categories'] ) ) { $args['tax_query'][] = [ 'taxonomy' => 'product_cat', 'field' => 'term_id', 'terms' => $settings['eael_product_gallery_categories'], 'operator' => 'IN', ]; } } $args['tax_query'] = $this->eael_terms_query_multiple( $args['tax_query'], $relation ); if ( $settings[ 'eael_product_gallery_product_filter' ] == 'featured-products' ) { $args[ 'tax_query' ][] = [ 'relation' => 'AND', [ 'taxonomy' => 'product_visibility', 'field' => 'name', 'terms' => 'featured', ], [ 'taxonomy' => 'product_visibility', 'field' => 'name', 'terms' => [ 'exclude-from-search', 'exclude-from-catalog' ], 'operator' => 'NOT IN', ], ]; } } //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitize, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $template_info = $this->eael_sanitize_template_param( $_REQUEST['template_info'] ); if ( $template_info ) { if ( $template_info['dir'] === 'theme' ) { $dir_path = $this->retrive_theme_path(); } else if ( $template_info['dir'] === 'pro' ) { $dir_path = sprintf( "%sincludes", EAEL_PRO_PLUGIN_PATH ); } else { $dir_path = sprintf( "%sincludes", EAEL_PLUGIN_PATH ); } $file_path = realpath( sprintf( '%s/Template/%s/%s', $dir_path, $template_info['name'], $template_info['file_name'] ) ); if ( ! $file_path || 0 !== strpos( $file_path, realpath( $dir_path ) ) ) { wp_send_json_error( 'Invalid template', 'invalid_template', '400' ); } $html = ''; if ( $file_path ) { // Convert args to WC_Product_Query format for product gallery $wc_args = $this->convert_pagination_args_to_wc_product_query( $args, $settings ); $wc_query = new \WC_Product_Query( $wc_args ); $products = $wc_query->get_products(); // Handle WC_Product_Query results if ( is_object( $products ) && isset( $products->products ) ) { $product_objects = $products->products; $found_posts = $products->total; $max_num_pages = $products->max_num_pages; } else { $product_objects = $products; $found_posts = count( $products ); $max_num_pages = 1; } if ( ! empty( $product_objects ) ) { do_action( 'eael_woo_before_product_loop' ); // Iterate through WC_Product objects foreach ( $product_objects as $product ) { global $post; $post = get_post( $product->get_id() ); setup_postdata( $post ); $html .= HelperClass::include_with_variable( $file_path, [ 'settings' => $settings ] ); } do_action( 'eael_woo_after_product_loop' ); $html .= '<div class="eael-max-page" style="display:none;">'. $max_num_pages . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $html; wp_reset_postdata(); } } } wp_die(); } public function eael_terms_query_multiple( $args_tax_query = [], $relation = 'OR' ){ if ( strpos($args_tax_query[0]['taxonomy'], '|') !== false ) { $args_tax_query_item = $args_tax_query[0]; //Query for category and tag $args_multiple['tax_query'] = []; if( isset( $args_tax_query_item['terms'] ) ){ $args_multiple['tax_query'][] = [ 'taxonomy' => 'product_cat', 'field' => 'term_id', 'terms' => $args_tax_query_item['terms'], ]; } if( isset( $args_tax_query_item['terms_tag'] ) ){ $args_multiple['tax_query'][] = [ 'taxonomy' => 'product_tag', 'field' => 'term_id', 'terms' => $args_tax_query_item['terms_tag'], ]; } if ( count( $args_multiple['tax_query'] ) ) { $args_multiple['tax_query']['relation'] = $relation; } $args_tax_query = $args_multiple['tax_query']; } if( isset( $args_tax_query[0]['terms_tag'] ) ){ if( 'product_tag' === $args_tax_query[0]['taxonomy'] ){ $args_tax_query[0]['terms'] = $args_tax_query[0]['terms_tag']; } unset($args_tax_query[0]['terms_tag']); } return $args_tax_query; } /** * Select2 Ajax Posts Filter Autocomplete * Fetch post/taxonomy data and render in Elementor control select2 ajax search box * * @access public * @return void * @since 4.0.0 */ public function select2_ajax_posts_filter_autocomplete() { if ( empty( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'eael_select2' ) ) { wp_send_json_error( ['error'=> esc_html__( 'Unauthorized', 'essential-addons-for-elementor-lite' )] ); } $post_type = 'post'; $source_name = 'post_type'; if ( ! empty( $_POST['post_type'] ) ) { $post_type = sanitize_text_field( wp_unslash( $_POST['post_type'] ) ); } if ( ! empty( $_POST['source_name'] ) ) { $source_name = sanitize_text_field( wp_unslash( $_POST['source_name'] ) ); } $search = ! empty( $_POST['term'] ) ? sanitize_text_field( wp_unslash( $_POST['term'] ) ) : ''; $results = $post_list = []; switch ( $source_name ) { case 'taxonomy': $args = [ 'hide_empty' => false, 'orderby' => 'name', 'order' => 'ASC', 'search' => $search ]; if ( $post_type !== 'all' ) { $args['taxonomy'] = $post_type; } $post_list = wp_list_pluck( get_terms( $args ), 'name', 'term_id' ); break; case 'user': if ( ! current_user_can( 'list_users' ) ) { $post_list = []; break; } $users = []; foreach ( get_users( [ 'search' => "*{$search}*" ] ) as $user ) { $user_id = $user->ID; $user_name = $user->display_name; $users[ $user_id ] = $user_name; } $post_list = $users; break; default: $post_list = HelperClass::get_query_post_list( $post_type, 10, $search ); } if ( ! empty( $post_list ) ) { foreach ( $post_list as $key => $item ) { $results[] = [ 'text' => $item, 'id' => $key ]; } } wp_send_json( [ 'results' => $results ] ); } /** * Select2 Ajax Get Posts Value Titles * get selected value to show elementor editor panel in select2 ajax search box * * @access public * @return void * @since 4.0.0 */ public function select2_ajax_get_posts_value_titles() { if ( empty( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'eael_select2' ) ) { wp_send_json_error( ['error'=> esc_html__( 'Unauthorized', 'essential-addons-for-elementor-lite' )] ); } if ( empty( $_POST['id'] ) ) { wp_send_json_error( [] ); } // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash if ( empty( array_filter( $_POST['id'] ) ) ) { wp_send_json_error( [] ); } $ids = array_map( 'intval', $_POST['id'] ); $source_name = ! empty( $_POST['source_name'] ) ? sanitize_text_field( wp_unslash( $_POST['source_name'] ) ) : ''; switch ( $source_name ) { case 'taxonomy': $args = [ 'hide_empty' => false, 'orderby' => 'name', 'order' => 'ASC', 'include' => implode( ',', $ids ), ]; if ( ! empty( $_POST['post_type'] ) && $_POST['post_type'] !== 'all' ) { $args['taxonomy'] = sanitize_text_field( wp_unslash( $_POST['post_type'] ) ); } $response = wp_list_pluck( get_terms( $args ), 'name', 'term_id' ); break; case 'user': $users = []; foreach ( get_users( [ 'include' => $ids ] ) as $user ) { $user_id = $user->ID; $user_name = $user->display_name; $users[ $user_id ] = $user_name; } $response = $users; break; default: $post_info = get_posts( [ 'post_type' => ! empty( $_POST['post_type'] ) ? sanitize_text_field( wp_unslash( $_POST['post_type'] ) ) : 'post', 'include' => implode( ',', $ids ) ] ); $response = wp_list_pluck( $post_info, 'post_title', 'ID' ); } if ( ! empty( $response ) ) { wp_send_json_success( [ 'results' => $response ] ); } else { wp_send_json_error( [] ); } } /** * Save Settings * Save EA settings data through ajax request * * @access public * @return void * @since 1.1.2 */ public function save_settings() { check_ajax_referer( 'essential-addons-elementor', 'security' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( __( 'you are not allowed to do this action', 'essential-addons-for-elementor-lite' ) ); } $settings = array_map( 'sanitize_text_field', $_POST ); unset( $settings['action'], $settings['security'] ); $settings['embedpress'] = true; $settings['career-page'] = true; $settings['better-payment'] = true; if ( ! empty( $_POST['is_login_register'] ) ) { // Saving Login | Register Related Data if ( isset( $settings['recaptchaSiteKey'] ) ) { update_option( 'eael_recaptcha_sitekey', sanitize_text_field( $settings['recaptchaSiteKey'] ) ); } if ( isset( $settings['recaptchaSiteSecret'] ) ) { update_option( 'eael_recaptcha_secret', sanitize_text_field( $settings['recaptchaSiteSecret'] ) ); } if ( isset( $settings['recaptchaLanguage'] ) ) { update_option( 'eael_recaptcha_language', sanitize_text_field( $settings['recaptchaLanguage'] ) ); } //reCAPTCHA V3 if ( isset( $settings['recaptchaSiteKeyV3'] ) ) { update_option( 'eael_recaptcha_sitekey_v3', sanitize_text_field( $settings['recaptchaSiteKeyV3'] ) ); } if ( isset( $settings['recaptchaSiteSecretV3'] ) ) { update_option( 'eael_recaptcha_secret_v3', sanitize_text_field( $settings['recaptchaSiteSecretV3'] ) ); } if ( isset( $settings['recaptchaLanguageV3'] ) ) { update_option( 'eael_recaptcha_language_v3', sanitize_text_field( $settings['recaptchaLanguageV3'] ) ); } //pro settings if ( isset( $settings['gClientId'] ) ) { update_option( 'eael_g_client_id', sanitize_text_field( $settings['gClientId'] ) ); } if ( isset( $settings['fbAppId'] ) ) { update_option( 'eael_fb_app_id', sanitize_text_field( $settings['fbAppId'] ) ); } if ( isset( $settings['fbAppSecret'] ) ) { update_option( 'eael_fb_app_secret', sanitize_text_field( $settings['fbAppSecret'] ) ); } wp_send_json_success( [ 'message' => __( 'Login | Register Settings updated', 'essential-addons-for-elementor-lite' ) ] ); } //Login-register data if ( isset( $settings['lr_recaptcha_sitekey'] ) ) { update_option( 'eael_recaptcha_sitekey', sanitize_text_field( $settings['lr_recaptcha_sitekey'] ) ); } if ( isset( $settings['lr_recaptcha_secret'] ) ) { update_option( 'eael_recaptcha_secret', sanitize_text_field( $settings['lr_recaptcha_secret'] ) ); } if ( isset( $settings['lr_recaptcha_language'] ) ) { update_option( 'eael_recaptcha_language', sanitize_text_field( $settings['lr_recaptcha_language'] ) ); } //Cloudflare Turnstile if ( isset( $settings['lr_cloudflare_turnstile_sitekey'] ) ) { update_option( 'eael_cloudflare_turnstile_sitekey', sanitize_text_field( $settings['lr_cloudflare_turnstile_sitekey'] ) ); } if ( isset( $settings['lr_cloudflare_turnstile_secretkey'] ) ) { update_option( 'eael_cloudflare_turnstile_secretkey', sanitize_text_field( $settings['lr_cloudflare_turnstile_secretkey'] ) ); } //reCAPTCHA v3 if ( isset( $settings['lr_recaptcha_sitekey_v3'] ) ) { update_option( 'eael_recaptcha_sitekey_v3', sanitize_text_field( $settings['lr_recaptcha_sitekey_v3'] ) ); } if ( isset( $settings['lr_recaptcha_secret_v3'] ) ) { update_option( 'eael_recaptcha_secret_v3', sanitize_text_field( $settings['lr_recaptcha_secret_v3'] ) ); } if ( isset( $settings['lr_recaptcha_language_v3'] ) ) { update_option( 'eael_recaptcha_language_v3', sanitize_text_field( $settings['lr_recaptcha_language_v3'] ) ); } if ( isset( $settings['lr_recaptcha_badge_hide'] ) ) { update_option( 'eael_recaptcha_badge_hide', sanitize_text_field( $settings['lr_recaptcha_badge_hide'] ) ); } if ( isset( $settings['lr_custom_profile_fields'] ) ) { update_option( 'eael_custom_profile_fields', sanitize_text_field( $settings['lr_custom_profile_fields'] ) ); } // Only save when request is from LR modal (lr_recaptcha_sitekey always present). // Without this guard the main "Save Settings" POST (no lr_* keys) would wipe the option. if ( array_key_exists( 'lr_recaptcha_sitekey', $settings ) ) { update_option( 'eael_lr_admin_approval', isset( $settings['lr_admin_approval'] ) ? sanitize_text_field( $settings['lr_admin_approval'] ) : '' ); } if ( isset( $settings['lr_custom_profile_fields_text'] ) ) { update_option( 'eael_custom_profile_fields_text', sanitize_text_field( $settings['lr_custom_profile_fields_text'] ) ); } if ( isset( $settings['lr_custom_profile_fields_img'] ) ) { update_option( 'eael_custom_profile_fields_img', sanitize_text_field( $settings['lr_custom_profile_fields_img'] ) ); } //pro settings if ( isset( $settings['lr_g_client_id'] ) ) { update_option( 'eael_g_client_id', sanitize_text_field( $settings['lr_g_client_id'] ) ); } if ( isset( $settings['lr_fb_app_id'] ) ) { update_option( 'eael_fb_app_id', sanitize_text_field( $settings['lr_fb_app_id'] ) ); } if ( isset( $settings['lr_fb_app_secret'] ) ) { update_option( 'eael_fb_app_secret', sanitize_text_field( $settings['lr_fb_app_secret'] ) ); } // Business Reviews : Saving Google Place Api Key if ( isset( $settings['br_google_place_api_key'] ) ) { update_option( 'eael_br_google_place_api_key', sanitize_text_field( $settings['br_google_place_api_key'] ) ); } // Saving Google Map Api Key if ( isset( $settings['google-map-api'] ) ) { update_option( 'eael_save_google_map_api', sanitize_text_field( $settings['google-map-api'] ) ); } // Saving Mailchimp Api Key if ( isset( $settings['mailchimp-api'] ) ) { update_option( 'eael_save_mailchimp_api', sanitize_text_field( $settings['mailchimp-api'] ) ); } // Saving Mailchimp Api Key for EA Login | Register Form if ( isset( $settings['lr_mailchimp_api_key'] ) ) { update_option( 'eael_lr_mailchimp_api_key', sanitize_text_field( $settings['lr_mailchimp_api_key'] ) ); } // Saving TYpeForm token if ( isset( $settings['typeform-personal-token'] ) ) { update_option( 'eael_save_typeform_personal_token', sanitize_text_field( $settings['typeform-personal-token'] ) ); } // Saving Duplicator Settings if ( isset( $settings['post-duplicator-post-type'] ) ) { update_option( 'eael_save_post_duplicator_post_type', sanitize_text_field( $settings['post-duplicator-post-type'] ) ); } // Saving Woo Acount Dashboard Settings if ( isset( $settings['woo-account-dashboard-custom-tabs'] ) ) { update_option( 'eael_woo_ac_dashboard_custom_tabs', sanitize_text_field( $settings['woo-account-dashboard-custom-tabs'] ) ); } // save js print method if ( isset( $settings['eael-js-print-method'] ) ) { update_option( 'eael_js_print_method', sanitize_text_field( $settings['eael-js-print-method'] ) ); } if ( ! empty( $settings['elements'] ) ) { $defaults = array_fill_keys( array_keys( array_merge( $this->registered_elements, $this->registered_extensions ) ), false ); $elements = array_merge( $defaults, array_fill_keys( array_keys( array_intersect_key( $settings, $defaults ) ), true ) ); $el_disable = get_option( 'elementor_disabled_elements', [] ); $new_disable = []; foreach ( $el_disable as $element ) { $el_new_name = Elements_Manager::replace_widget_name(); $el_new_name = $el_new_name[ $element ] ?? $element; $el_new_name = substr( $el_new_name, 5 ); if ( in_array( $el_new_name, $elements ) && $elements[ $el_new_name ] === true ) { continue; } $new_disable[] = $element; } // update new settings $updated = update_option( 'eael_save_settings', $elements ); update_option( 'elementor_disabled_elements', $new_disable ); // clear assets files $this->empty_dir( EAEL_ASSET_PATH ); } do_action( 'eael/admin/after_save_settings', $settings ); wp_send_json_success( true ); } /** * Clear Cache Files * Clear cache files from uploads/essential-addons-elementor * * @access public * @return void * @since 3.0.0 */ public function clear_cache_files() { check_ajax_referer( 'essential-addons-elementor', 'security' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( __( 'you are not allowed to do this action', 'essential-addons-for-elementor-lite' ) ); } if ( isset( $_REQUEST['posts'] ) ) { if ( ! empty( $_POST['posts'] ) ) { foreach ( json_decode( sanitize_text_field( wp_unslash( $_POST['posts'] ) ) ) as $post ) { $this->remove_files( 'post-' . $post ); } } } else { // clear cache files $this->empty_dir( EAEL_ASSET_PATH ); if ( $this->is_activate_elementor() ) { \Elementor\Plugin::$instance->files_manager->clear_cache(); } } // Purge All LS Cache // phpcs:disable do_action( 'litespeed_purge_all', '3rd Essential Addons for Elementor' ); // phpcs:enable // After clear the cache hook do_action( 'eael_after_clear_cache_files' ); wp_send_json( true ); } public function eael_admin_promotion(){ check_ajax_referer( 'essential-addons-elementor', 'security' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( __( 'you are not allowed to do this action', 'essential-addons-for-elementor-lite' ) ); } update_option( 'eael_admin_promotion', self::EAEL_PROMOTION_FLAG ); } /** * Get nonce token through ajax request * * @since 5.1.13 * @return void */ public function eael_get_token() { $nonce = wp_create_nonce( 'essential-addons-elementor' ); if ( $nonce ) { wp_send_json_success( [ 'nonce' => $nonce ] ); } wp_send_json_error( __( 'you are not allowed to do this action', 'essential-addons-for-elementor-lite' ) ); } public function eael_yith_wcwl_ajax_disable( $request ) { add_filter( 'option_yith_wcwl_ajax_enable', function ( $data ) { return 'no'; } ); } public function eael_ajax_add_to_cart() { check_ajax_referer( 'eael-ajax-add-to-cart', 'nonce' ); if ( ! function_exists( 'WC' ) ) { wp_send_json_error( [ 'message' => esc_html__( 'WooCommerce is not active.', 'essential-addons-for-elementor-lite' ) ] ); } // phpcs:disable WordPress.Security.NonceVerification.Missing -- nonce already checked above $product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0; $product_type = isset( $_POST['product_type'] ) ? sanitize_key( $_POST['product_type'] ) : 'simple'; // phpcs:enable if ( ! $product_id ) { wp_send_json_error( [ 'message' => esc_html__( 'Invalid product.', 'essential-addons-for-elementor-lite' ) ] ); } $added = false; if ( 'grouped' === $product_type ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing $quantities = isset( $_POST['quantity'] ) && is_array( $_POST['quantity'] ) ? $_POST['quantity'] : []; foreach ( $quantities as $child_id => $qty ) { $child_id = absint( $child_id ); $qty = absint( $qty ); if ( $child_id > 0 && $qty > 0 ) { WC()->cart->add_to_cart( $child_id, $qty ); $added = true; } } } elseif ( 'variable' === $product_type ) { // phpcs:disable WordPress.Security.NonceVerification.Missing $variation_id = isset( $_POST['variation_id'] ) ? absint( $_POST['variation_id'] ) : 0; $quantity = isset( $_POST['quantity'] ) ? absint( $_POST['quantity'] ) : 1; $attributes = []; foreach ( $_POST as $key => $value ) { if ( strpos( $key, 'attribute_' ) === 0 ) { $attributes[ sanitize_key( $key ) ] = sanitize_text_field( wp_unslash( $value ) ); } } // phpcs:enable if ( $variation_id ) { $added = WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $attributes ); } } else { // phpcs:ignore WordPress.Security.NonceVerification.Missing $quantity = isset( $_POST['quantity'] ) ? absint( $_POST['quantity'] ) : 1; $added = WC()->cart->add_to_cart( $product_id, $quantity ); } if ( false === $added ) { ob_start(); wc_print_notices(); $notices_html = ob_get_clean(); wp_send_json_error( [ 'notices' => $notices_html ] ); } WC()->cart->calculate_totals(); $fragments = apply_filters( 'woocommerce_add_to_cart_fragments', [] ); ob_start(); wc_print_notices(); $notices_html = ob_get_clean(); wp_send_json_success( [ 'fragments' => $fragments, 'cart_hash' => WC()->cart->get_cart_hash(), 'cart_count' => WC()->cart->get_cart_contents_count(), 'notices' => $notices_html, ] ); } }