| @@ -7,8 +7,10 @@ | ||
| 7 | 7 | */ |
| 8 | 8 | |
| 9 | 9 | namespace SRFM\Inc\Fields; |
| 10 | 10 | |
| 11 | +use SRFM\Inc\Helper; | |
| 12 | + | |
| 11 | 13 | if ( ! defined( 'ABSPATH' ) ) { |
| 12 | 14 | exit; // Exit if accessed directly. |
| 13 | 15 | } |
| 14 | 16 | |
| @@ -17,9 +19,8 @@ | ||
| 17 | 19 | * |
| 18 | 20 | * @since 0.0.1 |
| 19 | 21 | */ |
| 20 | 22 | class Phone_Markup extends Base { |
| 21 | - | |
| 22 | 23 | /** |
| 23 | 24 | * Stores the boolean string indicating if the country should be automatically determined. |
| 24 | 25 | * |
| 25 | 26 | * @var string |
| @@ -27,8 +28,48 @@ | ||
| 27 | 28 | */ |
| 28 | 29 | protected $auto_country; |
| 29 | 30 | |
| 30 | 31 | /** |
| 32 | + * Stores the default country code when auto country is disabled. | |
| 33 | + * | |
| 34 | + * @var string | |
| 35 | + * @since 1.12.1 | |
| 36 | + */ | |
| 37 | + protected $default_country; | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * Enable country filter toggle. | |
| 41 | + * | |
| 42 | + * @var bool | |
| 43 | + * @since 2.3.0 | |
| 44 | + */ | |
| 45 | + protected $enable_country_filter; | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * Country filter type (include or exclude). | |
| 49 | + * | |
| 50 | + * @var string | |
| 51 | + * @since 2.3.0 | |
| 52 | + */ | |
| 53 | + protected $country_filter_type; | |
| 54 | + | |
| 55 | + /** | |
| 56 | + * Array of country codes to include. | |
| 57 | + * | |
| 58 | + * @var array | |
| 59 | + * @since 2.3.0 | |
| 60 | + */ | |
| 61 | + protected $include_countries; | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * Array of country codes to exclude. | |
| 65 | + * | |
| 66 | + * @var array | |
| 67 | + * @since 2.3.0 | |
| 68 | + */ | |
| 69 | + protected $exclude_countries; | |
| 70 | + | |
| 71 | + /** | |
| 31 | 72 | * Initialize the properties based on block attributes. |
| 32 | 73 | * |
| 33 | 74 | * @param array<mixed> $attributes Block attributes. |
| 34 | 75 | * @since 0.0.2 |
| @@ -36,10 +77,43 @@ | ||
| 36 | 77 | public function __construct( $attributes ) { |
| 37 | 78 | $this->set_properties( $attributes ); |
| 38 | 79 | $this->set_input_label( __( 'Phone', 'sureforms' ) ); |
| 39 | 80 | $this->set_error_msg( $attributes, 'srfm_phone_block_required_text' ); |
| 40 | - $this->slug = 'phone'; | |
| 41 | - $this->auto_country = isset( $attributes['autoCountry'] ) ? $attributes['autoCountry'] : ''; | |
| 81 | + $this->set_duplicate_msg( $attributes, 'srfm_phone_block_unique_text' ); | |
| 82 | + $this->slug = 'phone'; | |
| 83 | + $this->auto_country = $attributes['autoCountry'] ?? ''; | |
| 84 | + $this->default_country = $attributes['defaultCountry'] ?? ''; | |
| 85 | + $this->enable_country_filter = $attributes['enableCountryFilter'] ?? false; | |
| 86 | + $this->country_filter_type = $attributes['countryFilterType'] ?? 'include'; | |
| 87 | + $this->include_countries = $attributes['includeCountries'] ?? []; | |
| 88 | + $this->exclude_countries = $attributes['excludeCountries'] ?? []; | |
| 89 | + | |
| 90 | + // When auto country is enabled, resolve a best-effort country here at render | |
| 91 | + // time to seed the baked `default-country` attribute (a sensible flag before | |
| 92 | + // any JS runs). The authoritative per-visitor detection happens client-side: | |
| 93 | + // phone.js applies an immediate network-free Intl guess and then refines it | |
| 94 | + // from the same-origin geo-country REST endpoint — so it stays correct even on | |
| 95 | + // full-page-cached sites, where this baked value would otherwise be the first | |
| 96 | + // visitor's country. | |
| 97 | + // | |
| 98 | + // Why not get_locale()? | |
| 99 | + // WordPress get_locale() returns the *site's* configured language (e.g. 'en_US'), | |
| 100 | + // not the visitor's physical location. A site set to English would show 'US' for | |
| 101 | + // every visitor worldwide — defeating the purpose of auto-country detection. | |
| 102 | + // | |
| 103 | + // Why resolve server-side at all (vs. a browser geo-IP fetch)? | |
| 104 | + // A client-side fetch('https://ipapi.co/json') caused CORS failures, 429 rate | |
| 105 | + // limits on high-traffic sites, and exposed visitor IPs to a third party from the | |
| 106 | + // browser. The server path (CDN header first, then a capped, cached ipapi.co | |
| 107 | + // lookup in Helper::get_geo_country()) avoids all three. | |
| 108 | + if ( $this->auto_country ) { | |
| 109 | + // Pass the configured default as the fallback so a detection failure | |
| 110 | + // degrades to the user's chosen country instead of a hardcoded 'us'. | |
| 111 | + $fallback = ! empty( $this->default_country ) && is_string( $this->default_country ) | |
| 112 | + ? strtolower( $this->default_country ) | |
| 113 | + : 'us'; | |
| 114 | + $this->default_country = Helper::get_geo_country( $fallback ); | |
| 115 | + } | |
| 42 | 116 | $this->set_unique_slug(); |
| 43 | 117 | $this->set_field_name( $this->unique_slug ); |
| 44 | 118 | $this->set_markup_properties( $this->input_label, true ); |
| 45 | 119 | $this->set_aria_described_by(); |
| @@ -49,9 +123,9 @@ | ||
| 49 | 123 | /** |
| 50 | 124 | * Render the sureforms phone classic styling |
| 51 | 125 | * |
| 52 | 126 | * @since 0.0.2 |
| 53 | - * @return string|boolean | |
| 127 | + * @return string|bool | |
| 54 | 128 | */ |
| 55 | 129 | public function markup() { |
| 56 | 130 | ob_start(); ?> |
| 57 | 131 | <div data-block-id="<?php echo esc_attr( $this->block_id ); ?>" class="srfm-block-single srfm-block srfm-<?php echo esc_attr( $this->slug ); ?>-block srf-<?php echo esc_attr( $this->slug ); ?>-<?php echo esc_attr( $this->block_id ); ?>-block<?php echo esc_attr( $this->block_width ); ?><?php echo esc_attr( $this->class_name ); ?> <?php echo esc_attr( $this->conditional_class ); ?>"> |
| @@ -57,16 +131,37 @@ | ||
| 57 | 131 | <div data-block-id="<?php echo esc_attr( $this->block_id ); ?>" class="srfm-block-single srfm-block srfm-<?php echo esc_attr( $this->slug ); ?>-block srf-<?php echo esc_attr( $this->slug ); ?>-<?php echo esc_attr( $this->block_id ); ?>-block<?php echo esc_attr( $this->block_width ); ?><?php echo esc_attr( $this->class_name ); ?> <?php echo esc_attr( $this->conditional_class ); ?>"> |
| 58 | 132 | <?php echo wp_kses_post( $this->label_markup ); ?> |
| 59 | 133 | <?php echo wp_kses_post( $this->help_markup ); ?> |
| 60 | 134 | <div class="srfm-block-wrap"> |
| 61 | - <input type="tel" class="srfm-input-common srfm-input-<?php echo esc_attr( $this->slug ); ?>" name="<?php echo esc_attr( $this->field_name ); ?>" id="<?php echo esc_attr( $this->unique_slug ); ?>" | |
| 62 | - <?php echo ! empty( $this->aria_described_by ) ? "aria-describedby='" . esc_attr( trim( $this->aria_described_by ) ) . "'" : ''; ?> | |
| 63 | - aria-required="<?php echo esc_attr( $this->aria_require_attr ); ?>" auto-country="<?php echo esc_attr( $this->auto_country ? 'true' : 'false' ); ?>" value="" <?php echo wp_kses_post( $this->placeholder_attr ); ?>> | |
| 135 | + <input type="tel" | |
| 136 | + class="srfm-input-common srfm-input-<?php echo esc_attr( $this->slug ); ?>" | |
| 137 | + name="<?php echo esc_attr( $this->field_name ); ?>" | |
| 138 | + id="<?php echo esc_attr( $this->unique_slug ); ?>" | |
| 139 | + <?php echo ! empty( $this->aria_described_by ) ? "aria-describedby='" . esc_attr( trim( $this->aria_described_by ) ) . "'" : ''; ?> | |
| 140 | + data-required="<?php echo esc_attr( $this->data_require_attr ); ?>" | |
| 141 | + aria-required="<?php echo esc_attr( $this->data_require_attr ); ?>" | |
| 142 | + default-country="<?php echo esc_attr( $this->default_country ); ?>" | |
| 143 | + <?php if ( $this->auto_country ) { ?> | |
| 144 | + data-auto-country="true" | |
| 145 | + <?php } ?> | |
| 146 | + <?php if ( $this->enable_country_filter ) { ?> | |
| 147 | + data-enable-country-filter="true" | |
| 148 | + data-country-filter-type="<?php echo esc_attr( $this->country_filter_type ); ?>" | |
| 149 | + <?php if ( 'include' === $this->country_filter_type && ! empty( $this->include_countries ) ) { ?> | |
| 150 | + data-include-countries="<?php echo esc_attr( Helper::get_string_value( wp_json_encode( $this->include_countries ) ) ); ?>" | |
| 151 | + <?php } elseif ( 'exclude' === $this->country_filter_type && ! empty( $this->exclude_countries ) ) { ?> | |
| 152 | + data-exclude-countries="<?php echo esc_attr( Helper::get_string_value( wp_json_encode( $this->exclude_countries ) ) ); ?>" | |
| 153 | + <?php } ?> | |
| 154 | + <?php } ?> | |
| 155 | + value="<?php echo esc_attr( $this->default ); ?>" | |
| 156 | + <?php echo wp_kses_post( $this->placeholder_attr ); ?> | |
| 157 | + data-unique="<?php echo esc_attr( $this->aria_unique ); ?>"> | |
| 64 | 158 | </div> |
| 65 | 159 | <div class="srfm-error-wrap"> |
| 66 | - <?php echo wp_kses_post( $this->error_msg_markup ); ?> | |
| 160 | + <?php echo wp_kses_post( $this->duplicate_msg_markup ); ?> | |
| 67 | 161 | </div> |
| 68 | 162 | </div> |
| 69 | 163 | <?php |
| 70 | 164 | return ob_get_clean(); |
| 71 | 165 | } |
| 166 | + | |
| 72 | 167 | } |