', 'wp-block-woocommerce-checkout wc-gzd-checkout ', $content ); preg_match( '/<\/div>(\s*)(\s*)(\s*)<\/div>$/', $content, $matches ); if ( ! empty( $matches ) ) { $replacement = '
'; $content = preg_replace( '/<\/div>(\s*)<\/div>$/', $replacement, $content ); } } } if ( WC()->session ) { WC()->session->set( 'checkout_checkboxes_checked', array() ); WC()->session->set( 'gzd_is_checkout_checkout', true ); } } elseif ( 'woocommerce/cart' === $block['blockName'] ) { if ( WC()->session ) { WC()->session->set( 'gzd_is_checkout_checkout', false ); } } return $content; }, 1000, 2 ); } private function register_integrations() { add_action( 'woocommerce_blocks_checkout_block_registration', function ( $integration_registry ) { $integration_registry->register( new \Vendidero\Germanized\Blocks\Integrations\Checkout() ); } ); add_action( 'woocommerce_blocks_payment_method_type_registration', function ( $payment_method_registry ) { $payment_method_registry->register( Package::container()->get( Invoice::class ) ); $payment_method_registry->register( Package::container()->get( DirectDebit::class ) ); } ); } private function register_endpoint_data() { woocommerce_store_api_register_endpoint_data( array( 'endpoint' => CartSchema::IDENTIFIER, 'namespace' => 'woocommerce-germanized', 'data_callback' => function () { return $this->get_cart_data(); }, 'schema_callback' => function () { return $this->get_cart_schema(); }, ) ); woocommerce_store_api_register_endpoint_data( array( 'endpoint' => CheckoutSchema::IDENTIFIER, 'namespace' => 'woocommerce-germanized', 'schema_callback' => function () { return $this->get_checkout_schema(); }, ) ); woocommerce_store_api_register_update_callback( array( 'namespace' => 'woocommerce-germanized-checkboxes', 'callback' => function ( $data ) { $checkboxes = isset( $data['checkboxes'] ) ? (array) wc_clean( wp_unslash( $data['checkboxes'] ) ) : array(); $this->parse_checkboxes( $checkboxes ); }, ) ); woocommerce_store_api_register_update_callback( array( 'namespace' => 'woocommerce-germanized-set-payment-method', 'callback' => function ( $data ) { $active_method = isset( $data['active_method'] ) ? wc_clean( wp_unslash( $data['active_method'] ) ) : ''; WC()->session->set( 'wc_gzd_blocks_chosen_payment_method', $active_method ); }, ) ); } private function register_validation_and_storage() { $wc_version = defined( 'WC_VERSION' ) ? WC_VERSION : false; $hook_name = '__experimental_woocommerce_blocks_validate_location_address_fields'; if ( $wc_version && version_compare( $wc_version, '8.9.0', '>=' ) ) { $hook_name = 'woocommerce_blocks_validate_location_address_fields'; } add_action( $hook_name, function ( $errors, $fields, $group ) { if ( 'never' !== get_option( 'woocommerce_gzd_checkout_validate_street_number' ) && function_exists( 'wc_gzd_split_shipment_street' ) ) { if ( 'billing' === $group && ! apply_filters( 'woocommerce_gzd_checkout_validate_billing_street_number', true ) ) { return $errors; } $country = isset( $fields['country'] ) ? $fields['country'] : $fields[ "{$group}_country" ]; $address_1 = isset( $fields['address_1'] ) ? $fields['address_1'] : $fields[ "{$group}_address_1" ]; /** * Somehow Woo calls the filter differently on my account address save action * by handing over the registered fields instead of the actual values. */ if ( is_array( $country ) ) { $country = isset( $_POST[ $group . '_country' ] ) ? wc_clean( wp_unslash( $_POST[ $group . '_country' ] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing $address_1 = isset( $_POST[ $group . '_address_1' ] ) ? wc_clean( wp_unslash( $_POST[ $group . '_address_1' ] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing } if ( ! empty( $country ) && ! empty( $address_1 ) && apply_filters( 'woocommerce_gzd_checkout_validate_street_number', true, $fields ) ) { $countries = array(); if ( 'always' === get_option( 'woocommerce_gzd_checkout_validate_street_number' ) ) { $countries = array_keys( WC()->countries->get_allowed_countries() ); } elseif ( 'base_only' === get_option( 'woocommerce_gzd_checkout_validate_street_number' ) ) { $countries = array( wc_gzd_get_base_country() ); } elseif ( 'eu_only' === get_option( 'woocommerce_gzd_checkout_validate_street_number' ) ) { $countries = WC()->countries->get_european_union_countries(); } $is_valid = true; if ( in_array( $country, $countries, true ) ) { $address_parts = wc_gzd_split_shipment_street( $address_1 ); $is_valid = '' === $address_parts['number'] ? false : true; } if ( ! apply_filters( 'woocommerce_gzd_checkout_is_valid_street_number', $is_valid, $fields ) ) { $errors->add( 'invalid_address_1', apply_filters( 'woocommerce_gzd_checkout_invalid_street_number_error_message', __( 'Please check the street field and make sure to provide a valid street number.', 'woocommerce-germanized' ), $fields ) ); } } } return $errors; }, 10, 3 ); add_action( 'woocommerce_store_api_checkout_update_customer_from_request', function ( $customer, $request ) { if ( 'never' !== get_option( 'woocommerce_gzd_checkout_validate_street_number' ) ) { $billing = $request['billing_address']; $shipping = $request['shipping_address']; if ( ! empty( $billing['address_1'] ) ) { $customer->set_billing_address_1( \WC_GZD_Checkout::instance()->format_address_1( $billing['address_1'] ) ); } if ( ! empty( $shipping['address_1'] ) ) { $customer->set_shipping_address_1( \WC_GZD_Checkout::instance()->format_address_1( $shipping['address_1'] ) ); } } }, 10, 2 ); /** * This hook does not contain any request data, therefor has only limited value. */ add_action( 'woocommerce_store_api_checkout_update_order_meta', function ( $order ) { \WC_GZD_Checkout::instance()->order_meta( $order ); }, 5 ); add_action( 'woocommerce_store_api_checkout_update_order_from_request', function ( $order, $request ) { $this->validate( $order, $request ); \WC_GZD_Checkout::instance()->order_store_checkbox_data( $order ); \WC_GZD_Checkout::instance()->add_order_notes( $order ); }, 10, 2 ); } private function get_cart_schema() { return array( 'applies_for_photovoltaic_system_vat_exempt' => array( 'description' => __( 'Whether the cart applies for a photovoltaic system vat exempt or not.', 'woocommerce-germanized' ), 'type' => 'boolean', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'photovoltaic_system_law_details' => array( 'description' => __( 'The current cart\'s photovoltaic system law details.', 'woocommerce-germanized' ), 'type' => 'object', 'context' => array( 'view', 'edit' ), 'readonly' => true, 'properties' => array( 'text' => array( 'description' => __( 'The actual law, e.g. paragraph.', 'woocommerce-germanized' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'url' => array( 'description' => __( 'The URL to the law.', 'woocommerce-germanized' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), ), ), 'shipping_costs_notice' => array( 'description' => __( 'Cart shipping costs notice.', 'woocommerce-germanized' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'checkboxes' => array( 'description' => __( 'List of cart checkboxes.', 'woocommerce-germanized' ), 'type' => 'array', 'context' => array( 'view', 'edit' ), 'readonly' => true, 'items' => array( 'type' => 'object', 'properties' => array( 'id' => array( 'description' => __( 'Unique identifier for the checkbox within the cart.', 'woocommerce-germanized' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'name' => array( 'description' => __( 'Checkbox name.', 'woocommerce-germanized' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'label' => array( 'description' => __( 'Checkbox label.', 'woocommerce-germanized' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'default_checked' => array( 'description' => __( 'Checkbox checked status.', 'woocommerce-germanized' ), 'type' => 'boolean', 'context' => array( 'view', 'edit' ), 'default' => false, ), 'default_hidden' => array( 'description' => __( 'Checkbox hidden by default.', 'woocommerce-germanized' ), 'type' => 'boolean', 'context' => array( 'view', 'edit' ), 'default' => false, ), 'error_message' => array( 'description' => __( 'Checkbox error message.', 'woocommerce-germanized' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'show_for_payment_methods' => array( 'description' => __( 'Show for specific payment methods only.', 'woocommerce-germanized' ), 'type' => 'array', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'wrapper_classes' => array( 'description' => __( 'Wrapper classes.', 'woocommerce-germanized' ), 'type' => 'array', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'custom_styles' => array( 'description' => __( 'Custom styles.', 'woocommerce-germanized' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'html_id' => array( 'description' => __( 'HTML field id.', 'woocommerce-germanized' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'has_checkbox' => array( 'description' => __( 'Whether to show a checkbox field or not.', 'woocommerce-germanized' ), 'type' => 'boolean', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'is_required' => array( 'description' => __( 'Whether the checkbox is required or not.', 'woocommerce-germanized' ), 'type' => 'boolean', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), ), ), ), ); } private function get_cart_data() { $checkboxes_for_api = array(); $checkboxes_force_print = array( 'privacy' ); $customer = wc()->customer; foreach ( $this->get_checkboxes() as $id => $checkbox ) { if ( ! $checkbox->is_printable() && ! in_array( $checkbox->get_id(), apply_filters( 'woocommerce_gzd_checkout_block_checkboxes_force_print_checkboxes', $checkboxes_force_print ), true ) ) { continue; } $checkboxes_for_api[] = array( 'id' => $id, 'name' => $checkbox->get_html_name(), 'label' => $checkbox->get_label(), 'wrapper_classes' => array_diff( $checkbox->get_html_wrapper_classes(), array( 'validate-required', 'form-row' ) ), 'custom_styles' => $checkbox->get_html_style(), 'error_message' => $checkbox->get_error_message( true ), 'html_id' => $checkbox->get_html_id(), 'has_checkbox' => ! $checkbox->hide_input(), 'show_for_payment_methods' => $checkbox->get_show_for_payment_methods(), 'is_required' => $checkbox->is_mandatory(), 'default_checked' => $checkbox->hide_input() ? true : false, 'default_hidden' => $checkbox->is_hidden(), ); } return array( 'applies_for_photovoltaic_system_vat_exempt' => wc_gzd_cart_applies_for_photovoltaic_system_vat_exemption(), 'photovoltaic_system_law_details' => wc_gzd_cart_get_photovoltaic_systems_law_details(), 'checkboxes' => $checkboxes_for_api, 'shipping_costs_notice' => wc_gzd_get_shipping_costs_text(), ); } private function get_checkout_schema() { return array( 'checkboxes' => array( 'description' => __( 'List of cart checkboxes.', 'woocommerce-germanized' ), 'type' => array( 'array', 'null' ), 'context' => array( 'view', 'edit' ), 'items' => array( 'type' => 'object', 'properties' => array( 'id' => array( 'description' => __( 'Unique identifier for the checkbox within the cart.', 'woocommerce-germanized' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'checked' => array( 'description' => __( 'Checkbox checked status.', 'woocommerce-germanized' ), 'type' => 'boolean', 'context' => array( 'view', 'edit' ), ), ), ), ), ); } private function get_checkboxes() { add_filter( 'woocommerce_gzd_get_checkout_value', function ( $value, $key ) { $getter = "get_{$key}"; $customer = wc()->customer; if ( is_callable( array( $customer, $getter ) ) ) { $value = $customer->{ $getter }(); } return $value; }, 10, 2 ); $checkbox_manager = \WC_GZD_Legal_Checkbox_Manager::instance(); return $checkbox_manager->get_checkboxes( array( 'locations' => 'checkout', 'sort' => true, ), 'render' ); } private function parse_checkboxes( $checkboxes ) { $checkbox_manager = \WC_GZD_Legal_Checkbox_Manager::instance(); $checkboxes_checked = array(); foreach ( $checkboxes as $checkbox_data ) { $checkbox_data = wp_parse_args( $checkbox_data, array( 'id' => '', 'checked' => false, ) ); $checkbox = $checkbox_manager->get_checkbox( $checkbox_data['id'] ); if ( ! $checkbox ) { continue; } if ( true === filter_var( $checkbox_data['checked'], FILTER_VALIDATE_BOOLEAN ) ) { $checkboxes_checked[] = $checkbox_data['id']; } } WC()->session->set( 'checkout_checkboxes_checked', $checkboxes_checked ); return $checkboxes_checked; } /** * @param \WC_Order $order * @param \WP_REST_Request $request * * @return void */ private function validate( $order, $request ) { WC()->session->set( 'checkout_checkboxes_checked', array() ); $data = $this->get_checkout_data_from_request( $request ); if ( $this->has_checkout_data( 'checkboxes', $request ) ) { $checkboxes_checked = $this->parse_checkboxes( $data['checkboxes'] ); foreach ( $this->get_checkboxes() as $id => $checkbox ) { if ( ! $checkbox->validate( in_array( $id, $checkboxes_checked, true ) ? 'yes' : '' ) ) { throw new RouteException( esc_html( "checkbox_{$id}" ), wp_kses_post( $checkbox->get_error_message() ), 400 ); } } } } private function has_checkout_data( $param, $request ) { $request_data = isset( $request['extensions']['woocommerce-germanized'] ) ? (array) $request['extensions']['woocommerce-germanized'] : array(); return isset( $request_data[ $param ] ) && null !== $request_data[ $param ]; } /** * @param \WP_REST_Request $request * * @return array */ private function get_checkout_data_from_request( $request ) { $data = array_filter( (array) wc_clean( $request['extensions']['woocommerce-germanized'] ) ); $data = wp_parse_args( $data, array( 'checkboxes' => array(), ) ); return $data; } }