PluginProbe
Polylang / 3.7.1
Polylang v3.7.1
3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 3.0.3 All 233 releases
polylang / include / Options / Business / Domains.php

Domains.php in Polylang 3.7.1, at include/Options/Business/Domains.php

189 lines 5.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Polylang
4 */
5
6 namespace WP_Syntex\Polylang\Options\Business;
7
8 use WP_Error;
9 use WP_Syntex\Polylang\Options\Abstract_Option;
10 use WP_Syntex\Polylang\Options\Options;
11 use WP_Syntex\Polylang\Model\Languages;
12
13 defined( 'ABSPATH' ) || exit;
14
15 /**
16 * Class defining single associative array of domain as value and language slug as key option.
17 * /!\ Sanitization depends on `force_lang`: this option must be set AFTER `force_lang`.
18 *
19 * @since 3.7
20 *
21 * @phpstan-type DomainsValue array<non-falsy-string, string>
22 */
23 class Domains extends Abstract_Option {
24 /**
25 * Returns option key.
26 *
27 * @since 3.7
28 *
29 * @return string
30 *
31 * @phpstan-return 'domains'
32 */
33 public static function key(): string {
34 return 'domains';
35 }
36
37 /**
38 * Returns the default value.
39 *
40 * @since 3.7
41 *
42 * @return array
43 */
44 protected function get_default() {
45 return array();
46 }
47
48 /**
49 * Returns the JSON schema part specific to this option.
50 *
51 * @since 3.7
52 *
53 * @return array Partial schema.
54 *
55 * @phpstan-return array{
56 * type: 'object',
57 * patternProperties: non-empty-array<non-empty-string, array{type: 'string', format: 'uri'}>,
58 * additionalProperties: false
59 * }
60 */
61 protected function get_data_structure(): array {
62 return array(
63 'type' => 'object', // Correspond to associative array in PHP, @see{https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#primitive-types}.
64 'patternProperties' => array(
65 Languages::SLUG_PATTERN => array( // Language slug as key.
66 'type' => 'string',
67 'format' => 'uri',
68 ),
69 ),
70 'additionalProperties' => false,
71 );
72 }
73
74 /**
75 * Sanitizes option's value.
76 * Can populate the `$errors` property with blocking and non-blocking errors: in case of non-blocking errors,
77 * the value is sanitized and can be stored.
78 *
79 * @since 3.7
80 *
81 * @param array $value Value to sanitize.
82 * @param Options $options All options.
83 * @return array|WP_Error The sanitized value. An instance of `WP_Error` in case of blocking error.
84 *
85 * @phpstan-return DomainsValue|WP_Error
86 */
87 protected function sanitize( $value, Options $options ) {
88 // Sanitize new URLs.
89 $value = parent::sanitize( $value, $options );
90
91 if ( is_wp_error( $value ) ) {
92 // Blocking error.
93 return $value;
94 }
95
96 /** @phpstan-var DomainsValue */
97 $current_value = $this->get();
98 /** @phpstan-var DomainsValue $value */
99 $all_values = array(); // Previous and new values.
100 $missing_langs = array(); // Lang names corresponding to the empty values.
101 $language_terms = $this->get_language_terms();
102
103 // Detect empty values, fill missing keys with previous values.
104 foreach ( $language_terms as $lang ) {
105 if ( array_key_exists( $lang->slug, $value ) ) {
106 // Use the new value.
107 $all_values[ $lang->slug ] = $value[ $lang->slug ];
108 unset( $value[ $lang->slug ] );
109 } else {
110 // Use previous value.
111 $all_values[ $lang->slug ] = $current_value[ $lang->slug ] ?? '';
112 }
113
114 if ( empty( $all_values[ $lang->slug ] ) ) {
115 // The value is empty.
116 $missing_langs[] = $lang->name;
117 }
118 }
119
120 // Detect invalid language slugs.
121 if ( ! empty( $value ) ) {
122 // Non-blocking error.
123 $this->add_unknown_languages_warning( array_keys( $value ) );
124 }
125
126 if ( 3 === $options->get( 'force_lang' ) && ! empty( $missing_langs ) ) {
127 // Non-blocking error.
128 if ( 1 === count( $missing_langs ) ) {
129 /* translators: %s is a native language name. */
130 $message = __( 'Please enter a valid URL for %s.', 'polylang' );
131 } else {
132 /* translators: %s is a list of native language names. */
133 $message = __( 'Please enter valid URLs for %s.', 'polylang' );
134 }
135
136 $this->errors->add(
137 'pll_empty_domains',
138 sprintf( $message, wp_sprintf_l( '%l', $missing_langs ) ),
139 'warning'
140 );
141 }
142
143 // Ping all URLs to make sure they are valid.
144 if ( $options->get( 'force_lang' ) > 1 ) {
145 $failed_urls = array();
146
147 foreach ( array_filter( $all_values ) as $url ) {
148 $url = add_query_arg( 'deactivate-polylang', 1, $url );
149 // Don't redefine vip_safe_wp_remote_get() as it has not the same signature as wp_remote_get().
150 $response = function_exists( 'vip_safe_wp_remote_get' ) ? vip_safe_wp_remote_get( $url ) : wp_remote_get( $url );
151
152 if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
153 $failed_urls[] = $url;
154 }
155 }
156
157 if ( ! empty( $failed_urls ) ) {
158 // Non-blocking error.
159 if ( 1 === count( $failed_urls ) ) {
160 /* translators: %s is a URL. */
161 $message = __( 'Polylang was unable to access the %s URL. Please check that the URL is valid.', 'polylang' );
162 } else {
163 /* translators: %s is a list of URLs. */
164 $message = __( 'Polylang was unable to access the %s URLs. Please check that the URLs are valid.', 'polylang' );
165 }
166 $this->errors->add(
167 'pll_invalid_domains',
168 sprintf( $message, wp_sprintf_l( '%l', $failed_urls ) ),
169 'warning'
170 );
171 }
172 }
173
174 /** @phpstan-var DomainsValue */
175 return $all_values;
176 }
177
178 /**
179 * Returns the description used in the JSON schema.
180 *
181 * @since 3.7
182 *
183 * @return string
184 */
185 protected function get_description(): string {
186 return __( 'Domains used when the language is set from different domains.', 'polylang' );
187 }
188 }
189