-
Notifications
You must be signed in to change notification settings - Fork 143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add user_select field #614
Changes from 10 commits
00935df
71c0d26
55e502d
471afc4
d5967a3
a077c94
e2b9c7a
ce078fb
19c9d3c
7a3aea0
a9098e8
9e816a1
c9a1365
0b9e7c9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
<?php | ||
|
||
class Shortcode_UI_Field_User_Select { | ||
|
||
private static $instance; | ||
|
||
// All registered user fields. | ||
private $user_fields = array(); | ||
|
||
// Field Settings. | ||
private $fields = array( | ||
'user_select' => array( | ||
'template' => 'shortcode-ui-field-user-select', | ||
'view' => 'editAttributeFieldUserSelect', | ||
), | ||
); | ||
|
||
/** | ||
* Setup the instance. | ||
* | ||
* @return Shortcode_UI_Field_User_Select | ||
*/ | ||
public static function get_instance() { | ||
|
||
if ( ! isset( self::$instance ) ) { | ||
self::$instance = new self; | ||
self::$instance->setup_actions(); | ||
} | ||
return self::$instance; | ||
} | ||
|
||
/** | ||
* Add the required actions and filters. | ||
*/ | ||
private function setup_actions() { | ||
|
||
add_filter( 'shortcode_ui_fields', array( $this, 'filter_shortcode_ui_fields' ) ); | ||
add_action( 'enqueue_shortcode_ui', array( $this, 'action_enqueue_shortcode_ui' ) ); | ||
add_action( 'wp_ajax_shortcode_ui_user_field', array( $this, 'action_wp_ajax_shortcode_ui_user_field' ) ); | ||
add_action( 'shortcode_ui_loaded_editor', array( $this, 'action_shortcode_ui_loaded_editor' ) ); | ||
} | ||
|
||
/** | ||
* Add our field to the shortcode fields. | ||
* | ||
* @param $fields | ||
* | ||
* @return array | ||
*/ | ||
public function filter_shortcode_ui_fields( $fields ) { | ||
|
||
return array_merge( $fields, $this->fields ); | ||
} | ||
|
||
/** | ||
* Add Select2 for our UI. | ||
*/ | ||
public function action_enqueue_shortcode_ui() { | ||
|
||
$plugin_dir = dirname( dirname( __FILE__ ) ); | ||
|
||
wp_enqueue_script( 'select2', plugins_url( 'lib/select2/select2.min.js', $plugin_dir ), array( 'jquery', 'jquery-ui-sortable' ), '3.5.2' ); | ||
wp_enqueue_style( 'select2', plugins_url( 'lib/select2/select2.css', $plugin_dir ), null, '3.5.2' ); | ||
|
||
wp_localize_script( 'shortcode-ui', 'shortcodeUiUserFieldData', array( | ||
'nonce' => wp_create_nonce( 'shortcode_ui_field_user_select' ), | ||
) ); | ||
} | ||
|
||
/** | ||
* Output styles and templates used by user select field. | ||
*/ | ||
public function action_shortcode_ui_loaded_editor() { | ||
?> | ||
|
||
<style> | ||
|
||
.edit-shortcode-form .select2-container { | ||
min-width: 300px; | ||
} | ||
|
||
.edit-shortcode-form .select2-container a { | ||
transition: none; | ||
-webkit-transition: none; | ||
} | ||
|
||
.wp-admin .select2-drop { | ||
z-index: 160001; | ||
} | ||
|
||
</style> | ||
|
||
<script type="text/html" id="tmpl-shortcode-ui-field-user-select"> | ||
<div class="field-block shortcode-ui-field-user-select shortcode-ui-attribute-{{ data.attr }}"> | ||
<label for="{{ data.id }}">{{{ data.label }}}</label> | ||
<input type="text" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value }}" class="shortcode-ui-user-select" /> | ||
<# if ( typeof data.description == 'string' ) { #> | ||
<p class="description">{{{ data.description }}}</p> | ||
<# } #> | ||
</div> | ||
</script> | ||
|
||
<?php | ||
} | ||
|
||
/** | ||
* Ajax handler for select2 user field queries. | ||
* Output JSON containing user data. | ||
* Requires that shortcode, attr and nonce are passed. | ||
* Requires that the field has been correctly registered and can be found in $this->post_fields | ||
* Supports passing page number and search query string. | ||
* | ||
* @return null | ||
*/ | ||
public function action_wp_ajax_shortcode_ui_user_field() { | ||
|
||
$nonce = isset( $_GET['nonce'] ) ? sanitize_text_field( $_GET['nonce'] ) : null; | ||
$requested_shortcode = isset( $_GET['shortcode'] ) ? sanitize_text_field( $_GET['shortcode'] ) : null; | ||
$requested_attr = isset( $_GET['attr'] ) ? sanitize_text_field( $_GET['attr'] ) : null; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Each of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @westonruter could you explain a bit more why we need There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dashaluna sure, WordPress has an unfortunately legacy back-compat feature where it will force all of the input vars like For more information, see https://core.trac.wordpress.org/ticket/18322 |
||
$response = array( 'users' => array(), 'found_users' => 0, 'users_per_page' => 0 ); | ||
|
||
if ( ! wp_verify_nonce( $nonce, 'shortcode_ui_field_user_select' ) ) { | ||
wp_send_json_error( $response ); | ||
} | ||
|
||
$shortcodes = Shortcode_UI::get_instance()->get_shortcodes(); | ||
|
||
// Shortcode not found. | ||
if ( ! isset( $shortcodes[ $requested_shortcode ] ) ) { | ||
wp_send_json_error( $response ); | ||
} | ||
|
||
$shortcode = $shortcodes[ $requested_shortcode ]; | ||
|
||
// Defaults user query args. | ||
$query_args['search_columns'] = array( 'ID', 'user_login', 'user_nicename', 'user_email' ); | ||
$query_args['number'] = 10; | ||
|
||
// Include selected users. | ||
if ( isset( $_GET['include'] ) ) { | ||
$query_args['include'] = is_array( $_GET['include'] ) ? $_GET['include'] : explode( ',', $_GET['include'] ); | ||
$query_args['include'] = array_map( 'absint', $query_args['include'] ); | ||
} | ||
|
||
// Supports WP_User_Query query args. | ||
foreach ( $shortcode['attrs'] as $attr ) { | ||
if ( $attr['attr'] === $requested_attr && isset( $attr['query'] ) ) { | ||
$query_args = $attr['query']; | ||
} | ||
} | ||
|
||
if ( isset( $_GET['page'] ) ) { | ||
$query_args['paged'] = sanitize_text_field( $_GET['page'] ); | ||
} | ||
|
||
if ( ! empty( $_GET['s'] ) ) { | ||
$query_args['search'] = '*' . sanitize_text_field( $_GET['s'] ) . '*'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest moving all of the accessing of the input vars to the top of this method and to store the sanitized values in regular variables. So at the top: $s = null;
if ( isset( $_GET['s'] ) ) {
$s = sanitize_text_field( wp_unslash( $_GET['s'] ) );
} And then down here: if ( ! empty( $_GET['s'] ) ) {
$query_args['search'] = '*' . $s . '*';
} I think it is a best practice to sanitize early and escape late. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @westonruter in the second code chunk you mean There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, sorry. It could be just: if ( $s ) {
$query_args['search'] = '*' . $s . '*';
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Np, just making sure I understand it correctly :) |
||
} | ||
|
||
$query = new WP_User_Query( $query_args ); | ||
|
||
foreach ( $query->get_results() as $user ) { | ||
array_push( $response['users'], array( | ||
'id' => $user->ID, | ||
'text' => html_entity_decode( $user->display_name ), | ||
) ); | ||
} | ||
|
||
$response['found_users'] = $query->get_total(); | ||
$response['users_per_page'] = $query->query_vars['number']; | ||
|
||
wp_send_json_success( $response ); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should
select2
be registered (e.g. viawp_register_script()
) once and then just the handle enqueued here?Here's how I've been doing it for a Customizer control that uses Select2:
https://github.com/xwp/wp-customize-object-selector/blob/423e8f62a326ba05f164b0077ce944ad2ed91bfc/php/class-plugin.php#L70-L76
https://github.com/xwp/wp-customize-object-selector/blob/423e8f62a326ba05f164b0077ce944ad2ed91bfc/php/class-plugin.php#L106-L112