abilities
2 weeks ago
admin
1 month ago
ai-form-builder
2 weeks ago
blocks
1 month ago
compatibility
3 weeks ago
database
3 weeks ago
email
3 months ago
fields
3 weeks ago
global-settings
2 weeks ago
lib
2 weeks ago
migrator
3 weeks ago
page-builders
3 weeks ago
payments
2 weeks ago
single-form-settings
1 month ago
traits
1 month ago
activator.php
1 year ago
admin-ajax.php
3 weeks ago
background-process.php
8 months ago
create-new-form.php
2 months ago
duplicate-form.php
1 month ago
entries.php
3 weeks ago
events-scheduler.php
2 years ago
export.php
1 month ago
field-validation.php
2 weeks ago
form-restriction.php
1 month ago
form-styling.php
3 months ago
form-submit.php
3 weeks ago
forms-data.php
3 months ago
frontend-assets.php
2 weeks ago
generate-form-markup.php
3 weeks ago
gutenberg-hooks.php
1 month ago
helper.php
3 weeks ago
learn.php
3 months ago
onboarding.php
1 month ago
post-types.php
1 month ago
rest-api.php
2 weeks ago
smart-tags.php
2 months ago
submit-token.php
3 months ago
translatable.php
2 weeks ago
updater-callbacks.php
1 year ago
updater.php
1 year ago
form-restriction.php
288 lines
| 1 | <?php |
| 2 | /** |
| 3 | * Create new Form with Template and return the form ID. |
| 4 | * |
| 5 | * @package sureforms. |
| 6 | * @since 1.10.1 |
| 7 | */ |
| 8 | |
| 9 | namespace SRFM\Inc; |
| 10 | |
| 11 | use SRFM\Inc\Compatibility\Multilingual\String_Translator; |
| 12 | use SRFM\Inc\Database\Tables\Entries; |
| 13 | use SRFM\Inc\Traits\Get_Instance; |
| 14 | |
| 15 | if ( ! defined( 'ABSPATH' ) ) { |
| 16 | exit; // Exit if accessed directly. |
| 17 | } |
| 18 | |
| 19 | /** |
| 20 | * Create New Form. |
| 21 | * |
| 22 | * @since 1.10.1 |
| 23 | */ |
| 24 | class Form_Restriction { |
| 25 | use Get_Instance; |
| 26 | |
| 27 | /** |
| 28 | * Get the restriction settings for a given form. |
| 29 | * |
| 30 | * @param int $form_id The ID of the form. |
| 31 | * @since 1.10.1 |
| 32 | * @return array Associative array of restriction settings or empty array if invalid. |
| 33 | */ |
| 34 | public static function get_form_restriction_setting( $form_id ) { |
| 35 | // Validate the form ID. Must be numeric and non-empty. |
| 36 | if ( empty( $form_id ) || ! is_int( $form_id ) ) { |
| 37 | return []; |
| 38 | } |
| 39 | |
| 40 | // Get the raw restriction meta. |
| 41 | $form_restriction_meta = get_post_meta( $form_id, '_srfm_form_restriction', true ); |
| 42 | |
| 43 | if ( empty( $form_restriction_meta ) || ! is_string( $form_restriction_meta ) ) { |
| 44 | return []; |
| 45 | } |
| 46 | |
| 47 | // Decode the meta to an array. |
| 48 | $form_restriction = json_decode( $form_restriction_meta, true ); |
| 49 | |
| 50 | // Ensure it's a valid array. |
| 51 | return is_array( $form_restriction ) ? $form_restriction : []; |
| 52 | } |
| 53 | |
| 54 | /** |
| 55 | * Check if the form has reached the entry limit. |
| 56 | * |
| 57 | * @param int $form_id The ID of the form. |
| 58 | * @since 1.10.1 |
| 59 | * @return bool True if form is restricted, false otherwise. |
| 60 | */ |
| 61 | public static function is_form_restricted( $form_id ) { |
| 62 | |
| 63 | if ( empty( $form_id ) || ! is_int( $form_id ) ) { |
| 64 | return false; // Invalid form ID. |
| 65 | } |
| 66 | |
| 67 | // Check for instant fom preview mode. |
| 68 | $srfm_live_mode_data = Helper::get_instant_form_live_data(); |
| 69 | |
| 70 | // Skip check in live mode. |
| 71 | if ( |
| 72 | ! empty( $srfm_live_mode_data ) && |
| 73 | is_array( $srfm_live_mode_data ) && |
| 74 | isset( $srfm_live_mode_data['live_mode'] ) |
| 75 | ) { |
| 76 | return false; // Skip check in live mode. |
| 77 | } |
| 78 | |
| 79 | // Get parsed restriction settings. |
| 80 | $form_restriction = self::get_form_restriction_setting( $form_id ); |
| 81 | |
| 82 | // If the form restriction is empty or not an array, or if the status is not set, return false. |
| 83 | if ( empty( $form_restriction ) || ! is_array( $form_restriction ) || empty( $form_restriction['status'] ) ) { |
| 84 | // Check for form scheduling even if entry restriction is not enabled. |
| 85 | $is_outside_schedule = self::is_form_outside_schedule( $form_restriction ); |
| 86 | return apply_filters( 'srfm_is_form_restricted', $is_outside_schedule, $form_id, $form_restriction, false, false, $is_outside_schedule ); |
| 87 | } |
| 88 | |
| 89 | $has_entries_limit_reached = self::has_entries_limit_reached( $form_id, $form_restriction ); |
| 90 | $scheduling_state = self::get_form_scheduling_state( $form_restriction ); |
| 91 | $is_outside_schedule = 'not_started' === $scheduling_state || 'ended' === $scheduling_state; |
| 92 | |
| 93 | $conversational_form = get_post_meta( $form_id, '_srfm_conversational_form', true ); |
| 94 | $is_conversational_form_enabled = is_array( $conversational_form ) && isset( $conversational_form['is_cf_enabled'] ) ? $conversational_form['is_cf_enabled'] : false; |
| 95 | if ( ( $has_entries_limit_reached || $is_outside_schedule ) && $is_conversational_form_enabled ) { |
| 96 | add_filter( 'srfm_show_conversational_form_footer', '__return_false' ); |
| 97 | } |
| 98 | |
| 99 | /** |
| 100 | * If the form has reached the entries limit or is outside schedule, return true. |
| 101 | * |
| 102 | * @since 1.10.1 |
| 103 | */ |
| 104 | return apply_filters( |
| 105 | 'srfm_is_form_restricted', |
| 106 | $has_entries_limit_reached || $is_outside_schedule, |
| 107 | $form_id, |
| 108 | $form_restriction, |
| 109 | $has_entries_limit_reached, |
| 110 | false, // Deprecated: $has_time_limit_reached - now handled by scheduling. |
| 111 | $is_outside_schedule |
| 112 | ); |
| 113 | } |
| 114 | |
| 115 | /** |
| 116 | * Check if the entries limit has been reached for a given form. |
| 117 | * |
| 118 | * @param int $form_id The ID of the form. |
| 119 | * @param array<string, mixed> $form_restriction The form restriction settings. |
| 120 | * @since 1.10.1 |
| 121 | * @return bool True if the entries limit is reached, false otherwise. |
| 122 | */ |
| 123 | public static function has_entries_limit_reached( $form_id, $form_restriction = [] ) { |
| 124 | |
| 125 | if ( ! isset( $form_restriction['maxEntries'] ) || ! is_int( $form_restriction['maxEntries'] ) ) { |
| 126 | return false; // Invalid form ID or restriction settings. |
| 127 | } |
| 128 | |
| 129 | $max_entries = $form_restriction['maxEntries']; |
| 130 | $entries_count = Entries::get_total_entries_by_status( 'all', $form_id ); |
| 131 | |
| 132 | if ( ! is_int( $entries_count ) ) { |
| 133 | $entries_count = 0; // Ensure entries count is a non-negative integer. |
| 134 | } |
| 135 | |
| 136 | /** |
| 137 | * Filter the count of entries used to evaluate the Maximum Number of Entries |
| 138 | * cap. Allows extensions (e.g. SureForms Pro's Recurring Entry Limit) to |
| 139 | * substitute a window-scoped count — entries since the start of today / |
| 140 | * the current week / month / year — in place of the lifetime count. |
| 141 | * |
| 142 | * Returning a value greater than `$entries_count` will trip the cap sooner; |
| 143 | * returning a smaller value will defer it. Non-integer return values are |
| 144 | * coerced back to a non-negative integer. |
| 145 | * |
| 146 | * @param int $entries_count Lifetime entry count for the form. |
| 147 | * @param int $form_id The ID of the form. |
| 148 | * @param array<string, mixed> $form_restriction The form restriction settings. |
| 149 | * @since 2.8.2 |
| 150 | */ |
| 151 | $entries_count = apply_filters( 'srfm_form_restriction_entries_count', $entries_count, $form_id, $form_restriction ); |
| 152 | |
| 153 | // Always coerce to a non-negative integer — covers both non-int returns |
| 154 | // from a misbehaving extension AND negative-int returns that would |
| 155 | // otherwise silently disable the cap (e.g. -5 >= 100 is false). |
| 156 | $entries_count = max( 0, (int) $entries_count ); |
| 157 | |
| 158 | return $entries_count >= $max_entries; |
| 159 | } |
| 160 | |
| 161 | /** |
| 162 | * Check if the form is outside its scheduled time period. |
| 163 | * |
| 164 | * @param array<string, mixed> $form_restriction The form restriction settings. |
| 165 | * @since 2.4.0 |
| 166 | * @return bool True if form is outside schedule, false otherwise. |
| 167 | */ |
| 168 | public static function is_form_outside_schedule( $form_restriction ) { |
| 169 | $scheduling_state = self::get_form_scheduling_state( $form_restriction ); |
| 170 | return 'not_started' === $scheduling_state || 'ended' === $scheduling_state; |
| 171 | } |
| 172 | |
| 173 | /** |
| 174 | * Get the appropriate restriction message based on scheduling state. |
| 175 | * |
| 176 | * @param string $scheduling_state The scheduling state ('not_started', 'ended', 'active', or 'disabled'). |
| 177 | * @param array<string, mixed> $form_restriction The form restriction settings. |
| 178 | * @since 2.4.0 |
| 179 | * @return string The appropriate restriction message. |
| 180 | */ |
| 181 | public static function get_restriction_message_by_state( $scheduling_state, $form_restriction ) { |
| 182 | if ( 'not_started' === $scheduling_state ) { |
| 183 | $message = $form_restriction['schedulingNotStartedMessage'] ?? __( 'This form is not yet available. Check back after the scheduled start time.', 'sureforms' ); |
| 184 | return is_string( $message ) ? $message : __( 'This form is not yet available. Check back after the scheduled start time.', 'sureforms' ); |
| 185 | } |
| 186 | |
| 187 | if ( 'ended' === $scheduling_state ) { |
| 188 | $message = $form_restriction['schedulingEndedMessage'] ?? __( 'This form is no longer accepting submissions. The submission period has ended.', 'sureforms' ); |
| 189 | return is_string( $message ) ? $message : __( 'This form is no longer accepting submissions. The submission period has ended.', 'sureforms' ); |
| 190 | } |
| 191 | |
| 192 | // Default to entry limit message. |
| 193 | $message = $form_restriction['message'] ?? Translatable::get_default_form_restriction_message(); |
| 194 | return is_string( $message ) ? $message : Translatable::get_default_form_restriction_message(); |
| 195 | } |
| 196 | |
| 197 | /** |
| 198 | * Get the scheduling state for a form. |
| 199 | * |
| 200 | * @param array<string, mixed> $form_restriction The form restriction settings. |
| 201 | * @since 2.4.0 |
| 202 | * @return string 'not_started', 'ended', 'active', or 'disabled'. |
| 203 | */ |
| 204 | public static function get_form_scheduling_state( $form_restriction ) { |
| 205 | $scheduling_status = $form_restriction['schedulingStatus'] ?? false; |
| 206 | |
| 207 | // Start date/time. |
| 208 | $start_date = $form_restriction['startDate'] ?? ''; |
| 209 | $start_hours = Helper::get_string_value( $form_restriction['startHours'] ?? '12' ); |
| 210 | $start_minutes = Helper::get_string_value( $form_restriction['startMinutes'] ?? '00' ); |
| 211 | $start_meridiem = Helper::get_string_value( $form_restriction['startMeridiem'] ?? 'AM' ); |
| 212 | |
| 213 | // End date/time. |
| 214 | $end_date = $form_restriction['date'] ?? ''; |
| 215 | $end_hours = Helper::get_string_value( $form_restriction['hours'] ?? '12' ); |
| 216 | $end_minutes = Helper::get_string_value( $form_restriction['minutes'] ?? '00' ); |
| 217 | $end_meridiem = Helper::get_string_value( $form_restriction['meridiem'] ?? 'PM' ); |
| 218 | |
| 219 | $dt = new \DateTime( 'now', wp_timezone() ); |
| 220 | $current_timestamp = $dt->getTimestamp(); |
| 221 | |
| 222 | // Check if before start time (only if scheduling is enabled). |
| 223 | if ( $scheduling_status && ! empty( $start_date ) && is_string( $start_date ) ) { |
| 224 | $start_timestamp = Helper::get_timestamp_from_string( $start_date, $start_hours, $start_minutes, $start_meridiem ); |
| 225 | |
| 226 | if ( false !== $start_timestamp && is_int( $start_timestamp ) && $current_timestamp < $start_timestamp ) { |
| 227 | return 'not_started'; |
| 228 | } |
| 229 | } |
| 230 | |
| 231 | // Check if after end time (works for both scheduling and simple time limit). |
| 232 | if ( $scheduling_status && ! empty( $end_date ) && is_string( $end_date ) ) { |
| 233 | $end_timestamp = Helper::get_timestamp_from_string( $end_date, $end_hours, $end_minutes, $end_meridiem ); |
| 234 | |
| 235 | if ( false !== $end_timestamp && is_int( $end_timestamp ) && $current_timestamp > $end_timestamp ) { |
| 236 | return 'ended'; |
| 237 | } |
| 238 | } |
| 239 | |
| 240 | // If scheduling is disabled but we haven't passed the end date, return 'disabled'. |
| 241 | // If scheduling is enabled and we're within the window, return 'active'. |
| 242 | return $scheduling_status ? 'active' : 'disabled'; |
| 243 | } |
| 244 | |
| 245 | /** |
| 246 | * Display the form restriction message. |
| 247 | * |
| 248 | * @param int $form_id The ID of the form. |
| 249 | * @since 1.10.1 |
| 250 | * @return string|false The HTML markup for the restriction message or false if no restriction is set. |
| 251 | */ |
| 252 | public static function display_form_restriction_message( $form_id ) { |
| 253 | // Get parsed restriction settings. |
| 254 | $form_restriction = self::get_form_restriction_setting( $form_id ); |
| 255 | |
| 256 | // Get the scheduling state and appropriate message. |
| 257 | $scheduling_state = self::get_form_scheduling_state( $form_restriction ); |
| 258 | $form_restriction_message = self::get_restriction_message_by_state( $scheduling_state, $form_restriction ); |
| 259 | |
| 260 | // Translate the restriction message via the active multilingual provider |
| 261 | // (no-op when no WPML/Polylang is installed). |
| 262 | $form_restriction_message = String_Translator::get_instance()->translate_restriction_message( (int) $form_id, $form_restriction_message ); |
| 263 | |
| 264 | $form_restriction_message = apply_filters( 'srfm_form_restriction_message', $form_restriction_message, $form_id, $form_restriction ); |
| 265 | |
| 266 | ob_start(); |
| 267 | ?> |
| 268 | <div class="srfm-form-container srfm-form-restriction-wrapper"> |
| 269 | <div class="srfm-form-restriction-message" role="alert" aria-live="assertive"> |
| 270 | <span class="srfm-form-restriction-icon" aria-hidden="true"> |
| 271 | <?php |
| 272 | echo wp_kses( |
| 273 | Helper::fetch_svg( 'instant-form-warning', 'srfm-form-restriction-icon', 'aria-hidden="true"' ), |
| 274 | Helper::$allowed_tags_svg |
| 275 | ); |
| 276 | ?> |
| 277 | </span> |
| 278 | <p class="srfm-form-restriction-text"> |
| 279 | <?php echo esc_html( $form_restriction_message ); ?> |
| 280 | </p> |
| 281 | </div> |
| 282 | </div> |
| 283 | <?php |
| 284 | return ob_get_clean(); |
| 285 | } |
| 286 | |
| 287 | } |
| 288 |