<?php /** * "WooCommerce Product" ACFE Form Action Class. * * Handles the "WooCommerce Product" ACFE Form Action. * * @package Conditional_Form_Actions_For_ACFE */ // Exit if accessed directly. defined( 'ABSPATH' ) || exit; /** * CiviCRM Profile Sync "WooCommerce Product" ACFE Form Action Class. * * A class that handles the "WooCommerce Product" ACFE Form Action. * * @since 0.1 */ class CFAFA_Form_Action_Product extends CFAFA_Form_Action_Base { /** * Plugin object. * * @since 0.1 * @access public * @var Conditional_Form_Actions_For_ACFE */ public $plugin; /** * ACFE object. * * @since 0.1 * @access public * @var CFAFA_ACFE */ public $acfe; /** * Form Action Name. * * @since 0.1 * @access public * @var string */ public $action_name = 'woo_cfafa_product'; /** * Field Key Prefix. * * @since 0.1 * @access public * @var string */ public $field_key = 'field_cfafa_woo_product_'; /** * Field Name Prefix. * * @since 0.1 * @access public * @var string */ public $field_name = 'cfafa_woo_product_'; /** * Constructor. * * @since 0.1 * * @param object $parent The parent object reference. */ public function __construct( $parent ) { // Store references to objects. $this->plugin = $parent->plugin; $this->acfe = $parent; // Label this Form Action. $this->action_label = __( 'WooCommerce Product action', 'conditional-form-actions-for-acfe' ); // Alias Placeholder for this Form Action. $this->alias_placeholder = __( 'WooCommerce Product', 'conditional-form-actions-for-acfe' ); // Init parent. parent::__construct(); } /** * Configure this object. * * @since 0.1 */ public function configure() { // WooCommerce Product Conditional Field. $this->mapping_field_filters_add( 'product_conditional' ); } /** * Performs the action when the Form the Action is attached to is submitted. * * @since 0.1 * * @param array $form The array of Form data. * @param integer $current_post_id The ID of the Post from which the Form has been submitted. * @param string $action The customised name of the action. */ public function make( $form, $current_post_id, $action ) { // Bail if a filter has overridden the action. if ( false === $this->make_skip( $form, $current_post_id, $action ) ) { return; } // Get some Form details. $form_name = acf_maybe_get( $form, 'name' ); $form_id = acf_maybe_get( $form, 'ID' ); // Populate Product data array. $product_data = $this->form_product_data( $form, $current_post_id, $action ); // Act with the data from the Form. $product_data = $this->form_product_save( $product_data ); // Save the results of this Action for later use. $this->make_action_save( $action, $product_data ); } /** * Defines additional Fields for the "Action" Tab. * * @since 0.1 * * @return array $fields The array of Fields for this section. */ public function tab_action_append() { // Init Fields. $fields = []; $fields[] = [ 'key' => $this->field_key . 'product_id', 'label' => __( 'WooCommerce Product', 'conditional-form-actions-for-acfe' ), 'name' => $this->field_name . 'product_id', 'type' => 'select', 'instructions' => __( 'Use this to add a WooCommerce Product to the Cart.', 'conditional-form-actions-for-acfe' ), 'required' => 0, 'conditional_logic' => 0, 'wrapper' => [ 'width' => '', 'class' => '', 'id' => '', 'data-instruction-placement' => 'field', ], 'acfe_permissions' => '', 'default_value' => '', 'placeholder' => '', 'allow_null' => 1, 'multiple' => 0, 'ui' => 0, // 'ajax' => 1, // 'ajax_action' => 'cfafa_get_products', 'return_format' => 'value', 'choices' => $this->product_choices_get(), ]; // Add Conditional Field. $code = 'product_conditional'; $label = __( 'Conditional On', 'conditional-form-actions-for-acfe' ); $conditional = $this->mapping_field_get( $code, $label ); $conditional['placeholder'] = __( 'Always add', 'conditional-form-actions-for-acfe' ); $conditional['wrapper']['data-instruction-placement'] = 'field'; $conditional['instructions'] = __( 'To add the Product to the Cart only when a Form Field is populated (e.g. "First Name") link this to the Form Field. To add the Product to the Cart only when more complex conditions are met, link this to a Hidden Field with value "1" where the conditional logic of that Field shows it when the conditions are met.', 'conditional-form-actions-for-acfe' ); $fields[] = $conditional; // --< return $fields; } /** * Builds Product data array from mapped Fields. * * @since 0.1 * * @param array $form The array of Form data. * @param integer $current_post_id The ID of the Post from which the Form has been submitted. * @param string $action The customised name of the action. * @return array $data The array of Product data. */ public function form_product_data( $form, $current_post_id, $action ) { // Add Product ID. $data['product_id'] = get_sub_field( $this->field_key . 'product_id' ); // Get Product Conditional Reference. $data['product_conditional_ref'] = get_sub_field( $this->field_key . 'map_product_conditional' ); $conditionals = [ $data['product_conditional_ref'] ]; // Populate array with mapped Conditional Field values. $conditionals = acfe_form_map_vs_fields( $conditionals, $conditionals, $current_post_id, $form ); // Save Product Conditional. $data['product_conditional'] = array_pop( $conditionals ); // --< return $data; } /** * Sends the WooCommerce Product given data from mapped Fields. * * @since 0.1 * * @param array $product_data The array of Product data. * @return array|bool $product_data The Product data array, or false on failure. */ public function form_product_save( $product_data ) { // Skip if the Product Conditional Reference Field has a value. if ( ! empty( $product_data['product_conditional_ref'] ) ) { // And the Product Conditional Field has no value. if ( empty( $product_data['product_conditional'] ) ) { return $product_data; } } // Unset Product Conditionals. if ( isset( $product_data['product_conditional'] ) ) { unset( $product_data['product_conditional'] ); } if ( isset( $product_data['product_conditional_ref'] ) ) { unset( $product_data['product_conditional_ref'] ); } // Strip out empty Fields. $product_data = $this->form_data_prepare( $product_data ); // Sanity check. if ( empty( $product_data['product_id'] ) ) { return false; } // Add the Product to the WooCommerce Cart. $result = $this->product_add_to_cart( $product_data ); // Bail on failure. if ( false === $result ) { return false; } // Add Cart Item key to Product data. $product_data['cart_item_key'] = $result; // --< return $product_data; } /** * Gets the WooCommerce Products as an array of options for ACF. * * @since 0.1 * * @return array $options The array of Products formatted for ACF. */ public function product_choices_get() { // Init return. $options = []; /* * Build params to get all published Products. * * We have to query directly because WooCommerce has not been initialised * at this point and wc_get_products() does not return any results. This * is because ACF hooks into `init` with priority 5 *before* WooCommerce * initialises. * * This may need to be looked at again in future. */ $args = [ 'post_type' => 'product', 'post_status' => [ 'publish' ], 'no_found_rows' => true, 'posts_per_page' => -1, ]; // Do query. $query = new WP_Query( $args ); // Do the loop. if ( $query->have_posts() ) { foreach ( $query->get_posts() as $found ) { $options[ $found->ID ] = $found->post_title; } } // Reset Post data just in case. wp_reset_postdata(); // --< return $options; } /** * Adds the Product to the Cart. * * @since 0.1 * * @param array $product_data The array of Product data. * @return integer|bool $cart_item_key The key of the Cart Item, or false otherwise. */ public function product_add_to_cart( $product_data ) { // Get the Product. $product = wc_get_product( $product_data['product_id'] ); // Sanity check. if ( empty( $product ) ) { return false; } // Some defaults. $product_id = $product->get_id(); $quantity = 1; $variation_id = 0; $variation = []; $cart_item_data = []; // Build Cart Item data? // Add the configured Product to the Cart. $cart_item_key = WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation, $cart_item_data ); // --< return $cart_item_key; } }