File "Dropdown.php"
Full Path: /home/romayxjt/public_html/wp-content/plugins/the-events-calendar/common/src/Tribe/Ajax/Dropdown.php
File size: 9.87 KB
MIME-type: text/x-php
Charset: utf-8
<?php
/**
* Ajax Dropdown class.
*/
/**
* Handles common AJAX operations.
*
* @since 4.6
*/
class Tribe__Ajax__Dropdown { // phpcs:ignore-next-line PEAR.NamingConventions.ValidClassName.Invalid
/**
* Hooks the AJAX for Select2 Dropdowns
*
* @since 4.6
*
* @return void
*/
public function hook() {
add_action( 'wp_ajax_tribe_dropdown', [ $this, 'route' ] );
add_action( 'wp_ajax_nopriv_tribe_dropdown', [ $this, 'route' ] );
}
/**
* Search for Terms using Select2
*
* @since 4.6
*
* @param string|array<string|mixed> $search Search string from Select2.
* @param int $page When we deal with pagination.
* @param array<string|mixed> $args Which arguments we got from the Template.
* @param string $source What source it is.
*
* @return array<string|mixed>
*/
public function search_terms( $search, $page, $args, $source ) {
$data = [];
if ( empty( $args['taxonomy'] ) ) {
$this->error( esc_attr__( 'Cannot look for Terms without a taxonomy', 'tribe-common' ) );
}
// We always want all the fields so we overwrite it.
$args['fields'] = $args['fields'] ?? 'all';
$args['hide_empty'] = $args['hide_empty'] ?? false;
if ( ! empty( $search ) ) {
if ( ! is_array( $search ) ) {
// For older pieces that still use Select2 format.
$args['search'] = $search;
} else {
// Newer SelectWoo uses a new search format.
$args['search'] = $search['term'];
}
}
// On versions older than 4.5 taxonomy goes as a Param.
if ( version_compare( $GLOBALS['wp_version'], '4.5', '<' ) ) {
$terms = get_terms( $args['taxonomy'], $args );
} else {
$terms = get_terms( $args );
}
$results = [];
// Respect the parent/child_of argument if set.
$parent = ! empty( $args['child_of'] ) ? (int) $args['child_of'] : 0;
$parent = ! empty( $args['parent'] ) ? (int) $args['parent'] : $parent;
if ( empty( $args['search'] ) ) {
$this->sort_terms_hierarchically( $terms, $results, $parent );
$results = $this->convert_children_to_array( $results );
} else {
foreach ( $terms as $term ) {
// Prep for Select2.
$term->id = $term->term_id;
$term->text = $term->name;
$term->breadcrumbs = [];
if ( 0 !== (int) $term->parent ) {
$ancestors = get_ancestors( $term->id, $term->taxonomy );
$ancestors = array_reverse( $ancestors );
foreach ( $ancestors as $ancestor ) {
$ancestor = get_term( $ancestor );
$term->breadcrumbs[] = $ancestor->name;
}
}
$results[] = $term;
}
}
foreach ( $results as $result ) {
$result->text = wp_specialchars_decode( wp_kses( $result->text, [] ) );
}
$data['results'] = $results;
$data['taxonomies'] = get_taxonomies();
return $data;
}
/**
* Search for Posts using Select2
*
* @since 4.12.17
*
* @param string|array<string,mixed> $search Search string from Select2.
* @param int $page Page we want when we're dealing with pagination.
* @param array<string,mixed> $args Arguments to pass to the query.
* @param string|int $selected Selected item ID.
*
* @return array<string|mixed> An Array of results.
*/
public function search_posts( $search, $page = 1, $args = [], $selected = null ) {
if ( ! empty( $search ) ) {
if ( is_array( $search ) ) {
// Newer SelectWoo uses a new search format.
$args['s'] = $search['term']; // post?
} else {
// For older pieces that still use Select2 format.
$args['s'] = $search;
}
}
$args['post_status'] = $args['post_status'] ?? 'publish';
$args['paged'] = $page;
$args['update_post_meta_cache'] = false;
$args['update_post_term_cache'] = false;
$results = new WP_Query( $args );
$has_pagination = $results->post_count < $results->found_posts;
return $this->format_posts_for_dropdown( $results->posts, $selected, $has_pagination );
}
/**
* Formats a given array of posts to be displayed into the Dropdown.js module with SelectWoo.
*
* @since 4.12.17
*
* @param array<WP_Post> $posts Array of WP_Post objects.
* @param null|int $selected Selected item ID.
* @param boolean $pagination Whether or not we have pagination.
*
* @return array
*/
public function format_posts_for_dropdown( array $posts, $selected = null, $pagination = false ) {
$data = [
'posts' => [],
'pagination' => $pagination,
];
// Skip when we don't have posts.
if ( empty( $posts ) ) {
return $data;
}
foreach ( $posts as $post ) {
if ( ! $post instanceof \WP_Post ) {
$post = get_post( $post );
}
// Skip non WP Post Objects.
if ( ! $post instanceof \WP_Post ) {
continue;
}
// Prep for Select2.
$data['posts'][] = [
'id' => $post->ID,
'text' => ! empty( $post->post_title_formatted ) ? $post->post_title_formatted : $post->post_title,
'selected' => ! empty( $selected ) && (int) $post->ID === (int) $selected,
];
}
return $data;
}
/**
* Sorts all the Terms for Select2 hierarchically.
*
* @since 4.6
*
* @param array<int|object> $terms Array of Terms from `get_terms`.
* @param array<string|mixed> $into Variable where we will store the.
* @param integer $parent Used for the recursion.
*/
public function sort_terms_hierarchically( &$terms, &$into, $parent = 0 ) {
foreach ( $terms as $i => $term ) {
if ( $term->parent === $parent ) {
// Prep for Select2.
$term->id = $term->term_id;
$term->text = $term->name;
$into[ $term->term_id ] = $term;
unset( $terms[ $i ] );
}
}
foreach ( $into as $term ) {
$term->children = [];
$this->sort_terms_hierarchically( $terms, $term->children, $term->term_id );
}
}
/**
* Makes sure we have arrays for the JS data for Select2
*
* @since 4.6
*
* @param object|array<string|mixed> $results The Select2 results.
*
* @return array<string|mixed>
*/
public function convert_children_to_array( $results ) {
if ( isset( $results->children ) ) {
$results->children = $this->convert_children_to_array( $results->children );
if ( empty( $results->children ) ) {
unset( $results->children );
}
} else {
foreach ( $results as $key => $item ) {
$item = $this->convert_children_to_array( $item );
}
}
if ( empty( $results ) ) {
return [];
}
return array_values( (array) $results );
}
/**
* Parses the Params coming from Select2 Search box.
*
* @since 4.6
* @since 5.1.17 Added an allow list of params to restrict the shape of the database queries.
*
* @param array<string|mixed> $params Params to overwrite the defaults.
*
* @return object
*/
public function parse_params( $params ) {
$allowed_params = [
'search' => $params['search'] ?? null,
'page' => $params['page'] ?? 0,
'source' => $params['source'] ?? null,
'args' => [ 'post_status' => 'publish' ],
];
if ( isset( $params['args']['taxonomy'] ) ) {
$allowed_params['args']['taxonomy'] = $params['args']['taxonomy'];
}
if ( isset( $params['args']['post_type'] ) ) {
$allowed_params['args']['post_type'] = $params['args']['post_type'];
}
// Return Object just for the sake of making it simpler to read.
return (object) $allowed_params;
}
/**
* The default Method that will route all the AJAX calls from our Dropdown AJAX requests
* It is like a Catch All on `wp_ajax_tribe_dropdown` and `wp_ajax_nopriv_tribe_dropdown`
*
* @since 4.6
* @since 5.1.17 Adding more sanitization to the request params.
*
* @return void
*/
public function route() {
// Push all POST params into a Default set of data.
$args = $this->parse_params( empty( $_POST ) ? [] : $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
check_ajax_referer( 'tribe_dropdown', 'nonce' );
if ( empty( $args->source ) ) {
$this->error( esc_attr__( 'Missing data source for this dropdown', 'tribe-common' ) );
}
// Define a Filter to allow external calls to our Select2 Dropdowns.
$filter = sanitize_key( 'tribe_dropdown_' . $args->source );
if ( has_filter( $filter ) ) {
$data = apply_filters( $filter, [], $args->search, $args->page, $args->args, $args->source );
} elseif ( in_array( $args->source, [ 'search_terms', 'search_posts' ] ) ) {
// Switched from array to object above. Specify what we're sending.
$data = call_user_func_array(
[ $this, $args->source ],
[
$args->search,
$args->page,
$args->args,
$args->source,
]
);
}
// If we've got a empty dataset we return an error.
if ( empty( $data ) ) {
$this->error( esc_attr__( 'Empty data set for this dropdown', 'tribe-common' ) );
} else {
$this->success( $data );
}
}
/**
* Prints a success message and ensures that we don't hit bugs on Select2
*
* @since 4.6
*
* @param array $data The data to send back to Select2.
*
* @return void
*/
private function success( $data ) {
// We need a Results item for Select2 Work.
if ( ! isset( $data['results'] ) ) {
$data['results'] = [];
}
wp_send_json_success( $data );
}
/**
* Prints an error message and ensures that we don't hit bugs on Select2
*
* @since 4.6
*
* @param string $message The error message.
*
* @return void
*/
private function error( $message ) {
$data = [
'message' => $message,
'results' => [],
];
wp_send_json_error( $data );
}
/**
* Avoid throwing fatals or notices on sources that are invalid
*
* @since 4.6
*
* @param string $name The name of the method.
* @param mixed $arguments The arguments passed to the method.
*/
public function __call( $name, $arguments ) {
/* Translators: %1$s is the name of the source, %2$s is the class name */
$message = __( 'The "%1$s" source is invalid and cannot be reached on "%2$s" instance.', 'tribe-common' );
return $this->error(
sprintf(
$message,
$name,
__CLASS__
)
);
}
}