Custom Search Dropdown

I’m trying to create a custom search on the items/browse page, where I have this…

<?php echo $this->partial('items/search-form-recipe.php',
    array('formAttributes' =>
        array('id'=>'advanced-search-form'))); ?>

In search-form-recipe.php I have a form, adapted from core, which just includes a keyword search and some dropdowns. The keyword search works as expected, but the dropdown is still a work in progress. Basically, I’m getting all the values for an element called “Meal Type” and allowing users to select a specific type before submitting the form.

I’m a little stuck on the first two parameters for $this->formSelect. Right now, I’m just using mealtype and that works as expected, though obviously it is not a valid Omeka search. I think I need to output something like advanced[0][element_id]=85&advanced[0][type]=is+exactly&advanced[0][terms] but that doesn’t work. I’ve also tried formatting that as a PHP array, to no avail. What am I getting wrong?

	<?php
	if(element_exists('Item Type Metadata','Meal Type')){
		// get values for Meal Type element #85
		$db = get_db();
		$elementId = 85; // is there an easy way to get this id programmatically?
		$table = $db->getTable('ElementText');
		$select = $table->getSelectForFindBy(array('element_id' => $elementId));
		$select->group('text');
		$texts = $table->fetchObjects($select);
		$options = array();
		foreach($texts as $text) {
			 $options[urlencode($text->text)] = $text->text;
		}
		array_unshift($options,'Select Meal Type');
		// needs to post as something like: advanced[0][element_id]=85&advanced[0][type]=is+exactly&advanced[0][terms]
		echo $this->formSelect(
			'mealtype',
			@$_REQUEST['mealtype'],
			array('id' => 'mealtype-search'),
			$options
		);
	}
	?>

You can’t create multiple query variables (separated by & in the URL) from a single form input: the browser will escape the “&” characters in your input name.

Instead take the static parts of the query you want to submit and make them hidden inputs on their own (you can use formHidden or just write them out):

<input type="hidden" name="advanced[0][element_id]" value="85">
<input type="hidden" name="advanced[0][type]" value="is exactly">

And then make the name for the dropdown just the dynamic part: advanced[0][terms].

Thanks, that worked, though it brings up another issue. I only want to submit those hidden inputs if something other than “All Meal Types” (value: 0) is selected below since this form also includes a keyword search. Am I just going to need to watch the form using JavaScript (i.e. adding the hidden inputs when the value changes) or is there a way to handle this in PHP?

	<?php
	if(element_exists('Item Type Metadata','Meal Type')){
		
		// I only want to submit these if something other than "All Meal Types" (value: 0) is selected below
		echo '<input type="hidden" name="advanced[0][element_id]" value="85">';
		echo '<input type="hidden" name="advanced[0][type]" value="is exactly">';
		
		// get values for Meal Type element #85
		$db = get_db();
		$elementId = 85; // is there an easy way to get this id programmatically?
		$table = $db->getTable('ElementText');
		$select = $table->getSelectForFindBy(array('element_id' => $elementId));
		$select->group('text');
		$texts = $table->fetchObjects($select);
		$options = array();
		foreach($texts as $text) {
			$options[$text->text] = $text->text;
		}
		array_unshift($options,'All Meal Types');
		echo $this->formSelect(
			'advanced[0][terms]',
			@$_REQUEST['advanced'][0]['terms'],
			array('id' => 'mealtype-search'),
			$options
		);
	}
	?>

EDIT: to clarify, the form will always post a query where field 85 is exactly 0 if the default “All Meal Types” is selected, even if the user is ignoring the dropdown and using the keyword search. I don’t suppose there is a special value to use for is exactly anything or a way to filter what gets posted so that when the value is 0, it ignores the hidden fields?

Nevermind…

	if(element_exists('Item Type Metadata','Meal Type')){
		// get values for Meal Type element #85
		$db = get_db();
		$elementId = 85; // is there an easy way to get this id programmatically?
		$table = $db->getTable('ElementText');
		$select = $table->getSelectForFindBy(array('element_id' => $elementId));
		$select->group('text');
		$texts = $table->fetchObjects($select);
		$options = array();
		foreach($texts as $text) {
			$options[$text->text] = $text->text;
		}
		array_unshift($options,'All Meal Types');
		echo $this->formSelect(
			'advanced[0][terms]',
			@$_REQUEST['advanced'][0]['terms'],
			array('id' => 'mealtype-search'),
			$options
		);
		
		if (isset($_POST['advanced[0][terms]']) && ($_POST['advanced[0][terms]'] !== 0)) {
			// Only submit these if something other than "All Meal Types" (value: 0) is selected
			echo '<input type="hidden" name="advanced[0][element_id]" value="85">';
			echo '<input type="hidden" name="advanced[0][type]" value="is exactly">';
		}
	}

Wait, no, that doesn’t work.

These are searches on different fields, right?

You could have one be the “0” indexed search “row,” one be the “1” and so on? Though I’m not sure I understand exactly how the search you’re trying to write works.

Otherwise you’re probably looking at Javascript yes, or having a plugin to accept the search query in a manner that’s simpler for your frontend.

Basically, I have three search options on the form. One is a keyword search. One allows the user to select from values in the Meal Type element. And one allows the user to select from values in the Dietary Restrictions element. The user should be able to use just one option, or two, or all three, depending on how specific they want the results to be. Basically, it’s a way to filter the results when browsing the Recipes item type.

Can you elaborate on this?

You could have one be the “0” indexed search “row,” one be the “1” and so on

Here’s the complete form:

<?php
if (!empty($formActionUri)):
	$formAttributes['action'] = $formActionUri;
else:
	$formAttributes['action'] = url(array('controller' => 'items',
										  'action' => 'browse'));
endif;
$formAttributes['method'] = 'GET';
?>

<form <?php echo tag_attributes($formAttributes); ?>>
	<?php
	// hidden: gets item type from URL
	echo $this->formSelect(
		'type',
		@$_REQUEST['type'],
		array('id' => 'item-type-search', 'hidden'=>true),
		get_table_options('ItemType')
	);
	?>
	
	<?php
	// keyword input
	echo $this->formText(
		'search',
		@$_REQUEST['search'],
		array('id' => 'keyword-search', 'placeholder'=>__('Enter a keyword'))
	);
	?>
	
	<?php
	if(element_exists('Item Type Metadata','Meal Type')){
		
		// Only submit these if something other than "All Meal Types" (value: 0) is selected
		echo '<input type="hidden" name="advanced[0][element_id]" value="85">';
		echo '<input type="hidden" name="advanced[0][type]" value="is exactly">';
		
		// get values for Meal Type element #85
		$db = get_db();
		$elementId = 85; // is there an easy way to get this id programmatically?
		$table = $db->getTable('ElementText');
		$select = $table->getSelectForFindBy(array('element_id' => $elementId));
		$select->group('text');
		$texts = $table->fetchObjects($select);
		$options = array();
		foreach($texts as $text) {
			$options[$text->text] = $text->text;
		}
		array_unshift($options,'All Meal Types');
		echo $this->formSelect(
			'advanced[0][terms]',
			@$_REQUEST['advanced'][0]['terms'],
			array('id' => 'mealtype-search'),
			$options
		);
	}
	if(element_exists('Item Type Metadata','Dietary Considerations')){
		
		// Only submit these if something other than "All Dietary Considerations" (value: 0) is selected
		echo '<input type="hidden" name="advanced[1][element_id]" value="91">';
		echo '<input type="hidden" name="advanced[1][type]" value="is exactly">';
		
		// get values for Dietary Considerations element #91
		$db = get_db();
		$elementId = 91; // is there an easy way to get this id programmatically?
		$table = $db->getTable('ElementText');
		$select = $table->getSelectForFindBy(array('element_id' => $elementId));
		$select->group('text');
		$texts = $table->fetchObjects($select);
		$options = array();
		foreach($texts as $text) {
			$options[$text->text] = $text->text;
		}
		array_unshift($options,'All Dietary Considerations');
		echo $this->formSelect(
			'advanced[1][terms]',
			@$_REQUEST['advanced'][1]['terms'],
			array('id' => 'dietaryconsiderations-search'),
			$options
		);
	}
	?>

	<input type="submit" class="submit" name="submit_search" id="submit_search_advanced" value="<?php echo __('Submit'); ?>">
</form>


For now, I’ve just added some JS to manage when the hidden inputs should be included…

<script>
let mt_hidden_container = document.querySelector("#mealtype-hidden-fields");
let mt_hidden_inputs = '<input type="hidden" name="advanced[0][element_id]" value="85">'
+'<input type="hidden" name="advanced[0][type]" value="is exactly">';
let mealtype = document.querySelector("select#mealtype-search");

// on load: meal type
if(mealtype.value !== "0"){
	mt_hidden_container.innerHTML = mt_hidden_inputs
}

// on change: meal type
mealtype.addEventListener("change", (e) => {
  if(mealtype.value !== "0"){
	  mt_hidden_container.innerHTML = mt_hidden_inputs
  }else{
	  mt_hidden_container.innerHTML = ''
  }
});

let dc_hidden_container = document.querySelector("#dietaryconsiderations-hidden-fields");
let dc_hidden_inputs = '<input type="hidden" name="advanced[1][element_id]" value="91">'
+'<input type="hidden" name="advanced[1][type]" value="is exactly">';
let dietaryconsiderations = document.querySelector("select#dietaryconsiderations-search");

// on load: dietary
if(dietaryconsiderations.value !== "0"){
	dc_hidden_container.innerHTML = dc_hidden_inputs
}

// on change: dietary
dietaryconsiderations.addEventListener("change", (e) => {
	if(dietaryconsiderations.value !== "0"){
	  	dc_hidden_container.innerHTML = dc_hidden_inputs
  	}else{
	  	dc_hidden_container.innerHTML = ''
  	}
});
</script>

I just meant advanced[0] vs advanced[1], etc.

The problem really I guess is just that once those hidden inputs are in there, we’re doing the search even with an empty-string search text. So the JS solution is probably the best thing short of getting into a plugin.

1 Like

This topic was automatically closed 250 days after the last reply. New replies are no longer allowed.