Skip to content
Snippets Groups Projects
cfafa-form-action-product.php 8.74 KiB
Newer Older
Christian Wach's avatar
Christian Wach committed
<?php
/**
 * "WooCommerce Product" ACFE Form Action Class.
 *
 * Handles the "WooCommerce Product" ACFE Form Action.
 *
 * @package Conditional_Form_Actions_For_ACFE
 * @since 0.1
 */

// 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 object $plugin The plugin object.
	 */
	public $plugin;

	/**
	 * Parent (calling) object.
	 *
	 * @since 0.1
	 * @access public
	 * @var object $acf The parent object.
	 */
	public $acfe;

	/**
	 * Form Action Name.
	 *
	 * @since 0.1
	 * @access public
	 * @var string $action_name The unique name of the Form Action.
	 */
	public $action_name = 'woo_cfafa_product';

	/**
	 * Field Key Prefix.
	 *
	 * @since 0.1
	 * @access public
	 * @var string $field_key The prefix for the Field Key.
	 */
	public $field_key = 'field_cfafa_woo_product_';

	/**
	 * Field Name Prefix.
	 *
	 * @since 0.1
	 * @access public
	 * @var string $field_name The prefix for the Field Name.
	 */
	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.
Christian Wach's avatar
Christian Wach committed
		$product_data = $this->form_product_data( $form, $current_post_id, $action );
Christian Wach's avatar
Christian Wach committed

		// 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.
	 */
Christian Wach's avatar
Christian Wach committed
	public function form_product_data( $form, $current_post_id, $action ) {
Christian Wach's avatar
Christian Wach committed

		// 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 ( $result === false ) {
			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;

	}

} // Class ends.