D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
home
/
everqlsh
/
www
/
wp-admin
/
user
/
577040
/
Filename :
addon.tar
back
Copy
class-integration.php 0000644 00000237352 15162271761 0010727 0 ustar 00 <?php /** * The Forminator_Integration class. * * @package Forminator */ /** * Class Forminator_Integration * Extend this class to create new forminator addon / integrations * Any change(s) to this file is subject to: * - Properly Written DocBlock! (what is this, why is that, how to be like those, etc, as long as you want!) * - Properly Written Changelog! * - Properly Written Sample Usage on @see Forminator_Integration_Simple * * @since 1.1 */ abstract class Forminator_Integration implements Forminator_Integration_Interface { /** * Multi Id * * @var mixed */ public $multi_id; /** * Slug will be used as identifier throughout forminator * make sure its unique, else it won't be loaded * or will carelessly override other addon with same slug * * @since 1.1 * @var string */ protected $_slug; /** * Version number of the Add-On * It will save on the wp options * And if user updated the addon, it will try to call @see Forminator_Integration::version_changed() * * @since 1.1 * @var string */ protected $_version; /** * Minimum version of Forminator, that the addon will work correctly * * @since 1.1 * @var string */ protected $_min_forminator_version; /** * URL info to of the Integration website / doc / info * * @since 1.1 * @var string */ protected $_url = 'http://wpmudev.com'; /** * Title of the addon will be used on add on list and add on setting * * @since 1.1 * @var string */ protected $_title; /** * Short version of the addon title, will be used at small places for the addon to be displayed * its optional, when its omitted it will use $_title * make sure its less then 10 chars to displayed correctly, we will auto truncate it if its more than 10 chars * * @since 1.1 * @var string */ protected $_short_title; /** * Integration Brief Desription, of what it does * * @since 1.1 * @var string */ protected $_description = ''; /** * Integration promotion description * * @since 1.7.1 * @var string */ protected $_promotion = ''; /** * Integration documentation link * * @since 1.7.1 * @var string */ protected $_documentation = ''; /** * Flag that an addon can be activated, that auto set by abstract * * @since 1.1 * @var bool */ private $is_activable = null; /** * Semaphore non redundant hooks for admin side * * @since 1.1 * @var bool */ private $_is_admin_hooked = false; /** * Semaphore non redundant hooks for global hooks * * @since 1.1 * @var bool */ private $_is_global_hooked = false; /** * Add-on order position * * @since 1.7.1 * @var int */ protected $_position = 1; /*********************************** Errors Messages ********************************/ /** * These error message can be set on the start of addon as default, or dynamically set on each related process * * @example $_activation_error_message can be dynamically set on activate() to display custom error messages when activatation failed * Default is empty, which will be replaced by forminator default messages */ /** * Error Message on activation * * @since 1.1 * @var string */ protected $_activation_error_message = ''; /** * Error Message on deactivation * * @since 1.1 * @var string */ protected $_deactivation_error_message = ''; /** * Error Message on update general settings * * @since 1.1 * @var string */ protected $_update_settings_error_message = ''; /*********************************** END Errors Messages ********************************/ /** * Form Hooks Instances with `module_id` as key * * @since 1.1 * @var Forminator_Integration_Hooks[]|array */ protected $addon_hooks_instances = array(); /** * Id of multiple provider accounts * * @var string */ public $multi_global_id; /** * Global Id for new integrations * * @var string */ public $global_id_for_new_integrations; /** * Support multiple accounts * * @var bool */ public $is_multi_global = false; /** * Wizard steps * * @var array */ private $steps = array(); /** * Nonce option name * * @var string */ const NONCE_OPTION_NAME = 'forminator_custom_nonce'; const DOMAIN = 'https://wpmudev.com'; const REDIRECT_URI = 'https://wpmudev.com/api/forminator/v1/provider'; /** * Get addon instance * * @return self */ public static function get_instance() { if ( is_null( static::$instance ) ) { static::$instance = new static(); } return static::$instance; } /** * Get this addon slug * * @see Forminator_Integration::$_slug * * its behave like `IDENTIFIER`, used for : * - easly calling this instance with @see forminator_get_addon(`slug`) * - avoid collision, registered as FIFO of @see do_action() * * Shouldn't be implemented / overridden on addons * * @since 1.1 * @return string */ final public function get_slug() { return $this->_slug; } /** * Get this addon version * * @since 1.1 * @return string */ final public function get_version() { return $this->_version; } /** * Get this addon requirement of installed forminator version * * @since 1.1 * @return string */ final public function get_min_forminator_version() { return $this->_min_forminator_version; } /** * Get external url of addon website / info / doc * * Can be overridden to offer dynamic external url display * * @since 1.1 * @return string */ public function get_url() { return $this->_url; } /** * Get redirect URL * * @param string $provider Provider. * @param string $action Action. * @param array $params Params. * @return string */ public static function redirect_uri( $provider, $action, $params ) { $params = wp_parse_args( $params, array( 'action' => $action, 'provider' => $provider, ) ); return add_query_arg( $params, self::REDIRECT_URI ); } /** * Validates request callback from WPMU DEV * * @param string $provider Provider. * @return bool */ public static function validate_callback_request( $provider ) { $wpnonce = filter_input( INPUT_GET, 'wpnonce', FILTER_SANITIZE_SPECIAL_CHARS ); $domain = filter_input( INPUT_GET, 'domain', FILTER_VALIDATE_URL ); $provider_input = filter_input( INPUT_GET, 'provider', FILTER_SANITIZE_SPECIAL_CHARS ); return ! empty( $wpnonce ) && self::verify_nonce( $wpnonce ) && self::DOMAIN === $domain && $provider === $provider_input; } /** * Helper function to validate nonce value. * * @param string $nonce Nonce. * * @return bool */ private static function verify_nonce( $nonce ) { return self::get_nonce_value() === $nonce; } /** * Helper function to generate unique none changeable nonce. * * @return string The unique nonce value. */ public static function get_nonce_value() { $nonce = get_option( self::NONCE_OPTION_NAME ); if ( empty( $nonce ) ) { /** * Generate the nonce value only once to avoid error response * when retrieving access token. */ $nonce = wp_generate_password( 40, false, false ); update_option( self::NONCE_OPTION_NAME, $nonce ); } return $nonce; } /** * Get external title of addon * * @since 1.1 * @return string */ final public function get_title() { return $this->_title; } /** * Get short title for small width placeholder * * @since 1.1 * @return string */ final public function get_short_title() { if ( empty( $this->_short_title ) ) { $this->_short_title = $this->_title; } return substr( $this->_short_title, 0, self::SHORT_TITLE_MAX_LENGTH ); } /** * Get Image * * @since 1.1 * @return string */ public function get_image() { return $this->assets_path() . 'image.png'; } /** * Get Retina image * * @since 1.1 * @return string */ public function get_image_x2() { return $this->assets_path() . 'image@2x.png'; } /** * Get banner image * * @since 1.7.1 * @return string */ public function get_banner() { return $this->assets_path() . 'banner.png'; } /** * Get retina banner image * * @since 1.7.1 * @return string */ public function get_banner_x2() { return $this->assets_path() . 'banner@2x.png'; } /** * Get icon * * @since 1.1 * @return string */ public function get_icon() { return $this->assets_path() . 'icon.png'; } /** * Get Retina icon * * @since 1.1 * @return string */ public function get_icon_x2() { return $this->assets_path() . 'icon@2x.png'; } /** * Get path to assets folder * * @return string */ public function assets_path(): string { return $this->addon_path() . 'assets/'; } /** * Get path to assets folder * * @return string */ public function addon_path(): string { return trailingslashit( forminator_plugin_url() . 'addons/pro/' . $this->get_slug() ); } /** * Get Description * * @since 1.1 * @return string */ public function get_description() { return $this->_description; } /** * Get promotion * * @since 1.7.1 * @return string */ public function get_promotion() { return __( $this->_promotion, 'forminator' ); // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText } /** * Get documentation link * * @since 1.7.1 * @return string */ public function get_documentation() { return $this->_documentation; } /** * Get add-on position * * @since 1.7.1 * @return int */ public function get_position() { return $this->_position; } /** * WP options name that holds settings of addon * * @since 1.1 * @return string */ final public function get_settings_options_name() { $addon_slug = $this->get_slug(); $addon = $this; $settings_options_name = 'forminator_addon_' . $this->get_slug() . '_settings'; /** * Filter wp options name for saving addon settings * * @since 1.1 * * @param string $settings_options_name * @param Forminator_Integration $addon Integration instance. */ $settings_options_name = apply_filters( 'forminator_addon_' . $addon_slug . '_settings_options_name', $settings_options_name, $addon ); return $settings_options_name; } /** * WP options name that holds current version of addon * * @since 1.1 * @return string */ final public function get_version_options_name() { $addon_slug = $this->get_slug(); $addon = $this; $version_options_name = 'forminator_addon_' . $this->get_slug() . '_version'; /** * Filter wp options name for saving addon version * * @since 1.1 * * @param string $version_options_name * @param Forminator_Integration $addon Integration instance. */ $version_options_name = apply_filters( 'forminator_addon_' . $addon_slug . '_version_options_name', $version_options_name, $addon ); return $version_options_name; } /** * Get multi global ids with identifiers. * * @return array */ final public function get_multi_global_ids() { $all_settings = $this->get_all_settings_values(); $multi_global_ids = array(); foreach ( $all_settings as $key => $settings ) { $multi_global_ids[ $key ] = ! empty( $settings['identifier'] ) ? $settings['identifier'] : ''; } return $multi_global_ids; } /** * Transform addon instance into array * * @since 1.1 * @return array */ final public function to_array() { $to_array = array( 'slug' => $this->get_slug(), 'is_pro' => $this->is_pro(), 'icon' => $this->get_icon(), 'icon_x2' => $this->get_icon_x2(), 'image' => $this->get_image(), 'image_x2' => $this->get_image_x2(), 'banner' => $this->get_banner(), 'banner_x2' => $this->get_banner_x2(), 'short_title' => $this->get_short_title(), 'title' => $this->get_title(), 'url' => $this->get_url(), 'description' => $this->get_description(), 'promotion' => $this->get_promotion(), 'documentation' => $this->get_documentation(), 'version' => $this->get_version(), 'min_forminator_version' => $this->get_min_forminator_version(), 'setting_options_name' => $this->get_settings_options_name(), 'version_option_name' => $this->get_version_options_name(), 'is_activable' => $this->is_activable(), 'is_settings_available' => $this->is_settings_available(), 'is_connected' => $this->is_connected(), 'is_multi_global' => $this->is_multi_global, 'new_global_id' => $this->global_id_for_new_integrations, 'position' => $this->get_position(), ); $addon_slug = $this->get_slug(); $addon = $this; /** * Filter array of addon properties * * @since 1.1 * * @param array $to_array array of addonn properties. * @param int $form_id Form ID. * @param Forminator_Integration $addon Integration Instance. */ $to_array = apply_filters( 'forminator_addon_' . $addon_slug . '_to_array', $to_array, $addon ); return $to_array; } /** * Transform addon instance into array with form relation * * @since 1.1 * @since 1.2 generate new multi_id to allow reference on wizard * * @param int $form_id Form Id. * * @return array */ final public function to_array_with_form( $form_id ) { $to_array = $this->to_array(); $is_allow_multi_on_form = $this->is_allow_multi_on_form(); $to_array['is_form_connected'] = $this->is_module_connected( $form_id ); $to_array['is_form_settings_available'] = $this->is_form_settings_available( $form_id ); $to_array['is_allow_multi_on_form'] = $is_allow_multi_on_form; $to_array['multi_id'] = $this->generate_form_settings_multi_id( $form_id ); // handle multiple form setting. if ( $is_allow_multi_on_form ) { $to_array['multi_ids'] = $this->get_form_settings_multi_ids( $form_id ); } $to_array_with_form = $to_array; $addon_slug = $this->get_slug(); $addon = $this; /** * Filter array of addon properties * * Including relation with form_id * * @since 1.1 * * @param array $to_array_with_form array of addonn properties. * @param int $form_id Form ID. * @param Forminator_Integration $addon Integration instance. */ $to_array_with_form = apply_filters( 'forminator_addon_' . $addon_slug . '_to_array_with_form', $to_array_with_form, $form_id, $addon ); return $to_array_with_form; } /** * Check if Plugin Is Pro * * @see forminator_get_pro_addon_list() * @since 1.1 * @return bool */ final public function is_pro() { if ( in_array( $this->_slug, array_keys( forminator_get_pro_addon_list() ), true ) ) { return true; } return false; } /** * Get activable status * * @since 1.1 * @return bool */ final public function is_activable() { if ( is_null( $this->is_activable ) ) { $this->is_activable = $this->check_is_activable(); } return $this->is_activable; } /** * Actually check requirement of an addon that can be activated * Override this method if you have another logic for checking activable_plugins * * @since 1.1 * @return bool */ public function check_is_activable() { // Check supported forminator version. if ( empty( $this->_min_forminator_version ) ) { forminator_addon_maybe_log( __METHOD__, $this->get_slug(), 'empty _min_forminator_version' ); return false; } $is_forminator_version_supported = version_compare( FORMINATOR_VERSION, $this->_min_forminator_version, '>=' ); if ( ! $is_forminator_version_supported ) { forminator_addon_maybe_log( __METHOD__, $this->get_slug(), $this->_min_forminator_version, FORMINATOR_VERSION, 'Forminator Version not supported' ); // un-strict version compare of forminator, override if needed. return true; } return true; } /** * Override or implement this method to add action when user deactivate addon * * @example DROP table * return true when succes * return false on failure, forminator will stop deactivate process * * @since 1.1 * @return bool */ public function deactivate() { return true; } /** * Override or implement this method to add action when user activate addon * * @example CREATE table * return true when succes * return false on failure, forminator will stop activation process * * @since 1.1 * @return bool */ public function activate() { return true; } /** * Override or implement this method to add action when version of addon changed * * @example CREATE table * return true when succes * return false on failure, forminator will stop activation process * * @since 1.1 * * @param string $old_version Old version. * @param string $new_version New version. * * @return bool */ public function version_changed( $old_version, $new_version ) { return true; } /** * Check if addon version has changed * * @since 1.1 * @return bool */ final public function is_version_changed() { $installed_version = $this->get_installed_version(); // new installed. if ( false === $installed_version ) { return false; } $version_is_changed = version_compare( $this->_version, $installed_version, '!=' ); if ( $version_is_changed ) { return true; } return false; } /** * Get currently installed addon version * retrieved from wp options * * @since 1.1 * @return string|bool */ final public function get_installed_version() { return get_option( $this->get_version_options_name(), false ); } /** * Get error message on activation * * @since 1.1 * @return string */ public function get_activation_error_message() { if ( ! empty( $this->_activation_error_message ) ) { return $this->_activation_error_message; } /* translators: integration title */ return sprintf( esc_html__( 'Sorry but we failed to activate %s Integration, don\'t hesitate to contact us', 'forminator' ), $this->get_title() ); } /** * Get error message on deactivation * * @since 1.1 * @return string */ public function get_deactivation_error_message() { if ( ! empty( $this->_deactivation_error_message ) ) { return $this->_deactivation_error_message; } /* translators: integration title */ return sprintf( esc_html__( 'Sorry but we failed to deactivate %s Integration, please try again', 'forminator' ), $this->get_title() ); } /** * Get error message on deactivation * * @since 1.1 * @return string */ public function get_update_settings_error_message() { if ( ! empty( $this->_update_settings_error_message ) ) { return $this->_update_settings_error_message; } return esc_html__( 'Sorry, we failed to update settings, please check your form and try again', 'forminator' ); } /** * Override this function to set wizardable settings * Default its and empty array which is indicating that Integration doesnt have settings * * Its multi array, with numerical key, start with `0` * Every step on wizard, will consist at least * - `callback` : when application requesting wizard, Forminator will do `call_user_func` on this value, with these arguments * - `$submitted_data` : array of submitted data POST-ed by user * - `$form_id` : current form_id when called on `Form Settings` or 0 when called on Global Settings * - `is_completed` : when application requesting wizard, will check if `Previous Step` `is_completed` by doing `call_user_func` on its value * this function should return `true` or `false` * * @since 1.1 * @return array */ public function settings_wizards() { // What this function return should looks like. $steps = array( // First Step / step `0`. array( /** * Value of `callback` will be passed as first argument of `call_user_func` * it does not have to be passed `$this` as reference such as `array( $this, 'sample_setting_first_step' )`, * But its encouraged to passed `$this` because you will be benefited with $this class instance, in case you need to call private function or variable inside it * you can make the value to be `some_function_name` as long `some_function_name` as long it will globally callable which will be checked with `is_callable` * and should be able to accept 2 arguments $submitted_data, $form_id * * This callback should return an array @see Forminator_Integration::sample_setting_first_step() * * @see Forminator_Integration::sample_setting_first_step() */ 'callback' => array( $this, 'sample_setting_first_step' ), /** * Before Forminator call the `calback`, Forminator will attempt to run `is_completed` from the previous step * In this case, `is_completed` will be called when Forminator trying to display Settings Wizard for Second Step / step `1` * Like `callback` its value will be passed as first argument of `call_user_func` * and no arguments passed to this function when its called * * @see Forminator_Integration::sample_setting_first_step_is_completed() */ 'is_completed' => array( $this, 'sample_setting_first_step_is_completed' ), ), ); return array(); } /** * Get Global Setting Wizard * This function will process @see Forminator_Integration::settings_wizards() * Please keep in mind this function will only be called when @see Forminator_Integration::is_settings_available() return `true` * Which is doing check on @see Forminator_Integration::settings_wizards() requirements is passed * * @since 1.1 * * @param array $submitted_data Submitted data. * @param int $form_id Form Id. * @param int $current_step Current step. * @param int $step Step. * * @return array|mixed */ final public function get_settings_wizard( $submitted_data, $form_id = 0, $current_step = 0, $step = 0 ) { $steps = $this->settings_wizards(); if ( ! is_array( $steps ) ) { /* translators: integration title */ return $this->get_empty_wizard( sprintf( esc_html__( 'No Settings available for %1$s', 'forminator' ), $this->get_title() ) ); } $total_steps = count( $steps ); if ( $total_steps < 1 ) { /* translators: integration title */ return $this->get_empty_wizard( sprintf( esc_html__( 'No Settings available for %1$s', 'forminator' ), $this->get_title() ) ); } if ( ! isset( $steps[ $step ] ) ) { // go to last step. $step = $total_steps - 1; return $this->get_settings_wizard( $submitted_data, $form_id, $current_step, $step ); } if ( $step > 0 ) { if ( $current_step > 0 ) { // check previous step is complete. $prev_step = $current_step - 1; $prev_step_is_completed = true; // only call `is_completed` when its defined. if ( isset( $steps[ $prev_step ]['is_completed'] ) && is_callable( $steps[ $prev_step ]['is_completed'] ) ) { $prev_step_is_completed = call_user_func( $steps[ $prev_step ]['is_completed'], $submitted_data ); } if ( ! $prev_step_is_completed ) { --$step; return $this->get_settings_wizard( $submitted_data, $form_id, $current_step, $step ); } } // only validation when it moves forward. if ( $step > $current_step ) { $current_step_result = $this->get_settings_wizard( $submitted_data, $form_id, $current_step, $current_step ); if ( isset( $current_step_result['has_errors'] ) && true === $current_step_result['has_errors'] ) { return $current_step_result; } else { // set empty submitted data for next step. $submitted_data = array(); } } } return $this->get_wizard( $steps, $submitted_data, $form_id, $step ); } /** * Get steps. * * @param int $form_id Form id. * @param string $module_type Module type. * @return array */ final public function get_steps( $form_id, $module_type = 'form' ) { if ( ! empty( $this->steps[ $form_id ] ) ) { $steps = $this->steps[ $form_id ]; } else { $settings_steps = array(); if ( ! $this->is_connected() ) { $settings_steps = $this->settings_wizards(); } $get_module_settings_steps = 'get_' . $module_type . '_settings_steps'; $form_settings_steps = $this->$get_module_settings_steps( $form_id ); $steps = array_merge( $settings_steps, $form_settings_steps ); } return $steps; } /** * Get Form Setting Wizard * This function will process @see Forminator_Integration::settings_wizards() * Please keep in mind this function will only be called when @see Forminator_Integration::is_settings_available() return `true` * Which is doing check on @see Forminator_Integration::settings_wizards() requirements is passed * * @since 1.1 * * @param array $submitted_data Submitted data. * @param int $form_id Form Id. * @param int $current_step Current step. * @param int $step Step. * * @return array|mixed */ final public function get_form_settings_wizard( $submitted_data, $form_id, $current_step = 0, $step = 0 ) { $steps = $this->get_steps( $form_id ); if ( ! is_array( $steps ) ) { /* translators: integration title */ return $this->get_empty_wizard( sprintf( esc_html__( 'No Form Settings available for %1$s', 'forminator' ), $this->get_title() ) ); } $total_steps = count( $steps ); if ( $total_steps < 1 ) { /* translators: integration title */ return $this->get_empty_wizard( sprintf( esc_html__( 'No Form Settings available for %1$s', 'forminator' ), $this->get_title() ) ); } if ( ! isset( $steps[ $step ] ) ) { // go to last step. $step = $total_steps - 1; return $this->get_form_settings_wizard( $submitted_data, $form_id, $current_step, $step ); } if ( $step > 0 ) { if ( $current_step > 0 ) { // check previous step is complete. $prev_step = $current_step - 1; $prev_step_is_completed = true; // only call `is_completed` when its defined. if ( isset( $steps[ $prev_step ]['is_completed'] ) && is_callable( $steps[ $prev_step ]['is_completed'] ) ) { $prev_step_is_completed = call_user_func( $steps[ $prev_step ]['is_completed'], $submitted_data ); } if ( ! $prev_step_is_completed ) { --$step; return $this->get_form_settings_wizard( $submitted_data, $form_id, $current_step, $step ); } } // only validation when it moves forward. if ( $step > $current_step ) { $current_step_result = $this->get_form_settings_wizard( $submitted_data, $form_id, $current_step, $current_step ); if ( isset( $current_step_result['has_errors'] ) && true === $current_step_result['has_errors'] ) { return $current_step_result; } else { // set empty submitted data for next step, except preserved as reference. $preserved_keys = array( 'multi_id', ); foreach ( $submitted_data as $key => $value ) { if ( ! in_array( $key, $preserved_keys, true ) ) { unset( $submitted_data[ $key ] ); } } // Reset steps cache - uses when wizard steps are conditional. unset( $this->steps[ $form_id ] ); $steps = $this->get_steps( $form_id ); } } } $form_settings_wizard = $this->get_wizard( $steps, $submitted_data, $form_id, $step ); $addon_slug = $this->get_slug(); $addon = $this; $form_settings_instance = $this->get_addon_settings( $form_id, 'form' ); /** * Filter form settings wizard returned to client * * @since 1.1 * * @param array $form_settings_wizard * @param array $submitted_data $_POST from client. * @param int $form_id Form ID requested for. * @param int $current_step Current Step displayed to user, start from 0. * @param int $step Step requested by client, start from 0. * @param Forminator_Integration $addon Integration Instance. * @param Forminator_Integration_Form_Settings|null $form_settings_instance Integration Form settings instancce, or null if unavailable. */ $form_settings_wizard = apply_filters( 'forminator_addon_' . $addon_slug . '_form_settings_wizard', $form_settings_wizard, $submitted_data, $form_id, $current_step, $step, $addon, $form_settings_instance ); return $form_settings_wizard; } /** * Get form settings wizard steps * * @since 1.1 * * @param int $form_id Form Id. * * @return array */ private function get_form_settings_steps( $form_id ) { $addon_slug = $this->get_slug(); $addon = $this; $form_settings_steps = array(); $form_settings_instance = $this->get_addon_settings( $form_id, 'form' ); if ( ! is_null( $form_settings_instance ) && $form_settings_instance instanceof Forminator_Integration_Form_Settings ) { $form_settings_steps = $form_settings_instance->module_settings_wizards(); } /** * Filter form settings step that will be used for building wizard * * More detail : @param array $form_settings_steps * * @param int $form_id current form id. * @param Forminator_Integration_Form_Settings $addon Integration instance. * @param Forminator_Integration_Form_Settings|null Form settings of addon if available, or null otherwise *@see Forminator_Integration_Form_Settings::module_settings_wizards() * * @since 1.1 */ $form_settings_steps = apply_filters( 'forminator_addon_' . $addon_slug . '_form_settings_steps', $form_settings_steps, $form_id, $addon, $form_settings_instance ); return $form_settings_steps; } /** * Get settings multi id * * @since 1.1 * * @param int $form_id Form Id. * * @return array */ private function get_form_settings_multi_ids( $form_id ) { $addon_slug = $this->get_slug(); $addon = $this; $multi_ids = array(); $form_settings_instance = $this->get_addon_settings( $form_id, 'form' ); if ( $this->is_allow_multi_on_form() && ! is_null( $form_settings_instance ) && $form_settings_instance instanceof Forminator_Integration_Form_Settings ) { $multi_ids = $form_settings_instance->get_multi_ids(); } /** * Filter multi id of addon form settings * * @since 1.1 * * @param array $multi_ids * @param Forminator_Integration_Form_Settings $addon Integration Instance. * @param Forminator_Integration_Form_Settings $form_settings_instance Integration Form Settings Instance. */ $multi_ids = apply_filters( 'forminator_addon_' . $addon_slug . '_form_settings_multi_ids', $multi_ids, $addon, $form_settings_instance ); return $multi_ids; } /** * Get the requested wizard * * @since 1.1 * @since 1.2 Refactor setup default values, rename `hasBack` to `has_back` * * @param array $steps Steps. * @param array $submitted_data Submitted data. * @param int $module_id Module id. * @param int $step Step. * * @return array|mixed */ private function get_wizard( $steps, $submitted_data, $module_id, $step = 0 ) { $total_steps = count( $steps ); // validate callback, when it's empty or not callable, mark as no wizard. if ( ! isset( $steps[ $step ]['callback'] ) || ! is_callable( $steps[ $step ]['callback'] ) ) { /* translators: integration title */ return $this->get_empty_wizard( sprintf( esc_html__( 'No Settings available for %1$s', 'forminator' ), $this->get_title() ) ); } $wizard = call_user_func( $steps[ $step ]['callback'], $submitted_data, $module_id ); // a wizard to be able to processed by our application need to has at least `html` which will be rendered or `redirect` which will be the url for redirect user to go to. if ( ! isset( $wizard['html'] ) && ! isset( $wizard['redirect'] ) ) { /* translators: integration title */ return $this->get_empty_wizard( sprintf( esc_html__( 'No Settings available for %1$s', 'forminator' ), $this->get_title() ) ); } $wizard['forminator_addon_current_step'] = $step; $wizard['forminator_addon_count_step'] = $total_steps; $wizard['forminator_addon_has_next_step'] = ( ( $step + 1 ) >= $total_steps ? false : true ); $wizard['forminator_addon_has_prev_step'] = ( $step > 0 ? true : false ); $wizard_default_values = array( 'has_errors' => false, 'is_close' => false, 'notification' => array(), 'size' => 'small', 'has_back' => false, 'is_poll' => false, ); foreach ( $wizard_default_values as $key => $wizard_default_value ) { if ( ! isset( $wizard[ $key ] ) ) { $wizard[ $key ] = $wizard_default_value; } } $addon_slug = $this->get_slug(); $addon = $this; /** * Filter returned setting wizard to client * * @since 1.1 * * @param array $wizard current wizard. * @param Forminator_Integration $addon current addon instance. * @param array $steps defined settings / form settings steps. * @param array $submitted_data $_POST. * @param int $module_id current form_id. * @param int $step requested step. */ $wizard = apply_filters( 'forminator_addon_' . $addon_slug . '_wizard', $wizard, $addon, $steps, $submitted_data, $module_id, $step ); return $wizard; } /** * Get Empty wizard markup * * @since 1.1 * * @param string $notice Message. * * @return array */ protected function get_empty_wizard( $notice ) { $empty_wizard_html = Forminator_Admin::get_red_notice( esc_html( $notice ) ); /** * Filter html markup for empty wizard * * @since 1.1 * * @param string $empty_wizard_html * @param string $notice notice or message to be displayed on empty wizard. */ $empty_wizard_html = apply_filters( 'forminator_addon_empty_wizard_html', $empty_wizard_html, $notice ); return array( 'html' => $empty_wizard_html, 'buttons' => array( 'close' => array( 'action' => 'close', 'data' => array(), 'markup' => self::get_button_markup( esc_html__( 'Close', 'forminator' ), 'sui-button-ghost forminator-addon-close' ), ), ), ); } /** * Override this function if addon need to do something with addon setting values * * @example transform, load from other storage ? * called when rendering settings form * * @since 1.1 * * @param array $values Settings. * * @return mixed */ public function before_get_settings_values( $values ) { return $values; } /** * Get settings value * its already hooked with * * @see before_get_settings_values * * @since 1.1 * @return array */ final public function get_settings_values() { $all_values = $this->get_all_settings_values(); if ( is_null( $this->multi_global_id ) ) { $values = $all_values ? reset( $all_values ) : array(); } elseif ( isset( $all_values[ $this->multi_global_id ] ) ) { $values = $all_values[ $this->multi_global_id ]; } else { $values = array(); } $addon_slug = $this->get_slug(); /** * Filter retrieved saved addon's settings values from db * * @since 1.1 * * @param mixed $values */ $values = apply_filters( 'forminator_addon_' . $addon_slug . '_get_settings_values', $values ); return $values; } /** * Get settings value for all accouns * * @return array */ final public function get_all_settings_values() { $all_values = get_option( $this->get_settings_options_name(), array() ); if ( $all_values && is_array( $all_values ) && ! is_array( reset( $all_values ) ) ) { // Backward compatibility before having multiple aprovider accounts. $this->multi_global_id = uniqid( '', true ); $all_values = array( $this->multi_global_id => $all_values ); update_option( $this->get_settings_options_name(), $all_values ); // Update modules integration options. $types = array( 'form', 'poll', 'quiz' ); global $wpdb; foreach ( $types as $type ) { $meta_key = 'forminator_addon_' . $this->get_slug() . '_' . $type . '_settings'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $results = $wpdb->get_results( $wpdb->prepare( "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = %s", $meta_key ), ARRAY_A ); $results = wp_list_pluck( $results, 'meta_value', 'post_id' ); foreach ( $results as $id => $value ) { update_post_meta( $id, $meta_key . '_' . $this->multi_global_id, maybe_unserialize( $value ) ); delete_post_meta( $id, $meta_key ); } } if ( 'hubspot' === $this->get_slug() ) { $option_name = 'forminator-hubspot-token'; $option_value = get_option( $option_name ); if ( $option_value ) { update_option( $option_name . $this->multi_global_id, $option_value ); delete_option( $option_name ); } } } return $all_values; } /** * Override this function if addon need to do something with addon setting values * * @example transform, save to other storage ? * Called before settings values saved to db * * @since 1.1 * * @param array $values Settings. * * @return mixed */ public function before_save_settings_values( $values ) { return $values; } /** * Save settings value * its already hooked with * * @see before_save_settings_values * * @since 1.1 * * @param array $values Settings. */ final public function save_settings_values( $values ) { $addon_slug = $this->get_slug(); $all_values = $this->get_all_settings_values(); /** * Filter settings values of addon to be saved * * `$addon_slug` is current slug of addon that will on save. * Example : `malchimp`, `webhook`, `etc` * * @since 1.1 * * @param mixed $values */ $values = apply_filters( 'forminator_addon_' . $addon_slug . '_save_settings_values', $values ); if ( empty( $this->multi_global_id ) ) { $this->multi_global_id = uniqid( '', true ); } if ( $this->is_multi_global ) { $all_values[ $this->multi_global_id ] = forminator_sanitize_array_field( $values ); } else { $all_values = array( $this->multi_global_id => forminator_sanitize_array_field( $values ), ); } update_option( $this->get_settings_options_name(), $all_values ); } /** * Auto Attach Default Admin hooks for addon * * @since 1.1 * @return bool */ final public function admin_hookable() { if ( $this->_is_admin_hooked ) { return true; } $default_filters = array( 'forminator_addon_' . $this->get_slug() . '_save_settings_values' => array( array( $this, 'before_save_settings_values' ), 1 ), ); if ( $this->is_connected() ) { $default_filters[ 'forminator_addon_' . $this->get_slug() . '_save_form_settings_values' ] = array( array( $this, 'before_save_form_settings_values' ), 2 ); $default_filters[ 'forminator_addon_' . $this->get_slug() . '_save_poll_settings_values' ] = array( array( $this, 'before_save_poll_settings_values' ), 2 ); $default_filters[ 'forminator_addon_' . $this->get_slug() . '_save_quiz_settings_values' ] = array( array( $this, 'before_save_quiz_settings_values' ), 2 ); } foreach ( $default_filters as $filter => $default_filter ) { $function_to_add = $default_filter[0]; if ( is_callable( $function_to_add ) ) { $accepted_args = $default_filter[1]; add_filter( $filter, $function_to_add, 10, $accepted_args ); } } $this->_is_admin_hooked = true; return true; } /** * Maintain hooks all pages for addons * * @since 1.1 * @return bool */ final public function global_hookable() { if ( $this->_is_global_hooked ) { return true; } $default_filters = array( 'forminator_addon_' . $this->get_slug() . '_get_settings_values' => array( array( $this, 'before_get_settings_values' ), 1 ), ); if ( $this->is_connected() ) { $default_filters[ 'forminator_addon_' . $this->get_slug() . '_get_form_settings_values' ] = array( array( $this, 'before_get_form_settings_values' ), 2 ); $default_filters[ 'forminator_addon_' . $this->get_slug() . '_get_poll_settings_values' ] = array( array( $this, 'before_get_poll_settings_values' ), 2 ); $default_filters[ 'forminator_addon_' . $this->get_slug() . '_get_quiz_settings_values' ] = array( array( $this, 'before_get_quiz_settings_values' ), 2 ); } foreach ( $default_filters as $filter => $default_filter ) { $function_to_add = $default_filter[0]; if ( is_callable( $function_to_add ) ) { $accepted_args = $default_filter[1]; add_filter( $filter, $function_to_add, 10, $accepted_args ); } } $this->_is_global_hooked = true; return true; } /** * Override this function if you need to apply some conditional logic on it * By Default this function will only check @see Forminator_Integration::settings_wizards() as valid multi array * * @since 1.1 * @return bool */ public function is_settings_available() { $steps = $this->settings_wizards(); if ( ! is_array( $steps ) ) { return false; } if ( count( $steps ) < 1 ) { return false; } return true; } /** * Override this function if you need to apply some conditional logic on it * By Default this function will check * * @param int $form_id Form Id. * * @return bool * @since 1.1 * * @see Forminator_Integration::settings_wizards() * @see Forminator_Integration_Form_Settings::module_settings_wizards() * as valid multi array */ public function is_form_settings_available( $form_id ) { $steps = $this->get_steps( $form_id ); if ( ! is_array( $steps ) ) { return false; } if ( count( $steps ) < 1 ) { return false; } return true; } /** * Flag for check if and addon connected (global settings such as api key complete) * * Please apply necessary WordPress hook on the inheritance class * * @since 1.1 * @return boolean */ public function is_connected() { $is_connected = $this->is_active() && $this->is_authorized(); /** * Filter connected status * * @param bool $is_connected */ $is_connected = apply_filters( 'forminator_addon_' . $this->get_slug() . '_is_connected', $is_connected ); return $is_connected; } /** * Authorized Callback * * @return bool */ public function is_authorized() { return false; } /** * Flag for check if and addon connected to a form(form settings such as list id completed) * * Please apply necessary WordPress hook on the inheritance class * * @since 1.1 * @param int $module_id Form ID. * @param string $module_slug Module type. * @param bool $check_lead Check is lead connected or not. * @return boolean * @throws Forminator_Integration_Exception When there is an Interaction error. */ public function is_module_connected( $module_id, $module_slug = 'form', $check_lead = false ) { try { $addon_settings = null; if ( ! $this->is_connected() ) { throw new Forminator_Integration_Exception( esc_html__( ' Integration is not connected', 'forminator' ) ); } $addon_settings = $this->get_addon_settings( $module_id, $module_slug ); if ( ! $addon_settings instanceof Forminator_Integration_Settings ) { throw new Forminator_Integration_Exception( esc_html__( 'Invalid Module Integration Settings', 'forminator' ) ); } if ( $check_lead ) { $is_connected = $addon_settings->has_lead(); } else { // Mark as active when there is at least one active connection. if ( false === $addon_settings->find_one_active_connection() ) { throw new Forminator_Integration_Exception( esc_html__( 'No active Integration connection found in this module', 'forminator' ) ); } $is_connected = true; } } catch ( Forminator_Integration_Exception $e ) { $is_connected = false; forminator_addon_maybe_log( __METHOD__, '[' . $this->get_title() . ']' . $e->getMessage() ); } /** * Filter addon connected status with the form * * @param bool $is_connected * @param int $module_id Current Module ID. * @param Forminator_Integration_Form_Settings $addon_settings Instance of form settings, or null when unavailable. */ $is_connected = apply_filters( 'forminator_addon_' . $this->get_slug() . '_is_' . $module_slug . ( $check_lead ? '_lead' : '' ) . '_connected', $is_connected, $module_id, $addon_settings ); return $is_connected; } /** * Check if this addon on active * * @since 1.1 * @return bool */ final public function is_active() { return forminator_addon_is_active( $this->get_slug() ); } /** * Flag show full log on entries * * @return bool */ public function is_show_full_log() { $slug = $this->get_slug(); $const = 'FORMINATOR_ADDON_' . strtoupper( $slug ) . '_SHOW_FULL_LOG'; $glob = 'FORMINATOR_ADDON_SHOW_FULL_LOG'; $show_full_log = ( defined( $const ) && constant( $const ) ) || ( defined( $glob ) && constant( $glob ) ); /** * Filter Flag show full log on entries * * @params bool $show_full_log */ $show_full_log = apply_filters( 'forminator_addon_' . $slug . '_show_full_log', $show_full_log ); return $show_full_log; } /** * Get ClassName of addon Module Settings * * @see Forminator_Integration_Settings * * @param string $module_type Module type. * * @since 1.1 * @return null|string */ final public function get_settings_class_name( $module_type ) { $addon_slug = $this->get_slug(); $settings_class_name = 'Forminator_' . ucfirst( $addon_slug ) . '_' . ucfirst( $module_type ) . '_Settings'; /** * Filter class name of the addon module settings * * Module settings class name is a string * it will be validated by `class_exists` and must be instanceof @see Forminator_Integration_Settings * * @since 1.1 * * @param string $settings_class_name */ $settings_class_name = apply_filters( 'forminator_addon_' . $addon_slug . '_' . $module_type . '_settings_class_name', $settings_class_name ); return $settings_class_name; } /** * Get Form Settings Instance * * @since 1.1 * * @param int $module_id Module type. * @param string $module_type Moodule type. * * @return Forminator_Integration_Form_Settings | null * @throws Forminator_Integration_Exception When there is an Integration error. */ final public function get_addon_settings( $module_id, $module_type ) { $class_name = $this->get_settings_class_name( $module_type ); if ( empty( $class_name ) || ! class_exists( $class_name ) ) { return null; } try { $settings_instance = new $class_name( $this, $module_id ); if ( ! $settings_instance instanceof Forminator_Integration_Settings ) { throw new Forminator_Integration_Exception( $class_name . ' is not instanceof Forminator_Integration_Settings' ); } forminator_maybe_attach_addon_hook( $this ); return $settings_instance; } catch ( Exception $e ) { forminator_addon_maybe_log( $this->get_slug(), 'Failed to instantiate its _addon_settings_instances', $e->getMessage(), $e->getTrace() ); return null; } } /** * Executor of before get form settings values, to be correctly mapped with form_setting instance for form_id * * @since 1.1 * * @param string $values Settings. * @param int $form_id Form Id. * * @return mixed */ final public function before_get_form_settings_values( $values, $form_id ) { $form_settings = $this->get_addon_settings( $form_id, 'form' ); if ( $form_settings instanceof Forminator_Integration_Form_Settings ) { if ( is_callable( array( $form_settings, 'before_get_form_settings_values' ) ) ) { return $form_settings->before_get_form_settings_values( $values ); } } return $values; } /** * Executor of before save form settings values, to be correctly mapped with form_setting instance for form_id * * @since 1.1 * * @param string $values Settings. * @param int $form_id Form Id. * * @return mixed */ final public function before_save_form_settings_values( $values, $form_id ) { $form_settings = $this->get_addon_settings( $form_id, 'form' ); if ( $form_settings instanceof Forminator_Integration_Form_Settings ) { if ( is_callable( array( $form_settings, 'before_save_form_settings_values' ) ) ) { return $form_settings->before_save_form_settings_values( $values ); } } return $values; } /** * Get Hooks object of Integrations * * @param int $module_id Module ID. * @param int $module_type Module type. * * @return Forminator_Integration_Hooks|null * @since 1.1 */ final public function get_addon_hooks( $module_id, $module_type ) { if ( ! isset( $this->addon_hooks_instances[ $module_id ] ) || ! $this->addon_hooks_instances[ $module_id ] instanceof Forminator_Integration_Hooks ) { $addon_slug = $this->get_slug(); $classname = 'Forminator_' . ucfirst( $addon_slug ) . '_' . ucfirst( $module_type ) . '_Hooks'; if ( ! class_exists( $classname ) ) { return null; } try { $this->addon_hooks_instances[ $module_id ] = new $classname( $this, $module_id ); } catch ( Exception $e ) { forminator_addon_maybe_log( $this->get_slug(), 'Failed to instantiate its addon_hooks_instance', $e->getMessage() ); return null; } } return $this->addon_hooks_instances[ $module_id ]; } /** * SAMPLE of callback wizard * * @example { * 'html' : '', => will contains title, description, and form it self * 'has_errors' : true/false => true when it has error, such as invalid input * buttons [ * submit [ * action: forminator_load_mailchimp_settings * data: { * step: 2 * }, * markup: '<a></a>' * ], * disconnect [ * action: forminator_disconnect_mailchimp, * data: [], * markup: '<a></a>' * ] * } * 'redirect': '', * 'is_close' : true if wizard should be closed * ] * * @param array $submitted_data Submitted data. * @param int $form_id Form Id. * * @since 1.1 * @return array */ private function sample_setting_first_step( $submitted_data, $form_id ) { // TODO: break `html` into `parts` to make easier for addon to extend. return array( 'html' => '<p>Hello im from first step settings</p>', 'has_errors' => false, ); } /** * SAMPLE of is_completed wizard step * * @since 1.1 * @return bool */ private function sample_setting_first_step_is_completed() { // check something. return true; // when check is passed. } /** * Override this function if you wanna make an addon allow multiple instance on 1 form * * @since 1.1 * @return bool */ public function is_allow_multi_on_form() { return false; } /** * Return button markup * * @since 1.1 * * @param string $label Text label. * @param string $classes Class names. * @param string $tooltip Content for Tooltip. * * @return string */ public static function get_button_markup( $label, $classes = '', $tooltip = '' ) { $markup = '<button type="button" class="sui-button '; if ( ! empty( $classes ) ) { $markup .= $classes; } $markup .= '"'; if ( ! empty( $tooltip ) ) { $markup .= 'data-tooltip="' . $tooltip . '"'; } $markup .= '>'; $markup .= '<span class="sui-loading-text">' . $label . '</span>'; $markup .= '<i class="sui-icon-loader sui-loading" aria-hidden="true"></i>'; $markup .= '</button>'; /** * Filter Integration button markup for setting * * Its possible @see Forminator_Integration::get_button_markup() overridden. * Thus this filter wont be called * * @since 1.1 * * @param string $markup Current markup. * @param string $label Button label. * @param string $classes Additional classes for `<button>`. * @param string $tooltip */ $markup = apply_filters( 'forminator_addon_setting_button_markup', $markup, $label, $classes, $tooltip ); return $markup; } /** * Return link markup * * @since 1.13 * * @param string $url URL. * @param string $label Text for label. * @param string $target Target attribute. * @param string $classes Class names. * @param string $tooltip Content for tooltip. * * @return string */ public static function get_link_markup( $url, $label, $target = '_blank', $classes = '', $tooltip = '' ) { $markup = '<a href="' . $url . '" target="' . $target . '" class="sui-button '; if ( ! empty( $classes ) ) { $markup .= $classes; } $markup .= '"'; if ( ! empty( $tooltip ) ) { $markup .= 'data-tooltip="' . $tooltip . '"'; } $markup .= '>'; $markup .= '<span class="sui-loading-text">' . $label . '</span>'; $markup .= '<i class="sui-icon-loader sui-loading" aria-hidden="true"></i>'; $markup .= '</a>'; /** * Filter Integration link markup for setting * * Its possible @see Forminator_Integration::get_link_markup() overridden. * Thus this filter wont be called * * @since 1.1 * * @param string $markup Current markup. * @param string $url Link URL. * @param string $label Button label. * @param string $target Link target. * @param string $classes Additional classes for `<button>`. * @param string $tooltip */ $markup = apply_filters( 'forminator_addon_setting_link_markup', $markup, $url, $label, $target, $classes, $tooltip ); return $markup; } /** * Get Template as string * * @since 1.2 * * @param string $template Template path. * @param array $params Template variables. * * @return string */ public static function get_template( $template, $params ) { /* @noinspection PhpUnusedLocalVariableInspection */ $template_vars = $params; ob_start(); /* @noinspection PhpIncludeInspection */ include $template; $html = ob_get_clean(); /** * Filter Html String from template * * @since 1.2 * * @param string $html * @param string $template template file path. * @param array $params template variables. */ $html = apply_filters( 'forminator_addon_get_template', $html, $template, $params ); return $html; } /** * Register section(s) on integrations page * * @see wp-admin/admin.php?page=forminator-integrations * * @since 1.2 * * @return array */ public function register_integration_sections() { // callback must be public method on this class. return array(); } /** * Get Callback of section on integration page * * When section not provided, it will return all callbacks * * @since 1.2 * * @param string $section Section. * * @return array|null */ public function get_integration_section_callback( $section = null ) { $addon_slug = $this->_slug; $integration_sections = $this->register_integration_sections(); $callback = null; if ( is_null( $section ) ) { $callback = $integration_sections; } elseif ( isset( $integration_sections[ $section ] ) ) { $callback = $integration_sections[ $section ]; } /** * Filter Integration section callback * * @since 1.2 * * @param array|null $callback * @param string|null $section requested section. * @param array $integration_sections registered sections. */ $callback = apply_filters( 'forminator_addon_' . $addon_slug . '_integration_section_callback', $callback, $section, $integration_sections ); return $callback; } /** * Generate multi_id * * @since 1.2 * * @param int $form_id Form id. * * @return array */ private function generate_form_settings_multi_id( $form_id ) { $addon_slug = $this->get_slug(); $addon = $this; $multi_id = 0; $form_settings_instance = $this->get_addon_settings( $form_id, 'form' ); if ( $this->is_allow_multi_on_form() && ! is_null( $form_settings_instance ) && $form_settings_instance instanceof Forminator_Integration_Form_Settings ) { $multi_id = $form_settings_instance->generate_multi_id(); } /** * Filter new generated multi id of addon form setting * * @since 1.2 * * @param string $multi_id * @param Forminator_Integration_Form_Settings $addon Integration Instance. * @param Forminator_Integration_Form_Settings $form_settings_instance Integration Form Settings Instance. */ $multi_ids = apply_filters( 'forminator_addon_' . $addon_slug . '_form_settings_multi_id', $multi_id, $addon, $form_settings_instance ); return $multi_ids; } /** * Executor of before get form settings values, to be correctly mapped with poll_setting instance for poll_id * * @since 1.6.1 * * @param array $values Settings. * @param int $poll_id Poll Id. * * @return mixed */ final public function before_get_poll_settings_values( $values, $poll_id ) { $poll_settings = $this->get_addon_settings( $poll_id, 'poll' ); if ( $poll_settings instanceof Forminator_Integration_Poll_Settings ) { if ( is_callable( array( $poll_settings, 'before_get_poll_settings_values' ) ) ) { return $poll_settings->before_get_poll_settings_values( $values ); } } return $values; } /** * Executor of before save form settings values, to be correctly mapped with poll_setting instance for poll_id * * @since 1.6.1 * * @param array $values Settings. * @param int $poll_id Poll Id. * * @return mixed */ final public function before_save_poll_settings_values( $values, $poll_id ) { $poll_settings = $this->get_addon_settings( $poll_id, 'poll' ); if ( $poll_settings instanceof Forminator_Integration_Poll_Settings ) { if ( is_callable( array( $poll_settings, 'before_save_poll_settings_values' ) ) ) { return $poll_settings->before_save_poll_settings_values( $values ); } } return $values; } /** * Get Poll Setting Wizard * This function will process @see Forminator_Integration::settings_wizards() * Please keep in mind this function will only be called when @see Forminator_Integration::is_settings_available() return `true` * Which is doing check on @see Forminator_Integration::settings_wizards() requirements is passed * * @since 1.6.1 * * @param array $submitted_data Submitted data. * @param int $poll_id Poll Id. * @param int $current_step Current step. * @param int $step Step. * * @return array|mixed */ final public function get_poll_settings_wizard( $submitted_data, $poll_id, $current_step = 0, $step = 0 ) { $settings_steps = array(); if ( ! $this->is_connected() ) { $settings_steps = $this->settings_wizards(); } $poll_settings_steps = $this->get_poll_settings_steps( $poll_id ); $steps = array_merge( $settings_steps, $poll_settings_steps ); if ( ! is_array( $steps ) ) { /* translators: integration title */ return $this->get_empty_wizard( sprintf( esc_html__( 'No Poll Settings available for %1$s', 'forminator' ), $this->get_title() ) ); } $total_steps = count( $steps ); if ( $total_steps < 1 ) { /* translators: integration title */ return $this->get_empty_wizard( sprintf( esc_html__( 'No Poll Settings available for %1$s', 'forminator' ), $this->get_title() ) ); } if ( ! isset( $steps[ $step ] ) ) { // go to last step. $step = $total_steps - 1; return $this->get_poll_settings_wizard( $submitted_data, $poll_id, $current_step, $step ); } if ( $step > 0 ) { if ( $current_step > 0 ) { // check previous step is complete. $prev_step = $current_step - 1; $prev_step_is_completed = true; // only call `is_completed` when its defined. if ( isset( $steps[ $prev_step ]['is_completed'] ) && is_callable( $steps[ $prev_step ]['is_completed'] ) ) { $prev_step_is_completed = call_user_func( $steps[ $prev_step ]['is_completed'], $submitted_data ); } if ( ! $prev_step_is_completed ) { --$step; return $this->get_poll_settings_wizard( $submitted_data, $poll_id, $current_step, $step ); } } // only validation when it moves forward. if ( $step > $current_step ) { $current_step_result = $this->get_poll_settings_wizard( $submitted_data, $poll_id, $current_step, $current_step ); if ( isset( $current_step_result['has_errors'] ) && true === $current_step_result['has_errors'] ) { return $current_step_result; } else { // set empty submitted data for next step, except preserved as reference. $preserved_keys = array( 'multi_id', ); foreach ( $submitted_data as $key => $value ) { if ( ! in_array( $key, $preserved_keys, true ) ) { unset( $submitted_data[ $key ] ); } } } } } $poll_settings_wizard = $this->get_wizard( $steps, $submitted_data, $poll_id, $step ); $addon_slug = $this->get_slug(); $addon = $this; $poll_settings_instance = $this->get_addon_settings( $poll_id, 'poll' ); /** * Filter poll settings wizard returned to client * * @since 1.6.1 * * @param array $poll_settings_wizard * @param array $submitted_data $_POST from client. * @param int $poll_id poll ID requested for. * @param int $current_step Current Step displayed to user, start from 0. * @param int $step Step requested by client, start from 0. * @param Forminator_Integration $addon Integration Instance. * @param Forminator_Integration_Poll_Settings|null $poll_settings_instance Integration Form settings instance, or null if unavailable. */ $poll_settings_wizard = apply_filters( 'forminator_addon_' . $addon_slug . '_poll_settings_wizard', $poll_settings_wizard, $submitted_data, $poll_id, $current_step, $step, $addon, $poll_settings_instance ); return $poll_settings_wizard; } /** * Get poll settings wizard steps * * @since 1.6.1 * * @param int $poll_id Poll Id. * * @return array */ private function get_poll_settings_steps( $poll_id ) { $addon_slug = $this->get_slug(); $addon = $this; $poll_settings_steps = array(); $poll_settings_instance = $this->get_addon_settings( $poll_id, 'poll' ); if ( ! is_null( $poll_settings_instance ) && $poll_settings_instance instanceof Forminator_Integration_Poll_Settings ) { $poll_settings_steps = $poll_settings_instance->module_settings_wizards(); } /** * Filter form settings step that will be used for building wizard * * More detail : @param array $poll_settings_steps * * @param int $poll_id current form id. * @param Forminator_Integration $addon Integration instance. * @param Forminator_Integration_Poll_Settings|null $poll_settings_instance Form settings of addon if available, or null otherwise. *@see Forminator_Integration_Poll_Settings::module_settings_wizards() * * @since 1.6.1 */ $poll_settings_steps = apply_filters( 'forminator_addon_' . $addon_slug . '_poll_settings_steps', $poll_settings_steps, $poll_id, $addon, $poll_settings_instance ); return $poll_settings_steps; } /** * Get poll settings multi id * * @since 1.6.1 * * @param int $poll_id Poll Id. * * @return array */ private function get_poll_settings_multi_ids( $poll_id ) { $addon_slug = $this->get_slug(); $addon = $this; $multi_ids = array(); $poll_settings_instance = $this->get_addon_settings( $poll_id, 'poll' ); if ( $this->is_allow_multi_on_poll() && ! is_null( $poll_settings_instance ) && $poll_settings_instance instanceof Forminator_Integration_Poll_Settings ) { $multi_ids = $poll_settings_instance->get_multi_ids(); } /** * Filter multi id of addon poll settings * * @since 1.6.1 * * @param array $multi_ids * @param Forminator_Integration $addon Integration Instance. * @param Forminator_Integration_Poll_Settings $poll_settings_instance Integration Form Settings Instance. */ $multi_ids = apply_filters( 'forminator_addon_' . $addon_slug . '_poll_settings_multi_ids', $multi_ids, $addon, $poll_settings_instance ); return $multi_ids; } /** * Override this function if you wanna make an addon allow multiple instance on 1 poll * * @since 1.6.1 * @return bool */ public function is_allow_multi_on_poll() { return false; } /** * Transform addon instance into array with form relation * * @since 1.1 * @since 1.2 generate new multi_id to allow reference on wizard * * @param int $poll_id Poll Id. * * @return array */ final public function to_array_with_poll( $poll_id ) { $to_array = $this->to_array(); $is_allow_multi_on_poll = $this->is_allow_multi_on_poll(); $to_array['is_poll_connected'] = $this->is_module_connected( $poll_id, 'poll' ); $to_array['is_poll_settings_available'] = $this->is_poll_settings_available( $poll_id ); $to_array['is_allow_multi_on_poll'] = $is_allow_multi_on_poll; $to_array['multi_id'] = $this->generate_poll_settings_multi_id( $poll_id ); // handle multiple form setting. if ( $is_allow_multi_on_poll ) { $to_array['multi_ids'] = $this->get_poll_settings_multi_ids( $poll_id ); } $to_array_with_poll = $to_array; $addon_slug = $this->get_slug(); $addon = $this; /** * Filter array of addon properties * * Including relation with form_id * * @since 1.6.1 * * @param array $to_array_with_poll array of addon properties. * @param int $poll_id Poll ID. * @param Forminator_Integration $addon Integration instance. */ $to_array_with_poll = apply_filters( 'forminator_addon_' . $addon_slug . '_to_array_with_poll', $to_array_with_poll, $poll_id, $addon ); return $to_array_with_poll; } /** * Override this function if you need to apply some conditional logic on it * By Default this function will check * * @param int $poll_id Poll Id. * * @return bool * @since 1.6.1 * * @see Forminator_Integration::settings_wizards() * @see Forminator_Integration_Poll_Settings::module_settings_wizards() * as valid multi array */ public function is_poll_settings_available( $poll_id ) { $steps = array(); $poll_steps = $this->get_poll_settings_steps( $poll_id ); $steps = array_merge( $steps, $poll_steps ); if ( ! is_array( $steps ) ) { return false; } if ( count( $steps ) < 1 ) { return false; } return true; } /** * Generate multi_id * * @since 1.6.1 * * @param int $poll_id Poll Id. * * @return array */ private function generate_poll_settings_multi_id( $poll_id ) { $addon_slug = $this->get_slug(); $addon = $this; $multi_id = 0; $poll_settings_instance = $this->get_addon_settings( $poll_id, 'poll' ); if ( $this->is_allow_multi_on_poll() && ! is_null( $poll_settings_instance ) && $poll_settings_instance instanceof Forminator_Integration_Poll_Settings ) { $multi_id = $poll_settings_instance->generate_multi_id(); } /** * Filter new generated multi id of addon form setting * * @since 1.6.1 * * @param string $multi_id * @param Forminator_Integration $addon Integration Instance. * @param Forminator_Integration_Poll_Settings $poll_settings_instance Integration Poll Settings Instance. */ $multi_ids = apply_filters( 'forminator_addon_' . $addon_slug . '_poll_settings_multi_id', $multi_id, $addon, $poll_settings_instance ); return $multi_ids; } /** * Executor of before get form settings values, to be correctly mapped with quiz_setting instance for quiz_id * * @since 1.6.2 * * @param array $values Settings. * @param int $quiz_id Quiz Id. * * @return mixed */ final public function before_get_quiz_settings_values( $values, $quiz_id ) { $quiz_settings = $this->get_addon_settings( $quiz_id, 'quiz' ); if ( $quiz_settings instanceof Forminator_Integration_Quiz_Settings ) { if ( is_callable( array( $quiz_settings, 'before_get_quiz_settings_values' ) ) ) { return $quiz_settings->before_get_quiz_settings_values( $values ); } } return $values; } /** * Executor of before save form settings values, to be correctly mapped with quiz_setting instance for quiz_id * * @since 1.6.2 * * @param array $values Settings. * @param int $quiz_id Quiz Id. * * @return mixed */ final public function before_save_quiz_settings_values( $values, $quiz_id ) { $quiz_settings = $this->get_addon_settings( $quiz_id, 'quiz' ); if ( $quiz_settings instanceof Forminator_Integration_Quiz_Settings ) { if ( is_callable( array( $quiz_settings, 'before_save_quiz_settings_values' ) ) ) { return $quiz_settings->before_save_quiz_settings_values( $values ); } } return $values; } /** * Get Quiz Setting Wizard * This function will process @see Forminator_Integration::settings_wizards() * Please keep in mind this function will only be called when @see Forminator_Integration::is_settings_available() return `true` * Which is doing check on @see Forminator_Integration::settings_wizards() requirements is passed * * @since 1.6.2 * * @param array $submitted_data Submitted data. * @param int $quiz_id Quiz Id. * @param int $current_step Current step. * @param int $step Step. * * @return array|mixed */ final public function get_quiz_settings_wizard( $submitted_data, $quiz_id, $current_step = 0, $step = 0 ) { $steps = $this->get_steps( $quiz_id, 'quiz' ); if ( ! is_array( $steps ) ) { /* translators: integration title */ return $this->get_empty_wizard( sprintf( esc_html__( 'No Quiz Settings available for %1$s', 'forminator' ), $this->get_title() ) ); } $total_steps = count( $steps ); if ( $total_steps < 1 ) { /* translators: integration title */ return $this->get_empty_wizard( sprintf( esc_html__( 'No Quiz Settings available for %1$s', 'forminator' ), $this->get_title() ) ); } if ( ! isset( $steps[ $step ] ) ) { // go to last step. $step = $total_steps - 1; return $this->get_quiz_settings_wizard( $submitted_data, $quiz_id, $current_step, $step ); } if ( $step > 0 ) { if ( $current_step > 0 ) { // check previous step is complete. $prev_step = $current_step - 1; $prev_step_is_completed = true; // only call `is_completed` when its defined. if ( isset( $steps[ $prev_step ]['is_completed'] ) && is_callable( $steps[ $prev_step ]['is_completed'] ) ) { $prev_step_is_completed = call_user_func( $steps[ $prev_step ]['is_completed'], $submitted_data ); } if ( ! $prev_step_is_completed ) { --$step; return $this->get_quiz_settings_wizard( $submitted_data, $quiz_id, $current_step, $step ); } } // only validation when it moves forward. if ( $step > $current_step ) { $current_step_result = $this->get_quiz_settings_wizard( $submitted_data, $quiz_id, $current_step, $current_step ); if ( isset( $current_step_result['has_errors'] ) && true === $current_step_result['has_errors'] ) { return $current_step_result; } else { // set empty submitted data for next step, except preserved as reference. $preserved_keys = array( 'multi_id', ); foreach ( $submitted_data as $key => $value ) { if ( ! in_array( $key, $preserved_keys, true ) ) { unset( $submitted_data[ $key ] ); } } // Reset steps cache - uses when wizard steps are conditional. unset( $this->steps[ $quiz_id ] ); $steps = $this->get_steps( $quiz_id, 'quiz' ); } } } $quiz_settings_wizard = $this->get_wizard( $steps, $submitted_data, $quiz_id, $step ); $addon_slug = $this->get_slug(); $addon = $this; $quiz_settings_instance = $this->get_addon_settings( $quiz_id, 'quiz' ); /** * Filter quiz settings wizard returned to client * * @since 1.6.2 * * @param array $quiz_settings_wizard * @param array $submitted_data $_POST from client. * @param int $quiz_id quiz ID requested for. * @param int $current_step Current Step displayed to user, start from 0. * @param int $step Step requested by client, start from 0. * @param Forminator_Integration $addon Integration Instance. * @param Forminator_Integration_Quiz_Settings|null $quiz_settings_instance Integration Form settings instance, or null if unavailable. */ $quiz_settings_wizard = apply_filters( 'forminator_addon_' . $addon_slug . '_quiz_settings_wizard', $quiz_settings_wizard, $submitted_data, $quiz_id, $current_step, $step, $addon, $quiz_settings_instance ); return $quiz_settings_wizard; } /** * Get quiz settings wizard steps * * @since 1.6.2 * * @param int $quiz_id Quiz Id. * * @return array */ private function get_quiz_settings_steps( $quiz_id ) { $addon_slug = $this->get_slug(); $addon = $this; $quiz_settings_steps = array(); $quiz_settings_instance = $this->get_addon_settings( $quiz_id, 'quiz' ); if ( ! is_null( $quiz_settings_instance ) && $quiz_settings_instance instanceof Forminator_Integration_Quiz_Settings ) { $quiz_settings_steps = $quiz_settings_instance->module_settings_wizards(); } /** * Filter form settings step that will be used for building wizard * * More detail : @param array $quiz_settings_steps * * @param int $quiz_id current quiz id. * @param Forminator_Integration $addon Integration instance. * @param Forminator_Integration_Quiz_Settings|null $quiz_settings_instance Quiz settings of addon if available, or null otherwise. *@see Forminator_Integration_Quiz_Settings::module_settings_wizards() * * @since 1.6.2 */ $quiz_settings_steps = apply_filters( 'forminator_addon_' . $addon_slug . '_quiz_settings_steps', $quiz_settings_steps, $quiz_id, $addon, $quiz_settings_instance ); return $quiz_settings_steps; } /** * Get quiz settings multi id * * @since 1.6.2 * * @param int $quiz_id Quiz Id. * * @return array */ private function get_quiz_settings_multi_ids( $quiz_id ) { $addon_slug = $this->get_slug(); $addon = $this; $multi_ids = array(); $quiz_settings_instance = $this->get_addon_settings( $quiz_id, 'quiz' ); if ( $this->is_allow_multi_on_quiz() && ! is_null( $quiz_settings_instance ) && $quiz_settings_instance instanceof Forminator_Integration_Quiz_Settings ) { $multi_ids = $quiz_settings_instance->get_multi_ids(); } /** * Filter multi id of addon quiz settings * * @since 1.6.2 * * @param array $multi_ids * @param Forminator_Integration $addon Integration Instance. * @param Forminator_Integration_Quiz_Settings $quiz_settings_instance Integration Quiz Settings Instance. */ $multi_ids = apply_filters( 'forminator_addon_' . $addon_slug . '_quiz_settings_multi_ids', $multi_ids, $addon, $quiz_settings_instance ); return $multi_ids; } /** * Override this function if you wanna make an addon allow multiple instance on 1 quiz * * @since 1.6.2 * @return bool */ public function is_allow_multi_on_quiz() { return false; } /** * Transform addon instance into array with form relation * * @since 1.6.2 * * @param int $quiz_id Quiz Id. * * @return array */ final public function to_array_with_quiz( $quiz_id ) { $to_array = $this->to_array(); $is_allow_multi_on_quiz = $this->is_allow_multi_on_quiz(); $to_array['is_quiz_connected'] = $this->is_module_connected( $quiz_id, 'quiz' ); $to_array['is_quiz_settings_available'] = $this->is_quiz_settings_available( $quiz_id ); $to_array['is_allow_multi_on_quiz'] = $is_allow_multi_on_quiz; $to_array['multi_id'] = $this->generate_quiz_settings_multi_id( $quiz_id ); // handle multiple form setting. if ( $is_allow_multi_on_quiz ) { $to_array['multi_ids'] = $this->get_quiz_settings_multi_ids( $quiz_id ); } $to_array_with_quiz = $to_array; $addon_slug = $this->get_slug(); $addon = $this; /** * Filter array of addon properties * * Including relation with form_id * * @since 1.6.2 * * @param array $to_array_with_quiz array of addon properties. * @param int $quiz_id Quiz ID. * @param Forminator_Integration $addon Integration instance. */ $to_array_with_quiz = apply_filters( 'forminator_addon_' . $addon_slug . '_to_array_with_quiz', $to_array_with_quiz, $quiz_id, $addon ); return $to_array_with_quiz; } /** * Override this function if you need to apply some conditional logic on it * By Default this function will check * * @param int $quiz_id Quiz Id. * * @return bool * @since 1.6.2 * * @see Forminator_Integration::settings_wizards() * @see Forminator_Integration_Quiz_Settings::module_settings_wizards() * as valid multi array */ public function is_quiz_settings_available( $quiz_id ) { $steps = array(); $quiz_steps = $this->get_quiz_settings_steps( $quiz_id ); $steps = array_merge( $steps, $quiz_steps ); if ( ! is_array( $steps ) ) { return false; } if ( count( $steps ) < 1 ) { return false; } return true; } /** * Generate multi_id * * @since 1.6.2 * * @param int $quiz_id Quiz Id. * * @return array */ private function generate_quiz_settings_multi_id( $quiz_id ) { $addon_slug = $this->get_slug(); $addon = $this; $multi_id = 0; $quiz_settings_instance = $this->get_addon_settings( $quiz_id, 'quiz' ); if ( $this->is_allow_multi_on_quiz() && ! is_null( $quiz_settings_instance ) && $quiz_settings_instance instanceof Forminator_Integration_Quiz_Settings ) { $multi_id = $quiz_settings_instance->generate_multi_id(); } /** * Filter new generated multi id of addon form setting * * @since 1.6.2 * * @param string $multi_id * @param Forminator_Integration $addon Integration Instance. * @param Forminator_Integration_Quiz_Settings $quiz_settings_instance Integration Quiz Settings Instance. */ $multi_ids = apply_filters( 'forminator_addon_' . $addon_slug . '_quiz_settings_multi_id', $multi_id, $addon, $quiz_settings_instance ); return $multi_ids; } /** * Connection failed * * @return string */ final public function connection_failed() { /* translators: integration title */ return sprintf( esc_html__( 'We couldn\'t connect to your %s account. Please resolve the errors below and try again.', 'forminator' ), $this->get_title() ); } /** * Get success authorize content * * @return string */ protected function success_authorize() { ob_start(); ?> <div class="forminator-integration-popup__header"> <h3 id="forminator-integration-popup__title" class="sui-box-title sui-lg" style="overflow: initial; white-space: normal; text-overflow: initial;"> <?php /* translators: 1: Add-on name */ printf( esc_html__( '%1$s Connected', 'forminator' ), esc_html( $this->get_title() ) ); ?> </h3> </div> <p id="forminator-integration-popup__description" class="sui-description" style="text-align: center;"> <?php printf( /* translators: 1: Title */ esc_html__( 'Awesome! You are connected to %1$s. You can now go to your forms and activate %1$s integration to collect data.', 'forminator' ), esc_html( $this->get_title() ) ); ?> </p> <div class="forminator-integration-popup__footer-temp"> <button class="sui-button forminator-addon-close forminator-integration-popup__close"> <?php esc_html_e( 'Close', 'forminator' ); ?> </button> </div> <?php return ob_get_clean(); } } class-integration-exception.php 0000644 00000000665 15162271762 0012717 0 ustar 00 <?php /** * The Forminator_Integration_Exception class. * * @package Forminator */ /** * Class Forminator_Integration_Exception * Exception used for Integration * * @since 1.1 */ class Forminator_Integration_Exception extends Exception { /** * Get error notice HTML * * @return string */ public function get_error_notice(): string { return Forminator_Admin::get_red_notice( esc_html( $this->getMessage() ) ); } } class-integration-poll-settings.php 0000644 00000023161 15162271763 0013522 0 ustar 00 <?php /** * The Forminator_Integration_Poll_Settings class. * * @package Forminator */ /** * Class Forminator_Integration_Poll_Settings * Any change(s) to this file is subject to: * - Properly Written DocBlock! (what is this, why is that, how to be like those, etc, as long as you want!) * - Properly Written Changelog! * * @since 1.6.1 */ abstract class Forminator_Integration_Poll_Settings extends Forminator_Integration_Settings { /** * Current Poll fields (answers) * * @since 1.6.1 * @var array */ protected $poll_fields = array(); /** * Current Poll Settings * * @since 1.6.1 * @var array */ protected $poll_settings = array(); /** * An addon can be force disconnected from poll, if its not met requirement, or data changed externally * example : * - Mail List deleted on mailchimp server app * - Fields removed * * @since 1.6.1 * @var bool */ protected $is_force_poll_disconnected = false; /** * Reason of Force disconnected * * @since 1.6.1 * @var string */ protected $force_poll_disconnected_reason = ''; /** * Poll Model * * @since 1.6.1 * @var Forminator_Poll_Model|null */ protected $poll = null; /** * Module slug * * @var string */ protected static $module_slug = 'poll'; /** * Forminator_Integration_Poll_Settings constructor. * * @since 1.6.1 * * @param Forminator_Integration $addon Class Forminator_Integration. * @param int $poll_id Poll Id. * * @throws Forminator_Integration_Exception When there is an Integration error. */ public function __construct( Forminator_Integration $addon, $poll_id ) { $this->addon = $addon; $this->module_id = $poll_id; $this->poll = Forminator_Base_Form_Model::get_model( $this->module_id ); if ( ! $this->poll ) { /* translators: %d: Poll ID */ throw new Forminator_Integration_Exception( sprintf( esc_html__( 'Poll with id %d could not be found', 'forminator' ), esc_html( $this->module_id ) ) ); } $this->poll_fields = forminator_addon_format_poll_fields( $this->poll ); $this->poll_settings = forminator_addon_format_poll_settings( $this->poll ); } /** * Override this function if addon need to do something with addon poll setting values * * @example transform, load from other storage ? * called when rendering tab on poll settings * * @since 1.6.1 * * @param array $values Settings. * * @return mixed */ public function before_get_poll_settings_values( $values ) { return $values; } /** * Override this function if addon need to do something with addon poll setting values * * @example transform, load from other storage ? * called when rendering tab on poll settings * @since 1.6.1 * * @param array $values Settings. * * @return mixed */ public function before_save_poll_settings_values( $values ) { return $values; } /** * Get status of force disconnected from WP post_meta * * @since 1.6.1 * @return bool */ final public function is_force_poll_disconnected() { $disconnected = get_post_meta( $this->module_id, 'forminator_addon_' . $this->addon->get_slug() . '_poll_disconnect', true ); if ( ! empty( $disconnected ) && isset( $disconnected['disconnect'] ) && $disconnected['disconnect'] ) { $this->is_force_poll_disconnected = true; $this->force_poll_disconnected_reason = $disconnected['disconnect_reason']; } return $this->is_force_poll_disconnected; } /** * Get disconnected reason * * @since 1.6.1 * @return string */ final public function force_poll_disconnected_reason() { return $this->force_poll_disconnected_reason; } /** * Force poll to be disconnected with addon * * @since 1.6.1 * * @param string $reason Reason for disconnect. */ final public function force_poll_disconnect( $reason ) { $this->is_force_poll_disconnected = true; $this->force_poll_disconnected_reason = $reason; $this->addon_settings = array(); $this->save_module_settings_values(); } /** * Save disconnect reason to WP post_meta * * @since 1.6.1 */ final public function save_force_poll_disconnect_reason() { if ( $this->is_force_poll_disconnected ) { update_post_meta( $this->module_id, 'forminator_addon_' . $this->addon->get_slug() . '_poll_disconnect', array( 'disconnect' => true, 'disconnect_reason' => $this->force_poll_disconnected_reason, ) ); } } /** * Remove disconnect reason poll WP post_meta * * @since 1.6.1 */ final public function remove_saved_force_poll_disconnect_reason() { delete_post_meta( $this->module_id, 'forminator_addon_' . $this->addon->get_slug() . '_poll_disconnect' ); } /** * Get current poll settings * * @since 1.6.1 * @return array */ final public function get_poll_settings() { return $this->poll_settings; } /** * Get current poll fields * * @since 1.6.1 * @return array */ final public function get_poll_fields() { return $this->poll_fields; } /** * Override this function to set wizardable settings * Default its and empty array which is indicating that Integration doesnt have settings * * Its multi array, with numerical key, start with `0` * Every step on wizard, will consist at least * - `callback` : when application requesting wizard, Forminator will do `call_user_func` on this value, with these arguments * - `$submitted_data` : array of submitted data POST-ed by user * - `$poll_id` : current poll_id when called on `Poll Settings` or 0 when called on Global Settings * - `is_completed` : when application requesting wizard, will check if `Previous Step` `is_completed` by doing `call_user_func` on its value * this function should return `true` or `false` * * @since 1.6.1 * @return array */ public function module_settings_wizards() { // What this function return should looks like. $steps = array( // First Step / step `0`. array( /** * Value of `callback` will be passed as first argument of `call_user_func` * it does not have to be passed `$this` as reference such as `array( $this, 'sample_setting_first_step' )`, * But its encouraged to passed `$this` because you will be benefited with $this class instance, in case you need to call private function or variable inside it * you can make the value to be `some_function_name` as long `some_function_name` as long it will globally callable which will be checked with `is_callable` * and should be able to accept 2 arguments $submitted_data, $poll_id * * This callback should return an array @see Forminator_Integration::sample_setting_first_step() * * @see Forminator_Integration::sample_setting_first_step() */ 'callback' => array( $this, 'sample_setting_first_step' ), /** * Before Forminator call the `callback`, Forminator will attempt to run `is_completed` from the previous step * In this case, `is_completed` will be called when Forminator trying to display Settings Wizard for Second Step / step `1` * Like `callback` its value will be passed as first argument of `call_user_func` * and no arguments passed to this function when its called * * @see Forminator_Integration::sample_setting_first_step_is_completed() */ 'is_completed' => array( $this, 'sample_setting_first_step_is_completed' ), ), ); return array(); } /** * Get poll settings data to export * * Default is from post_meta, override when needed * * @since 1.6.1 * * @return array */ public function to_exportable_data() { $addon_slug = $this->addon->get_slug(); $poll_settings = $this->get_settings_values(); if ( empty( $poll_settings ) ) { $exportable_data = array(); } else { $exportable_data = array( 'poll_settings' => $poll_settings, 'version' => $this->addon->get_version(), ); } $poll_id = $this->module_id; /** * Filter poll settings that will be exported when requested * * @since 1.6.1 * * @param array $exportable_data * @param int $poll_id */ $exportable_data = apply_filters( "forminator_addon_{$addon_slug}_poll_settings_to_exportable_data", $exportable_data, $poll_id ); return $exportable_data; } /** * Executed when poll settings imported * * Default is save imported data to post_meta, override when needed * * @since 1.6.1 * * @param mixed $import_data Import data. * @throws Forminator_Integration_Exception When there is an Integration error. */ public function import_data( $import_data ) { $addon_slug = $this->addon->get_slug(); $poll_id = $this->module_id; $import_data = apply_filters( "forminator_addon_{$addon_slug}_poll_settings_import_data", $import_data, $poll_id ); /** * Executed when importing poll settings of this addon * * @since 1.6.1 * * @param array $exportable_data * @param int $poll_id */ do_action( "forminator_addon_{$addon_slug}_on_import_poll_settings_data", $poll_id, $import_data ); try { // pre-basic-validation. if ( empty( $import_data ) ) { throw new Forminator_Integration_Exception( 'import_data_empty' ); } if ( ! isset( $import_data['poll_settings'] ) ) { throw new Forminator_Integration_Exception( 'import_data_no_poll_settings' ); } if ( empty( $import_data['poll_settings'] ) ) { throw new Forminator_Integration_Exception( 'import_data_poll_settings_empty' ); } if ( ! isset( $import_data['version'] ) ) { throw new Forminator_Integration_Exception( 'import_data_no_version' ); } $this->save_module_settings_values( $import_data['poll_settings'] ); } catch ( Forminator_Integration_Exception $e ) { forminator_addon_maybe_log( $e->getMessage() ); // do nothing. } } } class-integration-form-settings.php 0000644 00000023676 15162271764 0013533 0 ustar 00 <?php /** * The Forminator_Integration_Form_Settings class. * * @package Forminator */ /** * Class Forminator_Integration_Form_Settings * Any change(s) to this file is subject to: * - Properly Written DocBlock! (what is this, why is that, how to be like those, etc, as long as you want!) * - Properly Written Changelog! * * @since 1.1 */ abstract class Forminator_Integration_Form_Settings extends Forminator_Integration_Settings { /** * Current Form Settings * * @since 1.1 * @var array */ protected $form_settings = array(); /** * Current Form Fields * * @var array */ protected $form_fields = array(); /** * An addon can be force disconnected from form, if its not met requirement, or data changed externally * example : * - Mail List deleted on mailchimp server app * - Fields removed * * @since 1.1 * @var bool */ protected $is_force_form_disconnected = false; /** * Reason of Force disonnected * * @since 1.1 * @var string */ protected $force_form_disconnected_reason = ''; /** * Module slug * * @var string */ protected static $module_slug = 'form'; /** * Forminator_Integration_Form_Settings constructor. * * @since 1.1 * * @param Forminator_Integration $addon Class Forminator_Integration. * @param int $form_id Form Id. * * @throws Forminator_Integration_Exception When there is an addon error. */ public function __construct( Forminator_Integration $addon, $form_id ) { $this->addon = $addon; $this->module_id = $form_id; $custom_form = Forminator_Base_Form_Model::get_model( $this->module_id ); if ( ! $custom_form ) { /* translators: Form ID */ throw new Forminator_Integration_Exception( sprintf( esc_html__( 'Form with id %d could not be found', 'forminator' ), esc_html( $this->module_id ) ) ); } $this->form_fields = forminator_addon_format_form_fields( $custom_form ); $this->form_settings = forminator_addon_format_form_settings( $custom_form ); } /** * Override this function if addon need to do something with addon form setting values * * @example transform, load from other storage ? * called when rendering tab on form settings * * @since 1.1 * * @param array $values Settings. * * @return mixed */ public function before_get_form_settings_values( $values ) { return $values; } /** * Override this function if addon need to do something with addon form setting values * * @example transform, load from other storage ? * called when rendering tab on form settings * @since 1.1 * * @param array $values Settings. * * @return mixed */ public function before_save_form_settings_values( $values ) { return $values; } /** * Get status of force disconnected from WP post_meta * * @since 1.1 * @return bool */ final public function is_force_form_disconnected() { $disconnected = get_post_meta( $this->module_id, 'forminator_addon_' . $this->addon->get_slug() . '_form_disconnect', true ); if ( ! empty( $disconnected ) && isset( $disconnected['disconnect'] ) && $disconnected['disconnect'] ) { $this->is_force_form_disconnected = true; $this->force_form_disconnected_reason = $disconnected['disconnnect_reason']; } return $this->is_force_form_disconnected; } /** * Get disconnected reason * * @since 1.1 * @return string */ final public function force_form_disconnected_reason() { return $this->force_form_disconnected_reason; } /** * Force form to be disconnected with addon * * @since 1.1 * * @param string $reason Reason for disconnect. */ final public function force_form_disconnect( $reason ) { $this->is_force_form_disconnected = true; $this->force_form_disconnected_reason = $reason; $this->addon_settings = array(); $this->save_module_settings_values(); } /** * Save disconnect reason to WP post_meta * * @since 1.1 */ final public function save_force_form_disconnect_reason() { if ( $this->is_force_form_disconnected ) { update_post_meta( $this->module_id, 'forminator_addon_' . $this->addon->get_slug() . '_form_disconnect', array( 'disconnect' => true, 'disconnnect_reason' => $this->force_form_disconnected_reason, ) ); } } /** * Remove disconnect reason form WP post_meta * * @since 1.1 */ final public function remove_saved_force_form_disconnect_reason() { delete_post_meta( $this->module_id, 'forminator_addon_' . $this->addon->get_slug() . '_form_disconnect' ); } /** * Get current form settings * * @since 1.1 * @return array */ final public function get_form_settings() { return $this->form_settings; } /** * Get current form fields * * @since 1.1 * @return array */ final public function get_form_fields() { return $this->form_fields; } /** * Override this function to set wizardable settings * Default its and empty array which is indicating that Integration doesnt have settings * * Its multi array, with numerical key, start with `0` * Every step on wizard, will consist at least * - `callback` : when application requesting wizard, Forminator will do `call_user_func` on this value, with these arguments * - `$submitted_data` : array of submitted data POST-ed by user * - `$form_id` : current form_id when called on `Form Settings` or 0 when called on Global Settings * - `is_completed` : when application requesting wizard, will check if `Previous Step` `is_completed` by doing `call_user_func` on its value * this function should return `true` or `false` * * @since 1.1 * @return array */ public function module_settings_wizards() { // What this function return should looks like. $steps = array( // First Step / step `0`. array( /** * Value of `callback` will be passed as first argument of `call_user_func` * it does not have to be passed `$this` as reference such as `array( $this, 'sample_setting_first_step' )`, * But its encouraged to passed `$this` because you will be benefited with $this class instance, in case you need to call private function or variable inside it * you can make the value to be `some_function_name` as long `some_function_name` as long it will globally callable which will be checked with `is_callable` * and should be able to accept 2 arguments $submitted_data, $form_id * * This callback should return an array @see Forminator_Integration::sample_setting_first_step() * * @see Forminator_Integration::sample_setting_first_step() */ 'callback' => array( $this, 'sample_setting_first_step' ), /** * Before Forminator call the `calback`, Forminator will attempt to run `is_completed` from the previous step * In this case, `is_completed` will be called when Forminator trying to display Settings Wizard for Second Step / step `1` * Like `callback` its value will be passed as first argument of `call_user_func` * and no arguments passed to this function when its called * * @see Forminator_Integration::sample_setting_first_step_is_completed() */ 'is_completed' => array( $this, 'sample_setting_first_step_is_completed' ), ), ); return array(); } /** * Get form settings data to export * * Default is from post_meta, override when needed * * @since 1.4 * * @return array */ public function to_exportable_data() { $addon_slug = $this->addon->get_slug(); $form_settings = $this->get_settings_values(); if ( empty( $form_settings ) ) { $exportable_data = array(); } else { $exportable_data = array( 'form_settings' => $form_settings, 'version' => $this->addon->get_version(), ); } $form_id = $this->module_id; /** * Filter Form settings that will be exported when requested * * @since 1.4 * * @param array $exportable_data * @param int $form_id */ $exportable_data = apply_filters( "forminator_addon_{$addon_slug}_form_settings_to_exportable_data", $exportable_data, $form_id ); return $exportable_data; } /** * Executed when form settings imported * * Default is save imported data to post_meta, override when needed * * @since 1.4 * * @param mixed $import_data Import data. * @throws Forminator_Integration_Exception When there is an integration error. */ public function import_data( $import_data ) { $addon_slug = $this->addon->get_slug(); $form_id = $this->module_id; $import_data = apply_filters( "forminator_addon_{$addon_slug}_form_settings_import_data", $import_data, $form_id ); /** * Executed when importing form settings of this addon * * @since 1.4 * * @param array $exportable_data * @param int $form_id * @param Forminator_Integration_Form_Settings|null $form_settings_instance */ do_action( "forminator_addon_{$addon_slug}_on_import_form_settings_data", $form_id, $import_data ); try { // pre-basic-validation. if ( empty( $import_data ) ) { throw new Forminator_Integration_Exception( 'import_data_empty' ); } if ( ! isset( $import_data['form_settings'] ) ) { throw new Forminator_Integration_Exception( 'import_data_no_form_settings' ); } if ( empty( $import_data['form_settings'] ) ) { throw new Forminator_Integration_Exception( 'import_data_form_settings_empty' ); } if ( ! isset( $import_data['version'] ) ) { throw new Forminator_Integration_Exception( 'import_data_no_version' ); } $this->save_module_settings_values( $import_data['form_settings'] ); } catch ( Forminator_Integration_Exception $e ) { forminator_addon_maybe_log( $e->getMessage() ); // do nothing. } } /** * Mailchimp Address type fields array * * @since 1.0 Mailchimp Integration * @return array */ public function mail_address_fields() { $address = array( 'addr1' => 'Address 1', 'addr2' => 'Address 2', 'city' => 'City', 'state' => 'State', 'zip' => 'Zip', 'country' => 'Country', ); return $address; } } class-integration-settings.php 0000644 00000060237 15162271765 0012565 0 ustar 00 <?php /** * The Forminator_Integration_Settings class. * * @package Forminator */ /** * Class Forminator_Integration_Settings * Any change(s) to this file is subject to: * - Properly Written DocBlock! (what is this, why is that, how to be like those, etc, as long as you want!) * - Properly Written Changelog! * * @since 1.1 */ abstract class Forminator_Integration_Settings { /** * Current Module ID * * @since 1.1 * @var int */ protected $module_id; /** * Integration instance * * @since 1.1 * @var Forminator_Integration */ protected $addon; /** * Module settings for addon * * @since 1.1 * @var array */ protected $addon_settings = array(); /** * Get HTML select-options * * @param object $options Options. * @param string $selected_value Saved value. * @return string */ public static function get_select_html( $options, $selected_value = '' ) { $html = '<option value="">' . esc_html__( 'None', 'forminator' ) . '</option>'; foreach ( $options as $id => $title ) { $html .= '<option value="' . esc_attr( $id ) . '" ' . selected( $selected_value, $id, false ) . '>' . esc_html( $title ) . '</option>'; } return $html; } /** * Get HTML checkbox-options * * @param object $options Options. * @param string $name Name attribute. * @param array $selected_values Saved values. * @return string */ public static function get_checkboxes_html( $options, $name, $selected_values = array() ) { $html = ''; foreach ( $options as $id => $title ) { $html .= '<label for="' . esc_attr( $id ) . '" class="sui-checkbox sui-checkbox-sm sui-checkbox-stacked">' . '<input id="' . esc_attr( $id ) . '" name="' . esc_attr( $name ) . '" type="checkbox" value="' . esc_attr( $id ) . '"' . checked( is_array( $selected_values ) && in_array( $id, $selected_values, true ), true, false ) . '><span aria-hidden="true"></span><span>' . esc_html( $title ) . '</span></label>'; } return $html; } /** * Get HTML radio-options * * @param object $options Options. * @param string $name Name attribute. * @param array $selected_value Saved values. * @return string */ public static function get_radios_html( $options, $name, $selected_value = '' ) { $html = ''; foreach ( $options as $id => $title ) { $html .= '<label for="' . esc_attr( $id ) . '" class="sui-radio sui-radio-sm sui-radio-stacked">' . '<input id="' . esc_attr( $id ) . '" name="' . esc_attr( $name ) . '" type="radio" value="' . esc_attr( $id ) . '"' . checked( $id === $selected_value, true, false ) . '><span aria-hidden="true"></span><span>' . esc_html( $title ) . '</span></label>'; } return $html; } /** * Get HTML for refresh button * * @return string */ public static function refresh_button() { $html = '<button class="sui-button-icon sui-tooltip forminator-refresh-email-lists" data-tooltip="' . esc_html__( 'Refresh list', 'forminator' ) . '" type="button">' . '<span class="sui-loading-text" aria-hidden="true">' . '<i class="sui-icon-refresh"></i>' . '</span>' . '<i class="sui-icon-loader sui-loading" aria-hidden="true"></i>' . '<span class="sui-screen-reader-text">' . esc_html__( 'Refresh', 'forminator' ) . '</span>' . '</button>'; return $html; } /** * Meta key that will be used to save addon setting on WP post_meta * * @return string */ final public function get_settings_meta_key() { $addon = $this->addon; $global_id = ! empty( $addon->multi_global_id ) ? '_' . $addon->multi_global_id : ''; return 'forminator_addon_' . $addon->get_slug() . '_' . static::$module_slug . '_settings' . $global_id; } /** * Replace '-' to '_' in keys because some integrations don't support dashes like tray.io and workato. * * @param array $array_value Original array. * @param string $endpoint Endpoint URL. */ public static function replace_dashes_in_keys( $array_value, $endpoint ) { // don't do it for zapier for backward compatibility. if ( strpos( $endpoint, 'zapier' ) ) { return $array_value; } foreach ( $array_value as $key => $value ) { if ( is_array( $value ) ) { // Replace it recursively. $value = self::replace_dashes_in_keys( $value, $endpoint ); } unset( $array_value[ $key ] ); $new_key = str_replace( '-', '_', $key ); $array_value[ $new_key ] = $value; } return $array_value; } /** * Get HTML for GDPR fields * * @param array $current_data Saved data. * @return string */ protected static function gdpr_fields_html( $current_data ) { return '<div class="sui-form-field">' . '<label class="sui-label">' . esc_html__( 'Enable GDPR', 'forminator' ) . '</label> <input type="checkbox" name="enable_gdpr" value="1" ' . checked( 1, $current_data['enable_gdpr'], false ) . '> </div> <div class="sui-form-field"> <label class="sui-label">' . esc_html__( 'GDPR Text', 'forminator' ) . '</label> <textarea name="gdpr_text">' . wp_kses_post( $current_data['gdpr_text'] ) . '</textarea> </div>'; } /** * Step mapping fields on wizard * * @param array $submitted_data Submitted data. * @return array */ public function get_map_fields( $submitted_data ) { $is_close = false; $is_submit = ! empty( $submitted_data ); $error_message = ''; $html_input_map_fields = ''; $input_error_messages = array(); try { $fields_map = array(); $fields_list = $this->get_addon_custom_fields(); $fields_list_ids = wp_list_pluck( $fields_list, 'id' ); foreach ( $fields_list_ids as $key ) { $fields_map[ $key ] = $submitted_data['fields_map'][ $key ] ?? $this->addon_settings['fields_map'][ $key ] ?? ''; } /** Build table map fields input */ $html_input_map_fields = $this->get_input_map_fields( $fields_list, $fields_map ); if ( $is_submit ) { $this->step_map_fields_validate( $fields_list, $submitted_data ); $this->save_module_settings_values(); $is_close = true; } } catch ( Forminator_Integration_Settings_Exception $e ) { $input_error_messages = $e->get_input_exceptions(); if ( ! empty( $html_input_map_fields ) ) { foreach ( $input_error_messages as $input_id => $message ) { if ( is_array( $message ) ) { foreach ( $message as $addr => $m ) { $html_input_map_fields = str_replace( '{{$error_css_class_' . $input_id . '_' . $addr . '}}', 'sui-form-field-error', $html_input_map_fields ); $html_input_map_fields = str_replace( '{{$error_message_' . $input_id . '_' . $addr . '}}', '<span class="sui-error-message">' . esc_html( $m ) . '</span>', $html_input_map_fields ); } } else { $html_input_map_fields = str_replace( '{{$error_css_class_' . $input_id . '}}', 'sui-form-field-error', $html_input_map_fields ); $html_input_map_fields = str_replace( '{{$error_message_' . $input_id . '}}', '<span class="sui-error-message">' . esc_html( $message ) . '</span>', $html_input_map_fields ); } } } } catch ( Forminator_Integration_Exception $e ) { $error_message = $e->get_error_notice(); } // cleanup map fields input markup placeholder. if ( ! empty( $html_input_map_fields ) ) { $replaced_html_input_map_fields = $html_input_map_fields; $replaced_html_input_map_fields = preg_replace( '/\{\{\$error_css_class_(.+)\}\}/', '', $replaced_html_input_map_fields ); $replaced_html_input_map_fields = preg_replace( '/\{\{\$error_message_(.+)\}\}/', '', $replaced_html_input_map_fields ); if ( ! is_null( $replaced_html_input_map_fields ) ) { $html_input_map_fields = $replaced_html_input_map_fields; } } $buttons = array( 'cancel' => array( 'markup' => Forminator_Integration::get_button_markup( esc_html__( 'Back', 'forminator' ), 'sui-button-ghost forminator-addon-back' ), ), 'next' => array( 'markup' => '<div class="sui-actions-right">' . Forminator_Integration::get_button_markup( esc_html__( 'Save', 'forminator' ), 'sui-button-primary forminator-addon-finish' ) . '</div>', ), ); $notification = array(); if ( $is_submit && empty( $error_message ) && empty( $input_error_messages ) ) { $notification = array( 'type' => 'success', 'text' => '<strong>' . $this->addon->get_title() . '</strong> ' . esc_html__( 'is activated successfully.', 'forminator' ), ); } $html = '<div class="forminator-integration-popup__header">'; $html .= '<h3 id="dialogTitle2" class="sui-box-title sui-lg" style="overflow: initial; text-overflow: none; white-space: normal;">' . esc_html__( 'Map Fields', 'forminator' ) . '</h3>'; $html .= '<p class="sui-description">' . esc_html__( 'Lastly, match up your module fields with the campaign fields to ensure that the data is sent to the right place.', 'forminator' ) . '</p>'; $html .= $error_message; $html .= '</div>'; $html .= '<form enctype="multipart/form-data">'; $html .= $html_input_map_fields; $html .= '</form>'; return array( 'html' => $html, 'redirect' => false, 'is_close' => $is_close, 'buttons' => $buttons, 'has_errors' => ! empty( $error_message ) || ! empty( $input_error_messages ), 'notification' => $notification, 'size' => 'normal', 'has_back' => true, ); } /** * Validate submitted data by user as expected by merge field on addon mail list * * @param array $addon_fields_list List of Mailjet fields. * @param array $post_data POST data. * * @return array current addon form settings * @throws Forminator_Integration_Exception When there is an integration error. */ public function step_map_fields_validate( $addon_fields_list, $post_data ) { $form_fields = $this->get_fields_for_type(); $forminator_field_element_ids = wp_list_pluck( $form_fields, 'element_id' ); $tag_mapped_addon_fields = array(); $addon_required_fields = array(); foreach ( $addon_fields_list as $item ) { $tag_mapped_addon_fields[ $item->id ] = $item; if ( ! empty( $item->required ) ) { $addon_required_fields[] = $item; } } if ( ! isset( $post_data['fields_map'] ) ) { throw new Forminator_Integration_Exception( esc_html__( 'Please assign fields.', 'forminator' ) ); } $post_data = $post_data['fields_map']; if ( ! isset( $this->addon_settings['fields_map'] ) ) { $this->addon_settings['fields_map'] = array(); } // set fields_map from post_data for reuse. foreach ( $post_data as $field_tag => $forminator_field_id ) { $this->addon_settings['fields_map'][ $field_tag ] = $post_data[ $field_tag ]; } $input_exceptions = new Forminator_Integration_Settings_Exception(); // check required fields fulfilled. foreach ( $addon_required_fields as $required_addon_field ) { if ( empty( $post_data[ $required_addon_field->id ] ) ) { $input_exceptions->add_input_exception( /* translators: %s: Required field name */ sprintf( esc_html__( '%s is required, please choose valid Forminator field.', 'forminator' ), esc_html( $required_addon_field->name ) ), $required_addon_field->id ); } } // Check availability on forminator field. foreach ( $this->addon_settings['fields_map'] as $field_tag => $forminator_field_id ) { if ( empty( $forminator_field_id ) ) { continue; } $addon_field = $tag_mapped_addon_fields[ $field_tag ]; // If required field is empty or value is not in forminator field list. if ( ! in_array( $forminator_field_id, $forminator_field_element_ids, true ) ) { $input_exceptions->add_input_exception( /* translators: %s: Integration Field name */ sprintf( esc_html__( 'Please choose valid Forminator field for %s.', 'forminator' ), esc_html( $addon_field->name ) ), $field_tag ); } } if ( $input_exceptions->input_exceptions_is_available() ) { throw $input_exceptions; } return $this->addon_settings; } /** * Save module settings * * @param type $addon_settings Integration settings. */ final public function save_module_settings_values( $addon_settings = null ) { if ( is_null( $addon_settings ) ) { $addon_settings = $this->addon_settings; } $addon_slug = $this->addon->get_slug(); $module_id = $this->module_id; /** * Filter form settings data to be save to db * * @since 1.1 * * @param mixed $addon_settings current addon settings values. * @param int $module_id current module id. */ $addon_settings = apply_filters( 'forminator_addon_' . $addon_slug . '_save_' . static::$module_slug . '_settings_values', $addon_settings, $module_id ); update_post_meta( $module_id, $this->get_settings_meta_key(), forminator_sanitize_array_field( $addon_settings ) ); } /** * Get fields for specific field type. * * @param string $type Field type. * @return array */ protected function get_fields_for_type( $type = '' ) { if ( in_array( $type, array( 'email', 'upload' ), true ) ) { // find email type fields. $specific_fields = array(); foreach ( $this->form_fields as $form_field ) { if ( $type === $form_field['type'] ) { $specific_fields[] = $form_field; } } return $specific_fields; } else { return $this->form_fields; } } /** * Get HTML for header on Choose List step. * * @param string $error_message Error message. * @return array */ protected static function get_choose_list_header( $error_message ) { $html = '<div class="forminator-integration-popup__header">'; $html .= '<h3 id="dialogTitle2" class="sui-box-title sui-lg" style="overflow: initial; text-overflow: none; white-space: normal;">' . esc_html__( 'Choose contact list', 'forminator' ) . '</h3>'; $html .= '<p class="sui-description">' . esc_html__( 'Choose the contact list you want to send form data to', 'forminator' ) . '</p>'; $html .= wp_kses_post( $error_message ); $html .= '</div>'; return $html; } /** * Get HTML for Choose list field * * @param array $current_data Saved data. * @param array $lists Lists. * @param string $list_error Error messages. * @return string */ protected static function get_choose_list_field( $current_data, $lists, $list_error ) { $html = '<div class="sui-form-field' . ( $list_error ? ' sui-form-field-error' : '' ) . '" style="margin-bottom: 10px;"> <label class="sui-label">' . esc_html__( 'Contact list', 'forminator' ) . '</label> <div class="forminator-select-refresh"> <select name="mail_list_id" class="sui-select">' . self::get_select_html( $lists, $current_data['mail_list_id'] ) . '</select>' . self::refresh_button() . '</div>'; if ( $list_error ) { $html .= '<span class="sui-error-message">' . esc_html( $list_error ) . '</span>'; } $html .= '</div>'; return $html; } /** * Get HTML for Double Opt-in field * * @param array $current_data Saved data. * @return string */ protected static function get_double_optin_field( $current_data ) { $html = '<div class="sui-form-field">'; $html .= '<label class="sui-toggle">'; $html .= '<input type="checkbox" name="enable_double_opt_in" value="1" id="forminator_addon_enable_double_opt_in" ' . checked( 1, $current_data['enable_double_opt_in'], false ) . ' />'; $html .= '<span class="sui-toggle-slider"></span>'; $html .= '<span class="sui-toggle-label">' . esc_html__( 'Use Double Opt in', 'forminator' ) . '</span>'; $html .= '</label>'; $html .= '</div>'; return $html; } /** * Override this function to generate multiple id on module settings * Default is the uniqid * * @since 1.2 * @return string */ public function generate_multi_id() { return uniqid( $this->addon->get_slug() . '_', true ); } /** * Check if connection to module completed * * @since 1.0 * @param string $multi_id Multi ID. * * @return bool */ public function is_multi_id_completed( string $multi_id ): bool { $data = array( 'multi_id' => $multi_id ); $steps = wp_list_pluck( $this->module_settings_wizards(), 'is_completed' ); foreach ( $steps as $step ) { $is_completed = call_user_func( $step, $data ); if ( ! $is_completed ) { return false; } } return true; } /** * Get Module settings value * its already hooked with * * @see before_get_settings_values * * @since 1.1 * * @return array */ final public function get_settings_values() { // get single meta key. $values = get_post_meta( $this->module_id, $this->get_settings_meta_key(), true ); if ( ! $values ) { $values = array(); } $addon_slug = $this->addon->get_slug(); $module_id = $this->module_id; /** * Filter retrieved module settings data from db * * @since 1.1 * * @param mixed $values * @param int $module_id current module id. */ $values = apply_filters( 'forminator_addon_' . $addon_slug . '_get_' . static::$module_slug . '_settings_values', $values, $module_id ); return $values; } /** * Force Close Wizard with message * * @since 1.2 * * @return array */ public function get_force_closed_wizard() { return array( 'html' => '', 'buttons' => '', 'is_close' => true, 'redirect' => false, 'has_errors' => false, 'has_back' => false, 'notification' => array( 'type' => 'error', 'text' => '<strong>' . $this->addon->get_title() . '</strong> ' . esc_html__( 'Please pick valid connection', 'forminator' ), ), ); } /** * Disconnect Module with this addon * Override when needed * * @since 1.1 * * @param array $submitted_data Submitted data. */ public function disconnect_module( $submitted_data ) { $addon_settings = array(); // only execute if multi_id provided on submitted data. if ( ! empty( $submitted_data['multi_id'] ) ) { $addon_settings = $this->get_settings_values(); unset( $addon_settings[ $submitted_data['multi_id'] ] ); } $this->save_module_settings_values( $addon_settings ); } /** * Override this function to retrieve your multiple ids on module settings * Default is the array keys as id and label of settings_values * * @return array */ public function get_multi_ids(): array { $multi_ids = array(); $settings_values = $this->get_settings_values(); foreach ( $settings_values as $key => $value ) { $multi_ids[] = array( 'id' => $key, // use name that was added by user on creating connection. 'label' => $value['name'] ?? $key, ); } /** * Filter labels of multi_id on integrations tab * * @param array $multi_ids * @param array $settings_values */ return apply_filters( 'forminator_addon_' . static::$module_slug . '_' . $this->addon->get_slug() . '_multi_id_labels', $multi_ids, $settings_values ); } /** * Get multi Setting value of multi_id * Override when needed * * @since 1.2 * * @param int $multi_id Multi Id. * @param string $key key. * @param mixed $default_value Default value. * * @return mixed|string */ public function get_multi_id_settings( $multi_id, $key, $default_value = '' ) { $this->addon_settings = $this->get_settings_values(); if ( isset( $this->addon_settings[ $multi_id ] ) ) { $multi_settings = $this->addon_settings[ $multi_id ]; if ( isset( $multi_settings[ $key ] ) ) { return $multi_settings[ $key ]; } return $default_value; } return $default_value; } /** * Properties exist * * @param mixed $submitted_data Submitted data. * @param mixed $properties Properties. * @return bool */ protected function if_properties_exist( $submitted_data, $properties ) { $multi_id = $submitted_data['multi_id'] ?? ''; if ( empty( $multi_id ) ) { return false; } $properties = (array) $properties; foreach ( $properties as $property_name ) { $property = $this->get_multi_id_settings( $multi_id, $property_name ); if ( is_string( $property ) ) { $property = trim( $property ); } if ( empty( $property ) ) { return false; } } return true; } /** * Check if pick name step completed * * @since 1.0 * @param array $submitted_data Submitted data. * @return bool */ public function setup_name_is_completed( $submitted_data ) { return $this->if_properties_exist( $submitted_data, 'name' ); } /** * Check if setup list completed * * @since 1.0 * @param array $submitted_data Submitted data. * @return bool */ public function select_list_is_completed( $submitted_data ) { return $this->if_properties_exist( $submitted_data, 'list_id' ); } /** * Append multi settings or replace multi settings * * @since 1.2 * * @param int $multi_id Multi id. * @param array $settings Settings. * @param bool $replace Replace. */ public function save_multi_id_setting_values( $multi_id, $settings, $replace = false ) { $this->addon_settings = $this->get_settings_values(); // merge old values if not replace. if ( isset( $this->addon_settings[ $multi_id ] ) && ! $replace ) { $current_settings = $this->addon_settings[ $multi_id ]; $settings = array_merge( $current_settings, $settings ); } $this->addon_settings = array_merge( $this->addon_settings, array( $multi_id => $settings, ) ); $this->save_module_settings_values(); } /** * Find one active connection on current module * Override when needed * * @since 1.2 * @return bool|array false on no connection, or settings on available */ public function find_one_active_connection() { $addon_settings = $this->get_settings_values(); foreach ( $addon_settings as $multi_id => $addon_setting ) { if ( true === $this->is_multi_id_completed( $multi_id ) ) { return $addon_setting; } } return false; } /** * Has lead * * @return bool */ public function has_lead() { return false; } /** * Get input of Map Fields * its table with html select options as input * * @param array $addon_fields Integration fields. * @param array $fields_map Fields map. * @return string HTML table */ protected function get_input_map_fields( $addon_fields, $fields_map ) { ob_start(); ?> <table class="sui-table"> <thead> <tr> <th><?php esc_html_e( 'Integration Fields', 'forminator' ); ?></th> <th><?php esc_html_e( 'Forminator Field', 'forminator' ); ?></th> </tr> </thead> <tbody> <?php foreach ( $addon_fields as $item ) { $type = $item->type ?? $item->datatype; $all_fields = $this->get_fields_for_type( $type ); ?> <tr> <td><?php echo esc_html( $item->name ); ?> <?php if ( ! empty( $item->required ) ) { ?> <span class="integrations-required-field">*</span> <?php } ?> </td> <td> <div class="sui-form-field {{$error_css_class_<?php echo esc_attr( $item->id ); ?>}}"> <select class="sui-select" name="fields_map[<?php echo esc_attr( $item->id ); ?>]"> <?php if ( empty( $item->required ) || empty( $all_fields ) ) { ?> <option value=""><?php esc_html_e( 'None', 'forminator' ); ?></option> <?php } ?> <?php foreach ( $all_fields as $form_field ) { ?> <option value="<?php echo esc_attr( $form_field['element_id'] ); ?>" <?php selected( $fields_map[ $item->id ], $form_field['element_id'] ); ?>> <?php echo esc_html( wp_strip_all_tags( $form_field['field_label'] ) . ' | ' . $form_field['element_id'] ); ?> </option> <?php } ?> </select> {{$error_message_<?php echo esc_attr( $item->id ); ?>}} </div> </td> </tr> <?php } ?> </tbody> </table> <?php return ob_get_clean(); } /** * Get additional addon fields. * * @return array */ protected function get_additional_addon_fields() { return array( 'email' => (object) array( 'name' => __( 'Email', 'forminator' ), 'id' => 'email', 'type' => 'email', 'required' => true, ), ); } /** * Get custom addon fields. * * @return array */ protected function get_addon_custom_fields() { $additional_fields = $this->get_additional_addon_fields(); $fields_list = $this->addon->get_api()->get_contact_properties(); return $additional_fields + $fields_list; } /** * Get prepared array of Integration lists * * @return array */ protected function get_prepared_lists(): array { try { $lists = $this->addon->get_api()->get_all_lists(); $lists = wp_list_pluck( $lists, 'name', 'id' ); } catch ( Forminator_Integration_Exception $e ) { forminator_addon_maybe_log( __METHOD__, $e->getMessage() ); return array(); } return $lists; } } error_log 0000644 00000005667 15162271767 0006515 0 ustar 00 [29-Mar-2026 13:50:53 UTC] PHP Fatal error: Uncaught Error: Class "Forminator_Integration_Exception" not found in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-forminator-integration-settings-exception.php:14 Stack trace: #0 {main} thrown in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-forminator-integration-settings-exception.php on line 14 [29-Mar-2026 13:52:19 UTC] PHP Fatal error: Uncaught Error: Class "Forminator_Integration_Settings" not found in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-integration-form-settings.php:16 Stack trace: #0 {main} thrown in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-integration-form-settings.php on line 16 [29-Mar-2026 13:59:35 UTC] PHP Fatal error: Uncaught Error: Class "Forminator_Integration_Settings" not found in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-integration-poll-settings.php:16 Stack trace: #0 {main} thrown in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-integration-poll-settings.php on line 16 [29-Mar-2026 14:01:56 UTC] PHP Fatal error: Uncaught Error: Class "Forminator_Integration_Hooks" not found in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-integration-form-hooks.php:21 Stack trace: #0 {main} thrown in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-integration-form-hooks.php on line 21 [29-Mar-2026 14:02:45 UTC] PHP Fatal error: Uncaught Error: Interface "Forminator_Integration_Interface" not found in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-integration.php:18 Stack trace: #0 {main} thrown in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-integration.php on line 18 [29-Mar-2026 14:04:55 UTC] PHP Fatal error: Uncaught Error: Class "Forminator_Integration_Settings" not found in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-integration-quiz-settings.php:16 Stack trace: #0 {main} thrown in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-integration-quiz-settings.php on line 16 [29-Mar-2026 14:26:29 UTC] PHP Fatal error: Uncaught Error: Class "Forminator_Integration_Hooks" not found in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-integration-quiz-hooks.php:21 Stack trace: #0 {main} thrown in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-integration-quiz-hooks.php on line 21 [29-Mar-2026 14:27:19 UTC] PHP Fatal error: Uncaught Error: Class "Forminator_Integration_Hooks" not found in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-integration-poll-hooks.php:21 Stack trace: #0 {main} thrown in /home/everqlsh/public_html/wp-content/plugins/forminator/library/addon/class-integration-poll-hooks.php on line 21 class-forminator-integration-settings-exception.php 0000644 00000003345 15162271767 0016736 0 ustar 00 <?php /** * Class Forminator_Integration_Settings_Exception * Exception used for Addon Settings * * @package Forminator * @author Addons * @version test */ /** * Class Forminator_Integration_Settings_Exception */ class Forminator_Integration_Settings_Exception extends Forminator_Integration_Exception { /** * Holder of input exceptions * * @var array */ protected $input_exceptions = array(); /** * Forminator_Integration_Settings_Exception constructor. * * Useful if input_id is needed for later. * If no input_id needed, use @see Forminator_Integration_Exception * * @param string $message Message. * @param string $input_id Input Id. */ public function __construct( $message = '', $input_id = '' ) { parent::__construct( $message, 0 ); if ( ! empty( $input_id ) ) { $this->add_input_exception( $message, $input_id ); } } /** * Set exception message for an input * * @param string $message Message. * @param string $input_id Input Id. */ public function add_input_exception( $message, $input_id ) { $this->input_exceptions[ $input_id ] = $message; } /** * Set exception message for an address input * * @param string $message Message. * @param string $input_id Input Id. * @param string $sub_input Input. */ public function add_sub_input_exception( $message, $input_id, $sub_input ) { $this->input_exceptions[ $input_id ][ $sub_input ] = $message; } /** * Get all input exceptions * * @return array */ public function get_input_exceptions() { return $this->input_exceptions; } /** * Check if there is input_exceptions_is_available * * @return bool */ public function input_exceptions_is_available() { return count( $this->input_exceptions ) > 0; } } class-integration-quiz-hooks.php 0000644 00000014247 15162271767 0013040 0 ustar 00 <?php /** * The Forminator_Integration_Quiz_Hooks class. * * @package Forminator */ /** * Class Forminator_Integration_Quiz_Hooks * Any change(s) to this file is subject to: * - Properly Written DocBlock! (what is this, why is that, how to be like those, etc, as long as you want!) * - Properly Written Changelog! * * If you override any of these method, please add necessary hooks in it, * Which you can see below, as a reference and keep the arguments signature. * If needed you can call these method, as parent::method_name(), * and add your specific hooks. * * @since 1.6.2 */ abstract class Forminator_Integration_Quiz_Hooks extends Forminator_Integration_Hooks { /** * Module slug * * @var string */ protected static string $slug = 'quiz'; /** * Lead settings instance * * @since 1.6.2 * @var Forminator_Integration_Quiz_Settings|null */ protected $lead_settings_instance; /** * Lead Model * * @since 1.6.2 * @var Forminator_Form_Model */ protected $lead_model; /** * Forminator_Integration_Quiz_Hooks constructor. * * @param Forminator_Integration $addon Integration. * @param int $module_id Module ID. * * @since 1.6.2 * @throws Forminator_Integration_Exception When module ID is invalid. */ public function __construct( Forminator_Integration $addon, int $module_id ) { parent::__construct( $addon, $module_id ); if ( isset( $this->module->settings['hasLeads'] ) && $this->module->settings['hasLeads'] ) { $this->lead_model = Forminator_Base_Form_Model::get_model( $this->module->settings['leadsId'] ); $this->lead_settings_instance = $this->addon->get_addon_settings( $this->module->settings['leadsId'], 'form' ); } } /** * Override this function to execute action after entry saved * * Its void function, so return value will be ignored, and forminator process will always continue * unless it generates unrecoverable error, so please be careful on extending this function * * @since 1.6.2 * * @param Forminator_Form_Entry_Model $entry_model Form entry Model. */ public function after_entry_saved( Forminator_Form_Entry_Model $entry_model ) { $addon_slug = $this->addon->get_slug(); $quiz_id = $this->module_id; $quiz_settings_instance = $this->settings_instance; /** * Fires when entry already saved on db * * Although it can be used for all addon. * Please keep in mind that if the addon override this method, * then this filter probably might be not available. * To be sure please check individual addon documentations. * * @since 1.6.2 * * @param int $quiz_id current Quiz ID. * @param Forminator_Form_Entry_Model $entry_model Forminator Entry Model. * @param Forminator_Integration_Quiz_Settings|null $quiz_settings_instance of Integration Quiz Settings. */ do_action( 'forminator_addon_quiz_' . $addon_slug . '_after_entry_saved', $quiz_id, $entry_model, $quiz_settings_instance ); } /** * Get Submit quiz error message * * @since 1.6.2 * @return string */ public function get_submit_error_message() { $addon_slug = $this->addon->get_slug(); $quiz_id = $this->module_id; $quiz_settings_instance = $this->settings_instance; $error_message = $this->submit_error_message; /** * Filter error message on submit * * Although it can be used for all addon. * Please keep in mind that if the addon override this method, * then this filter probably not be available. * To be sure please check individual addon documentations. * * @since 1.6.2 * * @param array $export_columns column to be exported. * @param int $quiz_id current quiz ID. * @param Forminator_Integration_Quiz_Settings|null $quiz_settings_instance of Integration quiz Settings. */ $error_message = apply_filters( 'forminator_addon_' . $addon_slug . '_submit_quiz_error_message', $error_message, $quiz_id, $quiz_settings_instance ); return $error_message; } /** * Check if element_id is stripe type * * @since 1.7 * * @param string $element_id Element Id. * * @return bool */ public static function element_is_stripe( $element_id ) { $is_stripe = stripos( $element_id, self::STRIPE_ELEMENT_PREFIX ) !== false; /** * Filter stripe flag of element * * @since 1.7 * * @param bool $is_stripe * @param string $element_id * * @return bool */ $is_stripe = apply_filters( 'forminator_addon_element_is_stripe', $is_stripe, $element_id ); return $is_stripe; } /** * Check if element_id is calculation type * * @since 1.7 * * @param string $element_id Element Id. * * @return bool */ public static function element_is_calculation( $element_id ) { $is_calculation = stripos( $element_id, self::CALCULATION_ELEMENT_PREFIX ) !== false; /** * Filter calculation flag of element * * @since 1.7 * * @param bool $is_calculation * @param string $element_id * * @return bool */ $is_calculation = apply_filters( 'forminator_addon_element_is_calculation', $is_calculation, $element_id ); return $is_calculation; } /** * Return submitted data. * * @param array $submitted_data Submitted data. * @param int $module_id Module ID. * @param array $current_entry_fields Current entry fields. * @return array */ protected function prepare_submitted_data( array $submitted_data, int $module_id, array $current_entry_fields ): array { $quiz_submitted_data = get_quiz_submitted_data( $this->module, $submitted_data, $current_entry_fields ); $quiz_settings = $this->settings_instance->get_quiz_settings(); $addons_fields = $this->settings_instance->get_form_fields(); $submitted_data = get_addons_lead_form_entry_data( $quiz_settings, $submitted_data, $addons_fields ); $submitted_data = $this->reformat_submitted_data( $submitted_data, $module_id, $current_entry_fields ); $submitted_data = array_merge( $submitted_data, $quiz_submitted_data ); return $submitted_data; } } class-integration-form-hooks.php 0000644 00000040225 15162271770 0013000 0 ustar 00 <?php /** * The Forminator_Integration_Form_Hooks class. * * @package Forminator */ /** * Class Forminator_Integration * Any change(s) to this file is subject to: * - Properly Written DocBlock! (what is this, why is that, how to be like those, etc, as long as you want!) * - Properly Written Changelog! * * If you override any of these method, please add necessary hooks in it, * Which you can see below, as a reference and keep the arguments signature. * If needed you can call these method, as parent::method_name(), * and add your specific hooks. * * @since 1.1 */ abstract class Forminator_Integration_Form_Hooks extends Forminator_Integration_Hooks { /** * Module slug * * @var string */ protected static string $slug = 'form'; /** * Override this function to execute action before fields rendered * * If function generate output, it will output-ed, * race condition between addon probably happen. * Its void function, so return value will be ignored, and forminator process will always continue, * unless it generates unrecoverable error, so please be careful on extending this function. * If you want to `wp_enqueue_script` this might be the best place. * * @since 1.1 */ public function on_before_render_form_fields() { /** * Fires before form fields rendered by forminator * * Although it can be used for all addon. * Please keep in mind that if the addon override this method, * then this action won't be triggered. * To be sure please check individual addon documentations. * * @since 1.1 * * @param int $form_id current Form ID. * @param Forminator_Integration_Form_Settings|null $form_settings_instance of Integration Form Settings. */ do_action( 'forminator_addon_' . $this->addon->get_slug() . '_on_before_render_form_fields', $this->module_id, $this->settings_instance ); } /** * Override this function to execute action after all form fields rendered * * If function generate output, it will output-ed * race condition between addon probably happen * its void function, so return value will be ignored, and forminator process will always continue * unless it generates unrecoverable error, so please be careful on extending this function * * @since 1.1 */ public function on_after_render_form_fields() { /** * Fires when addon rendering extra output after connected form fields rendered * * Although it can be used for all addon. * Please keep in mind that if the addon override this method, * then this action won't be triggered. * To be sure please check individual addon documentations. * * @since 1.1 * * @param int $form_id current Form ID. * @param Forminator_Integration_Form_Settings|null $form_settings_instance of Integration Form Settings. */ do_action( 'forminator_addon_' . $this->addon->get_slug() . '_on_after_render_form_fields', $this->module_id, $this->settings_instance ); } /** * Override this function to execute action after html markup form rendered completely * * If function generate output, it will output-ed * race condition between addon probably happen * its void function, so return value will be ignored, and forminator process will always continue * unless it generates unrecoverable error, so please be careful on extending this function * * @since 1.1 */ public function on_after_render_form() { /** * Fires when connected form completely rendered * * Although it can be used for all addon. * Please keep in mind that if the addon override this method, * then this action won't be triggered. * To be sure please check individual addon documentations. * * @since 1.1 * * @param int $form_id current Form ID. * @param Forminator_Integration_Form_Settings|null $form_settings_instance of Integration Form Settings. */ do_action( 'forminator_addon_' . $this->addon->get_slug() . '_on_after_render_form', $this->module_id, $this->settings_instance ); } /** * Override this function to execute action after entry saved * * Its void function, so return value will be ignored, and forminator process will always continue * unless it generates unrecoverable error, so please be careful on extending this function * * @since 1.1 * * @param Forminator_Form_Entry_Model $entry_model Form entry model. */ public function after_entry_saved( Forminator_Form_Entry_Model $entry_model ) { $addon_slug = $this->addon->get_slug(); $form_id = $this->module_id; $form_settings_instance = $this->settings_instance; /** * Fires when entry already saved on db * * Although it can be used for all addon. * Please keep in mind that if the addon override this method, * then this filter probably won't be applied. * To be sure please check individual addon documentations. * * @since 1.1 * * @param int $form_id current Form ID. * @param Forminator_Form_Entry_Model $entry_model Forminator Entry Model. * @param Forminator_Integration_Form_Settings|null $form_settings_instance of Integration Form Settings. */ do_action( 'forminator_addon_' . $addon_slug . '_after_entry_saved', $form_id, $entry_model, $form_settings_instance ); } /** * Get Submit form error message * * @since 1.1 * @return string */ public function get_submit_error_message() { $addon_slug = $this->addon->get_slug(); $form_id = $this->module_id; $form_settings_instance = $this->settings_instance; $error_message = $this->submit_error_message; /** * Filter addon columns to be displayed on export submissions * * Although it can be used for all addon. * Please keep in mind that if the addon override this method, * then this filter probably won't be applied. * To be sure please check individual addon documentations. * * @since 1.1 * * @param array $export_columns column to be exported. * @param int $form_id current Form ID. * @param Forminator_Integration_Form_Settings|null $form_settings_instance of Integration Form Settings. */ $error_message = apply_filters( 'forminator_addon_' . $addon_slug . '_submit_form_error_message', $error_message, $form_id, $form_settings_instance ); return $error_message; } /** * Find Meta value from entry fields * * @since 1.7 * * @param string $element_id Element Id. * @param array $form_entry_fields Form entry fields. * * @return array */ public static function find_meta_value_from_entry_fields( $element_id, $form_entry_fields ) { $meta_value = array(); foreach ( $form_entry_fields as $form_entry_field ) { if ( isset( $form_entry_field['name'] ) && $form_entry_field['name'] === $element_id ) { $meta_value = isset( $form_entry_field['value'] ) ? $form_entry_field['value'] : array(); } } /** * Filter meta value of element_id from form entry fields * * @since 1.7 * * @param array $meta_value * @param string $element_id * @param array $form_entry_fields * * @return array */ $meta_value = apply_filters( 'forminator_addon_meta_value_entry_fields', $meta_value, $element_id, $form_entry_fields ); return $meta_value; } /** * Check if element_id is calculation type * * @since 1.7 * * @param string $element_id Element Id. * * @return bool */ public static function element_is_calculation( $element_id ) { $is_calculation = stripos( $element_id, self::CALCULATION_ELEMENT_PREFIX ) !== false; /** * Filter calculation flag of element * * @since 1.7 * * @param bool $is_calculation * @param string $element_id * * @return bool */ $is_calculation = apply_filters( 'forminator_addon_element_is_calculation', $is_calculation, $element_id ); return $is_calculation; } /** * Find calculations fields from entry fields * * @since 1.7 * * @param array $form_entry_fields Form entry fields. * * @return array */ public static function find_calculation_fields_meta_from_entry_fields( $form_entry_fields ) { $meta_value = array(); foreach ( $form_entry_fields as $form_entry_field ) { if ( isset( $form_entry_field['name'] ) ) { $element_id = $form_entry_field['name']; if ( self::element_is_calculation( $form_entry_field['name'] ) ) { $meta_value[ $element_id ] = isset( $form_entry_field['value'] ) ? $form_entry_field['value'] : array(); } } } /** * Filter calculations fields meta value form form entry fields * * @since 1.7 * * @param array $meta_value * @param array $form_entry_fields * * @return array */ $meta_value = apply_filters( 'forminator_addon_calculation_fields_entry_fields', $meta_value, $form_entry_fields ); return $meta_value; } /** * Check if element_id is stripe type * * @since 1.7 * * @param string $element_id Element Id. * * @return bool */ public static function element_is_stripe( $element_id ) { $is_stripe = stripos( $element_id, self::STRIPE_ELEMENT_PREFIX ) !== false; /** * Filter stripe flag of element * * @since 1.7 * * @param bool $is_stripe * @param string $element_id * * @return bool */ $is_stripe = apply_filters( 'forminator_addon_element_is_stripe', $is_stripe, $element_id ); return $is_stripe; } /** * Check if element_id is Datepicker * * @since 1.15.12 * * @param string $element_id Element Id. * * @return bool */ public static function element_is_datepicker( $element_id ) { $is_datepicker = stripos( $element_id, 'date-' ) !== false; /** * Filter date flag of element * * @since 1.15.12 * * @param bool $is_datepicker * @param string $element_id * * @return bool */ $is_datepicker = apply_filters( 'forminator_addon_element_is_datepicker', $is_datepicker, $element_id ); return $is_datepicker; } /** * Check if element_id is Signature * * @param string $element_id Field slug. * * @return bool */ public static function element_is_signature( $element_id ) { $is_signature = stripos( $element_id, 'signature-' ) !== false; /** * Filter date flag of element * * @since 1.16.0 * * @param bool $is_signature * @param string $element_id Field slug * * @return bool */ $is_signature = apply_filters( 'forminator_addon_element_is_signature', $is_signature, $element_id ); return $is_signature; } /** * Find stripe fields from entry fields * * @since 1.7 * * @param array $form_entry_fields Form entry fields. * * @return array */ public static function find_stripe_fields_meta_from_entry_fields( $form_entry_fields ) { $meta_value = array(); foreach ( $form_entry_fields as $form_entry_field ) { if ( isset( $form_entry_field['name'] ) ) { $element_id = $form_entry_field['name']; if ( self::element_is_stripe( $form_entry_field['name'] ) ) { $meta_value[ $element_id ] = isset( $form_entry_field['value'] ) ? $form_entry_field['value'] : array(); } } } /** * Filter stripe fields meta value form form entry fields * * @since 1.7 * * @param array $meta_value * @param array $form_entry_fields * * @return array */ $meta_value = apply_filters( 'forminator_addon_stripe_fields_entry_fields', $meta_value, $form_entry_fields ); return $meta_value; } /** * Check if element_id is upload * * @since 1.15.7 * * @param string $element_id Element Id. * * @return bool */ public static function element_is_upload( $element_id ) { $is_upload = stripos( $element_id, 'upload' ) !== false; /** * Filter upload flag of element * * @since 1.15.7 * * @param bool $is_upload * @param string $element_id * * @return bool */ $is_upload = apply_filters( 'forminator_addon_element_is_upload', $is_upload, $element_id ); return $is_upload; } /** * Return field data value as string * * @since 1.15.7 * * @param string $element_id Element Id. * @param array $element Element. * * @return bool */ public static function get_field_value( $element_id, $element ) { if ( is_array( $element ) ) { if ( self::element_is_upload( $element_id ) && isset( $element['file']['file_url'] ) ) { if ( is_array( $element['file']['file_url'] ) ) { $element_value = implode( ',', $element['file']['file_url'] ); } else { $element_value = $element['file']['file_url']; } } else { $element_value = implode( ',', $element ); } } else { $element_value = trim( $element ); } /** * Filter element value * * @since 1.15.7 * * @param bool $element_value * @param string $element_id * * @return bool */ $element_value = apply_filters( 'forminator_addon_element_value', $element_value, $element_id ); return $element_value; } /** * Return date value as Unix timestamp in milliseconds * * @since 1.15.12 * * @param string $element_id Element Id. * @param mixed $value Field value. * @param int $form_id Form Id. * * @return bool */ public static function get_date_in_ms( $element_id, $value, $form_id ) { $field = Forminator_API::get_form_field( $form_id, $element_id ); $normalized_format = new Forminator_Date(); $normalized_format = $normalized_format->normalize_date_format( $field['date_format'] ); $date = date_create_from_format( $normalized_format, $value ); $date->setTimezone( timezone_open( 'UTC' ) ); $date->modify( 'midnight' ); return $date->getTimestamp() * 1000; } /** * Prepare field value for passing to addon * * @param string $element_id Field slug. * @param mixed $form_entry_fields Form entry fields. * @param array $submitted_data Submitted data. * @return string */ public static function prepare_field_value_for_addon( $element_id, $form_entry_fields, $submitted_data ) { $element_value = null; if ( self::element_is_calculation( $element_id ) ) { $meta_value = self::find_meta_value_from_entry_fields( $element_id, $form_entry_fields ); $element_value = Forminator_Form_Entry_Model::meta_value_to_string( 'calculation', $meta_value ); } elseif ( self::element_is_stripe( $element_id ) ) { $meta_value = self::find_meta_value_from_entry_fields( $element_id, $form_entry_fields ); $element_value = Forminator_Form_Entry_Model::meta_value_to_string( 'stripe', $meta_value ); } elseif ( self::element_is_signature( $element_id ) ) { $meta_value = self::find_meta_value_from_entry_fields( $element_id, $form_entry_fields ); $element_value = Forminator_Form_Entry_Model::meta_value_to_string( 'signature', $meta_value ); } elseif ( ! empty( $submitted_data[ $element_id ] ) ) { $field_type = Forminator_Core::get_field_type( $element_id ); // Replace the `submission_id` with the form entry ID if it exists. if ( 'submission_id' === $submitted_data[ $element_id ] ) { $meta_value = self::find_meta_value_from_entry_fields( $element_id, $form_entry_fields ); $element_value = Forminator_Form_Entry_Model::meta_value_to_string( $field_type, $meta_value ); } else { $element_value = Forminator_Form_Entry_Model::meta_value_to_string( $field_type, $submitted_data[ $element_id ] ); } } return $element_value; } /** * Prepare Stripe subscription id for passing to addon * * @param array $submitted_data Submitted data. * @param array $form_entry_fields Form entry fields. * @return array */ public static function prepare_stripe_subscription_id_for_addon( $submitted_data, $form_entry_fields ) { if ( ! empty( $submitted_data['paymentid'] ) && 'subscription' === $submitted_data['paymentid'] ) { $field_data = wp_list_pluck( $form_entry_fields, 'value', 'name' ); foreach ( $field_data as $element_id => $value ) { if ( self::element_is_stripe( $element_id ) && ! empty( $value['subscription_id'] ) ) { $submitted_data['subscriptionid'] = $value['subscription_id']; break; } } } return $submitted_data; } } contracts/interface-integration.php 0000644 00000000727 15162271771 0013555 0 ustar 00 <?php /** * The Forminator_Integration_Interface class. * * @package Forminator */ /** * Interface Forminator_Integration_Interface * * @since 1.1 */ interface Forminator_Integration_Interface { const SHORT_TITLE_MAX_LENGTH = 10; /** * Action to execute on activation * * @since 1.1 * @return bool */ public function activate(); /** * Action to execute on de-activation * * @since 1.1 * @return bool */ public function deactivate(); } class-integration-quiz-settings.php 0000644 00000030061 15162271771 0013540 0 ustar 00 <?php /** * The Forminator_Integration_Quiz_Settings class. * * @package Forminator */ /** * Class Forminator_Integration_Quiz_Settings * Any change(s) to this file is subject to: * - Properly Written DocBlock! (what is this, why is that, how to be like those, etc, as long as you want!) * - Properly Written Changelog! * * @since 1.6.2 */ abstract class Forminator_Integration_Quiz_Settings extends Forminator_Integration_Settings { /** * Current Quiz Settings * * @since 1.6.2 * @var array */ protected $quiz_settings = array(); /** * An addon can be force disconnected from quiz, if its not met requirement, or data changed externally * example : * - Mail List deleted on mailchimp server app * - Fields removed * * @since 1.6.2 * @var bool */ protected $is_force_quiz_disconnected = false; /** * Reason of Force disconnected * * @since 1.6.2 * @var string */ protected $force_quiz_disconnected_reason = ''; /** * Quiz Model * * @since 1.6.2 * @var Forminator_Quiz_Model|null */ protected $quiz = null; /** * Current lead fields * * @since 1.14 * @var Forminator_Form_Model|null */ protected $form_fields; /** * Current lead settings * * @since 1.14 * @var Forminator_Form_Model|null */ protected $form_settings; /** * Module slug * * @var string */ protected static $module_slug = 'quiz'; /** * Forminator_Integration_Quiz_Settings constructor. * * @since 1.6.2 * * @param Forminator_Integration $addon Class Forminator_Integration. * @param int $quiz_id Quiz Id. * * @throws Forminator_Integration_Exception When there is an Integration error. */ public function __construct( Forminator_Integration $addon, $quiz_id ) { $this->addon = $addon; $this->module_id = $quiz_id; $this->quiz = Forminator_Base_Form_Model::get_model( $this->module_id ); if ( ! $this->quiz ) { /* translators: Quiz ID */ throw new Forminator_Integration_Exception( sprintf( esc_html__( 'Quiz with id %d could not be found', 'forminator' ), esc_html( $this->module_id ) ) ); } $this->quiz_settings = forminator_addon_format_quiz_settings( $this->quiz ); if ( isset( $this->quiz_settings['hasLeads'] ) && $this->quiz_settings['hasLeads'] ) { $lead_model = Forminator_Base_Form_Model::get_model( $this->quiz_settings['leadsId'] ); $this->form_fields = ! empty( $lead_model ) ? forminator_addon_format_form_fields( $lead_model ) : array(); $this->form_settings = ! empty( $lead_model ) ? forminator_addon_format_form_settings( $lead_model ) : array(); } } /** * Override this function if addon need to do something with addon quiz setting values * * @example transform, load from other storage ? * called when rendering tab on quiz settings * * @since 1.6.2 * * @param mixed $values Settings. * * @return mixed */ public function before_get_quiz_settings_values( $values ) { return $values; } /** * Override this function if addon need to do something with addon quiz setting values * * @example transform, load from other storage ? * called when rendering tab on quiz settings * @since 1.6.2 * * @param mixed $values Settings. * * @return mixed */ public function before_save_quiz_settings_values( $values ) { return $values; } /** * Get status of force disconnected from WP post_meta * * @since 1.6.2 * @return bool */ final public function is_force_quiz_disconnected() { $disconnected = get_post_meta( $this->module_id, 'forminator_addon_' . $this->addon->get_slug() . '_quiz_disconnect', true ); if ( ! empty( $disconnected ) && isset( $disconnected['disconnect'] ) && $disconnected['disconnect'] ) { $this->is_force_quiz_disconnected = true; $this->force_quiz_disconnected_reason = $disconnected['disconnect_reason']; } return $this->is_force_quiz_disconnected; } /** * Get disconnected reason * * @since 1.6.2 * @return string */ final public function force_quiz_disconnected_reason() { return $this->force_quiz_disconnected_reason; } /** * Force quiz to be disconnected with addon * * @since 1.6.2 * * @param string $reason Reason for disconnect. */ final public function force_quiz_disconnect( $reason ) { $this->is_force_quiz_disconnected = true; $this->force_quiz_disconnected_reason = $reason; $this->addon_settings = array(); $this->save_module_settings_values(); } /** * Save disconnect reason to WP post_meta * * @since 1.6.2 */ final public function save_force_quiz_disconnect_reason() { if ( $this->is_force_quiz_disconnected ) { update_post_meta( $this->module_id, 'forminator_addon_' . $this->addon->get_slug() . '_quiz_disconnect', array( 'disconnect' => true, 'disconnect_reason' => $this->force_quiz_disconnected_reason, ) ); } } /** * Remove disconnect reason quiz WP post_meta * * @since 1.6.2 */ final public function remove_saved_force_quiz_disconnect_reason() { delete_post_meta( $this->module_id, 'forminator_addon_' . $this->addon->get_slug() . '_quiz_disconnect' ); } /** * Get current quiz settings * * @since 1.6.2 * @return array */ final public function get_quiz_settings() { return $this->quiz_settings; } /** * Has lead * * @return bool */ public function has_lead() { $quiz_settings = $this->get_quiz_settings(); return ! empty( $quiz_settings['hasLeads'] ); } /** * Get current form settings * * @since 1.1 * @return array */ final public function get_form_settings() { return $this->form_settings; } /** * Get current lead form fields * * @since 1.1 * @return array */ final public function get_form_fields() { return $this->form_fields; } /** * Get current lead form fields * * @since 1.1 * @return array */ final public function get_quiz_fields() { return $this->quiz->questions; } /** * Override this function to set wizardable settings * Default its and empty array which is indicating that Integration doesnt have settings * * Its multi array, with numerical key, start with `0` * Every step on wizard, will consist at least * - `callback` : when application requesting wizard, Forminator will do `call_user_func` on this value, with these arguments * - `$submitted_data` : array of submitted data POST-ed by user * - `$quiz_id` : current quiz_id when called on `Quiz Settings` or 0 when called on Global Settings * - `is_completed` : when application requesting wizard, will check if `Previous Step` `is_completed` by doing `call_user_func` on its value * this function should return `true` or `false` * * @since 1.6.2 * @return array */ public function module_settings_wizards() { // What this function return should looks like. $steps = array( // First Step / step `0`. array( /** * Value of `callback` will be passed as first argument of `call_user_func` * it does not have to be passed `$this` as reference such as `array( $this, 'sample_setting_first_step' )`, * But its encouraged to passed `$this` because you will be benefited with $this class instance, in case you need to call private function or variable inside it * you can make the value to be `some_function_name` as long `some_function_name` as long it will globally callable which will be checked with `is_callable` * and should be able to accept 2 arguments $submitted_data, $quiz_id * * This callback should return an array @see Forminator_Integration::sample_setting_first_step() * * @see Forminator_Integration::sample_setting_first_step() */ 'callback' => array( $this, 'sample_setting_first_step' ), /** * Before Forminator call the `callback`, Forminator will attempt to run `is_completed` from the previous step * In this case, `is_completed` will be called when Forminator trying to display Settings Wizard for Second Step / step `1` * Like `callback` its value will be passed as first argument of `call_user_func` * and no arguments passed to this function when its called * * @see Forminator_Integration::sample_setting_first_step_is_completed() */ 'is_completed' => array( $this, 'sample_setting_first_step_is_completed' ), ), ); return array(); } /** * Get quiz settings data to export * * Default is from post_meta, override when needed * * @since 1.6.2 * * @return array */ public function to_exportable_data() { $addon_slug = $this->addon->get_slug(); $quiz_settings = $this->get_settings_values(); if ( empty( $quiz_settings ) ) { $exportable_data = array(); } else { $exportable_data = array( 'quiz_settings' => $quiz_settings, 'version' => $this->addon->get_version(), ); } $quiz_id = $this->module_id; /** * Filter quiz settings that will be exported when requested * * @since 1.6.2 * * @param array $exportable_data * @param int $quiz_id */ $exportable_data = apply_filters( "forminator_addon_{$addon_slug}_quiz_settings_to_exportable_data", $exportable_data, $quiz_id ); return $exportable_data; } /** * Executed when quiz settings imported * * Default is save imported data to post_meta, override when needed * * @since 1.6.2 * * @param mixed $import_data Import data. * @throws Forminator_Integration_Exception When there is an Integration error. */ public function import_data( $import_data ) { $addon_slug = $this->addon->get_slug(); $quiz_id = $this->module_id; $import_data = apply_filters( "forminator_addon_{$addon_slug}_quiz_settings_import_data", $import_data, $quiz_id ); /** * Executed when importing quiz settings of this addon * * @since 1.6.2 * * @param array $exportable_data * @param int $quiz_id */ do_action( "forminator_addon_{$addon_slug}_on_import_quiz_settings_data", $quiz_id, $import_data ); try { // pre-basic-validation. if ( empty( $import_data ) ) { throw new Forminator_Integration_Exception( 'import_data_empty' ); } if ( ! isset( $import_data['quiz_settings'] ) ) { throw new Forminator_Integration_Exception( 'import_data_no_quiz_settings' ); } if ( empty( $import_data['quiz_settings'] ) ) { throw new Forminator_Integration_Exception( 'import_data_quiz_settings_empty' ); } if ( ! isset( $import_data['version'] ) ) { throw new Forminator_Integration_Exception( 'import_data_no_version' ); } $this->save_module_settings_values( $import_data['quiz_settings'] ); } catch ( Forminator_Integration_Exception $e ) { forminator_addon_maybe_log( $e->getMessage() ); // do nothing. } } /** * Mailchimp Address type fields array * * @since 1.0 Mailchimp Integration * @return array */ public function mail_address_fields() { $address = array( 'addr1' => 'Address 1', 'addr2' => 'Address 2', 'city' => 'City', 'state' => 'State', 'zip' => 'Zip', 'country' => 'Country', ); return $address; } /** * Get fields for spesific addon field type * * @param string $type Field type. * @return array */ protected function get_fields_for_type( $type = '' ) { $fields = parent::get_fields_for_type( $type ); if ( 'email' === $type ) { return $fields; } $quiz_fields = array_map( function ( $quiz_question ) { return array( 'element_id' => $quiz_question['slug'], 'field_label' => $quiz_question['title'], ); }, $this->get_quiz_fields() ); array_unshift( $quiz_fields, array( 'element_id' => 'quiz-name', 'field_label' => __( 'Quiz Name', 'forminator' ), ) ); if ( 'knowledge' === $this->quiz->quiz_type ) { $quiz_fields[] = array( 'element_id' => 'correct-answers', 'field_label' => __( 'Correct Answers', 'forminator' ), ); $quiz_fields[] = array( 'element_id' => 'total-answers', 'field_label' => __( 'Total Answers', 'forminator' ), ); } elseif ( 'nowrong' === $this->quiz->quiz_type ) { $quiz_fields[] = array( 'element_id' => 'result-answers', 'field_label' => __( 'Result Answer', 'forminator' ), ); } return array_merge( $fields, $quiz_fields ); } } class-integration-hooks.php 0000644 00000074705 15162271772 0012053 0 ustar 00 <?php /** * The Forminator_Integration_Hooks class. * * @package Forminator */ /** * Class Forminator_Integration_Hooks */ abstract class Forminator_Integration_Hooks { /** * Integration Instance * * @since 1.1 * @var Forminator_Integration */ protected $addon; /** * Customizable submit form error message * * @since 1.1 * @var string */ protected $submit_error_message = ''; /** * Form settings instance * * @since 1.1 * @var Forminator_Integration_Settings|null */ protected $settings_instance; /** * Prefix for calculation element * * @since 1.7 */ const CALCULATION_ELEMENT_PREFIX = 'calculation-'; /** * Prefix for stripe element * * @since 1.7 */ const STRIPE_ELEMENT_PREFIX = 'stripe-'; /** * Current Module ID * * @since 1.1 * @var int */ protected $module_id; /** * Custom Module Model * * @since 1.2 * @var Forminator_Form_Model|Forminator_Poll_Model|Forminator_Quiz_Model */ protected $module; /** * Forminator_Integration_Hooks constructor. * * @param Forminator_Integration $addon Integration. * @param int $module_id Module ID. * * @since 1.1 * @throws Forminator_Integration_Exception When module ID is invalid. */ public function __construct( Forminator_Integration $addon, int $module_id ) { $this->addon = $addon; $this->module_id = $module_id; $this->module = Forminator_Base_Form_Model::get_model( $this->module_id ); if ( ! $this->module ) { /* translators: 1. Module type 2. Module ID */ throw new Forminator_Integration_Exception( sprintf( esc_html__( '%1$s with id %1$d could not be found', 'forminator' ), esc_html( ucfirst( static::$slug ) ), esc_html( $this->module_id ) ) ); } /* translators: Module type */ $this->submit_error_message = sprintf( esc_html__( '%1$s failed to process submitted data. Please check your %2$s and try again', 'forminator' ), $this->addon->get_title(), static::$slug ); // get module settings instance to be available throughout cycle. $this->settings_instance = $this->addon->get_addon_settings( $this->module_id, static::$slug ); } /** * Override this function to add another entry field to storage * * Return an multi array with format (at least, or it will be skipped) * [ * 'name' => NAME, * 'value' => VALUE', => can be array/object/scalar, it will serialized on storage * ], * [ * 'name' => NAME, * 'value' => VALUE' * ] * * @since 1.1 * @since 1.2 Add `$current_entry_fields` as optional param on inherit * * @param array $submitted_data Submitted data. * @param array $current_entry_fields default entry fields that will be saved, * its here for reference, this function doesnt need to return it * only return new entry fields. * @param array $entry Entry. * * @return array */ public function add_entry_fields( $submitted_data, $current_entry_fields, $entry ) { $addon_slug = $this->addon->get_slug(); $module_id = $this->module_id; $settings_instance = $this->settings_instance; /** * Filter submitted data to be processed by addon * * Although it can be used for all addon. * Please keep in mind that if the addon override this method, * then this filter won't be applied. * To be sure please check individual addon documentations. * * @since 1.1 * * @param array $submitted_data Submitted data. * @param int $module_id Current Module ID. * @param Forminator_Integration_Form_Settings|null $settings_instance Integration Settings instance. */ $submitted_data = apply_filters( 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_submitted_data', $submitted_data, $module_id, $settings_instance ); forminator_addon_maybe_log( __METHOD__, $submitted_data ); do_action_deprecated( 'forminator_addon_' . $addon_slug . '_before_contact_sync', array( $module_id, $submitted_data, $settings_instance ), '1.33', 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_submitted_data', ); do_action_deprecated( 'forminator_addon_' . $addon_slug . '_before_add_subscriber', array( $module_id, $submitted_data, $settings_instance ), '1.33', 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_submitted_data', ); do_action_deprecated( 'forminator_addon_' . $addon_slug . '_before_send_message', array( $module_id, $submitted_data, $settings_instance ), '1.33', 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_submitted_data', ); do_action_deprecated( 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_before_send_message', array( $module_id, $submitted_data, $settings_instance ), '1.33', 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_submitted_data', ); do_action_deprecated( 'forminator_addon_' . $addon_slug . '_before_create_row', array( $module_id, $submitted_data, $settings_instance ), '1.33', 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_submitted_data', ); do_action_deprecated( 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_before_create_row', array( $module_id, $submitted_data, $settings_instance ), '1.33', 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_submitted_data', ); do_action_deprecated( 'forminator_addon_' . $addon_slug . '_before_post_to_webhook', array( $module_id, $submitted_data, $settings_instance ), '1.33', 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_submitted_data', ); do_action_deprecated( 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_before_post_to_webhook', array( $module_id, $submitted_data, $settings_instance ), '1.33', 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_submitted_data', ); do_action_deprecated( 'forminator_addon_' . $addon_slug . '_before_create_card', array( $module_id, $submitted_data, $settings_instance ), '1.33', 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_submitted_data', ); do_action_deprecated( 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_before_create_card', array( $module_id, $submitted_data, $settings_instance ), '1.33', 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_submitted_data', ); $entry_fields = $this->custom_entry_fields( $submitted_data, $current_entry_fields, $entry ); /** * Filter addon entry fields to be saved to entry model * * @since 1.1 * @since 1.2 Add `$entry_fields` as param * * @param array $entry_fields Entry fields. * @param int $module_id Current Module ID. * @param array $submitted_data Submitted data. * @param Forminator_Integration_Settings $settings_instance Integration Settings instance. * @param array $current_entry_fields Current entry fields. */ $entry_fields = apply_filters( 'forminator_addon_' . static::$slug . '_' . $addon_slug . '_entry_fields', $entry_fields, $module_id, $submitted_data, $settings_instance, $current_entry_fields ); $entry_fields = apply_filters_deprecated( 'forminator_addon_' . $addon_slug . '_entry_fields', array( $entry_fields, $module_id, $submitted_data, $settings_instance, $current_entry_fields, ), '1.33', 'forminator_addon_' . static::$slug . '_' . $addon_slug . '_entry_fields' ); return $entry_fields; } /** * Return custom entry fields * * @param array $submitted_data Submitted data. * @param array $current_entry_fields Current entry fields. * @return array * @throws Forminator_Integration_Exception When there is an Integration error. */ protected function custom_entry_fields( array $submitted_data, array $current_entry_fields ): array { $module_id = $this->module_id; $settings_instance = $this->settings_instance; $submitted_data = $this->prepare_submitted_data( $submitted_data, $module_id, $current_entry_fields ); $addon_setting_values = $settings_instance->get_settings_values(); // initialize as null. $addon_api = null; $settings_values = $this->addon->get_settings_values(); $identifier = $settings_values['identifier'] ?? ''; $entry_name = 'status'; if ( ! empty( $this->addon->multi_global_id ) ) { $entry_name .= "-{$this->addon->multi_global_id}"; } // check required fields. try { $addon_api = $this->addon->get_api(); // email : super required**. if ( ! isset( $addon_setting_values['fields_map']['email'] ) ) { throw new Forminator_Integration_Exception( /* translators: 1: email */ sprintf( esc_html__( 'Required Field %1$s not mapped yet to Forminator Field, Please check your Integration Configuration on Module Settings', 'forminator' ), 'email' ) ); } if ( empty( $submitted_data[ $addon_setting_values['fields_map']['email'] ] ) ) { throw new Forminator_Integration_Exception( /* translators: 1: Email */ sprintf( esc_html__( 'Required Field %1$s is not filled by user', 'forminator' ), 'email' ) ); } $addon_fields = $this->addon->get_api()->get_contact_properties(); forminator_addon_maybe_log( __METHOD__, $addon_fields ); $email = strtolower( trim( $submitted_data[ $addon_setting_values['fields_map']['email'] ] ) ); $merge_fields = array(); foreach ( $addon_fields as $item ) { // its mapped ? if ( ! empty( $addon_setting_values['fields_map'][ $item->id ] ) ) { $element_id = $addon_setting_values['fields_map'][ $item->id ]; if ( ! isset( $submitted_data[ $element_id ] ) ) { continue; } $value = $submitted_data[ $element_id ]; $item_key = $item->key ?? $item->name; $merge_fields[ $item_key ] = $this->prepare_addon_field_format( $item, $value ); } } forminator_addon_maybe_log( __METHOD__, $addon_fields, $addon_setting_values, $submitted_data, $merge_fields ); $args = $this->get_special_addon_args( $submitted_data, $addon_setting_values ); if ( ! empty( $merge_fields ) ) { $args['merge_fields'] = $merge_fields; } $mail_list_id = $addon_setting_values['mail_list_id']; /** * Filter mail list id to send to Integration API * * Change $mail_list_id that will be sent to Integration API, * Any validation required by the mail list should be done. * Else if it's rejected by Integration API, It will only add Request to Log. * Log can be viewed on Entries Page * * @param string $mail_list_id * @param int $module_id Module ID. * @param array $submitted_data Submitted data. * @param Forminator_Integration_Settings $settings_instance Integration Settings. */ $mail_list_id = apply_filters( 'forminator_addon_' . $this->addon->get_slug() . '_add_update_member_request_mail_list_id', $mail_list_id, $module_id, $submitted_data, $settings_instance ); /** * Filter Integration API request arguments * * Request Arguments will be added to request body. * * @param array $args * @param int $module_id Module ID. * @param array $submitted_data Submitted data. * @param Forminator_Integration_Settings $settings_instance Integration Settings. */ $args = apply_filters( 'forminator_addon_' . $this->addon->get_slug() . '_add_update_member_request_args', $args, $module_id, $submitted_data, $settings_instance ); /** * Fires before Integration send request `add_or_update_member` to Integration API * * If this action throw an error, * then `add_or_update_member` process will be cancelled * * @param int $module_id Module ID. * @param array $submitted_data Submitted data. * @param Forminator_Integration_Settings $settings_instance Integration Settings. */ do_action( 'forminator_addon_' . $this->addon->get_slug() . '_before_add_update_member', $module_id, $submitted_data, $settings_instance ); $add_member_request = $addon_api->add_or_update_member( $mail_list_id, $email, $args ); if ( ! $add_member_request ) { throw new Forminator_Integration_Exception( esc_html__( 'Failed adding or updating member on Integration list', 'forminator' ) ); } forminator_addon_maybe_log( __METHOD__, 'Success Add Member' ); $entry_fields = array( array( 'value' => array( 'is_sent' => true, 'description' => esc_html__( 'Successfully added or updated member on the list', 'forminator' ), 'data_sent' => $addon_api->get_last_data_sent(), 'data_received' => $addon_api->get_last_data_received(), 'url_request' => $addon_api->get_last_url_request(), ), ), ); } catch ( Forminator_Integration_Exception $e ) { forminator_addon_maybe_log( __METHOD__, 'Failed to Add Member' ); $entry_fields = array( array( 'value' => array( 'is_sent' => false, 'description' => $e->getMessage(), 'data_sent' => method_exists( $addon_api, 'get_last_data_sent' ) ? $addon_api->get_last_data_sent() : array(), 'data_received' => method_exists( $addon_api, 'get_last_data_received' ) ? $addon_api->get_last_data_received() : array(), 'url_request' => method_exists( $addon_api, 'get_last_url_request' ) ? $addon_api->get_last_url_request() : '', ), ), ); } $entry_fields[0]['name'] = $entry_name; $entry_fields[0]['value']['connection_name'] = $identifier; return $entry_fields; } /** * Return special addon args * * @param array $submitted_data Submitted data. * @param array $addon_setting_values Integration settings. * @return array */ protected function get_special_addon_args( $submitted_data, $addon_setting_values ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- Used in extended class return array(); } /** * Add new Column on header of export file * for instance, `ActiveCampaign Info` * * @return array */ public function on_export_render_title_row(): array { $export_headers = array( /* translators: Integration name */ 'info' => sprintf( esc_html__( '%s Info', 'forminator' ), $this->addon->get_title() ), ); $module_id = $this->module_id; $settings_instance = $this->settings_instance; /** * Filter Activecampaign headers on export file * * @since 1.1 * * @param array $export_headers Headers to be displayed on export file. * @param int $module_id Current Module ID. * @param Forminator_Integration_Settings $settings_instance Integration Settings instance. */ $export_headers = apply_filters( 'forminator_addon_' . $this->addon->get_slug() . '_export_headers', $export_headers, $module_id, $settings_instance ); return $export_headers; } /** * Loop through addon meta data on multiple connections * * @since 1.0 * * @param array $addon_meta_datas Addon meta. * * @return array */ protected function on_render_entry_multi_connection( $addon_meta_datas ) { if ( ! isset( $addon_meta_datas[0] ) || ! is_array( $addon_meta_datas[0] ) ) { return array(); } $additional_entry_item = array(); foreach ( $addon_meta_datas as $addon_meta_data ) { $additional_entry_item[] = $this->get_additional_entry_item( $addon_meta_data ); } return $additional_entry_item; } /** * Integration will add a column that give user information whether sending data to the Integration successfully or not * It will only add one column even its multiple connection, every connection will be separated by comma * * @since 1.0 * * @param Forminator_Form_Entry_Model $entry_model Form entry model. * @param array $addon_meta_data Addon meta data. * * @return array */ public function on_export_render_entry( Forminator_Form_Entry_Model $entry_model, $addon_meta_data ) { $addon_slug = $this->addon->get_slug(); $module_id = $this->module_id; $settings_instance = $this->settings_instance; /** * Filter Integration metadata that previously saved on db to be processed * * Although it can be used for all addon. * Please keep in mind that if the addon override this method, * then this filter probably won't be applied. * To be sure please check individual addon documentations. * * @param array $addon_meta_data * @param int $module_id Current Module ID. * @param Forminator_Integration_Settings $settings_instance Integration Settings instance. *@since 1.1 */ $addon_meta_data = apply_filters( 'forminator_addon_' . static::$slug . '_' . $addon_slug . '_metadata', $addon_meta_data, $module_id, $settings_instance ); $export_columns = array( 'info' => $this->get_from_addon_meta_data( $addon_meta_data, 'description' ), ); /** * Filter Integration columns to be displayed on export submissions * * @since 1.1 * * @param array $export_columns column to be exported. * @param int $module_id current Module ID. * @param Forminator_Form_Entry_Model $entry_model Form Entry Model. * @param array $addon_meta_data meta data saved by addon on entry fields. * @param Forminator_Integration_Settings $settings_instance Integration Settings instance. */ $export_columns = apply_filters( 'forminator_addon_' . static::$slug . '_' . $addon_slug . '_export_columns', $export_columns, $module_id, $entry_model, $addon_meta_data, $settings_instance ); return $export_columns; } /** * Format additional entry item as label and value arrays * * - Integration Name : its defined by user when they are adding integration on their module * - Sent To {Integration name} : will be Yes/No value, that indicates whether sending data to the addon was successful * - Info : Text that are generated by addon when building and sending data to it * - Below subentries will be added if full log enabled, @see Forminator_Integration::is_show_full_log() * - API URL : URL that wes requested when sending data to the addon * - Data sent to {Integration name} : json encoded body request that was sent * - Data received from {Integration name} : json encoded body response that was received * * @param array $addon_meta_data Integration metadata. * * @return array */ protected function get_additional_entry_item( $addon_meta_data ) { if ( ! isset( $addon_meta_data['value'] ) || ! is_array( $addon_meta_data['value'] ) ) { return array(); } $status = $addon_meta_data['value']; $additional_entry_item = array( /* translators: Integration name */ 'label' => sprintf( esc_html__( '%s Integration', 'forminator' ), $this->addon->get_title() ), 'value' => '', ); $sub_entries = array(); if ( isset( $status['connection_name'] ) ) { $sub_entries[] = array( 'label' => esc_html__( 'Integration Name', 'forminator' ), 'value' => $status['connection_name'], ); } if ( isset( $status['is_sent'] ) ) { $is_sent = true === $status['is_sent'] ? esc_html__( 'Yes', 'forminator' ) : esc_html__( 'No', 'forminator' ); $sub_entries[] = array( /* translators: Integration name */ 'label' => sprintf( esc_html__( 'Sent To %s', 'forminator' ), $this->addon->get_title() ), 'value' => $is_sent, ); } if ( isset( $status['description'] ) ) { $sub_entries[] = array( 'label' => esc_html__( 'Info', 'forminator' ), 'value' => $status['description'], ); } if ( is_callable( array( $this, 'add_extra_entry_items' ) ) ) { static::add_extra_entry_items( $sub_entries, $status ); } if ( $this->addon->is_show_full_log() ) { // too long to be added on entry data enable this with the relevant constant. if ( isset( $status['url_request'] ) ) { $sub_entries[] = array( 'label' => esc_html__( 'API URL', 'forminator' ), 'value' => $status['url_request'], ); } if ( isset( $status['data_sent'] ) ) { $sub_entries[] = array( /* translators: Integration name */ 'label' => sprintf( esc_html__( 'Data sent to %s', 'forminator' ), $this->addon->get_title() ), 'value' => '<pre class="sui-code-snippet">' . wp_json_encode( $status['data_sent'], JSON_PRETTY_PRINT ) . '</pre>', ); } if ( isset( $status['data_received'] ) ) { $sub_entries[] = array( /* translators: Integration name */ 'label' => sprintf( esc_html__( 'Data received from %s', 'forminator' ), $this->addon->get_title() ), 'value' => '<pre class="sui-code-snippet">' . wp_json_encode( $status['data_received'], JSON_PRETTY_PRINT ) . '</pre>', ); } } $additional_entry_item['sub_entries'] = $sub_entries; // return single array. return $additional_entry_item; } /** * It wil add new row on entry table of submission page, with couple of sub-entries * sub-entries included are defined in @see Forminator_Integration_Hooks::get_additional_entry_item() * * @since 1.0 * * @param Forminator_Form_Entry_Model $entry_model Form entry model. * @param array $addon_meta_data Addon meta. * * @return array */ public function on_render_entry( Forminator_Form_Entry_Model $entry_model, $addon_meta_data ) { $module_id = $this->module_id; $settings_instance = $this->settings_instance; /** * * Filter addon metadata that previously saved on db to be processed * * Although it can be used for all addon. * Please keep in mind that if the addon override this method, * then this filter probably won't be applied. * To be sure please check individual addon documentations. * * @param array $addon_meta_data Integration metadata. * @param int $module_id Current Module ID. * @param Forminator_Form_Entry_Model $entry_model Forminator Entry Model. * @param object $settings_instance Integration Settings instance. */ $addon_meta_data = apply_filters( 'forminator_addon_' . $this->addon->get_slug() . '_metadata', $addon_meta_data, $module_id, $entry_model, $settings_instance ); return $this->on_render_entry_multi_connection( $addon_meta_data ); } /** * Get Integration meta data, will be recursive if meta data is multiple because of multiple connection added * * @since 1.6.2 * * @param array $addon_meta_data All meta data. * @param string $key Meta key. * @param mixed $default_value Default returning value. * * @return string */ protected function get_from_addon_meta_data( $addon_meta_data, $key, $default_value = '' ) { $addon_meta_datas = $addon_meta_data; if ( ! isset( $addon_meta_data[0] ) || ! is_array( $addon_meta_data[0] ) ) { return $default_value; } $addon_meta_data = $addon_meta_data[0]; // make sure its `status`, because we only add this. if ( 'status' !== $addon_meta_data['name'] ) { if ( stripos( $addon_meta_data['name'], 'status-' ) === 0 ) { $meta_data = array(); foreach ( $addon_meta_datas as $addon_meta_data ) { // make it like single value so it will be processed like single meta data. $addon_meta_data['name'] = 'status'; // add it on an array for next recursive process. $meta_data[] = $this->get_from_addon_meta_data( array( $addon_meta_data ), $key, $default_value ); } return implode( ', ', $meta_data ); } return $default_value; } if ( ! isset( $addon_meta_data['value'] ) || ! is_array( $addon_meta_data['value'] ) ) { return $default_value; } $status = $addon_meta_data['value']; if ( isset( $status[ $key ] ) ) { $connection_name = ''; if ( 'connection_name' !== $key ) { if ( isset( $status['connection_name'] ) ) { $connection_name = '[' . $status['connection_name'] . '] '; } } return $connection_name . $status[ $key ]; } return $default_value; } /** * Override this function to execute action before submission deleted * * If function generate output, it will output-ed * race condition between addon probably happen * its void function, so return value will be ignored, and forminator process will always continue * unless it generates unrecoverable error, so please be careful on extending this function * * @since 1.1 * * @param Forminator_Form_Entry_Model $entry_model Forminator Entry Model. * @param array $addon_meta_data Integration meta data. */ public function on_before_delete_entry( Forminator_Form_Entry_Model $entry_model, $addon_meta_data ) { $addon_slug = $this->addon->get_slug(); $module_id = $this->module_id; $settings_instance = $this->settings_instance; /** * Fires when connected module deletes a submission * * Although it can be used for all addon. * Please keep in mind that if the addon override this method, * then this action won't be triggered. * To be sure please check individual addon documentations. * * @since 1.1 * * @param int $module_id Current Module ID. * @param Forminator_Form_Entry_Model $entry_model Forminator Entry Model. * @param array $addon_meta_data Integration meta data. * @param Forminator_Integration_Settings|null $settings_instance Integration Settings. */ do_action( 'forminator_addon_' . static::$slug . '_' . $addon_slug . '_on_before_delete_submission', $module_id, $entry_model, $addon_meta_data, $settings_instance ); } /** * Override this function to execute action on submit module * * Return true will continue forminator process, * return false will stop forminator process, * and display error message to user @see Forminator_Integration_Hooks::get_submit_error_message() * * @since 1.1 * * @param array $submitted_data Submitted data. * * @return bool */ public function on_module_submit( $submitted_data ) { $addon_slug = $this->addon->get_slug(); $module_id = $this->module_id; $settings_instance = $this->settings_instance; /** * Filter submitted module data to be processed by addon * * Although it can be used for all addon. * Please keep in mind that if the addon override this method, * then this filter won't be applied. * To be sure please check individual addon documentations. * * @since 1.1 * * @param array $submitted_data * @param int $module_id Current Module ID. * @param Forminator_Integration_Settings|null $settings_instance Integration Settings instance. */ $submitted_data = apply_filters( 'forminator_addon_' . $addon_slug . '_' . static::$slug . '_submitted_data', $submitted_data, $module_id, $settings_instance ); $is_success = true; /** * Filter result of module submit * * Return `true` if success, or **(string) error message** on fail * Although it can be used for all addon. * Please keep in mind that if the addon override this method, * then this filter won't be applied. * To be sure please check individual addon documentations. * * @since 1.1 * * @param bool $is_success * @param int $module_id Current Module ID. * @param array $submitted_data * @param Forminator_Integration_Settings|null $settings_instance Integration Settings instance. */ $is_success = apply_filters( 'forminator_addon_' . $addon_slug . '_on_' . static::$slug . '_submit_result', $is_success, $module_id, $submitted_data, $settings_instance ); // process filter. if ( true !== $is_success && ! empty( $is_success ) ) { // only update `submit_error_message` when not empty. $this->submit_error_message = (string) $is_success; } return $is_success; } /** * Return submitted data. * * @param array $submitted_data Submitted data. * @param int $module_id Module ID. * @param array $current_entry_fields Current entry fields. * @return array */ protected function prepare_submitted_data( array $submitted_data, int $module_id, array $current_entry_fields ): array { $submitted_data = $this->reformat_submitted_data( $submitted_data, $module_id, $current_entry_fields ); return $submitted_data; } /** * Return submitted data. * * @param array $submitted_data Submitted data. * @param int $module_id Module ID. * @param array $current_entry_fields Current entry fields. * @return array */ protected function reformat_submitted_data( array $submitted_data, int $module_id, array $current_entry_fields ): array { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- May be used in extended class. foreach ( $submitted_data as $field => $value ) { // Also Check the date field doesn't include the '-year', '-month' or '-day'. if ( false !== stripos( $field, 'date-' ) && false === stripos( $field, '-year' ) && false === stripos( $field, '-month' ) && false === stripos( $field, '-day' ) && ! empty( $value ) ) { $date_format = Forminator_API::get_form_field( $module_id, $field, false )->date_format; $normalized_format = new Forminator_Date(); $normalized_format = $normalized_format->normalize_date_format( $date_format ); $addon_format = DateTime::createFromFormat( $normalized_format, $value ); $addon_formatted = $addon_format->format( 'Y-m-d' ); $submitted_data[ $field ] = $addon_formatted; } } return $submitted_data; } /** * Prepare field value according its type * * @param object $field Field properties. * @param string $value Origin value. * @return bool|float|int|string */ protected function prepare_addon_field_format( $field, $value ) { $field_type = $field->datatype ?? $field->type; if ( 'datetime' === $field_type ) { $time = strtotime( $value ); if ( $time ) { $value = gmdate( 'U', $time ); } else { $value = ''; } } elseif ( 'int' === $field_type ) { $value = (int) $value; } elseif ( 'float' === $field_type ) { $value = (float) $value; } elseif ( 'bool' === $field_type ) { $value = (bool) $value; } else { $value = (string) $value; } return $value; } } class-integration-poll-hooks.php 0000644 00000006355 15162271772 0013013 0 ustar 00 <?php /** * The Forminator_Integration_Poll_Hooks class. * * @package Forminator */ /** * Class Forminator_Integration_Poll_Hooks * Any change(s) to this file is subject to: * - Properly Written DocBlock! (what is this, why is that, how to be like those, etc, as long as you want!) * - Properly Written Changelog! * * If you override any of these method, please add necessary hooks in it, * Which you can see below, as a reference and keep the arguments signature. * If needed you can call these method, as parent::method_name(), * and add your specific hooks. * * @since 1.6.1 */ abstract class Forminator_Integration_Poll_Hooks extends Forminator_Integration_Hooks { /** * Module slug * * @var string */ protected static string $slug = 'poll'; /** * Override this function to execute action after entry saved * * Its void function, so return value will be ignored, and forminator process will always continue * unless it generates unrecoverable error, so please be careful on extending this function * * @since 1.6.1 * * @param Forminator_Form_Entry_Model $entry_model Form entry model. */ public function after_entry_saved( Forminator_Form_Entry_Model $entry_model ) { $addon_slug = $this->addon->get_slug(); $poll_id = $this->module_id; $poll_settings_instance = $this->settings_instance; /** * Fires when entry already saved on db * * Although it can be used for all addon. * Please keep in mind that if the addon override this method, * then this filter probably won't be applied. * To be sure please check individual addon documentations. * * @since 1.6.1 * * @param int $poll_id current Poll ID. * @param Forminator_Form_Entry_Model $entry_model Forminator Entry Model. * @param Forminator_Integration_Poll_Settings|null $poll_settings_instance of Integration Poll Settings. */ do_action( 'forminator_addon_poll_' . $addon_slug . '_after_entry_saved', $poll_id, $entry_model, $poll_settings_instance ); } /** * Get Submit poll error message * * @since 1.6.1 * @return string */ public function get_submit_error_message() { $addon_slug = $this->addon->get_slug(); $poll_id = $this->module_id; $poll_settings_instance = $this->settings_instance; $error_message = $this->submit_error_message; /** * Filter addon columns to be displayed on export submissions * * Although it can be used for all addon. * Please keep in mind that if the addon override this method, * then this filter probably won't be applied. * To be sure please check individual addon documentations. * * @since 1.6.1 * * @param array $export_columns column to be exported. * @param int $poll_id current poll ID. * @param Forminator_Integration_Poll_Settings|null $poll_settings_instance of Integration Poll Settings. */ $error_message = apply_filters( 'forminator_addon_' . $addon_slug . '_submit_poll_error_message', $error_message, $poll_id, $poll_settings_instance ); return $error_message; } } admin/class-integration-admin-ajax.php 0000644 00000035605 15162271773 0014026 0 ustar 00 <?php /** * The Forminator_Integration_Admin_Ajax class. * * @package Forminator */ /* @noinspection PhpIncludeInspection */ if ( ! defined( 'ABSPATH' ) ) { die(); } /** * Class Forminator_Integration_Admin_Ajax * Available ajax action for interacting with forminator addons * * @since 1.1 */ class Forminator_Integration_Admin_Ajax { /** * Default nonce action * * @since 1.1 * @var string */ private static $_nonce_action = 'forminator_addon_action'; /** * Current Nonce * * @since 1.1 * @var string */ private $_nonce = ''; /** * Current Instance * * @since 1.1 * @var self */ private static $_instance = null; /** * Singleton * * @since 1.1 * @return Forminator_Integration_Admin_Ajax */ public static function get_instance() { if ( is_null( self::$_instance ) ) { self::$_instance = new self(); } return self::$_instance; } /** * Semaphore to avoid wp_ajax hook called multiple times * * @var bool */ private static $is_ajax_hooked = false; /** * Define actions and its callback * * @since 1.1 * Forminator_Integration_Admin_Ajax constructor. */ public function __construct() { if ( ! self::$is_ajax_hooked ) { add_action( 'wp_ajax_forminator_addon_get_addons', array( $this, 'get_addons' ) ); add_action( 'wp_ajax_forminator_addon_deactivate', array( $this, 'deactivate' ) ); add_action( 'wp_ajax_forminator_addon_settings', array( $this, 'settings' ) ); add_action( 'wp_ajax_forminator_addon_get_module_addons', array( $this, 'get_module_addons' ) ); add_action( 'wp_ajax_forminator_addon_module_settings', array( $this, 'module_settings' ) ); add_action( 'wp_ajax_forminator_addon_deactivate_for_module', array( $this, 'deactivate_for_module' ) ); add_action( 'wp_ajax_forminator_refresh_email_lists', array( $this, 'refresh_email_lists' ) ); self::$is_ajax_hooked = true; } } /** * Validate Ajax request * * @param mixed $page_slug Page slug. * * @since 1.1 */ private function validate_ajax( $page_slug = '' ) { if ( ! forminator_is_user_allowed( $page_slug ) || ! check_ajax_referer( self::$_nonce_action, false, false ) ) { $this->send_json_errors( esc_html__( 'Invalid request, you are not allowed to do that action.', 'forminator' ) ); } } /** * Deactivate Integration * * @since 1.1 */ public function deactivate() { $this->validate_ajax( 'forminator-integrations' ); $data = $this->validate_and_sanitize_fields( array( 'slug' ) ); $slug = $data['slug']; $addon = forminator_get_addon( $slug ); if ( ! empty( $data['global_id'] ) ) { $addon->multi_global_id = $data['global_id']; unset( $data['global_id'] ); } forminator_maybe_attach_addon_hook( $addon ); $deactivated = Forminator_Integration_Loader::get_instance()->deactivate_addon( $slug ); if ( ! $deactivated ) { $this->send_json_errors( Forminator_Integration_Loader::get_instance()->get_last_error_message(), array(), array( 'notification' => array( 'type' => 'error', 'text' => Forminator_Integration_Loader::get_instance()->get_last_error_message(), ), ) ); } $this->send_json_success( esc_html__( 'Integration Deactivated', 'forminator' ), array( 'notification' => array( 'type' => 'success', 'text' => '<strong>' . $addon->get_title() . '</strong> ' . esc_html__( 'has been disconnected successfully.', 'forminator' ), ), ) ); }//end deactivate() /** * Get / Save settings * * @since 1.1 */ public function settings() { $this->validate_ajax( 'forminator-integrations' ); $sanitized_post_data = $this->validate_and_sanitize_fields( array( 'slug', 'current_step', 'step' ) ); $slug = $sanitized_post_data['slug']; $step = $sanitized_post_data['step']; $current_step = $sanitized_post_data['current_step']; $form_id = 0; if ( isset( $sanitized_post_data['form_id'] ) ) { $form_id = $sanitized_post_data['form_id']; unset( $sanitized_post_data['form_id'] ); } $addon = $this->validate_addon_from_slug( $slug ); if ( ! $addon->is_settings_available() ) { $this->send_json_errors( esc_html__( 'This Integration does not have settings available', 'forminator' ) ); } if ( isset( $sanitized_post_data['global_id'] ) ) { $addon->multi_global_id = $sanitized_post_data['global_id']; unset( $sanitized_post_data['global_id'] ); } forminator_maybe_attach_addon_hook( $addon ); unset( $sanitized_post_data['slug'] ); unset( $sanitized_post_data['step'] ); unset( $sanitized_post_data['current_step'] ); $wizard = $addon->get_settings_wizard( $sanitized_post_data, $form_id, $current_step, $step ); $this->send_json_success( '', $wizard ); }//end settings() /** * Disconnect module from addon * * @since 1.1 */ public function deactivate_for_module() { $this->validate_ajax( 'forminator' ); $sanitized_post_data = $this->validate_and_sanitize_fields( array( 'slug', 'module_id', 'module_type' ) ); $slug = $sanitized_post_data['slug']; $module_id = $sanitized_post_data['module_id']; $module_type = $sanitized_post_data['module_type']; $addon = $this->validate_addon_from_slug( $slug ); if ( ! empty( $sanitized_post_data['global_id'] ) ) { $addon->multi_global_id = $sanitized_post_data['global_id']; unset( $sanitized_post_data['global_id'] ); } forminator_maybe_attach_addon_hook( $addon ); $settings = $addon->get_addon_settings( $module_id, $module_type ); if ( $settings instanceof Forminator_Integration_Settings ) { unset( $sanitized_post_data['slug'] ); unset( $sanitized_post_data['module_id'] ); unset( $sanitized_post_data['module_type'] ); $addon_title = $addon->get_title(); // handling multi_id. if ( isset( $sanitized_post_data['multi_id'] ) ) { $multi_id_label = ''; $multi_ids = $settings->get_multi_ids(); foreach ( $multi_ids as $key => $multi_id ) { if ( isset( $multi_id['id'] ) && $multi_id['label'] ) { if ( $multi_id['id'] === $sanitized_post_data['multi_id'] ) { $multi_id_label = $multi_id['label']; break; } } } if ( ! empty( $multi_id_label ) ) { $addon_title .= ' [' . $multi_id_label . '] '; } } $settings->disconnect_module( $sanitized_post_data ); $this->send_json_success( /* translators: integration title */ sprintf( esc_html__( 'Successfully disconnected %s from this module', 'forminator' ), $addon->get_title() ), array( 'notification' => array( 'type' => 'success', 'text' => '<strong>' . $addon_title . '</strong> ' . esc_html__( 'Successfully disconnected from this module', 'forminator' ), ), ) ); } else { $this->send_json_errors( /* translators: integration title */ sprintf( esc_html__( 'Failed to disconnect %s from this module', 'forminator' ), $addon->get_title() ), array(), array( 'notification' => array( 'type' => 'error', 'text' => '<strong>' . $addon->get_title() . '</strong> ' . esc_html__( 'Failed to disconnected from this module', 'forminator' ), ), ) ); } } /** * Get Integrations list, grouped by connected status * * @since 1.1 */ public function get_addons() { $this->validate_ajax( 'forminator-integrations' ); /* @noinspection PhpUnusedLocalVariableInspection */ $addons = forminator_get_registered_addons_grouped_by_connected(); ob_start(); /* @noinspection PhpIncludeInspection */ include_once forminator_plugin_dir() . 'admin/views/integrations/page-content.php'; $html = ob_get_clean(); $this->send_json_success( '', $html ); } /** * Generate nonce * * @since 1.1 */ public function generate_nonce() { $this->_nonce = wp_create_nonce( self::$_nonce_action ); } /** * Get current generated nonce * * @since 1.1 * @return string */ public function get_nonce() { return $this->_nonce; } /** * Send Json Success to client * * @since 1.1 * * @param string $message Message. * @param array $additional_data Additional data. */ private function send_json_success( $message = '', $additional_data = array() ) { wp_send_json_success( array( 'message' => $message, 'data' => $additional_data, 'nonce' => $this->_nonce, ) ); }//end send_json_success() /** * Send Json Error to client * * @since 1.1 * * @param string $message Message. * @param array $errors Errors. * @param array $additional_data Additional data. */ private function send_json_errors( $message = '', $errors = array(), $additional_data = array() ) { wp_send_json_error( array( 'message' => $message, 'errors' => $errors, 'data' => $additional_data, 'nonce' => $this->_nonce, ) ); }//end send_json_errors() /** * Validate required fields, and sanitized post data * * @since 1.1 * * @param array $required_fields Required fields. * * @return mixed */ private function validate_and_sanitize_fields( $required_fields = array() ) { $post_data = isset( $_POST['data'] ) // phpcs:ignore WordPress.Security.NonceVerification.Missing ? ( is_string( $_POST['data'] ) // phpcs:ignore WordPress.Security.NonceVerification.Missing ? filter_input( INPUT_POST, 'data' ) : Forminator_Core::sanitize_array( $_POST['data'], 'data' ) ) // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput : ''; if ( ! $post_data ) { $post_data = filter_input( INPUT_GET, 'data' ); } // for serialized data or form. if ( is_string( $post_data ) ) { $post_string = $post_data; $post_data = array(); wp_parse_str( $post_string, $post_data ); } $errors = array(); foreach ( $required_fields as $key => $required_field ) { if ( ! isset( $post_data[ $required_field ] ) ) { /* translators: %s: Required field */ $errors[] = sprintf( esc_html__( 'Field %s is required', 'forminator' ), $required_field ); continue; } } if ( ! empty( $errors ) ) { $this->send_json_errors( esc_html__( 'Please check your form.', 'forminator' ), $errors ); } // TODO: sanitize. foreach ( $post_data as $key => $post_datum ) { // sanitize here, every request will sanitized here,. // so we dont need to sanitize it again on other methods, unless need special treatment. $post_data[ $key ] = $post_datum; } return $post_data; } /** * Validate addon from slug * * @since 1.5.2 * * @param string $slug Addon slug. * * @return Forminator_Integration */ private function validate_addon_from_slug( $slug ) { $addon = forminator_get_addon( $slug ); if ( ! $addon || ( ! $addon instanceof Forminator_Integration ) ) { $this->send_json_errors( esc_html__( 'Integration not found', 'forminator' ), array(), array( 'notification' => array( 'type' => 'error', 'text' => '<strong>' . $slug . '</strong> ' . esc_html__( 'Integration Not Found', 'forminator' ), ), ) ); } return $addon; } /** * Remove instance of Integration Admin Ajax * * @since 1.1 */ public static function remove_instance() { if ( ! is_null( self::$_instance ) ) { remove_action( 'wp_ajax_forminator_addon_get_addons', array( self::$_instance, 'get_addons' ) ); remove_action( 'wp_ajax_forminator_addon_settings', array( self::$_instance, 'settings' ) ); remove_action( 'wp_ajax_forminator_addon_deactivate', array( self::$_instance, 'deactivate' ) ); remove_action( 'wp_ajax_forminator_addon_get_module_addons', array( self::$_instance, 'get_module_addons' ) ); remove_action( 'wp_ajax_forminator_addon_module_settings', array( self::$_instance, 'module_settings' ) ); remove_action( 'wp_ajax_forminator_addon_deactivate_for_module', array( self::$_instance, 'deactivate_for_module' ) ); self::$is_ajax_hooked = false; self::$_instance = null; } } /** * Refresh email lists */ public function refresh_email_lists() { $this->validate_ajax( 'forminator-integrations' ); $sanitized_post_data = $this->validate_and_sanitize_fields( array( 'slug', 'global_id' ) ); $slug = $sanitized_post_data['slug']; $addon = $this->validate_addon_from_slug( $slug ); $lists = array(); if ( ! empty( $sanitized_post_data['global_id'] ) ) { $addon->multi_global_id = $sanitized_post_data['global_id']; unset( $sanitized_post_data['global_id'] ); } if ( method_exists( $addon, 'get_api' ) ) { $api = $addon->get_api(); if ( method_exists( $api, 'get_all_lists' ) ) { $lists = $api->get_all_lists( true ); $lists = wp_list_pluck( $lists, 'name', 'id' ); } } $html = Forminator_Integration_Settings::get_select_html( $lists ); wp_send_json_success( array( 'options' => $html, ) ); } /** * Get Integrations List, grouped by connected status with module * * @since 1.1 */ public function get_module_addons() { $this->validate_ajax( 'forminator' ); $sanitized_post_data = $this->validate_and_sanitize_fields( array( 'module_id', 'module_type' ) ); $module_id = $sanitized_post_data['module_id']; $module_slug = $sanitized_post_data['module_type']; $addons = forminator_get_registered_addons_grouped_by_module_connected( $module_id, $module_slug ); ob_start(); require_once forminator_plugin_dir() . 'admin/views/integrations/main.php'; $html = ob_get_clean(); $this->send_json_success( '', $html ); } /** * Get / Save module settings * * @since 1.1 */ public function module_settings() { $this->validate_ajax( 'forminator' ); $sanitized_post_data = $this->validate_and_sanitize_fields( array( 'slug', 'step', 'module_id', 'module_type', 'current_step' ) ); $slug = $sanitized_post_data['slug']; $step = $sanitized_post_data['step']; $current_step = $sanitized_post_data['current_step']; $module_id = $sanitized_post_data['module_id']; $module_type = $sanitized_post_data['module_type']; $addon = $this->validate_addon_from_slug( $slug ); $is_settings_available = 'is_' . $module_type . '_settings_available'; if ( ! $addon->$is_settings_available( $module_id ) ) { $this->send_json_errors( esc_html__( 'This Integration does not have module settings available', 'forminator' ) ); } forminator_maybe_attach_addon_hook( $addon ); if ( isset( $sanitized_post_data['global_id'] ) ) { $addon->multi_global_id = $sanitized_post_data['global_id']; unset( $sanitized_post_data['global_id'] ); } unset( $sanitized_post_data['slug'] ); unset( $sanitized_post_data['current_step'] ); unset( $sanitized_post_data['step'] ); unset( $sanitized_post_data['module_id'] ); unset( $sanitized_post_data['module_type'] ); unset( $sanitized_post_data['is_submit'] ); $get_settings_wizard = 'get_' . $module_type . '_settings_wizard'; $wizard = $addon->$get_settings_wizard( $sanitized_post_data, $module_id, $current_step, $step ); $this->send_json_success( '', $wizard ); }//end module_settings() } class-addon-container.php 0000644 00000007550 15162271774 0011450 0 ustar 00 <?php /** * The Forminator_Addon_Container class. * * @package Forminator */ /** * Class Forminator_Addon_Container * Container that holds addons * * @since 1.1 */ class Forminator_Addon_Container implements ArrayAccess, Countable, Iterator { /** * Addons * * @since 1.1 * @var Forminator_Integration[] */ private $addons = array(); /** * Offset exists * * @since 1.1 * * @param mixed $offset Offset. * * @return bool */ #[\ReturnTypeWillChange] public function offsetExists( $offset ) { return isset( $this->addons[ $offset ] ); } /** * Get offset * * @since 1.1 * * @param mixed $offset Offset. * * @return Forminator_Integration|mixed|null */ #[\ReturnTypeWillChange] public function offsetGet( $offset ) { if ( isset( $this->addons[ $offset ] ) ) { return $this->addons[ $offset ]; } return null; } /** * Set offset * * @since 1.1 * * @param mixed $offset Offset. * @param mixed $value Offset value. */ #[\ReturnTypeWillChange] public function offsetSet( $offset, $value ) { $this->addons[ $offset ] = $value; } /** * Unset offset * * @param mixed $offset Offset. */ #[\ReturnTypeWillChange] public function offsetUnset( $offset ) { unset( $this->addons[ $offset ] ); } /** * Count elements of an object * * @link http://php.net/manual/en/countable.count.php * @return int The custom count as an integer. * </p> * <p> * The return value is cast to an integer. * @since 1.1 */ #[\ReturnTypeWillChange] public function count() { return count( $this->addons ); } /** * Get All registers slug of addons * * @since 1.1 * @return array */ public function get_slugs() { return array_keys( $this->addons ); } /** * To group array. * * @return array */ public function to_grouped_array() { $addons = array(); foreach ( $this->addons as $slug => $addon_members ) { // force to offsetGet. // in case will added hook. $addon = $this[ $slug ]; // enable later when implemented. // if ( ! $addon ) {. // continue;. // }. $addons[ $addon->get_slug() ] = $addon->to_array(); } return $addons; } /** * Return add-ons list as array * * @since 1.1 * * @return array */ public function to_array() { $addons = array(); foreach ( $this->addons as $slug => $addon_members ) { // force to offsetGet: enable when needed. // in case will added hook. $addon = $this[ $slug ]; $addons[ $addon->get_slug() ] = $addon->to_array(); } return $addons; } /** * Return the current element * * @link http://php.net/manual/en/iterator.current.php * @return mixed Can return any type. * @since 1.1 */ #[\ReturnTypeWillChange] public function current() { return current( $this->addons ); } /** * Move forward to next element * * @link http://php.net/manual/en/iterator.next.php * @return void Any returned value is ignored. * @since 1.1 */ #[\ReturnTypeWillChange] public function next() { next( $this->addons ); } /** * Return the key of the current element * * @link http://php.net/manual/en/iterator.key.php * @return mixed scalar on success, or null on failure. * @since 1.1 */ #[\ReturnTypeWillChange] public function key() { return key( $this->addons ); } /** * Checks if current position is valid * * @link http://php.net/manual/en/iterator.valid.php * @return boolean The return value will be casted to boolean and then evaluated. * Returns true on success or false on failure. * @since 1.1 */ #[\ReturnTypeWillChange] public function valid() { return key( $this->addons ) !== null; } /** * Rewind the Iterator to the first element * * @link http://php.net/manual/en/iterator.rewind.php * @return void Any returned value is ignored. * @since 1.1 */ #[\ReturnTypeWillChange] public function rewind() { reset( $this->addons ); } }