Source: my-calendar-advanced-search.php

<?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 );