<?php
/**
* Advanced search
*
* @category Features
* @package My Calendar Pro
* @author Joe Dolson
* @license GPLv2 or later
* @link https://www.joedolson.com/my-calendar-pro/
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
require __DIR__ . '/classes/class-my-calendar-advanced-search.php';
add_filter( 'mcs_custom_settings_update', 'mcs_advanced_search_update', 10, 2 );
/**
* Update settings for advanced search.
*
* @param string $value Return string.
* @param array $post POST data.
*
* @return string
*/
function mcs_advanced_search_update( $value, $post ) {
// save settings.
$options = get_option( 'mcs_advanced_search' );
if ( isset( $post['advanced_search_settings'] ) ) {
$options['home'] = isset( $post['mcs_home'] ) ? absint( $post['mcs_home'] ) : false;
if ( ! isset( $post['mcs_home'] ) || empty( $post['mcs_home'] ) ) {
$page = mcs_generate_search_page( 'advanced-event-search' );
$options['home'] = $page;
}
$options['date'] = isset( $post['mcs_date'] ) ? true : false;
$options['author'] = isset( $post['mcs_author_search'] ) ? true : false;
$options['host'] = isset( $post['mcs_host'] ) ? true : false;
$options['category'] = isset( $post['mcs_category'] ) ? true : false;
$options['location'] = isset( $post['mcs_location'] ) ? true : false;
$options['template'] = isset( $post['mcs_template'] ) ? sanitize_textarea_field( $post['mcs_template'] ) : '';
$fields = mc_location_fields_array( false );
foreach ( $fields as $field ) {
if ( isset( $post['mcs_location_fields'][ $field ] ) ) {
$location_fields[ $field ] = 'true';
} else {
$location_fields[ $field ] = 'false';
}
}
$options['location_fields'] = $location_fields;
$options['date_from_label'] = isset( $post['mcs_date_from_label'] ) ? sanitize_text_field( $post['mcs_date_from_label'] ) : '';
$options['date_to_label'] = isset( $post['mcs_date_to_label'] ) ? sanitize_text_field( $post['mcs_date_to_label'] ) : '';
$options['author_label'] = isset( $post['mcs_author_label'] ) ? sanitize_text_field( $post['mcs_author_label'] ) : '';
$options['host_label'] = isset( $post['mcs_host_label'] ) ? sanitize_text_field( $post['mcs_host_label'] ) : '';
$options['category_label'] = isset( $post['mcs_category_label'] ) ? sanitize_text_field( $post['mcs_category_label'] ) : '';
$options['location_type_label'] = isset( $post['mcs_location_type_label'] ) ? sanitize_text_field( $post['mcs_location_type_label'] ) : '';
$options['location_name_label'] = isset( $post['mcs_location_name_label'] ) ? sanitize_text_field( $post['mcs_location_name_label'] ) : '';
$options['location_city_label'] = isset( $post['mcs_location_city_label'] ) ? sanitize_text_field( $post['mcs_location_city_label'] ) : '';
$options['location_state_label'] = isset( $post['mcs_location_state_label'] ) ? sanitize_text_field( $post['mcs_location_state_label'] ) : '';
$options['location_region_label'] = isset( $post['mcs_location_region_label'] ) ? sanitize_text_field( $post['mcs_location_region_label'] ) : '';
$options['location_postcode_label'] = isset( $post['mcs_location_postcode_label'] ) ? sanitize_text_field( $post['mcs_location_postcode_label'] ) : '';
$options['location_country_label'] = isset( $post['mcs_location_country_label'] ) ? sanitize_text_field( $post['mcs_location_country_label'] ) : '';
update_option( 'mcs_advanced_search', $options );
$value = __( 'Advanced Search Settings Updated', 'my-calendar-pro' );
}
return $value;
}
add_filter( 'mcs_settings_tabs', 'mcs_advanced_search_tabs' );
/**
* Add settings tab.
*
* @param array $tabs Array of existing tabs.
*
* @return array tabs
*/
function mcs_advanced_search_tabs( $tabs ) {
$tabs['advanced_search'] = __( 'Advanced Search', 'my-calendar-pro' );
return $tabs;
}
/**
* Create a page to use for advanced event search.
*
* @param string $slug desired page.
*
* @return $post_ID integer ID of newly created post.
*/
function mcs_generate_search_page( $slug ) {
global $current_user;
$current_user = wp_get_current_user();
$post = get_page_by_path( $slug );
if ( ! $post ) {
$page = array(
'post_title' => __( 'Advanced Event Search', 'my-calendar-pro' ),
'post_status' => 'publish',
'post_type' => 'page',
'post_author' => $current_user->ID,
'ping_status' => 'closed',
'post_content' => '[advanced_search]',
);
$post_ID = wp_insert_post( $page );
$post_slug = wp_unique_post_slug( $slug, $post_ID, 'publish', 'page', 0 );
wp_update_post(
array(
'ID' => $post_ID,
'post_name' => $post_slug,
)
);
} else {
$post_ID = $post->ID;
}
$options = get_option( 'mcs_advanced_search', array() );
$options['home'] = $post_ID;
update_option( 'mcs_advanced_search', $options );
return $post_ID;
}
/**
* Get advanced search options.
*
* @return array
*/
function mcs_advanced_search_options() {
$options = ( is_array( get_option( 'mcs_advanced_search' ) ) ) ? get_option( 'mcs_advanced_search' ) : array();
$defaults = array(
'home' => '',
'date' => true,
'author' => '',
'host' => '',
'category' => '',
'location' => '',
'template' => '<h3 class="mcs-search-result-title">{linking_title} <strong class="event-date">{date}{time before=", "}</strong></h3> {excerpt}',
'location_fields' => array(),
'date_from_label' => __( 'From', 'my-calendar-pro' ),
'date_to_label' => __( 'To', 'my-calendar-pro' ),
'author_label' => __( 'Author', 'my-calendar-pro' ),
'host_label' => __( 'Host', 'my-calendar-pro' ),
'category_label' => __( 'Category', 'my-calendar-pro' ),
'location_type_label' => __( 'Type of location search', 'my-calendar-pro' ),
'location_name_label' => __( 'Place Name', 'my-calendar-pro' ),
'location_city_label' => __( 'City', 'my-calendar-pro' ),
'location_state_label' => __( 'State', 'my-calendar-pro' ),
'location_region_label' => __( 'Region', 'my-calendar-pro' ),
'location_postcode_label' => __( 'Postal Code', 'my-calendar-pro' ),
'location_country_label' => __( 'Country', 'my-calendar-pro' ),
);
$options = array_merge( $defaults, $options );
return $options;
}
add_filter( 'mcs_settings_panels', 'mcs_advanced_search_settings' );
/**
* Add settings panel for advanced search.
*
* @param array $panels Array of existing tab panels.
*
* @return array
*/
function mcs_advanced_search_settings( $panels ) {
$options = mcs_advanced_search_options();
// Translators: Link to advanced search page.
$url = ( '' !== $options['home'] && is_numeric( $options['home'] ) ) ? sprintf( __( 'Edit: %s', 'my-calendar-pro' ), "<a href='" . get_edit_post_link( $options['home'] ) . "'>" . get_the_title( $options['home'] ) . '</a>' ) : __( 'Page will be generated on save', 'my-calendar-pro' );
$location_fields = '';
$fields = mc_location_fields_array();
foreach ( $fields as $key => $value ) {
if ( empty( $options['location_fields'] ) && 'event_label' === $key ) {
$checked = 'checked="checked"';
} else {
$checked = ( in_array( $key, array_keys( $options['location_fields'] ), true ) && 'true' === $options['location_fields'][ $key ] ) ? 'checked="checked"' : '';
}
$location_fields .= "<li><input type='checkbox' value='true' name='mcs_location_fields[$key]' id='mcs_location_fields_$key' $checked /> <label for='mcs_location_fields_$key'>$value</label></li>";
}
// Translators: URL to template help.
$get_help = sprintf( __( 'See <a href="%s">templating help</a> for template assistance.', 'my-calendar-pro' ), admin_url( 'admin.php?page=my-calendar-design#my-calendar-templates' ) );
$controls = "
<p>
<label for='mcs_home'>" . __( 'Advanced Search Page', 'my-calendar-pro' ) . "</label>
<input size='4' type='number' name='mcs_home' readonly id='mcs_home' aria-describedby='mcs_home_url' value='" . esc_attr( $options['home'] ) . "' /> <span id='mcs_home_url'>$url</span>
</p>
<fieldset>
<legend>" . __( 'Enabled Search Fields', 'my-calendar-pro' ) . "</legend>
<ul class='checkboxes'>
<li>
<input type='checkbox' value='true' name='mcs_date' id='mcs_date' " . checked( $options['date'], true, false ) . " /> <label for='mcs_date'>" . __( 'Dates', 'my-calendar-pro' ) . "</label>
</li>
<li>
<input type='checkbox' value='true' name='mcs_author_search' id='mcs_author_search' " . checked( $options['author'], true, false ) . " /> <label for='mcs_author_search'>" . __( 'Author', 'my-calendar-pro' ) . "</label>
</li>
<li>
<input type='checkbox' value='true' name='mcs_host' id='mcs_host' " . checked( $options['host'], true, false ) . " /> <label for='mcs_host'>" . __( 'Host', 'my-calendar-pro' ) . "</label>
</li>
<li>
<input type='checkbox' value='true' name='mcs_category' id='mcs_category' " . checked( $options['category'], true, false ) . " /> <label for='mcs_category'>" . __( 'Categories', 'my-calendar-pro' ) . "</label>
</li>
<li>
<input type='checkbox' value='true' name='mcs_location' id='mcs_location' " . checked( $options['location'], true, false ) . " /> <label for='mcs_location'>" . __( 'Location', 'my-calendar-pro' ) . '</label>
</li>
</ul>
</fieldset>
<fieldset>
<legend>' . __( 'Search Field Labels', 'my-calendar-pro' ) . "</legend>
<ul class='labels'>
<li>
<label for='mcs_date_from'>" . __( 'Starting Date Label', 'my-calendar-pro' ) . "</label>
<input type='text' name='mcs_date_from_label' id='mcs_date_from' value='" . esc_attr( $options['date_from_label'] ) . "' />
</li>
<li>
<label for='mcs_date_to'>" . __( 'Ending Date Label', 'my-calendar-pro' ) . "</label>
<input type='text' name='mcs_date_to_label' id='mcs_date_to' value='" . esc_attr( $options['date_to_label'] ) . "' />
</li>
<li>
<label for='mcs_author_label'>" . __( 'Author Label', 'my-calendar-pro' ) . "</label>
<input type='text' name='mcs_author_label' id='mcs_author_label' value='" . esc_attr( $options['author_label'] ) . "' />
</li>
<li>
<label for='mcs_host_label'>" . __( 'Host Label', 'my-calendar-pro' ) . "</label>
<input type='text' name='mcs_host_label' id='mcs_host_label' value='" . esc_attr( $options['host_label'] ) . "' />
</li>
<li>
<label for='mcs_category_label'>" . __( 'Category Label', 'my-calendar-pro' ) . "</label>
<input type='text' name='mcs_category_label' id='mcs_category_label' value='" . esc_attr( $options['category_label'] ) . "' />
</li>
<li>
<label for='mcs_location_label'>" . __( 'Location Type Label', 'my-calendar-pro' ) . "</label>
<input type='text' name='mcs_location_type_label' id='mcs_location_label' value='" . esc_attr( $options['location_type_label'] ) . "' />
</li>
</ul>
</fieldset>
<fieldset>
<legend>" . __( 'Location search options', 'my-calendar-pro' ) . "</legend>
<ul class='checkboxes'>
$location_fields
</ul>
</fieldset>
<fieldset>
<legend>" . __( 'Location Field Labels', 'my-calendar-pro' ) . "</legend>
<ul class='labels'>
<li>
<label for='mcs_location_name'>" . __( 'Name Label', 'my-calendar-pro' ) . "</label>
<input type='text' name='mcs_location_name_label' id='mcs_location_name' value='" . esc_attr( $options['location_name_label'] ) . "' />
</li>
<li>
<label for='mcs_location_city'>" . __( 'City Label', 'my-calendar-pro' ) . "</label>
<input type='text' name='mcs_location_city_label' id='mcs_location_city' value='" . esc_attr( $options['location_city_label'] ) . "' />
</li>
<li>
<label for='mcs_location_state'>" . __( 'State Label', 'my-calendar-pro' ) . "</label>
<input type='text' name='mcs_location_state_label' id='mcs_location_state' value='" . esc_attr( $options['location_state_label'] ) . "' />
</li>
<li>
<label for='mcs_location_country'>" . __( 'Country Label', 'my-calendar-pro' ) . "</label>
<input type='text' name='mcs_location_country_label' id='mcs_location_country' value='" . esc_attr( $options['location_country_label'] ) . "' />
</li>
<li>
<label for='mcs_location_postcode'>" . __( 'Postal Code Label', 'my-calendar-pro' ) . "</label>
<input type='text' name='mcs_location_postcode_label' id='mcs_location_postcode' value='" . esc_attr( $options['location_postcode_label'] ) . "' />
</li>
<li>
<label for='mcs_location_region'>" . __( 'Region Label', 'my-calendar-pro' ) . "</label>
<input type='text' name='mcs_location_region_label' id='mcs_location_region' value='" . esc_attr( $options['location_region_label'] ) . "' />
</li>
</ul>
</fieldset>
<p>
<label for='mcs_template'>" . __( 'Search Results Template', 'my-calendar-pro' ) . "</label>
<textarea aria-describedby='mcs_template_help' class='widefat' cols='60' rows='12' name='mcs_template' id='mcs_template'>" . stripslashes( esc_attr( $options['template'] ) ) . "</textarea>
<span id='mcs_template_help'>" . $get_help . '</span>
</p>';
$panels['advanced_search'] = '
<h2>' . __( 'Advanced Search', 'my-calendar-pro' ) . '</h2>
<div class="inside">
' . $controls . '
{submit}
</div>';
return $panels;
}
add_filter( 'mc_advanced_search', 'mcs_advanced_search', 10, 2 );
/**
* Insert advanced search query into search results
*
* @param string $sql SQL query produced by basic search.
* @param array $query Search parameters.
*
* @return search query.
*/
function mcs_advanced_search( $sql, $query ) {
$defaults = array(
'mc_from' => false,
'mc_to' => false,
'mc_author' => false,
'mc_host' => false,
'mc_category' => false,
'mc_location' => false,
'mc_location_type' => false,
'mcs' => false,
);
$query = array_merge( $defaults, $query );
$category = $query['mc_category'];
$author = $query['mc_author'];
$host = $query['mc_host'];
$ltype = $query['mc_location_type'];
if ( $ltype ) {
$location = ( 'event_label' === $ltype ) ? intval( $query['mc_location']['event_label'] ) : $query['mc_location'][ $ltype ];
} else {
$location = false;
}
$term = $query['mcs'];
$from = ( $query['mc_from'] ) ? mcs_date( 'Y-m-d', strtotime( $query['mc_from'] ) ) : false;
$to = ( $query['mc_to'] ) ? mcs_date( 'Y-m-d', strtotime( $query['mc_to'] ) ) : false;
if ( $location && 'event_label' === $ltype ) {
global $wpdb;
$mcdb = $wpdb;
if ( 'true' === get_option( 'mc_remote' ) && function_exists( 'mc_remote_db' ) ) {
$mcdb = mc_remote_db();
}
$cur_loc = false;
$string_type = '%s';
if ( is_numeric( $location ) ) {
$string_type = '%d';
}
$sql = $mcdb->prepare( 'SELECT location_label FROM ' . my_calendar_locations_table() . " WHERE location_id=$string_type", $location );
$cur_loc = $mcdb->get_row( $sql );
$lvalue = $cur_loc->location_label;
} else {
$lvalue = $location;
}
if ( ! $from && ! $to ) {
$search = mc_prepare_search_query( $term );
} else {
$search = array(
'category' => $category,
'author' => $author,
'host' => $host,
'ltype' => $ltype,
'lvalue' => $lvalue,
'search' => $term,
'from' => $from,
'to' => $to,
);
}
return apply_filters( 'mcs_filter_search_query', $search );
}
/**
* Filter pagination for search results.
*
* @param int $skip Items being skipped.
*
* @return int
*/
function mcs_skip_search_results( $skip = 0 ) {
$i = isset( $_GET['mcsp'] ) ? absint( $_GET['mcsp'] ) : 0;
$i = ( $i > 0 ) ? $i - 1 : 0;
$per_page = 20;
$skip = $i * $per_page;
return $skip;
}
add_filter( 'mc_skip_search_results', 'mcs_skip_search_results', 10, 1 );
add_shortcode( 'advanced_search', 'mcs_advanced_search_form' );
/**
* Advanced search form shortcode.
*
* @param array $atts Shortcode attributes.
* @param string $content contained content.
*
* @return string search form.
*/
function mcs_advanced_search_form( $atts, $content ) {
$args = shortcode_atts(
array(
'date' => 'true',
'author' => 'true',
'host' => 'true',
'category' => 'true',
'location' => 'true',
'home' => '',
),
$atts,
'advanced_search'
);
$options = mcs_advanced_search_options();
if ( get_post( $options['home'] ) ) {
$args = array_merge( $args, $options );
$url = get_permalink( $args['home'] );
} else {
$url = $args['home'];
}
return mcs_search_form( $args, $url );
}
/**
* Advanced search form.
*
* @param array $args Arguments for fields to search by.
* @param string $url Target URL to submit form to.
*
* @return string
*/
function mcs_search_form( $args = array(), $url = '' ) {
global $mcs_version;
$defaults = array(
'date' => false,
'author' => false,
'host' => false,
'category' => false,
'location' => false,
);
$form_id = wp_rand( 1000, 9999 );
$args = array_merge( $defaults, $args );
if ( ! $url || '' === $url ) {
$url = mc_get_uri();
}
$enabled = 0;
$advanced = '';
$mcs = ( isset( $_POST['mcs'] ) ) ? sanitize_text_field( $_POST['mcs'] ) : '';
$mcs = ( isset( $_GET['mcs'] ) && ! isset( $_POST['mcs'] ) ) ? sanitize_text_field( $_GET['mcs'] ) : $mcs;
$script = mcs_setup_duetjs();
$search_js = plugins_url( '/js/jquery.mcs-search.min.js', __FILE__ );
if ( SCRIPT_DEBUG ) {
$mcs_version .= '-' . wp_rand( 10000, 100000 );
$search_js = plugins_url( '/js/jquery.mcs-search.js', __FILE__ );
}
wp_register_script( 'mcs-search-form', $search_js, array( 'jquery' ), $mcs_version, true );
wp_enqueue_script( 'mcs-search-form' );
wp_localize_script(
'mcs-search-form',
'mcsSearch',
array(
'per_page' => 20,
)
);
foreach ( $args as $field => $active ) {
if ( 'false' === $active || false === $active || 0 === $active ) {
$advanced .= '';
} else {
++$enabled;
$advanced .= mcs_generate_search_field( $field, $form_id );
}
}
if ( str_contains( $advanced, 'has-value' ) ) {
$expanded = ' expanded';
} else {
$expanded = ' collapsed';
}
$class = '';
$expand = '';
if ( $enabled > 1 ) {
$expand = '<button type="button" aria-expanded="false">' . __( 'Filters', 'my-calendar-pro' ) . '<span class="dashicons dashicons-arrow-down" aria-hidden="true"></span></button>';
$class = ' has-options';
}
$fields = '
<div class="mc-advanced-search mc-submissions">' . $script . '<form action="' . apply_filters( 'mc_search_page', esc_url( $url ) ) . '" method="GET">
<div>
<input type="hidden" name="mcp" value="true" />
</div>
<label for="mcs' . $form_id . '">' . __( 'Search Term', 'my-calendar-pro' ) . ' ' . mcs_required_text() . '</label>
<div class="mc-search-field' . $class . '">
<input type="text" required="required" class="widefat" value="' . esc_attr( $mcs ) . '" name="mcs" id="mcs' . $form_id . '" />
' . $expand . '
</div>
<div class="mcs-search-fields' . $expanded . '">' . $advanced;
$fields .= "</div>
<p>
<input type='submit' class='mc-button' value='" . __( 'Search Events', 'my-calendar-pro' ) . "' />
</p>
</form>
</div>";
return $fields;
}
/**
* Get data that's been used in My Calendar db.
*
* @param string $type of data to check.
*
* @return array $results
*/
function my_calendar_get_used( $type ) {
global $wpdb;
$sql = "SELECT DISTINCT $type FROM " . my_calendar_table();
return $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
}
/**
* Select users fields used in advanced search.
*
* @param string $type Authors or hosts.
* @param mixed boolean/integer $current Currently selected value.
*
* @return string
*/
function mcs_select_user( $type = 'authors', $current = false ) {
$field = ( 'authors' === $type ) ? 'event_author' : 'event_host';
$users = my_calendar_get_used( $field );
if ( 1 >= count( $users ) ) {
return '';
}
$select = '';
foreach ( $users as $u ) {
if ( 'event_author' === $field ) {
$id = $u->event_author;
} else {
$id = $u->event_host;
}
$current = ( $current ) ? $current : false;
if ( (string) $id === (string) $current ) {
$selected = ' selected="selected"';
} else {
$selected = '';
}
$user = get_user_by( 'id', $id );
if ( is_object( $user ) ) {
$display_name = ( '' === $user->display_name ) ? $user->user_nicename : $user->display_name;
} else {
if ( 0 === (int) $id ) {
$select .= "<option value='$id'$selected>" . __( 'Public Submission', 'my-calendar-pro' ) . "</option>\n";
}
continue;
}
$select .= "<option value='$id'$selected>$display_name</option>\n";
}
return $select;
}
/**
* Generate search fields
*
* @param string $field Field to produce form for.
* @param int $form_id ID of this form.
*
* @return string
*/
function mcs_generate_search_field( $field, $form_id ) {
$return = '';
$class = '';
switch ( $field ) {
case 'author':
$selected = ( isset( $_REQUEST['mc_author'] ) ) ? intval( $_REQUEST['mc_author'] ) : false;
$class = ( $selected ) ? ' has-value' : '';
$select = mcs_select_user( 'authors', $selected );
if ( '' !== $select ) {
$return = '
<p class="mc_author' . $class . '">
<label for="mc_author' . $form_id . '">' . __( 'Author', 'my-calendar-pro' ) . '</label>
<select class="widefat" name="mc_author" id="mc_author' . $form_id . '">
<option value="">' . __( 'All authors', 'my-calendar-pro' ) . '</option>
' . $select . '
</select>
</p>';
}
break;
case 'host':
$selected = ( isset( $_REQUEST['mc_host'] ) ) ? intval( $_REQUEST['mc_host'] ) : false;
$class = ( $selected ) ? ' has-value' : '';
$select = mcs_select_user( 'hosts', $selected );
if ( '' !== $select ) {
$return = '
<p class="mc_host' . $class . '">
<label for="mc_host' . $form_id . '">' . __( 'Host', 'my-calendar-pro' ) . '</label>
<select class="widefat" name="mc_host" id="mc_host' . $form_id . '">
<option value="">' . __( 'All hosts', 'my-calendar-pro' ) . '</option>
' . $select . '
</select>
</p>';
}
break;
case 'category':
// Don't render category field if only one category.
$allcats = mc_no_category_default();
if ( 1 < count( $allcats ) ) {
$selected = ( isset( $_REQUEST['mc_category'] ) ) ? intval( $_REQUEST['mc_category'] ) : false;
$class = ( $selected ) ? ' has-value' : '';
$select = mc_category_select( $selected, true, false );
$return = '
<p class="mc_category' . $class . '">
<label for="mc_category' . $form_id . '">' . __( 'Category', 'my-calendar-pro' ) . '</label>
<select class="widefat" name="mc_category" id="mc_category' . $form_id . '">
<option value="">' . __( 'All categories', 'my-calendar-pro' ) . '</option>
' . $select . '
</select>
</p>';
}
break;
case 'location':
$count = 2; // Set value to 2 to handle old installations with in-event locations.
$return = '';
if ( function_exists( 'mc_count_locations' ) ) {
$count = mc_count_locations();
}
if ( $count > 1 ) {
$selected_field = ( isset( $_REQUEST['mc_location_type'] ) ) ? esc_attr( $_REQUEST['mc_location_type'] ) : 'event_label';
$selected = ( isset( $_REQUEST['mc_location'][ $selected_field ] ) ) ? $_REQUEST['mc_location'][ $selected_field ] : false;
$class = ( $selected ) ? ' has-value' : '';
$select = mcs_location_select( $selected, $selected_field, $form_id );
$select_fields = mcs_location_field( $selected_field );
$return = '<p class="mc_location_type' . $class . '">
<label for="mc_location_type' . $form_id . '">' . __( 'Type of location search', 'my-calendar-pro' ) . '</label>
<select class="widefat" name="mc_location_type" id="mc_location_type' . $form_id . '">
' . $select_fields . '
</select>
</p>
<div class="mc_location' . $class . '">' . $select . '</div>';
}
break;
case 'date':
$sweek = absint( get_option( 'start_of_week' ) );
$firstday = ( 1 === $sweek || 0 === $sweek ) ? $sweek : 0;
$format = 'Y-m-d';
$selected = ( isset( $_REQUEST['mc_from'] ) ) ? sanitize_text_field( $_REQUEST['mc_from'] ) : current_time( $format );
$return = '
<p class="mc_from">
<label for="mcs_event_begin' . $form_id . '">' . __( 'From', 'my-calendar-pro' ) . '</label> <duet-date-picker first-day-of-week="' . $firstday . '" name="mc_from" identifier="mcs_event_begin' . $form_id . '" value="' . esc_attr( $selected ) . '" required></duet-date-picker>
</p>';
$selected = ( isset( $_REQUEST['mc_to'] ) ) ? sanitize_text_field( $_REQUEST['mc_to'] ) : mcs_date( $format, strtotime( '+ 3 months' ) );
$return .= '
<p class="mc_to">
<label for="mc_event_enddate' . $form_id . '">' . __( 'To', 'my-calendar-pro' ) . '</label> <duet-date-picker first-day-of-week="' . $firstday . '" name="mc_to" identifier="mc_event_enddate' . $form_id . '" value="' . esc_attr( $selected ) . '" required></duet-date-picker>
</p>';
$return = '<div class="mcs-date-search">' . $return . '</div>';
break;
default:
$return = '';
}
return $return;
}
/**
* Generate a complete set of controlled select fields or text fields for available fields.
*
* @param string $value currently selected value for submitted searches.
* @param string $field previously searched field type.
* @param int $form_id ID for this form.
*
* @return string HTML for all enabled location search fields
*/
function mcs_location_select( $value, $field, $form_id ) {
$options = mcs_advanced_search_options();
$label = $options['location_name_label'];
$city = $options['location_city_label'];
$state = $options['location_state_label'];
$country = $options['location_region_label'];
$postcode = $options['location_postcode_label'];
$region = $options['location_country_label'];
$label_label = '<label for="e_label">' . esc_html( $label ) . '</label> ';
$city_label = '<label for="e_city">' . esc_html( $city ) . '</label> ';
$state_label = '<label for="e_state">' . esc_html( $state ) . '</label> ';
$country_label = '<label for="e_country">' . esc_html( $country ) . '</label> ';
$postcode_label = '<label for="e_postcode">' . esc_html( $postcode ) . '</label> ';
$region_label = '<label for="e_region">' . esc_html( $region ) . '</label> ';
$labels = '';
if ( mcs_location_field_enabled( 'event_label' ) && '' !== trim( $label ) ) {
$selected = ( 'event_label' === $field || ! $field ) ? 'selected' : '';
$labels .= "<p class='location_field event_label " . $selected . "'>";
if ( mc_controlled_field( 'label' ) ) {
$labels .= $label_label . str_replace( 'location_label', 'mc_location[event_label]', mc_location_controller( 'label', $value ) );
} else {
$labels .= $label_label . '<select id="e_label" name="mc_location[event_label]">' . mc_location_select( $value ) . '</select>';
}
$labels .= '</p>';
$labels = str_replace( 'e_label', 'e_label' . $form_id, $labels );
}
if ( mcs_location_field_enabled( 'event_city' ) && '' !== trim( $city ) ) {
$selected = ( 'event_city' === $field ) ? 'selected' : '';
$labels .= "<p class='location_field event_city " . $selected . "'>";
if ( mc_controlled_field( 'city' ) ) {
$labels .= $city_label . str_replace( 'location_city', 'mc_location[event_city]', mc_location_controller( 'city', $value ) );
} else {
$labels .= $city_label . '<input id="e_city" name="mc_location[event_city]" value="' . esc_attr( $value ) . '" />';
}
$labels .= '</p>';
$labels = str_replace( 'e_city', 'e_city' . $form_id, $labels );
}
if ( mcs_location_field_enabled( 'event_state' ) && '' !== trim( $state ) ) {
$selected = ( 'event_state' === $field ) ? 'selected' : '';
$labels .= "<p class='location_field event_state " . $selected . "'>";
if ( mc_controlled_field( 'state' ) ) {
$labels .= $state_label . str_replace( 'location_state', 'mc_location[event_state]', mc_location_controller( 'state', $value ) );
} else {
$labels .= $state_label . '<input id="e_state" name="mc_location[event_state]" value="' . esc_attr( $value ) . '" />';
}
$labels .= '</p>';
$labels = str_replace( 'e_state', 'e_state' . $form_id, $labels );
}
if ( mcs_location_field_enabled( 'event_country' ) && '' !== trim( $country ) ) {
$selected = ( 'event_country' === $field ) ? 'selected' : '';
$labels .= "<p class='location_field event_country " . $selected . "'>";
if ( mc_controlled_field( 'country' ) ) {
$labels .= $country_label . str_replace( 'location_country', 'mc_location[event_country]', mc_location_controller( 'country', $value ) );
} else {
$labels .= $country_label . '<input id="e_country" name="mc_location[event_country]" value="' . esc_attr( $value ) . '" />';
}
$labels .= '</p>';
$labels = str_replace( 'e_country', 'e_country' . $form_id, $labels );
}
if ( mcs_location_field_enabled( 'event_postcode' ) && '' !== trim( $postcode ) ) {
$selected = ( 'event_postcode' === $field ) ? 'selected' : '';
$labels .= "<p class='location_field event_postcode " . $selected . "'>";
if ( mc_controlled_field( 'postcode' ) ) {
$labels .= $postcode_label . str_replace( 'location_postcode', 'mc_location[event_postcode]', mc_location_controller( 'postcode', $value ) );
} else {
$labels .= $postcode_label . '<input id="e_postcode" name="mc_location[event_postcode]" value="' . esc_attr( $value ) . '" />';
}
$labels .= '</p>';
$labels = str_replace( 'e_postcode', 'e_postcode' . $form_id, $labels );
}
if ( mcs_location_field_enabled( 'event_region' ) && '' !== trim( $region ) ) {
$selected = ( 'event_region' === $field ) ? 'selected' : '';
$labels .= "<p class='location_field event_region " . $selected . "'>";
if ( mc_controlled_field( 'region' ) ) {
$labels .= $region_label . str_replace( 'location_region', 'mc_location[event_region]', mc_location_controller( 'region', $value ) );
} else {
$labels .= $region_label . '<input id="e_region" name="mc_location[event_region]" value="' . esc_attr( $value ) . '" />';
}
$labels .= '</p>';
$labels = str_replace( 'e_region', 'e_region' . $form_id, $labels );
}
return $labels;
}
/**
* Check whether a given field has been enabled for location searches
*
* @param string $field Field name.
*
* @return boolean
*/
function mcs_location_field_enabled( $field ) {
$options = get_option( 'mcs_advanced_search' );
$fields = ( isset( $options['location_fields'] ) && is_array( $options['location_fields'] ) ) ? $options['location_fields'] : array();
$return = true;
if ( in_array( $field, array_keys( $fields ), true ) && 'true' === $fields[ $field ] ) {
$return = true;
} elseif ( in_array( $field, array_keys( $fields ), true ) && 'false' === $fields[ $field ] ) {
$return = false;
}
return $return;
}
/**
* Return list of locations field to select from
*
* @param string $selected Selected value.
*
* @return string
*/
function mcs_location_field( $selected ) {
$fields = mc_location_fields_array();
$options = '';
$settings = mcs_advanced_search_options();
$label = $settings['location_name_label'];
$city = $settings['location_city_label'];
$state = $settings['location_state_label'];
$country = $settings['location_region_label'];
$postcode = $settings['location_postcode_label'];
$region = $settings['location_country_label'];
$labels = array(
'event_label' => $label,
'event_city' => $city,
'event_state' => $state,
'event_country' => $country,
'event_postcode' => $postcode,
'event_region' => $region,
);
foreach ( $fields as $key => $field ) {
if ( mcs_location_field_enabled( $key ) ) {
$select = selected( $key, $selected, false );
$field_label = $labels[ $key ];
if ( '' !== trim( $field_label ) ) {
$options .= "<option value='$key' $select>" . esc_html( $field_label ) . '</option>';
}
}
}
return $options;
}
/**
* Fetch array of location fields available for searches
*
* @param boolean $full Default true; return full array. False to return array keys only.
*
* @return array
*/
function mc_location_fields_array( $full = true ) {
$array = array(
'event_label' => __( 'Location Name', 'my-calendar-pro' ),
'event_city' => __( 'City', 'my-calendar-pro' ),
'event_state' => __( 'State', 'my-calendar-pro' ),
'event_country' => __( 'Country', 'my-calendar-pro' ),
'event_postcode' => __( 'Postal Code', 'my-calendar-pro' ),
'event_region' => __( 'Region', 'my-calendar-pro' ),
);
/**
* Filter location fields usable as search filters.
*
* @hook mcs_location_fields
*
* @param {array} $array Array of table columns & labels that can be queried in search.
* @param {bool} $full Return entire array. False to return keys only.
*
* @return {array}
*/
$array = apply_filters( 'mcs_location_fields', $array, $full );
return ( $full ) ? $array : array_keys( $array );
}
add_filter( 'mc_search_template', 'mcs_advanced_search_template', 10, 1 );
/**
* Filter search template used in advanced search results
*
* @param string $template tagged template.
*
* @return string
*/
function mcs_advanced_search_template( $template ) {
$options = mcs_advanced_search_options();
$temp = $options['template'];
$type = mc_get_option( 'list_template', 'list' );
if ( $temp && 'list' === $type ) {
$template = $temp;
}
if ( ! $temp && 'list' === $type ) {
$template = $type;
}
return $template;
}
add_filter( 'mc_search_before', 'mcs_advanced_search_before', 10, 3 );
/**
* Insert custom header before search results.
*
* @param string $content Existing content.
* @param string $search Searched term.
* @param int $count Events found.
*
* @return string
*/
function mcs_advanced_search_before( $content, $search, $count ) {
$options = mcs_advanced_search_options();
if ( get_post( $options['home'] ) ) { // Home is the advanced search page, or an alternate page if provided by the shortcode.
$skip = mcs_skip_search_results();
$start = $skip + 1;
$end = ( $start + 20 ) - 1;
if ( $end > $count ) {
$end = $count;
}
$args = $options;
$url = get_permalink( $options['home'] );
if ( is_array( $args ) ) {
$form = mcs_search_form( $args, $url );
}
$content = "<div class='mc-event-list mc-advanced-search mc-search-results mc-submissions'>";
if ( $count > 0 ) {
// Translators: Search query. 1) number of results; 2) starting result shown; 3) end result shown; 4) search term.
$header = sprintf( _n( '%1$s search result for "%4$s"', '%2$s to %3$s of %1$s search results for "%4$s"', $count, 'my-calendar-pro' ), "<span class='mcs-total'>$count</span>", "<span class='mcs-start'>$start</span>", "<span class='mcs-end'>$end</span>", esc_html( $search ) ); // phpcs:ignore WordPress.WP.I18n.MismatchedPlaceholders, WordPress.WP.I18n.MissingSingularPlaceholder
} else {
// Translators: Search term.
$header = sprintf( __( 'No search results for "%s"', 'my-calendar-pro' ), esc_html( $search ) );
}
$content .= $form . '
<div class="mcs-advanced-search-results">
<h2 id="mcs-search-results-header">' . $header . "</h2>
<ol class='mcs-search-results mc-event-list' role='list'>";
return $content;
}
return $content;
}
add_filter( 'mc_search_after', 'mcs_advanced_search_after', 10, 2 );
/**
* Insert custom footer after search results.
*
* @param string $content Existing content. Default '</ol>'.
*
* @return string
*/
function mcs_advanced_search_after( $content ) {
$options = mcs_advanced_search_options();
if ( get_post( $options['home'] ) ) {
return str_replace( '</ol>', '', $content ) . '</ol></div></div>';
}
return $content;
}
/**
* Map keys to readable labels.
*
* @param string $key Key.
*
* @return string label.
*/
function mcs_map_label( $key ) {
switch ( $key ) {
case 'date':
$label = __( 'Dates', 'my-calendar-pro' );
break;
case 'author':
$label = __( 'Authors', 'my-calendar-pro' );
break;
case 'host':
$label = __( 'Hosts', 'my-calendar-pro' );
break;
case 'category':
$label = __( 'Categories', 'my-calendar-pro' );
break;
case 'location':
$label = __( 'Locations (by name)', 'my-calendar-pro' );
break;
default:
$label = __( 'Undefined key', 'my-calendar-pro' );
}
return $label;
}
/**
* Configure view for advanced search page.
*/
function mcs_search_view() {
$options = mcs_advanced_search_options();
$search_id = ( isset( $options['home'] ) && is_numeric( $options['home'] ) ) ? $options['home'] : '';
if ( isset( $_GET['post'] ) && $search_id === (int) $_GET['post'] ) {
add_meta_box( 'mc-search-view', __( 'My Calendar Pro: Advanced Search Options', 'my-calendar-pro' ), 'mcs_search_options', 'page', 'advanced', 'high', 'main' );
}
}
add_action( 'add_meta_boxes', 'mcs_search_view' );
/**
* Configure options for advanced search.
*/
function mcs_search_options() {
echo '<input type="hidden" name="advanced_search_settings" value="page" />';
// Correct heading hierarchy and remove submit button placeholder.
echo wp_kses( str_replace( array( 'h2', '{submit}' ), array( 'h3', '' ), mcs_advanced_search_settings( array() )['advanced_search'] ), mc_kses_elements() );
}
/**
* Save options in post editing panel.
*
* @param int $post_id Post ID.
*/
function mcs_search_options_save( $post_id ) {
$options = mcs_advanced_search_options();
if ( ! isset( $options['home'] ) ) {
return $post_id;
}
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE || wp_is_post_revision( $post_id ) || ! ( (int) $options['home'] === (int) $post_id ) ) {
return $post_id;
}
$post = map_deep( $_POST, 'wp_kses_post' );
mcs_advanced_search_update( '', $post );
}
add_action( 'save_post', 'mcs_search_options_save', 10, 1 );