From 9f3da56af876509d322e49741ceee3fb0432540a Mon Sep 17 00:00:00 2001 From: Christian Wach <needle@haystack.co.uk> Date: Mon, 29 Nov 2021 15:18:05 +0000 Subject: [PATCH] Initial commit --- README.md | 27 +- conditional-form-actions-for-acfe.php | 241 ++++++ cwps-acf-acfe-form.php | 608 +++++++++++++ includes/cfafa-acfe.php | 131 +++ .../form-actions/cfafa-form-action-base.php | 498 +++++++++++ .../form-actions/cfafa-form-action-email.php | 815 ++++++++++++++++++ .../cfafa-form-action-product.php | 349 ++++++++ .../cfafa-form-action-redirect.php | 278 ++++++ 8 files changed, 2946 insertions(+), 1 deletion(-) create mode 100644 conditional-form-actions-for-acfe.php create mode 100644 cwps-acf-acfe-form.php create mode 100644 includes/cfafa-acfe.php create mode 100644 includes/form-actions/cfafa-form-action-base.php create mode 100644 includes/form-actions/cfafa-form-action-email.php create mode 100644 includes/form-actions/cfafa-form-action-product.php create mode 100644 includes/form-actions/cfafa-form-action-redirect.php diff --git a/README.md b/README.md index 7987d9d..c1b45f1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,28 @@ # Conditional Form Actions for ACFE -Adds some Form Actions to ACFE that have a Conditional Field through which the Action can be bypassed. \ No newline at end of file +Adds some Form Actions to *ACF Extended* that have a Conditional Field through which the Action can be bypassed. + +## Basic Usage + +When creating an *ACF Extended* Form, you will see some new Form Actions: + +* _Conditional Redirect action_ +* _Conditional Email action_ +* _WooCommerce Product action_ + +Add them to your *ACF Extended* Form to make use of the functionality that they offer. + +## Installation + +There are two ways to install from GitLab: + +### ZIP Download + +If you have downloaded *Conditional Form Actions for ACFE* as a ZIP file from the GitLab repository, do the following to install the plugin: + +1. Unzip the .zip file and, if needed, rename the enclosing folder so that the plugin's files are located directly inside `/wp-content/plugins/conditional-form-actions-for-acfe` +2. *Conditional Form Actions for ACFE* is installed. + +### git clone + +If you have cloned the code from GitLab, it is assumed that you know what you're doing. diff --git a/conditional-form-actions-for-acfe.php b/conditional-form-actions-for-acfe.php new file mode 100644 index 0000000..737e669 --- /dev/null +++ b/conditional-form-actions-for-acfe.php @@ -0,0 +1,241 @@ +<?php /* +-------------------------------------------------------------------------------- +Plugin Name: Conditional Form Actions for ACFE +Plugin URI: https://develop.tadpole.cc/plugins/conditional-form-actions-for-acfe +Description: Provides some ACF Extended Form Actions that have a Conditional Field. +Author: Christian Wach +Version: 0.1 +Author URI: https://haystack.co.uk +Text Domain: conditional-form-actions-for-acfe +Domain Path: /languages +-------------------------------------------------------------------------------- +*/ + +// Set plugin version here. +define( 'CFAFA_VERSION', '0.1' ); + +// Store reference to this file. +if ( ! defined( 'CFAFA_FILE' ) ) { + define( 'CFAFA_FILE', __FILE__ ); +} + +// Store URL to this plugin's directory. +if ( ! defined( 'CFAFA_URL' ) ) { + define( 'CFAFA_URL', plugin_dir_url( CFAFA_FILE ) ); +} + +// Store PATH to this plugin's directory. +if ( ! defined( 'CFAFA_PATH' ) ) { + define( 'CFAFA_PATH', plugin_dir_path( CFAFA_FILE ) ); +} + +/** + * Conditional Form Actions for ACFE Class. + * + * A class that encapsulates this plugin's functionality. + * + * @since 0.1 + */ +class Conditional_Form_Actions_For_ACFE { + + /** + * ACF Extended object. + * + * @since 0.1 + * @access public + * @var object $acfe The ACF Extended object. + */ + public $acfe; + + /** + * Initialises this object. + * + * @since 0.1 + */ + public function __construct() { + + // Always load translations. + add_action( 'plugins_loaded', [ $this, 'translation' ] ); + + // Initialise when ACF Extended is initialised. + add_action( 'acfe/init', [ $this, 'initialise' ] ); + + } + + /** + * Initialise this plugin. + * + * @since 0.1 + */ + public function initialise() { + + // Only do this once. + static $done; + if ( isset( $done ) && $done === true ) { + return; + } + + // Include files. + $this->include_files(); + + // Set up objects and references. + $this->setup_objects(); + + /** + * Broadcast that this plugin is loaded. + * + * @since 0.1 + */ + do_action( 'cfafa/loaded' ); + + // We're done. + $done = true; + + } + + /** + * Enable translation. + * + * @since 0.1 + */ + public function translation() { + + // Load translations. + load_plugin_textdomain( + 'conditional-form-actions-for-acfe', // Unique name. + false, // Deprecated argument. + dirname( plugin_basename( CFAFA_FILE ) ) . '/languages/' // Relative path to files. + ); + + } + + /** + * Include files. + * + * @since 0.1 + */ + public function include_files() { + + // Load our class files. + require CFAFA_PATH . 'includes/cfafa-acfe.php'; + + } + + /** + * Set up this plugin's objects. + * + * @since 0.1 + */ + public function setup_objects() { + + // Initialise objects. + $this->acfe = new CFAFA_ACFE( $this ); + + } + + /** + * Check if this plugin is network activated. + * + * @since 0.1 + * + * @return bool $is_network_active True if network activated, false otherwise. + */ + public function is_network_activated() { + + // Only need to test once. + static $is_network_active; + + // Have we done this already? + if ( isset( $is_network_active ) ) { + return $is_network_active; + } + + // If not multisite, it cannot be. + if ( ! is_multisite() ) { + $is_network_active = false; + return $is_network_active; + } + + // Make sure plugin file is included when outside admin. + if ( ! function_exists( 'is_plugin_active_for_network' ) ) { + require_once ABSPATH . '/wp-admin/includes/plugin.php'; + } + + // Get path from 'plugins' directory to this plugin. + $this_plugin = plugin_basename( CFAFA_FILE ); + + // Test if network active. + $is_network_active = is_plugin_active_for_network( $this_plugin ); + + // --< + return $is_network_active; + + } + +} // Class ends. + +/** + * Load plugin if not yet loaded and return reference. + * + * @since 0.1 + * + * @return Conditional_Form_Actions_For_ACFE $plugin The plugin reference. + */ +function cfafa() { + + // Declare as global. + static $plugin; + + // Instantiate plugin if not yet instantiated. + if ( ! isset( $plugin ) ) { + $plugin = new Conditional_Form_Actions_For_ACFE(); + } + + // --< + return $plugin; + +} + +// Load immediately. +cfafa(); + +/** + * Performs plugin activation tasks. + * + * @since 0.1 + */ +function cfafa_activate() { + + /** + * Broadcast that this plugin has been activated. + * + * @since 0.1 + */ + do_action( 'cfafa/activated' ); + +} + +// Activation. +register_activation_hook( __FILE__, 'cfafa_activate' ); + +/** + * Performs plugin deactivation tasks. + * + * @since 0.1 + */ +function cfafa_deactivated() { + + /** + * Broadcast that this plugin has been deactivated. + * + * @since 0.1 + */ + do_action( 'cfafa/deactivated' ); + +} + +// Deactivation. +register_deactivation_hook( __FILE__, 'cfafa_deactivated' ); + +// Uninstall uses the 'uninstall.php' method. +// See: http://codex.wordpress.org/Function_Reference/register_uninstall_hook diff --git a/cwps-acf-acfe-form.php b/cwps-acf-acfe-form.php new file mode 100644 index 0000000..3a18ba3 --- /dev/null +++ b/cwps-acf-acfe-form.php @@ -0,0 +1,608 @@ +<?php +/** + * ACFE Form Class. + * + * Handles compatibility with ACFE Forms. + * + * @package Conditional_Form_Actions_For_ACFE + * @since 0.1 + */ + +// Exit if accessed directly. +defined( 'ABSPATH' ) || exit; + + + +/** + * CiviCRM Profile Sync ACFE Form Class. + * + * A class that handles compatibility with ACFE Forms. + * + * @since 0.1 + */ +class CFAFA_Form { + + /** + * Plugin object. + * + * @since 0.1 + * @access public + * @var object $plugin The plugin object. + */ + public $plugin; + + /** + * ACF Loader object. + * + * @since 0.1 + * @access public + * @var object $acf_loader The ACF Loader object. + */ + public $acf_loader; + + /** + * CiviCRM object. + * + * @since 0.1 + * @access public + * @var object $civicrm The CiviCRM object. + */ + public $civicrm; + + /** + * ACF object. + * + * @since 0.1 + * @access public + * @var object $acf The ACF object. + */ + public $acf; + + /** + * Parent (calling) object. + * + * @since 0.1 + * @access public + * @var object $acfe The parent object. + */ + public $acfe; + + /** + * Supported Location Rule name. + * + * @since 0.1 + * @access public + * @var string $rule_name The supported Location Rule name. + */ + public $rule_name = 'form_civicrm'; + + + + /** + * Constructor. + * + * @since 0.1 + * + * @param object $parent The parent object reference. + */ + public function __construct( $parent ) { + + // Store references to objects. + $this->plugin = $parent->acf_loader->plugin; + $this->acf_loader = $parent->acf_loader; + $this->civicrm = $this->acf_loader->civicrm; + $this->acf = $this->acf_loader->acf; + $this->acfe = $parent; + + // Init when this plugin is loaded. + add_action( 'cfafa/acf/acfe/loaded', [ $this, 'initialise' ] ); + + } + + + + /** + * Initialise this object. + * + * @since 0.1 + */ + public function initialise() { + + // Include files. + $this->include_files(); + + // Register Location Types. + $this->register_location_types(); + + // Register hooks. + $this->register_hooks(); + + } + + + + /** + * Include files. + * + * @since 0.1 + */ + public function include_files() { + + } + + + + /** + * Register WordPress hooks. + * + * @since 0.1 + */ + public function register_hooks() { + + // Listen for queries from the ACF Field Group class. + add_filter( 'cfafa/acf/query_field_group_mapped', [ $this, 'query_field_group_mapped' ], 10, 2 ); + add_filter( 'cfafa/acf/field_group/query_supported_rules', [ $this, 'query_supported_rules' ], 10, 4 ); + + // Listen for queries from the ACF Field class. + add_filter( 'cfafa/acf/query_settings_field', [ $this, 'query_settings_field' ], 200, 3 ); + + // Register ACFE Form Actions. + add_filter( 'acfe/include_form_actions', [ $this, 'register_form_actions' ] ); + + // Add Form Actions Javascript. + add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_form_action_scripts' ] ); + + // Add Form Actions Javascript. + add_action( 'acfe/form/submit', [ $this, 'form_action_query_vars_clear' ] ); + + // Set a better Form Wrapper class. + add_filter( 'acfe/form/load', [ $this, 'form_wrapper' ], 10, 2 ); + + } + + + + /** + * Clear the Form Action Query Vars. + * + * This means we get a fresh set of Query Vars during the load process after + * a Form has been submitted. + * + * @since 0.1 + */ + public function form_action_query_vars_clear() { + + // Clear the array of Action results. + set_query_var( 'acfe_form_actions', [] ); + + } + + + + /** + * Alters the default "Success Wrapper" class. + * + * @since 0.1 + * + * @param array $form The ACF Form data array. + * @param integer $post_id The numeric ID of the WordPress Post. + * @return array $form The modified ACF Form data array. + */ + public function form_wrapper( $form, $post_id ) { + + // Alter the default "Success Wrapper". + if ( $form['html_updated_message'] === '<div id="message" class="updated">%s</div>' ) { + $form['html_updated_message'] = '<div id="message" class="acfe-success">%s</div>'; + } + + // --< + return $form; + + } + + + + /** + * Register Location Types. + * + * @since 0.1 + */ + public function register_location_types() { + + // Bail if less than ACF 5.9.0. + if ( ! function_exists( 'acf_register_location_type' ) ) { + return; + } + + // Include Location Rule class files. + include CIVICRM_WP_PROFILE_SYNC_PATH . 'includes/acf/acfe/locations/cfafa-acf-acfe-location-bypass.php'; + + // Register Location Types with ACF. + acf_register_location_type( 'CiviCRM_Profile_Sync_ACF_Location_Type_Bypass' ); + + } + + + + /** + * Register Form Actions. + * + * @since 0.1 + */ + public function register_form_actions() { + + // Include Form Action base class. + include CIVICRM_WP_PROFILE_SYNC_PATH . 'includes/acf/acfe/form-actions/cfafa-acf-acfe-form-action-base.php'; + + // Include Form Action classes. + include CIVICRM_WP_PROFILE_SYNC_PATH . 'includes/acf/acfe/form-actions/cfafa-acf-acfe-form-action-contact.php'; + include CIVICRM_WP_PROFILE_SYNC_PATH . 'includes/acf/acfe/form-actions/cfafa-acf-acfe-form-action-activity.php'; + include CIVICRM_WP_PROFILE_SYNC_PATH . 'includes/acf/acfe/form-actions/cfafa-acf-acfe-form-action-participant.php'; + include CIVICRM_WP_PROFILE_SYNC_PATH . 'includes/acf/acfe/form-actions/cfafa-acf-acfe-form-action-redirect.php'; + + // Init Form Actions. + new CFAFA_Form_Action_Contact( $this ); + new CFAFA_Form_Action_Activity( $this ); + new CFAFA_Form_Action_Participant( $this ); + new CFAFA_Form_Action_Redirect( $this ); + + // Init Case Action if the CiviCase component is active. + $case_active = $this->plugin->civicrm->is_component_enabled( 'CiviCase' ); + if ( $case_active ) { + include CIVICRM_WP_PROFILE_SYNC_PATH . 'includes/acf/acfe/form-actions/cfafa-acf-acfe-form-action-case.php'; + new CFAFA_Form_Action_Case( $this ); + } + + // Init Email Action if the "Email API" Extension is active. + $email_active = $this->plugin->civicrm->is_extension_enabled( 'org.civicoop.emailapi' ); + if ( $email_active ) { + include CIVICRM_WP_PROFILE_SYNC_PATH . 'includes/acf/acfe/form-actions/cfafa-acf-acfe-form-action-email.php'; + new CFAFA_Form_Action_Email( $this ); + } + + if ( function_exists( 'WC' ) ) { + include CIVICRM_WP_PROFILE_SYNC_PATH . 'includes/acf/acfe/form-actions/cfafa-acf-acfe-form-action-product.php'; + new CFAFA_Form_Action_Product( $this ); + } + + } + + + + /** + * Enqueue Form Action Javascript. + * + * @since 0.1 + */ + public function enqueue_form_action_scripts() { + + // Bail if the current screen is not an Edit ACFE Form screen. + $screen = get_current_screen(); + if ( ! ( $screen instanceof WP_Screen ) ) { + return; + } + if ( $screen->base != 'post' || $screen->id != 'acfe-form' ) { + return; + } + + // Add JavaScript plus dependencies. + wp_enqueue_script( + 'cfafa-acfe-form-actions', + plugins_url( 'assets/js/acf/acfe/form-actions/cfafa-form-action-model.js', CIVICRM_WP_PROFILE_SYNC_FILE ), + [ 'acf-extended' ], + CIVICRM_WP_PROFILE_SYNC_VERSION // Version. + ); + + // Init the Contact Reference Field actions array. + $contact_action_refs = [ + // Contact Actions must always be present. + 'new_field/key=field_cfafa_contact_action_custom_alias' => 'newContactActionAlias', + 'remove_field/key=field_cfafa_contact_action_custom_alias' => 'removeContactActionAlias', + ]; + + /** + * Query Form Action classes to build the Contact Reference Fields ACF Model actions array. + * + * @since 0.1 + * + * @param array $contact_action_refs The ACF Model actions array to be populated. + */ + $contact_actions = apply_filters( 'cfafa/acf/acfe/form_actions/reference_fields/contact', $contact_action_refs ); + + // Init the Case Reference Field actions array. + $case_action_refs = [ + // Case Actions must always be present. + 'new_field/key=field_cfafa_case_action_custom_alias' => 'newCaseActionAlias', + 'remove_field/key=field_cfafa_case_action_custom_alias' => 'removeCaseActionAlias', + ]; + + /** + * Query Form Action classes to build the Case Reference Fields ACF Model actions array. + * + * @since 0.1 + * + * @param array $case_action_refs The ACF Model actions array to be populated. + */ + $case_actions = apply_filters( 'cfafa/acf/acfe/form_actions/reference_fields/case', $case_action_refs ); + + // Init the Participant Reference Field actions array. + $participant_action_refs = [ + // Participant Actions must always be present. + 'new_field/key=field_cfafa_participant_action_custom_alias' => 'newParticipantActionAlias', + 'remove_field/key=field_cfafa_participant_action_custom_alias' => 'removeParticipantActionAlias', + ]; + + /** + * Query Form Action classes to build the Participant Reference Fields ACF Model actions array. + * + * @since 0.1 + * + * @param array $participant_action_refs The ACF Model actions array to be populated. + */ + $participant_actions = apply_filters( 'cfafa/acf/acfe/form_actions/reference_fields/participant', $participant_action_refs ); + + // Build data array. + $vars = [ + 'localisation' => [], + 'settings' => [ + 'contact_actions_reference' => $contact_actions, + 'case_actions_reference' => $case_actions, + 'participant_actions_reference' => $participant_actions, + ], + ]; + + // Localize our script. + wp_localize_script( + 'cfafa-acfe-form-actions', + 'CWPS_ACFE_Form_Action_Vars', + $vars + ); + + } + + + + // ------------------------------------------------------------------------- + + + + /** + * Listen for queries from the Field Group class. + * + * This method responds with a Boolean if it detects that this Field Group + * should bypass ACF. + * + * @since 0.1 + * + * @param bool $mapped The existing mapping flag. + * @param array $field_group The array of ACF Field Group data. + * @param bool $mapped True if the Field Group should bypass ACF, or pass through if not. + */ + public function query_field_group_mapped( $mapped, $field_group ) { + + // Bail if a Mapping has already been found. + if ( $mapped !== false ) { + return $mapped; + } + + // Bail if this is not a Bypass Field Group. + $is_bypass_field_group = $this->is_bypass_field_group( $field_group ); + if ( $is_bypass_field_group === false ) { + return $mapped; + } + + // --< + return true; + + } + + + + /** + * Check if this Field Group should bypass ACF. + * + * @since 0.1 + * + * @param array $field_group The Field Group to check. + * @return array|bool The array of Entities if the Field Group should bypass ACF, or false otherwise. + */ + public function is_bypass_field_group( $field_group ) { + + // Bail if there's no Field Group ID. + if ( empty( $field_group['ID'] ) ) { + return false; + } + + // Only do this once per Field Group. + static $pseudocache; + if ( isset( $pseudocache[ $field_group['ID'] ] ) ) { + return $pseudocache[ $field_group['ID'] ]; + } + + // Assume not visible. + $is_visible = false; + + // Bail if no Location Rules exist. + if ( ! empty( $field_group['location'] ) ) { + + // We only need the key to test for an ACF Bypass location. + $params = [ + $this->rule_name => 'foo', + ]; + + // Do the check. + $is_visible = $this->acf_loader->acf->field_group->is_visible( $field_group, $params ); + + } + + // Maybe add to pseudo-cache. + if ( ! isset( $pseudocache[ $field_group['ID'] ] ) ) { + $pseudocache[ $field_group['ID'] ] = $is_visible; + } + + // --< + return $is_visible; + + } + + + + /** + * Listen for queries for supported Location Rules. + * + * @since 0.1 + * + * @param bool $supported The existing supported Location Rules status. + * @param array $rule The Location Rule. + * @param array $params The query params array. + * @param array $field_group The ACF Field Group data array. + * @return bool $supported The modified supported Location Rules status. + */ + public function query_supported_rules( $supported, $rule, $params, $field_group ) { + + // Bail if already supported. + if ( $supported === true ) { + return $supported; + } + + // Test for this Location Rule. + if ( $rule['param'] == $this->rule_name && ! empty( $params[$this->rule_name] ) ) { + $supported = true; + } + + // --< + return $supported; + + } + + + + // ------------------------------------------------------------------------- + + + + /** + * Returns a Setting Field from this Entity when found. + * + * @since 0.1 + * + * @param array $setting_field The existing Setting Field array. + * @param array $field The ACF Field data array. + * @param array $field_group The ACF Field Group data array. + * @return array|bool $setting_field The Setting Field array if populated, false if conflicting. + */ + public function query_settings_field( $setting_field, $field, $field_group ) { + + // Pass if conflicting Fields have been found. + if ( $setting_field === false ) { + return false; + } + + // Pass if this is not a Bypass Field Group. + $is_visible = $this->is_bypass_field_group( $field_group ); + if ( $is_visible === false ) { + return $setting_field; + } + + // If already populated, then this is a conflicting Field. + if ( ! empty( $setting_field ) ) { + return false; + } + + // Get the array of Entities and IDs. + $entity_array = $this->entity_mapping_extract( $field_group['location'] ); + + /** + * Request an array of Setting Field choices from Entity classes. + * + * @since 0.1 + * + * @param array The empty default Setting Field choices array. + * @param array $field The ACF Field data array. + * @param array $field_group The ACF Field Group data array. + * @param array $entity_array The array of Entities and IDs. + */ + $choices = apply_filters( 'cfafa/acf/bypass/query_settings_choices', [], $field, $field_group, $entity_array ); + + // Bail if there aren't any. + if ( empty( $choices ) ) { + return false; + } + + // Define Setting Field. + $setting_field = [ + 'key' => $this->civicrm->acf_field_key_get(), + 'label' => __( 'CiviCRM Field', 'conditional-form-actions-for-acfe' ), + 'name' => $this->civicrm->acf_field_key_get(), + 'type' => 'select', + 'instructions' => __( 'Choose the CiviCRM Field that this ACF Field should sync with. (Optional)', 'conditional-form-actions-for-acfe' ), + 'default_value' => '', + 'placeholder' => '', + 'allow_null' => 1, + 'multiple' => 0, + 'ui' => 0, + 'required' => 0, + 'return_format' => 'value', + 'parent' => $this->acf->field_group->placeholder_group_get(), + 'choices' => $choices, + ]; + + // Return populated array. + return $setting_field; + + } + + + + /** + * Returns an array containing the Entities and their IDs. + * + * @since 0.1 + * + * @param array $location_rules The Location Rules for the Field. + * @return array $entity_mapping The array containing the Entities and IDs. + */ + public function entity_mapping_extract( $location_rules ) { + + // Init an empty Entity mapping array. + $entity_mapping = []; + + // The Location Rules outer array is made of "grouos". + foreach ( $location_rules as $group ) { + + // Skip group if it has no rules. + if ( empty( $group ) ) { + continue; + } + + // The Location Rules inner array is made of "rules". + foreach ( $group as $rule ) { + + // Is this a Bypass rule? + if ( $rule['param'] === $this->rule_name ) { + + // Extract the Entity and ID. + //$entity_map = []; + $tmp = explode( '-', $rule['value'] ); + //$entity_map[] = [ 'entity' => $tmp[0], 'entity_id' => (int) $tmp[1] ]; + + // Add to return. + $entity_mapping[ $tmp[0] ][] = (int) $tmp[1]; + + } + + } + + } + + // --< + return $entity_mapping; + + } + + + +} // Class ends. + + + diff --git a/includes/cfafa-acfe.php b/includes/cfafa-acfe.php new file mode 100644 index 0000000..569fc3d --- /dev/null +++ b/includes/cfafa-acfe.php @@ -0,0 +1,131 @@ +<?php +/** + * ACF Extended Class. + * + * Handles general "ACF Extended" functionality. + * + * @package Conditional_Form_Actions_For_ACFE + * @since 0.1 + */ + +// Exit if accessed directly. +defined( 'ABSPATH' ) || exit; + +/** + * "ACF Extended" Class. + * + * A class that encapsulates ACF Extended functionality. + * + * @since 0.1 + */ +class CFAFA_ACFE { + + /** + * Plugin object. + * + * @since 0.1 + * @access public + * @var object $plugin The plugin object. + */ + public $plugin; + + /** + * Constructor. + * + * @since 0.1 + * + * @param object $plugin The plugin object. + */ + public function __construct( $plugin ) { + + // Store references to objects. + $this->plugin = $plugin; + + // Init when ACF class is loaded. + add_action( 'cfafa/loaded', [ $this, 'initialise' ] ); + + } + + /** + * Initialise this object. + * + * @since 0.1 + */ + public function initialise() { + + // Only do this once. + static $done; + if ( isset( $done ) && $done === true ) { + return; + } + + // Register hooks. + $this->register_hooks(); + + /** + * Broadcast that this class is now loaded. + * + * @since 0.1 + */ + do_action( 'cfafa/acfe/loaded' ); + + // We're done and loaded. + $done = true; + + } + + /** + * Register hooks. + * + * @since 0.1 + */ + public function register_hooks() { + + // Register ACFE Form Actions. + add_filter( 'acfe/include_form_actions', [ $this, 'register_form_actions' ], 50 ); + + // Add Form Actions Javascript. + add_action( 'acfe/form/submit', [ $this, 'form_action_query_vars_clear' ] ); + + } + + /** + * Clear the Form Action Query Vars. + * + * This means we get a fresh set of Query Vars during the load process after + * a Form has been submitted. + * + * @since 0.1 + */ + public function form_action_query_vars_clear() { + + // Clear the array of Action results. + set_query_var( 'acfe_form_actions', [] ); + + } + + /** + * Register Form Actions. + * + * @since 0.1 + */ + public function register_form_actions() { + + // Include class files. + include CFAFA_PATH . 'includes/form-actions/cfafa-form-action-base.php'; + include CFAFA_PATH . 'includes/form-actions/cfafa-form-action-redirect.php'; + //include CFAFA_PATH . 'includes/form-actions/cfafa-form-action-email.php'; + + // Instantiate the Form Actions. + new CFAFA_Form_Action_Redirect( $this ); + //new CFAFA_Form_Action_Email( $this ); + + // Maybe add WooCommerce Product Action. + if ( function_exists( 'WC' ) ) { + include CFAFA_PATH . 'includes/form-actions/cfafa-form-action-product.php'; + new CFAFA_Form_Action_Product( $this ); + } + + } + +} // Class ends. diff --git a/includes/form-actions/cfafa-form-action-base.php b/includes/form-actions/cfafa-form-action-base.php new file mode 100644 index 0000000..095c74c --- /dev/null +++ b/includes/form-actions/cfafa-form-action-base.php @@ -0,0 +1,498 @@ +<?php +/** + * ACFE Base Form Action Class. + * + * Holds methods common to ACFE Form Action classes. + * + * @package Conditional_Form_Actions_For_ACFE + * @since 0.1 + */ + +// Exit if accessed directly. +defined( 'ABSPATH' ) || exit; + +/** + * CiviCRM Profile Sync "Base" ACFE Form Action Class. + * + * A class that is extended by CiviCRM Profile Sync ACFE Form Action classes. + * * + * @since 0.1 + */ +class CFAFA_Form_Action_Base { + + /** + * Form Action Name. + * + * @since 0.1 + * @access public + * @var string $action_name The unique name of the Form Action. + */ + public $action_name = ''; + + /** + * Form Action Label. + * + * @since 0.1 + * @access public + * @var string $action_label The label of the Form Action. + */ + public $action_label = ''; + + /** + * Form Action Alias Placeholder. + * + * @since 0.1 + * @access public + * @var string $alias_placeholder The alias placeholder for the Form Action. + */ + public $alias_placeholder = ''; + + /** + * Field Key Prefix. + * + * @since 0.1 + * @access public + * @var string $field_key The prefix for the Field Key. + */ + public $field_key = ''; + + /** + * Field Name Prefix. + * + * @since 0.1 + * @access public + * @var string $field_name The prefix for the Field Name. + */ + public $field_name = ''; + + /** + * Constructor. + * + * @since 0.1 + */ + public function __construct() { + + // Callback for the "acfe/form/load/..." hook. + add_filter( 'acfe/form/load/' . $this->action_name, [ $this, 'load' ], 10, 3 ); + + // Callback for the "acfe/form/make/..." hook. + add_action( 'acfe/form/make/' . $this->action_name, [ $this, 'make' ], 10, 3 ); + + // Generic callback for ACFE Form Actions hook. + add_filter( 'acfe/form/actions', [ $this, 'action_add' ] ); + + } + + /** + * Allow classes to configure themselves prior to the Layout being returned. + * + * @since 0.1 + */ + public function configure() {} + + /** + * Performs tasks when the Form that the Action is attached to is loaded. + * + * @since 0.1 + * + * @param array $form The array of Form data. + * @param integer $current_post_id The ID of the Post in which the Form has been embedded. + * @param string $action The customised name of the action. + */ + public function load( $form, $current_post_id, $action ) { + return $form; + } + + /** + * Saves the result of the Action for use by subsequent Actions. + * + * @since 0.1 + * + * @param string $action The name of the Action. + * @param array $data The result of the Action. + */ + public function load_action_save( $action = '', $data ) { + + // Get the existing array of Action results. + $actions = get_query_var( 'acfe_form_actions', [] ); + + $actions[$this->action_name] = $data; + if ( ! empty( $action ) ) { + $actions[$action] = $data; + } + + // Update array of Action results. + set_query_var( 'acfe_form_actions', $actions ); + + } + + /** + * 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 ) {} + + /** + * Maybe skip 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 Form Action. + * @return bool $prepare The net result of the set of filters. + */ + public function make_skip( $form, $current_post_id, $action ) { + + // Get some Form details. + $form_name = acf_maybe_get( $form, 'name' ); + $form_id = acf_maybe_get( $form, 'ID' ); + + // Assume we're good to go. + $prepare = true; + + /** + * Allow others to prevent Form Action. + * + * Returning false for any of these filters will skip the Action. + * + * @since 0.1 + * + * @param bool $prepare True by default so that the Form Action goes ahead. + * @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 Form Action. + */ + $filter = 'acfe/form/prepare/' . $this->action_name; + $prepare = apply_filters( $filter, $prepare, $form, $current_post_id, $action ); + $prepare = apply_filters( $filter . '/form=' . $form_name, $prepare, $form, $current_post_id, $action ); + if ( ! empty( $action ) ) { + $prepare = apply_filters( $filter . '/action=' . $action, $prepare, $form, $current_post_id, $action ); + } + + // --< + return $prepare; + + } + + /** + * Saves the result of the Action for use by subsequent Actions. + * + * @since 0.1 + * + * @param string $action The name of the Action. + * @param array $data The result of the Action. + */ + public function make_action_save( $action = '', $data ) { + + // Get the existing array of Action results. + $actions = get_query_var( 'acfe_form_actions', [] ); + + $actions[$this->action_name] = $data; + if ( ! empty( $action ) ) { + $actions[$action] = $data; + } + + // Update array of Action results. + set_query_var( 'acfe_form_actions', $actions ); + + } + + /** + * Defines the action by adding a layout. + * + * The "name" value of the layout determines the construction of the + * "acfe/form/load/..." and "acfe/form/make/..." actions. + * + * @since 0.1 + * + * @param array $layouts The existing layouts. + * @return array $layouts The modified layouts. + */ + public function action_add( $layouts ) { + + // Let the classes that extend this one configure themselves. + $this->configure(); + + // Init our layout. + $layout = [ + 'key' => 'layout_' . $this->action_name, + 'name' => $this->action_name, + 'label' => $this->action_label, + 'display' => 'row', + 'min' => '', + 'max' => '', + ]; + + // Build Action Tab. + $action_tab_fields = $this->tab_action_add(); + + // Build Mapping Tab. + $mapping_tab_fields = $this->tab_mapping_add(); + + // Combine Sub-Fields. + $sub_fields = array_merge( + $action_tab_fields, + $mapping_tab_fields + ); + + /** + * Let the classes that extend this one modify the Sub-Fields. + * + * @since 0.1 + * + * @param array $sub_fields The array of Sub-Fields. + */ + $layout['sub_fields'] = apply_filters( 'cfafa/acfe/form/actions/sub_fields', $sub_fields ); + + // Add our completed layout to the layouts array. + $layouts['layout_' . $this->action_name] = $layout; + + // --< + return $layouts; + + } + + /** + * Defines the "Action" Tab. + * + * These Fields are required to configure the Form Action. + * + * The ACFE "Action name" Field has a pre-defined format, e.g. it must be + * assigned the "acfe_slug" Field Type and have "acfe_form_custom_alias" as + * its "name". Only its "placeholder" attribute needs to be configured. + * + * @since 0.1 + * + * @return array $fields The array of Fields for this section. + */ + public function tab_action_add() { + + // Init Fields array. + $fields = []; + + // "Action" Tab wrapper. + $fields[] = [ + 'key' => $this->field_key . 'tab_action', + 'label' => __( 'Action', 'conditional-form-actions-for-acfe' ), + 'name' => '', + 'type' => 'tab', + 'instructions' => '', + 'required' => 0, + 'conditional_logic' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + 'data-no-preference' => true, + ], + 'acfe_permissions' => '', + 'placement' => 'top', + 'endpoint' => 0, + ]; + + // "Action name" Field. + $fields[] = [ + 'key' => $this->field_key . 'custom_alias', + 'label' => __( 'Action name', 'conditional-form-actions-for-acfe' ), + 'name' => 'acfe_form_custom_alias', + 'type' => 'acfe_slug', + 'instructions' => __( '(Required) Name this action so it can be referenced.', 'conditional-form-actions-for-acfe' ), + 'required' => 1, + 'conditional_logic' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + 'data-instruction-placement' => 'field', + ], + 'acfe_permissions' => '', + 'default_value' => '', + 'placeholder' => $this->alias_placeholder, + 'prepend' => '', + 'append' => '', + 'maxlength' => '', + ]; + + // Add any further Fields. + $action_extras = $this->tab_action_append(); + if ( ! empty( $action_extras ) ) { + $fields = array_merge( + $fields, + $action_extras + ); + } + + // --< + return $fields; + + } + + /** + * 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() { + $fields = []; + return $fields; + } + + /** + * Defines the "Mapping" Tab. + * + * @since 0.1 + * + * @return array $fields The array of Fields for this section. + */ + public function tab_mapping_add() { + $fields = []; + return $fields; + } + + /** + * Defines the "Mapping" Tab Header. + * + * @since 0.1 + * + * @return array $fields The array of Fields for this section. + */ + public function tab_mapping_header() { + + // "Mapping" Tab wrapper. + $mapping_tab = [ [ + 'key' => $this->field_key . 'tab_load', + 'label' => __( 'Mapping', 'conditional-form-actions-for-acfe' ), + 'name' => '', + 'type' => 'tab', + 'instructions' => '', + 'required' => 0, + 'conditional_logic' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + 'data-no-preference' => true, + ], + 'acfe_permissions' => '', + 'placement' => 'top', + 'endpoint' => 0, + ] ]; + + // Combine Fields. + $fields = array_merge( + $mapping_tab + ); + + // --< + return $fields; + + } + + /** + * Gets the array that defines a "Map Field" for the "Mapping" Tab. + * + * @since 0.1 + * + * @param string $code The unique code for the Field. + * @param string $label The label for the Field. + * @param array $conditional_logic The conditional logic for the Field. + * @return array $field The array of Field data. + */ + public function mapping_field_get( $code, $label, $conditional_logic = [] ) { + + // Build the Field array. + $field = [ + 'key' => $this->field_key . 'map_' . $code, + 'label' => $label, + 'name' => $this->field_name . 'map_' . $code, + 'type' => 'select', + 'instructions' => '', + 'required' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + ], + 'acfe_permissions' => '', + 'choices' => [], + 'default_value' => [], + 'allow_null' => 1, + 'multiple' => 0, + 'ui' => 1, + 'return_format' => 'value', + 'placeholder' => __( 'Default', 'conditional-form-actions-for-acfe' ), + 'ajax' => 0, + 'search_placeholder' => __( 'Enter a custom value or template tag. (See "Cheatsheet" tab)', 'conditional-form-actions-for-acfe' ), + 'allow_custom' => 1, + ]; + + // Default conditional logic. + $field['conditional_logic'] = 0; + + // Maybe replace with custom conditional logic. + if ( ! empty( $conditional_logic ) ) { + $field['conditional_logic'] = $conditional_logic; + } + + // --< + return $field; + + } + + /** + * Adds filters that configure "Mapping Fields" when loaded. + * + * @since 0.1 + * + * @param string $code The unique code for the Field. + */ + public function mapping_field_filters_add( $code ) { + + // Grab reference to ACFE Helper object. + $helpers = acf_get_instance( 'acfe_dynamic_forms_helpers' ); + + // Populate mapping Fields. + add_filter( 'acf/prepare_field/name=' . $this->field_name . 'map_' . $code, [ $helpers, 'map_fields_deep_no_custom' ] ); + + } + + /** + * Prepare the data from an ACFE Form. + * + * @since 0.1 + * + * @param array $form_data The array of data from the ACFE Form. + * @return array $filtered_data The filtered data. + */ + public function form_data_prepare( $form_data ) { + + // Init filtered data. + $filtered_data = []; + + // Bail if we have no Form data to save. + if ( empty( $form_data ) ) { + return $filtered_data; + } + + // Populate Activity data from the Form data. + foreach ( $form_data as $param => $value ) { + // Allow (string) "0" as valid data. + if ( ! empty( $value ) || $value === '0' ) { + $filtered_data[$param] = $value; + } + } + + // --< + return $filtered_data; + + } + +} // Class ends. diff --git a/includes/form-actions/cfafa-form-action-email.php b/includes/form-actions/cfafa-form-action-email.php new file mode 100644 index 0000000..fbca6e2 --- /dev/null +++ b/includes/form-actions/cfafa-form-action-email.php @@ -0,0 +1,815 @@ +<?php +/** + * "Conditional Email" ACFE Form Action Class. + * + * Handles the "Conditional Email" ACFE Form Action. + * + * @package Conditional_Form_Actions_For_ACFE + * @since 0.1 + */ + +// Exit if accessed directly. +defined( 'ABSPATH' ) || exit; + +/** + * CiviCRM Profile Sync "Conditional Email" ACFE Form Action Class. + * + * A class that handles the "Conditional Email" ACFE Form Action. + * + * @since 0.1 + */ +class CFAFA_Form_Action_Email 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 = 'email_cfafa'; + + /** + * Field Key Prefix. + * + * @since 0.1 + * @access public + * @var string $field_key The prefix for the Field Key. + */ + public $field_key = 'field_cfafa_email_'; + + /** + * Field Name Prefix. + * + * @since 0.1 + * @access public + * @var string $field_name The prefix for the Field Name. + */ + public $field_name = 'cfafa_email_'; + + /** + * 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 = __( 'Conditional Email action', 'conditional-form-actions-for-acfe' ); + + // Alias Placeholder for this Form Action. + $this->alias_placeholder = __( 'Conditional Email', 'conditional-form-actions-for-acfe' ); + + // Init parent. + parent::__construct(); + + } + + /** + * Configure this object. + * + * @since 0.1 + */ + public function configure() { + + // Declare the mapped Email Fields with translatable titles. + $this->mapped_email_fields = [ + 'subject' => __( 'Subject', 'conditional-form-actions-for-acfe' ), + 'from_name' => __( 'From Name', 'conditional-form-actions-for-acfe' ), + 'from_email' => __( 'From Email', 'conditional-form-actions-for-acfe' ), + 'alternative_receiver_address' => __( 'Alternative Receiver Address', 'conditional-form-actions-for-acfe' ), + 'cc' => __( 'Carbon Copy', 'conditional-form-actions-for-acfe' ), + 'bcc' => __( 'Blind Carbon Copy', 'conditional-form-actions-for-acfe' ), + //'extra_data' => __( 'Extra Data', 'conditional-form-actions-for-acfe' ), + //'from_email_option' => __( 'From Email Option', 'conditional-form-actions-for-acfe' ), + ]; + + // Populate mapping Fields. + foreach ( $this->mapped_email_fields as $name => $title ) { + $this->mapping_field_filters_add( $name ); + } + + // Declare the Email Contact Fields with translatable titles. + $this->contact_fields = [ + 'contact_id' => __( 'Recipient CiviCRM Contact', 'conditional-form-actions-for-acfe' ), + ]; + + // Handle Contact Fields. + foreach ( $this->contact_fields as $name => $title ) { + + // Populate mapping Fields. + $this->mapping_field_filters_add( $name ); + + // Add Contact Action Reference Field to ACF Model. + $this->js_model_contact_reference_field_add( $this->field_name . 'ref_' . $name ); + + // Pre-load with "Generic" values. + //$filter = 'acf/prepare_field/name=' . $this->field_name . 'map_' . $name; + //add_filter( $filter, [ $this, 'prepare_choices' ], 5 ); + + } + + // Email Conditional Field. + $this->mapping_field_filters_add( 'email_conditional' ); + + } + + /** + * Pre-load mapping Fields with "Generic" choices. + * + * Not used but leaving this here for future use. + * + * @since 0.1 + * + * @param array $field The existing array of Field data. + * @param array $field The modified array of Field data. + */ + public function prepare_choices( $field ) { + + // --< + return $field; + + } + + /** + * Performs validation 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 validation( $form, $current_post_id, $action ) { + + /* + // Get some Form details. + $form_name = acf_maybe_get( $form, 'name' ); + $form_id = acf_maybe_get( $form, 'ID' ); + //acfe_add_validation_error( $selector, $message ); + */ + + } + + /** + * 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 Email data array. + $email = $this->form_email_data( $form, $current_post_id, $action ); + + // Send the Email with the data from the Form. + $email = $this->form_email_save( $email ); + + // Save the results of this Action for later use. + $this->make_action_save( $action, $email ); + + } + + /** + * 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() { + + // Define Template Field. + $template_field = [ + 'key' => $this->field_key . 'template', + 'label' => __( 'Message Template', 'conditional-form-actions-for-acfe' ), + 'name' => $this->field_name . 'template', + 'type' => 'select', + 'instructions' => '', + 'required' => 0, + 'conditional_logic' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + 'data-instruction-placement' => 'field', + ], + 'acfe_permissions' => '', + 'default_value' => '', + 'placeholder' => '', + 'allow_null' => 0, + 'multiple' => 0, + 'ui' => 0, + 'return_format' => 'value', + 'choices' => $this->civicrm->email->template_options_get(), + ]; + + // Define "Disable Smarty" Field. + $smarty_field = [ + 'key' => $this->field_key . 'disable_smarty', + 'label' => __( 'Disable Smarty', 'conditional-form-actions-for-acfe' ), + 'name' => $this->field_name . 'disable_smarty', + 'type' => 'true_false', + 'instructions' => __( 'Disable Smarty. Normal CiviMail tokens are still supported. By default Smarty is enabled if configured by CIVICRM_MAIL_SMARTY.', 'conditional-form-actions-for-acfe' ), + 'required' => 0, + 'conditional_logic' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + 'data-instruction-placement' => 'field', + ], + 'acfe_permissions' => '', + 'message' => '', + 'default_value' => 0, + 'ui' => 1, + 'ui_on_text' => '', + 'ui_off_text' => '', + ]; + + // Define "Create Activity" Field. + $create_activity_field = [ + 'key' => $this->field_key . 'create_activity', + 'label' => __( 'Create Activity', 'conditional-form-actions-for-acfe' ), + 'name' => $this->field_name . 'create_activity', + 'type' => 'true_false', + 'instructions' => __( 'Usually an Email Activity is created when an Email is sent.', 'conditional-form-actions-for-acfe' ), + 'required' => 0, + 'conditional_logic' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + 'data-instruction-placement' => 'field', + ], + 'acfe_permissions' => '', + 'message' => '', + 'default_value' => 1, + 'ui' => 1, + 'ui_on_text' => '', + 'ui_off_text' => '', + ]; + + // Define "Activity Details" Field. + $activity_details_field = [ + 'key' => $this->field_key . 'activity_details', + 'label' => __( 'Activity Details', 'conditional-form-actions-for-acfe' ), + 'name' => $this->field_name . 'activity_details', + 'type' => 'select', + 'instructions' => '', + 'required' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + 'data-instruction-placement' => 'field', + ], + 'acfe_permissions' => '', + 'default_value' => 'html,text', + 'placeholder' => '', + 'allow_null' => 0, + 'multiple' => 0, + 'ui' => 0, + 'return_format' => 'value', + 'choices' => [ + 'html,text' => __( 'HTML and Text versions of the body', 'conditional-form-actions-for-acfe' ), + 'tplName' => __( 'Just the name of the message template', 'conditional-form-actions-for-acfe' ), + 'html' => __( 'Just the HTML version of the body', 'conditional-form-actions-for-acfe' ), + 'text' => __( 'Just the text version of the body', 'conditional-form-actions-for-acfe' ), + ], + 'conditional_logic' => [ + [ + [ + 'field' => $this->field_key . 'create_activity', + 'operator' => '==', + 'value' => 1, + ], + ], + ], + ]; + + // Init Fields. + $fields = [ + $template_field, + $smarty_field, + $create_activity_field, + $activity_details_field, + ]; + + // Add Case Field if the CiviCase component is active. + $case_active = $this->civicrm->is_component_enabled( 'CiviCase' ); + if ( $case_active ) { + + $fields[] = [ + 'key' => $this->field_key . 'email_case_id', + 'label' => __( 'Case', 'conditional-form-actions-for-acfe' ), + 'name' => $this->field_name . 'email_case_id', + 'type' => 'cfafa_acfe_case_action_ref', + 'instructions' => __( 'Select a Case Action in this Form.', 'conditional-form-actions-for-acfe' ), + 'required' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + 'data-instruction-placement' => 'field', + ], + 'acfe_permissions' => '', + 'default_value' => '', + 'placeholder' => __( 'None', 'conditional-form-actions-for-acfe' ), + 'allow_null' => 1, + 'multiple' => 0, + 'ui' => 0, + 'return_format' => 'value', + 'choices' => [], + ]; + + } + + // Add Conditional Field. + $code = 'email_conditional'; + $label = __( 'Conditional On', 'conditional-form-actions-for-acfe' ); + $conditional = $this->mapping_field_get( $code, $label ); + $conditional['placeholder'] = __( 'Always send', 'conditional-form-actions-for-acfe' ); + $conditional['wrapper']['data-instruction-placement'] = 'field'; + $conditional['instructions'] = __( 'To send the Email only when a Form Field is populated (e.g. "First Name") link this to the Form Field. To send the Email 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; + + } + + /** + * Defines the "Mapping" Tab. + * + * @since 0.1 + * + * @return array $fields The array of Fields for this section. + */ + public function tab_mapping_add() { + + // Get Tab Header. + $mapping_tab_header = $this->tab_mapping_header(); + + // Build Contacts Accordion. + $mapping_contacts_accordion = $this->tab_mapping_accordion_contacts_add(); + + // Build Email Details Accordion. + $mapping_email_accordion = $this->tab_mapping_accordion_email_add(); + + // Combine Sub-Fields. + $fields = array_merge( + $mapping_tab_header, + $mapping_contacts_accordion, + $mapping_email_accordion + ); + + // --< + return $fields; + + } + + /** + * Defines the Fields in the "Contacts" Accordion. + * + * @since 0.1 + * + * @return array $fields The array of Fields for this section. + */ + public function tab_mapping_accordion_contacts_add() { + + // Init return. + $fields = []; + + // "Recipient Contact Reference" Accordion wrapper open. + $fields[] = [ + 'key' => $this->field_key . 'mapping_accordion_contacts_open', + 'label' => __( 'Recipient Contact Reference', 'conditional-form-actions-for-acfe' ), + 'name' => '', + 'type' => 'accordion', + 'instructions' => '', + 'required' => 0, + 'conditional_logic' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + ], + 'acfe_permissions' => '', + 'open' => 0, + 'multi_expand' => 1, + 'endpoint' => 0, + ]; + + // Add Contact Reference Fields. + foreach ( $this->contact_fields as $name => $title ) { + + // Bundle them into a container group. + $contact_group_field = [ + 'key' => $this->field_key . 'contact_group_' . $name, + 'label' => $title, + 'name' => $this->field_name . 'contact_group_' . $name, + 'type' => 'group', + 'instructions' => sprintf( __( 'Use one Field to identify the %s.', 'conditional-form-actions-for-acfe' ), $title ), + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + ], + 'required' => 0, + 'layout' => 'block', + ]; + + // Define Contact Action Reference Field. + $contact_group_field['sub_fields'][] = [ + 'key' => $this->field_key . 'ref_' . $name, + 'label' => __( 'CiviCRM Contact Action', 'conditional-form-actions-for-acfe' ), + 'name' => $this->field_name . 'ref_' . $name, + 'type' => 'cfafa_acfe_contact_action_ref', + 'instructions' => __( 'Select a Contact Action in this Form.', 'conditional-form-actions-for-acfe' ), + 'required' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + ], + 'acfe_permissions' => '', + 'default_value' => '', + 'placeholder' => __( 'None', 'conditional-form-actions-for-acfe' ), + 'allow_null' => 0, + 'multiple' => 0, + 'ui' => 0, + 'return_format' => 'value', + 'choices' => [], + 'conditional_logic' => [ + [ + [ + 'field' => $this->field_key . 'map_' . $name, + 'operator' => '==empty', + ], + [ + 'field' => $this->field_key . 'cid_' . $name, + 'operator' => '==empty', + ], + ], + ], + ]; + + // Define Contact ID Field. + $cid_field = [ + 'key' => $this->field_key . 'cid_' . $name, + 'label' => __( 'CiviCRM Contact ID', 'conditional-form-actions-for-acfe' ), + 'name' => $this->field_name . 'cid_' . $name, + 'type' => 'civicrm_contact', + 'instructions' => __( 'Select a CiviCRM Contact ID from the database.', 'conditional-form-actions-for-acfe' ), + 'required' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + ], + 'acfe_permissions' => '', + 'default_value' => '', + 'placeholder' => __( 'None', 'conditional-form-actions-for-acfe' ), + 'allow_null' => 0, + 'multiple' => 0, + 'ui' => 0, + 'return_format' => 'value', + 'choices' => [], + 'conditional_logic' => [ + [ + [ + 'field' => $this->field_key . 'ref_' . $name, + 'operator' => '==empty', + ], + [ + 'field' => $this->field_key . 'map_' . $name, + 'operator' => '==empty', + ], + ], + ], + ]; + + // Add Contact ID Field. + $contact_group_field['sub_fields'][] = $cid_field; + + // Define Custom Contact Reference Field. + $title = sprintf( __( 'Custom Contact Reference', 'conditional-form-actions-for-acfe' ), $title ); + $mapping_field = $this->mapping_field_get( $name, $title ); + $mapping_field['instructions'] = __( 'Define a custom Contact Reference.', 'conditional-form-actions-for-acfe' ); + $mapping_field['conditional_logic'] = [ + [ + [ + 'field' => $this->field_key . 'ref_' . $name, + 'operator' => '==empty', + ], + [ + 'field' => $this->field_key . 'cid_' . $name, + 'operator' => '==empty', + ], + ], + ]; + + // Add Custom Contact Reference Field. + $contact_group_field['sub_fields'][] = $mapping_field; + + // Add Contact Reference Group. + $fields[] = $contact_group_field; + + } + + // "Recipient Contact Reference" Accordion wrapper close. + $fields[] = [ + 'key' => $this->field_key . 'mapping_accordion_contacts_close', + 'label' => __( 'Recipient Contact Reference', 'conditional-form-actions-for-acfe' ), + 'name' => '', + 'type' => 'accordion', + 'instructions' => '', + 'required' => 0, + 'conditional_logic' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + ], + 'acfe_permissions' => '', + 'open' => 0, + 'multi_expand' => 1, + 'endpoint' => 1, + ]; + + // --< + return $fields; + + } + + /** + * Defines the Fields in the "Email Fields" Accordion. + * + * @since 0.1 + * + * @return array $fields The array of Fields for this section. + */ + public function tab_mapping_accordion_email_add() { + + // Init return. + $fields = []; + + // "Email Fields" Accordion wrapper open. + $fields[] = [ + 'key' => $this->field_key . 'mapping_accordion_email_open', + 'label' => __( 'Email Fields', 'conditional-form-actions-for-acfe' ), + 'name' => '', + 'type' => 'accordion', + 'instructions' => '', + 'required' => 0, + 'conditional_logic' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + ], + 'acfe_permissions' => '', + 'open' => 0, + 'multi_expand' => 1, + 'endpoint' => 0, + ]; + + // Add "Mapping" Fields. + foreach ( $this->mapped_email_fields as $name => $title ) { + $fields[] = $this->mapping_field_get( $name, $title ); + } + + // "Email Fields" Accordion wrapper close. + $fields[] = [ + 'key' => $this->field_key . 'mapping_accordion_email_close', + 'label' => __( 'Email Fields', 'conditional-form-actions-for-acfe' ), + 'name' => '', + 'type' => 'accordion', + 'instructions' => '', + 'required' => 0, + 'conditional_logic' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + ], + 'acfe_permissions' => '', + 'open' => 0, + 'multi_expand' => 1, + 'endpoint' => 1, + ]; + + // --< + return $fields; + + } + + /** + * Builds Email 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 Email data. + */ + public function form_email_data( $form, $current_post_id, $action ) { + + // Init data array. + $data = []; + + // Get Field data. + $data['from'] = get_sub_field( $this->field_key . 'from' ); + $data['from'] = acfe_form_map_field_value( $from, $current_post_id, $form ); + + $data['reply_to'] = get_sub_field( $this->field_key . 'reply_to' ); + $data['reply_to'] = acfe_form_map_field_value( $reply_to, $current_post_id, $form ); + + $data['to'] = get_sub_field($this->field_key . 'to' ); + $data['to'] = acfe_form_map_field_value( $to, $current_post_id, $form ); + + $data['cc'] = get_sub_field( $this->field_key . 'cc' ); + $data['cc'] = acfe_form_map_field_value( $cc, $current_post_id, $form ); + + $data['bcc'] = get_sub_field( $this->field_key . 'bcc' ); + $data['bcc'] = acfe_form_map_field_value( $bcc, $current_post_id, $form ); + + $data['subject'] = get_sub_field( $this->field_key . 'subject' ); + $data['subject'] = acfe_form_map_field_value( $subject, $current_post_id, $form ); + + $data['content'] = get_sub_field( $this->field_key . 'content' ); + $data['content'] = acfe_form_map_field_value( $content, $current_post_id, $form ); + + // Get Email Conditional Reference. + $data['email_conditional_ref'] = get_sub_field( $this->field_key . 'map_email_conditional' ); + $conditionals = [ $data['email_conditional_ref'] ]; + + // Populate array with mapped Conditional Field values. + $conditionals = acfe_form_map_vs_fields( $conditionals, $conditionals, $current_post_id, $form ); + + // Save Email Conditional. + $data['email_conditional'] = array_pop( $conditionals ); + + // --< + return $data; + + } + + /** + * Sends the Conditional Email given data from mapped Fields. + * + * @since 0.1 + * + * @param array $email_data The array of Email data. + * @return array|bool $email The Email data array, or false on failure. + */ + public function form_email_save( $email_data ) { + + // Init return. + $email = false; + + // Skip if the Email Conditional Reference Field has a value. + if ( ! empty( $email_data['email_conditional_ref'] ) ) { + // And the Email Conditional Field has no value. + if ( empty( $email_data['email_conditional'] ) ) { + return $email; + } + } + + // Add Custom Field data if present. + if ( ! empty ( $custom_data ) ) { + $email_data += $custom_data; + } + + // Unset Email Conditionals. + if ( isset( $email_data['email_conditional'] ) ) { + unset( $email_data['email_conditional'] ); + } + if ( isset( $email_data['email_conditional_ref'] ) ) { + unset( $email_data['email_conditional_ref'] ); + } + + // Strip out empty Fields. + $email_data = $this->form_data_prepare( $email_data ); + + // Sanity checks. + if ( empty( $email_data['contact_id'] ) || empty( $email_data['template_id'] ) ) { + return $email; + } + + // Send the Email. + $result = $this->civicrm->email->email_send( $email_data ); + + // Bail on failure. + if ( $result === false ) { + return $email; + } + + // --< + return $result; + + } + + /** + * Finds the linked Contact ID when it has been mapped. + * + * @since 0.1 + * + * @param string $action_name The name of the referenced Form Action. + * @return integer|bool $contact_id The numeric ID of the Contact, or false if not found. + */ + public function form_contact_id_get_mapped( $action_name ) { + + // Init return. + $contact_id = false; + + // We need an Action Name. + if ( empty( $action_name ) ) { + return $contact_id; + } + + // Get the Contact data for that Action. + $related_contact = acfe_form_get_action( $action_name, 'contact' ); + if ( empty( $related_contact['id'] ) ) { + return $contact_id; + } + + // Assign return. + $contact_id = (int) $related_contact['id']; + + // --< + return $contact_id; + + } + + /** + * Finds the linked Case ID when it has been mapped. + * + * @since 0.1 + * + * @param string $action_name The name of the referenced Form Action. + * @return integer|bool $case_id The numeric ID of the Case, or false if not found. + */ + public function form_case_id_get_mapped( $action_name ) { + + // Init return. + $case_id = false; + + // We need an Action Name. + if ( empty( $action_name ) ) { + return $case_id; + } + + // Get the Case ID for that Action. + $related_case_id = acfe_form_get_action( $action_name, 'id' ); + if ( empty( $related_case_id ) ) { + return $case_id; + } + + // Assign return. + $case_id = (int) $related_case_id; + + // --< + return $case_id; + + } + +} // Class ends. diff --git a/includes/form-actions/cfafa-form-action-product.php b/includes/form-actions/cfafa-form-action-product.php new file mode 100644 index 0000000..975862e --- /dev/null +++ b/includes/form-actions/cfafa-form-action-product.php @@ -0,0 +1,349 @@ +<?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. + $product_data = $this->form_data_get( $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_data_get( $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 ( $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. diff --git a/includes/form-actions/cfafa-form-action-redirect.php b/includes/form-actions/cfafa-form-action-redirect.php new file mode 100644 index 0000000..42c7734 --- /dev/null +++ b/includes/form-actions/cfafa-form-action-redirect.php @@ -0,0 +1,278 @@ +<?php +/** + * "CiviCRM Redirect" ACFE Form Action Class. + * + * Handles the "CiviCRM Redirect" ACFE Form Action. + * + * @package Conditional_Form_Actions_For_ACFE + * @since 0.1 + */ + +// Exit if accessed directly. +defined( 'ABSPATH' ) || exit; + +/** + * CiviCRM Profile Sync "CiviCRM Redirect" ACFE Form Action Class. + * + * A class that handles the "CiviCRM Redirect" ACFE Form Action. + * + * @since 0.1 + */ +class CFAFA_Form_Action_Redirect 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 = 'redirect_cfafa'; + + /** + * Field Key Prefix. + * + * @since 0.1 + * @access public + * @var string $field_key The prefix for the Field Key. + */ + public $field_key = 'field_cfafa_redirect_'; + + /** + * Field Name Prefix. + * + * @since 0.1 + * @access public + * @var string $field_name The prefix for the Field Name. + */ + public $field_name = 'cfafa_redirect_'; + + /** + * 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 = __( 'Conditional Redirect action', 'conditional-form-actions-for-acfe' ); + + // Alias Placeholder for this Form Action. + $this->alias_placeholder = __( 'Conditional Redirect', 'conditional-form-actions-for-acfe' ); + + // Init parent. + parent::__construct(); + + } + + /** + * Configure this object. + * + * @since 0.1 + */ + public function configure() { + + // Conditional Field. + $this->mapping_field_filters_add( 'redirect_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; + } + + // Populate Redirect data array. + $conditional_redirect = $this->form_redirect_data( $form, $current_post_id, $action ); + + // Do the Redirect with the data from the Form. + $conditional_redirect = $this->form_redirect_perform( $conditional_redirect ); + + // Save the results of this Action for later use. + $this->make_action_save( $action, $conditional_redirect ); + + } + + /** + * 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 = []; + + // Add URL Field. + $fields[] = [ + 'key' => $this->field_key . 'redirect_url', + 'label' => __( 'Redirect URL', 'conditional-form-actions-for-acfe' ), + 'name' => $this->field_name . 'redirect_url', + 'type' => 'text', + 'instructions' => __( 'The URL to redirect to. See "Cheatsheet" tab for all available template tags.', 'conditional-form-actions-for-acfe' ), + 'required' => 0, + 'conditional_logic' => 0, + 'wrapper' => [ + 'width' => '', + 'class' => '', + 'id' => '', + 'data-instruction-placement' => 'field' + ], + 'acfe_permissions' => '', + 'default_value' => '', + 'placeholder' => '', + 'prepend' => '', + 'append' => '', + 'maxlength' => '', + ]; + + // Add Conditional Field. + $code = 'redirect_conditional'; + $label = __( 'Conditional On', 'conditional-form-actions-for-acfe' ); + $conditional = $this->mapping_field_get( $code, $label ); + $conditional['placeholder'] = __( 'Always redirect', 'conditional-form-actions-for-acfe' ); + $conditional['wrapper']['data-instruction-placement'] = 'field'; + $conditional['instructions'] = __( 'To redirect only when a Form Field is populated, link this to the Form Field. To redirect 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 Redirect 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 Redirect data. + */ + public function form_redirect_data( $form, $current_post_id, $action ) { + + // Get some Form details. + $form_name = acf_maybe_get( $form, 'name' ); + $form_id = acf_maybe_get( $form, 'ID' ); + + // Init data array. + $data = []; + + // Get the Action variables. + $url = get_sub_field( $this->field_key . 'redirect_url' ); + $url = acfe_form_map_field_value( $url, $current_post_id, $form ); + + /** + * Filter the Redirect URL. + * + * @since 0.1 + * + * @param string $url The Redirect URL. + * @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 Form Action. + */ + $filter = 'acfe/form/submit/' . $this->action_name . '/url'; + $url = apply_filters( $filter, $url, $form, $current_post_id, $action ); + $url = apply_filters( $filter . '/form=' . $form_name, $url, $form, $current_post_id, $action ); + if ( ! empty( $action ) ) { + $url = apply_filters( $filter . '/action=' . $action, $url, $form, $current_post_id, $action ); + } + + // Add trimmed URL to the data array. + $data['redirect_url'] = trim( $url ); + + // Get Redirect Conditional Reference. + $data['redirect_conditional_ref'] = get_sub_field( $this->field_key . 'map_redirect_conditional' ); + $conditionals = [ $data['redirect_conditional_ref'] ]; + + // Populate array with mapped Conditional Field values. + $conditionals = acfe_form_map_vs_fields( $conditionals, $conditionals, $current_post_id, $form ); + + // Save Redirect Conditional. + $data['redirect_conditional'] = array_pop( $conditionals ); + + // --< + return $data; + + } + + /** + * Conditionally performs the redirect given data from mapped Fields. + * + * @since 0.1 + * + * @param array $redirect_data The array of Redirect data. + * @return array|bool $redirect The Redirect data array, or false on failure. + */ + public function form_redirect_perform( $redirect_data ) { + + // Skip if the Redirect Conditional Reference Field has a value. + if ( ! empty( $redirect_data['redirect_conditional_ref'] ) ) { + // And the Redirect Conditional Field has no value. + if ( empty( $redirect_data['redirect_conditional'] ) ) { + return $redirect_data; + } + } + + // Unset Redirect Conditionals. + if ( isset( $redirect_data['redirect_conditional'] ) ) { + unset( $redirect_data['redirect_conditional'] ); + } + if ( isset( $redirect_data['redirect_conditional_ref'] ) ) { + unset( $redirect_data['redirect_conditional_ref'] ); + } + + // Strip out empty Fields. + $redirect_data = $this->form_data_prepare( $redirect_data ); + + // Sanity check. + if ( empty( $redirect_data['redirect_url'] ) ) { + return false; + } + + // Do the redirect. + wp_redirect( $redirect_data['redirect_url'] ); + exit; + + } + +} // Class ends. -- GitLab