PluginProbe ʕ •ᴥ•ʔ
Admin and Site Enhancements (ASE) / 8.8.6
Admin and Site Enhancements (ASE) v8.8.6
9.1.0 9.0.2 9.0.1 9.0.0 8.9.2 8.9.1 8.9.0 8.8.8 8.8.7 8.8.6 8.8.5 8.8.4 8.8.3 8.8.2 8.8.1 8.8.0 8.7.3 8.7.2 8.7.1 8.2.1 8.2.2 8.2.3 8.3.0 8.3.1 8.3.2 8.4.0 8.4.1 8.4.2 8.5.0 8.5.1 8.5.2 8.6.0 8.6.1 8.6.2 8.7.0 5.0.1 5.0.2 5.0.2.1 5.0.2.2 5.0.2.3 5.0.2.4 5.1.0 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.8.0 5.8.1 6.0.0 6.0.3 6.0.4 6.0.5 6.0.5.1 6.0.6 6.0.7 6.0.8.1 6.1.0 6.1.3 6.2.0 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.2.6 6.2.7 6.3.0 6.3.1 6.3.2 6.4.0 6.5.0 6.5.1 6.6.0 6.7.0 6.8.0 6.8.2 6.8.3 6.9.0 6.9.1 6.9.10 6.9.11 6.9.12 6.9.13.1 6.9.13.2 6.9.2 6.9.3 6.9.4 6.9.5 6.9.6 6.9.7 6.9.8 6.9.9 7.0.0 7.0.2 7.0.2.1 7.0.2.2 7.0.2.3 7.0.3 7.1.0 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2.0 7.2.1 7.3.0 7.3.1 7.3.2 7.3.3 7.4.0 7.4.2 7.4.4 7.4.5 7.4.6 7.4.7 7.4.8 7.5.0 7.5.1 7.5.2 7.5.3 7.5.4 7.6.0 7.6.1 7.6.1.1 7.6.10 7.6.11 7.6.2 7.6.3 7.6.4 7.6.5 7.6.6 7.6.7 7.6.7.1 7.6.8 7.6.9 7.7.0 7.8.0 7.8.1 7.8.10 7.8.11 7.8.12 7.8.13 7.8.14 7.8.15 7.8.16 7.8.17 7.8.18 7.8.2 7.8.3 7.8.4 7.8.5 7.8.5.1 7.8.6 7.8.7 7.8.8 7.8.9 7.9.0 7.9.1 7.9.10 7.9.11 7.9.2 7.9.3 7.9.4 7.9.5 7.9.6 7.9.7 7.9.8 7.9.9 8.0.0 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.0.6 8.0.7 8.0.8 8.1.0 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 trunk 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 1.9.0 2.0.0 2.1.0 2.2.0 2.3.0 2.4.0 2.5.0 2.6.0 2.7.0 2.8.0 2.8.1 2.8.2 2.8.3 2.9.0 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.2.0 3.3.0 3.4.0 3.5.0 3.6.1 3.7.0 3.8.0 3.9.0 3.9.1 3.9.2 4.0.0 4.0.1 4.1.0 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.1 4.8.2 4.8.3 4.9.0 4.9.1 4.9.2 4.9.3 5.0.0
admin-site-enhancements / classes / class-settings-fields-render.php
admin-site-enhancements / classes Last commit date
class-activation.php 2 months ago class-admin-menu-organizer.php 2 months ago class-admin-menu-svg-icon-mask.php 2 months ago class-auto-publish-posts-with-missed-schedule.php 2 months ago class-avif-upload.php 2 months ago class-captcha-protection.php 2 months ago class-change-login-url.php 2 months ago class-cleanup-admin-bar.php 2 months ago class-common-methods.php 2 months ago class-content-duplication.php 2 months ago class-content-order.php 2 months ago class-custom-admin-footer-text.php 2 months ago class-custom-body-class.php 2 months ago class-custom-css.php 2 months ago class-custom-nav-menu-items-in-new-tab.php 2 months ago class-deactivation.php 2 months ago class-disable-author-archives.php 2 months ago class-disable-comments.php 2 months ago class-disable-dashboard-widgets.php 2 months ago class-disable-embeds.php 2 months ago class-disable-feeds.php 2 months ago class-disable-gutenberg.php 2 months ago class-disable-rest-api.php 2 months ago class-disable-smaller-components.php 2 months ago class-disable-updates.php 2 months ago class-disable-user-account.php 2 months ago class-disable-xml-rpc.php 2 months ago class-display-system-summary.php 2 months ago class-email-address-obfuscator.php 2 months ago class-email-delivery.php 2 months ago class-enhance-list-tables.php 2 months ago class-external-permalinks.php 2 months ago class-heartbeat-control.php 2 months ago class-hide-admin-bar.php 2 months ago class-hide-admin-notices.php 2 months ago class-image-sizes-panel.php 2 months ago class-image-upload-control.php 2 months ago class-insert-head-body-footer-code.php 2 months ago class-last-login-column.php 2 months ago class-limit-login-attempts.php 2 months ago class-login-id-type.php 2 months ago class-login-logout-menu.php 2 months ago class-maintenance-mode.php 2 months ago class-manage-ads-appads-txt.php 2 months ago class-manage-robots-txt.php 2 months ago class-media-files-visibility-control.php 2 months ago class-media-replacement.php 2 months ago class-multiple-user-roles.php 2 months ago class-obfuscate-author-slugs.php 2 months ago class-open-external-links-in-new-tab.php 2 months ago class-password-protection.php 2 months ago class-redirect-after-login.php 2 months ago class-redirect-after-logout.php 2 months ago class-redirect-fourofour.php 2 months ago class-registration-date-column.php 2 months ago class-revisions-control.php 2 months ago class-search-engines-visibility.php 2 months ago class-settings-fields-render.php 2 months ago class-settings-sanitization.php 2 months ago class-settings-sections-fields.php 2 months ago class-show-custom-taxonomy-filters.php 2 months ago class-site-identity-on-login-page.php 2 months ago class-svg-upload.php 2 months ago class-various-admin-ui-enhancements.php 2 months ago class-view-admin-as-role.php 2 months ago class-wider-admin-menu.php 2 months ago class-wp-config-transformer.php 2 months ago
class-settings-fields-render.php
1376 lines
1 <?php
2
3 namespace ASENHA\Classes;
4
5 /**
6 * Class related to rendering of settings fields on the admin page
7 *
8 * @since 2.2.0
9 */
10 class Settings_Fields_Render {
11 /**
12 * Render checkbox field as a toggle/switcher
13 *
14 * @since 1.0.0
15 */
16 function render_checkbox_toggle( $args ) {
17 $option_name = ( isset( $args['option_name'] ) ? $args['option_name'] : '' );
18 if ( !empty( $option_name ) ) {
19 $options = get_option( $option_name, array() );
20 } else {
21 $options = get_option( ASENHA_SLUG_U, array() );
22 }
23 $field_name = $args['field_name'];
24 $field_title = ( isset( $args['field_title'] ) ? $args['field_title'] : '' );
25 $field_description = $args['field_description'];
26 $field_option_value = ( array_key_exists( $args['field_id'], $options ) ? $options[$args['field_id']] : false );
27 echo '<input type="checkbox" id="' . esc_attr( $field_name ) . '" class="asenha-field-checkbox" name="' . esc_attr( $field_name ) . '" ' . checked( $field_option_value, true, false ) . '>';
28 echo '<label for="' . esc_attr( $field_name ) . '"></label>';
29 // For field with additional options / sub-fields, we add a wrapper to enclose field descriptions
30 if ( array_key_exists( 'field_options_wrapper', $args ) && $args['field_options_wrapper'] ) {
31 // For when the options / sub-fields occupy lengthy vertical space, we add show all / less toggler
32 if ( array_key_exists( 'field_options_moreless', $args ) && $args['field_options_moreless'] ) {
33 echo '<div class="asenha-field-with-options field-show-more">';
34 echo '<a id="' . esc_attr( $args['field_slug'] ) . '-show-moreless" class="show-more-less show-more" href="#">' . __( 'Expand', 'admin-site-enhancements' ) . ' &#9660;</a>';
35 echo '<div class="asenha-field-options-wrapper wrapper-show-more">';
36 } else {
37 echo '<div class="asenha-field-with-options">';
38 echo '<div class="asenha-field-options-wrapper">';
39 }
40 }
41 echo '<div class="asenha-field-description" data-search-filter data-module-info="' . esc_attr( strtolower( $field_title ) ) . '">' . wp_kses_post( $field_description ) . '</div>';
42 // For field with additional options / sub-fields, we add wrapper for them
43 if ( array_key_exists( 'field_options_wrapper', $args ) && $args['field_options_wrapper'] ) {
44 echo '<div class="asenha-subfields" style="display:none"></div>';
45 }
46 // For field with additional options / sub-fields, we add a wrapper to enclose field descriptions
47 if ( array_key_exists( 'field_options_wrapper', $args ) && $args['field_options_wrapper'] ) {
48 echo '</div>';
49 echo '</div>';
50 }
51 }
52
53 /**
54 * Render checkbox field as sub-field of a toggle/switcher checkbox
55 *
56 * @since 1.9.0
57 */
58 function render_checkbox_plain( $args ) {
59 $option_name = $args['option_name'];
60 if ( !empty( $option_name ) ) {
61 $options = get_option( $option_name, array() );
62 } else {
63 $options = get_option( ASENHA_SLUG_U, array() );
64 }
65 $field_name = $args['field_name'];
66 $field_label = $args['field_label'];
67 $default_value = false;
68 switch ( $args['field_id'] ) {
69 case 'login_page_disable_registration':
70 $default_value = ( 1 == get_option( 'users_can_register' ) ? false : true );
71 break;
72 }
73 $field_option_value = ( isset( $options[$args['field_id']] ) ? $options[$args['field_id']] : $default_value );
74 $display_none_on_load = ( isset( $args['display_none_on_load'] ) ? $args['display_none_on_load'] : false );
75 if ( $display_none_on_load ) {
76 $inline_style = 'display:none;';
77 } else {
78 $inline_style = '';
79 }
80 echo '<input type="checkbox" id="' . esc_attr( $field_name ) . '" class="asenha-subfield-checkbox" style="' . esc_attr( $inline_style ) . '" name="' . esc_attr( $field_name ) . '" ' . checked( $field_option_value, true, false ) . '>';
81 echo '<label for="' . esc_attr( $field_name ) . '" class="asenha-subfield-checkbox-label" style="' . esc_attr( $inline_style ) . '">' . wp_kses_post( $field_label ) . '</label>';
82 }
83
84 /**
85 * Render checkbox field as sub-field of a toggle/switcher checkbox
86 *
87 * @since 1.3.0
88 */
89 function render_checkbox_subfield( $args ) {
90 $option_name = $args['option_name'];
91 if ( !empty( $option_name ) ) {
92 $options = get_option( $option_name, array() );
93 } else {
94 $options = get_option( ASENHA_SLUG_U, array() );
95 }
96 $field_name = $args['field_name'];
97 $field_label = $args['field_label'];
98 $parent_field_id = ( isset( $args['parent_field_id'] ) ? $args['parent_field_id'] : '' );
99 $sub_field_id = ( isset( $args['sub_field_id'] ) ? $args['sub_field_id'] : '' );
100 if ( in_array( $parent_field_id, array('enable_duplication_for', 'enable_rest_api_for') ) ) {
101 // Default is true/enabled. Usually for options introduced at a later date where the previous default is true/enabled.
102 $default_value = true;
103 } else {
104 // Default is false / checked
105 $default_value = false;
106 }
107 if ( !empty( $parent_field_id ) && !empty( $sub_field_id ) && isset( $options[$parent_field_id][$sub_field_id][$args['field_id']] ) ) {
108 $field_option_value = $options[$parent_field_id][$sub_field_id][$args['field_id']];
109 } elseif ( in_array( $parent_field_id, array('redirect_after_login_for_separate', 'redirect_after_logout_for_separate'), true ) && !empty( $sub_field_id ) ) {
110 $field_option_value = ( isset( $options[$sub_field_id][$args['field_id']] ) ? $options[$sub_field_id][$args['field_id']] : $default_value );
111 } elseif ( empty( $parent_field_id ) && !empty( $args['field_id'] ) ) {
112 $field_option_value = ( isset( $options[$args['field_id']] ) ? $options[$args['field_id']] : $default_value );
113 } else {
114 $field_option_value = ( isset( $options[$parent_field_id][$args['field_id']] ) ? $options[$parent_field_id][$args['field_id']] : $default_value );
115 }
116 echo '<input type="checkbox" id="' . esc_attr( $field_name ) . '" class="asenha-subfield-checkbox" name="' . esc_attr( $field_name ) . '" ' . checked( $field_option_value, true, false ) . '>';
117 echo '<label for="' . esc_attr( $field_name ) . '" class="asenha-subfield-checkbox-label">' . wp_kses_post( $field_label ) . '</label>';
118 if ( !empty( $args['field_description'] ) ) {
119 $desc_display = ( isset( $args['field_description_display'] ) ? $args['field_description_display'] : 'inline' );
120 if ( 'tooltip' === $desc_display ) {
121 echo '<span class="asenha-info-tooltip-wrap">';
122 echo '<button type="button" class="asenha-info-tooltip-toggle" aria-label="' . esc_attr__( 'More information', 'admin-site-enhancements' ) . '">';
123 echo '<span class="dashicons dashicons-info-outline" aria-hidden="true"></span>';
124 echo '</button>';
125 echo '<span class="asenha-info-tooltip" role="tooltip">' . esc_html( $args['field_description'] ) . '</span>';
126 echo '</span>';
127 } else {
128 echo '<div class="asenha-subfield-description">' . wp_kses_post( $args['field_description'] ) . '</div>';
129 }
130 }
131 }
132
133 /**
134 * Render radio buttons field as sub-field of a toggle/switcher checkbox
135 *
136 * @since 1.3.0
137 */
138 function render_radio_buttons_subfield( $args ) {
139 $option_name = $args['option_name'];
140 if ( !empty( $option_name ) ) {
141 $options = get_option( $option_name, array() );
142 } else {
143 $options = get_option( ASENHA_SLUG_U, array() );
144 }
145 $field_id = $args['field_id'];
146 $field_name = $args['field_name'];
147 $field_radios = $args['field_radios'];
148 if ( !empty( $args['field_default'] ) ) {
149 $default_value = $args['field_default'];
150 } else {
151 $default_value = false;
152 }
153 $field_description = ( isset( $args['field_description'] ) ? $args['field_description'] : '' );
154 $field_option_value = ( isset( $options[$field_id] ) ? $options[$field_id] : $default_value );
155 echo '<div class="asenha-subfield-radio-button-wrapper">';
156 foreach ( $field_radios as $radio_label => $radio_value ) {
157 echo '<input type="radio" id="' . esc_attr( $field_id . '_' . $radio_value ) . '" class="asenha-subfield-radio-button" name="' . esc_attr( $field_name ) . '" value="' . esc_attr( $radio_value ) . '" ' . checked( $radio_value, $field_option_value, false ) . '>';
158 echo '<label for="' . esc_attr( $field_id . '_' . $radio_value ) . '" class="asenha-subfield-radio-button-label">' . wp_kses_post( $radio_label ) . '</label>';
159 }
160 echo '</div>';
161 if ( !empty( $field_description ) ) {
162 echo '<div class="asenha-subfield-description">' . wp_kses_post( $field_description ) . '</div>';
163 }
164 }
165
166 /**
167 * Render checkboxes field as sub-field of a toggle/switcher checkbox
168 *
169 * @since 6.9.2
170 */
171 function render_checkboxes_subfield( $args ) {
172 $options = get_option( ASENHA_SLUG_U, array() );
173 $field_id = $args['field_id'];
174 $field_name = $args['field_name'];
175 $field_options = $args['field_options'];
176 $layout = ( !empty( $args['layout'] ) ? $args['layout'] : 'horizontal' );
177 $default_value = ( !empty( $args['field_default'] ) ? $args['field_default'] : array() );
178 $parent_field_id = ( isset( $args['parent_field_id'] ) ? $args['parent_field_id'] : '' );
179 $sub_field_id = ( isset( $args['sub_field_id'] ) ? $args['sub_field_id'] : '' );
180 if ( !empty( $parent_field_id ) && !empty( $sub_field_id ) && isset( $options[$parent_field_id][$sub_field_id][$field_id] ) ) {
181 $field_option_value = (array) $options[$parent_field_id][$sub_field_id][$field_id];
182 } else {
183 $field_option_value = ( isset( $options[$field_id] ) ? (array) $options[$field_id] : $default_value );
184 }
185 // Back-compat: legacy naming for Two-Factor Recovery Codes.
186 if ( in_array( $field_id, array('two_factor_available_providers', 'available_providers'), true ) && is_array( $field_option_value ) ) {
187 $field_option_value = array_map( static function ( $provider_key ) {
188 return ( 'backup_codes' === $provider_key ? 'recovery_codes' : $provider_key );
189 }, $field_option_value );
190 }
191 echo '<div class="wrapper-for-checkboxes ' . esc_attr( $layout ) . '">';
192 foreach ( $field_options as $option_label => $option_value ) {
193 $checkbox_id = ( !empty( $parent_field_id ) && !empty( $sub_field_id ) ? $parent_field_id . '_' . $sub_field_id . '_' . $field_id . '_' . $option_value : $field_id . '_' . $option_value );
194 echo '<div>';
195 echo '<input type="checkbox" id="' . esc_attr( $checkbox_id ) . '" class="asenha-subfield-radio-button" name="' . esc_attr( $field_name ) . '" value="' . esc_attr( $option_value ) . '" ' . checked( in_array( $option_value, $field_option_value ), 1, false ) . '>';
196 echo '<label for="' . esc_attr( $checkbox_id ) . '" class="asenha-subfield-radio-button-label">' . wp_kses_post( $option_label ) . '</label>';
197 echo '</div>';
198 }
199 echo '</div>';
200 }
201
202 /**
203 * Render text field as sub-field of a toggle/switcher checkbox
204 *
205 * @since 1.4.0
206 */
207 function render_text_subfield( $args ) {
208 $option_name = $args['option_name'];
209 if ( !empty( $option_name ) ) {
210 $options = get_option( $option_name, array() );
211 } else {
212 $options = get_option( ASENHA_SLUG_U, array() );
213 }
214 $field_id = $args['field_id'];
215 $field_slug = str_replace( '_', '-', $field_id );
216 $field_name = $args['field_name'];
217 $field_width_classname = ( isset( $args['field_width_classname'] ) ? $args['field_width_classname'] : '' );
218 $field_type = $args['field_type'];
219 $field_prefix = $args['field_prefix'];
220 $field_suffix = $args['field_suffix'];
221 $field_is_read_only = ( isset( $args['read_only'] ) ? $args['read_only'] : false );
222 $field_is_read_only_output = ( $field_is_read_only ? ' readonly="readonly"' : '' );
223 $field_placeholder = ( isset( $args['field_placeholder'] ) ? $args['field_placeholder'] : '' );
224 $field_description = $args['field_description'];
225 if ( isset( $options[$field_id] ) ) {
226 if ( 'live_site_url' == $field_id ) {
227 if ( false !== strpos( $options[$field_id], 'http' ) ) {
228 $field_option_value = $options[$field_id];
229 } else {
230 // Legacy support for when base64 encoding was used prior to v7.3.1
231 $field_option_value = base64_decode( $options[$field_id] );
232 }
233 } elseif ( 'login_page_logo_image_width' == $field_id || 'login_page_logo_image_height' == $field_id ) {
234 if ( isset( $options[$field_id] ) ) {
235 if ( is_numeric( $options[$field_id] ) ) {
236 $field_option_value = $options[$field_id];
237 } else {
238 $field_option_value = str_replace( 'px', '', $options[$field_id] );
239 }
240 }
241 } else {
242 $field_option_value = $options[$field_id];
243 }
244 } else {
245 if ( 'altcha_secret_key' == $field_id ) {
246 $field_option_value = '';
247 } else {
248 $field_option_value = '';
249 }
250 }
251 if ( !empty( $field_prefix ) && !empty( $field_suffix ) ) {
252 $field_classname = ' with-prefix with-suffix';
253 } elseif ( !empty( $field_prefix ) && empty( $field_suffix ) ) {
254 $field_classname = ' with-prefix';
255 } elseif ( empty( $field_prefix ) && !empty( $field_suffix ) ) {
256 $field_classname = ' with-suffix';
257 } else {
258 $field_classname = '';
259 }
260 if ( !empty( $field_width_classname ) ) {
261 $field_classname .= ' ' . $field_width_classname;
262 }
263 echo wp_kses_post( $field_prefix ) . '<input type="text" id="' . esc_attr( $field_name ) . '" class="asenha-subfield-text' . esc_attr( $field_classname ) . '" name="' . esc_attr( $field_name ) . '" placeholder="' . esc_attr( $field_placeholder ) . '" value="' . esc_attr( $field_option_value ) . '"' . esc_html( $field_is_read_only_output ) . '>' . wp_kses_post( $field_suffix );
264 echo '<label for="' . esc_attr( $field_name ) . '" class="asenha-subfield-checkbox-label">' . esc_html( $field_description ) . '</label>';
265 }
266
267 /**
268 * Render text field as sub-field of a checkbox field. e.g. in Redirect After Login module
269 *
270 * @since 7.3.3
271 */
272 function render_checkbox_field_text_subfield( $args ) {
273 $option_name = $args['option_name'];
274 if ( !empty( $option_name ) ) {
275 $options = get_option( $option_name, array() );
276 } else {
277 $options = get_option( ASENHA_SLUG_U, array() );
278 }
279 $field_id = $args['field_id'];
280 $field_name = $args['field_name'];
281 $field_width_classname = ( isset( $args['field_width_classname'] ) ? $args['field_width_classname'] : '' );
282 $field_type = $args['field_type'];
283 $field_prefix = $args['field_prefix'];
284 $field_suffix = $args['field_suffix'];
285 $field_placeholder = ( isset( $args['field_placeholder'] ) ? $args['field_placeholder'] : '' );
286 $field_description = $args['field_description'];
287 $parent_field_id = ( isset( $args['parent_field_id'] ) ? $args['parent_field_id'] : '' );
288 $sub_field_id = ( isset( $args['sub_field_id'] ) ? $args['sub_field_id'] : '' );
289 if ( 'redirect_after_login_for_separate' == $parent_field_id && !empty( $sub_field_id ) ) {
290 $field_option_value = ( isset( $options[$sub_field_id][$field_id] ) ? $options[$sub_field_id][$field_id] : '' );
291 } else {
292 $field_option_value = ( isset( $options[$parent_field_id][$field_id] ) ? $options[$parent_field_id][$field_id] : '' );
293 }
294 // $field_option_value = ( isset( $options[$field_id] ) ) ? $options[$field_id] : '';
295 $field_option_value = ( isset( $options[$parent_field_id . '_slug'][$args['field_id']] ) ? $options[$parent_field_id . '_slug'][$field_id] : '' );
296 if ( !empty( $field_prefix ) && !empty( $field_suffix ) ) {
297 $field_classname = ' with-prefix with-suffix';
298 } elseif ( !empty( $field_prefix ) && empty( $field_suffix ) ) {
299 $field_classname = ' with-prefix';
300 } elseif ( empty( $field_prefix ) && !empty( $field_suffix ) ) {
301 $field_classname = ' with-suffix';
302 } else {
303 $field_classname = '';
304 }
305 if ( !empty( $field_width_classname ) ) {
306 $field_classname .= ' ' . $field_width_classname;
307 }
308 echo wp_kses_post( $field_prefix ) . '<input type="text" id="' . esc_attr( $field_name ) . '" class="asenha-subfield-text' . esc_attr( $field_classname ) . '" name="' . esc_attr( $field_name ) . '" placeholder="' . esc_attr( $field_placeholder ) . '" value="' . esc_attr( $field_option_value ) . '">' . wp_kses_post( $field_suffix );
309 echo '<label for="' . esc_attr( $field_name ) . '" class="asenha-subfield-checkbox-label">' . esc_html( $field_description ) . '</label>';
310 }
311
312 /**
313 * Render description field as sub-field of a toggle/switcher checkbox
314 *
315 * @since 4.6.0
316 */
317 function render_description_subfield( $args ) {
318 $field_description = $args['field_description'];
319 echo '<div class="asenha-subfield-description">' . wp_kses( $field_description, get_kses_with_style_src_svg_ruleset() ) . '</div>';
320 }
321
322 /**
323 * Render View Admin as Role recovery URL description at display time.
324 *
325 * @since 8.8.5
326 * @param array $args Settings field arguments.
327 * @return void
328 */
329 function render_view_admin_as_role_recovery_description( $args ) {
330 $view_admin_as_role = new View_Admin_As_Role();
331 $recovery_url = $view_admin_as_role->get_recovery_url_for_settings( get_current_user_id() );
332 $field_description = '<div class="asenha-warning"><strong>' . sprintf(
333 /* translators: %s is the secret recovery URL or instructional text */
334 __( 'If something goes wrong</strong> and you need to regain access to your account as an administrator, please visit the following URL: <br /><strong>%s</strong><br /><br />If you use <strong>Ninja Firewall</strong>, please uncheck "Block attempts to gain administrative privileges" in the Firewall Policies settings before you try to view as a non-admin user role to <strong>prevent being locked out</strong> of your admin account.', 'admin-site-enhancements' ),
335 esc_html( $recovery_url )
336 ) . '<br /><br />' . __( 'In any case, please also <strong>create at least one backup admin user</strong> as a last resort should your primary admin user fails to properly login as admin. With this second admin user, you can also restore the admin role for your primary admin user.', 'admin-site-enhancements' ) . '</div>';
337 echo '<div class="asenha-subfield-description">' . wp_kses( $field_description, get_kses_with_style_src_svg_ruleset() ) . '</div>';
338 }
339
340 /**
341 * Render heading for sub-fields of a toggle/switcher checkbox
342 *
343 * @since 5.0.0
344 */
345 function render_subfields_heading( $args ) {
346 $subfields_heading = $args['subfields_heading'];
347 echo '<div class="asenha-subfields-heading">' . wp_kses_post( $subfields_heading ) . '</div>';
348 }
349
350 /**
351 * Render password field as sub-field of a toggle/switcher checkbox
352 *
353 * @since 4.1.0
354 */
355 function render_password_subfield( $args ) {
356 $option_name = $args['option_name'];
357 if ( !empty( $option_name ) ) {
358 $options = get_option( $option_name, array() );
359 } else {
360 $options = get_option( ASENHA_SLUG_U, array() );
361 }
362 $field_id = $args['field_id'];
363 $field_name = $args['field_name'];
364 $field_type = $args['field_type'];
365 $field_prefix = $args['field_prefix'];
366 $field_suffix = $args['field_suffix'];
367 $field_description = $args['field_description'];
368 $field_option_value = ( isset( $options[$args['field_id']] ) ? $options[$args['field_id']] : '' );
369 $hide_stored_value = ( isset( $args['hide_stored_value'] ) ? (bool) $args['hide_stored_value'] : false );
370 if ( !empty( $field_prefix ) && !empty( $field_suffix ) ) {
371 $field_classname = ' with-prefix with-suffix';
372 } elseif ( !empty( $field_prefix ) && empty( $field_suffix ) ) {
373 $field_classname = ' with-prefix';
374 } elseif ( empty( $field_prefix ) && !empty( $field_suffix ) ) {
375 $field_classname = ' with-suffix';
376 } else {
377 $field_classname = '';
378 }
379 if ( $hide_stored_value ) {
380 $field_option_value = '';
381 }
382 $placeholder = ( isset( $args['field_placeholder'] ) ? $args['field_placeholder'] : '' );
383 echo wp_kses_post( $field_prefix ) . '<input type="password" id="' . esc_attr( $field_name ) . '" class="asenha-subfield-password' . esc_attr( $field_classname ) . '" name="' . esc_attr( $field_name ) . '" placeholder="' . esc_attr( $placeholder ) . '" size="24" autocomplete="off" value="' . esc_attr( $field_option_value ) . '">' . wp_kses_post( $field_suffix );
384 echo '<label for="' . esc_attr( $field_name ) . '" class="asenha-subfield-checkbox-label">' . esc_html( $field_description ) . '</label>';
385 }
386
387 /**
388 * Render number field as sub-field of a toggle/switcher checkbox
389 *
390 * @since 1.4.0
391 */
392 function render_number_subfield( $args ) {
393 $option_name = $args['option_name'];
394 if ( !empty( $option_name ) ) {
395 $options = get_option( $option_name, array() );
396 } else {
397 $options = get_option( ASENHA_SLUG_U, array() );
398 }
399 $field_id = $args['field_id'];
400 $field_name = $args['field_name'];
401 $field_type = $args['field_type'];
402 $field_prefix = $args['field_prefix'];
403 $field_suffix = $args['field_suffix'];
404 $field_intro = $args['field_intro'];
405 $field_placeholder = ( isset( $args['field_placeholder'] ) ? $args['field_placeholder'] : '' );
406 $field_min = ( isset( $args['field_min'] ) ? $args['field_min'] : 1 );
407 $field_max = ( isset( $args['field_max'] ) ? $args['field_max'] : 10 );
408 $field_description = ( isset( $args['field_description'] ) ? $args['field_description'] : '' );
409 $field_option_value = ( isset( $options[$args['field_id']] ) ? $options[$args['field_id']] : '' );
410 if ( !empty( $field_prefix ) && !empty( $field_suffix ) ) {
411 $field_classname = ' with-prefix with-suffix';
412 } elseif ( !empty( $field_prefix ) && empty( $field_suffix ) ) {
413 $field_classname = ' with-prefix';
414 } elseif ( empty( $field_prefix ) && !empty( $field_suffix ) ) {
415 $field_classname = ' with-suffix';
416 } else {
417 $field_classname = '';
418 }
419 echo '<div class="asenha-subfield-number-wrapper">';
420 if ( !empty( $field_intro ) ) {
421 echo '<div class="asenha-subfield-number-intro">' . wp_kses_post( $field_intro ) . '</div>';
422 }
423 echo '<div>' . wp_kses_post( $field_prefix ) . '<input type="number" id="' . esc_attr( $field_name ) . '" class="asenha-subfield-number' . esc_attr( $field_classname ) . '" name="' . esc_attr( $field_name ) . '" placeholder="' . esc_attr( $field_placeholder ) . '" step="1" min="' . esc_attr( $field_min ) . '" max="' . esc_attr( $field_max ) . '" value="' . esc_attr( $field_option_value ) . '">' . wp_kses_post( $field_suffix ) . '</div>';
424 if ( !empty( $field_description ) ) {
425 echo '<div class="asenha-subfield-number-description">' . wp_kses_post( $field_description ) . '</div>';
426 }
427 echo '</div>';
428 }
429
430 /**
431 * Render select field as sub-field of a toggle/switcher checkbox
432 *
433 * @since 1.4.0
434 */
435 function render_select_subfield( $args ) {
436 $option_name = $args['option_name'];
437 if ( !empty( $option_name ) ) {
438 $options = get_option( $option_name, array() );
439 } else {
440 $options = get_option( ASENHA_SLUG_U, array() );
441 }
442 $field_id = $args['field_id'];
443 $field_name = $args['field_name'];
444 $field_type = $args['field_type'];
445 $field_prefix = $args['field_prefix'];
446 $field_suffix = $args['field_suffix'];
447 $field_select_options = $args['field_select_options'];
448 $field_select_default = $args['field_select_default'];
449 $field_intro = $args['field_intro'];
450 $field_description = $args['field_description'];
451 $parent_field_id = ( isset( $args['parent_field_id'] ) ? $args['parent_field_id'] : '' );
452 $sub_field_id = ( isset( $args['sub_field_id'] ) ? $args['sub_field_id'] : '' );
453 if ( !empty( $field_select_default ) ) {
454 $default_value = $field_select_default;
455 } else {
456 $default_value = false;
457 }
458 if ( !empty( $parent_field_id ) && !empty( $sub_field_id ) && isset( $options[$parent_field_id][$sub_field_id][$field_id] ) ) {
459 $field_option_value = $options[$parent_field_id][$sub_field_id][$field_id];
460 } else {
461 $field_option_value = ( isset( $options[$field_id] ) ? $options[$field_id] : $default_value );
462 }
463 if ( !empty( $field_prefix ) && !empty( $field_suffix ) ) {
464 $field_classname = ' with-prefix with-suffix';
465 } elseif ( !empty( $field_prefix ) && empty( $field_suffix ) ) {
466 $field_classname = ' with-prefix';
467 } elseif ( empty( $field_prefix ) && !empty( $field_suffix ) ) {
468 $field_classname = ' with-suffix';
469 } else {
470 $field_classname = '';
471 }
472 $display_none_on_load = ( isset( $args['display_none_on_load'] ) ? $args['display_none_on_load'] : false );
473 if ( $display_none_on_load ) {
474 $inline_style = 'display:none;';
475 } else {
476 $inline_style = '';
477 }
478 echo '<div class="asenha-subfield-select-wrapper">';
479 if ( !empty( $field_intro ) ) {
480 echo '<div class="asenha-subfield-select-intro">' . wp_kses_post( $field_intro ) . '</div>';
481 }
482 echo '<div style="' . esc_attr( $inline_style ) . '" class="asenha-subfield-select-inner">' . wp_kses_post( $field_prefix );
483 echo '<select name="' . esc_attr( $field_name ) . '" class="asenha-subfield-select' . esc_attr( $field_classname ) . '">';
484 foreach ( $field_select_options as $label => $value ) {
485 echo '<option value="' . esc_attr( $value ) . '" ' . selected( $value, $field_option_value, false ) . '>' . esc_html( $label ) . '</option>';
486 }
487 echo '</select>';
488 echo wp_kses_post( $field_suffix ) . '</div>';
489 if ( !empty( $field_description ) ) {
490 echo '<div class="asenha-subfield-select-description">' . wp_kses_post( $field_description ) . '</div>';
491 }
492 echo '</div>';
493 }
494
495 /**
496 * Render textarea field as sub-field of a toggle/switcher checkbox
497 *
498 * @since 2.3.0
499 */
500 function render_textarea_subfield( $args ) {
501 $option_name = $args['option_name'];
502 if ( !empty( $option_name ) ) {
503 $options = get_option( $option_name, array() );
504 } else {
505 $options = get_option( ASENHA_SLUG_U, array() );
506 }
507 $field_id = $args['field_id'];
508 $field_slug = $args['field_slug'];
509 $field_name = $args['field_name'];
510 $field_type = $args['field_type'];
511 $field_rows = $args['field_rows'];
512 $field_intro = $args['field_intro'];
513 $field_description = $args['field_description'];
514 $field_placeholder = ( isset( $args['field_placeholder'] ) ? $args['field_placeholder'] : '' );
515 // Always load textarea content from robots.txt URL, whether it's a real, custom-made robots.txt file or a virtual one generated by WordPress
516 if ( 'robots_txt_content' == $field_id ) {
517 if ( array_key_exists( 'manage_robots_txt', $options ) ) {
518 // Manage robots.txt feature has been enabled before
519 if ( !$options['manage_robots_txt'] ) {
520 // Manage robots.txt feature is NOT enabled
521 if ( array_key_exists( 'robots_txt_content', $options ) && $options['robots_txt_content'] ) {
522 $field_option_value = $options['robots_txt_content'];
523 } else {
524 $robots_txt_content = wp_remote_get( get_site_url() . '/robots.txt' );
525 $robots_txt_content = esc_textarea( trim( wp_remote_retrieve_body( $robots_txt_content ) ) );
526 $field_option_value = $robots_txt_content;
527 }
528 } else {
529 // Manage robots.txt feature is enabled
530 if ( array_key_exists( 'robots_txt_content', $options ) && $options['robots_txt_content'] ) {
531 $field_option_value = $options['robots_txt_content'];
532 } else {
533 $robots_txt_content = wp_remote_get( get_site_url() . '/robots.txt' );
534 $robots_txt_content = esc_textarea( trim( wp_remote_retrieve_body( $robots_txt_content ) ) );
535 $field_option_value = $robots_txt_content;
536 }
537 }
538 } else {
539 // Manage robots.txt feature has never been enabled yet
540 $robots_txt_content = wp_remote_get( get_site_url() . '/robots.txt' );
541 $robots_txt_content = esc_textarea( trim( wp_remote_retrieve_body( $robots_txt_content ) ) );
542 $field_option_value = $robots_txt_content;
543 }
544 } else {
545 $field_option_value = ( isset( $options[$args['field_id']] ) ? $options[$args['field_id']] : '' );
546 }
547 echo '<div class="asenha-subfield-textarea-wrapper">';
548 if ( !empty( $field_intro ) ) {
549 echo '<div class="asenha-subfield-textarea-intro">' . wp_kses_post( $field_intro ) . '</div>';
550 }
551 echo '<textarea rows="' . esc_attr( $field_rows ) . '" class="asenha-subfield-textarea" id="' . esc_attr( $field_name ) . '" name="' . esc_attr( $field_name ) . '" placeholder="' . esc_attr( $field_placeholder ) . '">' . esc_textarea( $field_option_value ) . '</textarea>';
552 if ( !empty( $field_description ) ) {
553 echo '<div class="asenha-subfield-textarea-description">' . wp_kses_post( $field_description ) . '</div>';
554 }
555 echo '</div>';
556 }
557
558 /**
559 * Render textarea field as sub-field of a toggle/switcher checkbox
560 *
561 * @since 2.3.0
562 */
563 function render_wpeditor_subfield( $args ) {
564 $option_name = $args['option_name'];
565 if ( !empty( $option_name ) ) {
566 $options = get_option( $option_name, array() );
567 } else {
568 $options = get_option( ASENHA_SLUG_U, array() );
569 }
570 $field_id = $args['field_id'];
571 $field_slug = $args['field_slug'];
572 $field_name = $args['field_name'];
573 $field_type = $args['field_type'];
574 $field_intro = $args['field_intro'];
575 $field_description = $args['field_description'];
576 $field_placeholder = ( isset( $args['field_placeholder'] ) ? $args['field_placeholder'] : '' );
577 $field_option_value = ( isset( $options[$args['field_id']] ) ? $options[$args['field_id']] : '' );
578 $editor_settings = $args['editor_settings'];
579 // https://developer.wordpress.org/reference/classes/_wp_editors/parse_settings/
580 echo '<div class="asenha-subfield-wpeditor-wrapper">';
581 if ( !empty( $field_intro ) ) {
582 echo '<div class="asenha-subfield-wpeditor-intro">' . wp_kses_post( $field_intro ) . '</div>';
583 }
584 $content = $field_option_value;
585 $editor_id = str_replace( array('[', ']'), array('--', ''), $field_name );
586 // vi( $editor_id, '', 'for ' . $field_name );
587 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
588 echo wp_editor( $content, $editor_id, $editor_settings );
589 if ( !empty( $field_description ) ) {
590 echo '<div class="asenha-subfield-wpeditor-description">' . wp_kses_post( $field_description ) . '</div>';
591 }
592 echo '</div>';
593 }
594
595 /**
596 * Render custom HTML subfield
597 *
598 * @since 5.3.0
599 */
600 function render_custom_html( $args ) {
601 echo wp_kses( $args['html'], get_kses_with_custom_html_ruleset() );
602 }
603
604 /**
605 * Render media subfield
606 *
607 * @since 6.2.2
608 */
609 function render_media_subfield( $args ) {
610 $field_id = $args['field_id'];
611 $field_slug = $args['field_slug'];
612 $field_name = $args['field_name'];
613 $field_media_frame_title = $args['field_media_frame_title'];
614 $field_media_frame_multiple = $args['field_media_frame_multiple'];
615 $field_media_frame_library_type = $args['field_media_frame_library_type'];
616 $field_media_frame_button_text = $args['field_media_frame_button_text'];
617 $field_intro = $args['field_intro'];
618 $field_description = $args['field_description'];
619 $options = get_option( $args['option_name'], array() );
620 $field_option_value = ( isset( $options[$field_id] ) ? $options[$field_id] : '' );
621 ?>
622 <div class="media-subfield-wrapper">
623 <input id="<?php
624 echo esc_attr( $field_slug );
625 ?>" class="image-picker" type="text" size="40" name="<?php
626 echo esc_attr( $field_name );
627 ?>" value="<?php
628 echo esc_url( $field_option_value );
629 ?>" />
630 <button id="<?php
631 echo esc_attr( $field_slug );
632 ?>-button" class="image-picker-button button-secondary"><?php
633 echo __( 'Select an Image', 'admin-site-enhancements' );
634 ?></button>
635 <?php
636 if ( array_key_exists( 'field_hidden_inputs', $args ) && is_array( $args['field_hidden_inputs'] ) ) {
637 foreach ( $args['field_hidden_inputs'] as $hidden_input ) {
638 $hidden_option_key = ( isset( $hidden_input['option_key'] ) ? sanitize_key( $hidden_input['option_key'] ) : '' );
639 $hidden_id = ( isset( $hidden_input['field_id'] ) ? (string) $hidden_input['field_id'] : '' );
640 $hidden_name = ( isset( $hidden_input['field_name'] ) ? (string) $hidden_input['field_name'] : '' );
641 if ( empty( $hidden_option_key ) || empty( $hidden_id ) || empty( $hidden_name ) ) {
642 continue;
643 }
644 $hidden_value = ( isset( $options[$hidden_option_key] ) ? absint( $options[$hidden_option_key] ) : 0 );
645 echo '<input type="hidden" id="' . esc_attr( $hidden_id ) . '" class="asenha-hidden-media-dim" name="' . esc_attr( $hidden_name ) . '" value="' . esc_attr( $hidden_value ) . '" />';
646 }
647 }
648 ?>
649 <?php
650 if ( !empty( $field_description ) ) {
651 echo '<div class="asenha-subfield-description media-subfield">' . wp_kses_post( $field_description ) . '</div>';
652 }
653 ?>
654 </div>
655 <?php
656 }
657
658 /**
659 * Render media subfield
660 *
661 * @since 6.2.2
662 */
663 function render_color_picker_subfield( $args ) {
664 $common_methods = new Common_Methods();
665 $field_id = $args['field_id'];
666 $field_slug = $args['field_slug'];
667 $field_name = $args['field_name'];
668 $field_intro = $args['field_intro'];
669 $field_description = $args['field_description'];
670 $field_default_value = $args['field_default_value'];
671 $options = get_option( $args['option_name'], array() );
672 $field_option_value = ( isset( $options[$field_id] ) ? $options[$field_id] : $field_default_value );
673 ?>
674 <div class="color-subfield-wrapper">
675 <input type="text" id="<?php
676 echo esc_attr( $field_slug );
677 ?>" name="<?php
678 echo esc_attr( $field_name );
679 ?>" value="<?php
680 echo esc_attr( $common_methods->sanitize_hex_color( $field_option_value ) );
681 ?>" data-default-color="<?php
682 echo esc_attr( $common_methods->sanitize_hex_color( $field_default_value ) );
683 ?>" class="color-picker"/>
684 </div>
685 <?php
686 }
687
688 /**
689 * Render text field as sub-field of a toggle/switcher checkbox
690 *
691 * @since 1.4.0
692 */
693 function render_content_toggler( $args ) {
694 $field_id = $args['field_id'];
695 $field_slug = $args['field_slug'];
696 $field_slug = str_replace( '_', '-', $field_id );
697 $show_text = ( isset( $args['show_text'] ) ? $args['show_text'] : '' );
698 $hide_text = ( isset( $args['hide_text'] ) ? $args['hide_text'] : '' );
699 $content_selector = ( isset( $args['content_selector'] ) ? $args['content_selector'] : '' );
700 ?>
701 <div class="subfield-content-toggler <?php
702 echo esc_attr( $field_slug );
703 ?>"><a href="#" data-show-text="<?php
704 echo esc_attr( $show_text );
705 ?>" data-hide-text="<?php
706 echo esc_attr( $hide_text );
707 ?>" data-target-selector="<?php
708 echo esc_attr( $content_selector );
709 ?>" class="asenha-content-toggler" data-expanded="no"><?php
710 echo esc_html( $show_text );
711 ?> <span></span></a></div>
712 <?php
713 }
714
715 /**
716 * Human-readable label fragment for an admin menu separator slug (AMO sortable UI).
717 *
718 * WordPress core and plugins use slugs like separator1, separator-last, separator-woocommerce.
719 * Internal slugs stay unchanged; this output is display-only (Spacer-* wording).
720 *
721 * @since 8.5.3
722 *
723 * @param string $menu_slug Separator menu slug from global $menu item index 2.
724 * @return string Middle segment only (without surrounding ~~); safe for esc_html when wrapped.
725 */
726 private function format_admin_menu_separator_slug_for_display( $menu_slug ) {
727 $name = str_replace( 'separator', 'Spacer-', $menu_slug );
728 $name = str_replace( '--last', '-Last', $name );
729 $name = str_replace( '--woocommerce', '--WooCommerce', $name );
730 return $name;
731 }
732
733 /**
734 * Render sortable menu field
735 *
736 * @since 2.0.0
737 */
738 function render_sortable_menu() {
739 $triangle_right_icon = '<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 16 16"><path fill="currentColor" d="M14.222 6.687a1.5 1.5 0 0 1 0 2.629l-10 5.499A1.5 1.5 0 0 1 2 13.5V2.502a1.5 1.5 0 0 1 2.223-1.314z"/></svg>';
740 ?>
741 <ul id="custom-admin-menu" class="menu ui-sortable">
742 <?php
743 global $menu, $submenu;
744 $common_methods = new Common_Methods();
745 $options_extra = get_option( ASENHA_SLUG_U . '_extra', array() );
746 $options = ( isset( $options_extra['admin_menu'] ) ? $options_extra['admin_menu'] : array() );
747 // Parsed early so Pro merge of custom spacers and render loops can use the same list.
748 $deleted_separators = ( isset( $options['custom_menu_deleted_separators'] ) ? $options['custom_menu_deleted_separators'] : '' );
749 $deleted_separators_array = array();
750 if ( is_string( $deleted_separators ) && !empty( $deleted_separators ) ) {
751 $deleted_separators_array = json_decode( $deleted_separators, true );
752 if ( !is_array( $deleted_separators_array ) ) {
753 $deleted_separators_array = array();
754 }
755 }
756 // Set menu items to be excluded from title renaming. These are from WordPress core.
757 $renaming_not_allowed = array(
758 'menu-dashboard',
759 'menu-pages',
760 // 'menu-posts',
761 'menu-media',
762 'menu-comments',
763 'menu-appearance',
764 'menu-plugins',
765 'menu-users',
766 'menu-tools',
767 'menu-settings',
768 );
769 // Get custom menu item titles
770 if ( array_key_exists( 'custom_menu_titles', $options ) ) {
771 $custom_menu_titles = $options['custom_menu_titles'];
772 $custom_menu_titles = explode( ',', $custom_menu_titles );
773 } else {
774 $custom_menu_titles = array();
775 }
776 // Get menu items hidden by toggle
777 $menu_hidden_by_toggle = $common_methods->get_menu_hidden_by_toggle();
778 $i = 1;
779 // Check if there's an existing custom menu order data stored in options
780 if ( array_key_exists( 'custom_menu_order', $options ) ) {
781 $custom_menu = $options['custom_menu_order'];
782 $custom_menu = explode( ',', $custom_menu );
783 $menu_key_in_use = array();
784 // Render sortables with data in custom menu order
785 foreach ( $custom_menu as $custom_menu_item ) {
786 foreach ( $menu as $menu_key => $menu_info ) {
787 // Skip deleted built-in separators only for real separator rows; Pro distinguishes ASE additional-separator rows.
788 $skip_deleted_separator = false;
789 if ( isset( $menu_info[2], $menu_info[4] ) && false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
790 $skip_deleted_separator = in_array( $menu_info[2], $deleted_separators_array, true );
791 }
792 if ( $skip_deleted_separator ) {
793 continue;
794 }
795 if ( false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
796 $menu_item_title = $menu_info[2];
797 $menu_item_id = $menu_info[2];
798 } else {
799 $menu_item_title = $menu_info[0];
800 $menu_item_id = $menu_info[5];
801 }
802 $menu_url_fragment = '';
803 if ( $custom_menu_item == $menu_item_id ) {
804 $menu_item_id_transformed = $common_methods->transform_menu_item_id( $menu_item_id );
805 $is_custom_menu = 'no';
806 $menu_required_capability = ( isset( $menu_info[1] ) ? $menu_info[1] : '' );
807 ?>
808 <li id="<?php
809 echo esc_attr( $menu_item_id );
810 ?>" class="menu-item parent-menu-item menu-item-depth-0" data-custom-menu-item="<?php
811 echo esc_attr( $is_custom_menu );
812 ?>" data-menu-slug="<?php
813 echo esc_attr( $menu_info[2] );
814 ?>">
815 <div class="menu-item-bar">
816 <div class="menu-item-handle">
817 <span class="dashicons dashicons-menu"></span>
818 <div class="item-title">
819 <div class="title-wrapper">
820 <span class="menu-item-title">
821 <?php
822 if ( false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
823 echo '~~ ' . esc_html( $this->format_admin_menu_separator_slug_for_display( $menu_info[2] ) ) . ' ~~';
824 } else {
825 if ( in_array( $menu_item_id, $renaming_not_allowed ) ) {
826 $menu_item_title = $menu_info[0];
827 echo wp_kses_post( $common_methods->strip_html_tags_and_content( $menu_item_title ) );
828 } else {
829 // Get defaul/custom menu item title
830 foreach ( $custom_menu_titles as $custom_menu_title ) {
831 // At this point, $custom_menu_title value looks like toplevel_page_snippets__Code Snippets
832 $custom_menu_title = explode( '__', $custom_menu_title );
833 if ( $custom_menu_title[0] == $menu_item_id ) {
834 $menu_item_title = $common_methods->strip_html_tags_and_content( $custom_menu_title[1] );
835 // e.g. Code Snippets
836 break;
837 // stop foreach loop so $menu_item_title is not overwritten in the next iteration
838 } else {
839 $menu_item_title = $common_methods->strip_html_tags_and_content( $menu_info[0] );
840 }
841 }
842 ?>
843 <input type="text" value="<?php
844 echo wp_kses_post( wp_unslash( $menu_item_title ) );
845 ?>" class="menu-item-custom-title" data-menu-item-id="<?php
846 echo esc_attr( $menu_item_id );
847 ?>">
848 <?php
849 }
850 }
851 ?>
852 </span><!-- end of .menu-item-title -->
853 <?php
854 ?>
855 </div><!-- end of .title-wrapper -->
856 <div class="options-for-hiding">
857 <?php
858 $hide_text = __( 'Hide until toggled', 'admin-site-enhancements' );
859 $checkbox_class = 'parent-menu-hide-checkbox';
860 ?>
861 <label class="menu-item-checkbox-label">
862 <?php
863 if ( in_array( $custom_menu_item, $menu_hidden_by_toggle ) ) {
864 ?>
865 <input type="checkbox" id="hide-status-for-<?php
866 echo esc_attr( $menu_item_id_transformed );
867 ?>" class="<?php
868 echo esc_attr( $checkbox_class );
869 ?>" data-menu-item-title="<?php
870 echo esc_attr( $common_methods->strip_html_tags_and_content( $menu_item_title ) );
871 ?>" data-menu-item-id="<?php
872 echo esc_attr( $menu_item_id_transformed );
873 ?>" data-menu-item-id-ori="<?php
874 echo esc_attr( $menu_item_id );
875 ?>" data-menu-url-fragment="<?php
876 echo esc_attr( $menu_url_fragment );
877 ?>" data-required-capability="<?php
878 echo esc_attr( $menu_required_capability );
879 ?>" checked>
880 <span><?php
881 echo esc_html( $hide_text );
882 ?></span>
883 <?php
884 } else {
885 ?>
886 <input type="checkbox" id="hide-status-for-<?php
887 echo esc_attr( $menu_item_id_transformed );
888 ?>" class="<?php
889 echo esc_attr( $checkbox_class );
890 ?>" data-menu-item-title="<?php
891 echo esc_attr( $common_methods->strip_html_tags_and_content( $menu_item_title ) );
892 ?>" data-menu-item-id="<?php
893 echo esc_attr( $menu_item_id_transformed );
894 ?>" data-menu-item-id-ori="<?php
895 echo esc_attr( $menu_item_id );
896 ?>" data-menu-url-fragment="<?php
897 echo esc_attr( $menu_url_fragment );
898 ?>" data-required-capability="<?php
899 echo esc_attr( $menu_required_capability );
900 ?>">
901 <span><?php
902 echo esc_html( $hide_text );
903 ?></span>
904 <?php
905 }
906 ?>
907 </label>
908 <?php
909 ?>
910 </div><!-- end of .options-for-hiding -->
911 </div><!-- end of .item-title -->
912 </div><!-- end of .menu-item-handle -->
913 </div><!-- end of .menu-item-bar -->
914 <?php
915 $i = 1;
916 ?>
917 </li>
918 <?php
919 $menu_key_in_use[] = $menu_key;
920 }
921 }
922 }
923 // Render the rest of the current menu towards the end of the sortables
924 foreach ( $menu as $menu_key => $menu_info ) {
925 if ( !in_array( $menu_key, $menu_key_in_use ) ) {
926 // Skip deleted built-in separators only for real separator rows; Pro distinguishes ASE additional-separator rows.
927 $skip_deleted_separator = false;
928 if ( isset( $menu_info[2], $menu_info[4] ) && false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
929 $skip_deleted_separator = in_array( $menu_info[2], $deleted_separators_array, true );
930 }
931 if ( $skip_deleted_separator ) {
932 continue;
933 }
934 if ( false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
935 $menu_item_id = $menu_info[2];
936 } else {
937 $menu_item_id = $menu_info[5];
938 }
939 $menu_item_title = $menu_info[0];
940 $menu_url_fragment = '';
941 // Strip tags
942 $menu_item_title = $common_methods->strip_html_tags_and_content( $menu_item_title );
943 // Exclude Show All/Less toggles
944 if ( false === strpos( $menu_item_id, 'toplevel_page_asenha_' ) ) {
945 $menu_item_id_transformed = $common_methods->transform_menu_item_id( $menu_item_id );
946 $is_custom_menu = 'no';
947 $menu_required_capability = ( isset( $menu_info[1] ) ? $menu_info[1] : '' );
948 ?>
949 <li id="<?php
950 echo esc_attr( $menu_item_id );
951 ?>" class="menu-item parent-menu-item menu-item-depth-0" data-custom-menu-item="<?php
952 echo esc_attr( $is_custom_menu );
953 ?>">
954 <div class="menu-item-bar">
955 <div class="menu-item-handle">
956 <span class="dashicons dashicons-menu"></span>
957 <div class="item-title">
958 <div class="title-wrapper">
959 <span class="menu-item-title">
960 <?php
961 if ( false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
962 echo '~~ ' . esc_html( $this->format_admin_menu_separator_slug_for_display( $menu_info[2] ) ) . ' ~~';
963 } else {
964 ?>
965 <input type="text" value="<?php
966 echo wp_kses_post( wp_unslash( $menu_item_title ) );
967 ?>" class="menu-item-custom-title" data-menu-item-id="<?php
968 echo esc_attr( $menu_item_id );
969 ?>">
970 <?php
971 }
972 ?>
973 </span>
974 <?php
975 ?>
976 </div>
977 <div class="options-for-hiding">
978 <?php
979 $hide_text = __( 'Hide until toggled', 'admin-site-enhancements' );
980 $checkbox_class = 'parent-menu-hide-checkbox';
981 ?>
982 <label class="menu-item-checkbox-label">
983 <input type="checkbox" id="hide-status-for-<?php
984 echo esc_attr( $menu_item_id_transformed );
985 ?>" class="<?php
986 echo esc_attr( $checkbox_class );
987 ?>" data-menu-item-title="<?php
988 echo esc_attr( $common_methods->strip_html_tags_and_content( $menu_item_title ) );
989 ?>" data-menu-item-id="<?php
990 echo esc_attr( $menu_item_id_transformed );
991 ?>" data-menu-item-id-ori="<?php
992 echo esc_attr( $menu_item_id );
993 ?>" data-menu-url-fragment="<?php
994 echo esc_attr( $menu_url_fragment );
995 ?>" data-required-capability="<?php
996 echo esc_attr( $menu_required_capability );
997 ?>">
998 <span><?php
999 echo esc_html( $hide_text );
1000 ?></span>
1001 </label>
1002 <?php
1003 ?>
1004 </div><!-- end of .options-for-hiding -->
1005 </div><!-- end of .item-title -->
1006 </div><!-- end of .menu-item-handle -->
1007 </div><!-- end of .menu-item-bar -->
1008 <?php
1009 $i = 1;
1010 // Add delete icon for saved custom menu items (not separators)
1011 if ( $is_custom_menu === 'yes' && strpos( $menu_info[2], 'separator' ) === false ) {
1012 ?>
1013 <div class="remove-custom-menu-item-saved" data-menu-item-id="<?php
1014 echo esc_attr( $menu_info[2] );
1015 ?>">
1016 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24">
1017 <path fill="#bbbbbb" d="M24 2.4L21.6 0L12 9.6L2.4 0L0 2.4L9.6 12L0 21.6L2.4 24l9.6-9.6l9.6 9.6l2.4-2.4l-9.6-9.6z"/>
1018 </svg>
1019 </div>
1020 <?php
1021 }
1022 ?>
1023 </li><!-- end of .menu-item -->
1024 <?php
1025 }
1026 }
1027 }
1028 } else {
1029 // No custom menu order has been saved yet
1030 // Render sortables with existing items in the admin menu
1031 foreach ( $menu as $menu_key => $menu_info ) {
1032 // Skip deleted built-in separators only for real separator rows; Pro distinguishes ASE additional-separator rows.
1033 $skip_deleted_separator = false;
1034 if ( isset( $menu_info[2], $menu_info[4] ) && false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
1035 $skip_deleted_separator = in_array( $menu_info[2], $deleted_separators_array, true );
1036 }
1037 if ( $skip_deleted_separator ) {
1038 continue;
1039 }
1040 if ( false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
1041 $menu_item_id = $menu_info[2];
1042 } else {
1043 $menu_item_id = $menu_info[5];
1044 }
1045 $menu_url_fragment = '';
1046 $menu_item_title = $menu_info[0];
1047 $menu_item_id_transformed = $common_methods->transform_menu_item_id( $menu_item_id );
1048 // Strip tags
1049 $menu_item_title = $common_methods->strip_html_tags_and_content( $menu_item_title );
1050 $is_custom_menu = 'no';
1051 $menu_required_capability = ( isset( $menu_info[1] ) ? $menu_info[1] : '' );
1052 $custom_menu_data = null;
1053 $menu_item_handle_classes = 'menu-item-handle';
1054 ?>
1055 <li id="<?php
1056 echo esc_attr( $menu_item_id );
1057 ?>" class="menu-item parent-menu-item menu-item-depth-0" data-custom-menu-item="<?php
1058 echo esc_attr( $is_custom_menu );
1059 ?>" data-menu-slug="<?php
1060 echo esc_attr( $menu_info[2] );
1061 ?>">
1062 <div class="menu-item-bar">
1063 <div class="<?php
1064 echo esc_attr( $menu_item_handle_classes );
1065 ?>">
1066 <span class="dashicons dashicons-menu"></span>
1067 <div class="item-title">
1068 <div class="title-wrapper">
1069 <span class="menu-item-title">
1070 <?php
1071 if ( false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
1072 echo '~~ ' . esc_html( $this->format_admin_menu_separator_slug_for_display( $menu_info[2] ) ) . ' ~~';
1073 } else {
1074 if ( in_array( $menu_item_id, $renaming_not_allowed ) ) {
1075 echo wp_kses_post( $menu_item_title );
1076 } else {
1077 ?>
1078 <input type="text" value="<?php
1079 echo wp_kses_post( wp_unslash( $menu_item_title ) );
1080 ?>" class="menu-item-custom-title" data-menu-item-id="<?php
1081 echo esc_attr( $menu_item_id );
1082 ?>">
1083 <?php
1084 }
1085 }
1086 ?>
1087 </span>
1088 <?php
1089 ?>
1090 </div><!-- end of .title-wrapper -->
1091 <div class="options-for-hiding">
1092 <?php
1093 $hide_text = __( 'Hide until toggled', 'admin-site-enhancements' );
1094 $checkbox_class = 'parent-menu-hide-checkbox';
1095 ?>
1096 <label class="menu-item-checkbox-label">
1097 <input type="checkbox" id="hide-status-for-<?php
1098 echo esc_attr( $menu_item_id_transformed );
1099 ?>" class="<?php
1100 echo esc_attr( $checkbox_class );
1101 ?>" data-menu-item-title="<?php
1102 echo esc_attr( $common_methods->strip_html_tags_and_content( $menu_item_title ) );
1103 ?>" data-menu-item-id="<?php
1104 echo esc_attr( $menu_item_id_transformed );
1105 ?>" data-menu-item-id-ori="<?php
1106 echo esc_attr( $menu_item_id );
1107 ?>" data-menu-url-fragment="<?php
1108 echo esc_attr( $menu_url_fragment );
1109 ?>" data-required-capability="<?php
1110 echo esc_attr( $menu_required_capability );
1111 ?>">
1112 <span><?php
1113 echo esc_html( $hide_text );
1114 ?></span>
1115 </label>
1116 <?php
1117 ?>
1118 </div><!-- end of .options-for-hiding -->
1119 </div><!-- end of .item-title -->
1120 </div><!-- end of .menu-item-handle -->
1121 </div><!-- end of .menu-item-bar -->
1122 <?php
1123 $i = 1;
1124 // Add delete icon for saved custom menu items (not separators)
1125 if ( $is_custom_menu === 'yes' && strpos( $menu_info[2], 'separator' ) === false ) {
1126 ?>
1127 <div class="remove-custom-menu-item-saved" data-menu-item-id="<?php
1128 echo esc_attr( $menu_info[2] );
1129 ?>">
1130 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24">
1131 <path fill="#bbbbbb" d="M24 2.4L21.6 0L12 9.6L2.4 0L0 2.4L9.6 12L0 21.6L2.4 24l9.6-9.6l9.6 9.6l2.4-2.4l-9.6-9.6z"/>
1132 </svg>
1133 </div>
1134 <?php
1135 }
1136 ?>
1137 </li>
1138 <?php
1139 }
1140 }
1141 ?>
1142 </ul>
1143 <?php
1144 // Hidden input field to store custom menu order (from options as is, or sortupdate) upon clicking Save Changes.
1145 $field_id = 'custom_menu_order';
1146 $field_option_value = ( isset( $options[$field_id] ) ? $options[$field_id] : '' );
1147 echo '<input type="hidden" id="' . esc_attr( $field_id ) . '" class="asenha-subfield-text" name="' . esc_attr( $field_id ) . '" value="' . esc_attr( $field_option_value ) . '">';
1148 // Hidden input field to store hidden menu items (from options as is, or 'Hide' checkbox clicks) upon clicking Save Changes.
1149 $this->output_admin_menu_organizer_hidden_field( 'custom_menu_hidden' );
1150 // Hidden input field to store custom menu titles (from options as is, or custom values entered on each non-WP-default menu items.
1151 $this->output_admin_menu_organizer_hidden_field( 'custom_menu_titles' );
1152 }
1153
1154 /**
1155 * Decode and re-encode JSON option values for AMO hidden fields so WordPress-slashed or legacy
1156 * strings become valid for JavaScript JSON.parse(), without applying stripslashes() to raw strings
1157 * (which would break JSON \\u Unicode escapes).
1158 *
1159 * @since 8.5.3
1160 *
1161 * @param string $value Raw option value.
1162 * @return string
1163 */
1164 private function normalize_admin_menu_json_option_for_output( $value ) {
1165 if ( !is_string( $value ) || '' === $value ) {
1166 return $value;
1167 }
1168 // Use objects (not associative arrays) so JSON objects stay objects and arrays stay arrays.
1169 $decoded = json_decode( $value, false );
1170 if ( JSON_ERROR_NONE === json_last_error() ) {
1171 return wp_json_encode( $decoded );
1172 }
1173 $decoded = json_decode( wp_unslash( $value ), false );
1174 if ( JSON_ERROR_NONE === json_last_error() ) {
1175 return wp_json_encode( $decoded );
1176 }
1177 return $value;
1178 }
1179
1180 /**
1181 * Output hidden field
1182 *
1183 * @since 6.9.13
1184 */
1185 public function output_admin_menu_organizer_hidden_field( $field_id ) {
1186 $options_extra = get_option( ASENHA_SLUG_U . '_extra', array() );
1187 $options = ( isset( $options_extra['admin_menu'] ) ? $options_extra['admin_menu'] : array() );
1188 $field_name = $field_id;
1189 $field_option_value = ( isset( $options[$field_id] ) ? $options[$field_id] : '' );
1190 $json_option_field_ids = array(
1191 'custom_menu_new_separators',
1192 'custom_menu_deleted_separators',
1193 'custom_submenus_order',
1194 'custom_menu_always_hidden',
1195 'custom_submenu_always_hidden',
1196 'custom_menu_new_items'
1197 );
1198 if ( in_array( $field_id, $json_option_field_ids, true ) ) {
1199 $field_option_value = $this->normalize_admin_menu_json_option_for_output( $field_option_value );
1200 }
1201 echo '<input type="hidden" id="' . esc_attr( $field_name ) . '" class="asenha-subfield-text" name="' . esc_attr( $field_name ) . '" value="' . esc_attr( $field_option_value ) . '">';
1202 }
1203
1204 /**
1205 * Render textarea field as sub-field of a toggle/switcher checkbox
1206 *
1207 * @since 2.3.0
1208 */
1209 function render_datatable( $args ) {
1210 global $wpdb;
1211 $option_name = $args['option_name'];
1212 if ( !empty( $option_name ) ) {
1213 $options = get_option( $option_name, array() );
1214 } else {
1215 $options = get_option( ASENHA_SLUG_U, array() );
1216 }
1217 $field_id = $args['field_id'];
1218 $field_slug = $args['field_slug'];
1219 $field_name = $args['field_name'];
1220 $field_type = $args['field_type'];
1221 $field_description = $args['field_description'];
1222 $table_title = $args['table_title'];
1223 $table_name = $args['table_name'];
1224 $field_option_value = ( isset( $options[$args['field_id']] ) ? $options[$args['field_id']] : '' );
1225 $login_fails_allowed = ( isset( $options['login_fails_allowed'] ) ? (int) $options['login_fails_allowed'] : 3 );
1226 $login_lockout_maxcount = ( isset( $options['login_lockout_maxcount'] ) ? (int) $options['login_lockout_maxcount'] : 3 );
1227 $login_fails_allowed = ( $login_fails_allowed > 0 ? $login_fails_allowed : 3 );
1228 $login_lockout_maxcount = ( $login_lockout_maxcount > 0 ? $login_lockout_maxcount : 3 );
1229 $default_lockout_period = 60 * 15;
1230 // 15 minutes in seconds.
1231 $extended_lockout_period = 24 * 60 * 60;
1232 // 24 hours in seconds.
1233 $now = time();
1234 $ip_address_whitelist = array();
1235 ?>
1236 <table id="login-attempts-log" class="wp-list-table widefat striped datatable">
1237 <thead>
1238 <tr class="datatable-tr">
1239 <th class="datatable-th"><?php
1240 _e( 'IP Address<br />Last Username', 'admin-site-enhancements' );
1241 ?></th>
1242 <th class="datatable-th"><?php
1243 _e( 'Attempts<br />Lockouts', 'admin-site-enhancements' );
1244 ?></th>
1245 <th class="datatable-th"><?php
1246 _e( 'Last Attempt On', 'admin-site-enhancements' );
1247 ?></th>
1248 <th class="datatable-th"><?php
1249 _e( 'Actions', 'admin-site-enhancements' );
1250 ?></th>
1251 </tr>
1252 </thead>
1253 <tbody>
1254 <?php
1255 $limit = 1000;
1256 $sql = $wpdb->prepare( "SELECT * FROM {$table_name} ORDER BY unixtime DESC LIMIT %d", array($limit) );
1257 $entries = $wpdb->get_results( $sql, ARRAY_A );
1258 foreach ( $entries as $entry ) {
1259 $unixtime = $entry['unixtime'];
1260 $ip_address = ( isset( $entry['ip_address'] ) ? (string) $entry['ip_address'] : '' );
1261 $fail_count = ( isset( $entry['fail_count'] ) ? (int) $entry['fail_count'] : 0 );
1262 $lockout_count = ( isset( $entry['lockout_count'] ) ? (int) $entry['lockout_count'] : 0 );
1263 $locked_condition = $fail_count > 0 && $fail_count % $login_fails_allowed === 0;
1264 $is_extended_lockout = $lockout_count >= $login_lockout_maxcount;
1265 $lockout_period = ( $is_extended_lockout ? $extended_lockout_period : $default_lockout_period );
1266 $is_locked_out = $locked_condition && $now - (int) $unixtime <= $lockout_period;
1267 $is_whitelisted = in_array( $ip_address, $ip_address_whitelist, true );
1268 if ( function_exists( 'wp_date' ) ) {
1269 $date = wp_date( 'F j, Y', $unixtime );
1270 $time = wp_date( 'H:i:s', $unixtime );
1271 } else {
1272 $date = date_i18n( 'F j, Y', $unixtime );
1273 $time = date_i18n( 'H:i:s', $unixtime );
1274 }
1275 ?>
1276 <tr class="datatable-tr">
1277 <td class="datatable-td"><?php
1278 echo esc_html( $ip_address );
1279 ?><br /><?php
1280 echo esc_html( $entry['username'] );
1281 ?></td>
1282 <td class="datatable-td"><?php
1283 echo esc_html( $fail_count );
1284 ?><br /><?php
1285 echo esc_html( $lockout_count );
1286 ?></td>
1287 <td class="datatable-td"><span class="unixtime"><?php
1288 echo esc_html( $entry['unixtime'] );
1289 ?></span><?php
1290 echo esc_html( $date );
1291 ?><br /><?php
1292 echo esc_html( $time );
1293 ?></td>
1294 <td class="datatable-td">
1295 <?php
1296 if ( $is_locked_out && !$is_whitelisted ) {
1297 ?>
1298 <a href="#" class="button button-secondary button-small asenha-release-login-lock" data-ip-address="<?php
1299 echo esc_attr( $ip_address );
1300 ?>"><?php
1301 _e( 'Release Lock', 'admin-site-enhancements' );
1302 ?></a>
1303 <?php
1304 }
1305 ?>
1306 <?php
1307 ?>
1308 </td>
1309 </tr>
1310 <?php
1311 }
1312 ?>
1313 </tbody>
1314 </table>
1315 <?php
1316 echo '<div class="asenha-subfield-description">' . esc_html( $field_description ) . '</div>';
1317 echo '<input type="hidden" id="' . esc_attr( $field_name ) . '" class="asenha-subfield-datatable" name="' . esc_attr( $field_name ) . '" value="' . esc_attr( $field_option_value ) . '">';
1318 }
1319
1320 /**
1321 * Render checks and status for AVIF support
1322 *
1323 * @link https://php.watch/versions/8.1/gd-avif
1324 * @since 5.7.0
1325 */
1326 public function render_avif_support_status() {
1327 // Check status of GD extension and it's AVIF support
1328 if ( extension_loaded( 'gd' ) && function_exists( 'gd_info' ) ) {
1329 $is_gd_enabled = true;
1330 $gd_info = gd_info();
1331 $gd_version = $gd_info['GD Version'];
1332 $gd_avif_support = ( isset( $gd_info['AVIF Support'] ) ? isset( $gd_info['AVIF Support'] ) : false );
1333 if ( $gd_avif_support ) {
1334 $gd_status = $gd_version . ' <span class="supported">' . __( 'with AVIF support', 'admin-site-enhancements' ) . '</span>';
1335 } else {
1336 $gd_status = $gd_version . ' <span class="unsupported">' . __( 'without AVIF support', 'admin-site-enhancements' ) . '</span>';
1337 }
1338 } else {
1339 $is_gd_enabled = false;
1340 $gd_avif_support = false;
1341 $gd_status = __( 'Not available', 'admin-site-enhancements' );
1342 }
1343 // Check status of ImageMagick library and it's AVIF support
1344 if ( extension_loaded( 'imagick' ) && class_exists( 'Imagick' ) ) {
1345 $is_imagick_enabled = true;
1346 $imagick_version = \Imagick::getVersion();
1347 if ( preg_match( '/((?:[0-9]+\\.?)+)/', $imagick_version['versionString'], $matches ) ) {
1348 $imagick_version = $matches[0];
1349 } else {
1350 $imagick_version = $imagick_version['versionString'];
1351 }
1352 if ( version_compare( $imagick_version, '7.0.25', '>=' ) ) {
1353 $imagick_avif_support = true;
1354 $imagick_status = $imagick_version . ' <span class="supported">with AVIF support</span>';
1355 } else {
1356 $imagick_avif_support = false;
1357 $imagick_status = $imagick_version . ' <span class="unsupported">without AVIF support</span>';
1358 }
1359 } else {
1360 $is_imagick_enabled = false;
1361 $imagick_avif_support = false;
1362 $imagick_status = __( 'Not available', 'admin-site-enhancements' );
1363 }
1364 echo '<div class="asenha-subfield-status">';
1365 echo '<div class="status-title">' . __( 'AVIF Support Status', 'admin-site-enhancements' ) . '</div>';
1366 echo '<div class="status-body">';
1367 echo '<div class="status-item"><span class="status-item-title">PHP</span> : ' . wp_kses_post( phpversion() ) . '</div>';
1368 echo '<div class="status-item"><span class="status-item-title">GD</span> : ' . wp_kses_post( $gd_status ) . '</div>';
1369 echo '<div class="status-item"><span class="status-item-title">ImageMagick</span> : ' . wp_kses_post( $imagick_status ) . '</div>';
1370 echo '</div>';
1371 echo '<div class="status-footer">' . __( 'Full AVIF support requires that your server / hosting has <a href="https://php.watch/versions/8.1/gd-avif" target="_blank">GD extension</a> compiled with AVIF support in PHP 8.1 or greater, or, <a href="https://web.archive.org/web/20240104012918/https://avif.io/blog/tutorials/imagemagick/" target="_blank">ImageMagick 7.0.25 or greater</a> installed. Without either, you can still upload AVIF files but without auto-generation of the smaller thumbnail sizes. A majority of <a href="https://web.archive.org/web/20231207174740/https://avif.io/blog/articles/avif-browser-support/" target="_blank">modern desktop and mobile browsers</a> support the display of AVIF files.', 'admin-site-enhancements' ) . '</div>';
1372 echo '</div>';
1373 }
1374
1375 }
1376