D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
home
/
everqlsh
/
www
/
wp-admin
/
user
/
577040
/
Filename :
model.tar
back
Copy
class-poll-form-model.php 0000644 00000032764 15162406305 0011403 0 ustar 00 <?php /** * The Forminator_Poll_Model class. * * @package Forminator */ if ( ! defined( 'ABSPATH' ) ) { die(); } /** * Author: Hoang Ngo */ class Forminator_Poll_Model extends Forminator_Base_Form_Model { /** * Module slug * * @var string */ public static $module_slug = 'poll'; /** * Post type * * @var string */ protected $post_type = 'forminator_polls'; /** * Whether to check form access * * @since 1.0.5 * * @var bool */ protected $check_access = true; /** * Prepare data for preview * * @param object $form_model Model. * @param array $data Passed data. * * @return object */ public static function prepare_data_for_preview( $form_model, $data ) { // build the field. $fields = array(); if ( isset( $data['answers'] ) ) { $fields = $data['answers']; unset( $data['answers'] ); } // Set fields. foreach ( $fields as $f ) { $field = new Forminator_Form_Field_Model(); $field->form_id = isset( $f['wrapper_id'] ) ? $f['wrapper_id'] : $f['title']; $field->slug = isset( $f['element_id'] ) ? $f['element_id'] : $f['title']; $field->import( $f ); $form_model->add_field( $field ); } return $form_model; } /** * Check if the vote clause is set up and if a user can vote again * * @since 1.0 * @param bool $freeze Optional. Should it prevent parallel requests. False by default. * @return bool */ public function current_user_can_vote( $freeze = false ) { /** * Added condition for poll access. * * @since 1.0.5 */ if ( $this->check_access ) { if ( $this->is_method_browser_cookie() ) { return $this->poll_votes_method_browser_cookie(); } else { $user_ip = Forminator_Geo::get_user_ip(); $key_requests = 'forminator_request_from_ip_' . $this->id . '_' . $user_ip; // Check if the IP has made a request within the allowed interval. if ( get_transient( $key_requests ) ) { // IP has made a request too soon. $can_vote = false; } else { if ( $freeze ) { /** * Filter the time interval (in seconds) between consecutive requests allowed per IP * * @param int $seconds Second amount. 10 by default. * @param string $user_ip Current IP. */ $expiration = apply_filters( 'forminator_poll_request_interval_seconds', 10, $user_ip ); $set_transient = set_transient( $key_requests, 1, $expiration ); if ( ! $set_transient ) { // It doesn't set transient for parallel requests. return false; } } $can_vote = $this->poll_votes_method_user_ip(); } return $can_vote; } } return true; } /** * Check user can vote by browser cookie * * @return bool */ public function poll_votes_method_browser_cookie() { $settings = $this->settings; $poll_cookie = 'poll-cookie-' . md5( $this->id ); if ( ! isset( $_COOKIE[ $poll_cookie ] ) ) { return true; } if ( $this->is_allow_multiple_votes() ) { if ( isset( $settings['vote_limit_input'] ) && ! empty( $settings['vote_limit_input'] ) ) { $duration = is_numeric( $settings['vote_limit_input'] ) ? $settings['vote_limit_input'] : '1'; $vote_limit_options = isset( $settings['vote_limit_options'] ) ? $settings['vote_limit_options'] : 'm'; switch ( $vote_limit_options ) { case 'h': $interval = 'hour'; break; case 'd': $interval = 'day'; break; case 'W': $interval = 'week'; break; case 'M': $interval = 'month'; break; case 'm': $interval = 'minute'; break; case 'Y': $interval = 'year'; break; default: $interval = 'year'; break; } $cookie_value = date_i18n( 'Y-m-d H:i:s', strtotime( Forminator_Core::sanitize_text_field( $_COOKIE[ $poll_cookie ] ) ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput $cookie_expire = $cookie_value . ' +' . $duration . ' ' . $interval; if ( time() < strtotime( $cookie_expire ) ) { return false; } else { return true; } } else { return true; } } else { return false; } } /** * Check user can vote by user IP * * @return bool */ public function poll_votes_method_user_ip() { $settings = $this->settings; $user_ip = Forminator_Geo::get_user_ip(); if ( $this->is_allow_multiple_votes() ) { if ( isset( $settings['vote_limit_input'] ) ) { $duration = is_numeric( $settings['vote_limit_input'] ) ? $settings['vote_limit_input'] : 0; $vote_limit_options = isset( $settings['vote_limit_options'] ) ? $settings['vote_limit_options'] : 'm'; switch ( $vote_limit_options ) { case 'h': $interval = "INTERVAL $duration HOUR"; break; case 'd': $interval = "INTERVAL $duration DAY"; break; case 'W': $interval = "INTERVAL $duration WEEK"; break; case 'M': $interval = "INTERVAL $duration MONTH"; break; case 'Y': $interval = "INTERVAL $duration YEAR"; break; default: $interval = "INTERVAL $duration MINUTE"; break; } $last_entry = Forminator_Form_Entry_Model::get_last_entry_by_ip_and_form( $this->id, $user_ip ); if ( $last_entry ) { $can_vote = Forminator_Form_Entry_Model::check_entry_date_by_ip_and_form( $this->id, $user_ip, $last_entry, $interval ); if ( $can_vote ) { return true; } else { return false; } } else { return true; } } else { return true; } } else { $last_entry = Forminator_Form_Entry_Model::get_last_entry_by_ip_and_form( $this->id, $user_ip ); if ( $last_entry ) { return false; } } return true; } /** * Overridden load function to check element_id of answers for older poll * Backward compat for <= 1.0.4 * which is forminator poll doesnt have element_id on poll answers * * @since 1.0.5 * * @param int $id Id. * @param bool $callback Callback. * * @return bool|Forminator_Poll_Model */ public function load( $id, $callback = false ) { $model = parent::load( $id, $callback ); // callback means load latest post and replace data,. // so we dont need to add element_id since its must be try to loading preview. if ( ! $callback ) { if ( $model instanceof Forminator_Poll_Model ) { // patch for backward compat. return $this->maybe_add_element_id_on_answers( $model ); } } return $model; } /** * Add Element id on answers that doesnt have it * * @since 1.0.5 * * @param Forminator_Poll_Model $model Poll model. * * @return Forminator_Poll_Model */ private function maybe_add_element_id_on_answers( Forminator_Poll_Model $model ) { $answers = $model->get_fields_as_array(); $is_need_to_add_element_id = false; foreach ( $answers as $key => $answer ) { if ( ! isset( $answer['element_id'] ) || ! $answer['element_id'] ) { $is_need_to_add_element_id = true; break; } } if ( $is_need_to_add_element_id ) { // get max element id here. $max_element_id = 0; foreach ( $answers as $answer ) { if ( isset( $answer['element_id'] ) && $answer['element_id'] ) { $element_id = trim( str_replace( 'answer-', '', $answer['element_id'] ) ); if ( $element_id > $max_element_id ) { $max_element_id = $element_id; } } } foreach ( $answers as $key => $answer ) { if ( ! isset( $answer['element_id'] ) || ! $answer['element_id'] ) { ++$max_element_id; $answers[ $key ]['element_id'] = 'answer-' . $max_element_id; // start from 1. $answers[ $key ]['id'] = 'answer-' . $max_element_id; // start from 1. } } $model->clear_fields(); foreach ( $answers as $answer ) { $field = new Forminator_Form_Field_Model(); $field->form_id = $model->id; $field->slug = $answer['id']; unset( $answer['id'] ); $field->import( $answer ); $model->add_field( $field ); } return $this->resave_and_reload( $model ); } return $model; } /** * Resave model and then load to return new model * * @since 1.0.5 * * @param Forminator_Poll_Model $model Poll model. * * @return Forminator_Poll_Model */ private function resave_and_reload( Forminator_Poll_Model $model ) { $model->save(); return $model; } /** * Get Fields as array with `$key` as key of array and `$pluck_key` as $value with `$default` as fallback * * @since 1.0.5 * * @param string $pluck_key Pluck key. * @param string|null $key Key. * @param null $default_value Default value. * * @return array */ public function pluck_fields_array( $pluck_key, $key = null, $default_value = null ) { $fields_with_key = array(); $fields = $this->get_fields_as_array(); foreach ( $fields as $field ) { if ( '*' === $pluck_key ) { $field_value = $field; } elseif ( isset( $field[ $pluck_key ] ) ) { $field_value = $field[ $pluck_key ]; } else { $field_value = $default_value; } if ( ! is_null( $key ) ) { if ( isset( $field[ $key ] ) ) { $fields_with_key[ $field[ $key ] ] = $field_value; } else { $fields_with_key[] = $field_value; } } else { $fields_with_key[] = $field_value; } } return $fields_with_key; } /** * Get enable limit votes status flag * * @since 1.6.1 * @return bool */ public function is_allow_multiple_votes() { $settings = $this->settings; $poll_id = $this->id; $allow_multiple_votes = isset( $settings['enable-votes-limit'] ) ? filter_var( $settings['enable-votes-limit'], FILTER_VALIDATE_BOOLEAN ) : false; /** * Filter allow_multiple_votes flag of a poll * * @since 1.6.1 * * @param bool $allow_multiple_votes * @param int $poll_id * @param array $settings */ $allow_multiple_votes = apply_filters( 'forminator_poll_allow_multiple_votes', $allow_multiple_votes, $poll_id, $settings ); return $allow_multiple_votes; } /** * Get Browser votes method enable status flag * * @since 1.7 * * @return bool */ public function is_method_browser_cookie() { $settings = $this->settings; $poll_id = $this->id; $browser_method = isset( $settings['enable-votes-method'] ) && 'browser_cookie' === $settings['enable-votes-method'] ? true : false; /** * Filter browser_method flag of a poll * * @since 1.7 * * @param bool $browser_method * @param int $poll_id * @param array $settings */ $browser_method = apply_filters( 'forminator_poll_method_browser_cookie', $browser_method, $poll_id, $settings ); return $browser_method; } /** * Check vote opening status * * @return array */ public function opening_status() { static $info = array(); if ( isset( $info[ $this->id ] ) ) { return $info[ $this->id ]; } $settings = $this->settings; $info[ $this->id ] = array( 'status' => 'open', 'msg' => '', ); $close_msg = ( isset( $settings['opening_close_msg'] ) ) ? trim( $settings['opening_close_msg'] ) : ''; if ( '' === $close_msg ) { $close_msg = esc_html__( 'Voting is closed', 'forminator' ); } $pause_msg = ( isset( $settings['opening_pause_msg'] ) ) ? trim( $settings['opening_pause_msg'] ) : ''; if ( '' === $pause_msg ) { $pause_msg = esc_html__( 'Voting is paused, check again later', 'forminator' ); } $before_open_from_msg = ( isset( $settings['opening_before_open_from_msg'] ) ) ? trim( $settings['opening_before_open_from_msg'] ) : ''; if ( '' === $before_open_from_msg ) { $before_open_from_msg = esc_html__( 'Voting has not been started yet, check again later', 'forminator' ); } $status = ( isset( $settings['opening_status'] ) ) ? $settings['opening_status'] : 'open'; if ( ! in_array( $status, array( 'open', 'pause', 'close' ), true ) ) { $status = 'open'; } $info[ $this->id ]['status'] = $status; switch ( $status ) { case 'close': $info[ $this->id ]['msg'] = $close_msg; break; case 'pause': $info[ $this->id ]['msg'] = $pause_msg; break; case 'open': $current_time = current_time( 'timestamp' ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested -- We are using the current timestamp based on the site's timezone. // check open from and open until time. $open_from = ( isset( $settings['opening_open_from'] ) ) ? trim( $settings['opening_open_from'] ) : 'now'; if ( '' === $open_from ) { $open_from = 'now'; } $open_until = ( isset( $settings['opening_open_until'] ) ) ? trim( $settings['opening_open_until'] ) : 'forever'; if ( '' === $open_until ) { $open_until = 'forever'; } if ( 'now' !== $open_from ) { $open_from_time = ( isset( $settings['opening_open_from_date_time'] ) ) ? trim( $settings['opening_open_from_date_time'] ) : ''; if ( '' !== $open_from_time ) { $open_from_timestamp = strtotime( $open_from_time ); if ( $current_time < $open_from_timestamp ) { $info[ $this->id ]['status'] = 'before_open_from'; $info[ $this->id ]['msg'] = $before_open_from_msg; return $info[ $this->id ]; } } } if ( 'forever' !== $open_until ) { $open_until_time = ( isset( $settings['opening_open_until_date_time'] ) ) ? trim( $settings['opening_open_until_date_time'] ) : ''; if ( '' !== $open_until_time ) { $open_until_timestamp = strtotime( $open_until_time ); if ( $current_time > $open_until_timestamp ) { $info[ $this->id ]['status'] = 'close'; $info[ $this->id ]['msg'] = $close_msg; return $info[ $this->id ]; } } } break; default: break; } return $info[ $this->id ]; } } class-quiz-form-model.php 0000644 00000024111 15162406305 0011410 0 ustar 00 <?php /** * The Forminator_Quiz_Model class. * * @package Forminator */ if ( ! defined( 'ABSPATH' ) ) { die(); } /** * Author: Hoang Ngo */ class Forminator_Quiz_Model extends Forminator_Base_Form_Model { /** * Module slug * * @var string */ public static $module_slug = 'quiz'; /** * Post type * * @var string */ protected $post_type = 'forminator_quizzes'; /** * Results * * @var array */ public $results = array(); /** * Questions * * @var array */ public $questions = array(); /** * Quiz type * * @var string */ public $quiz_type = ''; /** * Get maps * * @since 1.0 * @return array */ public function get_maps() { return array( array( 'type' => 'meta', 'property' => 'questions', 'field' => 'questions', ), array( 'type' => 'meta', 'property' => 'results', 'field' => 'results', ), array( 'type' => 'meta', 'property' => 'quiz_type', 'field' => 'quiz_type', ), ); } /** * Get right answer for question * * @since 1.0 * * @param string $slug Slug. * * @return array|bool */ public function getRightAnswerForQuestion( $slug ) { if ( ! empty( $this->questions ) ) { foreach ( $this->questions as $question ) { if ( $question['slug'] === $slug ) { $answers = $question['answers']; $picked = null; $index = - 1; foreach ( $answers as $k => $answer ) { if ( isset( $answer['toggle'] ) && filter_var( $answer['toggle'], FILTER_VALIDATE_BOOLEAN ) === true ) { $picked = $answer; $index = $k; break; } } return array( $index, $picked ); } } } return array( false, false ); } /** * Return questions * * @since 1.0 * * @param string $slug Slug. * * @return mixed */ public function getQuestion( $slug ) { if ( ! empty( $this->questions ) ) { foreach ( $this->questions as $question ) { if ( $question['slug'] === $slug ) { return $question; } } } return false; } /** * Return answer * * @since 1.0 * * @param string $slug Slug. * @param string $index Index. * * @return bool */ public function getAnswer( $slug, $index ) { if ( ! empty( $this->questions ) ) { foreach ( $this->questions as $question ) { if ( $question['slug'] === $slug ) { $answers = $question['answers']; return $answers[ $index ]; } } } return false; } /** * Get result from answer * * @since 1.0 * * @param string $slug Slug. * @param string $index Index. * * @return mixed */ public function getResultFromAnswer( $slug, $index ) { $this->getAnswer( $slug, $index ); $answer = $this->getAnswer( $slug, $index ); if ( isset( $answer['result'] ) ) { return $answer['result']; } return false; } /** * Get priority * * @since 1.0 * @since 1.3 use results instead of non existent value of priority_order * @return mixed */ public function getPriority() { foreach ( $this->results as $result ) { if ( isset( $result['order'] ) && isset( $result['slug'] ) && 0 === (int) $result['order'] ) { return $result['slug']; } } return false; } /** * Return results * * @since 1.0 * @return array */ public function getResults() { $results = array(); if ( empty( $this->results ) ) { return $results; } foreach ( $this->results as $slug => $result ) { $results[] = $result; } return $results; } /** * Get result * * @since 1.0 * * @param string $slug Slug. * * @return mixed|null */ public function getResult( $slug ) { if ( ! empty( $this->results ) ) { foreach ( $this->results as $result ) { if ( $result['slug'] === $slug ) { return $result; } } } return null; } /** * Prepare data for preview * * @param object $form_model Model. * @param array $data Passed data. * * @return object */ public static function prepare_data_for_preview( $form_model, $data ) { if ( isset( $data['type'] ) ) { $form_model->quiz_type = $data['type']; } // build the field. $questions = array(); if ( isset( $data['questions'] ) ) { $questions = $data['questions']; unset( $data['questions'] ); } $form_model->questions = $questions; return $form_model; } /** * Export integrations setting * * @param array $exportable_data Exportable data. * @return array */ public function export_integrations_data( $exportable_data ) { return $exportable_data; } /** * Import Integrations data model * * @since 1.4 * * @param mixed $model Model. * @param array $import_data Import data. * @param string $module Module. * * @return Forminator_Base_Form_Model */ public static function import_integrations_data( $model, $import_data, $module ) { return $model; } /** * Get result of nowrong quiz * * @since 1.6.1 * * @param array $answer_results Answer results. * * @return array contains `title`, `order`, `slug` if found, return empty array otherwise */ public function get_nowrong_result( $answer_results ) { /** * $answer_results FORMAT : * { * 'result-id-1' => `COUNT`, * 'result-id-2' => `COUNT`, * } */ // picking top results. // sort by value since, count is on value,. // do reverse sort, to get bigger value on top. arsort( $answer_results ); $top_results = array(); $top_count = 0; foreach ( $answer_results as $result_id => $count ) { // FIRST item always have BIGGEST count, means its prioritized. if ( empty( $top_results ) ) { $top_results[] = $result_id; $top_count = $count; } else { // already in the pool. if ( in_array( $result_id, $top_results, true ) ) { continue; } // same $top_count found, means the this should be considered too! if ( $count === $top_count ) { $top_results[] = $result_id; } else { // if count not same as $top_count, this item onwards can safely ignored. // since it will always be less than BIGGEST count. break; } } } // somehow top results is empty,. // we might got bad $answer_results. if ( empty( $top_results ) ) { return array(); } // default top_result is first on the pool. $top_result_id = $top_results[0]; $top_result = $this->getResult( $top_result_id ); // somehow the result could not be found, odin forbid. if ( is_null( $top_result ) ) { return array(); } // God knows why `order` could not be found,. // but we might as well set it as 0 so it will get top priority. // remember smaller `order` value means it gets more prioritized. $top_priority = isset( $top_result['order'] ) ? (int) $top_result['order'] : 0; // > (more than) 1 result happening. if ( count( $top_results ) > 1 ) { foreach ( $top_results as $top_result_id ) { $top_result_to_compare = $this->getResult( $top_result_id ); if ( is_null( $top_result_to_compare ) ) { continue; } if ( ! isset( $top_result_to_compare['order'] ) ) { continue; } $top_priority_to_compare = (int) $top_result_to_compare['order']; // remember smaller `order` value means it gets more prioritized. if ( $top_priority_to_compare < $top_priority ) { $top_result = $top_result_to_compare; $top_priority = $top_priority_to_compare; } } } return $top_result; } /** * Check whether answer is correct for a question on Knowledge Quiz * * @since 1.6.2 * * @param string $slug question slug. * @param int $answer_index answer index. * * @return bool */ public function is_correct_answer_for_question( $slug, $answer_index ) { if ( ! empty( $this->questions ) ) { foreach ( $this->questions as $question ) { if ( isset( $question['slug'] ) && $question['slug'] === $slug ) { $answers = $question['answers']; foreach ( $answers as $k => $answer ) { if ( isset( $answer['toggle'] ) && filter_var( $answer['toggle'], FILTER_VALIDATE_BOOLEAN ) === true ) { if ( (int) $answer_index === (int) $k ) { return true; } } } } } } return false; } /** * Find Correct Answers for a question on knowledge quiz * * @since 1.6.2 * * @param string $slug question slug. * * @return array */ public function get_correct_answers_for_question( $slug ) { $correct_answers = array(); if ( ! empty( $this->questions ) ) { foreach ( $this->questions as $question ) { if ( isset( $question['slug'] ) && $question['slug'] === $slug ) { $answers = $question['answers']; foreach ( $answers as $k => $answer ) { if ( isset( $answer['toggle'] ) && filter_var( $answer['toggle'], FILTER_VALIDATE_BOOLEAN ) === true ) { $answer['id'] = $k; $correct_answers[] = $answer; } } } } } return $correct_answers; } /** * Check whether entry share-able * * @since 1.7 * @return bool */ public function is_entry_share_enabled() { $quiz_id = (int) $this->id; $quiz_settings = $this->settings; $global_enabled = parent::is_entry_share_enabled(); $enabled = isset( $quiz_settings['enable-share'] ) ? $quiz_settings['enable-share'] : false; $enabled = filter_var( $enabled, FILTER_VALIDATE_BOOLEAN ); $enabled = $global_enabled || $enabled; /** * Filter is entry share enabled for Quiz * * @since 1.7 * * @param bool $enabled * @param bool $global_enabled * @param int $quiz_id * @param array $form_settings * * @return bool */ $enabled = apply_filters( 'forminator_quiz_is_result_share_enabled', $enabled, $global_enabled, $quiz_id, $quiz_settings ); return $enabled; } /** * Get the count of answered questions for multi-answer questions * * @param array $questions Questions. * @param array $user_answers User answers. * * @return int */ public function count_answered_questions( $questions, $user_answers ) { $answered_questions = 0; foreach ( $questions as $key => $val ) { foreach ( $user_answers as $a_key => $a_val ) { if ( false !== strpos( $a_key, $val['slug'] ) ) { ++$answered_questions; break; } } } return $answered_questions; } } class-base-form-model.php 0000644 00000134174 15162406305 0011345 0 ustar 00 <?php /** * The Forminator_Base_Form_Model class. * * @package Forminator */ if ( ! defined( 'ABSPATH' ) ) { die(); } /** * Author: Hoang Ngo * * @property string $status */ abstract class Forminator_Base_Form_Model { const META_KEY = 'forminator_form_meta'; /** * Form ID * * @var int */ public $id; /** * Form name * * @var string */ public $name; /** * Client Id * * @var string */ public $client_id; /** * Status * * @var string */ public $status; /** * Contain fields of this form * * @var Forminator_Form_Field_Model[] */ public $fields = array(); /** * Contain real fields of this form excluding 'html', 'page-break', 'section' and so on. * * @var Forminator_Form_Field_Model[] */ private $real_fields; /** * Form settings * * @var array */ public $settings = array(); /** * Form notification * * @var array */ public $notifications = array(); /** * Form behaviors * * @var array */ public $behaviors = array(); /** * Integration Conditions * * @var array */ public $integration_conditions = array(); /** * WP_Post * * @var WP_Post */ public $raw; /** * This post type * * @var string */ protected $post_type; const STATUS_PUBLISH = 'publish'; const STATUS_DRAFT = 'draft'; /** * Save form * * @param bool $clone_form Clone. * * @return mixed * @since 1.0 */ public function save( $clone_form = false ) { // todo use save_post for saving the form and update_post_meta for saving fields. // prepare the data. $maps = array_merge( $this->get_default_maps(), $this->get_maps() ); $post_data = array(); $meta_data = array(); if ( ! empty( $maps ) ) { foreach ( $maps as $map ) { $attribute = $map['property']; if ( 'post' === $map['type'] ) { if ( isset( $this->{$attribute} ) ) { $post_data[ $map['field'] ] = $this->{$attribute}; } elseif ( isset( $map['default'] ) ) { $post_data[ $map['field'] ] = $map['default']; } } elseif ( 'fields' === $map['field'] ) { $meta_data[ $map['field'] ] = $this->get_fields_as_array(); } else { $meta_data[ $map['field'] ] = $this->{$attribute}; } } } $validate = forminator_validate_registration_form_settings( $meta_data['settings'] ); if ( is_wp_error( $validate ) ) { return $validate; } $post_data['post_type'] = $this->post_type; // storing. if ( is_null( $this->id ) ) { $id = wp_insert_post( $post_data ); } else { $id = wp_update_post( $post_data ); } // If cloned we have to update the fromID. if ( $clone_form ) { $meta_data['settings']['form_id'] = $id; } update_post_meta( $id, self::META_KEY, $meta_data ); return $id; } /** * Get fields * * @return Forminator_Form_Field_Model[] * @since 1.0 */ public function get_fields() { return $this->fields; } /** * Get real fields - all fields except ignored ones * * @return Forminator_Form_Field_Model[] */ public function get_real_fields() { if ( is_null( $this->real_fields ) ) { $fields = $this->fields; $ignored_field_types = Forminator_Form_Entry_Model::ignored_fields(); foreach ( $fields as $field_index => $field ) { $field_array = $field->to_formatted_array(); if ( empty( $field_array['type'] ) ) { continue; } if ( in_array( $field_array['type'], $ignored_field_types, true ) ) { unset( $fields[ $field_index ] ); } } $this->real_fields = $fields; } return $this->real_fields; } /** * Get filtered fields by group. If group ID is empty - it returns ungrouped fields * * @param string $group_id Group ID. * @return array */ public function get_grouped_real_fields( $group_id = '' ) { $real_fields = $this->get_real_fields(); $fields = array_filter( $real_fields, function ( $value ) use ( $group_id ) { return ! $group_id ? empty( $value->parent_group ) : $group_id === $value->parent_group; } ); return $fields; } /** * Get filtered fields by group. If group ID is empty - it returns ungrouped fields * * @param string $group_id Group ID. * @return array */ public function get_grouped_fields( $group_id = '' ) { $fields = $this->get_fields(); $grouped_fields = array_filter( $fields, function ( $value ) use ( $group_id ) { return ! $group_id ? empty( $value->parent_group ) : $group_id === $value->parent_group; } ); return $grouped_fields; } /** * Get fields IDs of filtered fields by group * * @param string $group_id Group ID. * @return array */ public function get_grouped_fields_slugs( $group_id ) { $grouped_fields = $this->get_grouped_fields( $group_id ); $field_slugs = wp_list_pluck( $grouped_fields, 'slug' ); return $field_slugs; } /** * Set var in array * * @param string $property Property. * @param string $name Name. * @param string $array_values Array values. * @param string $sanitize_function custom sanitize function to use, default is sanitize_title. * * @since 1.0 * @since 1.2 Add $sanitize_function as optional param */ public function set_var_in_array( $property, $name, $array_values, $sanitize_function = 'sanitize_title' ) { $val = isset( $array_values[ $name ] ) ? $array_values[ $name ] : null; if ( is_callable( $sanitize_function ) ) { $val = call_user_func_array( $sanitize_function, array( $val ) ); } $this->$property = $val; } /** * Add field * * @param mixed $field Field. * * @since 1.0 */ public function add_field( $field ) { $this->fields[] = $field; } /** * Get field * * @param string $slug Slug. * * @return Forminator_Form_Field|null * @since 1.0 */ public function get_field( $slug ) { // get a field and return as object. return isset( $this->fields[ $slug ] ) ? $this->fields[ $slug ] : null; } /** * Remove field * * @param string $slug Slug. * * @since 1.0 */ public function remove_field( $slug ) { unset( $this->fields[ $slug ] ); } /** * Clear fields * * @since 1.0 */ public function clear_fields() { $this->fields = array(); } /** * Load model * * @param int $id Id. * @param mixed $callback Callback function. * * @return bool|$this * @since 1.0 */ public function load( $id, $callback = false ) { $post = get_post( $id ); if ( ! is_object( $post ) ) { // If we haven't saved yet, fallback to latest ID and replace the data. if ( $callback ) { $id = $this->get_latest_id(); $post = get_post( $id ); if ( ! is_object( $post ) ) { return false; } } else { return false; } } return $this->_load( $post ); } /** * Load preview * * @param int $id Id. * @param array $data Data for preview. * * @return bool|Forminator_Base_Form_Model * @since 1.0 */ public function load_preview( $id, $data ) { $form_model = $this->load( $id, true ); // If bool, abort. if ( is_bool( $form_model ) ) { return false; } $form_model->clear_fields(); $form_model->set_var_in_array( 'name', 'formName', $data ); // build the settings. if ( isset( $data['settings'] ) ) { $settings = $data['settings']; $form_model->settings = $settings; } $form_model = static::prepare_data_for_preview( $form_model, $data ); return $form_model; } /** * Get relevant module object based on its ID. * * @param int $id Module ID. * * @return boolean|object */ public static function get_model( $id ) { $class = self::get_model_class( $id ); if ( $class ) { $model = $class::model()->load( $id ); return $model; } return false; } /** * Get module class by module ID * * @param int $id Module ID. * * @return boolean|string */ public static function get_model_class( $id ) { $post_type = get_post_type( $id ); switch ( $post_type ) { case 'forminator_forms': $class = 'Forminator_Form_Model'; break; case 'forminator_polls': $class = 'Forminator_Poll_Model'; break; case 'forminator_quizzes': $class = 'Forminator_Quiz_Model'; break; default: return false; } return $class; } /** * Return latest id for the post_type * * @return int * @since 1.0 */ public function get_latest_id() { $id = 1; $args = array( 'post_type' => $this->post_type, 'numberposts' => 1, 'fields' => 'ids', ); $post = get_posts( $args ); if ( isset( $post[0] ) ) { $id = $post[0]; } return $id; } /** * Count all form types * * @param string $status Status. * * @return int * @since 1.0 * @since 1.6 add optional param `status` */ public function count_all( $status = '' ) { $count_posts = wp_count_posts( $this->post_type ); $count_posts = (array) $count_posts; if ( ! empty( $status ) ) { if ( isset( $count_posts[ $status ] ) ) { return $count_posts[ $status ]; } else { return 0; } } elseif ( 'forminator_forms' === $this->post_type ) { unset( $count_posts['leads'] ); unset( $count_posts['pdf_form'] ); } return array_sum( $count_posts ); } /** * Get entry type * * @return string */ public function get_entry_type() { $post_type = $this->get_post_type(); switch ( $post_type ) { case 'forminator_forms': $entry_type = 'custom-forms'; break; case 'forminator_polls': $entry_type = 'polls'; break; case 'forminator_quizzes': $entry_type = 'quizzes'; break; default: $entry_type = ''; break; } return $entry_type; } /** * Get all paginated * * @param int $current_page Current page. * @param null|int $per_page Limit per page. * @param string $status Status. * @param null|int $pdf_parent_id PDF parent Id. * * @return array * @since 1.5.4 add optional param per_page * @since 1.5.4 add optional param $status * * @since 1.2 */ public function get_all_paged( $current_page = 1, $per_page = null, $status = '', $pdf_parent_id = null ) { if ( is_null( $per_page ) ) { $per_page = forminator_form_view_per_page(); } $args = array( 'post_type' => $this->post_type, 'post_status' => 'any', 'posts_per_page' => $per_page, 'paged' => $current_page, ); if ( ! empty( $status ) ) { $args['post_status'] = $status; } if ( 'forminator_forms' === $this->post_type ) { if ( 'pdf_form' === $status ) { $args['meta_key'] = 'forminator_form_meta'; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key $args['meta_value'] = '("parent_form_id";s:[0-9]+:"' . $pdf_parent_id . '";)'; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value $args['meta_compare'] = 'REGEXP'; } else { $args['meta_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query array( 'key' => 'forminator_form_meta', 'value' => 'form-type";s:5:"leads"', 'compare' => 'NOT LIKE', ), array( 'key' => 'forminator_form_meta', 'value' => '"form-type";s:[0-9]+:"pdf-form"', 'compare' => 'NOT REGEXP', ), ); } } $query = new WP_Query( $args ); $models = array(); foreach ( $query->posts as $post ) { $models[] = $this->_load( $post ); } return array( 'totalPages' => $query->max_num_pages, 'totalRecords' => $query->post_count, 'models' => $models, ); } /** * Get all * * @param string $status post_status arg. * @param int $limit Limit. * * @return array() * @since 1.0 * @since 1.6 add `status` in param * @since 1.6 add `limit` in param */ public function get_all_models( $status = '', $limit = - 1 ) { $args = array( 'post_type' => $this->post_type, 'post_status' => 'any', 'posts_per_page' => $limit, ); if ( ! empty( $status ) ) { $args['post_status'] = $status; } $query = new WP_Query( $args ); $models = array(); foreach ( $query->posts as $post ) { $models[] = $this->_load( $post ); } return array( 'totalPages' => $query->max_num_pages, 'totalRecords' => $query->post_count, 'models' => $models, ); } /** * Get 3 models with old stripe field * * @return array */ public function get_models_with_old_stripe() { $max_title_length = 50; $models = array(); $data = $this->get_models( 99, 'publish' ); foreach ( $data as $model ) { if ( $model->get_field( 'stripe-1' ) && ! $model->get_field( 'stripe-ocs-1' ) ) { $title = $model->settings['formName'] ?? "Form #{$model->id}"; $title = mb_strlen( $title ) > $max_title_length ? mb_substr( $title, 0, $max_title_length ) . '...' : $title; $models[] = array( 'id' => $model->id, 'title' => $title, ); } // Return only 3 forms. if ( 3 === count( $models ) ) { break; } } return $models; } /** * Get modules from field * * @param int $id Id. * * @return array * @since 1.9 */ public function get_models_by_field( $id ) { $modules = array(); $data = $this->get_models( 999 ); foreach ( $data as $model ) { if ( $model->get_field( $id ) ) { $modules[] = array( 'id' => $model->id, 'title' => $model->name, 'version' => $model->version, ); } } return $modules; } /** * Get modules from field id & version * * @param int $id Id. * @param string $version Version. * * @return array * @since 1.9 */ public function get_models_by_field_and_version( $id, $version ) { $modules = array(); $data = $this->get_models( 999 ); foreach ( array_filter( $data ) as $model ) { if ( $model->get_field( $id ) && version_compare( $model->settings['version'], $version, 'lt' ) ) { $modules[] = array( 'id' => $model->id, 'title' => $model->name, 'version' => $model->settings['version'], ); } } return $modules; } /** * Get Models * * @param int $total - the total. Defaults to 4. * @param string $status Status. * * @return array $models * @since 1.6 add `status` as optional param * * @since 1.0 */ public function get_models( $total = 4, $status = '' ) { $args = array( 'post_type' => $this->post_type, 'post_status' => 'any', 'posts_per_page' => $total, 'order' => 'DESC', ); if ( ! empty( $status ) ) { $args['post_status'] = $status; } $query = new WP_Query( $args ); $models = array(); foreach ( $query->posts as $post ) { $models[] = $this->_load( $post ); } return $models; } /** * Load form * * @param WP_Post $post Post. * * @return mixed * @since 1.0 */ private function _load( $post ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore if ( $this->post_type === $post->post_type ) { $class = get_class( $this ); $object = new $class(); $meta = get_post_meta( $post->ID, self::META_KEY, true ); $fields = ! empty( $meta['fields'] ) ? $meta['fields'] : array(); $form_settings = array( 'version' => '1.0', 'cform-section-border-color' => '#E9E9E9', ); if ( $fields ) { $meta['fields'] = static::disable_fields( $fields ); } $maps = array_merge( $this->get_default_maps(), $this->get_maps() ); // Update version from form settings. if ( isset( $meta['settings']['version'] ) ) { $form_settings['version'] = $meta['settings']['version']; } // Update section border color. if ( isset( $meta['settings']['cform-section-border-color'] ) ) { $form_settings['cform-section-border-color'] = $meta['settings']['cform-section-border-color']; } // Decode HTML entities. $decode_html_keys = array( 'notifications', 'behaviors', 'integration_conditions' ); foreach ( $decode_html_keys as $decode_html_key ) { if ( ! empty( $meta[ $decode_html_key ] ) ) { foreach ( $meta[ $decode_html_key ] as $key => $meta_data ) { if ( ! empty( $meta_data['conditions'] ) ) { $meta[ $decode_html_key ][ $key ]['conditions'] = forminator_decode_html_entity( $meta_data['conditions'] ); } if ( 'notifications' === $decode_html_key && ! empty( $meta_data['routing'] ) ) { $meta[ $decode_html_key ][ $key ]['routing'] = forminator_decode_html_entity( $meta_data['routing'] ); } } } } if ( ! empty( $meta['settings']['user_role'] ) ) { $meta['settings']['user_role'] = forminator_decode_html_entity( $meta['settings']['user_role'] ); } if ( ! empty( $maps ) ) { foreach ( $maps as $map ) { $attribute = $map['property']; if ( 'post' === $map['type'] ) { $att = $map['field']; if ( 'pdf_form' === $post->post_status && 'name' === $attribute ) { // To support non-English characters in the file name. $object->{$attribute} = urldecode( $post->{$att} ); } else { $object->{$attribute} = $post->{$att}; } } elseif ( ! empty( $meta['fields'] ) && 'fields' === $map['field'] ) { $meta['fields'] = forminator_decode_html_entity( $meta['fields'] ); $password_count = 0; foreach ( $meta['fields'] as $field_data ) { // Prevent creating empty wrappers. if ( isset( $field_data['type'] ) ) { if ( 'honeypot' === $field_data['type'] ) { continue; } if ( 'password' === $field_data['type'] ) { if ( $password_count >= 1 ) { continue; } else { ++$password_count; } } } $field = new Forminator_Form_Field_Model( $form_settings ); $field->form_id = $post->ID; $field->slug = $field_data['id']; unset( $field_data['id'] ); $field->import( $field_data ); $object->add_field( $field ); } } elseif ( isset( $meta[ $map['field'] ] ) ) { $object->{$attribute} = $meta[ $map['field'] ]; } } } $form_settings = $object->settings; if ( is_array( $form_settings ) && ! isset( $form_settings['form_id'] ) ) { $form_settings['form_id'] = $object->id; } // Migrate settings Custom Form. if ( 'forminator_forms' === $this->post_type ) { $form_settings = self::validate_registration_fields_mapping( $form_settings, $fields ); $object->settings = Forminator_Migration::migrate_custom_form_settings( $form_settings, $fields ); $object->notifications = Forminator_Migration::migrate_custom_form_notifications( $object->notifications, $form_settings, $meta ); } // Migrate settings Polls. if ( 'forminator_polls' === $this->post_type ) { $object->settings = Forminator_Migration::migrate_polls_settings( $form_settings ); } // Migrate settings Polls. if ( 'forminator_quizzes' === $this->post_type ) { $object->settings = Forminator_Migration::migrate_quizzes_settings( $form_settings ); $object->notifications = Forminator_Migration::migrate_quizzes_notifications( $object->notifications, $form_settings, $meta ); } $object->raw = $post; return $object; } return false; } /** * Disable fields * * @param array $fields Fields. * @return array */ protected static function disable_fields( $fields ) { return $fields; } /** * Validate registration fields mapping for Registration forms * If the field is removed - replace it to the first field in the list * * @param array $form_settings Form settings. * @param array $fields Form fields. * * @return array */ private static function validate_registration_fields_mapping( $form_settings, $fields ) { $field_ids = wp_list_pluck( $fields, 'id' ); if ( ! empty( $form_settings['form-type'] ) && 'registration' === $form_settings['form-type'] && ! empty( $field_ids ) ) { // Get first field id (not password). $i = 0; do { $first_id = isset( $field_ids[ $i ] ) ? $field_ids[ $i ] : null; ++$i; $is_password = false !== strpos( $first_id, 'password' ); $go_next = empty( $first_id ) || $is_password; } while ( $go_next ); foreach ( $form_settings as $key => $value ) { if ( ! is_string( $value ) ) { continue; } $value_parts = explode( '-', $value ); if ( ! $first_id || 'registration-' !== substr( $key, 0, 13 ) || '-field' !== substr( $key, - 6 ) || 'registration-role-field' === $key || in_array( $value, $field_ids, true ) // for multiple fields like name, address. || ( 2 < count( $value_parts ) && in_array( $value_parts[0] . '-' . $value_parts[1], $field_ids, true ) ) ) { continue; } if ( 'registration-password-field' === $key ) { $form_settings[ $key ] = 'auto'; } else { $form_settings[ $key ] = $first_id; } } } return $form_settings; } /** * Return fields as array * * @return array * @since 1.0 */ public function get_fields_as_array() { $arr = array(); if ( empty( $this->fields ) ) { return $arr; } foreach ( $this->fields as $field ) { $arr[] = $field->to_array(); } return $arr; } /** * Return fields grouped * * @return array * @since 1.0 */ public function get_fields_grouped() { $wrappers = array(); if ( empty( $this->fields ) ) { return $wrappers; } foreach ( $this->fields as $field ) { /** * Forminator_Form_Field_Model * * @var Forminator_Form_Field_Model $field */ if ( strpos( $field->form_id, 'wrapper-' ) === 0 ) { $form_id = $field->form_id; } else { // Backward Compat. $form_id = $field->formID; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase } if ( ! isset( $wrappers[ $form_id ] ) ) { $wrappers[ $form_id ] = array( 'wrapper_id' => $form_id, ); } $field_data = $field->to_formatted_array(); $field_data = $this->migrate_payments( $field_data ); $wrappers[ $form_id ]['parent_group'] = ! empty( $field->parent_group ) ? $field->parent_group : ''; $wrappers[ $form_id ]['fields'][] = $field_data; } $wrappers = array_values( $wrappers ); return $wrappers; } /** * Migrate payment fields to new behavior with multi payments * * @param array $field Field. * * @return array * @since 1.15 */ private function migrate_payments( $field ) { if ( ! isset( $field['type'] ) || ( 'stripe' !== $field['type'] && 'stripe-ocs' !== $field['type'] ) ) { return $field; } if ( ! isset( $field['payments'] ) ) { $type = isset( $field['amount_type'] ) ? $field['amount_type'] : 'fixed'; $amount = isset( $field['amount'] ) ? $field['amount'] : 0; $variable = isset( $field['variable'] ) ? $field['variable'] : ''; $field['payments'][] = array( 'plan_name' => 'Plan 1', 'payment_method' => 'single', 'amount_type' => $type, 'amount' => $amount, 'variable' => $variable, ); } return $field; } /** * Model to array * * @return array * @since 1.0 */ public function to_array() { $data = array(); $maps = array_merge( $this->get_default_maps(), $this->get_maps() ); if ( empty( $maps ) ) { return $data; } foreach ( $maps as $map ) { $property = $map['property']; $data[ $property ] = $this->$property; } return $data; } /** * Model to json * * @return mixed|string * @since 1.0 */ public function to_json() { $wrappers = array(); if ( ! empty( $this->fields ) ) { foreach ( $this->fields as $field ) { $wrappers[] = $field->to_json(); } } $settings = $this->settings; $notifications = $this->notifications; $data = array_merge( array( 'wrappers' => array( 'fields' => $wrappers, ), ), $settings, $notifications ); $ret = array( 'formName' => $this->name, 'data' => $data, ); return wp_json_encode( $ret ); } /** * In here we will define how we store the properties * * @return array * @since 1.0 */ public function get_default_maps() { return array( array( 'type' => 'post', 'property' => 'id', 'field' => 'ID', ), array( 'type' => 'post', 'property' => 'name', 'field' => 'post_title', ), array( 'type' => 'post', 'property' => 'status', 'field' => 'post_status', 'default' => self::STATUS_PUBLISH, ), array( 'type' => 'meta', 'property' => 'fields', 'field' => 'fields', ), array( 'type' => 'meta', 'property' => 'settings', 'field' => 'settings', ), array( 'type' => 'meta', 'property' => 'client_id', 'field' => 'client_id', ), array( 'type' => 'meta', 'property' => 'integration_conditions', 'field' => 'integration_conditions', ), array( 'type' => 'meta', 'property' => 'behaviors', 'field' => 'behaviors', ), array( 'type' => 'meta', 'property' => 'notifications', 'field' => 'notifications', ), ); } /** * This should be get override by children * * @return array * @since 1.0 */ public function get_maps() { return array(); } /** * Return model * * @param string $class_name Class name. * * @return self * @since 1.0 */ public static function model( $class_name = null ) { if ( is_null( $class_name ) ) { $class_name = static::class; } $class = new $class_name(); return $class; } /** * Get Post Type of cpt * * @return mixed * @since 1.0.5 */ public function get_post_type() { return $this->post_type; } /** * Get export Model * * @return array * @since 1.4 * Override-able, but use of hook `forminator_{$module_type}_model_to_exportable_data` encouraged */ public function to_exportable_data() { if ( ! Forminator::is_import_export_feature_enabled() ) { return array(); } $hook = 'forminator_' . static::$module_slug . '_model_to_exportable_data'; if ( Forminator::is_export_integrations_feature_enabled() ) { add_filter( $hook, array( $this, 'export_integrations_data' ), 1, 1 ); } $model_id = $this->id; $module_type = static::$module_slug; // cleanup form id. $post_meta = get_post_meta( $this->id, self::META_KEY, true ); if ( is_array( $post_meta ) ) { if ( isset( $post_meta['settings'] ) && isset( $post_meta['settings'] ) ) { if ( isset( $post_meta['settings']['form_id'] ) ) { unset( $post_meta['settings']['form_id'] ); } if ( isset( $post_meta['settings']['formID'] ) ) { unset( $post_meta['settings']['formID'] ); } } } $exportable_data = array( 'type' => $module_type, 'data' => $post_meta, 'status' => $this->status, 'version' => FORMINATOR_VERSION, ); $exportable_data = apply_filters( $hook, $exportable_data, $module_type, $model_id ); // avoid filter executed on next cycle. remove_filter( $hook, array( $this, 'export_integrations_data' ), 1 ); return $exportable_data; } /** * Export integrations setting * * @param array $exportable_data Exportable data. * * @return array * @since 1.4 */ public function export_integrations_data( $exportable_data ) { $model_id = $this->id; $exportable_integrations = array(); $connected_addons = forminator_get_addons_instance_connected_with_module( $model_id, static::$module_slug ); foreach ( $connected_addons as $connected_addon ) { try { $settings = $connected_addon->get_addon_settings( $model_id, 'form' ); if ( $settings instanceof Forminator_Integration_Settings ) { $exportable_integrations[ $connected_addon->get_slug() ] = $settings->to_exportable_data(); } } catch ( Exception $e ) { forminator_addon_maybe_log( $connected_addon->get_slug(), 'failed to get to_exportable_data', $e->getMessage() ); } } /** * Filter integrations data to export * * @param array $exportable_integrations * @param array $exportable_data all exportable data from model, useful. * * @since 1.4 */ $exportable_integrations = apply_filters( 'forminator_' . static::$module_slug . '_model_export_integrations_data', $exportable_integrations, $model_id ); $exportable_data['integrations'] = $exportable_integrations; return $exportable_data; } /** * Create model from import data * * @param array $import_data Import data. * @param string $name Form name. * * @return self|Forminator_Form_Model|Forminator_Poll_Model|Forminator_Quiz_Model|WP_Error * @since 1.4 * @throws Exception When there is an error. */ public static function create_from_import_data( $import_data, $name = '' ) { $class = static::class; if ( Forminator::is_import_integrations_feature_enabled() ) { add_filter( 'forminator_import_model', array( $class, 'import_integrations_data' ), 1, 3 ); } try { if ( ! Forminator::is_import_export_feature_enabled() ) { throw new Exception( esc_html__( 'Export Import feature disabled', 'forminator' ) ); } if ( ! is_callable( array( $class, 'model' ) ) ) { throw new Exception( esc_html__( 'Model loader for importer does not exist.', 'forminator' ) ); } // call static method ::model. $model = call_user_func( array( $class, 'model' ) ); /** * Executes before create model from import data * * @param array $import_data * @param string $module * * @since 1.4 */ do_action( 'forminator_before_create_model_from_import_data', $import_data, $class ); if ( empty( $import_data['type'] ) ) { throw new Exception( esc_html__( 'Invalid format of import data type', 'forminator' ) ); } $meta = ( isset( $import_data['data'] ) ? $import_data['data'] : array() ); $meta = self::clear_stripe_plan_ids( $meta ); if ( empty( $meta ) ) { throw new Exception( esc_html__( 'Invalid format of import data', 'forminator' ) ); } if ( empty( $meta['settings'] ) ) { throw new Exception( esc_html__( 'Invalid format of import data settings', 'forminator' ) ); } if ( empty( $meta['settings']['formName'] ) ) { throw new Exception( esc_html__( 'Invalid format of import data name', 'forminator' ) ); } if ( $name ) { $meta['settings']['formName'] = $name; } $form_name = $meta['settings']['formName']; $type = $import_data['type']; switch ( $type ) { case 'quiz': $post_type = 'forminator_quizzes'; break; case 'poll': $post_type = 'forminator_polls'; break; default: $post_type = 'forminator_forms'; break; } $post_status = ( isset( $import_data['status'] ) && ! empty( $import_data['status'] ) ) ? $import_data['status'] : self::STATUS_PUBLISH; /** * Todo : use @see self::save() */ $post_data = array( 'post_title' => $form_name, 'post_type' => $post_type, 'post_status' => $post_status, ); $post_id = wp_insert_post( $post_data, true ); if ( is_wp_error( $post_id ) ) { throw new Exception( $post_id->get_error_message(), $post_id->get_error_code() ); } // update form_id. $meta['settings']['form_id'] = $post_id; $meta['settings']['previous_status'] = 'draft'; update_post_meta( $post_id, self::META_KEY, $meta ); /** * Forminator_Base_Form_Model * * @var Forminator_Base_Form_Model|Forminator_Poll_Model|Forminator_Quiz_Model|Forminator_Form_Model $model */ $model = $model->load( $post_id ); if ( ! $model instanceof $class ) { throw new Exception( esc_html__( 'Failed to load imported Forminator model', 'forminator' ) ); } /** * Action called after module imported * * @param int $post_id - module id. * @param string $post_status - module status. * @param object $model - module model. * @param array $import_data - Import data. * * @since 1.11 * @since 1.32 Added the `$import_data` parameter. */ do_action( 'forminator_' . $type . '_action_imported', $post_id, $post_status, $model, $import_data ); // Call do action after create imported module. self::module_update_do_action( $type, $post_id, $model ); } catch ( Exception $e ) { $code = $e->getCode(); if ( empty( $code ) ) { $code = 'forminator_import_model_error'; } $model = new WP_Error( $code, $e->getMessage(), $import_data ); } /** * Filter imported model of form * * @param Forminator_Base_Form_Model|WP_Error $model * @param array $import_data * @param string $module * * @since 1.4 */ $model = apply_filters( 'forminator_import_model', $model, $import_data, $class ); // avoid filter executed on next cycle. remove_filter( 'forminator_import_model', array( $class, 'import_integrations_data' ), 1 ); return $model; } /** * Clear Stripe plan IDs * * @param array $data Data. * * @return mixed */ public static function clear_stripe_plan_ids( $data ) { if ( isset( $data['fields'] ) ) { $i = 0; foreach ( $data['fields'] as $field ) { if ( isset( $field['type'] ) && ( 'stripe' === $field['type'] || 'stripe-ocs' === $field['type'] ) ) { if ( isset( $field['payments'] ) ) { $x = 0; foreach ( $field['payments'] as $plan ) { if ( ! FORMINATOR_PRO && 'subscription' === $plan['payment_method'] ) { if ( isset( $plan['subscription_amount'] ) ) { $data['fields'][ $i ]['payments'][ $x ]['subscription_amount'] = ''; } if ( isset( $plan['subscription_variable'] ) ) { $data['fields'][ $i ]['payments'][ $x ]['subscription_variable'] = ''; } } $data['fields'][ $i ]['payments'][ $x ]['plan_id'] = ''; $data['fields'][ $i ]['payments'][ $x ]['live_plan_id'] = ''; $data['fields'][ $i ]['payments'][ $x ]['test_plan_id'] = ''; ++$x; } } } ++$i; } } return $data; } /** * Import Integrations data model * * @param mixed $model Model. * @param array $import_data Import data. * @param string $module Module. * * @return Forminator_Base_Form_Model * @since 1.4 */ public static function import_integrations_data( $model, $import_data, $module ) { // return what it is. if ( is_wp_error( $model ) ) { return $model; } if ( static::class !== $module ) { return $model; } if ( ! isset( $import_data['integrations'] ) || empty( $import_data['integrations'] ) || ! is_array( $import_data['integrations'] ) ) { return $model; } $integrations_data = $import_data['integrations']; foreach ( $integrations_data as $slug => $integrations_datum ) { try { $addon = forminator_get_addon( $slug ); if ( $addon instanceof Forminator_Integration ) { $method = 'get_addon_settings'; if ( method_exists( $addon, $method ) ) { $settings = $addon->$method( $model->id, static::$module_slug ); } if ( ! empty( $settings ) && $settings instanceof Forminator_Integration_Form_Settings ) { $settings->import_data( $integrations_datum ); } } } catch ( Exception $e ) { forminator_addon_maybe_log( $slug, 'failed to get import module settings', $e->getMessage() ); } } return $model; } /** * Get status of prevent_store * * @param int $id Id. * @param array $settings Settings. * * @return boolean * @since 1.5 */ public function is_prevent_store( $id = null, $settings = array() ) { $module_id = ! empty( $id ) ? $id : (int) $this->id; $settings = ! empty( $settings ) ? $settings : $this->settings; // default is always store. $store_submissions = true; $store_submissions = isset( $settings['store_submissions'] ) ? $settings['store_submissions'] : $store_submissions; // We have to reverse this because disable store submissions was changed to positive statement since 1.15.12 // from prevent store to store submissions. $is_prevent_store = filter_var( $store_submissions, FILTER_VALIDATE_BOOLEAN ) ? false : true; /** * Filter is_prevent_store flag of the module * * @param bool $is_prevent_store * @param int $module_id * @param array $settings * * @since 1.5 */ $is_prevent_store = apply_filters( 'forminator_' . static::$module_slug . '_is_prevent_store', $is_prevent_store, $module_id, $settings ); return $is_prevent_store; } /** * Flag if module should be loaded via ajax * * @param bool $force Force. * * @return bool * @since 1.6.1 */ public function is_ajax_load( $force = false ) { $module_id = (int) $this->id; $settings = $this->settings; $global_enabled = self::is_global_ajax_load( $force ); $enabled = isset( $settings['use_ajax_load'] ) ? $settings['use_ajax_load'] : false; $enabled = filter_var( $enabled, FILTER_VALIDATE_BOOLEAN ); $enabled = $global_enabled || $enabled; /** * Filter is ajax load for module * * @param bool $enabled * @param bool $global_enabled * @param int $form_id * @param array $form_settings * * @return bool * @since 1.6.1 */ $enabled = apply_filters( 'forminator_' . static::$module_slug . '_is_ajax_load', $enabled, $global_enabled, $module_id, $settings ); return $enabled; } /** * Flag if module should be loaded via ajax (Global settings) * * @param bool $force Force. * * @return bool * @since 1.6.1 */ private static function is_global_ajax_load( $force = false ) { // from constant. $enabled = defined( 'FORMINATOR_MODULE_ENABLE_LOAD_AJAX' ) && FORMINATOR_MODULE_ENABLE_LOAD_AJAX; // if one is true, then its enabled. $enabled = $force || $enabled; /** * Filter flag is ajax load of module * * @param bool $enabled * @param bool $force * * @return bool * @since 1.6 */ $enabled = apply_filters( 'forminator_module_is_ajax_load', $enabled, $force ); return $enabled; } /** * Flag to use `DONOTCACHEPAGE` * * @return bool * @since 1.6.1 */ public function is_use_donotcachepage_constant() { $module_id = (int) $this->id; $settings = $this->settings; $global_enabled = self::is_global_use_donotcachepage_constant(); $enabled = isset( $settings['use_donotcachepage'] ) ? $settings['use_donotcachepage'] : false; $enabled = filter_var( $enabled, FILTER_VALIDATE_BOOLEAN ); $enabled = $global_enabled || $enabled; /** * Filter use `DONOTCACHEPAGE` Module * * @param bool $enabled * @param bool $global_enabled * @param int $module_id * @param array $settings * * @return bool * @since 1.6.1 */ $enabled = apply_filters( 'forminator_custom_form_is_use_donotcachepage_constant', $enabled, $global_enabled, $module_id, $settings ); return $enabled; } /** * Flag to use `DONOTCACHEPAGE` * * @return bool * @since 1.6.1 */ private static function is_global_use_donotcachepage_constant() { // from constant. $enabled = defined( 'FORMINATOR_MODULE_USE_DONOTCACHEPAGE' ) && FORMINATOR_MODULE_USE_DONOTCACHEPAGE; /** * Filter flag is use `DONOTCACHEPAGE` of module * * @param bool $enabled * * @return bool * @since 1.6 */ $enabled = apply_filters( 'forminator_module_is_use_donotcachepage_constant', $enabled ); return $enabled; } /** * Check if the result enable for share * * @return bool * @since 1.7 */ public function is_entry_share_enabled() { $module_id = (int) $this->id; $module_type = $this->post_type; // from settings. $settings_enabled = get_option( 'forminator_module_enable_share_entry', false ); // from constant. $enabled = defined( 'FORMINATOR_MODULE_ENABLE_SHARE_ENTRY' ) && FORMINATOR_MODULE_ENABLE_SHARE_ENTRY; // if one is true, then its enabled. $enabled = $settings_enabled || $enabled; /** * Filter flag is use `ENABLE_SHARE_ENTRY` of module * * @param bool $enabled * @param int $module_id * @param string $module_type * * @return bool * @since 1.7 */ $enabled = apply_filters( 'forminator_module_is_entry_share_enabled', $enabled, $module_id, $module_type ); return $enabled; } /** * Check if we can submit the form * * @since 1.19.0 * @return array */ public function form_can_submit() { $form_settings = $this->settings; $can_show = array( 'can_submit' => true, 'error' => '', ); // Allow module slug to be translated for messages. $module_slug = static::$module_slug; switch ( $module_slug ) { case 'quiz': $module_slug = esc_html__( 'quiz', 'forminator' ); break; case 'poll': $module_slug = esc_html__( 'poll', 'forminator' ); break; default: $module_slug = esc_html__( 'form', 'forminator' ); break; } $only_users = ! empty( $form_settings['logged-users'] ) && filter_var( $form_settings['logged-users'], FILTER_VALIDATE_BOOLEAN ); if ( $only_users && ! is_user_logged_in() ) { $can_show = array( 'can_submit' => false, /* translators: %s: module slug */ 'error' => sprintf( esc_html__( 'Only logged in users can submit this %s.', 'forminator' ), $module_slug ), ); } if ( $only_users && ! empty( $form_settings['limit-per-user'] ) ) { $user_submitted = Forminator_Form_Entry_Model::count_user_entries( $this->id ); if ( $form_settings['limit-per-user'] <= $user_submitted ) { $error = ! empty( $form_settings['limit-per-user-error'] ) ? $form_settings['limit-per-user-error'] : esc_html__( 'You’ve already reached submissions limit.', 'forminator' ); $can_show = array( 'can_submit' => false, 'error' => $error, ); } } if ( $can_show['can_submit'] ) { if ( isset( $form_settings['form-expire'] ) ) { if ( 'submits' === $form_settings['form-expire'] ) { if ( isset( $form_settings['expire_submits'] ) && ! empty( $form_settings['expire_submits'] ) ) { $submits = intval( $form_settings['expire_submits'] ); $total_entries = Forminator_Form_Entry_Model::count_entries( $this->id ); if ( $total_entries >= $submits ) { $can_show = array( 'can_submit' => false, /* translators: %s: module slug */ 'error' => sprintf( esc_html__( 'You have reached the maximum allowed submissions for this %s.', 'forminator' ), $module_slug ), ); } } } elseif ( 'date' === $form_settings['form-expire'] ) { if ( isset( $form_settings['expire_date'] ) && ! empty( $form_settings['expire_date'] ) ) { $expire_date = $this->get_expiry_date( $form_settings['expire_date'] ); $current_date = strtotime( 'now' ); if ( $current_date > $expire_date ) { $can_show = array( 'can_submit' => false, /* translators: %s: module slug */ 'error' => sprintf( esc_html__( 'Unfortunately this %s has expired.', 'forminator' ), $module_slug ), ); } } } } } if ( $can_show['can_submit'] ) { // disable submit if status is draft. if ( self::STATUS_DRAFT === $this->status ) { $can_show = array( 'can_submit' => false, /* translators: %s: module slug */ 'error' => sprintf( esc_html__( 'This %s is not published.', 'forminator' ), $module_slug ), ); } } return apply_filters( 'forminator_cform_' . static::$module_slug . '_is_submittable', $can_show, $this->id, $form_settings ); } /** * Check if we can show the form * * @param bool $is_preview Is preview. * * @since 1.19.0 * @return bool */ public function form_is_visible( $is_preview ) { $form_settings = $this->settings; $can_show = true; if ( isset( $form_settings['logged-users'] ) && ! empty( $form_settings['logged-users'] ) ) { if ( filter_var( $form_settings['logged-users'], FILTER_VALIDATE_BOOLEAN ) && ! is_user_logged_in() ) { $can_show = false; } } if ( $can_show ) { if ( isset( $form_settings['form-expire'] ) ) { if ( 'submits' === $form_settings['form-expire'] ) { if ( isset( $form_settings['expire_submits'] ) && ! empty( $form_settings['expire_submits'] ) ) { $submits = intval( $form_settings['expire_submits'] ); $total_entries = Forminator_Form_Entry_Model::count_entries( $this->id ); if ( $total_entries >= $submits && ! $is_preview ) { $can_show = false; } } } elseif ( 'date' === $form_settings['form-expire'] ) { if ( isset( $form_settings['expire_date'] ) && ! empty( $form_settings['expire_date'] ) ) { $expire_date = $this->get_expiry_date( $form_settings['expire_date'] ); $current_date = strtotime( 'now' ); if ( $current_date > $expire_date && ! $is_preview ) { $can_show = false; } } } } } return apply_filters( 'forminator_cform_' . static::$module_slug . '_is_visible', $can_show, $this->id, $form_settings ); } /** * Get expiry date * * Before 1.15.4 expiry date is being saved like: 1 Mar 2022 * Since we changed it to save as Unix timestamp, we need to process * * @param string $expire_date Expire date. * * @since 1.19.0 * @return string */ public function get_expiry_date( $expire_date ) { return is_numeric( $expire_date ) ? (int) $expire_date / 1000 : strtotime( $expire_date ); } /** * Call do action when module update * * @param string $type module type. * @param string $post_id post ID. * @param object $model model array. * * @return void */ public static function module_update_do_action( $type, $post_id, $model ) { $model_array = (array) $model; $post_status = ! empty( $model_array['status'] ) ? $model_array['status'] : ''; $settings = ! empty( $model_array['settings'] ) ? $model_array['settings'] : array(); $settings['previous_status'] = 'draft'; try { switch ( $type ) { case 'form': $fields = ! empty( $model->fields ) ? $model->get_fields_grouped() : array(); $form_name = $model_array['settings']['formName']; /** This action is documented in library/modules/custom-forms/admin/admin-loader.php */ do_action( 'forminator_custom_form_action_update', $post_id, $form_name, $post_status, $fields, $settings ); break; case 'poll': $answer = ! empty( $model->fields ) ? $model->get_fields_as_array() : array(); /** This action is documented in library/modules/polls/admin/admin-loader.php */ do_action( 'forminator_poll_action_update', $post_id, $post_status, $answer, $settings ); break; case 'quiz': $quiz_type = $model_array['quiz_type']; $questions = $model_array['questions']; $results = $model_array['results']; /** This action is documented in library/modules/quizzes/admin/admin-loader.php */ do_action( 'forminator_quiz_action_update', $post_id, $quiz_type, $post_status, $questions, $results, $settings ); break; default: break; } } catch ( Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch // Ignore errors coming from the add-on for now. // TODO: Display an appropriate error message. } } } class-custom-form-model.php 0000644 00000023023 15162406305 0011733 0 ustar 00 <?php /** * The Forminator_Form_Model class. * * @package Forminator */ if ( ! defined( 'ABSPATH' ) ) { die(); } /** * Author: Hoang Ngo */ class Forminator_Form_Model extends Forminator_Base_Form_Model { /** * Module slug * * @var string */ public static $module_slug = 'form'; /** * Post type * * @var string */ protected $post_type = 'forminator_forms'; /** * Get field * * @since 1.0 * * @param int $id Id. * @param bool $to_array Return in array. * * @return array|null|Forminator_Form_Field_Model */ public function get_field( $id, $to_array = true ) { foreach ( $this->get_fields() as $field ) { if ( $field->slug === $id ) { if ( $to_array ) { return $field->to_array(); } else { return $field; } } } // probably it's repeated field. $explode = explode( '-', $id ); $last = array_pop( $explode ); if ( 1 < count( $explode ) && is_numeric( $last ) ) { $original_id = implode( '-', $explode ); return $this->get_field( $original_id, $to_array ); } return null; } /** * Return fields as array * * @since 1.5 * * @param string $type Field type. * * @return array */ public function get_fields_by_type( $type ) { $fields = array(); if ( empty( $this->fields ) ) { return $fields; } foreach ( $this->fields as $field ) { $field_settings = $field->to_array(); if ( isset( $field_settings['type'] ) && $field_settings['type'] === $type ) { $fields[] = $field; } } return $fields; } /** * Get wrapper * * @since 1.5 * * @param string $id Wrapper Id. * * @return array|null */ public function get_wrapper( $id ) { $position = 0; foreach ( $this->get_fields_grouped() as $wrapper ) { if ( $wrapper['wrapper_id'] === $id ) { $wrapper['position'] = $position; return $wrapper; } ++$position; } return null; } /** * Delete form field by ID * * @since 1.5 * * @param int $id Field Id. * * @return string|false */ public function delete_field( $id ) { $counter = 0; foreach ( $this->fields as $field ) { if ( $field->slug === $id ) { unset( $this->fields[ $counter ] ); return $field->form_id; } ++$counter; } return false; } /** * Update fields cols in specific wrapper * * @since 1.5 * * @param string $wrapper_id Wrapper Id. * * @return bool */ public function update_fields_by_wrapper( $wrapper_id ) { // Get wrapper. $wrapper = $this->get_wrapper( $wrapper_id ); // Check if any fields in the wrapper. if ( ! isset( $wrapper['fields'] ) ) { return false; } // Get total fields in the wrapper. $total = count( $wrapper['fields'] ); if ( $total > 0 ) { $cols = 12 / $total; // Update fields. foreach ( $wrapper['fields'] as $field ) { $field_object = $this->get_field( $field['element_id'], false ); // Update field object. $field_object->import( array( 'cols' => $cols, ) ); } return true; } return false; } /** * Prepare data for preview * * @param object $form_model Model. * @param array $data Passed data. * * @return object */ public static function prepare_data_for_preview( $form_model, $data ) { // build the field. $fields = array(); if ( isset( $data['wrappers'] ) ) { $fields = $data['wrappers']; unset( $data['wrappers'] ); } if ( ! empty( $fields ) ) { foreach ( $fields as $row ) { foreach ( $row['fields'] as $f ) { $field = new Forminator_Form_Field_Model(); $field->form_id = $row['wrapper_id']; $field->slug = $f['element_id']; $field->parent_group = ! empty( $row['parent_group'] ) ? $row['parent_group'] : ''; $field->import( $f ); $form_model->add_field( $field ); } } } return $form_model; } /** * Return Form Settings * * @since 1.1 * * @return mixed */ public function get_form_settings() { // If not using the new "submission-behaviour" setting, set it according to the previous settings. if ( ! isset( $this->settings['submission-behaviour'] ) ) { $redirect = ( isset( $this->settings['redirect'] ) && filter_var( $this->settings['redirect'], FILTER_VALIDATE_BOOLEAN ) ); if ( $redirect ) { $this->settings['submission-behaviour'] = 'behaviour-redirect'; } else { $this->settings['submission-behaviour'] = 'behaviour-thankyou'; } } if ( $this->has_stripe_or_paypal() && $this->is_ajax_submit() ) { if ( isset( $this->settings['submission-behaviour'] ) && 'behaviour-thankyou' === $this->settings['submission-behaviour'] ) { $this->settings['submission-behaviour'] = 'behaviour-hide'; } } $this->settings = apply_filters( 'forminator_form_settings', $this->settings, $this ); return $this->settings; } /** * Return behaviors options. * * @return array */ public function get_behavior_array() { if ( empty( $this->behaviors ) ) { $settings = $this->get_form_settings(); // Backward compatibility | Default. return array( array( 'slug' => 'behavior-1234-4567', 'label' => '', 'autoclose-time' => isset( $settings['autoclose-time'] ) ? $settings['autoclose-time'] : 5, 'autoclose' => isset( $settings['autoclose'] ) ? $settings['autoclose'] : true, 'newtab' => isset( $settings['newtab'] ) ? $settings['newtab'] : 'sametab', 'thankyou-message' => isset( $settings['thankyou-message'] ) ? $settings['thankyou-message'] : '', 'email-thankyou-message' => isset( $settings['email-thankyou-message'] ) ? $settings['email-thankyou-message'] : '', 'manual-thankyou-message' => isset( $settings['manual-thankyou-message'] ) ? $settings['manual-thankyou-message'] : '', 'submission-behaviour' => isset( $settings['submission-behaviour'] ) ? $settings['submission-behaviour'] : 'behaviour-thankyou', 'redirect-url' => isset( $settings['redirect-url'] ) ? $settings['redirect-url'] : '', ), ); } return $this->behaviors; } /** * Check if submit is handled with AJAX * * @since 1.9 * * @return bool */ public function is_ajax_submit() { $form_settings = $this->settings; // Force AJAX submit if form contains Stripe payment field. if ( $this->has_stripe_field() ) { return true; } if ( empty( $form_settings['enable-ajax'] ) ) { return false; } return filter_var( $form_settings['enable-ajax'], FILTER_VALIDATE_BOOLEAN ); } /** * Get field * * Call this method when you need get field and migrate it as well * * @since 1.7 * * @param string $id Field Id. * * @return array|null */ public function get_formatted_array_field( $id ) { foreach ( $this->get_fields() as $field ) { if ( $field->slug === $id ) { return $field->to_formatted_array(); } } return null; } /** * Disable payments fields if payments are disabled * * @param array $fields Fields. * @return array */ protected static function disable_fields( $fields ) { $disabled_fields = apply_filters( 'forminator_disabled_fields', array() ); if ( forminator_payments_disabled() ) { $disabled_fields = array_merge( $disabled_fields, array( 'stripe', 'stripe-ocs', 'paypal' ) ); } if ( $disabled_fields && $fields ) { $fields = array_filter( $fields, function ( $field ) use ( $disabled_fields ) { return empty( $field['type'] ) || ! in_array( $field['type'], $disabled_fields, true ); } ); } return $fields; } /** * Flag whether ssl required when payment exists * * @since 1.7 * * @return bool */ public function is_payment_require_ssl() { $form_id = (int) $this->id; $form_settings = $this->settings; $global_enabled = defined( 'FORMINATOR_PAYMENT_REQUIRE_SSL' ) && FORMINATOR_PAYMENT_REQUIRE_SSL; $enabled = isset( $form_settings['payment_require_ssl'] ) ? $form_settings['payment_require_ssl'] : false; $enabled = filter_var( $enabled, FILTER_VALIDATE_BOOLEAN ); $enabled = $global_enabled || $enabled; /** * Filter is ajax load for Custom Form * * @since 1.6.1 * * @param bool $enabled * @param bool $global_enabled * @param int $form_id * @param array $form_settings * * @return bool */ $enabled = apply_filters( 'forminator_custom_form_is_payment_require_ssl', $enabled, $global_enabled, $form_id, $form_settings ); return $enabled; } /** * Check if Custom form has stripe field * * @since 1.7 * @return object|false */ public function has_stripe_field() { $fields = $this->get_real_fields(); foreach ( $fields as $field ) { $field_array = $field->to_formatted_array(); if ( isset( $field_array['type'] ) && ( 'stripe' === $field_array['type'] || 'stripe-ocs' === $field_array['type'] ) ) { return $field; } } return false; } /** * Check if Custom form has paypal field * * @since 1.41 * @return object|false */ public function has_paypal_field() { $fields = $this->get_real_fields(); foreach ( $fields as $field ) { $field_array = $field->to_formatted_array(); if ( isset( $field_array['type'] ) && 'paypal' === $field_array['type'] ) { return $field; } } return false; } /** * Check if form has stripe or paypal field * * @since 1.9.3 * @return bool */ public function has_stripe_or_paypal() { $fields = $this->get_real_fields(); foreach ( $fields as $field ) { $field = $field->to_formatted_array(); if ( isset( $field['type'] ) && in_array( $field['type'], array( 'paypal', 'stripe', 'stripe-ocs' ), true ) ) { return true; } } return false; } } class-form-field-model.php 0000644 00000012604 15162406305 0011507 0 ustar 00 <?php /** * The Forminator_Form_Field_Model class. * * Author: Hoang Ngo * * @package Forminator */ /** * Forminator_Form_Field_Model * * Hold Field as model * Heads up! this class use __get and __set magic method, use with care * * @property string $wrapper_id */ class Forminator_Form_Field_Model { /** * This should be unique * * @var string */ public $slug; /** * This is parent form ID, optional * * @var int */ public $form_id; /** * This is parent group, optional * * @var string */ public $parent_group = ''; /** * This contains all the parsed json data from frontend form * * @var array */ protected $raw = array(); /** * This contains all form settings for field migration * * @var array */ protected $form_settings = array(); /** * Forminator_Form_Field_Model constructor. * * @param null|array $settings Settings. */ public function __construct( $settings = null ) { if ( ! empty( $settings ) ) { $this->form_settings = $settings; } } /** * Get * * @since 1.0 * * @param string $name Field name. * * @return mixed|null */ public function __get( $name ) { if ( property_exists( $this, $name ) ) { return $this->$name; } $value = isset( $this->raw[ $name ] ) ? $this->raw[ $name ] : null; $value = apply_filters( 'forminator_get_field_' . $this->slug, $value, $this->form_id, $name ); return $value; } /** * Set * * @since 1.0 * * @param string $name Field name. * @param mixed $value Field value. */ public function __set( $name, $value ) { if ( property_exists( $this, $name ) ) { $this->$name = $value; return; } $value = apply_filters( 'forminator_set_field_' . $this->slug, $value, $this->form_id, $name ); $this->raw[ $name ] = $value; } /** * To JSON * * @since 1.0 * @return string */ public function to_json() { return wp_json_encode( $this->to_array() ); } /** * To array * * @since 1.0 * @return array */ public function to_array() { $data = array( 'id' => $this->slug, 'element_id' => $this->slug, 'form_id' => $this->form_id, 'parent_group' => $this->parent_group, ); return array_merge( $data, $this->raw ); } /** * Format to array * * @since 1.0 * @return array */ public function to_formatted_array() { $field_settings = $this->raw; $field_settings['parent_group'] = $this->parent_group; return Forminator_Migration::migrate_field( $field_settings, $this->form_settings ); } /** * Import * * @since 1.0 * @since 1.5 add `wrapper_id` on the attribute * * @param array $data Data. */ public function import( $data ) { if ( empty( $data ) ) { return; } foreach ( $data as $key => $val ) { $key = sanitize_key( $key ); // Attempt ti sanitize key. $this->$key = $val; } // Add `wrapper_id` when necessary. if ( ! isset( $this->wrapper_id ) ) { $wrapper_id = ''; if ( isset( $this->form_id ) && ! empty( $this->form_id ) && false !== stripos( $this->form_id, 'wrapper-' ) ) { $wrapper_id = $this->form_id; } elseif ( isset( $this->formID ) && ! empty( $this->formID ) // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase && false !== stripos( $this->formID, 'wrapper-' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase // Backward compat formID. $wrapper_id = $this->formID; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase } if ( ! empty( $wrapper_id ) ) { $this->wrapper_id = $wrapper_id; } } } /** * Check if subfield is enabled or disabled * * @param string $subfield_name Subfield name. * @return boolean */ public function is_subfield_enabled( $subfield_name ) { $subfield_slugs = array( 'hours' => 'element_id', // Always enabled. 'minutes' => 'element_id', 'ampm' => 'element_id', 'year' => 'element_id', 'day' => 'element_id', 'month' => 'element_id', 'min' => 'element_id', 'max' => 'element_id', 'street_address' => 'street_address', 'address_line' => 'address_line', 'city' => 'address_city', 'state' => 'address_state', 'zip' => 'address_zip', 'country' => 'address_country', 'prefix' => 'prefix', 'first-name' => 'fname', 'middle-name' => 'mname', 'last-name' => 'lname', ); $subfield_slug = isset( $subfield_slugs[ $subfield_name ] ) ? $subfield_slugs[ $subfield_name ] : $subfield_name; $is_enabled = ! empty( $this->raw[ $subfield_slug ] ); /** * Filter is subfield enabled or not * * @param boolean $is_enabled Filtered result. * @param string $subfield_name Subfield name. * @param Forminator_Form_Field_Model $object Field object. */ $is_enabled = apply_filters( 'forminator_is_subfield_enabled', $is_enabled, $subfield_name, $this ); return $is_enabled; } /** * Get Field Label For Entry * * @since 1.0.3 * * @return string */ public function get_label_for_entry() { $field_type = $this->__get( 'type' ); $label = $this->__get( 'field_label' ); if ( empty( $label ) ) { $label = $this->title; } if ( empty( $label ) ) { $label = ucfirst( $field_type ); } return $label; } } class-form-entry-model.php 0000644 00000277102 15162406305 0011573 0 ustar 00 <?php /** * The Forminator_Form_Entry_Model class. * * @package Forminator */ /** * Form Entry model * Base model for all form entries * * @since 1.0 */ class Forminator_Form_Entry_Model { /** * Cache group for entry model */ const FORM_ENTRY_CACHE_GROUP = 'Forminator_Form_Entry_Model'; /** * Cache group for total entries */ const FORM_COUNT_CACHE_GROUP = 'forminator_total_entries'; /** * Entry id * * @var int */ public $entry_id = 0; /** * Entry type * * @var string */ public $entry_type; /** * Form id * * @var int */ public $form_id; /** * Draft id * * @var string */ public $draft_id; /** * Spam flag * * @var bool */ public $is_spam = false; /** * Date created in sql format 0000-00-00 00:00:00 * * @var string */ public $date_created_sql; /** * Date created in sql format D M Y * * @var string */ public $date_created; /** * Time created in sql format M D Y @ g:i A * * @var string */ public $time_created; /** * Meta data * * @var array */ public $meta_data = array(); /** * The table name * * @var string */ protected $table_name; /** * The table meta name * * @var string */ protected $table_meta_name; /** * Hold information about connected addons * * @since 1.1 * @var array */ private static $connected_addons = array(); /** * Initialize the Model * * @param int $entry_id Entry Id. * * @since 1.0 * @since 1.1 Add instantiate connected addons * @since 1.2 Limit initiate addon only on custom-forms by default */ public function __construct( $entry_id = 0 ) { $this->table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $this->table_meta_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); /* * @since 1.17.0 * draft_id could be used in place of the entry_id in the argument * but we still need to get the entry_id which is used as the key for object cache */ if ( ! is_numeric( $entry_id ) && is_string( $entry_id ) && ctype_alnum( $entry_id ) ) { $entry_id = $this->get_entry_id_by_draft_id( $entry_id ); } if ( is_numeric( $entry_id ) && $entry_id > 0 ) { $this->get( $entry_id ); // get connected addons. if ( ! empty( $this->form_id ) ) { $entry_types = array( 'custom-forms', ); /** * Filter Entry Types that can be connected with addons * * @param array $entry_types * * @since 1.2 */ $entry_types = apply_filters( 'forminator_addon_entry_types', $entry_types ); if ( ! empty( $this->entry_type ) && in_array( $this->entry_type, $entry_types, true ) ) { self::get_connected_addons( $this->form_id ); } } } } /** * Load entry by id * After load set entry to cache * * @param int $entry_id - the entry id. * * @return bool|mixed * @since 1.0 */ public function get( $entry_id ) { global $wpdb; $cache_key = self::FORM_ENTRY_CACHE_GROUP; $entry_object_cache = wp_cache_get( $entry_id, $cache_key ); if ( $entry_object_cache ) { $this->entry_id = $entry_object_cache->entry_id; $this->entry_type = $entry_object_cache->entry_type; $this->form_id = $entry_object_cache->form_id; $this->is_spam = $entry_object_cache->is_spam; $this->date_created_sql = $entry_object_cache->date_created_sql; $this->date_created = $entry_object_cache->date_created; $this->time_created = $entry_object_cache->time_created; $this->meta_data = $entry_object_cache->meta_data; $this->draft_id = $entry_object_cache->draft_id; return $entry_object_cache; } else { $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT `entry_type`, `form_id`, `is_spam`, `date_created`, `draft_id` FROM {$table_name} WHERE `entry_id` = %d"; $entry = $wpdb->get_row( $wpdb->prepare( $sql, $entry_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery if ( $entry ) { $this->entry_id = $entry_id; $this->entry_type = $entry->entry_type; $this->form_id = $entry->form_id; $this->is_spam = $entry->is_spam; $this->date_created_sql = $entry->date_created; $this->date_created = date_i18n( 'j M Y', strtotime( $entry->date_created ) ); $this->time_created = date_i18n( 'M j, Y @ g:i A', strtotime( $entry->date_created ) ); $this->draft_id = $entry->draft_id; $this->load_meta(); wp_cache_set( $entry_id, $this, $cache_key ); } } } /** * Set fields * * @param array $meta_array Array of data to be saved. * @param string $entry_date Entry date. * * @type key - string the meta key * @type value - string the meta value * } * * @return bool - true or false * @since 1.5 set meta_data values even entry_id is null for object reference in the future usage * entry_id has null value is the outcome of failed to save or prevent_store is enabled * * @since 1.0 */ public function set_fields( $meta_array, $entry_date = '' ) { global $wpdb; if ( $meta_array && ! is_array( $meta_array ) && ! empty( $meta_array ) ) { return false; } // probably prevent_store enabled. $prevent_store = ! $this->entry_id; if ( ! $prevent_store ) { // clear cache first. wp_cache_delete( $this->entry_id, self::FORM_ENTRY_CACHE_GROUP ); wp_cache_delete( 'poll_entries_' . $this->form_id, self::FORM_ENTRY_CACHE_GROUP ); } foreach ( $meta_array as $meta ) { if ( ! isset( $meta['name'] ) || ! isset( $meta['value'] ) ) { continue; } $key = wp_unslash( $meta['name'] ); $value = wp_unslash( $meta['value'] ); if ( ! $prevent_store ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $meta_id = $wpdb->insert( esc_sql( $this->table_meta_name ), array( 'entry_id' => $this->entry_id, 'meta_key' => $key, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key 'meta_value' => maybe_serialize( $value ), // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value 'date_created' => ! empty( $entry_date ) ? $entry_date : date_i18n( 'Y-m-d H:i:s' ), ) ); } else { $meta_id = $key; } /** * Set Meta data for later usage * * @since 1.0.3 */ if ( $meta_id ) { $this->meta_data[ $key ] = array( 'id' => $meta_id, 'value' => $value, ); } } return ! $prevent_store; } /** * Load all meta data for entry * * @param object|bool $db - the WP_Db object. * * @since 1.0 */ public function load_meta( $db = false ) { if ( ! $db ) { global $wpdb; $db = $wpdb; } $this->meta_data = array(); $table_meta_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $sql = "SELECT `meta_id`, `meta_key`, `meta_value` FROM {$table_meta_name} WHERE `entry_id` = %d"; $results = $db->get_results( $db->prepare( $sql, $this->entry_id ) ); foreach ( $results as $result ) { $this->meta_data[ $result->meta_key ] = array( 'id' => $result->meta_id, 'value' => is_array( $result->meta_value ) ? array_map( 'maybe_unserialize', $result->meta_value ) : maybe_unserialize( $result->meta_value ), ); } // Allow new field to get data of old field for old submissions. if ( in_array( 'stripe-1', array_keys( $this->meta_data ), true ) && ! isset( $this->meta_data['stripe-ocs-1'] ) ) { $this->meta_data['stripe-ocs-1'] = $this->meta_data['stripe-1']; } } /** * Get Meta * * @param string $meta_key - the meta key. * @param bool|object $default_value - the default value. * * @return bool|string * @since 1.0 */ public function get_meta( $meta_key, $default_value = false ) { if ( ! empty( $this->meta_data ) && isset( $this->meta_data[ $meta_key ] ) ) { return $this->meta_data[ $meta_key ]['value']; } return $this->get_grouped_meta( $meta_key, $default_value ); } /** * Get Grouped Meta * Sometimes the meta prefix is same * * @param string $meta_key - the meta key. * @param bool|object $default_value - the default value. * * @return bool|string * @since 1.0 */ public function get_grouped_meta( $meta_key, $default_value = false ) { if ( ! empty( $this->meta_data ) ) { $response = ''; $field_suffix = self::field_suffix(); foreach ( $field_suffix as $suffix ) { if ( isset( $this->meta_data[ $meta_key . '-' . $suffix ] ) ) { $response .= $this->meta_data[ $meta_key . '-' . $suffix ]['value'] . ' ' . $suffix . ' , '; } } if ( ! empty( $response ) ) { return substr( trim( $response ), 0, - 1 ); } } return $default_value; } /** * Save entry * * @param string|null $data_created Optional custom date created. * @param int|null $entry_id Entry Id. * @param int|null $previous_draft Draft Id. * * @return bool * @since 1.6.1 add $data_created arg * * @since 1.0 */ public function save( $data_created = null, $entry_id = null, $previous_draft = null ) { global $wpdb; $this->delete_previous_draft( $previous_draft ); if ( ! empty( $entry_id ) ) { $this->entry_id = $entry_id; return true; } if ( empty( $data_created ) ) { $data_created = date_i18n( 'Y-m-d H:i:s' ); } // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $result = $wpdb->insert( $this->table_name, array( 'entry_type' => $this->entry_type, 'form_id' => $this->form_id, 'is_spam' => $this->is_spam, 'date_created' => $data_created, 'draft_id' => $this->draft_id, ) ); if ( ! $result ) { return false; } self::delete_form_entry_cache( $this->form_id ); wp_cache_delete( 'all_form_types', self::FORM_COUNT_CACHE_GROUP ); wp_cache_delete( $this->entry_type . '_form_type', self::FORM_COUNT_CACHE_GROUP ); $this->entry_id = (int) $wpdb->insert_id; return true; } /** * Delete entry with meta * * @since 1.0 */ public function delete() { self::delete_by_entry( $this->entry_id ); } /** * Field suffix * Some fields are grouped and have the same suffix * * @return array * @since 1.0 */ public static function field_suffix() { return apply_filters( 'forminator_field_suffix', array( 'min', 'max', 'hours', 'minutes', 'ampm', 'street_address', 'address_line', 'city', 'state', 'zip', 'country', 'year', 'day', 'month', 'prefix', 'first-name', 'middle-name', 'last-name', 'post-title', 'post-content', 'post-excerpt', 'post-image', 'post-category', 'post-tags', 'product-id', 'product-quantity', ) ); } /** * Field suffix label * Displayable label for suffix * * @param string $suffix Suffix. * * @return string * @since 1.0.5 */ public static function translate_suffix( $suffix ) { $translated_suffix = $suffix; $field_suffixes = self::field_suffix(); $default_label_map = array( 'hours' => esc_html__( 'Hour', 'forminator' ), 'minutes' => esc_html__( 'Minute', 'forminator' ), 'ampm' => esc_html__( 'AM/PM', 'forminator' ), 'country' => esc_html__( 'Country', 'forminator' ), 'city' => esc_html__( 'City', 'forminator' ), 'state' => esc_html__( 'State', 'forminator' ), 'zip' => esc_html__( 'Zip', 'forminator' ), 'street_address' => esc_html__( 'Street Address', 'forminator' ), 'address_line' => esc_html__( 'Address Line 2', 'forminator' ), 'year' => esc_html__( 'Year', 'forminator' ), 'day' => esc_html__( 'Day', 'forminator' ), 'month' => esc_html__( 'Month', 'forminator' ), 'prefix' => esc_html__( 'Prefix', 'forminator' ), 'first-name' => esc_html__( 'First Name', 'forminator' ), 'middle-name' => esc_html__( 'Middle Name', 'forminator' ), 'last-name' => esc_html__( 'Last Name', 'forminator' ), 'post-title' => esc_html__( 'Post Title', 'forminator' ), 'post-content' => esc_html__( 'Post Content', 'forminator' ), 'post-excerpt' => esc_html__( 'Post Excerpt', 'forminator' ), 'post-image' => esc_html__( 'Post Image', 'forminator' ), 'post-category' => esc_html__( 'Post Category', 'forminator' ), 'post-tags' => esc_html__( 'Post Tags', 'forminator' ), 'product-id' => esc_html__( 'Product ID', 'forminator' ), 'product-quantity' => esc_html__( 'Product Quantity', 'forminator' ), ); // could be filtered out field_suffix. if ( in_array( $suffix, $field_suffixes, true ) && isset( $default_label_map[ $suffix ] ) ) { $translated_suffix = $default_label_map[ $suffix ]; } /** * Translatable suffix * * @param string $translated_suffix * @param string $suffix original suffix. * @param array $default_label_map default translated suffix. * * @since 1.0.5 */ return apply_filters( 'forminator_translate_suffix', $translated_suffix, $suffix, $default_label_map ); } /** * Ignored fields * Fields not saved or shown * * @return array * @since 1.0 */ public static function ignored_fields() { $ignored_fields = array( 'html', 'page-break', 'captcha', 'section', ); if ( forminator_payments_disabled() ) { $ignored_fields[] = 'stripe'; $ignored_fields[] = 'paypal'; $ignored_fields[] = 'stripe-ocs'; } return apply_filters( 'forminator_entry_ignored_fields', $ignored_fields ); } /** * Return if form has live payment entry * * @param int $form_id - the form id. * * @return mixed * @since 1.10 */ public static function has_live_payment( $form_id ) { global $wpdb; $cached_count = wp_cache_get( 'live_payment_count_' . $form_id, self::FORM_COUNT_CACHE_GROUP ); if ( false !== $cached_count ) { return $cached_count; } $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT count(1) > 0 FROM {$table_name} m LEFT JOIN {$entry_table_name} e ON (m.entry_id = e.entry_id) WHERE e.form_id = %d AND ( m.meta_key = 'stripe-1' || m.meta_key = 'stripe-ocs-1' || m.meta_key = 'paypal-1' ) AND m.meta_value LIKE '%4:\"mode\";s:4:\"live\"%' LIMIT 1"; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery -- unprepared SQL ok. false positive. $count = $wpdb->get_var( $wpdb->prepare( $sql, $form_id ) ); wp_cache_set( 'live_payment_count_' . $form_id, $count, self::FORM_COUNT_CACHE_GROUP ); return $count; } /** * Get all entries * * @param int $form_id - the form id. * @param array $filters Filters. * * @return Forminator_Form_Entry_Model[] * @since 1.40 */ public static function get_all_entries( $form_id, $filters = array() ) { $per_page = apply_filters( 'forminator_get_all_entries_limit', 100, $form_id ); $offset = 0; $args = array( 'form_id' => $form_id, 'is_spam' => 0, 'per_page' => $per_page, 'offset' => $offset, ); if ( ! empty( $filters ) && is_array( $filters ) ) { $args = array_merge( $filters, $args ); } $all_entries = array(); $page = 1; do { $entries = self::query_entries( $args ); if ( ! empty( $entries ) ) { $all_entries = array_merge( $all_entries, $entries ); } $args['offset'] = $page * $per_page; $total_items = count( $entries ); ++$page; } while ( $total_items === $per_page ); return $all_entries; } /** * Group count of Entries with extra selected * * @param int $form_id Form id. * @param array $fields_element_id_with_extra Fields element Id. * * @return array|null|object * @example = [ * 'FIELDS_WITH_EXTRA_ELEMENT_ID' => [ * 'META_VALUE-1' => COUNT * 'META_VALUE-2' => COUNT * ], * 'answer-3' => [ * 'javascript is the best' => 8 * 'php is the best' => 7 * ], * ] * * @since 1.0.5 */ public static function count_polls_with_extra( $form_id, $fields_element_id_with_extra ) { global $wpdb; $polls_with_extras = array(); $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); // Cached key. $cache_key = 'forminator_count_polls_with_extra_' . $form_id; // Check if cached data exists. $cached_data = wp_cache_get( $cache_key, self::FORM_ENTRY_CACHE_GROUP ); if ( ! is_array( $cached_data ) ) { $cached_data = array(); } foreach ( $fields_element_id_with_extra as $field_element_id_with_extra ) { $votes = array(); if ( isset( $cached_data[ $field_element_id_with_extra ] ) ) { $votes = $cached_data[ $field_element_id_with_extra ]; } else { $sql = "SELECT m.entry_id AS entry_id FROM {$table_name} m LEFT JOIN {$entry_table_name} e ON (m.entry_id = e.entry_id) WHERE e.form_id = %d AND m.meta_key = %s GROUP BY m.entry_id"; $sql = $wpdb->prepare( $sql, $form_id, esc_sql( $field_element_id_with_extra ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $entry_ids = $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery if ( ! empty( $entry_ids ) ) { $entry_id_placeholders = implode( ', ', array_fill( 0, count( $entry_ids ), '%d' ) ); $sql = "SELECT m.meta_value AS meta_value, COUNT(1) votes FROM {$table_name} m WHERE m.entry_id IN ({$entry_id_placeholders}) AND m.meta_key = 'extra' GROUP BY m.meta_value ORDER BY votes DESC"; $sql = $wpdb->prepare( $sql, $entry_ids ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $votes = $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery $cached_data[ $field_element_id_with_extra ] = $votes; // Store the result in the cache. wp_cache_set( $cache_key, $cached_data, self::FORM_ENTRY_CACHE_GROUP ); } } if ( ! empty( $votes ) ) { $polls_with_extras[ $field_element_id_with_extra ] = array(); foreach ( $votes as $vote ) { $polls_with_extras[ $field_element_id_with_extra ][ $vote['meta_value'] ] = $vote['votes']; } } } return $polls_with_extras; } /** * Count entries by form * * @param int $form_id - the form id. * @param mixed $db DB. * @param bool $include_draft Include draft. * * @return int - total entries * @since 1.0 */ public static function count_entries( $form_id, $db = false, $include_draft = false ) { if ( ! $db ) { global $wpdb; $db = $wpdb; } $entries_cache = wp_cache_get( $form_id, self::FORM_COUNT_CACHE_GROUP ); $where = ''; if ( $entries_cache ) { return $entries_cache; } else { /* * On Submissions page we include drafts in the entries count * but in specific form submissions count (in admin.php?page=forminator-cform) * we dont count the drafts to prevent affecting conversion rate where we only count complete submissions */ if ( ! $include_draft ) { $where = ' AND ( `draft_id` IS NULL OR `draft_id` = "" )'; } $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT count(`entry_id`) FROM {$table_name} WHERE `form_id` = %d AND `is_spam` = 0 {$where}"; $entries = $db->get_var( $db->prepare( $sql, $form_id ) ); if ( $entries ) { wp_cache_set( $form_id, $entries, self::FORM_COUNT_CACHE_GROUP ); return $entries; } } return 0; } /** * Count lead entries by form * * @param int $form_id Form Id. * @param string $start_date Start date. * @param string $end_date End date. * * @return int|string */ public static function count_leads( $form_id, $start_date = '', $end_date = '' ) { global $wpdb; $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); // Cached key. $cache_key = 'forminator_count_leads_' . $form_id; $unique_id = md5( wp_json_encode( array( $start_date, $end_date ) ) ); // Get cached data. $cached_data = wp_cache_get( $cache_key, self::FORM_ENTRY_CACHE_GROUP ); if ( ! is_array( $cached_data ) ) { $cached_data = array(); } if ( isset( $cached_data[ $unique_id ] ) ) { return $cached_data[ $unique_id ]; } else { $where = ''; if ( ! empty( $start_date ) && ! empty( $end_date ) ) { $end_date = $end_date . ' 23:59:00'; $where .= $wpdb->prepare( ' AND ( e.date_created >= %s AND e.date_created <= %s )', esc_sql( $start_date ), esc_sql( $end_date ) ); } $sql = "SELECT count(DISTINCT e.`entry_id`) FROM {$table_name} m LEFT JOIN {$entry_table_name} e ON(e.`entry_id` = m.`entry_id`) WHERE e.`form_id` = %d AND m.meta_key = 'skip_form' {$where} AND m.meta_value = '0' AND e.`is_spam` = 0"; $entries = $wpdb->get_var( $wpdb->prepare( $sql, $form_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery -- false positive if ( ! $entries ) { $entries = 0; } $cached_data[ $unique_id ] = $entries; // Store the result in the cache. wp_cache_set( $cache_key, $cached_data, self::FORM_ENTRY_CACHE_GROUP ); return $entries; } } /** * Count entries by form * * @param int $form_id - the form id. * * @return int - total entries * @since 1.0 * @deprecated */ public static function count_entries_by_form_and_field( $form_id ) { _deprecated_function( 'count_entries_by_form_and_field', '1.0.5' ); global $wpdb; $field = ''; $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT count(m.`meta_id`) FROM {$table_name} m LEFT JOIN {$entry_table_name} e ON(e.`entry_id` = m.`entry_id`) WHERE e.`form_id` = %d AND m.`meta_key` = %s AND e.`is_spam` = 0"; $entries = $wpdb->get_var( $wpdb->prepare( $sql, $form_id, $field ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery if ( $entries ) { return $entries; } return 0; } /** * Map Polls Entries with its votes * * @param int $form_id Form id. * @param array $fields Fields. * * @return array * @example { * 'ELEMENT_ID' => 'NUMBER' * 'answer-1' = 9 * } * * @since 1.0.5 */ public static function map_polls_entries( $form_id, $fields ) { $cache_key = 'poll_entries_' . $form_id; $cached_entries = wp_cache_get( $cache_key, self::FORM_ENTRY_CACHE_GROUP ); if ( false !== $cached_entries ) { return $cached_entries; } global $wpdb; $map_entries = array(); $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); // Make sure $form_id is always number. if ( ! is_numeric( $form_id ) ) { $form_id = 0; } $element_ids = array(); foreach ( $fields as $field ) { $element_id = (string) $field['element_id']; $element_ids[] = $element_id; $title = sanitize_title( $field['title'] ); // First, escape the link for use in a LIKE statement. $new_element_id_format = $wpdb->esc_like( 'answer-' ); // Add wildcards. $new_element_id_format = $new_element_id_format . '%'; // find old format entries of this field. $sql = "SELECT count(1) FROM {$table_name} m LEFT JOIN {$entry_table_name} e ON (e.`entry_id` = m.`entry_id`) WHERE e.form_id = %d AND m.meta_key NOT LIKE %s AND m.meta_value = '1' AND m.meta_key = %s LIMIT 1"; $old_format_entries = $wpdb->get_var( $wpdb->prepare( $sql, $form_id, esc_sql( $new_element_id_format ), esc_sql( $title ) ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery // old format exist. if ( $old_format_entries ) { // update old format entries if avail. self::maybe_update_poll_entries_meta_key_to_element_id( $form_id, $title, $element_id ); } } if ( ! empty( $element_ids ) ) { $element_ids_placeholders = implode( ', ', array_fill( 0, count( $element_ids ), '%s' ) ); $sql = "SELECT m.meta_key as element_id, count(1) as votes FROM {$table_name} m LEFT JOIN {$entry_table_name} e ON (e.`entry_id` = m.`entry_id`) WHERE e.form_id = {$form_id} AND m.meta_key IN ({$element_ids_placeholders}) GROUP BY m.meta_key"; $sql = $wpdb->prepare( $sql, $element_ids ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $results = $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery foreach ( $results as $result ) { $map_entries[ $result['element_id'] ] = $result['votes']; } } wp_cache_set( $cache_key, $map_entries, self::FORM_ENTRY_CACHE_GROUP ); return $map_entries; } /** * Map Polls Entries to be used for export * Pretty much @see Form_Entry_Model::map_polls_entries(), but returning what's required for the export. * * @since 1.6 * * @example { * 'meta_id' => 'values' * '2' = [ * 'date_created' = '1999-12-31 23:59:59', * 'meta_key' = 'answer-1', * 'is_spam' = '0', * ] * } * * @param int $form_id Form Id. * @param array $fields Fields. * * @return array */ public static function map_polls_entries_for_export( $form_id, $fields ) { global $wpdb; $map_entries = array(); $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); // Make sure $form_id is always number. if ( ! is_numeric( $form_id ) ) { $form_id = 0; } $element_ids = array(); foreach ( $fields as $field ) { $element_id = (string) $field['element_id']; $element_ids[] = $element_id; $title = sanitize_title( $field['title'] ); // First, escape the link for use in a LIKE statement. $new_element_id_format = $wpdb->esc_like( 'answer-' ); // Add wildcards. $new_element_id_format = $new_element_id_format . '%'; // find old format entries of this field. $sql = "SELECT count(1) FROM {$table_name} m LEFT JOIN {$entry_table_name} e ON (e.`entry_id` = m.`entry_id`) WHERE e.form_id = %d AND m.meta_key NOT LIKE %s AND m.meta_value = '1' AND m.meta_key = %s LIMIT 1"; $old_format_entries = $wpdb->get_var( $wpdb->prepare( $sql, $form_id, esc_sql( $new_element_id_format ), esc_sql( $title ) ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery // old format exist. if ( $old_format_entries ) { // update old format entries if avail. self::maybe_update_poll_entries_meta_key_to_element_id( $form_id, $title, $element_id ); } } if ( ! empty( $element_ids ) ) { $element_ids_placeholders = implode( ', ', array_fill( 0, count( $element_ids ), '%s' ) ); $sql = "SELECT m.meta_id, m.meta_key, m.meta_value, m.date_created, e.is_spam, m.entry_id FROM {$table_name} m LEFT JOIN {$entry_table_name} e ON (e.`entry_id` = m.`entry_id`) WHERE e.form_id = {$form_id} AND m.meta_key IN ({$element_ids_placeholders})"; $sql = $wpdb->prepare( $sql, $element_ids ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $results = $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery foreach ( $results as $result ) { $map_entries[ $result['meta_id'] ]['entry_id'] = $result['entry_id']; $map_entries[ $result['meta_id'] ]['is_spam'] = $result['is_spam']; $map_entries[ $result['meta_id'] ]['date_created'] = $result['date_created']; $map_entries[ $result['meta_id'] ]['meta_key'] = $result['meta_key']; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key $map_entries[ $result['meta_id'] ]['meta_value'] = $result['meta_value']; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value } } return $map_entries; } /** * Update poll entries meta_key to its element_id * * @param int $form_id Form id. * @param string $old_meta_key Old meta key. * @param string $element_id Element Id. * * @since 1.0.5 */ public static function maybe_update_poll_entries_meta_key_to_element_id( $form_id, $old_meta_key, $element_id ) { global $wpdb; $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); // find entries that using old format. $sql = "SELECT entry_id FROM {$entry_table_name} where form_id = %d"; $sql = $wpdb->prepare( $sql, $form_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $entry_ids = $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery if ( ! empty( $entry_ids ) && count( $entry_ids ) > 0 ) { $entry_ids = implode( ', ', $entry_ids ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $wpdb->query( $wpdb->prepare( "UPDATE %s SET meta_key = %s, meta_value = %s WHERE entry_id IN (%s) AND meta_key = %s AND meta_value = '1'", $table_name, $element_id, $entry_ids, $old_meta_key, $old_meta_key ) ); } } /** * Get entry date by ip and form * * @param int $form_id - the form id. * @param string $ip - the user ip. * * @return string|bool * @since 1.0 */ public static function get_entry_date_by_ip_and_form( $form_id, $ip ) { global $wpdb; $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT m.`date_created` FROM {$table_name} m LEFT JOIN {$entry_table_name} e ON(e.`entry_id` = m.`entry_id`) WHERE e.`form_id` = %d AND m.`meta_key` = %s AND m.`meta_value` = %s order by m.`meta_id` desc limit 0,1"; $entry_date = $wpdb->get_var( $wpdb->prepare( $sql, $form_id, '_forminator_user_ip', $ip ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery if ( $entry_date ) { return $entry_date; } return false; } /** * Get amount submissions by current user * * @param int $form_id Form ID. * @return int */ public static function count_user_entries( $form_id ) { global $wpdb; $user_id = get_current_user_id(); // Cached key. $cache_key = 'forminator_count_user_entries_' . $form_id; // Get cached data. $cached_data = wp_cache_get( $cache_key, self::FORM_ENTRY_CACHE_GROUP ); if ( ! is_array( $cached_data ) ) { $cached_data = array(); } if ( isset( $cached_data[ $user_id ] ) ) { return $cached_data[ $user_id ]; } else { $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT COUNT(*) FROM {$table_name} m LEFT JOIN {$entry_table_name} e ON(e.`entry_id` = m.`entry_id`) WHERE e.`form_id` = %d AND m.`meta_key` = '_user_id' AND m.`meta_value` = %s"; $amount = $wpdb->get_var( $wpdb->prepare( $sql, $form_id, $user_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery $amount = intval( $amount ); $cached_data[ $user_id ] = $amount; // Store the result in the cache. wp_cache_set( $cache_key, $cached_data, self::FORM_ENTRY_CACHE_GROUP ); return $amount; } } /** * Get last entry by IP and form * * @param int $form_id - the form id. * @param string $ip - the user ip. * * @return string|bool * @since 1.0 */ public static function get_last_entry_by_ip_and_form( $form_id, $ip ) { $cache_key = 'last_entry_by_ip_' . $form_id . '_' . md5( $ip ); $cache_group = self::FORM_ENTRY_CACHE_GROUP . '_' . $form_id; $cached_entry = wp_cache_get( $cache_key, $cache_group ); if ( false !== $cached_entry ) { return $cached_entry; } global $wpdb; $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT m.`entry_id` FROM {$table_name} m LEFT JOIN {$entry_table_name} e ON(e.`entry_id` = m.`entry_id`) WHERE e.`form_id` = %d AND m.`meta_key` = %s AND m.`meta_value` = %s order by m.`meta_id` desc limit 0,1"; $entry_id = $wpdb->get_var( $wpdb->prepare( $sql, $form_id, '_forminator_user_ip', $ip ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery if ( $entry_id ) { wp_cache_set( $cache_key, $entry_id, $cache_group ); return $entry_id; } return false; } /** * Get entry date by ip and form * * @param int $form_id - the form id. * @param string $ip - the user ip. * @param int $entry_id - the entry id. * @param string $interval - the mysql interval. Eg (INTERVAL 1 HOUR). * * @return string|bool * @since 1.0 */ public static function check_entry_date_by_ip_and_form( $form_id, $ip, $entry_id, $interval = '' ) { global $wpdb; $current_date = date_i18n( 'Y-m-d H:i:s' ); $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $interval = esc_sql( $interval ); $sql = "SELECT m.`meta_id` FROM {$table_name} m LEFT JOIN {$entry_table_name} e ON(e.`entry_id` = m.`entry_id`) WHERE e.`form_id` = %d AND m.`meta_key` = %s AND m.`meta_value` = %s AND m.`entry_id` = %d AND DATE_ADD(m.`date_created`, {$interval}) < %s order by m.`meta_id` desc limit 0,1"; $entry = $wpdb->get_var( $wpdb->prepare( $sql, $form_id, '_forminator_user_ip', $ip, $entry_id, $current_date ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery if ( $entry ) { return $entry; } return false; } /** * Bulk delete form entries * * @param int $form_id - the form id. * @param mixed $db - DB. * * @since 1.0 */ public static function delete_by_form( $form_id, $db = false ) { if ( ! $db ) { global $wpdb; $db = $wpdb; } $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT GROUP_CONCAT(`entry_id`) FROM {$table_name} WHERE `form_id` = %d"; $entries = $db->get_var( $db->prepare( $sql, $form_id ) ); if ( $entries ) { self::delete_by_entrys( $form_id, $entries, $db ); } } /** * Delete by string of comma separated entry ids * * @param int $form_id Form id. * @param string $entries Entries. * @param bool|wpdb $db DB. * * @return bool * @since 1.0 * @since 1.1 Add init addons and Add hooks `forminator_before_delete_entry` */ public static function delete_by_entrys( $form_id, $entries, $db = false ) { if ( ! $db ) { global $wpdb; $db = $wpdb; } if ( empty( $form_id ) || empty( $entries ) ) { return false; } $form_id = (int) $form_id; $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $table_meta_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); forminator_maybe_log( 'delete_by_entrys', $form_id, $entries ); $entries_to_array = explode( ',', $entries ); forminator_maybe_log( 'delete_by_entrys', $form_id, $entries_to_array ); $valid_entries_to_delete = array(); if ( ! empty( $entries_to_array ) && is_array( $entries_to_array ) ) { foreach ( $entries_to_array as $entry_id ) { $entry_id = (int) $entry_id; $entry_model = new Forminator_Form_Entry_Model( $entry_id ); // validate : entry must be exist on requested $form_id. if ( $form_id === (int) $entry_model->form_id ) { $valid_entries_to_delete[] = $entry_id; self::attach_addons_on_before_delete_entry( $form_id, $entry_model ); self::entry_delete_upload_files( $form_id, $entry_model ); } } } if ( empty( $valid_entries_to_delete ) ) { return false; } // modify $entries with $valid_entries_to_delete. $entries = implode( ', ', $valid_entries_to_delete ); /** * Fires just before an entry getting deleted * * @param int $form_id Current Form ID. * @param int $entry_id Current Entry ID to be deleted. * * @since 1.1 */ do_action_ref_array( 'forminator_before_delete_entries', array( $form_id, $entries ) ); $sql = "DELETE FROM {$table_meta_name} WHERE `entry_id` IN ($entries)"; $db->query( $sql ); $sql = "DELETE FROM {$table_name} WHERE `entry_id` IN ($entries)"; $db->query( $sql ); self::delete_form_entry_cache( $form_id ); wp_cache_delete( 'all_form_types', self::FORM_COUNT_CACHE_GROUP ); $model = forminator_get_model_from_id( $form_id ); if ( is_object( $model ) ) { wp_cache_delete( $model->get_entry_type() . '_form_type', self::FORM_COUNT_CACHE_GROUP ); } } /** * Delete by entry * * @param int $entry_id - the entry id. * * @since 1.0 * @since 1.1 Add init addons and Add hooks `forminator_before_delete_entry` */ public static function delete_by_entry( $entry_id ) { global $wpdb; $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $table_meta_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $entry_model = new Forminator_Form_Entry_Model( $entry_id ); $form_id = (int) $entry_model->form_id; $entry_id = (int) $entry_id; forminator_maybe_log( 'forminator_before_delete_entry', $form_id, $entry_id ); /** * Fires just before an entry getting deleted * * @param int $form_id Current Form ID. * @param int $entry_id Current Entry ID to be deleted. * * @since 1.1 */ do_action_ref_array( 'forminator_before_delete_entry', array( $form_id, $entry_id ) ); self::attach_addons_on_before_delete_entry( $form_id, $entry_model ); self::entry_delete_upload_files( $form_id, $entry_model ); $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . esc_sql( $table_meta_name ) . ' WHERE `entry_id` = %d', $entry_id ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . esc_sql( $table_name ) . ' WHERE `entry_id` = %d', $entry_id ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery wp_cache_delete( $entry_id, self::FORM_ENTRY_CACHE_GROUP ); self::delete_form_entry_cache( $form_id ); wp_cache_delete( 'all_form_types', self::FORM_COUNT_CACHE_GROUP ); wp_cache_delete( $entry_model->entry_type . '_form_type', self::FORM_COUNT_CACHE_GROUP ); } /** * Delete files from upload folder * * @param int $form_id Form Id. * @param Forminator_Form_Entry_Model $entry_model Form Entry model. * * @since 1.7 */ public static function entry_delete_upload_files( $form_id, $entry_model ) { $custom_form = Forminator_Base_Form_Model::get_model( $form_id ); $submission_file = 'delete'; if ( is_object( $custom_form ) ) { $settings = $custom_form->settings; $submission_file = isset( $settings['submission-file'] ) ? $settings['submission-file'] : 'delete'; } if ( 'delete' === $submission_file ) { foreach ( $entry_model->meta_data as $meta_data ) { $meta_value = $meta_data['value']; if ( is_array( $meta_value ) && isset( $meta_value['file'] ) ) { $file_path = is_array( $meta_value['file']['file_path'] ) ? $meta_value['file']['file_path'] : array( $meta_value['file']['file_path'] ); if ( ! empty( $file_path ) ) { foreach ( $file_path as $key => $path ) { if ( ! empty( $path ) && file_exists( $path ) ) { wp_delete_file( $path ); if ( isset( $meta_value['file']['file_url'][ $key ] ) ) { $attachment_id = attachment_url_to_postid( $meta_value['file']['file_url'][ $key ] ); if ( $attachment_id ) { wp_delete_attachment( $attachment_id ); } } } } } } } } } /** * Convert meta value to string * Useful on displaying metadata without PHP warning on conversion * * @param string $field_type Field type. * @param mixed $meta_value Meta value. * @param bool $allow_html Allow HTML. * @param int $truncate truncate returned string (usefull if display container is limited). * * @return string * @since 1.0.5 */ public static function meta_value_to_string( $field_type, $meta_value, $allow_html = false, $truncate = PHP_INT_MAX ) { switch ( $field_type ) { case 'postdata': $string_value = self::postdata_to_string( $meta_value, $allow_html, $truncate ); break; case 'time': if ( ! isset( $meta_value['hours'] ) || ! isset( $meta_value['minutes'] ) ) { $string_value = ''; } else { $string_value = sprintf( '%02d', $meta_value['hours'] ) . ':' . sprintf( '%02d', $meta_value['minutes'] ) . ' ' . ( isset( $meta_value ['ampm'] ) ? $meta_value['ampm'] : '' ); } // truncate. if ( strlen( $string_value ) > $truncate ) { $string_value = substr( $string_value, 0, $truncate ) . '...'; } break; case 'date': if ( ! isset( $meta_value['year'] ) || ! isset( $meta_value['month'] ) || ! isset( $meta_value['day'] ) ) { // is it date picker? if ( ! empty( $meta_value ) && is_string( $meta_value ) ) { $string_value = $meta_value; } else { $string_value = ''; } } elseif ( empty( $meta_value['year'] ) || empty( $meta_value['month'] ) || empty( $meta_value['day'] ) ) { $string_value = ''; } else { $date_value = $meta_value['year'] . '/' . sprintf( '%02d', $meta_value['month'] ) . '/' . sprintf( '%02d', $meta_value['day'] ); if ( isset( $meta_value['format'] ) && ! empty( $meta_value['format'] ) ) { $string_value = date_i18n( $meta_value['format'], strtotime( $date_value ) ); } else { $string_value = date_i18n( get_option( 'date_format' ), strtotime( $date_value ) ); } } // truncate. if ( strlen( $string_value ) > $truncate ) { $string_value = substr( $string_value, 0, $truncate ) . '...'; } break; case 'email': if ( ! empty( $meta_value ) ) { $string_value = $meta_value; // truncate. if ( $allow_html ) { // make link. $email = $string_value; // truncate. if ( strlen( $email ) > $truncate ) { $email = substr( $email, 0, $truncate ) . '...'; } $string_value = '<a href="mailto:' . $email . '" target="_blank" rel="noopener noreferrer" title="' . esc_html__( 'Send Email', 'forminator' ) . '">' . $email . '</a>'; } elseif ( strlen( $string_value ) > $truncate ) { // truncate url. $string_value = substr( $string_value, 0, $truncate ) . '...'; } } else { $string_value = ''; } break; case 'url': if ( ! empty( $meta_value ) ) { $string_value = $meta_value; // truncate. if ( $allow_html ) { // make link. $website = esc_url( $string_value ); // truncate. if ( strlen( $website ) > $truncate ) { $website = substr( $website, 0, $truncate ) . '...'; } $string_value = '<a href="' . $website . '" target="_blank" rel="noopener noreferrer" title="' . esc_html__( 'View Website', 'forminator' ) . '">' . $website . '</a>'; } elseif ( strlen( $string_value ) > $truncate ) { // truncate url. $string_value = substr( $string_value, 0, $truncate ) . '...'; } } else { $string_value = ''; } break; case 'upload': $file = ''; if ( isset( $meta_value['file'] ) ) { $file = $meta_value['file']; } if ( ! empty( $file ) && is_array( $file ) && isset( $file['file_url'] ) && ! empty( $file['file_url'] ) ) { if ( $allow_html ) { // make link. $string_value = ''; $upload_count = 0; $file_values = is_array( $file['file_url'] ) ? $file['file_url'] : array( $file['file_url'] ); foreach ( $file_values as $file_value ) { $url = $file_value; $file_name = basename( $url ); $file_name = ! empty( $file_name ) ? $file_name : esc_html__( '(no filename)', 'forminator' ); // truncate. if ( strlen( $file_name ) > $truncate ) { $file_name = substr( $file_name, 0, $truncate ) . '...'; } ++$upload_count; if ( $upload_count > 1 ) { $string_value .= '<br/>'; } $string_value .= '<a href="' . $url . '" rel="noopener noreferrer" target="_blank" title="' . esc_html__( 'View File', 'forminator' ) . '">' . $file_name . '</a>'; } } else { // truncate url. $string_value = is_array( $file['file_url'] ) ? implode( ', ', $file['file_url'] ) : $file['file_url']; if ( strlen( $string_value ) > $truncate ) { $string_value = substr( $string_value, 0, $truncate ) . '...'; } } } else { $string_value = ''; } break; case 'checkbox': if ( is_array( $meta_value ) ) { $string_value = implode( ', ', $meta_value ); } elseif ( is_string( $meta_value ) ) { $string_value = $meta_value; } else { $string_value = ''; } // truncate. if ( strlen( $string_value ) > $truncate ) { $string_value = substr( $string_value, 0, $truncate ) . '...'; } break; case 'calculation': if ( ! is_array( $meta_value ) ) { $string_value = '0.0'; } elseif ( ! empty( $meta_value['error'] ) ) { $string_value = $meta_value['error']; } else { if ( isset( $meta_value['formatting_result'] ) ) { $result = $meta_value['formatting_result']; } else { $result = $meta_value['result']; } if ( ! isset( $result ) ) { $string_value = '0.0'; } elseif ( is_infinite( floatval( $result ) ) ) { $string_value = 'INF'; } else { $string_value = (string) $result; } } // truncate. if ( strlen( $string_value ) > $truncate ) { $string_value = substr( $string_value, 0, $truncate ) . '...'; } break; case 'stripe': case 'stripe-ocs': // In case stripe requested without mapper, we return transaction_id. $string_value = ''; if ( is_array( $meta_value ) && isset( $meta_value['transaction_id'] ) ) { if ( ! empty( $meta_value['transaction_id'] ) ) { $string_value = $meta_value['transaction_id']; } } // truncate. if ( strlen( $string_value ) > $truncate ) { $string_value = substr( $string_value, 0, $truncate ) . '...'; } /** * Filter string value of Stripe meta entry * * @param string $string_value * @param array $meta_value * @param boolean $allow_html * @param int $truncate * * @return string * @since 1.7 */ $string_value = apply_filters( 'forminator_entry_stripe_meta_value_to_string', $string_value, $meta_value, $allow_html, $truncate ); break; case 'password': // Hide value for login/template forms. $string_value = '*****'; break; case 'slider': // Change behavior for range slider. if ( is_array( $meta_value ) && isset( $meta_value['min'] ) && isset( $meta_value['max'] ) ) { $string_value = $meta_value['min'] . ' - ' . $meta_value['max']; break; } // fall-through. default: // base flattener. // implode on array. if ( is_array( $meta_value ) ) { $string_value = wp_json_encode( $meta_value ); } else { // or juggling to string. $string_value = (string) $meta_value; } // truncate. if ( strlen( $string_value ) > $truncate ) { $string_value = substr( $string_value, 0, $truncate ) . '...'; } break; } /** * Filter string value of meta entry * * @param string $string_value * @param string $field_type * @param array $meta_value * @param boolean $allow_html * @param int $truncate * * @return string * @since 1.7 */ $string_value = apply_filters( 'forminator_entry_meta_value_to_string', $string_value, $field_type, $meta_value, $allow_html, $truncate ); return $string_value; } /** * Process postdata meta value * * @param array $meta_value Meta value. * @param bool $allow_html Allow HTML. * @param int $truncate Truncate. * * @return string * @since 1.17.0 */ public static function postdata_to_string( $meta_value, $allow_html = false, $truncate = PHP_INT_MAX ) { if ( empty( $meta_value ) ) { $string_value = ''; } elseif ( is_string( $meta_value ) ) { $string_value = $meta_value; } elseif ( ! empty( $meta_value['postdata'] ) ) { $post_id = $meta_value['postdata']; // Title. if ( current_user_can( 'edit_post', $post_id ) ) { $url = get_edit_post_link( $post_id, 'link' ); } else { // is not logged in. $url = get_home_url(); } // Title make link. $title = get_the_title( $post_id ); $post_content = isset( $meta_value['value']['post-content'] ) ? $meta_value['value']['post-content'] : ''; $post_excerpt = isset( $meta_value['value']['post-excerpt'] ) ? $meta_value['value']['post-excerpt'] : ''; $category = isset( $meta_value['value']['category'] ) ? $meta_value['value']['category'] : array(); $tags = isset( $meta_value['value']['post_tag'] ) ? $meta_value['value']['post_tag'] : array(); $post_custom = isset( $meta_value['value']['post-custom'] ) ? $meta_value['value']['post-custom'] : ''; $tax_keys = forminator_list_custom_taxonomies( $meta_value['value'] ); if ( $allow_html ) { $post_image = ! empty( $meta_value['value']['post-image'] ) && ! empty( $meta_value['value']['post-image']['attachment_id'] ) ? $meta_value['value']['post-image']['attachment_id'] : ''; $string_value = self::get_postdata_title( $title, 'allow_html', $truncate, $url ); $string_value .= self::get_postdata_content( $post_content, true, $truncate ); $string_value .= self::get_postdata_excerpt( $post_excerpt, true, $truncate ); $string_value .= self::get_postdata_categories( $category, true ); $string_value .= self::get_postdata_tags( $tags, true ); $string_value .= self::get_postdata_image( $post_image, true ); $string_value .= self::get_postdata_customfields( $post_custom, true ); if ( ! empty( $tax_keys ) ) { foreach ( $tax_keys as $tax_key => $tax_name ) { $taxonomy_val = isset( $meta_value['value'][ $tax_name ] ) ? $meta_value['value'][ $tax_name ] : array(); $string_value .= self::get_postdata_taxonomies( $tax_name, $taxonomy_val ); } } } else { $post_image = ! empty( $meta_value['value']['post-image'] ) && ! empty( $meta_value['value']['post-image']['uploaded_file'] ) ? $meta_value['value']['post-image']['uploaded_file'][0] : ''; $string_value = self::get_postdata_title( $title, 'no_html', $truncate ); $string_value .= self::get_postdata_content( $post_content, false, $truncate ); $string_value .= self::get_postdata_excerpt( $post_excerpt, false, $truncate ); $string_value .= self::get_postdata_categories( $category, false ); $string_value .= self::get_postdata_tags( $tags, false ); $string_value .= self::get_postdata_image( $post_image, false ); $string_value .= self::get_postdata_customfields( $post_custom, false, $truncate ); if ( ! empty( $tax_keys ) ) { foreach ( $tax_keys as $tax_key => $tax_name ) { $taxonomy_val = isset( $meta_value['value'][ $tax_name ] ) ? $meta_value['value'][ $tax_name ] : array(); $string_value .= self::get_postdata_taxonomies( $tax_name, $taxonomy_val, false ); } } // truncate. if ( strlen( $string_value ) > $truncate ) { $string_value = substr( $string_value, 0, $truncate ) . '...'; } } } else { // Draft postdata values. $title = isset( $meta_value['post-title'] ) ? $meta_value['post-title'] : ''; $post_content = isset( $meta_value['post-content'] ) ? $meta_value['post-content'] : ''; $post_excerpt = isset( $meta_value['post-excerpt'] ) ? $meta_value['post-excerpt'] : ''; $category = isset( $meta_value['category'] ) ? $meta_value['category'] : array(); $tags = isset( $meta_value['post_tag'] ) ? $meta_value['post_tag'] : array(); $tax_keys = forminator_list_custom_taxonomies( $meta_value ); $string_value = self::get_postdata_title( $title, 'draft', $truncate ); $string_value .= self::get_postdata_content( $post_content, true, $truncate ); $string_value .= self::get_postdata_excerpt( $post_excerpt, true, $truncate ); $string_value .= self::get_postdata_categories( $category, true ); $string_value .= self::get_postdata_tags( $tags, true ); if ( ! empty( $tax_keys ) ) { foreach ( $tax_keys as $tax_key => $tax_name ) { $taxonomy_val = isset( $meta_value[ $tax_name ] ) ? $meta_value[ $tax_name ] : array(); $string_value .= self::get_postdata_taxonomies( $tax_name, $taxonomy_val ); } } // Custom fields are not being saved in drafts but automatically created after full submission. } return $string_value; } /** * Get the postdata title depending on context * * @param string $value Value. * @param string $type allow_html, no_html, draft. * @param int $truncate Truncate, Default: PHP_INT_MAX. * @param string $url URL. * * @since 1.17.0 */ public static function get_postdata_title( $value, $type = 'allow_html', $truncate = PHP_INT_MAX, $url = '' ) { if ( empty( $value ) ) { return; } $title = ! empty( $value ) ? $value : esc_html__( '(no title)', 'forminator' ); $title = forminator_truncate_text( wp_kses_post( $title ), $truncate ); $label = esc_html__( 'Title', 'forminator' ); if ( 'no_html' !== $type ) { $value = '<b>' . $label . ':</b> '; } if ( 'allow_html' === $type ) { $value .= '<a href="' . $url . '" target="_blank" rel="noopener noreferrer" title="' . esc_attr__( 'Edit Post', 'forminator' ) . '">' . $title . '</a>'; } elseif ( 'draft' === $type ) { $value .= $title; } else { $value = $label . ': '; $value .= $title . ' | '; } return $value; } /** * Get the postdata content depending on context * * @param string $value Value. * @param bool $allow_html Allow HTML. * @param int $truncate Truncate. * * @since 1.17.0 */ public static function get_postdata_content( $value = '', $allow_html = true, $truncate = PHP_INT_MAX ) { if ( empty( $value ) ) { return ''; } $post_content = forminator_truncate_text( $value, $truncate ); $label = esc_html__( 'Content', 'forminator' ); if ( $allow_html ) { $value = '<hr>'; $value .= '<b>' . $label . ':</b><br>'; $value .= wp_kses_post( $post_content, 'post' ); } else { $post_content = wp_strip_all_tags( $post_content ); $value = $label . ': '; $value .= $post_content . ' | '; } return $value; } /** * Get the postdata excerpt depending on context * * @param string $value Value. * @param bool $allow_html Allow HTML. * @param int $truncate Truncate. * * @since 1.17.0 */ public static function get_postdata_excerpt( $value = '', $allow_html = true, $truncate = PHP_INT_MAX ) { if ( empty( $value ) ) { return; } $post_excerpt = forminator_truncate_text( $value, $truncate ); $label = esc_html__( 'Excerpt', 'forminator' ); if ( $allow_html ) { $value = '<hr>'; $value .= '<b>' . $label . ':</b><br>'; $value .= wp_strip_all_tags( $post_excerpt ); } else { $post_excerpt = wp_strip_all_tags( $post_excerpt ); $value = $label . ': '; $value .= $post_excerpt . ' | '; } return $value; } /** * Get the postdata categories depending on context * * @param string|array $value Value. * @param bool $allow_html Allow HTML. * * @since 1.17.0 */ public static function get_postdata_categories( $value = '', $allow_html = true ) { if ( empty( $value ) ) { return; } $post_category = $value; $the_categories = ''; $countegories = 0; $single_label = esc_html__( 'Category', 'forminator' ); if ( is_array( $post_category ) ) { foreach ( $post_category as $category ) { $categories[] = get_the_category_by_ID( $category ); } $countegories = count( $categories ); $the_categories = implode( ', ', $categories ); } else { $the_categories = get_the_category_by_ID( $post_category ); } if ( $allow_html ) { $value = '<hr>'; if ( is_array( $post_category ) ) { $value .= '<b>' . esc_html( _n( 'Category', 'Categories', $countegories, 'forminator' ) ) . ':</b> '; } else { $value .= '<b>' . $single_label . ':</b> '; } $value .= $the_categories; } else { $value = ''; $value .= $single_label . ': '; $value .= $the_categories . ' | '; } return $value; } /** * Get the postdata taxonmies depending on context * * @param string $tax_name Tax name. * @param string|array $value Value. * @param bool $allow_html Allow HTML. * * @since 1.20.0 */ public static function get_postdata_taxonomies( $tax_name, $value = '', $allow_html = true ) { if ( empty( $value ) ) { return; } $post_taxonomy = $value; $tax_obj = get_taxonomy( $tax_name ); $single_label = ''; $plural_label = ''; if ( ! empty( $tax_obj ) ) { $single_label = ! empty( $tax_obj->labels->singular_name ) ? $tax_obj->labels->singular_name : $tax_obj->labels->name; $plural_label = $tax_obj->labels->name; } $the_taxonomies = ''; $countonomies = 0; if ( is_array( $post_taxonomy ) ) { foreach ( $post_taxonomy as $taxonomy ) { if ( ! is_wp_error( get_the_category_by_ID( $taxonomy ) ) ) { $taxonomies[] = get_the_category_by_ID( $taxonomy ); } } if ( ! empty( $taxonomies ) ) { $countonomies = count( $taxonomies ); $the_taxonomies = implode( ', ', $taxonomies ); } } else { $the_taxonomies = get_the_category_by_ID( $post_taxonomy ); if ( is_wp_error( $the_taxonomies ) ) { $the_taxonomies = ''; } } if ( $allow_html ) { $value = '<hr>'; if ( is_array( $post_taxonomy ) ) { $value .= '<b>' . esc_html( _n( $single_label, $plural_label, $countonomies, 'forminator' ) ) . ':</b> '; // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralSingle, WordPress.WP.I18n.NonSingularStringLiteralPlural } else { $value .= '<b>' . $single_label . ':</b> '; } $value .= $the_taxonomies; } else { $value = ''; $value .= $single_label . ': '; $value .= $the_taxonomies . ' | '; } return $value; } /** * Get the postdata tags depending on context * * @param string|array $value Value. * @param bool $allow_html Allow HTML. * * @since 1.17.0 */ public static function get_postdata_tags( $value = '', $allow_html = true ) { if ( empty( $value ) ) { return; } $post_tags = $value; $the_tags = ''; $tags_count = 0; $term_args = array( 'taxonomy' => 'post_tag', 'term_taxonomy_id' => $post_tags, 'hide_empty' => false, 'fields' => 'names', ); $term_query = new WP_Term_Query( $term_args ); $tags = $term_query->terms; if ( ! empty( $tags ) ) { $tags_count = count( $tags ); $the_tags .= implode( ', ', $tags ); } $label = esc_html( _n( 'Tag', 'Tags', $tags_count, 'forminator' ) ); if ( $allow_html ) { $value = '<hr>'; $value .= '<b>' . $label . ':</b> '; $value .= $the_tags; } else { $value = ''; $value .= $label; $value .= $the_tags . ' | '; } return $value; } /** * Get the postdata featured image depending on context * * @param string|array $value Value. * @param bool $allow_html Allow HTML. * * @since 1.17.0 */ public static function get_postdata_image( $value = '', $allow_html = true ) { if ( empty( $value ) ) { return; } $label = esc_html__( 'Featured image', 'forminator' ) . ': '; if ( $allow_html ) { $post_image_id = $value; $value = '<hr>'; $value .= '<b>' . $label . ':</b><br>'; $value .= wp_get_attachment_image( $post_image_id, array( 100, 100 ) ); } else { $post_image_url = $value; $value = $label . ': '; $value .= $post_image_url; } return $value; } /** * Get the postdata Custom fields depending on context * * @param string|array $value Value. * @param bool $allow_html Allow HTML. * @param int $truncate Truncate. * * @since 1.17.0 */ public static function get_postdata_customfields( $value = array(), $allow_html = true, $truncate = PHP_INT_MAX ) { if ( empty( $value ) ) { return ''; } $post_custom = $value; $label = esc_html__( 'Custom fields', 'forminator' ); if ( $allow_html ) { $value = '<hr>'; $value .= '<b>' . $label . ':</b><br>'; $value .= '<ul class="' . esc_attr( 'bulleted' ) . '">'; foreach ( $post_custom as $field ) { if ( ! empty( $field['value'] ) ) { $value .= '<li>'; $value .= esc_html( $field['key'] ) . ': '; $value .= wp_kses_post( $field['value'] ); $value .= '</li>'; } } $value .= '</ul>'; } else { $value = $label . ': '; foreach ( $post_custom as $index => $field ) { if ( ! empty( $field['value'] ) ) { if ( 0 !== $index ) { $value .= ', '; } $value .= esc_html( $field['key'] ) . ' = '; $value .= esc_html( $field['value'] ); } } $value = forminator_truncate_text( $value, $truncate ); } return $value; } /** * Count all entries for all form_type */ public static function count_all_entries() { global $wpdb; $entries_cache = wp_cache_get( 'all_form_types', self::FORM_COUNT_CACHE_GROUP ); if ( $entries_cache ) { return $entries_cache; } else { $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT count(`entry_id`) FROM {$table_name} WHERE `is_spam` = %d"; $entries = $wpdb->get_var( $wpdb->prepare( $sql, 0 ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery if ( $entries ) { wp_cache_set( 'all_form_types', $entries, self::FORM_COUNT_CACHE_GROUP ); return $entries; } } return 0; } /** * Count all entries for the selected entry type * * @param string $entry_type Entry type. * * @return int * @since 1.5.4 */ public static function count_all_entries_by_type( $entry_type = 'custom-forms' ) { $available_entry_types = array( 'custom-forms', 'quizzes', 'poll', ); if ( ! in_array( $entry_type, $available_entry_types, true ) ) { return null; } global $wpdb; $entries_cache = wp_cache_get( $entry_type . '_form_type', self::FORM_COUNT_CACHE_GROUP ); if ( $entries_cache ) { return $entries_cache; } else { $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT count(`entry_id`) FROM {$table_name} WHERE `entry_type` = %s AND `is_spam` = %d"; $entries = $wpdb->get_var( $wpdb->prepare( $sql, $entry_type, 0 ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery if ( $entries ) { wp_cache_set( $entry_type . '_form_type', $entries, self::FORM_COUNT_CACHE_GROUP ); return $entries; } } return 0; } /** * Get Latest Entry * * @param string $entry_type Entry type. * * @return Forminator_Form_Entry_Model|null */ public static function get_latest_entry( $entry_type = 'custom-forms' ) { if ( 'form' === $entry_type ) { $entry_type = 'custom-forms'; } elseif ( 'quiz' === $entry_type ) { $entry_type = 'quizzes'; } $available_entry_types = array( 'custom-forms', 'quizzes', 'poll', 'all', ); if ( ! in_array( $entry_type, $available_entry_types, true ) ) { return null; } global $wpdb; $entry = null; $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); if ( 'all' !== $entry_type ) { $sql = "SELECT `entry_id` FROM {$table_name} WHERE `entry_type` = %s AND `is_spam` = 0 ORDER BY `date_created` DESC"; $sql = $wpdb->prepare( $sql, $entry_type ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } else { $sql = "SELECT `entry_id` FROM {$table_name} WHERE `is_spam` = 0 ORDER BY `date_created` DESC"; } $entry_id = $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery if ( ! empty( $entry_id ) ) { $entry = new Forminator_Form_Entry_Model( $entry_id ); } return $entry; } /** * Get Latest Entry by form_id * * @param int $form_id Form Id. * @param string $order Order by. * * @return Forminator_Form_Entry_Model|null */ public static function get_latest_entry_by_form_id( $form_id, $order = 'DESC' ) { global $wpdb; $entry = null; $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT `entry_id` FROM {$table_name} WHERE `form_id` = %d AND `is_spam` = 0 ORDER BY `date_created` {$order}"; $entry_id = $wpdb->get_var( $wpdb->prepare( $sql, $form_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery if ( ! empty( $entry_id ) ) { $entry = new Forminator_Form_Entry_Model( $entry_id ); } return $entry; } /** * Get Connected Addons for form_id, avoid overhead for checking connected addons many times * * @param int $module_id Module id. * @param string $module_slug Module slug. * * @return array|Forminator_Integration[] * @since 1.1 */ public static function get_connected_addons( $module_id, $module_slug = 'form' ) { if ( ! isset( self::$connected_addons[ $module_id ] ) ) { self::$connected_addons[ $module_id ] = array(); $connected_addons = forminator_get_addons_instance_connected_with_module( $module_id, $module_slug ); foreach ( $connected_addons as $connected_addon ) { try { $module_hooks = $connected_addon->get_addon_hooks( $module_id, $module_slug ); if ( $module_hooks instanceof Forminator_Integration_Hooks ) { self::$connected_addons[ $module_id ][] = $connected_addon; } } catch ( Exception $e ) { forminator_addon_maybe_log( $connected_addon->get_slug(), 'failed to get_addon_hooks', $e->getMessage() ); } } } return self::$connected_addons[ $module_id ]; } /** * Attach hooks for delete entry on connected addons * * @param int $form_id Form Id. * @param Forminator_Form_Entry_Model $entry_model Form entry model. * * @since 1.1 * @throws Exception When there is an error. */ public static function attach_addons_on_before_delete_entry( $form_id, Forminator_Form_Entry_Model $entry_model ) { $module_slug = 'form'; if ( ! empty( $entry_model->entry_type ) && 'poll' === $entry_model->entry_type ) { $module_slug = 'poll'; } elseif ( ! empty( $entry_model->entry_type ) && 'quizzes' === $entry_model->entry_type ) { $module_slug = 'quiz'; } $connected_addons = self::get_connected_addons( $form_id, $module_slug ); foreach ( $connected_addons as $connected_addon ) { try { $method = "get_addon_{$module_slug}_hooks"; if ( ! method_exists( $connected_addon, $method ) ) { throw new Exception( 'Method ' . $method . ' doesn\'t exist.' ); } $module_hooks = $connected_addon->$method( $form_id ); $addon_meta_data = forminator_find_addon_meta_data_from_entry_model( $connected_addon, $entry_model ); $module_hooks->on_before_delete_entry( $entry_model, $addon_meta_data ); } catch ( Exception $e ) { forminator_addon_maybe_log( $connected_addon->get_slug(), 'failed to on_before_delete_entry', $e->getMessage() ); } } } /** * Get entries by email * * @since 1.0.6 * * @param string $email Email. * * @return array */ public static function get_custom_form_entry_ids_by_email( $email ) { global $wpdb; $meta_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $sql = "SELECT m.entry_id AS entry_id FROM {$meta_table_name} m WHERE (m.meta_key LIKE %s OR m.meta_key LIKE %s) AND m.meta_value = %s GROUP BY m.entry_id"; $sql = $wpdb->prepare( $sql, // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $wpdb->esc_like( 'email-' ) . '%', $wpdb->esc_like( 'text-' ) . '%', $email ); $entry_ids = $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery return $entry_ids; } /** * Get entries older than $date_created * * @param string $date_created Created date. * @param string $entry_type Entry type. * @param int $id Id. * @param bool $is_draft Is draft. * * @return array * @since 1.0.6 */ public static function get_older_entry_ids( $date_created, $entry_type = '', $id = 0, $is_draft = false ) { global $wpdb; $where = ''; if ( $entry_type ) { $where .= $wpdb->prepare( ' AND e.entry_type = %s', $entry_type ); } if ( $id ) { $where .= $wpdb->prepare( ' AND e.form_id = %d', $id ); } // wpdb prepare needs something to substitute or else it will throw an error. if ( ! $is_draft ) { $where .= $wpdb->prepare( ' AND ( e.draft_id IS NULL OR e.draft_id = %s )', '' ); } else { $where .= $wpdb->prepare( ' AND e.draft_id IS NOT NULL AND e.draft_id != %s', '' ); } $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT e.entry_id AS entry_id FROM {$entry_table_name} e WHERE e.date_created < %s {$where}"; $sql = $wpdb->prepare( $sql, // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared esc_sql( $date_created ) ); $entry_ids = $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery return $entry_ids; } /** * Get entries newer than $date_created * * @param string $entry_type Entry type. * @param string $date_created Created date. * * @return array * @since 1.5.3 */ public static function get_newer_entry_ids( $entry_type, $date_created ) { global $wpdb; $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT e.entry_id AS entry_id FROM {$entry_table_name} e WHERE e.entry_type = %s AND e.date_created > %s"; $sql = $wpdb->prepare( $sql, // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $entry_type, esc_sql( $date_created ) ); $entry_ids = $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery return $entry_ids; } /** * Get entries newer than $date_created * * @param string $entry_type Entry type. * * @return array|object * @since 1.5.3 */ public static function get_most_entry( $entry_type ) { global $wpdb; $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT form_id, count(*) entry_count FROM {$entry_table_name} WHERE entry_type = %s GROUP BY form_id ORDER BY entry_count DESC LIMIT 1"; $most_entry = $wpdb->get_row( $wpdb->prepare( $sql, $entry_type ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery -- false positive return $most_entry; } /** * Get entries newer than $date_created of form_id * * @param int $form_id Form Id. * @param string $date_created Created date. * * @return array * @since 1.5.3 */ public static function get_newer_entry_ids_of_form_id( $form_id, $date_created ) { global $wpdb; $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT e.entry_id AS entry_id FROM {$entry_table_name} e WHERE e.form_id = %d AND e.date_created > %s"; $sql = $wpdb->prepare( $sql, // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $form_id, esc_sql( $date_created ) ); $entry_ids = $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery return $entry_ids; } /** * Get entries newer than $date_created of form_id grouped by date_created Day * * @param int $form_id Form Id. * @param string $date_created Created date. * @param string $date_end End date. * * @return array * @since 1.5.3 */ public static function get_form_latest_entries_count_grouped_by_day( $form_id, $date_created, $date_end = '' ) { global $wpdb; $end_date = ''; $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); if ( ! empty( $date_end ) ) { $date_end = $date_end . ' 23:59:00'; $end_date .= $wpdb->prepare( ' AND e.date_created <= %s ', esc_sql( $date_end ) ); } $sql = "SELECT COUNT(e.entry_id) AS entries_amount, DATE(e.date_created) AS date_created FROM {$entry_table_name} e WHERE e.form_id = %d AND e.date_created > %s {$end_date} GROUP BY DATE(e.date_created) ORDER BY e.date_created DESC"; $sql = $wpdb->prepare( $sql, // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $form_id, esc_sql( $date_created ) ); $entry_ids = $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery return $entry_ids; } /** * Get entries newer than $date_created of form_id grouped by date_created Day * * @param int $form_id Form id. * @param string $date_created Created date. * * @return array * @since 1.14 */ public static function get_form_latest_lead_entries_count_grouped_by_day( $form_id, $date_created ) { global $wpdb; $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $entry_meta_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $sql = "SELECT COUNT(e.entry_id) AS entries_amount, DATE(e.date_created) AS date_created FROM {$entry_table_name} e LEFT JOIN {$entry_meta_table_name} m ON(e.`entry_id` = m.`entry_id`) WHERE e.form_id = %d AND e.date_created > %s AND m.meta_key = 'skip_form' AND m.meta_value = '' GROUP BY DATE(e.date_created) ORDER BY e.date_created DESC"; $sql = $wpdb->prepare( $sql, // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $form_id, esc_sql( $date_created ) ); $entry_ids = $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery return $entry_ids; } /** * Update Meta * * @param int $meta_id Meta Id. * @param string $meta_key - the meta key. * @param bool|object $default_value - the default value. * @param string $date_updated Update date. * @param string $date_created Create date. * * @since 1.0.6 * @since 1.5 : add optional `$date_updated` and `$date_created` arguments */ public function update_meta( $meta_id, $meta_key, $default_value = false, $date_updated = '', $date_created = '' ) { global $wpdb; $updated_meta = array( 'entry_id' => $this->entry_id, 'meta_key' => $meta_key, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key 'meta_value' => $default_value, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value ); if ( ! empty( $date_updated ) ) { $updated_meta['date_updated'] = $date_updated; } if ( ! empty( $date_created ) ) { $updated_meta['date_created'] = $date_created; } // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $wpdb->update( $this->table_meta_name, $updated_meta, array( 'meta_id' => $meta_id, ) ); wp_cache_delete( $this->entry_id, self::FORM_ENTRY_CACHE_GROUP ); $this->get( $this->entry_id ); } /** * Custom Query entries * * @param array $args Arguments. `form_id` is required to retrieve entries. * * @return Forminator_Form_Entry_Model[] | array * @since 1.5.4 * * @since 1.40 * @param bool $get_count If true, returns an array with the keys `count` and `data`. Default: false. */ public static function query_entries( $args, $get_count = false ) { // Check if Form ID is set. if ( empty( $args['form_id'] ) ) { return array(); } $form_id = $args['form_id']; $entries = array(); $total_count = 0; $cache_count_exists = false; $cache_data_exists = false; $unique_id = md5( wp_json_encode( $args ) ); // Cached key. $cache_key = 'forminator_query_entries_' . $form_id; // Check if cached data exists. $cached_data = wp_cache_get( $cache_key, self::FORM_ENTRY_CACHE_GROUP ); if ( ! is_array( $cached_data ) ) { $cached_data = array(); } if ( isset( $cached_data[ $unique_id ] ) ) { $cache_data_exists = true; if ( ! empty( $cached_data[ $unique_id ] ) && is_array( $cached_data[ $unique_id ] ) ) { foreach ( $cached_data[ $unique_id ] as $result ) { $entries[] = new Forminator_Form_Entry_Model( $result->entry_id ); } } // Return cached entries if count not requested. if ( false === $get_count ) { return $entries; } } if ( true === $get_count ) { // Convert args array to a unique key for count. $count_args = $args; $remove_keys = array( 'order_by', 'order', 'offset', 'per_page' ); // Remove unused keys for count query. foreach ( $remove_keys as $remove_key ) { if ( isset( $count_args[ $remove_key ] ) ) { unset( $count_args[ $remove_key ] ); } } $unique_count_id = md5( wp_json_encode( $count_args ) ); $count_cache_key = 'forminator_query_entries_count_' . $form_id; // Check if cached data exists. $cached_count = wp_cache_get( $count_cache_key, self::FORM_ENTRY_CACHE_GROUP ); if ( ! is_array( $cached_count ) ) { $cached_count = array(); } if ( isset( $cached_count[ $unique_count_id ] ) ) { $cache_count_exists = true; $total_count = $cached_count[ $unique_count_id ]; } } // Return cached data if both count and data cache exists. if ( true === $cache_data_exists && true === $cache_count_exists ) { return array( 'count' => $total_count, 'data' => $entries, ); } global $wpdb; /** * $args * [ * form_id => X, * date_created=> array(), * search = '', * min_id => * max_id => * orderby => 'x', * order => 'DESC', * per_page => '10' * offset => 0 * ] */ if ( ! isset( $args['per_page'] ) ) { $args['per_page'] = 10; } if ( ! isset( $args['offset'] ) ) { $args['offset'] = 0; } if ( ! isset( $args['order'] ) ) { $args['order'] = 'DESC'; } $entries_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $entries_meta_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); // Building where. $where = 'WHERE 1=1'; // exclude Addon meta. $where .= $wpdb->prepare( ' AND metas.meta_key NOT LIKE %s', $wpdb->esc_like( 'forminator_addon_' ) . '%' ); if ( isset( $args['form_id'] ) ) { $where .= $wpdb->prepare( ' AND entries.form_id = %d', esc_sql( $args['form_id'] ) ); } if ( isset( $args['is_spam'] ) ) { $where .= $wpdb->prepare( ' AND entries.is_spam = %s', esc_sql( $args['is_spam'] ) ); } if ( isset( $args['date_created'] ) ) { $date_created = $args['date_created']; if ( is_array( $date_created ) && isset( $date_created[0] ) && isset( $date_created[1] ) ) { // hack to before nextday. // https://app.asana.com/0/385581670491499/864371485201331/f. $date_created[1] = $date_created[1] . ' 23:59:00'; $where .= $wpdb->prepare( ' AND ( entries.date_created >= %s AND entries.date_created <= %s )', esc_sql( $date_created[0] ), esc_sql( $date_created[1] ) ); } } if ( isset( $args['user_status'] ) ) { require_once __DIR__ . '/../modules/custom-forms/user/class-forminator-cform-user-signups.php'; Forminator_CForm_User_Signups::prep_signups_functionality(); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery $ids = $wpdb->get_col( "SELECT entries.entry_id FROM {$entries_meta_table_name} entries INNER JOIN {$wpdb->base_prefix}signups AS `signups` ON (entries.meta_value = `signups`.activation_key) WHERE entries.meta_key='activation_key' AND `signups`.active = 0" ); $not = 'approved' === $args['user_status'] ? ' NOT' : ''; if ( $ids ) { $where .= " AND entries.entry_id {$not} IN(" . implode( ', ', $ids ) . ')'; } } if ( isset( $args['search'] ) ) { $where .= $wpdb->prepare( ' AND metas.meta_value LIKE %s', '%' . $wpdb->esc_like( $args['search'] ) . '%' ); } if ( isset( $args['min_id'] ) ) { $where .= $wpdb->prepare( ' AND entries.entry_id >= %d', esc_sql( $args['min_id'] ) ); } if ( isset( $args['max_id'] ) ) { $where .= $wpdb->prepare( ' AND entries.entry_id <= %d', esc_sql( $args['max_id'] ) ); } if ( isset( $args['entry_status'] ) && 'completed' === $args['entry_status'] ) { $where .= $wpdb->prepare( ' AND ( entries.draft_id IS NULL OR entries.draft_id = %s )', '' ); } if ( isset( $args['entry_status'] ) && 'draft' === $args['entry_status'] ) { $where .= $wpdb->prepare( ' AND entries.draft_id IS NOT NULL AND entries.draft_id != %s', '' ); } /** * Filter where query to be used on query-ing entries * * @param string $where * @param array $args * * @since 1.5.4 */ $where = apply_filters( 'forminator_query_entries_where', $where, $args ); // group. $group_by = 'GROUP BY entries.entry_id'; /** * Filter GROUP BY query to be used on query-ing entries * * @param string $group_by * @param array $args * * @since 1.5.4 */ $group_by = apply_filters( 'forminator_query_entries_group_by', $group_by, $args ); // order. $order_by = 'ORDER BY entries.entry_id'; if ( isset( $args['order_by'] ) ) { $order_by = 'ORDER BY ' . $args['order_by']; // unesacaped. } /** * Filter ORDER BY query to be used on query-ing entries * * @param string $order_by * @param array $args * * @since 1.5.4 */ $order_by = apply_filters( 'forminator_query_entries_order_by', $order_by, $args ); $order = $args['order']; /** * Filter order (DESC/ASC) query to be used on query-ing entries * * @param string $order * @param array $args * * @since 1.5.4 */ $order = apply_filters( 'forminator_query_entries_order', $order, $args ); // limit. $limit = $wpdb->prepare( 'LIMIT %d, %d', esc_sql( $args['offset'] ), esc_sql( $args['per_page'] ) ); /** * Filter LIMIT query to be used on query-ing entries * * @param string $order * @param array $args * * @since 1.5.4 */ $limit = apply_filters( 'forminator_query_entries_limit', $limit, $args ); if ( true === $get_count && false === $cache_count_exists ) { // sql count. $sql_count = "SELECT count(DISTINCT entries.entry_id) as total_entries FROM {$entries_table_name} AS entries INNER JOIN {$entries_meta_table_name} AS metas ON (entries.entry_id = metas.entry_id) {$where} "; $sql_count = apply_filters( 'forminator_query_entries_sql_count', $sql_count, $args ); $total_count = intval( $wpdb->get_var( $sql_count ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery $cached_count[ $unique_count_id ] = $total_count; // Store the count in the cache. wp_cache_set( $count_cache_key, $cached_count, self::FORM_ENTRY_CACHE_GROUP ); } if ( false === $cache_data_exists ) { // sql. $sql = "SELECT entries.entry_id AS entry_id FROM {$entries_table_name} AS entries INNER JOIN {$entries_meta_table_name} AS metas ON (entries.entry_id = metas.entry_id) {$where} {$group_by} {$order_by} {$order} {$limit} "; $sql = apply_filters( 'forminator_query_entries_sql', $sql, $args ); $results = $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery $cached_data[ $unique_id ] = $results; // Store the result in the cache. wp_cache_set( $cache_key, $cached_data, self::FORM_ENTRY_CACHE_GROUP ); foreach ( $results as $result ) { $entries[] = new Forminator_Form_Entry_Model( $result->entry_id ); } } if ( true === $get_count ) { return array( 'count' => $total_count, 'data' => $entries, ); } return $entries; } /** * Is option limit reached * * @param int $module_id - Module ID. * @param string $field_name - Field name. * @param string $field_type - Field type. * @param array $option Option settings. * @param bool $freeze Optional. Should it save transient option for the current request or not. False by default. * @return bool */ public static function is_option_limit_reached( $module_id, $field_name, $field_type, $option, $freeze = false ) { if ( empty( $option['limit'] ) ) { return false; } $entries = self::select_count_entries_by_meta_field( $module_id, $field_name, $option['value'], $option['label'], $field_type ); if ( $option['limit'] <= $entries ) { return true; } if ( $freeze ) { /** * Filter the time interval (in seconds) after which transient option for limited Select Option for submissions in process will be expired. * * @param int $seconds Second amount. 10 by default. * @param string $module_id Module ID. */ $expiration = apply_filters( 'forminator_form_select_option_limit_interval', 10, $module_id ); do { $transient_key = 'forminator_select_option_limit_in_process' . $module_id . $field_name . $option['value'] . '_' . $entries; $is_set = set_transient( $transient_key, 1, $expiration ); } while ( ! $is_set && $entries++ ); add_filter( 'forminator_submission_success', function ( $response ) use ( $transient_key ) { delete_transient( $transient_key ); return $response; } ); add_filter( 'forminator_submission_error', function ( $response ) use ( $transient_key ) { delete_transient( $transient_key ); return $response; } ); if ( $option['limit'] <= $entries ) { return true; } } return false; } /** * Count entries of form select key and value * * @param int $form_id - the form id. * @param string $field_name - the field name. * @param string $field_value - the field value. * @param string $field_label - the field label. * @param string $option_type - Option type (multiselect|single). * * @return int - total entries * @since 1.7 */ public static function select_count_entries_by_meta_field( $form_id, $field_name, $field_value, $field_label, $option_type = 'single' ) { global $wpdb; if ( 'single' === $option_type ) { $condition = $wpdb->prepare( ' AND ( m.`meta_value` = %s OR m.`meta_value` = %s )', esc_sql( $field_value ), esc_sql( $field_label ) ); } else { // todo: change this condition to check if it's multiple one - do this, otherwise do the previous code block. $condition = $wpdb->prepare( ' AND ( m.`meta_value` LIKE %s OR m.`meta_value` LIKE %s )', '%' . $wpdb->esc_like( $field_value ) . '%', '%' . $wpdb->esc_like( $field_label ) . '%' ); } $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT count(m.`meta_id`) FROM {$table_name} m LEFT JOIN {$entry_table_name} e ON(e.`entry_id` = m.`entry_id`) WHERE e.`form_id` = %d AND m.`meta_key` = '%s' {$condition} AND ( e.draft_id IS NULL OR e.draft_id = '' ) AND e.`is_spam` = 0"; $entries = $wpdb->get_var( $wpdb->prepare( $sql, $form_id, esc_sql( $field_name ) ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery if ( ! $entries || is_wp_error( $entries ) ) { $entries = 0; } return (int) $entries; } /** * Load entry by draft_id * * @param int $draft_id - the draft id. * * @return bool|mixed * @since 1.17.0 */ public function get_entry_id_by_draft_id( $draft_id ) { global $wpdb; $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $sql = "SELECT `entry_id` FROM {$table_name} WHERE `draft_id` = %s"; $entry = $wpdb->get_row( $wpdb->prepare( $sql, $draft_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery return is_object( $entry ) ? $entry->entry_id : null; } /** * Delete previous draft * * @param string $previous_draft - draft ID of previously saved draft. * * @since 1.17.0 */ public function delete_previous_draft( $previous_draft ) { if ( ! is_null( $previous_draft ) ) { $entry_id = $this->get_entry_id_by_draft_id( $previous_draft ); if ( ! empty( $entry_id ) ) { self::delete_by_entry( $entry_id ); } } } /** * Get entries with filters * * @param int $form_id Form Id. * @param string $start_date Start date. * @param string $end_date End date. * * @return int */ public static function count_report_entries( $form_id, $start_date = '', $end_date = '' ) { // Cached key. $cache_key = 'forminator_count_report_entries_' . $form_id; $unique_key = md5( wp_json_encode( array( $start_date, $end_date ) ) ); // Get cached data. $cached_data = wp_cache_get( $cache_key, self::FORM_ENTRY_CACHE_GROUP ); if ( ! is_array( $cached_data ) ) { $cached_data = array(); } if ( isset( $cached_data[ $unique_key ] ) ) { return $cached_data[ $unique_key ]; } else { global $wpdb; $entry_count = 0; $where = 'entries.`form_id` = %d AND entries.`is_spam` = 0 AND ( `draft_id` IS NULL OR `draft_id` = "" )'; $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); $entries_meta_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $end_date = $end_date . ' 23:59:00'; if ( ! empty( $start_date ) && ! empty( $end_date ) ) { $where .= $wpdb->prepare( ' AND ( entries.date_created >= %s AND entries.date_created <= %s )', esc_sql( $start_date ), esc_sql( $end_date ) ); } $sql = "SELECT count(DISTINCT entries.`entry_id`) entry_count FROM {$table_name} entries LEFT JOIN {$entries_meta_table_name} AS metas ON (entries.entry_id = metas.entry_id) WHERE {$where}"; $result = $wpdb->get_var( $wpdb->prepare( $sql, $form_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery -- false positive if ( ! empty( $result ) ) { $entry_count = $result; } $cached_data[ $unique_key ] = $entry_count; // Store the result in the cache. wp_cache_set( $cache_key, $cached_data, self::FORM_ENTRY_CACHE_GROUP ); return $entry_count; } } /** * Payment array * * @param int $form_id Form Id. * @param string $start_date Start date. * @param string $end_date End date. * * @return array */ public static function payment_amount( $form_id, $start_date = '', $end_date = '' ) { global $wpdb; $where = ''; $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); if ( ! empty( $start_date ) && ! empty( $end_date ) ) { $end_date = $end_date . ' 23:59:00'; $where .= $wpdb->prepare( ' AND ( e.date_created >= %s AND e.date_created <= %s )', esc_sql( $start_date ), esc_sql( $end_date ) ); } $sql = "SELECT m.meta_key, m.meta_value, e.date_created FROM {$table_name} m LEFT JOIN {$entry_table_name} e ON (m.entry_id = e.entry_id) WHERE e.form_id = %d AND ( m.meta_key = 'stripe-1' || m.meta_key = 'stripe-ocs-1' || m.meta_key = 'paypal-1' ) AND m.meta_value LIKE '%4:\"mode\";s:4:\"live\"%'{$where}"; $results = $wpdb->get_results( $wpdb->prepare( $sql, $form_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery -- false positive return $results; } /** * Addon array * * @param int $form_id Form Id. * @param string $data_key Meta key name. * @param string $start_date Start date. * @param string $end_date End date. * * @return int */ public static function addons_data( $form_id, $data_key, $start_date = '', $end_date = '' ) { global $wpdb; $where = ''; $table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY_META ); $entry_table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_ENTRY ); if ( ! empty( $start_date ) && ! empty( $end_date ) ) { $end_date = $end_date . ' 23:59:00'; $where .= $wpdb->prepare( ' AND ( e.date_created >= %s AND e.date_created <= %s )', esc_sql( $start_date ), esc_sql( $end_date ) ); } $sql = "SELECT count(m.entry_id) FROM {$table_name} m LEFT JOIN {$entry_table_name} e ON (m.entry_id = e.entry_id) WHERE e.form_id = %d AND ( m.meta_key = %s ) AND m.meta_value LIKE '%:\"is_sent\";b:1;%' {$where}"; $count = $wpdb->get_var( $wpdb->prepare( $sql, $form_id, $data_key ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery -- false positive return $count; } /** * Delete form cache * * @param int $form_id Form ID. * * @return void */ public static function delete_form_entry_cache( int $form_id ): void { // Delete cache for form count. wp_cache_delete( $form_id, self::FORM_COUNT_CACHE_GROUP ); // Delete cache for payment count. wp_cache_delete( 'live_payment_count_' . $form_id, self::FORM_COUNT_CACHE_GROUP ); if ( 'forminator_polls' === get_post_type( $form_id ) ) { // Delete cache for polls entries. wp_cache_delete( 'poll_entries_' . $form_id, self::FORM_ENTRY_CACHE_GROUP ); // Delete cache for poll count. wp_cache_delete( 'forminator_count_polls_with_extra_' . $form_id, self::FORM_ENTRY_CACHE_GROUP ); } // Delete the cache for the form entries query. self::delete_form_entries_query_cache( $form_id ); // Delete the cache for the report count. wp_cache_delete( 'forminator_count_report_entries_' . $form_id, self::FORM_ENTRY_CACHE_GROUP ); // Delete the cache for counting user entries. wp_cache_delete( 'forminator_count_user_entries_' . $form_id, self::FORM_ENTRY_CACHE_GROUP ); // Delete the cache for the leads count. wp_cache_delete( 'forminator_count_leads_' . $form_id, self::FORM_ENTRY_CACHE_GROUP ); } /** * Delete form entries query cache * * @param int $form_id Form Id. * @return void */ public static function delete_form_entries_query_cache( $form_id ): void { // Delete the cache for entries. wp_cache_delete( 'forminator_query_entries_' . $form_id, self::FORM_ENTRY_CACHE_GROUP ); // Delete the cache for entries count. wp_cache_delete( 'forminator_query_entries_count_' . $form_id, self::FORM_ENTRY_CACHE_GROUP ); } } class-form-views-model.php 0000644 00000012710 15162406305 0011557 0 ustar 00 <?php /** * The Forminator_Form_Views_Model class. * * @package Forminator */ /** * Form Views * Handles conversions and views of the different forms */ class Forminator_Form_Views_Model { /** * The table name * * @var string */ protected $table_name; /** * Plugin instance * * @var null */ private static $instance = null; /** * Return the plugin instance * * @since 1.0 * @return Forminator_Form_Views_Model */ public static function get_instance() { if ( is_null( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Forminator_Form_Views_Model constructor. * * @since 1.0 */ public function __construct() { $this->table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_VIEWS ); } /** * Save conversion * * @since 1.0 * @param int $form_id - the form id. * @param int $page_id - the page id. */ public function save_view( $form_id, $page_id ) { global $wpdb; $sql = "SELECT `view_id` FROM {$this->get_table_name()} WHERE `form_id` = %d AND `page_id` = %d AND DATE(`date_created`) = CURDATE()"; $view_id = $wpdb->get_var( $wpdb->prepare( $sql, $form_id, $page_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery if ( $view_id ) { $this->_update( $view_id, $wpdb ); } else { $this->_save( $form_id, $page_id, $wpdb ); } } /** * Save Data to database * * @param int $form_id - the form id. * @param int $page_id - the page id. * @param bool|object $db - the wp db object. */ private function _save( $form_id, $page_id, $db = false ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore if ( ! $db ) { global $wpdb; $db = $wpdb; } $db->insert( $this->table_name, array( 'form_id' => $form_id, 'page_id' => $page_id, 'date_created' => date_i18n( 'Y-m-d H:i:s' ), ) ); } /** * Update view * * @since 1.0 * @param int $id - entry id. * @param bool|object $db - the wp db object. */ private function _update( $id, $db = false ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore if ( ! $db ) { global $wpdb; $db = $wpdb; } $db->query( $db->prepare( "UPDATE {$this->get_table_name()} SET `count` = `count`+1, `date_updated` = now() WHERE `view_id` = %d", $id ) ); } /** * Count views * * @since 1.0 * @param int $form_id - the form id. * @param string $starting_date - the start date (dd-mm-yyy). * @param string $ending_date - the end date (dd-mm-yyy). * * @return int - totol views based on parameters */ public function count_views( $form_id, $starting_date = null, $ending_date = null ) { return $this->_count( $form_id, $starting_date, $ending_date ); } /** * Delete views by form * * @since 1.0 * @param int $form_id - the form id. */ public function delete_by_form( $form_id ) { global $wpdb; $sql = "DELETE FROM {$this->get_table_name()} WHERE `form_id` = %d"; $wpdb->query( $wpdb->prepare( $sql, $form_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery } /** * Count data * * @since 1.0 * @param int $form_id - the form id. * @param string $starting_date - the start date (dd-mm-yyy). * @param string $ending_date - the end date (dd-mm-yyy). * * @return int - totol counts based on parameters */ private function _count( $form_id, $starting_date = null, $ending_date = null ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore global $wpdb; $date_query = $this->generate_date_query( $wpdb, $starting_date, $ending_date ); $sql = "SELECT SUM(`count`) FROM {$this->get_table_name()} WHERE `form_id` = %d $date_query"; $counts = $wpdb->get_var( $wpdb->prepare( $sql, $form_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery if ( $counts ) { return $counts; } return 0; } /** * Generate the date query * * @since 1.0 * @param object $wpdb - the WordPress database object. * @param string $starting_date - the start date (dd-mm-yyy). * @param string $ending_date - the end date (dd-mm-yyy). * @param string $prefix Prefix. * @param string $clause Clause. * * @return string $date_query */ private function generate_date_query( $wpdb, $starting_date = null, $ending_date = null, $prefix = '', $clause = 'AND' ) { $date_query = ''; if ( ! is_null( $starting_date ) && ! is_null( $ending_date ) && ! empty( $starting_date ) && ! empty( $ending_date ) ) { $ending_date = $ending_date . ' 23:59:00'; $date_query = $wpdb->prepare( "$clause date_created >= %s AND date_created <= %s", $starting_date, $ending_date ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared } elseif ( ! is_null( $starting_date ) && ! empty( $starting_date ) ) { $date_query = $wpdb->prepare( "$clause date_created >= %s", $starting_date ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared } elseif ( ! is_null( $ending_date ) && ! empty( $ending_date ) ) { $date_query = $wpdb->prepare( "$clause date_created <= %s", $starting_date ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared } return $date_query; } /** * Return views table name * * @since 1.6.3 * * @return string */ public function get_table_name() { return Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_VIEWS ); } } class-form-reports-model.php 0000644 00000013515 15162406306 0012125 0 ustar 00 <?php /** * The Forminator_Form_Reports_Model class. * * Author: Hoang Ngo * * @package Forminator */ /** * Form Reports */ class Forminator_Form_Reports_Model { /** * The table name * * @var string */ protected $table_name; /** * Plugin instance * * @var null */ private static $instance = null; /** * Return the plugin instance * * @return Forminator_Form_Views_Model * @since 1.0 */ public static function get_instance() { if ( is_null( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Forminator_Form_Reports_Model constructor. * * @since 1.0 */ public function __construct() { $this->table_name = Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_REPORTS ); } /** * Save reports to database * * @param mixed $report Report. * @param string $status Status. * * @return int */ public function report_save( $report, $status ) { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $wpdb->insert( $this->table_name, array( 'report_value' => maybe_serialize( $report ), 'status' => $status, 'date_created' => date_i18n( 'Y-m-d H:i:s' ), 'date_updated' => date_i18n( 'Y-m-d H:i:s' ), ) ); return $wpdb->insert_id; } /** * Update report * * @param int $report_id Report Id. * @param mixed $report Report. * @param string $status Status. * * @return bool|int|mysqli_result|resource|null */ public function report_update( $report_id, $report, $status ) { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery return $wpdb->update( $this->get_table_name(), array( 'report_value' => maybe_serialize( $report ), 'status' => $status, 'date_updated' => date_i18n( 'Y-m-d H:i:s' ), ), array( 'report_id' => $report_id, ) ); } /** * Update report data * * @param int $report_id Report Id. * * @return bool|int|mysqli_result|resource|null */ public function report_update_date( $report_id ) { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery return $wpdb->update( $this->get_table_name(), array( 'date_updated' => date_i18n( 'Y-m-d H:i:s' ), ), array( 'report_id' => $report_id, ) ); } /** * Delete Report * * @param int $report_id Report Id. * * @return bool|int|mysqli_result|resource|null */ public function report_delete( $report_id ) { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $result = $wpdb->delete( $this->get_table_name(), array( 'report_id' => $report_id, ) ); if ( ! is_wp_error( $result ) ) { /** * Fires after report status update * * @param string $report_id Report ID. * * @since 1.27.0 */ do_action( 'forminator_after_notification_delete', $report_id ); } return $result; } /** * Load all report data * * @param int $id Id. * * @since 1.20.0 */ public function fetch_all_report( $id = 0 ) { global $wpdb; $table_name = $this->get_table_name(); $results = $wpdb->get_results( 'SELECT * FROM ' . esc_sql( $table_name ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery return $results; } /** * Load reports data by id * * @param int $id Id. * * @return array|object|stdClass[]|null */ public function fetch_report_by_id( $id ) { global $wpdb; $table_name = $this->get_table_name(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $results = $wpdb->get_row( $wpdb->prepare( 'SELECT report_id, report_value, status FROM ' . esc_sql( $table_name ) . ' WHERE report_id = %d', $id ) ); return $results; } /** * Update report status * * @param int $report_id Report Id. * @param string $status Status. * * @return bool|int|mysqli_result|resource|null */ public function report_update_status( $report_id, $status ) { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $result = $wpdb->update( $this->get_table_name(), array( 'status' => $status, ), array( 'report_id' => $report_id, ) ); if ( ! is_wp_error( $result ) ) { /** * Fires after report status update * * @param string $report_id Report ID. * @param string $status Report status. * * @since 1.27.0 */ do_action( 'forminator_after_notification_status_update', $report_id, $status ); } return $result; } /** * Return report table name * * @return string * @since 1.20.0 */ public function get_table_name() { return Forminator_Database_Tables::get_table_name( Forminator_Database_Tables::FORM_REPORTS ); } /** * Insert default report entry * * @since 1.20.0 */ public function default_report_entry() { $current_user = wp_get_current_user(); if ( empty( $current_user->ID ) ) { $current_user = get_userdata( 1 ); } $get_default = get_option( 'forminator_default_report_entry', false ); if ( ! $get_default ) { $reports = array( 'exclude' => ! empty( $current_user->ID ) ? array( $current_user->ID ) : array( 1 ), 'settings' => array( 'label' => 'Form reports', 'module' => 'forms', 'forms_type' => 'all', ), 'schedule' => array( 'frequency' => 'monthly', 'monthDay' => '4', 'monthTime' => '04:00 AM', ), 'report_status' => 'inactive', 'recipients' => array( array( 'id' => $current_user->ID, 'name' => $current_user->display_name, 'email' => $current_user->user_email, 'role' => empty( $current_user->roles ) ? null : ucfirst( $current_user->roles[0] ), 'avatar' => get_avatar_url( $current_user->user_email ), ), ), ); $this->report_save( $reports, 'inactive' ); update_option( 'forminator_default_report_entry', true ); } } }