Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
5.45% |
14 / 257 |
|
50.00% |
1 / 2 |
CRAP | |
0.00% |
0 / 1 |
| Country_Code_Utils | |
5.45% |
14 / 257 |
|
50.00% |
1 / 2 |
62.10 | |
0.00% |
0 / 1 |
| country_code_to_emoji_flag | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
6 | |||
| get_phone_prefix_to_country_map | |
1.22% |
3 / 246 |
|
0.00% |
0 / 1 |
5.86 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * Country_Code_Utils trait. |
| 4 | * |
| 5 | * @package automattic/jetpack-forms |
| 6 | */ |
| 7 | |
| 8 | namespace Automattic\Jetpack\Forms\ContactForm; |
| 9 | |
| 10 | /** |
| 11 | * Trait for country code utilities including emoji flags and phone prefix mapping. |
| 12 | * |
| 13 | * This trait provides reusable methods for: |
| 14 | * - Converting two-letter ISO country codes (e.g., 'US', 'GB', 'DE') into emoji flags |
| 15 | * - Mapping international phone prefixes to country codes |
| 16 | */ |
| 17 | trait Country_Code_Utils { |
| 18 | |
| 19 | /** |
| 20 | * Convert a country code to an emoji flag. |
| 21 | * |
| 22 | * @param string $country_code The two-letter country code (e.g., 'US', 'GB', 'DE'). |
| 23 | * |
| 24 | * @return string The emoji flag for the country code, or empty string if invalid. |
| 25 | */ |
| 26 | private static function country_code_to_emoji_flag( $country_code ) { |
| 27 | if ( empty( $country_code ) || strlen( $country_code ) !== 2 ) { |
| 28 | return ''; |
| 29 | } |
| 30 | |
| 31 | $country_code = strtoupper( $country_code ); |
| 32 | |
| 33 | // Convert each letter to a regional indicator symbol. |
| 34 | // Regional indicator symbols start at Unicode code point 127462 (🇦) |
| 35 | // and correspond to A-Z (ASCII 65-90). |
| 36 | $flag = ''; |
| 37 | for ( $i = 0; $i < 2; $i++ ) { |
| 38 | $char = $country_code[ $i ]; |
| 39 | |
| 40 | // Check if the character is a valid uppercase letter (A-Z). |
| 41 | if ( ord( $char ) < 65 || ord( $char ) > 90 ) { |
| 42 | return ''; |
| 43 | } |
| 44 | |
| 45 | $code_point = 127462 + ( ord( $char ) - 65 ); |
| 46 | |
| 47 | // Convert code point to UTF-8 encoded character. |
| 48 | $flag .= mb_chr( $code_point, 'UTF-8' ); |
| 49 | } |
| 50 | |
| 51 | return $flag; |
| 52 | } |
| 53 | |
| 54 | /** |
| 55 | * Get the mapping of international phone prefixes to ISO country codes. |
| 56 | * |
| 57 | * The array is sorted by prefix length (longest first) to ensure |
| 58 | * more specific prefixes are matched before general ones |
| 59 | * (e.g., +1264 Anguilla before +1 USA). |
| 60 | * |
| 61 | * @return array<string, string> Phone prefix => ISO country code mapping. |
| 62 | */ |
| 63 | private static function get_phone_prefix_to_country_map() { |
| 64 | static $sorted_map = null; |
| 65 | |
| 66 | if ( $sorted_map !== null ) { |
| 67 | return $sorted_map; |
| 68 | } |
| 69 | |
| 70 | /* |
| 71 | * This list is synced with the JavaScript country list at: |
| 72 | * projects/packages/forms/src/blocks/field-telephone/country-list.js |
| 73 | * |
| 74 | * Some territories from the JS list are intentionally omitted here because they |
| 75 | * share phone prefixes with other countries (e.g., Guernsey, Jersey, and Isle of Man |
| 76 | * all share +44 with the UK). Since we can only map one country per prefix for |
| 77 | * flag display, we use the primary country for shared prefixes. |
| 78 | */ |
| 79 | $prefix_to_country = array( |
| 80 | // 4-digit prefixes (Caribbean and other NANP territories). |
| 81 | '+1264' => 'AI', // Anguilla |
| 82 | '+1268' => 'AG', // Antigua and Barbuda |
| 83 | '+1242' => 'BS', // Bahamas |
| 84 | '+1246' => 'BB', // Barbados |
| 85 | '+1441' => 'BM', // Bermuda |
| 86 | '+1284' => 'VG', // British Virgin Islands |
| 87 | '+1345' => 'KY', // Cayman Islands |
| 88 | '+1767' => 'DM', // Dominica |
| 89 | '+1809' => 'DO', // Dominican Republic |
| 90 | '+1829' => 'DO', // Dominican Republic |
| 91 | '+1849' => 'DO', // Dominican Republic |
| 92 | '+1473' => 'GD', // Grenada |
| 93 | '+1671' => 'GU', // Guam |
| 94 | '+1876' => 'JM', // Jamaica |
| 95 | '+1664' => 'MS', // Montserrat |
| 96 | '+1670' => 'MP', // Northern Mariana Islands |
| 97 | '+1787' => 'PR', // Puerto Rico |
| 98 | '+1939' => 'PR', // Puerto Rico |
| 99 | '+1869' => 'KN', // Saint Kitts and Nevis |
| 100 | '+1758' => 'LC', // Saint Lucia |
| 101 | '+1784' => 'VC', // Saint Vincent and the Grenadines |
| 102 | '+1721' => 'SX', // Sint Maarten |
| 103 | '+1868' => 'TT', // Trinidad and Tobago |
| 104 | '+1649' => 'TC', // Turks and Caicos Islands |
| 105 | '+1340' => 'VI', // U.S. Virgin Islands |
| 106 | '+1684' => 'AS', // American Samoa |
| 107 | |
| 108 | // 3-digit prefixes. |
| 109 | '+355' => 'AL', // Albania |
| 110 | '+213' => 'DZ', // Algeria |
| 111 | '+376' => 'AD', // Andorra |
| 112 | '+244' => 'AO', // Angola |
| 113 | '+246' => 'IO', // British Indian Ocean Territory |
| 114 | '+374' => 'AM', // Armenia |
| 115 | '+297' => 'AW', // Aruba |
| 116 | '+994' => 'AZ', // Azerbaijan |
| 117 | '+973' => 'BH', // Bahrain |
| 118 | '+880' => 'BD', // Bangladesh |
| 119 | '+375' => 'BY', // Belarus |
| 120 | '+501' => 'BZ', // Belize |
| 121 | '+229' => 'BJ', // Benin |
| 122 | '+975' => 'BT', // Bhutan |
| 123 | '+591' => 'BO', // Bolivia |
| 124 | '+387' => 'BA', // Bosnia and Herzegovina |
| 125 | '+267' => 'BW', // Botswana |
| 126 | '+269' => 'KM', // Comoros |
| 127 | '+673' => 'BN', // Brunei |
| 128 | '+359' => 'BG', // Bulgaria |
| 129 | '+226' => 'BF', // Burkina Faso |
| 130 | '+257' => 'BI', // Burundi |
| 131 | '+855' => 'KH', // Cambodia |
| 132 | '+237' => 'CM', // Cameroon |
| 133 | '+238' => 'CV', // Cape Verde |
| 134 | '+236' => 'CF', // Central African Republic |
| 135 | '+235' => 'TD', // Chad |
| 136 | '+682' => 'CK', // Cook Islands |
| 137 | '+506' => 'CR', // Costa Rica |
| 138 | '+385' => 'HR', // Croatia |
| 139 | '+357' => 'CY', // Cyprus |
| 140 | '+420' => 'CZ', // Czech Republic |
| 141 | '+243' => 'CD', // Democratic Republic of the Congo |
| 142 | '+253' => 'DJ', // Djibouti |
| 143 | '+593' => 'EC', // Ecuador |
| 144 | '+503' => 'SV', // El Salvador |
| 145 | '+240' => 'GQ', // Equatorial Guinea |
| 146 | '+291' => 'ER', // Eritrea |
| 147 | '+298' => 'FO', // Faroe Islands |
| 148 | '+372' => 'EE', // Estonia |
| 149 | '+268' => 'SZ', // Eswatini |
| 150 | '+251' => 'ET', // Ethiopia |
| 151 | '+679' => 'FJ', // Fiji |
| 152 | '+358' => 'FI', // Finland |
| 153 | '+594' => 'GF', // French Guiana |
| 154 | '+689' => 'PF', // French Polynesia |
| 155 | '+241' => 'GA', // Gabon |
| 156 | '+220' => 'GM', // Gambia |
| 157 | '+995' => 'GE', // Georgia |
| 158 | '+233' => 'GH', // Ghana |
| 159 | '+350' => 'GI', // Gibraltar |
| 160 | '+299' => 'GL', // Greenland |
| 161 | '+590' => 'GP', // Guadeloupe |
| 162 | '+502' => 'GT', // Guatemala |
| 163 | '+224' => 'GN', // Guinea |
| 164 | '+245' => 'GW', // Guinea-Bissau |
| 165 | '+592' => 'GY', // Guyana |
| 166 | '+509' => 'HT', // Haiti |
| 167 | '+504' => 'HN', // Honduras |
| 168 | '+852' => 'HK', // Hong Kong |
| 169 | '+354' => 'IS', // Iceland |
| 170 | '+964' => 'IQ', // Iraq |
| 171 | '+353' => 'IE', // Ireland |
| 172 | '+972' => 'IL', // Israel |
| 173 | '+225' => 'CI', // Ivory Coast |
| 174 | '+962' => 'JO', // Jordan |
| 175 | '+254' => 'KE', // Kenya |
| 176 | '+686' => 'KI', // Kiribati |
| 177 | '+383' => 'XK', // Kosovo |
| 178 | '+965' => 'KW', // Kuwait |
| 179 | '+996' => 'KG', // Kyrgyzstan |
| 180 | '+856' => 'LA', // Laos |
| 181 | '+371' => 'LV', // Latvia |
| 182 | '+961' => 'LB', // Lebanon |
| 183 | '+266' => 'LS', // Lesotho |
| 184 | '+231' => 'LR', // Liberia |
| 185 | '+218' => 'LY', // Libya |
| 186 | '+423' => 'LI', // Liechtenstein |
| 187 | '+370' => 'LT', // Lithuania |
| 188 | '+352' => 'LU', // Luxembourg |
| 189 | '+853' => 'MO', // Macau |
| 190 | '+261' => 'MG', // Madagascar |
| 191 | '+265' => 'MW', // Malawi |
| 192 | '+960' => 'MV', // Maldives |
| 193 | '+223' => 'ML', // Mali |
| 194 | '+356' => 'MT', // Malta |
| 195 | '+692' => 'MH', // Marshall Islands |
| 196 | '+596' => 'MQ', // Martinique |
| 197 | '+222' => 'MR', // Mauritania |
| 198 | '+230' => 'MU', // Mauritius |
| 199 | '+691' => 'FM', // Micronesia |
| 200 | '+373' => 'MD', // Moldova |
| 201 | '+377' => 'MC', // Monaco |
| 202 | '+976' => 'MN', // Mongolia |
| 203 | '+382' => 'ME', // Montenegro |
| 204 | '+212' => 'MA', // Morocco |
| 205 | '+258' => 'MZ', // Mozambique |
| 206 | '+264' => 'NA', // Namibia |
| 207 | '+674' => 'NR', // Nauru |
| 208 | '+977' => 'NP', // Nepal |
| 209 | '+687' => 'NC', // New Caledonia |
| 210 | '+505' => 'NI', // Nicaragua |
| 211 | '+227' => 'NE', // Niger |
| 212 | '+234' => 'NG', // Nigeria |
| 213 | '+683' => 'NU', // Niue |
| 214 | '+672' => 'NF', // Norfolk Island |
| 215 | '+850' => 'KP', // North Korea |
| 216 | '+389' => 'MK', // North Macedonia |
| 217 | '+968' => 'OM', // Oman |
| 218 | '+680' => 'PW', // Palau |
| 219 | '+970' => 'PS', // Palestine |
| 220 | '+500' => 'FK', // Falkland Islands |
| 221 | '+507' => 'PA', // Panama |
| 222 | '+675' => 'PG', // Papua New Guinea |
| 223 | '+595' => 'PY', // Paraguay |
| 224 | '+974' => 'QA', // Qatar |
| 225 | '+242' => 'CG', // Republic of the Congo |
| 226 | '+262' => 'RE', // Reunion (also Mayotte) |
| 227 | '+250' => 'RW', // Rwanda |
| 228 | '+290' => 'SH', // Saint Helena |
| 229 | '+508' => 'PM', // Saint Pierre and Miquelon |
| 230 | '+685' => 'WS', // Samoa |
| 231 | '+378' => 'SM', // San Marino |
| 232 | '+239' => 'ST', // Sao Tome and Principe |
| 233 | '+966' => 'SA', // Saudi Arabia |
| 234 | '+221' => 'SN', // Senegal |
| 235 | '+381' => 'RS', // Serbia |
| 236 | '+248' => 'SC', // Seychelles |
| 237 | '+232' => 'SL', // Sierra Leone |
| 238 | '+421' => 'SK', // Slovakia |
| 239 | '+386' => 'SI', // Slovenia |
| 240 | '+677' => 'SB', // Solomon Islands |
| 241 | '+252' => 'SO', // Somalia |
| 242 | '+211' => 'SS', // South Sudan |
| 243 | '+249' => 'SD', // Sudan |
| 244 | '+597' => 'SR', // Suriname |
| 245 | '+963' => 'SY', // Syria |
| 246 | '+886' => 'TW', // Taiwan |
| 247 | '+992' => 'TJ', // Tajikistan |
| 248 | '+255' => 'TZ', // Tanzania |
| 249 | '+228' => 'TG', // Togo |
| 250 | '+670' => 'TL', // Timor-Leste |
| 251 | '+690' => 'TK', // Tokelau |
| 252 | '+676' => 'TO', // Tonga |
| 253 | '+216' => 'TN', // Tunisia |
| 254 | '+993' => 'TM', // Turkmenistan |
| 255 | '+688' => 'TV', // Tuvalu |
| 256 | '+256' => 'UG', // Uganda |
| 257 | '+380' => 'UA', // Ukraine |
| 258 | '+971' => 'AE', // United Arab Emirates |
| 259 | '+598' => 'UY', // Uruguay |
| 260 | '+998' => 'UZ', // Uzbekistan |
| 261 | '+678' => 'VU', // Vanuatu |
| 262 | '+379' => 'VA', // Vatican City |
| 263 | '+681' => 'WF', // Wallis and Futuna |
| 264 | '+967' => 'YE', // Yemen |
| 265 | '+260' => 'ZM', // Zambia |
| 266 | '+263' => 'ZW', // Zimbabwe |
| 267 | '+351' => 'PT', // Portugal |
| 268 | '+872' => 'PN', // Pitcairn Islands |
| 269 | |
| 270 | // 2-digit prefixes. |
| 271 | '+93' => 'AF', // Afghanistan |
| 272 | '+54' => 'AR', // Argentina |
| 273 | '+61' => 'AU', // Australia |
| 274 | '+43' => 'AT', // Austria |
| 275 | '+32' => 'BE', // Belgium |
| 276 | '+55' => 'BR', // Brazil |
| 277 | '+56' => 'CL', // Chile |
| 278 | '+86' => 'CN', // China |
| 279 | '+57' => 'CO', // Colombia |
| 280 | '+53' => 'CU', // Cuba |
| 281 | '+45' => 'DK', // Denmark |
| 282 | '+20' => 'EG', // Egypt |
| 283 | '+33' => 'FR', // France |
| 284 | '+49' => 'DE', // Germany |
| 285 | '+30' => 'GR', // Greece |
| 286 | '+36' => 'HU', // Hungary |
| 287 | '+91' => 'IN', // India |
| 288 | '+62' => 'ID', // Indonesia |
| 289 | '+98' => 'IR', // Iran |
| 290 | '+39' => 'IT', // Italy |
| 291 | '+81' => 'JP', // Japan |
| 292 | '+77' => 'KZ', // Kazakhstan |
| 293 | '+82' => 'KR', // South Korea |
| 294 | '+60' => 'MY', // Malaysia |
| 295 | '+52' => 'MX', // Mexico |
| 296 | '+95' => 'MM', // Myanmar |
| 297 | '+31' => 'NL', // Netherlands |
| 298 | '+64' => 'NZ', // New Zealand |
| 299 | '+47' => 'NO', // Norway |
| 300 | '+92' => 'PK', // Pakistan |
| 301 | '+51' => 'PE', // Peru |
| 302 | '+63' => 'PH', // Philippines |
| 303 | '+48' => 'PL', // Poland |
| 304 | '+40' => 'RO', // Romania |
| 305 | '+7' => 'RU', // Russia (also Kazakhstan +77) |
| 306 | '+65' => 'SG', // Singapore |
| 307 | '+27' => 'ZA', // South Africa |
| 308 | '+34' => 'ES', // Spain |
| 309 | '+94' => 'LK', // Sri Lanka |
| 310 | '+46' => 'SE', // Sweden |
| 311 | '+41' => 'CH', // Switzerland |
| 312 | '+66' => 'TH', // Thailand |
| 313 | '+90' => 'TR', // Turkey |
| 314 | '+44' => 'GB', // United Kingdom |
| 315 | '+1' => 'US', // United States/Canada (NANP) |
| 316 | '+58' => 'VE', // Venezuela |
| 317 | '+84' => 'VN', // Vietnam |
| 318 | ); |
| 319 | |
| 320 | // Sort by prefix length (longest first) to match most specific prefix. |
| 321 | uksort( |
| 322 | $prefix_to_country, |
| 323 | static function ( $a, $b ) { |
| 324 | return strlen( $b ) - strlen( $a ); |
| 325 | } |
| 326 | ); |
| 327 | |
| 328 | $sorted_map = $prefix_to_country; |
| 329 | |
| 330 | return $sorted_map; |
| 331 | } |
| 332 | } |