PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.2
WooCommerce v10.9.2
11.0.0-beta.1 10.9.4 10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / includes / abstracts / abstract-wc-settings-api.php
woocommerce / includes / abstracts Last commit date
abstract-wc-address-provider.php 9 months ago abstract-wc-data.php 4 months ago abstract-wc-deprecated-hooks.php 6 years ago abstract-wc-integration.php 5 years ago abstract-wc-log-handler.php 2 years ago abstract-wc-object-query.php 5 years ago abstract-wc-order.php 1 month ago abstract-wc-payment-gateway.php 1 month ago abstract-wc-payment-token.php 5 years ago abstract-wc-privacy.php 5 years ago abstract-wc-product.php 1 month ago abstract-wc-session.php 10 months ago abstract-wc-settings-api.php 1 year ago abstract-wc-shipping-method.php 4 months ago abstract-wc-widget.php 5 years ago class-wc-background-process.php 5 years ago
abstract-wc-settings-api.php
1015 lines
1 <?php
2 /**
3 * Abstract Settings API Class
4 *
5 * Admin Settings API used by Integrations, Shipping Methods, and Payment Gateways.
6 *
7 * @package WooCommerce\Abstracts
8 */
9
10 defined( 'ABSPATH' ) || exit;
11
12 use Automattic\WooCommerce\Internal\Utilities\HtmlSanitizer;
13
14 /**
15 * WC_Settings_API class.
16 */
17 abstract class WC_Settings_API {
18
19 /**
20 * The plugin ID. Used for option names.
21 *
22 * @var string
23 */
24 public $plugin_id = 'woocommerce_';
25
26 /**
27 * ID of the class extending the settings API. Used in option names.
28 *
29 * @var string
30 */
31 public $id = '';
32
33 /**
34 * Validation errors.
35 *
36 * @var array of strings
37 */
38 public $errors = array();
39
40 /**
41 * Setting values.
42 *
43 * @var array
44 */
45 public $settings = array();
46
47 /**
48 * Form option fields.
49 *
50 * @var array
51 */
52 public $form_fields = array();
53
54 /**
55 * The posted settings data. When empty, $_POST data will be used.
56 *
57 * @var array
58 */
59 protected $data = array();
60
61 /**
62 * Get the form fields after they are initialized.
63 *
64 * @return array of options
65 */
66 public function get_form_fields() {
67 return apply_filters( 'woocommerce_settings_api_form_fields_' . $this->id, array_map( array( $this, 'set_defaults' ), $this->form_fields ) );
68 }
69
70 /**
71 * Set default required properties for each field.
72 *
73 * @param array $field Setting field array.
74 * @return array
75 */
76 protected function set_defaults( $field ) {
77 if ( ! isset( $field['default'] ) ) {
78 $field['default'] = '';
79 }
80 return $field;
81 }
82
83 /**
84 * Output the admin options table.
85 */
86 public function admin_options() {
87 echo '<table class="form-table">' . $this->generate_settings_html( $this->get_form_fields(), false ) . '</table>'; // WPCS: XSS ok.
88 }
89
90 /**
91 * Initialise settings form fields.
92 *
93 * Add an array of fields to be displayed on the gateway's settings screen.
94 *
95 * @since 1.0.0
96 */
97 public function init_form_fields() {}
98
99 /**
100 * Return the name of the option in the WP DB.
101 *
102 * @since 2.6.0
103 * @return string
104 */
105 public function get_option_key() {
106 return $this->plugin_id . $this->id . '_settings';
107 }
108
109 /**
110 * Get a fields type. Defaults to "text" if not set.
111 *
112 * @param array $field Field array.
113 * @return string
114 */
115 public function get_field_type( $field ) {
116 return empty( $field['type'] ) ? 'text' : $field['type'];
117 }
118
119 /**
120 * Get a fields default value. Defaults to "" if not set.
121 *
122 * @param array $field Field array.
123 * @return string
124 */
125 public function get_field_default( $field ) {
126 return empty( $field['default'] ) ? '' : $field['default'];
127 }
128
129 /**
130 * Get a field's posted and validated value.
131 *
132 * @param string $key Field key.
133 * @param array $field Field array.
134 * @param array $post_data Posted data.
135 * @return string
136 */
137 public function get_field_value( $key, $field, $post_data = array() ) {
138 $type = $this->get_field_type( $field );
139 $field_key = $this->get_field_key( $key );
140 $post_data = empty( $post_data ) ? $_POST : $post_data; // WPCS: CSRF ok, input var ok.
141 $value = isset( $post_data[ $field_key ] ) ? $post_data[ $field_key ] : null;
142
143 if ( isset( $field['sanitize_callback'] ) && is_callable( $field['sanitize_callback'] ) ) {
144 return call_user_func( $field['sanitize_callback'], $value );
145 }
146
147 // Look for a validate_FIELDID_field method for special handling.
148 if ( is_callable( array( $this, 'validate_' . $key . '_field' ) ) ) {
149 return $this->{'validate_' . $key . '_field'}( $key, $value );
150 }
151
152 // Look for a validate_FIELDTYPE_field method.
153 if ( is_callable( array( $this, 'validate_' . $type . '_field' ) ) ) {
154 return $this->{'validate_' . $type . '_field'}( $key, $value );
155 }
156
157 // Fallback to text.
158 return $this->validate_text_field( $key, $value );
159 }
160
161 /**
162 * Sets the POSTed data. This method can be used to set specific data, instead of taking it from the $_POST array.
163 *
164 * @param array $data Posted data.
165 */
166 public function set_post_data( $data = array() ) {
167 $this->data = $data;
168 }
169
170 /**
171 * Returns the POSTed data, to be used to save the settings.
172 *
173 * @return array
174 */
175 public function get_post_data() {
176 if ( ! empty( $this->data ) && is_array( $this->data ) ) {
177 return $this->data;
178 }
179 return $_POST; // WPCS: CSRF ok, input var ok.
180 }
181
182 /**
183 * Update a single option.
184 *
185 * @since 3.4.0
186 * @param string $key Option key.
187 * @param mixed $value Value to set.
188 * @return bool was anything saved?
189 */
190 public function update_option( $key, $value = '' ) {
191 if ( empty( $this->settings ) ) {
192 $this->init_settings();
193 }
194
195 $this->settings[ $key ] = $value;
196
197 return update_option( $this->get_option_key(), apply_filters( 'woocommerce_settings_api_sanitized_fields_' . $this->id, $this->settings ), 'yes' );
198 }
199
200 /**
201 * Processes and saves options.
202 * If there is an error thrown, will continue to save and validate fields, but will leave the erroring field out.
203 *
204 * @return bool was anything saved?
205 */
206 public function process_admin_options() {
207 $this->init_settings();
208
209 $post_data = $this->get_post_data();
210
211 foreach ( $this->get_form_fields() as $key => $field ) {
212 if ( 'title' !== $this->get_field_type( $field ) ) {
213 try {
214 $this->settings[ $key ] = $this->get_field_value( $key, $field, $post_data );
215 if ( 'select' === $field['type'] || 'checkbox' === $field['type'] ) {
216 /**
217 * Notify that a non-option setting has been updated.
218 *
219 * @since 7.8.0
220 */
221 do_action(
222 'woocommerce_update_non_option_setting',
223 array(
224 'id' => $key,
225 'type' => $field['type'],
226 'value' => $this->settings[ $key ],
227 )
228 );
229 }
230 } catch ( Exception $e ) {
231 $this->add_error( $e->getMessage() );
232 }
233 }
234 }
235
236 $option_key = $this->get_option_key();
237 do_action( 'woocommerce_update_option', array( 'id' => $option_key ) ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
238 return update_option( $option_key, apply_filters( 'woocommerce_settings_api_sanitized_fields_' . $this->id, $this->settings ), 'yes' ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
239 }
240
241 /**
242 * Add an error message for display in admin on save.
243 *
244 * @param string $error Error message.
245 */
246 public function add_error( $error ) {
247 $this->errors[] = $error;
248 }
249
250 /**
251 * Get admin error messages.
252 */
253 public function get_errors() {
254 return $this->errors;
255 }
256
257 /**
258 * Display admin error messages.
259 */
260 public function display_errors() {
261 if ( $this->get_errors() ) {
262 echo '<div id="woocommerce_errors" class="error notice is-dismissible">';
263 foreach ( $this->get_errors() as $error ) {
264 echo '<p>' . wp_kses_post( $error ) . '</p>';
265 }
266 echo '</div>';
267 }
268 }
269
270 /**
271 * Initialise Settings.
272 *
273 * Store all settings in a single database entry
274 * and make sure the $settings array is either the default
275 * or the settings stored in the database.
276 *
277 * @since 1.0.0
278 * @uses get_option(), add_option()
279 */
280 public function init_settings() {
281 $this->settings = get_option( $this->get_option_key(), null );
282
283 // If there are no settings defined, use defaults.
284 if ( ! is_array( $this->settings ) ) {
285 $form_fields = $this->get_form_fields();
286 $this->settings = array_merge( array_fill_keys( array_keys( $form_fields ), '' ), wp_list_pluck( $form_fields, 'default' ) );
287 }
288 }
289
290 /**
291 * Get option from DB.
292 *
293 * Gets an option from the settings API, using defaults if necessary to prevent undefined notices.
294 *
295 * @param string $key Option key.
296 * @param mixed $empty_value Value when empty.
297 * @return string The value specified for the option or a default value for the option.
298 */
299 public function get_option( $key, $empty_value = null ) {
300 if ( empty( $this->settings ) ) {
301 $this->init_settings();
302 }
303
304 // Get option default if unset.
305 if ( ! isset( $this->settings[ $key ] ) ) {
306 $form_fields = $this->get_form_fields();
307 $this->settings[ $key ] = isset( $form_fields[ $key ] ) ? $this->get_field_default( $form_fields[ $key ] ) : '';
308 }
309
310 if ( ! is_null( $empty_value ) && '' === $this->settings[ $key ] ) {
311 $this->settings[ $key ] = $empty_value;
312 }
313
314 return $this->settings[ $key ];
315 }
316
317 /**
318 * Prefix key for settings.
319 *
320 * @param string $key Field key.
321 * @return string
322 */
323 public function get_field_key( $key ) {
324 return $this->plugin_id . $this->id . '_' . $key;
325 }
326
327 /**
328 * Generate Settings HTML.
329 *
330 * Generate the HTML for the fields on the "settings" screen.
331 *
332 * @param array $form_fields (default: array()) Array of form fields.
333 * @param bool $echo Echo or return.
334 * @return string the html for the settings
335 * @since 1.0.0
336 * @uses method_exists()
337 */
338 public function generate_settings_html( $form_fields = array(), $echo = true ) {
339 if ( empty( $form_fields ) ) {
340 $form_fields = $this->get_form_fields();
341 }
342
343 $html = '';
344 foreach ( $form_fields as $k => $v ) {
345 $type = $this->get_field_type( $v );
346
347 if ( method_exists( $this, 'generate_' . $type . '_html' ) ) {
348 $html .= $this->{'generate_' . $type . '_html'}( $k, $v );
349 } elseif ( has_filter( 'woocommerce_generate_' . $type . '_html' ) ) {
350 /**
351 * Allow the generation of custom field types on the settings screen.
352 *
353 * The dynamic portion of the hook name refers to the slug of the custom field type.
354 * For instance, to introduce a new field type `fancy_lazy_dropdown` you would use
355 * the hook `woocommerce_generate_fancy_lazy_dropdown_html`.
356 *
357 * @since 6.5.0
358 *
359 * @param string $field_html The markup of the field being generated (initiated as an empty string).
360 * @param string $key The key of the field.
361 * @param array $data The attributes of the field as an associative array.
362 * @param object $wc_settings The current WC_Settings_API object.
363 */
364 $html .= apply_filters( 'woocommerce_generate_' . $type . '_html', '', $k, $v, $this );
365 } else {
366 $html .= $this->generate_text_html( $k, $v );
367 }
368 }
369
370 if ( $echo ) {
371 echo $html; // WPCS: XSS ok.
372 } else {
373 return $html;
374 }
375 }
376
377 /**
378 * Get HTML for tooltips.
379 *
380 * @param array $data Data for the tooltip.
381 * @return string
382 */
383 public function get_tooltip_html( $data ) {
384 if ( true === $data['desc_tip'] ) {
385 $tip = $data['description'];
386 } elseif ( ! empty( $data['desc_tip'] ) ) {
387 $tip = $data['desc_tip'];
388 } else {
389 $tip = '';
390 }
391
392 return $tip ? wc_help_tip( $tip, true ) : '';
393 }
394
395 /**
396 * Get HTML for descriptions.
397 *
398 * @param array $data Data for the description.
399 * @return string
400 */
401 public function get_description_html( $data ) {
402 if ( true === $data['desc_tip'] ) {
403 $description = '';
404 } elseif ( ! empty( $data['desc_tip'] ) ) {
405 $description = $data['description'];
406 } elseif ( ! empty( $data['description'] ) ) {
407 $description = $data['description'];
408 } else {
409 $description = '';
410 }
411
412 return $description ? '<p class="description">' . wp_kses_post( $description ) . '</p>' . "\n" : '';
413 }
414
415 /**
416 * Get custom attributes.
417 *
418 * @param array $data Field data.
419 * @return string
420 */
421 public function get_custom_attribute_html( $data ) {
422 $custom_attributes = array();
423
424 if ( ! empty( $data['custom_attributes'] ) && is_array( $data['custom_attributes'] ) ) {
425 foreach ( $data['custom_attributes'] as $attribute => $attribute_value ) {
426 $custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
427 }
428 }
429
430 return implode( ' ', $custom_attributes );
431 }
432
433 /**
434 * Generate Text Input HTML.
435 *
436 * @param string $key Field key.
437 * @param array $data Field data.
438 * @since 1.0.0
439 * @return string
440 */
441 public function generate_text_html( $key, $data ) {
442 $field_key = $this->get_field_key( $key );
443 $defaults = array(
444 'title' => '',
445 'disabled' => false,
446 'class' => '',
447 'css' => '',
448 'placeholder' => '',
449 'type' => 'text',
450 'desc_tip' => false,
451 'description' => '',
452 'custom_attributes' => array(),
453 );
454
455 $data = wp_parse_args( $data, $defaults );
456
457 ob_start();
458 ?>
459 <tr valign="top">
460 <th scope="row" class="titledesc">
461 <label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?> <?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?></label>
462 </th>
463 <td class="forminp">
464 <fieldset>
465 <legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
466 <input class="input-text regular-input <?php echo esc_attr( $data['class'] ); ?>" type="<?php echo esc_attr( $data['type'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="<?php echo esc_attr( $this->get_option( $key ) ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?> />
467 <?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
468 </fieldset>
469 </td>
470 </tr>
471 <?php
472
473 return ob_get_clean();
474 }
475
476 /**
477 * Generates HTML for the 'safe_text' input type (mostly used for gateway-related settings).
478 *
479 * @param string $key Field key.
480 * @param array $data Field data.
481 * @return string
482 *
483 * @since 7.6.0
484 */
485 public function generate_safe_text_html( $key, $data ) {
486 $data['type'] = 'text';
487 return $this->generate_text_html( $key, $data );
488 }
489
490 /**
491 * Generate Price Input HTML.
492 *
493 * @param string $key Field key.
494 * @param array $data Field data.
495 * @since 1.0.0
496 * @return string
497 */
498 public function generate_price_html( $key, $data ) {
499 $field_key = $this->get_field_key( $key );
500 $defaults = array(
501 'title' => '',
502 'disabled' => false,
503 'class' => '',
504 'css' => '',
505 'placeholder' => '',
506 'type' => 'text',
507 'desc_tip' => false,
508 'description' => '',
509 'custom_attributes' => array(),
510 );
511
512 $data = wp_parse_args( $data, $defaults );
513
514 ob_start();
515 ?>
516 <tr valign="top">
517 <th scope="row" class="titledesc">
518 <label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?> <?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?></label>
519 </th>
520 <td class="forminp">
521 <fieldset>
522 <legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
523 <input class="wc_input_price input-text regular-input <?php echo esc_attr( $data['class'] ); ?>" type="text" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="<?php echo esc_attr( wc_format_localized_price( $this->get_option( $key ) ) ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?> />
524 <?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
525 </fieldset>
526 </td>
527 </tr>
528 <?php
529
530 return ob_get_clean();
531 }
532
533 /**
534 * Generate Decimal Input HTML.
535 *
536 * @param string $key Field key.
537 * @param array $data Field data.
538 * @since 1.0.0
539 * @return string
540 */
541 public function generate_decimal_html( $key, $data ) {
542 $field_key = $this->get_field_key( $key );
543 $defaults = array(
544 'title' => '',
545 'disabled' => false,
546 'class' => '',
547 'css' => '',
548 'placeholder' => '',
549 'type' => 'text',
550 'desc_tip' => false,
551 'description' => '',
552 'custom_attributes' => array(),
553 );
554
555 $data = wp_parse_args( $data, $defaults );
556
557 ob_start();
558 ?>
559 <tr valign="top">
560 <th scope="row" class="titledesc">
561 <label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?> <?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?></label>
562 </th>
563 <td class="forminp">
564 <fieldset>
565 <legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
566 <input class="wc_input_decimal input-text regular-input <?php echo esc_attr( $data['class'] ); ?>" type="text" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="<?php echo esc_attr( wc_format_localized_decimal( $this->get_option( $key ) ) ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?> />
567 <?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
568 </fieldset>
569 </td>
570 </tr>
571 <?php
572
573 return ob_get_clean();
574 }
575
576 /**
577 * Generate Password Input HTML.
578 *
579 * @param string $key Field key.
580 * @param array $data Field data.
581 * @since 1.0.0
582 * @return string
583 */
584 public function generate_password_html( $key, $data ) {
585 $data['type'] = 'password';
586 return $this->generate_text_html( $key, $data );
587 }
588
589 /**
590 * Generate Color Picker Input HTML.
591 *
592 * @param string $key Field key.
593 * @param array $data Field data.
594 * @since 1.0.0
595 * @return string
596 */
597 public function generate_color_html( $key, $data ) {
598 $field_key = $this->get_field_key( $key );
599 $defaults = array(
600 'title' => '',
601 'disabled' => false,
602 'class' => '',
603 'css' => '',
604 'placeholder' => '',
605 'desc_tip' => false,
606 'description' => '',
607 'custom_attributes' => array(),
608 );
609
610 $data = wp_parse_args( $data, $defaults );
611
612 ob_start();
613 ?>
614 <tr valign="top">
615 <th scope="row" class="titledesc">
616 <label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?> <?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?></label>
617 </th>
618 <td class="forminp">
619 <fieldset>
620 <legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
621 <span class="colorpickpreview" style="background:<?php echo esc_attr( $this->get_option( $key ) ); ?>;">&nbsp;</span>
622 <input class="colorpick <?php echo esc_attr( $data['class'] ); ?>" type="text" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="<?php echo esc_attr( $this->get_option( $key ) ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?> />
623 <div id="colorPickerDiv_<?php echo esc_attr( $field_key ); ?>" class="colorpickdiv" style="z-index: 100; background: #eee; border: 1px solid #ccc; position: absolute; display: none;"></div>
624 <?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
625 </fieldset>
626 </td>
627 </tr>
628 <?php
629
630 return ob_get_clean();
631 }
632
633 /**
634 * Generate Textarea HTML.
635 *
636 * @param string $key Field key.
637 * @param array $data Field data.
638 * @since 1.0.0
639 * @return string
640 */
641 public function generate_textarea_html( $key, $data ) {
642 $field_key = $this->get_field_key( $key );
643 $defaults = array(
644 'title' => '',
645 'disabled' => false,
646 'class' => '',
647 'css' => '',
648 'placeholder' => '',
649 'type' => 'text',
650 'desc_tip' => false,
651 'description' => '',
652 'custom_attributes' => array(),
653 );
654
655 $data = wp_parse_args( $data, $defaults );
656
657 ob_start();
658 ?>
659 <tr valign="top">
660 <th scope="row" class="titledesc">
661 <label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?> <?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?></label>
662 </th>
663 <td class="forminp">
664 <fieldset>
665 <legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
666 <textarea rows="3" cols="20" class="input-text wide-input <?php echo esc_attr( $data['class'] ); ?>" type="<?php echo esc_attr( $data['type'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?>><?php echo esc_textarea( $this->get_option( $key ) ); ?></textarea>
667 <?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
668 </fieldset>
669 </td>
670 </tr>
671 <?php
672
673 return ob_get_clean();
674 }
675
676 /**
677 * Generate Checkbox HTML.
678 *
679 * @param string $key Field key.
680 * @param array $data Field data.
681 * @since 1.0.0
682 * @return string
683 */
684 public function generate_checkbox_html( $key, $data ) {
685 $field_key = $this->get_field_key( $key );
686 $defaults = array(
687 'title' => '',
688 'label' => '',
689 'disabled' => false,
690 'class' => '',
691 'css' => '',
692 'type' => 'text',
693 'desc_tip' => false,
694 'description' => '',
695 'custom_attributes' => array(),
696 );
697
698 $data = wp_parse_args( $data, $defaults );
699
700 if ( ! $data['label'] ) {
701 $data['label'] = $data['title'];
702 }
703
704 ob_start();
705 ?>
706 <tr valign="top">
707 <th scope="row" class="titledesc">
708 <label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?> <?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?></label>
709 </th>
710 <td class="forminp">
711 <fieldset>
712 <legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
713 <label for="<?php echo esc_attr( $field_key ); ?>">
714 <input <?php disabled( $data['disabled'], true ); ?> class="<?php echo esc_attr( $data['class'] ); ?>" type="checkbox" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="1" <?php checked( $this->get_option( $key ), 'yes' ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?> /> <?php echo wp_kses_post( $data['label'] ); ?></label><br/>
715 <?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
716 </fieldset>
717 </td>
718 </tr>
719 <?php
720
721 return ob_get_clean();
722 }
723
724 /**
725 * Generate Select HTML.
726 *
727 * @param string $key Field key.
728 * @param array $data Field data.
729 * @since 1.0.0
730 * @return string
731 */
732 public function generate_select_html( $key, $data ) {
733 $field_key = $this->get_field_key( $key );
734 $defaults = array(
735 'title' => '',
736 'disabled' => false,
737 'class' => '',
738 'css' => '',
739 'placeholder' => '',
740 'type' => 'text',
741 'desc_tip' => false,
742 'description' => '',
743 'custom_attributes' => array(),
744 'options' => array(),
745 );
746
747 $data = wp_parse_args( $data, $defaults );
748 $value = $this->get_option( $key );
749
750 ob_start();
751 ?>
752 <tr valign="top">
753 <th scope="row" class="titledesc">
754 <label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?> <?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?></label>
755 </th>
756 <td class="forminp">
757 <fieldset>
758 <legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
759 <select class="select <?php echo esc_attr( $data['class'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?>>
760 <?php foreach ( (array) $data['options'] as $option_key => $option_value ) : ?>
761 <?php if ( is_array( $option_value ) ) : ?>
762 <optgroup label="<?php echo esc_attr( $option_key ); ?>">
763 <?php foreach ( $option_value as $option_key_inner => $option_value_inner ) : ?>
764 <option value="<?php echo esc_attr( $option_key_inner ); ?>" <?php selected( (string) $option_key_inner, esc_attr( $value ) ); ?>><?php echo esc_html( $option_value_inner ); ?></option>
765 <?php endforeach; ?>
766 </optgroup>
767 <?php else : ?>
768 <option value="<?php echo esc_attr( $option_key ); ?>" <?php selected( (string) $option_key, esc_attr( $value ) ); ?>><?php echo esc_html( $option_value ); ?></option>
769 <?php endif; ?>
770 <?php endforeach; ?>
771 </select>
772 <?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
773 </fieldset>
774 </td>
775 </tr>
776 <?php
777
778 return ob_get_clean();
779 }
780
781 /**
782 * Generate Multiselect HTML.
783 *
784 * @param string $key Field key.
785 * @param array $data Field data.
786 * @since 1.0.0
787 * @return string
788 */
789 public function generate_multiselect_html( $key, $data ) {
790 $field_key = $this->get_field_key( $key );
791 $defaults = array(
792 'title' => '',
793 'disabled' => false,
794 'class' => '',
795 'css' => '',
796 'placeholder' => '',
797 'type' => 'text',
798 'desc_tip' => false,
799 'description' => '',
800 'custom_attributes' => array(),
801 'select_buttons' => false,
802 'options' => array(),
803 );
804
805 $data = wp_parse_args( $data, $defaults );
806 $value = (array) $this->get_option( $key, array() );
807
808 ob_start();
809 ?>
810 <tr valign="top">
811 <th scope="row" class="titledesc">
812 <label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?> <?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?></label>
813 </th>
814 <td class="forminp">
815 <fieldset>
816 <legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
817 <select multiple="multiple" class="multiselect <?php echo esc_attr( $data['class'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>[]" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?>>
818 <?php foreach ( (array) $data['options'] as $option_key => $option_value ) : ?>
819 <?php if ( is_array( $option_value ) ) : ?>
820 <optgroup label="<?php echo esc_attr( $option_key ); ?>">
821 <?php foreach ( $option_value as $option_key_inner => $option_value_inner ) : ?>
822 <option value="<?php echo esc_attr( $option_key_inner ); ?>" <?php selected( in_array( (string) $option_key_inner, $value, true ), true ); ?>><?php echo esc_html( $option_value_inner ); ?></option>
823 <?php endforeach; ?>
824 </optgroup>
825 <?php else : ?>
826 <option value="<?php echo esc_attr( $option_key ); ?>" <?php selected( in_array( (string) $option_key, $value, true ), true ); ?>><?php echo esc_html( $option_value ); ?></option>
827 <?php endif; ?>
828 <?php endforeach; ?>
829 </select>
830 <?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
831 <?php if ( $data['select_buttons'] ) : ?>
832 <br/><a class="select_all button" href="#"><?php esc_html_e( 'Select all', 'woocommerce' ); ?></a> <a class="select_none button" href="#"><?php esc_html_e( 'Select none', 'woocommerce' ); ?></a>
833 <?php endif; ?>
834 </fieldset>
835 </td>
836 </tr>
837 <?php
838
839 return ob_get_clean();
840 }
841
842 /**
843 * Generate Title HTML.
844 *
845 * @param string $key Field key.
846 * @param array $data Field data.
847 * @since 1.0.0
848 * @return string
849 */
850 public function generate_title_html( $key, $data ) {
851 $field_key = $this->get_field_key( $key );
852 $defaults = array(
853 'title' => '',
854 'class' => '',
855 );
856
857 $data = wp_parse_args( $data, $defaults );
858
859 ob_start();
860 ?>
861 </table>
862 <h3 class="wc-settings-sub-title <?php echo esc_attr( $data['class'] ); ?>" id="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></h3>
863 <?php if ( ! empty( $data['description'] ) ) : ?>
864 <p><?php echo wp_kses_post( $data['description'] ); ?></p>
865 <?php endif; ?>
866 <table class="form-table">
867 <?php
868
869 return ob_get_clean();
870 }
871
872 /**
873 * Validate Text Field.
874 *
875 * Make sure the data is escaped correctly, etc.
876 *
877 * @param string $key Field key.
878 * @param string $value Posted Value.
879 * @return string
880 */
881 public function validate_text_field( $key, $value ) {
882 $value = is_null( $value ) ? '' : $value;
883 return wp_kses_post( trim( stripslashes( $value ) ) );
884 }
885
886 /**
887 * Sanitize 'Safe Text' fields.
888 *
889 * These fields are similar to regular text fields, but a much smaller set of HTML tags are allowed. By default,
890 * this means `<br>`, `<img>`, `<p>` and `<span>` tags.
891 *
892 * Note: this is a sanitization method, rather than a validation method (the name is due to some historic naming
893 * choices).
894 *
895 * @param string $key Field key (currently unused).
896 * @param string $value Posted Value.
897 *
898 * @return string
899 */
900 public function validate_safe_text_field( string $key, ?string $value ): string {
901 return wc_get_container()->get( HtmlSanitizer::class )->sanitize( (string) $value, HtmlSanitizer::LOW_HTML_BALANCED_TAGS_NO_LINKS );
902 }
903
904 /**
905 * Validate Price Field.
906 *
907 * Make sure the data is escaped correctly, etc.
908 *
909 * @param string $key Field key.
910 * @param string $value Posted Value.
911 * @return string
912 */
913 public function validate_price_field( $key, $value ) {
914 $value = is_null( $value ) ? '' : $value;
915 return ( '' === $value ) ? '' : wc_format_decimal( trim( stripslashes( $value ) ) );
916 }
917
918 /**
919 * Validate Decimal Field.
920 *
921 * Make sure the data is escaped correctly, etc.
922 *
923 * @param string $key Field key.
924 * @param string $value Posted Value.
925 * @return string
926 */
927 public function validate_decimal_field( $key, $value ) {
928 $value = is_null( $value ) ? '' : $value;
929 return ( '' === $value ) ? '' : wc_format_decimal( trim( stripslashes( $value ) ) );
930 }
931
932 /**
933 * Validate Password Field. No input sanitization is used to avoid corrupting passwords.
934 *
935 * @param string $key Field key.
936 * @param string $value Posted Value.
937 * @return string
938 */
939 public function validate_password_field( $key, $value ) {
940 $value = is_null( $value ) ? '' : $value;
941 return trim( stripslashes( $value ) );
942 }
943
944 /**
945 * Validate Textarea Field.
946 *
947 * @since 9.0.0 No longer allows storing IFRAME, which was allowed for "ShareThis" integration no longer found in core.
948 * @param string $key Field key.
949 * @param string $value Posted Value.
950 * @return string
951 */
952 public function validate_textarea_field( $key, $value ) {
953 $value = is_null( $value ) ? '' : $value;
954 return wp_kses_post( trim( stripslashes( $value ) ) );
955 }
956
957 /**
958 * Validate Checkbox Field.
959 *
960 * If not set, return "no", otherwise return "yes".
961 *
962 * @param string $key Field key.
963 * @param string $value Posted Value.
964 * @return string
965 */
966 public function validate_checkbox_field( $key, $value ) {
967 return ! is_null( $value ) ? 'yes' : 'no';
968 }
969
970 /**
971 * Validate Select Field.
972 *
973 * @param string $key Field key.
974 * @param string $value Posted Value.
975 * @return string
976 */
977 public function validate_select_field( $key, $value ) {
978 $value = is_null( $value ) ? '' : $value;
979 return wc_clean( stripslashes( $value ) );
980 }
981
982 /**
983 * Validate Multiselect Field.
984 *
985 * @param string $key Field key.
986 * @param string $value Posted Value.
987 * @return string|array
988 */
989 public function validate_multiselect_field( $key, $value ) {
990 return is_array( $value ) ? array_map( 'wc_clean', array_map( 'stripslashes', $value ) ) : '';
991 }
992
993 /**
994 * Validate the data on the "Settings" form.
995 *
996 * @deprecated 2.6.0 No longer used.
997 * @param array $form_fields Array of fields.
998 */
999 public function validate_settings_fields( $form_fields = array() ) {
1000 wc_deprecated_function( 'validate_settings_fields', '2.6' );
1001 }
1002
1003 /**
1004 * Format settings if needed.
1005 *
1006 * @deprecated 2.6.0 Unused.
1007 * @param array $value Value to format.
1008 * @return array
1009 */
1010 public function format_settings( $value ) {
1011 wc_deprecated_function( 'format_settings', '2.6' );
1012 return $value;
1013 }
1014 }
1015