logger = $logger; $this->configuration = $configuration; $this->product_service = $product_service; $this->payment_service = $payment_service; $this->payment_method_service = $payment_method_service; $this->i18n = $i18n; $this->regex = $regex; } /** * Handle the widget shortcode callback * [sequra_widget] * Expected attributes: * - product: The seQura product identifier. Required. * - campaign: The seQura campaign name. Optional. * - dest: A CSS selector to place the widget. Required. * - product_id: The WooCommerce product identifier. Required * - price: A CSS selector to get the product price. Optional. * - alt_price: An alternative CSS selector to retrieve the product price for special product page layouts. Optional. * - is_alt_price: A CSS selector to determine if the product has an alternative price. Optional. * - reg_amount: The registration amount. Optional. * - theme: The theme to use. Accepted values are: L, R, legacy, legacyL, legacyR, minimal, minimalL, minimalR or JSON formatted string. Optional. * * @param array $atts The shortcode attributes * @return string */ public function do_widget_shortcode( $atts ) { $this->logger->log_debug( 'Shortcode called', __FUNCTION__, __CLASS__ ); $atts = (array) $atts; // Check for required attributes. foreach ( array( 'product', 'product_id' ) as $required ) { if ( ! isset( $atts[ $required ] ) ) { $this->logger->log_error( "\"$required\" attribute is required", __FUNCTION__, __CLASS__ ); return ''; } } $current_country = $this->i18n->get_current_country(); $campaign = isset( $atts['campaign'] ) && '' !== $atts['campaign'] ? $atts['campaign'] : null; if ( ! $this->configuration->is_widget_enabled( $atts['product'], $campaign, $current_country ) ) { $this->logger->log_info( 'Widget is disabled', __FUNCTION__, __CLASS__ ); return ''; } // Replace old attribute names introduced in 2.0.0 with the new ones. $atts_replacements = array( 'variation_price' => 'alt_price', 'is_variable' => 'is_alt_price', ); foreach ( $atts_replacements as $old => $new ) { if ( isset( $atts[ $old ] ) ) { $atts[ $new ] = $atts[ $old ]; unset( $atts[ $old ] ); } } $atts = \shortcode_atts( array( 'product' => '', 'campaign' => '', 'product_id' => '', 'theme' => $this->configuration->get_widget_theme( $atts['product'], $campaign, $current_country ), 'reverse' => 0, 'reg_amount' => $this->product_service->get_registration_amount( (int) $atts['product_id'], true ), 'dest' => $this->configuration->get_widget_dest_css_sel( $atts['product'], $campaign, $current_country ), 'price' => $this->configuration->get_widget_price_css_sel(), 'alt_price' => $this->configuration->get_widget_alt_price_css_sel(), 'is_alt_price' => $this->configuration->get_widget_is_alt_price_css_sel(), ), $atts, 'sequra_widget' ); if ( ! $this->product_service->can_display_widget_for_method( (int) $atts['product_id'], $atts['product'] ) ) { $this->logger->log_info( 'Widget cannot be displayed for product', __FUNCTION__, __CLASS__, array( new LogContextData( 'payment_method', $atts['product'] ), new LogContextData( 'campaign', $atts['campaign'] ), new LogContextData( 'product_id', $atts['product_id'] ), ) ); return ''; } ob_start(); \wc_get_template( 'front/widget.php', $atts, '', $this->templates_path ); return ob_get_clean(); } /** * Handle the cart widget shortcode callback * * @param array $atts The shortcode attributes * @return string */ public function do_cart_widget_shortcode( $atts ) { $this->logger->log_debug( 'Shortcode called', __FUNCTION__, __CLASS__ ); $atts = (array) $atts; $current_country = $this->i18n->get_current_country(); if ( ! $this->configuration->is_cart_widget_enabled( $current_country ) ) { $this->logger->log_info( 'Cart Widget is disabled', __FUNCTION__, __CLASS__, array( new LogContextData( 'country', $current_country ) ) ); return ''; } if ( ! $this->product_service->can_display_mini_widgets() ) { $this->logger->log_info( 'SeQura payment gateway is disabled', __FUNCTION__, __CLASS__ ); return ''; } try { $store_id = $this->configuration->get_store_id(); $merchant = $this->payment_service->get_merchant_id(); $methods = $this->payment_method_service->get_all_mini_widget_compatible_payment_methods( $store_id, $merchant ); $config = $this->configuration->get_cart_widget_config( $current_country ); if ( ! $config ) { $this->logger->log_info( 'Cart Widget configuration not found', __FUNCTION__, __CLASS__, array( new LogContextData( 'country', $current_country ) ) ); return ''; } foreach ( $methods as $method ) { if ( $method['product'] !== $config['product'] ) { continue; } $atts = \shortcode_atts( array( 'product' => $method['product'] ?? '', 'campaign' => $method['campaign'] ?? '', 'dest' => $config['selForLocation'], 'price' => $config['selForPrice'], 'message' => $config['message'], 'message_below_limit' => $config['messageBelowLimit'], 'min_amount' => $method['minAmount'] ?? 0, 'max_amount' => $method['maxAmount'] ?? null, ), $atts, 'sequra_cart_widget' ); ob_start(); \wc_get_template( 'front/mini_widget.php', $atts, '', $this->templates_path ); return ob_get_clean(); } } catch ( \Throwable $e ) { $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ ); } return ''; } /** * Handle the product listing widget shortcode callback * * @param array $atts The shortcode attributes * @return string */ public function do_product_listing_widget_shortcode( $atts ) { $this->logger->log_debug( 'Shortcode called', __FUNCTION__, __CLASS__ ); $atts = (array) $atts; $current_country = $this->i18n->get_current_country(); if ( ! $this->configuration->is_product_listing_widget_enabled( $current_country ) ) { $this->logger->log_info( 'Product listing Widget is disabled', __FUNCTION__, __CLASS__, array( new LogContextData( 'country', $current_country ) ) ); return ''; } if ( ! $this->product_service->can_display_mini_widgets() ) { $this->logger->log_info( 'SeQura payment gateway is disabled', __FUNCTION__, __CLASS__ ); return ''; } try { $store_id = $this->configuration->get_store_id(); $merchant = $this->payment_service->get_merchant_id(); $methods = $this->payment_method_service->get_all_mini_widget_compatible_payment_methods( $store_id, $merchant ); $config = $this->configuration->get_product_listing_widget_config( $current_country ); if ( ! $config ) { $this->logger->log_info( 'Product listing Widget configuration not found', __FUNCTION__, __CLASS__, array( new LogContextData( 'country', $current_country ) ) ); return ''; } foreach ( $methods as $method ) { if ( $method['product'] !== $config['product'] ) { continue; } $atts = \shortcode_atts( array( 'product' => $method['product'] ?? '', 'campaign' => $method['campaign'] ?? '', 'dest' => $config['selForLocation'], 'price' => $config['selForPrice'], 'message' => $config['message'], 'message_below_limit' => $config['messageBelowLimit'], 'min_amount' => $method['minAmount'] ?? 0, 'max_amount' => $method['maxAmount'] ?? null, ), $atts, 'sequra_product_listing_widget' ); ob_start(); \wc_get_template( 'front/mini_widget.php', $atts, '', $this->templates_path ); return ob_get_clean(); } } catch ( \Throwable $e ) { $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ ); } return ''; } /** * Add [sequra_widget] to product page automatically */ private function add_widget_shortcode_to_product_page(): void { if ( ! \is_product() ) { return; } /** * The current product. * * @var WC_Product $product */ global $product; $methods = array(); try { $store_id = $this->configuration->get_store_id(); $merchant = $this->payment_service->get_merchant_id(); $methods = $this->payment_method_service->get_all_widget_compatible_payment_methods( $store_id, $merchant ); } catch ( \Throwable $e ) { $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ ); return; } foreach ( $methods as $method ) { if ( ! $this->product_service->can_display_widget_for_method( $product, $method ) ) { continue; } $atts = array( 'product' => $method['product'] ?? '', 'campaign' => $method['campaign'] ?? '', 'product_id' => $product->get_id(), ); $atts_str = ''; foreach ( $atts as $key => $value ) { $atts_str .= " $key=\"$value\""; } echo \do_shortcode( "[sequra_widget $atts_str]" ); } } /** * Add [sequra_cart_widget] to product page automatically */ private function add_widget_shortcode_to_cart_page(): void { if ( ! \is_cart() ) { return; } echo \do_shortcode( '[sequra_cart_widget]' ); } /** * Add [sequra_product_listing_widget] to product archive automatically */ private function add_widget_shortcode_to_product_listing_page(): void { if ( ! \is_product_category() && ! \is_product_tag() && ! \is_shop() ) { return; } echo \do_shortcode( '[sequra_product_listing_widget]' ); } /** * Add [sequra_widget] to product page automatically * Add [sequra_cart_widget] to cart page automatically * * @return void */ public function add_widget_shortcode_to_page() { $this->logger->log_debug( 'Hook executed', __FUNCTION__, __CLASS__ ); if ( \did_action( 'before_woocommerce_sequra_add_widget_to_page' ) ) { return; } /** * Fires before the SeQura widget is added to the page to prevent multiple executions. * * @since 3.0.0 */ \do_action( 'before_woocommerce_sequra_add_widget_to_page' ); $this->add_widget_shortcode_to_product_page(); $this->add_widget_shortcode_to_cart_page(); $this->add_widget_shortcode_to_product_listing_page(); } /** * Add meta boxes to the product edit page * * @return void */ public function add_meta_boxes() { \add_meta_box( 'sequra_settings', esc_html__( 'seQura settings', 'sequra' ), array( $this, 'render_meta_boxes' ), 'product', 'side', 'default' ); } /** * Render the meta boxes * * @param WP_Post $post The post object * @return void */ public function render_meta_boxes( $post ) { $args = array( 'is_banned' => $this->product_service->get_is_banned( $post->ID ), 'is_banned_field_name' => self::FIELD_NAME_IS_BANNED, 'enabled_for_services' => $this->configuration->is_enabled_for_services(), 'is_service' => $this->product_service->is_service( $post->ID ), 'is_service_field_name' => self::FIELD_NAME_IS_SERVICE, 'service_end_date_default' => $this->configuration->get_default_services_end_date(), 'service_end_date' => $this->product_service->get_service_end_date( $post->ID, true ), 'service_end_date_field_name' => self::FIELD_NAME_SERVICE_END_DATE, 'allow_payment_delay' => $this->configuration->allow_first_service_payment_delay(), 'service_desired_first_charge_date' => $this->product_service->get_desired_first_charge_date( $post->ID, true ) ?? '', 'service_desired_first_charge_date_field_name' => self::FIELD_NAME_SERVICE_DESIRED_FIRST_CHARGE_DATE, 'date_or_duration_regex' => $this->regex->date_or_duration( false ), 'allow_registration_items' => $this->configuration->allow_service_reg_items(), 'service_registration_amount' => $this->product_service->get_registration_amount( $post->ID ), 'service_registration_amount_field_name' => self::FIELD_NAME_REGISTRATION_AMOUNT, 'nonce_name' => self::NONCE_SEQURA_PRODUCT, ); \wc_get_template( 'admin/product_metabox.php', $args, '', $this->templates_path ); } /** * Save product meta * * @param int $post_id The post ID * @return void */ public function save_product_meta( $post_id ) { if ( ! isset( $_POST[ self::NONCE_SEQURA_PRODUCT ] ) || ! \wp_verify_nonce( $_POST[ self::NONCE_SEQURA_PRODUCT ], -1 ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized || ! \current_user_can( 'edit_post', $post_id ) || \wp_doing_ajax() ) { return; } $this->product_service->set_is_banned( $post_id, isset( $_POST[ self::FIELD_NAME_IS_BANNED ] ) ? \sanitize_text_field( \wp_unslash( $_POST[ self::FIELD_NAME_IS_BANNED ] ) ) : null ); $this->product_service->set_is_service( $post_id, isset( $_POST[ self::FIELD_NAME_IS_SERVICE ] ) ? \sanitize_text_field( \wp_unslash( $_POST[ self::FIELD_NAME_IS_SERVICE ] ) ) : null ); $this->product_service->set_service_end_date( $post_id, ! empty( $_POST[ self::FIELD_NAME_SERVICE_END_DATE ] ) ? \sanitize_text_field( \wp_unslash( $_POST[ self::FIELD_NAME_SERVICE_END_DATE ] ) ) : null ); $this->product_service->set_desired_first_charge_date( $post_id, ! empty( $_POST[ self::FIELD_NAME_SERVICE_DESIRED_FIRST_CHARGE_DATE ] ) ? \sanitize_text_field( \wp_unslash( $_POST[ self::FIELD_NAME_SERVICE_DESIRED_FIRST_CHARGE_DATE ] ) ) : null ); $this->product_service->set_registration_amount( $post_id, ! empty( $_POST[ self::FIELD_NAME_REGISTRATION_AMOUNT ] ) ? \sanitize_text_field( \wp_unslash( $_POST[ self::FIELD_NAME_REGISTRATION_AMOUNT ] ) ) : null ); } }