PluginProbe ʕ •ᴥ•ʔ
Admin and Site Enhancements (ASE) / 9.0.2
Admin and Site Enhancements (ASE) v9.0.2
9.1.1 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 weeks ago class-admin-menu-organizer.php 2 weeks ago class-admin-menu-svg-icon-mask.php 2 weeks ago class-auto-publish-posts-with-missed-schedule.php 2 weeks ago class-avif-upload.php 2 weeks ago class-captcha-protection.php 2 weeks ago class-change-login-url.php 2 weeks ago class-cleanup-admin-bar.php 2 weeks ago class-common-methods.php 2 weeks ago class-content-duplication.php 2 weeks ago class-content-order.php 2 weeks ago class-custom-admin-footer-text.php 2 weeks ago class-custom-body-class.php 2 weeks ago class-custom-css.php 2 weeks ago class-custom-nav-menu-items-in-new-tab.php 2 weeks ago class-deactivation.php 2 weeks ago class-disable-author-archives.php 2 weeks ago class-disable-comments.php 2 weeks ago class-disable-dashboard-widgets.php 2 weeks ago class-disable-embeds.php 2 weeks ago class-disable-feeds.php 2 weeks ago class-disable-gutenberg.php 2 weeks ago class-disable-rest-api.php 2 weeks ago class-disable-smaller-components.php 2 weeks ago class-disable-updates.php 2 weeks ago class-disable-user-account.php 2 weeks ago class-disable-xml-rpc.php 2 weeks ago class-display-system-summary.php 2 weeks ago class-email-address-obfuscator.php 2 weeks ago class-email-delivery.php 2 weeks ago class-enhance-list-tables.php 2 weeks ago class-external-permalinks.php 2 weeks ago class-heartbeat-control.php 2 weeks ago class-hide-admin-bar.php 2 weeks ago class-hide-admin-notices.php 2 weeks ago class-image-sizes-panel.php 2 weeks ago class-image-upload-control.php 2 weeks ago class-insert-head-body-footer-code.php 2 weeks ago class-last-login-column.php 2 weeks ago class-limit-login-attempts.php 2 weeks ago class-login-id-type.php 2 weeks ago class-login-logout-menu.php 2 weeks ago class-maintenance-mode.php 2 weeks ago class-manage-ads-appads-txt.php 2 weeks ago class-manage-robots-txt.php 2 weeks ago class-media-files-visibility-control.php 2 weeks ago class-media-replacement.php 2 weeks ago class-multiple-user-roles.php 2 weeks ago class-navigation-menu-duplicator.php 2 weeks ago class-obfuscate-author-slugs.php 2 weeks ago class-open-external-links-in-new-tab.php 2 weeks ago class-password-protection.php 2 weeks ago class-redirect-after-login.php 2 weeks ago class-redirect-after-logout.php 2 weeks ago class-redirect-fourofour.php 2 weeks ago class-registration-date-column.php 2 weeks ago class-revisions-control.php 2 weeks ago class-search-engines-visibility.php 2 weeks ago class-settings-fields-render.php 2 weeks ago class-settings-sanitization.php 2 weeks ago class-settings-sections-fields.php 2 weeks ago class-show-custom-taxonomy-filters.php 2 weeks ago class-site-identity-on-login-page.php 2 weeks ago class-svg-upload.php 2 weeks ago class-third-party-compat.php 2 weeks ago class-various-admin-ui-enhancements.php 2 weeks ago class-view-admin-as-role.php 2 weeks ago class-wider-admin-menu.php 2 weeks ago class-wp-config-transformer.php 2 weeks ago
class-settings-fields-render.php
1458 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 $field_disabled = !empty( $args['field_disabled'] );
81 // Disabled checkboxes are omitted from POST; preserve a checked value so save does not wipe it.
82 if ( $field_disabled && $field_option_value ) {
83 echo '<input type="hidden" name="' . esc_attr( $field_name ) . '" value="on">';
84 }
85 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 ) . ' ' . disabled( $field_disabled, true, false ) . '>';
86 echo '<label for="' . esc_attr( $field_name ) . '" class="asenha-subfield-checkbox-label" style="' . esc_attr( $inline_style ) . '">' . wp_kses_post( $field_label ) . '</label>';
87 }
88
89 /**
90 * Render checkbox field as sub-field of a toggle/switcher checkbox
91 *
92 * @since 1.3.0
93 */
94 function render_checkbox_subfield( $args ) {
95 $option_name = $args['option_name'];
96 if ( !empty( $option_name ) ) {
97 $options = get_option( $option_name, array() );
98 } else {
99 $options = get_option( ASENHA_SLUG_U, array() );
100 }
101 $field_name = $args['field_name'];
102 $field_label = $args['field_label'];
103 $parent_field_id = ( isset( $args['parent_field_id'] ) ? $args['parent_field_id'] : '' );
104 $sub_field_id = ( isset( $args['sub_field_id'] ) ? $args['sub_field_id'] : '' );
105 if ( in_array( $parent_field_id, array('enable_duplication_for', 'enable_rest_api_for') ) ) {
106 // Default is true/enabled. Usually for options introduced at a later date where the previous default is true/enabled.
107 $default_value = true;
108 } else {
109 // Default is false / checked
110 $default_value = false;
111 }
112 if ( !empty( $parent_field_id ) && !empty( $sub_field_id ) && isset( $options[$parent_field_id][$sub_field_id][$args['field_id']] ) ) {
113 $field_option_value = $options[$parent_field_id][$sub_field_id][$args['field_id']];
114 } elseif ( in_array( $parent_field_id, array('redirect_after_login_for_separate', 'redirect_after_logout_for_separate'), true ) && !empty( $sub_field_id ) ) {
115 $field_option_value = ( isset( $options[$sub_field_id][$args['field_id']] ) ? $options[$sub_field_id][$args['field_id']] : $default_value );
116 } elseif ( empty( $parent_field_id ) && !empty( $args['field_id'] ) ) {
117 $field_option_value = ( isset( $options[$args['field_id']] ) ? $options[$args['field_id']] : $default_value );
118 } else {
119 $field_option_value = ( isset( $options[$parent_field_id][$args['field_id']] ) ? $options[$parent_field_id][$args['field_id']] : $default_value );
120 }
121 echo '<input type="checkbox" id="' . esc_attr( $field_name ) . '" class="asenha-subfield-checkbox" name="' . esc_attr( $field_name ) . '" ' . checked( $field_option_value, true, false ) . '>';
122 echo '<label for="' . esc_attr( $field_name ) . '" class="asenha-subfield-checkbox-label">' . wp_kses_post( $field_label ) . '</label>';
123 if ( !empty( $args['field_description'] ) ) {
124 $desc_display = ( isset( $args['field_description_display'] ) ? $args['field_description_display'] : 'inline' );
125 if ( 'tooltip' === $desc_display ) {
126 echo '<span class="asenha-info-tooltip-wrap">';
127 echo '<button type="button" class="asenha-info-tooltip-toggle" aria-label="' . esc_attr__( 'More information', 'admin-site-enhancements' ) . '">';
128 echo '<span class="dashicons dashicons-info-outline" aria-hidden="true"></span>';
129 echo '</button>';
130 echo '<span class="asenha-info-tooltip" role="tooltip">' . esc_html( $args['field_description'] ) . '</span>';
131 echo '</span>';
132 } else {
133 echo '<div class="asenha-subfield-description">' . wp_kses_post( $args['field_description'] ) . '</div>';
134 }
135 }
136 }
137
138 /**
139 * Render radio buttons field as sub-field of a toggle/switcher checkbox
140 *
141 * @since 1.3.0
142 */
143 function render_radio_buttons_subfield( $args ) {
144 $option_name = $args['option_name'];
145 if ( !empty( $option_name ) ) {
146 $options = get_option( $option_name, array() );
147 } else {
148 $options = get_option( ASENHA_SLUG_U, array() );
149 }
150 $field_id = $args['field_id'];
151 $field_name = $args['field_name'];
152 $field_radios = $args['field_radios'];
153 if ( !empty( $args['field_default'] ) ) {
154 $default_value = $args['field_default'];
155 } else {
156 $default_value = false;
157 }
158 $field_description = ( isset( $args['field_description'] ) ? $args['field_description'] : '' );
159 $field_option_value = ( isset( $options[$field_id] ) ? $options[$field_id] : $default_value );
160 echo '<div class="asenha-subfield-radio-button-wrapper">';
161 foreach ( $field_radios as $radio_label => $radio_value ) {
162 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 ) . '>';
163 echo '<label for="' . esc_attr( $field_id . '_' . $radio_value ) . '" class="asenha-subfield-radio-button-label">' . wp_kses_post( $radio_label ) . '</label>';
164 }
165 echo '</div>';
166 if ( !empty( $field_description ) ) {
167 echo '<div class="asenha-subfield-description">' . wp_kses_post( $field_description ) . '</div>';
168 }
169 }
170
171 /**
172 * Render checkboxes field as sub-field of a toggle/switcher checkbox
173 *
174 * @since 6.9.2
175 */
176 function render_checkboxes_subfield( $args ) {
177 $options = get_option( ASENHA_SLUG_U, array() );
178 $field_id = $args['field_id'];
179 $field_name = $args['field_name'];
180 $field_options = $args['field_options'];
181 $layout = ( !empty( $args['layout'] ) ? $args['layout'] : 'horizontal' );
182 $default_value = ( !empty( $args['field_default'] ) ? $args['field_default'] : array() );
183 $parent_field_id = ( isset( $args['parent_field_id'] ) ? $args['parent_field_id'] : '' );
184 $sub_field_id = ( isset( $args['sub_field_id'] ) ? $args['sub_field_id'] : '' );
185 if ( !empty( $parent_field_id ) && !empty( $sub_field_id ) && isset( $options[$parent_field_id][$sub_field_id][$field_id] ) ) {
186 $field_option_value = (array) $options[$parent_field_id][$sub_field_id][$field_id];
187 } else {
188 $field_option_value = ( isset( $options[$field_id] ) ? (array) $options[$field_id] : $default_value );
189 }
190 // Back-compat: legacy naming for Two-Factor Recovery Codes.
191 if ( in_array( $field_id, array('two_factor_available_providers', 'available_providers'), true ) && is_array( $field_option_value ) ) {
192 $field_option_value = array_map( static function ( $provider_key ) {
193 return ( 'backup_codes' === $provider_key ? 'recovery_codes' : $provider_key );
194 }, $field_option_value );
195 }
196 echo '<div class="wrapper-for-checkboxes ' . esc_attr( $layout ) . '">';
197 foreach ( $field_options as $option_label => $option_value ) {
198 $checkbox_id = ( !empty( $parent_field_id ) && !empty( $sub_field_id ) ? $parent_field_id . '_' . $sub_field_id . '_' . $field_id . '_' . $option_value : $field_id . '_' . $option_value );
199 echo '<div>';
200 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 ) . '>';
201 echo '<label for="' . esc_attr( $checkbox_id ) . '" class="asenha-subfield-radio-button-label">' . wp_kses_post( $option_label ) . '</label>';
202 echo '</div>';
203 }
204 echo '</div>';
205 }
206
207 /**
208 * Render text field as sub-field of a toggle/switcher checkbox
209 *
210 * @since 1.4.0
211 */
212 function render_text_subfield( $args ) {
213 $option_name = $args['option_name'];
214 if ( !empty( $option_name ) ) {
215 $options = get_option( $option_name, array() );
216 } else {
217 $options = get_option( ASENHA_SLUG_U, array() );
218 }
219 $field_id = $args['field_id'];
220 $field_slug = str_replace( '_', '-', $field_id );
221 $field_name = $args['field_name'];
222 $field_width_classname = ( isset( $args['field_width_classname'] ) ? $args['field_width_classname'] : '' );
223 $field_type = $args['field_type'];
224 $field_prefix = ( isset( $args['field_prefix'] ) ? $args['field_prefix'] : '' );
225 $field_suffix = ( isset( $args['field_suffix'] ) ? $args['field_suffix'] : '' );
226 $field_is_read_only = ( isset( $args['read_only'] ) ? $args['read_only'] : false );
227 $field_is_read_only_output = ( $field_is_read_only ? ' readonly="readonly"' : '' );
228 $field_placeholder = ( isset( $args['field_placeholder'] ) ? $args['field_placeholder'] : '' );
229 $field_description = $args['field_description'];
230 if ( isset( $options[$field_id] ) ) {
231 if ( 'live_site_url' == $field_id ) {
232 if ( false !== strpos( $options[$field_id], 'http' ) ) {
233 $field_option_value = $options[$field_id];
234 } else {
235 // Legacy support for when base64 encoding was used prior to v7.3.1
236 $field_option_value = base64_decode( $options[$field_id] );
237 }
238 } elseif ( 'login_page_logo_image_width' == $field_id || 'login_page_logo_image_height' == $field_id ) {
239 if ( isset( $options[$field_id] ) ) {
240 if ( is_numeric( $options[$field_id] ) ) {
241 $field_option_value = $options[$field_id];
242 } else {
243 $field_option_value = str_replace( 'px', '', $options[$field_id] );
244 }
245 }
246 } else {
247 $field_option_value = $options[$field_id];
248 }
249 } else {
250 if ( 'altcha_secret_key' == $field_id ) {
251 $field_option_value = '';
252 } else {
253 $field_option_value = '';
254 }
255 }
256 if ( !empty( $field_prefix ) && !empty( $field_suffix ) ) {
257 $field_classname = ' with-prefix with-suffix';
258 } elseif ( !empty( $field_prefix ) && empty( $field_suffix ) ) {
259 $field_classname = ' with-prefix';
260 } elseif ( empty( $field_prefix ) && !empty( $field_suffix ) ) {
261 $field_classname = ' with-suffix';
262 } else {
263 $field_classname = '';
264 }
265 if ( !empty( $field_width_classname ) ) {
266 $field_classname .= ' ' . $field_width_classname;
267 }
268 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 );
269 if ( !empty( $field_description ) ) {
270 echo '<label for="' . esc_attr( $field_name ) . '" class="asenha-subfield-checkbox-label">' . wp_kses_post( $field_description ) . '</label>';
271 }
272 }
273
274 /**
275 * Render text field as sub-field of a checkbox field. e.g. in Redirect After Login module
276 *
277 * @since 7.3.3
278 */
279 function render_checkbox_field_text_subfield( $args ) {
280 $option_name = $args['option_name'];
281 if ( !empty( $option_name ) ) {
282 $options = get_option( $option_name, array() );
283 } else {
284 $options = get_option( ASENHA_SLUG_U, array() );
285 }
286 $field_id = $args['field_id'];
287 $field_name = $args['field_name'];
288 $field_width_classname = ( isset( $args['field_width_classname'] ) ? $args['field_width_classname'] : '' );
289 $field_type = $args['field_type'];
290 $field_prefix = $args['field_prefix'];
291 $field_suffix = $args['field_suffix'];
292 $field_placeholder = ( isset( $args['field_placeholder'] ) ? $args['field_placeholder'] : '' );
293 $field_description = $args['field_description'];
294 $parent_field_id = ( isset( $args['parent_field_id'] ) ? $args['parent_field_id'] : '' );
295 $sub_field_id = ( isset( $args['sub_field_id'] ) ? $args['sub_field_id'] : '' );
296 if ( 'redirect_after_login_for_separate' == $parent_field_id && !empty( $sub_field_id ) ) {
297 $field_option_value = ( isset( $options[$sub_field_id][$field_id] ) ? $options[$sub_field_id][$field_id] : '' );
298 } else {
299 $field_option_value = ( isset( $options[$parent_field_id][$field_id] ) ? $options[$parent_field_id][$field_id] : '' );
300 }
301 // $field_option_value = ( isset( $options[$field_id] ) ) ? $options[$field_id] : '';
302 $field_option_value = ( isset( $options[$parent_field_id . '_slug'][$args['field_id']] ) ? $options[$parent_field_id . '_slug'][$field_id] : '' );
303 if ( !empty( $field_prefix ) && !empty( $field_suffix ) ) {
304 $field_classname = ' with-prefix with-suffix';
305 } elseif ( !empty( $field_prefix ) && empty( $field_suffix ) ) {
306 $field_classname = ' with-prefix';
307 } elseif ( empty( $field_prefix ) && !empty( $field_suffix ) ) {
308 $field_classname = ' with-suffix';
309 } else {
310 $field_classname = '';
311 }
312 if ( !empty( $field_width_classname ) ) {
313 $field_classname .= ' ' . $field_width_classname;
314 }
315 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 );
316 echo '<label for="' . esc_attr( $field_name ) . '" class="asenha-subfield-checkbox-label">' . esc_html( $field_description ) . '</label>';
317 }
318
319 /**
320 * Render description field as sub-field of a toggle/switcher checkbox
321 *
322 * @since 4.6.0
323 */
324 function render_description_subfield( $args ) {
325 $field_description = $args['field_description'];
326 echo '<div class="asenha-subfield-description">' . wp_kses( $field_description, get_kses_with_style_src_svg_ruleset() ) . '</div>';
327 }
328
329 /**
330 * Render View Admin as Role recovery URL description at display time.
331 *
332 * @since 8.8.5
333 * @param array $args Settings field arguments.
334 * @return void
335 */
336 function render_view_admin_as_role_recovery_description( $args ) {
337 $view_admin_as_role = new View_Admin_As_Role();
338 $recovery_url = $view_admin_as_role->get_recovery_url_for_settings( get_current_user_id() );
339 $field_description = '<div class="asenha-warning"><strong>' . sprintf(
340 /* translators: %s is the secret recovery URL or instructional text */
341 __( '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' ),
342 esc_html( $recovery_url )
343 ) . '<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>';
344 echo '<div class="asenha-subfield-description">' . wp_kses( $field_description, get_kses_with_style_src_svg_ruleset() ) . '</div>';
345 }
346
347 /**
348 * Render heading for sub-fields of a toggle/switcher checkbox
349 *
350 * @since 5.0.0
351 */
352 function render_subfields_heading( $args ) {
353 $subfields_heading = $args['subfields_heading'];
354 echo '<div class="asenha-subfields-heading">' . wp_kses_post( $subfields_heading ) . '</div>';
355 }
356
357 /**
358 * Render password field as sub-field of a toggle/switcher checkbox
359 *
360 * @since 4.1.0
361 */
362 function render_password_subfield( $args ) {
363 $option_name = $args['option_name'];
364 if ( !empty( $option_name ) ) {
365 $options = get_option( $option_name, array() );
366 } else {
367 $options = get_option( ASENHA_SLUG_U, array() );
368 }
369 $field_id = $args['field_id'];
370 $field_name = $args['field_name'];
371 $field_type = $args['field_type'];
372 $field_prefix = $args['field_prefix'];
373 $field_suffix = $args['field_suffix'];
374 $field_description = $args['field_description'];
375 $field_option_value = ( isset( $options[$args['field_id']] ) ? $options[$args['field_id']] : '' );
376 $hide_stored_value = ( isset( $args['hide_stored_value'] ) ? (bool) $args['hide_stored_value'] : false );
377 if ( !empty( $field_prefix ) && !empty( $field_suffix ) ) {
378 $field_classname = ' with-prefix with-suffix';
379 } elseif ( !empty( $field_prefix ) && empty( $field_suffix ) ) {
380 $field_classname = ' with-prefix';
381 } elseif ( empty( $field_prefix ) && !empty( $field_suffix ) ) {
382 $field_classname = ' with-suffix';
383 } else {
384 $field_classname = '';
385 }
386 if ( $hide_stored_value ) {
387 $field_option_value = '';
388 }
389 $placeholder = ( isset( $args['field_placeholder'] ) ? $args['field_placeholder'] : '' );
390 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 );
391 echo '<label for="' . esc_attr( $field_name ) . '" class="asenha-subfield-checkbox-label">' . esc_html( $field_description ) . '</label>';
392 }
393
394 /**
395 * Render SMTP password field with live storage status and inline warning.
396 *
397 * @since 8.8.7
398 *
399 * @param array $args Field registration arguments.
400 * @return void
401 */
402 function render_smtp_password_subfield( $args ) {
403 $option_name = ( isset( $args['option_name'] ) ? $args['option_name'] : ASENHA_SLUG_U );
404 $field_name = $args['field_name'];
405 $placeholder = ( isset( $args['field_placeholder'] ) ? $args['field_placeholder'] : '' );
406 if ( function_exists( '\\asenha_get_option_array' ) ) {
407 $options = \asenha_get_option_array( $option_name, true );
408 } else {
409 $options = get_option( $option_name, array() );
410 }
411 $email_delivery = new Email_Delivery();
412 $ui_state = ( method_exists( $email_delivery, 'get_smtp_password_ui_state' ) ? $email_delivery->get_smtp_password_ui_state( $options ) : array(
413 'description' => __( 'Leave blank to keep the current password.', 'admin-site-enhancements' ),
414 'show_warning' => false,
415 'warning_message' => '',
416 ) );
417 echo '<div class="asenha-subfield-password-wrapper">';
418 echo '<input type="password" id="' . esc_attr( $field_name ) . '" class="asenha-subfield-password" name="' . esc_attr( $field_name ) . '" placeholder="' . esc_attr( $placeholder ) . '" size="24" autocomplete="off" value="">';
419 echo '<label for="' . esc_attr( $field_name ) . '" class="asenha-subfield-description asenha-smtp-password-description">' . esc_html( $ui_state['description'] ) . '</label>';
420 echo '<div class="asenha-smtp-password-warning"' . (( empty( $ui_state['show_warning'] ) ? ' style="display:none;"' : '' )) . '>';
421 if ( !empty( $ui_state['show_warning'] ) && !empty( $ui_state['warning_message'] ) ) {
422 echo '<div class="notice notice-warning inline"><p>' . esc_html( $ui_state['warning_message'] ) . '</p></div>';
423 }
424 echo '</div>';
425 echo '</div>';
426 }
427
428 /**
429 * Render encrypted Google Maps API key subfield for Custom Content Types.
430 *
431 * @since 8.9.2
432 *
433 * @param array $args Field registration arguments.
434 * @return void
435 */
436 function render_cct_google_maps_api_key_subfield( $args ) {
437 $option_name = ( isset( $args['option_name'] ) ? $args['option_name'] : ASENHA_SLUG_U );
438 $field_name = $args['field_name'];
439 $placeholder = ( isset( $args['field_placeholder'] ) ? $args['field_placeholder'] : '' );
440 if ( function_exists( '\\asenha_get_option_array' ) ) {
441 $options = \asenha_get_option_array( $option_name, true );
442 } else {
443 $options = get_option( $option_name, array() );
444 }
445 if ( !class_exists( __NAMESPACE__ . '\\CCT_Secrets' ) ) {
446 require_once ASENHA_PATH . 'includes/premium/custom-content/class-cct-secrets.php';
447 }
448 $cct_secrets = new CCT_Secrets();
449 $ui_state = $cct_secrets->get_api_key_ui_state( $options );
450 echo '<div class="asenha-subfield-password-wrapper">';
451 echo '<input type="password" id="' . esc_attr( $field_name ) . '" class="asenha-subfield-password" name="' . esc_attr( $field_name ) . '" placeholder="' . esc_attr( $placeholder ) . '" size="40" autocomplete="off" value="">';
452 echo '<label for="' . esc_attr( $field_name ) . '" class="asenha-subfield-description">' . esc_html( $ui_state['description'] ) . '</label>';
453 echo '</div>';
454 }
455
456 /**
457 * Render number field as sub-field of a toggle/switcher checkbox
458 *
459 * @since 1.4.0
460 */
461 function render_number_subfield( $args ) {
462 $option_name = $args['option_name'];
463 if ( !empty( $option_name ) ) {
464 $options = get_option( $option_name, array() );
465 } else {
466 $options = get_option( ASENHA_SLUG_U, array() );
467 }
468 $field_id = $args['field_id'];
469 $field_name = $args['field_name'];
470 $field_type = $args['field_type'];
471 $field_prefix = $args['field_prefix'];
472 $field_suffix = $args['field_suffix'];
473 $field_intro = $args['field_intro'];
474 $field_placeholder = ( isset( $args['field_placeholder'] ) ? $args['field_placeholder'] : '' );
475 $field_min = ( isset( $args['field_min'] ) ? $args['field_min'] : 1 );
476 $field_max = ( isset( $args['field_max'] ) ? $args['field_max'] : 10 );
477 $field_description = ( isset( $args['field_description'] ) ? $args['field_description'] : '' );
478 $field_option_value = ( isset( $options[$args['field_id']] ) ? $options[$args['field_id']] : '' );
479 if ( !empty( $field_prefix ) && !empty( $field_suffix ) ) {
480 $field_classname = ' with-prefix with-suffix';
481 } elseif ( !empty( $field_prefix ) && empty( $field_suffix ) ) {
482 $field_classname = ' with-prefix';
483 } elseif ( empty( $field_prefix ) && !empty( $field_suffix ) ) {
484 $field_classname = ' with-suffix';
485 } else {
486 $field_classname = '';
487 }
488 echo '<div class="asenha-subfield-number-wrapper">';
489 if ( !empty( $field_intro ) ) {
490 echo '<div class="asenha-subfield-number-intro">' . wp_kses_post( $field_intro ) . '</div>';
491 }
492 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>';
493 if ( !empty( $field_description ) ) {
494 echo '<div class="asenha-subfield-number-description">' . wp_kses_post( $field_description ) . '</div>';
495 }
496 echo '</div>';
497 }
498
499 /**
500 * Render select field as sub-field of a toggle/switcher checkbox
501 *
502 * @since 1.4.0
503 */
504 function render_select_subfield( $args ) {
505 $option_name = $args['option_name'];
506 if ( !empty( $option_name ) ) {
507 $options = get_option( $option_name, array() );
508 } else {
509 $options = get_option( ASENHA_SLUG_U, array() );
510 }
511 $field_id = $args['field_id'];
512 $field_name = $args['field_name'];
513 $field_type = $args['field_type'];
514 $field_prefix = $args['field_prefix'];
515 $field_suffix = $args['field_suffix'];
516 $field_select_options = $args['field_select_options'];
517 $field_select_default = $args['field_select_default'];
518 $field_intro = $args['field_intro'];
519 $field_description = $args['field_description'];
520 $parent_field_id = ( isset( $args['parent_field_id'] ) ? $args['parent_field_id'] : '' );
521 $sub_field_id = ( isset( $args['sub_field_id'] ) ? $args['sub_field_id'] : '' );
522 if ( !empty( $field_select_default ) ) {
523 $default_value = $field_select_default;
524 } else {
525 $default_value = false;
526 }
527 if ( !empty( $parent_field_id ) && !empty( $sub_field_id ) && isset( $options[$parent_field_id][$sub_field_id][$field_id] ) ) {
528 $field_option_value = $options[$parent_field_id][$sub_field_id][$field_id];
529 } else {
530 $field_option_value = ( isset( $options[$field_id] ) ? $options[$field_id] : $default_value );
531 }
532 if ( !empty( $field_prefix ) && !empty( $field_suffix ) ) {
533 $field_classname = ' with-prefix with-suffix';
534 } elseif ( !empty( $field_prefix ) && empty( $field_suffix ) ) {
535 $field_classname = ' with-prefix';
536 } elseif ( empty( $field_prefix ) && !empty( $field_suffix ) ) {
537 $field_classname = ' with-suffix';
538 } else {
539 $field_classname = '';
540 }
541 $display_none_on_load = ( isset( $args['display_none_on_load'] ) ? $args['display_none_on_load'] : false );
542 if ( $display_none_on_load ) {
543 $inline_style = 'display:none;';
544 } else {
545 $inline_style = '';
546 }
547 echo '<div class="asenha-subfield-select-wrapper">';
548 if ( !empty( $field_intro ) ) {
549 echo '<div class="asenha-subfield-select-intro">' . wp_kses_post( $field_intro ) . '</div>';
550 }
551 echo '<div style="' . esc_attr( $inline_style ) . '" class="asenha-subfield-select-inner">' . wp_kses_post( $field_prefix );
552 echo '<select name="' . esc_attr( $field_name ) . '" class="asenha-subfield-select' . esc_attr( $field_classname ) . '">';
553 foreach ( $field_select_options as $label => $value ) {
554 echo '<option value="' . esc_attr( $value ) . '" ' . selected( $value, $field_option_value, false ) . '>' . esc_html( $label ) . '</option>';
555 }
556 echo '</select>';
557 echo wp_kses_post( $field_suffix ) . '</div>';
558 if ( !empty( $field_description ) ) {
559 echo '<div class="asenha-subfield-select-description">' . wp_kses_post( $field_description ) . '</div>';
560 }
561 echo '</div>';
562 }
563
564 /**
565 * Render textarea field as sub-field of a toggle/switcher checkbox
566 *
567 * @since 2.3.0
568 */
569 function render_textarea_subfield( $args ) {
570 $option_name = $args['option_name'];
571 if ( !empty( $option_name ) ) {
572 $options = get_option( $option_name, array() );
573 } else {
574 $options = get_option( ASENHA_SLUG_U, array() );
575 }
576 $field_id = $args['field_id'];
577 $field_slug = $args['field_slug'];
578 $field_name = $args['field_name'];
579 $field_type = $args['field_type'];
580 $field_rows = $args['field_rows'];
581 $field_intro = $args['field_intro'];
582 $field_description = $args['field_description'];
583 $field_placeholder = ( isset( $args['field_placeholder'] ) ? $args['field_placeholder'] : '' );
584 // 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
585 if ( 'robots_txt_content' == $field_id ) {
586 if ( array_key_exists( 'manage_robots_txt', $options ) ) {
587 // Manage robots.txt feature has been enabled before
588 if ( !$options['manage_robots_txt'] ) {
589 // Manage robots.txt feature is NOT enabled
590 if ( array_key_exists( 'robots_txt_content', $options ) && $options['robots_txt_content'] ) {
591 $field_option_value = $options['robots_txt_content'];
592 } else {
593 $robots_txt_content = wp_remote_get( get_site_url() . '/robots.txt' );
594 $robots_txt_content = esc_textarea( trim( wp_remote_retrieve_body( $robots_txt_content ) ) );
595 $field_option_value = $robots_txt_content;
596 }
597 } else {
598 // Manage robots.txt feature is enabled
599 if ( array_key_exists( 'robots_txt_content', $options ) && $options['robots_txt_content'] ) {
600 $field_option_value = $options['robots_txt_content'];
601 } else {
602 $robots_txt_content = wp_remote_get( get_site_url() . '/robots.txt' );
603 $robots_txt_content = esc_textarea( trim( wp_remote_retrieve_body( $robots_txt_content ) ) );
604 $field_option_value = $robots_txt_content;
605 }
606 }
607 } else {
608 // Manage robots.txt feature has never been enabled yet
609 $robots_txt_content = wp_remote_get( get_site_url() . '/robots.txt' );
610 $robots_txt_content = esc_textarea( trim( wp_remote_retrieve_body( $robots_txt_content ) ) );
611 $field_option_value = $robots_txt_content;
612 }
613 } else {
614 $field_option_value = ( isset( $options[$args['field_id']] ) ? $options[$args['field_id']] : '' );
615 }
616 echo '<div class="asenha-subfield-textarea-wrapper">';
617 if ( !empty( $field_intro ) ) {
618 echo '<div class="asenha-subfield-textarea-intro">' . wp_kses_post( $field_intro ) . '</div>';
619 }
620 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>';
621 if ( !empty( $field_description ) ) {
622 echo '<div class="asenha-subfield-textarea-description">' . wp_kses_post( $field_description ) . '</div>';
623 }
624 echo '</div>';
625 }
626
627 /**
628 * Render textarea field as sub-field of a toggle/switcher checkbox
629 *
630 * @since 2.3.0
631 */
632 function render_wpeditor_subfield( $args ) {
633 $option_name = $args['option_name'];
634 if ( !empty( $option_name ) ) {
635 $options = get_option( $option_name, array() );
636 } else {
637 $options = get_option( ASENHA_SLUG_U, array() );
638 }
639 $field_id = $args['field_id'];
640 $field_slug = $args['field_slug'];
641 $field_name = $args['field_name'];
642 $field_type = $args['field_type'];
643 $field_intro = $args['field_intro'];
644 $field_description = $args['field_description'];
645 $field_placeholder = ( isset( $args['field_placeholder'] ) ? $args['field_placeholder'] : '' );
646 $field_option_value = ( isset( $options[$args['field_id']] ) ? $options[$args['field_id']] : '' );
647 $editor_settings = $args['editor_settings'];
648 // https://developer.wordpress.org/reference/classes/_wp_editors/parse_settings/
649 echo '<div class="asenha-subfield-wpeditor-wrapper">';
650 if ( !empty( $field_intro ) ) {
651 echo '<div class="asenha-subfield-wpeditor-intro">' . wp_kses_post( $field_intro ) . '</div>';
652 }
653 $content = $field_option_value;
654 $editor_id = str_replace( array('[', ']'), array('--', ''), $field_name );
655 // vi( $editor_id, '', 'for ' . $field_name );
656 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
657 echo wp_editor( $content, $editor_id, $editor_settings );
658 if ( !empty( $field_description ) ) {
659 echo '<div class="asenha-subfield-wpeditor-description">' . wp_kses_post( $field_description ) . '</div>';
660 }
661 echo '</div>';
662 }
663
664 /**
665 * Render custom HTML subfield
666 *
667 * @since 5.3.0
668 */
669 function render_custom_html( $args ) {
670 echo wp_kses( $args['html'], get_kses_with_custom_html_ruleset() );
671 }
672
673 /**
674 * Render media subfield
675 *
676 * @since 6.2.2
677 */
678 function render_media_subfield( $args ) {
679 $field_id = $args['field_id'];
680 $field_slug = $args['field_slug'];
681 $field_name = $args['field_name'];
682 $field_media_frame_title = $args['field_media_frame_title'];
683 $field_media_frame_multiple = $args['field_media_frame_multiple'];
684 $field_media_frame_library_type = $args['field_media_frame_library_type'];
685 $field_media_frame_button_text = $args['field_media_frame_button_text'];
686 $field_intro = $args['field_intro'];
687 $field_description = $args['field_description'];
688 $options = get_option( $args['option_name'], array() );
689 $field_option_value = ( isset( $options[$field_id] ) ? $options[$field_id] : '' );
690 ?>
691 <div class="media-subfield-wrapper">
692 <input id="<?php
693 echo esc_attr( $field_slug );
694 ?>" class="image-picker" type="text" size="40" name="<?php
695 echo esc_attr( $field_name );
696 ?>" value="<?php
697 echo esc_url( $field_option_value );
698 ?>" />
699 <button id="<?php
700 echo esc_attr( $field_slug );
701 ?>-button" class="image-picker-button button-secondary"><?php
702 echo __( 'Select an Image', 'admin-site-enhancements' );
703 ?></button>
704 <?php
705 if ( array_key_exists( 'field_hidden_inputs', $args ) && is_array( $args['field_hidden_inputs'] ) ) {
706 foreach ( $args['field_hidden_inputs'] as $hidden_input ) {
707 $hidden_option_key = ( isset( $hidden_input['option_key'] ) ? sanitize_key( $hidden_input['option_key'] ) : '' );
708 $hidden_id = ( isset( $hidden_input['field_id'] ) ? (string) $hidden_input['field_id'] : '' );
709 $hidden_name = ( isset( $hidden_input['field_name'] ) ? (string) $hidden_input['field_name'] : '' );
710 if ( empty( $hidden_option_key ) || empty( $hidden_id ) || empty( $hidden_name ) ) {
711 continue;
712 }
713 $hidden_value = ( isset( $options[$hidden_option_key] ) ? absint( $options[$hidden_option_key] ) : 0 );
714 echo '<input type="hidden" id="' . esc_attr( $hidden_id ) . '" class="asenha-hidden-media-dim" name="' . esc_attr( $hidden_name ) . '" value="' . esc_attr( $hidden_value ) . '" />';
715 }
716 }
717 ?>
718 <?php
719 if ( !empty( $field_description ) ) {
720 echo '<div class="asenha-subfield-description media-subfield">' . wp_kses_post( $field_description ) . '</div>';
721 }
722 ?>
723 </div>
724 <?php
725 }
726
727 /**
728 * Render media subfield
729 *
730 * @since 6.2.2
731 */
732 function render_color_picker_subfield( $args ) {
733 $common_methods = new Common_Methods();
734 $field_id = $args['field_id'];
735 $field_slug = $args['field_slug'];
736 $field_name = $args['field_name'];
737 $field_intro = $args['field_intro'];
738 $field_description = $args['field_description'];
739 $field_default_value = $args['field_default_value'];
740 $options = get_option( $args['option_name'], array() );
741 $field_option_value = ( isset( $options[$field_id] ) ? $options[$field_id] : $field_default_value );
742 ?>
743 <div class="color-subfield-wrapper">
744 <input type="text" id="<?php
745 echo esc_attr( $field_slug );
746 ?>" name="<?php
747 echo esc_attr( $field_name );
748 ?>" value="<?php
749 echo esc_attr( $common_methods->sanitize_hex_color( $field_option_value ) );
750 ?>" data-default-color="<?php
751 echo esc_attr( $common_methods->sanitize_hex_color( $field_default_value ) );
752 ?>" class="color-picker"/>
753 </div>
754 <?php
755 }
756
757 /**
758 * Render text field as sub-field of a toggle/switcher checkbox
759 *
760 * @since 1.4.0
761 */
762 function render_content_toggler( $args ) {
763 $field_id = $args['field_id'];
764 $field_slug = $args['field_slug'];
765 $field_slug = str_replace( '_', '-', $field_id );
766 $show_text = ( isset( $args['show_text'] ) ? $args['show_text'] : '' );
767 $hide_text = ( isset( $args['hide_text'] ) ? $args['hide_text'] : '' );
768 $content_selector = ( isset( $args['content_selector'] ) ? $args['content_selector'] : '' );
769 ?>
770 <div class="subfield-content-toggler <?php
771 echo esc_attr( $field_slug );
772 ?>"><a href="#" data-show-text="<?php
773 echo esc_attr( $show_text );
774 ?>" data-hide-text="<?php
775 echo esc_attr( $hide_text );
776 ?>" data-target-selector="<?php
777 echo esc_attr( $content_selector );
778 ?>" class="asenha-content-toggler" data-expanded="no"><?php
779 echo esc_html( $show_text );
780 ?> <span></span></a></div>
781 <?php
782 }
783
784 /**
785 * Human-readable label fragment for an admin menu separator slug (AMO sortable UI).
786 *
787 * WordPress core and plugins use slugs like separator1, separator-last, separator-woocommerce.
788 * Internal slugs stay unchanged; this output is display-only (Spacer-* wording).
789 *
790 * @since 8.5.3
791 *
792 * @param string $menu_slug Separator menu slug from global $menu item index 2.
793 * @return string Middle segment only (without surrounding ~~); safe for esc_html when wrapped.
794 */
795 private function format_admin_menu_separator_slug_for_display( $menu_slug ) {
796 $name = str_replace( 'separator', 'Spacer-', $menu_slug );
797 $name = str_replace( '--last', '-Last', $name );
798 $name = str_replace( '--woocommerce', '--WooCommerce', $name );
799 return $name;
800 }
801
802 /**
803 * Render sortable menu field
804 *
805 * @since 2.0.0
806 */
807 function render_sortable_menu() {
808 $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>';
809 ?>
810 <ul id="custom-admin-menu" class="menu ui-sortable">
811 <?php
812 global $menu, $submenu;
813 $common_methods = new Common_Methods();
814 $options_extra = get_option( ASENHA_SLUG_U . '_extra', array() );
815 $options = ( isset( $options_extra['admin_menu'] ) ? $options_extra['admin_menu'] : array() );
816 // Parsed early so Pro merge of custom spacers and render loops can use the same list.
817 $deleted_separators = ( isset( $options['custom_menu_deleted_separators'] ) ? $options['custom_menu_deleted_separators'] : '' );
818 $deleted_separators_array = array();
819 if ( is_string( $deleted_separators ) && !empty( $deleted_separators ) ) {
820 $deleted_separators_array = json_decode( $deleted_separators, true );
821 if ( !is_array( $deleted_separators_array ) ) {
822 $deleted_separators_array = array();
823 }
824 }
825 // Set menu items to be excluded from title renaming. These are from WordPress core.
826 $renaming_not_allowed = array(
827 'menu-dashboard',
828 'menu-pages',
829 // 'menu-posts',
830 'menu-media',
831 'menu-comments',
832 'menu-appearance',
833 'menu-plugins',
834 'menu-users',
835 'menu-tools',
836 'menu-settings',
837 );
838 // Get custom menu item titles
839 if ( array_key_exists( 'custom_menu_titles', $options ) ) {
840 $custom_menu_titles = $options['custom_menu_titles'];
841 $custom_menu_titles = explode( ',', $custom_menu_titles );
842 } else {
843 $custom_menu_titles = array();
844 }
845 // Get menu items hidden by toggle
846 $menu_hidden_by_toggle = $common_methods->get_menu_hidden_by_toggle();
847 $i = 1;
848 // Check if there's an existing custom menu order data stored in options
849 if ( array_key_exists( 'custom_menu_order', $options ) ) {
850 $custom_menu = $options['custom_menu_order'];
851 $custom_menu = explode( ',', $custom_menu );
852 $menu_key_in_use = array();
853 // Render sortables with data in custom menu order
854 foreach ( $custom_menu as $custom_menu_item ) {
855 foreach ( $menu as $menu_key => $menu_info ) {
856 // Skip deleted built-in separators only for real separator rows; Pro distinguishes ASE additional-separator rows.
857 $skip_deleted_separator = false;
858 if ( isset( $menu_info[2], $menu_info[4] ) && false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
859 $skip_deleted_separator = in_array( $menu_info[2], $deleted_separators_array, true );
860 }
861 if ( $skip_deleted_separator ) {
862 continue;
863 }
864 if ( false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
865 $menu_item_title = $menu_info[2];
866 $menu_item_id = $menu_info[2];
867 } else {
868 $menu_item_title = $menu_info[0];
869 $menu_item_id = $menu_info[5];
870 }
871 $menu_url_fragment = '';
872 if ( $custom_menu_item == $menu_item_id ) {
873 $menu_item_id_transformed = $common_methods->transform_menu_item_id( $menu_item_id );
874 $is_custom_menu = 'no';
875 $menu_required_capability = ( isset( $menu_info[1] ) ? $menu_info[1] : '' );
876 ?>
877 <li id="<?php
878 echo esc_attr( $menu_item_id );
879 ?>" class="menu-item parent-menu-item menu-item-depth-0" data-custom-menu-item="<?php
880 echo esc_attr( $is_custom_menu );
881 ?>" data-menu-slug="<?php
882 echo esc_attr( $menu_info[2] );
883 ?>">
884 <div class="menu-item-bar">
885 <div class="menu-item-handle">
886 <span class="dashicons dashicons-menu"></span>
887 <div class="item-title">
888 <div class="title-wrapper">
889 <span class="menu-item-title">
890 <?php
891 if ( false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
892 echo '~~ ' . esc_html( $this->format_admin_menu_separator_slug_for_display( $menu_info[2] ) ) . ' ~~';
893 } else {
894 if ( in_array( $menu_item_id, $renaming_not_allowed ) ) {
895 $menu_item_title = $menu_info[0];
896 echo wp_kses_post( $common_methods->strip_html_tags_and_content( $menu_item_title ) );
897 } else {
898 // Get defaul/custom menu item title
899 foreach ( $custom_menu_titles as $custom_menu_title ) {
900 // At this point, $custom_menu_title value looks like toplevel_page_snippets__Code Snippets
901 $custom_menu_title = explode( '__', $custom_menu_title );
902 if ( $custom_menu_title[0] == $menu_item_id ) {
903 $menu_item_title = $common_methods->strip_html_tags_and_content( $custom_menu_title[1] );
904 // e.g. Code Snippets
905 break;
906 // stop foreach loop so $menu_item_title is not overwritten in the next iteration
907 } else {
908 $menu_item_title = $common_methods->strip_html_tags_and_content( $menu_info[0] );
909 }
910 }
911 ?>
912 <input type="text" value="<?php
913 echo wp_kses_post( wp_unslash( $menu_item_title ) );
914 ?>" class="menu-item-custom-title" data-menu-item-id="<?php
915 echo esc_attr( $menu_item_id );
916 ?>">
917 <?php
918 }
919 }
920 ?>
921 </span><!-- end of .menu-item-title -->
922 <?php
923 ?>
924 </div><!-- end of .title-wrapper -->
925 <div class="options-for-hiding">
926 <?php
927 $hide_text = __( 'Hide until toggled', 'admin-site-enhancements' );
928 $checkbox_class = 'parent-menu-hide-checkbox';
929 ?>
930 <label class="menu-item-checkbox-label">
931 <?php
932 if ( in_array( $custom_menu_item, $menu_hidden_by_toggle ) ) {
933 ?>
934 <input type="checkbox" id="hide-status-for-<?php
935 echo esc_attr( $menu_item_id_transformed );
936 ?>" class="<?php
937 echo esc_attr( $checkbox_class );
938 ?>" data-menu-item-title="<?php
939 echo esc_attr( $common_methods->strip_html_tags_and_content( $menu_item_title ) );
940 ?>" data-menu-item-id="<?php
941 echo esc_attr( $menu_item_id_transformed );
942 ?>" data-menu-item-id-ori="<?php
943 echo esc_attr( $menu_item_id );
944 ?>" data-menu-url-fragment="<?php
945 echo esc_attr( $menu_url_fragment );
946 ?>" data-required-capability="<?php
947 echo esc_attr( $menu_required_capability );
948 ?>" checked>
949 <span><?php
950 echo esc_html( $hide_text );
951 ?></span>
952 <?php
953 } else {
954 ?>
955 <input type="checkbox" id="hide-status-for-<?php
956 echo esc_attr( $menu_item_id_transformed );
957 ?>" class="<?php
958 echo esc_attr( $checkbox_class );
959 ?>" data-menu-item-title="<?php
960 echo esc_attr( $common_methods->strip_html_tags_and_content( $menu_item_title ) );
961 ?>" data-menu-item-id="<?php
962 echo esc_attr( $menu_item_id_transformed );
963 ?>" data-menu-item-id-ori="<?php
964 echo esc_attr( $menu_item_id );
965 ?>" data-menu-url-fragment="<?php
966 echo esc_attr( $menu_url_fragment );
967 ?>" data-required-capability="<?php
968 echo esc_attr( $menu_required_capability );
969 ?>">
970 <span><?php
971 echo esc_html( $hide_text );
972 ?></span>
973 <?php
974 }
975 ?>
976 </label>
977 <?php
978 ?>
979 </div><!-- end of .options-for-hiding -->
980 </div><!-- end of .item-title -->
981 </div><!-- end of .menu-item-handle -->
982 </div><!-- end of .menu-item-bar -->
983 <?php
984 $i = 1;
985 ?>
986 </li>
987 <?php
988 $menu_key_in_use[] = $menu_key;
989 }
990 }
991 }
992 // Render the rest of the current menu towards the end of the sortables
993 foreach ( $menu as $menu_key => $menu_info ) {
994 if ( !in_array( $menu_key, $menu_key_in_use ) ) {
995 // Skip deleted built-in separators only for real separator rows; Pro distinguishes ASE additional-separator rows.
996 $skip_deleted_separator = false;
997 if ( isset( $menu_info[2], $menu_info[4] ) && false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
998 $skip_deleted_separator = in_array( $menu_info[2], $deleted_separators_array, true );
999 }
1000 if ( $skip_deleted_separator ) {
1001 continue;
1002 }
1003 if ( false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
1004 $menu_item_id = $menu_info[2];
1005 } else {
1006 $menu_item_id = $menu_info[5];
1007 }
1008 $menu_item_title = $menu_info[0];
1009 $menu_url_fragment = '';
1010 // Strip tags
1011 $menu_item_title = $common_methods->strip_html_tags_and_content( $menu_item_title );
1012 // Exclude Show All/Less toggles
1013 if ( false === strpos( $menu_item_id, 'toplevel_page_asenha_' ) ) {
1014 $menu_item_id_transformed = $common_methods->transform_menu_item_id( $menu_item_id );
1015 $is_custom_menu = 'no';
1016 $menu_required_capability = ( isset( $menu_info[1] ) ? $menu_info[1] : '' );
1017 ?>
1018 <li id="<?php
1019 echo esc_attr( $menu_item_id );
1020 ?>" class="menu-item parent-menu-item menu-item-depth-0" data-custom-menu-item="<?php
1021 echo esc_attr( $is_custom_menu );
1022 ?>">
1023 <div class="menu-item-bar">
1024 <div class="menu-item-handle">
1025 <span class="dashicons dashicons-menu"></span>
1026 <div class="item-title">
1027 <div class="title-wrapper">
1028 <span class="menu-item-title">
1029 <?php
1030 if ( false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
1031 echo '~~ ' . esc_html( $this->format_admin_menu_separator_slug_for_display( $menu_info[2] ) ) . ' ~~';
1032 } else {
1033 ?>
1034 <input type="text" value="<?php
1035 echo wp_kses_post( wp_unslash( $menu_item_title ) );
1036 ?>" class="menu-item-custom-title" data-menu-item-id="<?php
1037 echo esc_attr( $menu_item_id );
1038 ?>">
1039 <?php
1040 }
1041 ?>
1042 </span>
1043 <?php
1044 ?>
1045 </div>
1046 <div class="options-for-hiding">
1047 <?php
1048 $hide_text = __( 'Hide until toggled', 'admin-site-enhancements' );
1049 $checkbox_class = 'parent-menu-hide-checkbox';
1050 ?>
1051 <label class="menu-item-checkbox-label">
1052 <input type="checkbox" id="hide-status-for-<?php
1053 echo esc_attr( $menu_item_id_transformed );
1054 ?>" class="<?php
1055 echo esc_attr( $checkbox_class );
1056 ?>" data-menu-item-title="<?php
1057 echo esc_attr( $common_methods->strip_html_tags_and_content( $menu_item_title ) );
1058 ?>" data-menu-item-id="<?php
1059 echo esc_attr( $menu_item_id_transformed );
1060 ?>" data-menu-item-id-ori="<?php
1061 echo esc_attr( $menu_item_id );
1062 ?>" data-menu-url-fragment="<?php
1063 echo esc_attr( $menu_url_fragment );
1064 ?>" data-required-capability="<?php
1065 echo esc_attr( $menu_required_capability );
1066 ?>">
1067 <span><?php
1068 echo esc_html( $hide_text );
1069 ?></span>
1070 </label>
1071 <?php
1072 ?>
1073 </div><!-- end of .options-for-hiding -->
1074 </div><!-- end of .item-title -->
1075 </div><!-- end of .menu-item-handle -->
1076 </div><!-- end of .menu-item-bar -->
1077 <?php
1078 $i = 1;
1079 // Add delete icon for saved custom menu items (not separators)
1080 if ( $is_custom_menu === 'yes' && strpos( $menu_info[2], 'separator' ) === false ) {
1081 ?>
1082 <div class="remove-custom-menu-item-saved" data-menu-item-id="<?php
1083 echo esc_attr( $menu_info[2] );
1084 ?>">
1085 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24">
1086 <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"/>
1087 </svg>
1088 </div>
1089 <?php
1090 }
1091 ?>
1092 </li><!-- end of .menu-item -->
1093 <?php
1094 }
1095 }
1096 }
1097 } else {
1098 // No custom menu order has been saved yet
1099 // Render sortables with existing items in the admin menu
1100 foreach ( $menu as $menu_key => $menu_info ) {
1101 // Skip deleted built-in separators only for real separator rows; Pro distinguishes ASE additional-separator rows.
1102 $skip_deleted_separator = false;
1103 if ( isset( $menu_info[2], $menu_info[4] ) && false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
1104 $skip_deleted_separator = in_array( $menu_info[2], $deleted_separators_array, true );
1105 }
1106 if ( $skip_deleted_separator ) {
1107 continue;
1108 }
1109 if ( false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
1110 $menu_item_id = $menu_info[2];
1111 } else {
1112 $menu_item_id = $menu_info[5];
1113 }
1114 $menu_url_fragment = '';
1115 $menu_item_title = $menu_info[0];
1116 $menu_item_id_transformed = $common_methods->transform_menu_item_id( $menu_item_id );
1117 // Strip tags
1118 $menu_item_title = $common_methods->strip_html_tags_and_content( $menu_item_title );
1119 $is_custom_menu = 'no';
1120 $menu_required_capability = ( isset( $menu_info[1] ) ? $menu_info[1] : '' );
1121 $custom_menu_data = null;
1122 $menu_item_handle_classes = 'menu-item-handle';
1123 ?>
1124 <li id="<?php
1125 echo esc_attr( $menu_item_id );
1126 ?>" class="menu-item parent-menu-item menu-item-depth-0" data-custom-menu-item="<?php
1127 echo esc_attr( $is_custom_menu );
1128 ?>" data-menu-slug="<?php
1129 echo esc_attr( $menu_info[2] );
1130 ?>">
1131 <div class="menu-item-bar">
1132 <div class="<?php
1133 echo esc_attr( $menu_item_handle_classes );
1134 ?>">
1135 <span class="dashicons dashicons-menu"></span>
1136 <div class="item-title">
1137 <div class="title-wrapper">
1138 <span class="menu-item-title">
1139 <?php
1140 if ( false !== strpos( $menu_info[4], 'wp-menu-separator' ) ) {
1141 echo '~~ ' . esc_html( $this->format_admin_menu_separator_slug_for_display( $menu_info[2] ) ) . ' ~~';
1142 } else {
1143 if ( in_array( $menu_item_id, $renaming_not_allowed ) ) {
1144 echo wp_kses_post( $menu_item_title );
1145 } else {
1146 ?>
1147 <input type="text" value="<?php
1148 echo wp_kses_post( wp_unslash( $menu_item_title ) );
1149 ?>" class="menu-item-custom-title" data-menu-item-id="<?php
1150 echo esc_attr( $menu_item_id );
1151 ?>">
1152 <?php
1153 }
1154 }
1155 ?>
1156 </span>
1157 <?php
1158 ?>
1159 </div><!-- end of .title-wrapper -->
1160 <div class="options-for-hiding">
1161 <?php
1162 $hide_text = __( 'Hide until toggled', 'admin-site-enhancements' );
1163 $checkbox_class = 'parent-menu-hide-checkbox';
1164 ?>
1165 <label class="menu-item-checkbox-label">
1166 <input type="checkbox" id="hide-status-for-<?php
1167 echo esc_attr( $menu_item_id_transformed );
1168 ?>" class="<?php
1169 echo esc_attr( $checkbox_class );
1170 ?>" data-menu-item-title="<?php
1171 echo esc_attr( $common_methods->strip_html_tags_and_content( $menu_item_title ) );
1172 ?>" data-menu-item-id="<?php
1173 echo esc_attr( $menu_item_id_transformed );
1174 ?>" data-menu-item-id-ori="<?php
1175 echo esc_attr( $menu_item_id );
1176 ?>" data-menu-url-fragment="<?php
1177 echo esc_attr( $menu_url_fragment );
1178 ?>" data-required-capability="<?php
1179 echo esc_attr( $menu_required_capability );
1180 ?>">
1181 <span><?php
1182 echo esc_html( $hide_text );
1183 ?></span>
1184 </label>
1185 <?php
1186 ?>
1187 </div><!-- end of .options-for-hiding -->
1188 </div><!-- end of .item-title -->
1189 </div><!-- end of .menu-item-handle -->
1190 </div><!-- end of .menu-item-bar -->
1191 <?php
1192 $i = 1;
1193 // Add delete icon for saved custom menu items (not separators)
1194 if ( $is_custom_menu === 'yes' && strpos( $menu_info[2], 'separator' ) === false ) {
1195 ?>
1196 <div class="remove-custom-menu-item-saved" data-menu-item-id="<?php
1197 echo esc_attr( $menu_info[2] );
1198 ?>">
1199 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24">
1200 <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"/>
1201 </svg>
1202 </div>
1203 <?php
1204 }
1205 ?>
1206 </li>
1207 <?php
1208 }
1209 }
1210 ?>
1211 </ul>
1212 <?php
1213 ?>
1214 <div class="admin-menu-actions-wrapper">
1215 <?php
1216 ?>
1217 <div class="reset-menu-wrapper">
1218 <img src="<?php
1219 echo esc_attr( ASENHA_URL );
1220 ?>assets/img/oval.svg" class="reset-menu-spinner" style="display: none;" /><a href="#" id="reset-menu"><?php
1221 echo esc_html__( 'Reset Menu', 'admin-site-enhancements' );
1222 ?></a>
1223 </div>
1224 </div>
1225 <?php
1226 // Hidden input field to store custom menu order (from options as is, or sortupdate) upon clicking Save Changes.
1227 $field_id = 'custom_menu_order';
1228 $field_option_value = ( isset( $options[$field_id] ) ? $options[$field_id] : '' );
1229 echo '<input type="hidden" id="' . esc_attr( $field_id ) . '" class="asenha-subfield-text" name="' . esc_attr( $field_id ) . '" value="' . esc_attr( $field_option_value ) . '">';
1230 // Hidden input field to store hidden menu items (from options as is, or 'Hide' checkbox clicks) upon clicking Save Changes.
1231 $this->output_admin_menu_organizer_hidden_field( 'custom_menu_hidden' );
1232 // Hidden input field to store custom menu titles (from options as is, or custom values entered on each non-WP-default menu items.
1233 $this->output_admin_menu_organizer_hidden_field( 'custom_menu_titles' );
1234 }
1235
1236 /**
1237 * Decode and re-encode JSON option values for AMO hidden fields so WordPress-slashed or legacy
1238 * strings become valid for JavaScript JSON.parse(), without applying stripslashes() to raw strings
1239 * (which would break JSON \\u Unicode escapes).
1240 *
1241 * @since 8.5.3
1242 *
1243 * @param string $value Raw option value.
1244 * @return string
1245 */
1246 private function normalize_admin_menu_json_option_for_output( $value ) {
1247 if ( !is_string( $value ) || '' === $value ) {
1248 return $value;
1249 }
1250 // Use objects (not associative arrays) so JSON objects stay objects and arrays stay arrays.
1251 $decoded = json_decode( $value, false );
1252 if ( JSON_ERROR_NONE === json_last_error() ) {
1253 return wp_json_encode( $decoded );
1254 }
1255 $decoded = json_decode( wp_unslash( $value ), false );
1256 if ( JSON_ERROR_NONE === json_last_error() ) {
1257 return wp_json_encode( $decoded );
1258 }
1259 return $value;
1260 }
1261
1262 /**
1263 * Output hidden field
1264 *
1265 * @since 6.9.13
1266 */
1267 public function output_admin_menu_organizer_hidden_field( $field_id ) {
1268 $options_extra = get_option( ASENHA_SLUG_U . '_extra', array() );
1269 $options = ( isset( $options_extra['admin_menu'] ) ? $options_extra['admin_menu'] : array() );
1270 $field_name = $field_id;
1271 $field_option_value = ( isset( $options[$field_id] ) ? $options[$field_id] : '' );
1272 $json_option_field_ids = array(
1273 'custom_menu_new_separators',
1274 'custom_menu_deleted_separators',
1275 'custom_submenus_order',
1276 'custom_menu_always_hidden',
1277 'custom_submenu_always_hidden',
1278 'custom_menu_new_items'
1279 );
1280 if ( in_array( $field_id, $json_option_field_ids, true ) ) {
1281 $field_option_value = $this->normalize_admin_menu_json_option_for_output( $field_option_value );
1282 }
1283 echo '<input type="hidden" id="' . esc_attr( $field_name ) . '" class="asenha-subfield-text" name="' . esc_attr( $field_name ) . '" value="' . esc_attr( $field_option_value ) . '">';
1284 }
1285
1286 /**
1287 * Render textarea field as sub-field of a toggle/switcher checkbox
1288 *
1289 * @since 2.3.0
1290 */
1291 function render_datatable( $args ) {
1292 global $wpdb;
1293 $option_name = $args['option_name'];
1294 if ( !empty( $option_name ) ) {
1295 $options = get_option( $option_name, array() );
1296 } else {
1297 $options = get_option( ASENHA_SLUG_U, array() );
1298 }
1299 $field_id = $args['field_id'];
1300 $field_slug = $args['field_slug'];
1301 $field_name = $args['field_name'];
1302 $field_type = $args['field_type'];
1303 $field_description = $args['field_description'];
1304 $table_title = $args['table_title'];
1305 $table_name = $args['table_name'];
1306 $field_option_value = ( isset( $options[$args['field_id']] ) ? $options[$args['field_id']] : '' );
1307 $login_fails_allowed = ( isset( $options['login_fails_allowed'] ) ? (int) $options['login_fails_allowed'] : 3 );
1308 $login_lockout_maxcount = ( isset( $options['login_lockout_maxcount'] ) ? (int) $options['login_lockout_maxcount'] : 3 );
1309 $login_fails_allowed = ( $login_fails_allowed > 0 ? $login_fails_allowed : 3 );
1310 $login_lockout_maxcount = ( $login_lockout_maxcount > 0 ? $login_lockout_maxcount : 3 );
1311 $default_lockout_period = 60 * 15;
1312 // 15 minutes in seconds.
1313 $extended_lockout_period = 24 * 60 * 60;
1314 // 24 hours in seconds.
1315 $now = time();
1316 $ip_address_whitelist = array();
1317 ?>
1318 <table id="login-attempts-log" class="wp-list-table widefat striped datatable">
1319 <thead>
1320 <tr class="datatable-tr">
1321 <th class="datatable-th"><?php
1322 _e( 'IP Address<br />Last Username', 'admin-site-enhancements' );
1323 ?></th>
1324 <th class="datatable-th"><?php
1325 _e( 'Attempts<br />Lockouts', 'admin-site-enhancements' );
1326 ?></th>
1327 <th class="datatable-th"><?php
1328 _e( 'Last Attempt On', 'admin-site-enhancements' );
1329 ?></th>
1330 <th class="datatable-th"><?php
1331 _e( 'Actions', 'admin-site-enhancements' );
1332 ?></th>
1333 </tr>
1334 </thead>
1335 <tbody>
1336 <?php
1337 $limit = 1000;
1338 $sql = $wpdb->prepare( "SELECT * FROM {$table_name} ORDER BY unixtime DESC LIMIT %d", array($limit) );
1339 $entries = $wpdb->get_results( $sql, ARRAY_A );
1340 foreach ( $entries as $entry ) {
1341 $unixtime = $entry['unixtime'];
1342 $ip_address = ( isset( $entry['ip_address'] ) ? (string) $entry['ip_address'] : '' );
1343 $fail_count = ( isset( $entry['fail_count'] ) ? (int) $entry['fail_count'] : 0 );
1344 $lockout_count = ( isset( $entry['lockout_count'] ) ? (int) $entry['lockout_count'] : 0 );
1345 $locked_condition = $fail_count > 0 && $fail_count % $login_fails_allowed === 0;
1346 $is_extended_lockout = $lockout_count >= $login_lockout_maxcount;
1347 $lockout_period = ( $is_extended_lockout ? $extended_lockout_period : $default_lockout_period );
1348 $is_locked_out = $locked_condition && $now - (int) $unixtime <= $lockout_period;
1349 $is_whitelisted = in_array( $ip_address, $ip_address_whitelist, true );
1350 if ( function_exists( 'wp_date' ) ) {
1351 $date = wp_date( 'F j, Y', $unixtime );
1352 $time = wp_date( 'H:i:s', $unixtime );
1353 } else {
1354 $date = date_i18n( 'F j, Y', $unixtime );
1355 $time = date_i18n( 'H:i:s', $unixtime );
1356 }
1357 ?>
1358 <tr class="datatable-tr">
1359 <td class="datatable-td"><?php
1360 echo esc_html( $ip_address );
1361 ?><br /><?php
1362 echo esc_html( $entry['username'] );
1363 ?></td>
1364 <td class="datatable-td"><?php
1365 echo esc_html( $fail_count );
1366 ?><br /><?php
1367 echo esc_html( $lockout_count );
1368 ?></td>
1369 <td class="datatable-td"><span class="unixtime"><?php
1370 echo esc_html( $entry['unixtime'] );
1371 ?></span><?php
1372 echo esc_html( $date );
1373 ?><br /><?php
1374 echo esc_html( $time );
1375 ?></td>
1376 <td class="datatable-td">
1377 <?php
1378 if ( $is_locked_out && !$is_whitelisted ) {
1379 ?>
1380 <a href="#" class="button button-secondary button-small asenha-release-login-lock" data-ip-address="<?php
1381 echo esc_attr( $ip_address );
1382 ?>"><?php
1383 _e( 'Release Lock', 'admin-site-enhancements' );
1384 ?></a>
1385 <?php
1386 }
1387 ?>
1388 <?php
1389 ?>
1390 </td>
1391 </tr>
1392 <?php
1393 }
1394 ?>
1395 </tbody>
1396 </table>
1397 <?php
1398 echo '<div class="asenha-subfield-description">' . esc_html( $field_description ) . '</div>';
1399 echo '<input type="hidden" id="' . esc_attr( $field_name ) . '" class="asenha-subfield-datatable" name="' . esc_attr( $field_name ) . '" value="' . esc_attr( $field_option_value ) . '">';
1400 }
1401
1402 /**
1403 * Render checks and status for AVIF support
1404 *
1405 * @link https://php.watch/versions/8.1/gd-avif
1406 * @since 5.7.0
1407 */
1408 public function render_avif_support_status() {
1409 // Check status of GD extension and it's AVIF support
1410 if ( extension_loaded( 'gd' ) && function_exists( 'gd_info' ) ) {
1411 $is_gd_enabled = true;
1412 $gd_info = gd_info();
1413 $gd_version = $gd_info['GD Version'];
1414 $gd_avif_support = ( isset( $gd_info['AVIF Support'] ) ? isset( $gd_info['AVIF Support'] ) : false );
1415 if ( $gd_avif_support ) {
1416 $gd_status = $gd_version . ' <span class="supported">' . __( 'with AVIF support', 'admin-site-enhancements' ) . '</span>';
1417 } else {
1418 $gd_status = $gd_version . ' <span class="unsupported">' . __( 'without AVIF support', 'admin-site-enhancements' ) . '</span>';
1419 }
1420 } else {
1421 $is_gd_enabled = false;
1422 $gd_avif_support = false;
1423 $gd_status = __( 'Not available', 'admin-site-enhancements' );
1424 }
1425 // Check status of ImageMagick library and it's AVIF support
1426 if ( extension_loaded( 'imagick' ) && class_exists( 'Imagick' ) ) {
1427 $is_imagick_enabled = true;
1428 $imagick_version = \Imagick::getVersion();
1429 if ( preg_match( '/((?:[0-9]+\\.?)+)/', $imagick_version['versionString'], $matches ) ) {
1430 $imagick_version = $matches[0];
1431 } else {
1432 $imagick_version = $imagick_version['versionString'];
1433 }
1434 if ( version_compare( $imagick_version, '7.0.25', '>=' ) ) {
1435 $imagick_avif_support = true;
1436 $imagick_status = $imagick_version . ' <span class="supported">with AVIF support</span>';
1437 } else {
1438 $imagick_avif_support = false;
1439 $imagick_status = $imagick_version . ' <span class="unsupported">without AVIF support</span>';
1440 }
1441 } else {
1442 $is_imagick_enabled = false;
1443 $imagick_avif_support = false;
1444 $imagick_status = __( 'Not available', 'admin-site-enhancements' );
1445 }
1446 echo '<div class="asenha-subfield-status">';
1447 echo '<div class="status-title">' . __( 'AVIF Support Status', 'admin-site-enhancements' ) . '</div>';
1448 echo '<div class="status-body">';
1449 echo '<div class="status-item"><span class="status-item-title">PHP</span> : ' . wp_kses_post( phpversion() ) . '</div>';
1450 echo '<div class="status-item"><span class="status-item-title">GD</span> : ' . wp_kses_post( $gd_status ) . '</div>';
1451 echo '<div class="status-item"><span class="status-item-title">ImageMagick</span> : ' . wp_kses_post( $imagick_status ) . '</div>';
1452 echo '</div>';
1453 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>';
1454 echo '</div>';
1455 }
1456
1457 }
1458