On a search view, linked to search api and facets, I want to add contextual filters on my content type.
This content type have referenced entity fields, linked to taxonomy term (one field to taxonomy from destination vocabulary, the other to taxonomy from activity vocabulary)
So, I have created 2 contexual filter, one for each "taxonomy field".
view
filter
But, I appears only the first filter (destination) is applied. If my taxonomy term from URL is a destination, the view displays right results. But if it's an activity, it display all contents. So I supposed there is a problem with contextual filter validator : 'Action to take if filter value does not validate' should have something like 'Ignore filter' option, because with 'Display all results for the specified field', its shows everything, but don't execute next filter.
Anyone has a solution ?
Thanks a lot
Finally, I found a solution, just altering view in pre_build
/**
* Implements hook_views_pre_build().
*/
function my_module_views_pre_build(ViewExecutable $view)
{
if ($view->id() == 'tour_search' && $view->current_display == 'tours_taxonomy') {
$tid = reset($view->args);
if (! $tid) {
return;
}
/** #var Term $term */
$term = Term::load($tid);
if ($term->getVocabularyId() === 'activities') {
unset($view->argument['field_tour_destination']);
return;
}
if ($term->getVocabularyId() === 'destinations') {
unset($view->argument['field_tour_activity']);
return;
}
return;
}
}
I moved validation logic in this hook, by unsetting filter in with a simple term vocabulary test.
Hope it will helps somebody !
Related
I’ve developed a new theme for a website, but i seem to have a problem related to widget Filter By Attribute.
When i use the filter, that comes with the gutenberg block editor for widgets, the filter attribute widget doesn’t filter anything. (i guess it uses ajax to filter, but its not filtering anything)
When i use the add_filter('use_widgets_block_editor', '__return_false'); to remove the gutenberg and use a new filter by attribute (which is a different widget, than the one that comes with Gutenberg), the widget works, because it filters the query by passing some params on the url, but has a problem. It shows variations that are out of stock, which is something that have been fixed with the new widget, using the product lookup tables, and it's exactly what i'm trying to achieve here.
I strongly believe this is related to the AJAX call it uses to filter the shop page, so i guess i'm missing an ID or Class, to the product wrapper or something.
Does anyone also had this problem?
If you want to see the page in question, is this one https://www.hiima-store.com/bch/shop/
When you go into Filters, you can see both widgets there. (there are two for sizes. the first one uses query params and the second one, is the one that is not filtering).
I did a custom script regarding that.
It might help someone with the same problem.
It will hide the product if the variation is out of stock.
add_action('woocommerce_before_shop_loop_item_title', 'out_of_stock_variations_loop');
function out_of_stock_variations_loop()
{
global $product;
if (isset($_GET["filter_size"])) { // check if the attribute is in the url
if ($product->product_type == 'variable') {
$available = $product->get_available_variations();
if ($available) foreach ($available as $instockvar) {
if (isset($instockvar['attributes']['attribute_pa_' . __('size', 'hiima')])) {
var_dump('entrei');
if (($instockvar['attributes']['attribute_pa_.' . __('size', 'hiima')] == $_GET['filter_size']) && (!$instockvar['max_qty'] > 0)) {
global $product;
$id = $product->get_id();
echo "<style>.post-$id{display: none}</style>";
}
}
}
}
if (!$product->is_in_stock()) {
global $product;
$id = $product->get_id();
echo "<style>.post-$id{display: none}</style>";
}
}
}
In a Drupal 8 site, I have a taxonomy page with a view block on it. The view lists articles tagged with the term of the page you are on. It also shows articles tagged with the child terms of the current taxonomy page.
I am using the exposed filter "Content: Has taxonomy terms (with depth) (exposed)" to let a user filter the articles based on the child terms. Currently that filter shows all of the terms regardless of which taxonomy you are currently on.
Here is an example of the items listed in the exposed filter:
Mammals
- Cat
- Dog
Reptiles
- Lizard
- Snake
Amphibians
- Frog
- Salamander
The URL for one of the parent terms would be:
site.com/animal/mammals
I need to limit the list of options within the exposed filter to only show the children of the term based on the URL. So on the URL above, only Cat and Dog would be listed in the exposed filter.
In Drupal 7 I could accomplish this with a hook_form_alter in my theme.module using the URL arg(2) to get the term name. I cannot find any documentation on how to do this in Drupal 8.
Here is what I have found so far:
function myTheme_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
if ($form_id == 'views_exposed_form' && $form['#id'] == 'views-exposed-form-article-tags-block-1') {
$term = arg(2);
//Need D8 code to load term, find it's children and alter the select box to show those children
}
}
I am open to other options if this is not the way to accomplish my goal. Thank you in advance.
hook_form_alter will still work, though arg() is removed in Drupal 8.
It is not clear to me what the general replacement for arg() is. The code below uses two techniques to get the taxonomy term id.
You probably want to turn caching off in the view during development.
function myTheme_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
if ($form_id == 'views_exposed_form' && $form['#id'] == 'views-exposed-form-article-tags-block-1') {
// initial page load
$parameters = \Drupal::routeMatch()->getRawParameters();
$this_term_id = $parameters->get('taxonomy_term');
// ajax refresh via apply button
if (!isset($this_term_id)) {
$this_term_id = $_REQUEST['view_args'];
}
// get children of $this_term_id
$tree = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree('tags', $parent = $this_term_id, $max_depth = NULL, $load_entities = FALSE);
// get rid of all options except default
$all_option = $form['term_node_tid_depth']['#options']['All'];
unset($form['term_node_tid_depth']['#options']);
$form['term_node_tid_depth']['#options']['All'] = $all_option;
// add child terms
foreach ($tree as $term) {
$option = new stdClass();
$option->option[$term->tid]=$term->name;
$form['term_node_tid_depth']['#options'][] = $option;
}
}
}
I'm trying to allow users to update head titles and meta descriptions for each page. I thought that an easy way to achieve this would be to add a field to the 'Basic page' content type for the page title, then check if that field is not empty in html.tpl.php and if it is not, override $head_title with this user-defined value.
However, it appears that the $node variable is not available in html.tpl.php. Can anyone suggest a way for me to make this data available in this template file, or alternatively, alter $head_title before it is sent to html.tpl.php? Thanks for reading.
Taken in part from this thread that I found: http://drupal.org/node/1041768...
In your template.php, you can do the following:
function yourtheme_preprocess_html(&$variables) {
// If on an individual node page, add the node type to body classes.
if ($node = menu_get_object()) {
$variables['head_title'] = $node-> // find your cck field here
}
}
Bit messy, but would work:
if(arg(0) == 'node' && !empty(arg(1))) {
$node = node_load(arg(1));
}
However, you might prefer http://drupal.org/project/metatags_quick (an interrim module until the full http://drupal.org/project/metatags is finished).
Using Drupal 6.x I have created two content types: Person and Event. Event has a custom field called Attendees (of type: Node Reference; unlimited number of values to person). When viewing a specific person how does one show all their events?
I have created a view (Personal Events) and added a block display. I enabled the block to show for content type Person. How should the view be defined? Or is there a better way?
Modules installed: CCK; Node Relationships; Views
I think one of these modules might be of help to you:
Reverse Node Reference
NodeReferrer
I have an answer to my own question. However, there maybe better answers... I can only hope.
Created content block (Personal Events)
Added this code to the body of the block. This code passes the node id argument to a view
<?php
if ( arg(0) == 'node' && is_numeric(arg(1)) && ! arg(2) ) {
$node = node_load(arg(1));
$args = array($node->nid );
$view = views_get_view('PersonalEvents');
print $view->preview('default', $args);
}
?>
Added this code to the Pages of the block [by selecting: Show if the following PHP code returns TRUE (PHP-mode, experts only)]... this drives the block to only appear person content.
<?php
//Read URL
$path=$_GET['q'];
//If URL is node page
if ( strpos($path,'node')===0){
//Parse URL to get nid
$links=explode("/",$_GET['q']);
$nid=$links[1];
//Load node
$node=node_load($nid);
//Display block only if node is of certain content type
if($node->type=='person'){
return TRUE;
}
}
return FALSE;
?>
Then created view with:
Style: Table
Relationship Content: Attendees (field_attendees); requires this relationship (checked); and Delta set to ALL.
Argument: Node: Nid; Relationship: Attendees; Hide view / Page not found (404) [selected]
Fields... simply selected Node Title and Date (for now)
Filter: Node Type = Event
Anyone have a better way?
For example, in the registration form, there is "Username" and the text field for it which has the input type="text" name="name" ....
I need to know how can I get the title from the input field's name.
I'm expecting a function like:
$title = get_title_for_element('name');
Result:
assert($title == 'Username'); // is true
Is there something like this in Drupal?
Thanks.
You have the form and the form state variables available to your validation function. You should use form_set_error() to set the error.
There is no function that I am aware of which will map from the values array to the form array. But it is not dificult to work it out. Understanding the form data structure is one of the key skills you need when building drupal.
In this case the form in question is generated (in a roundabout way) by user_edit_form, you can see the data structure in there.
$form['account']['name'] is the username field. and the array key for the title is '#title' as it will be in most cases for form elements.
You can do it in two different ways as I see it. Let's create a module called mycustomvalidation.module (remember to create the mycustomvalidation.info file also).
Note: The code below has not been tested, so you might have to do some minor adjustments. This is Drupal 6.x code by the way.
1) Using hook_user()
What you need is a custom module containing your own implementation of hook_user() http://api.drupal.org/api/function/hook_user/6.
<?php
function mycustomvalidation_user($op, &$edit, &$account, $category = NULL) {
if ($op == 'validate') {
// Checking for an empty 'profile_fullname' field here, but you should adjust it to your needs.
if ($edit['profile_fullname'] != '') {
form_set_error('profile_fullname', t("Field 'Fullname' must not be empty."));
}
}
}
?>
2) Using form_alter() and a custom validation function
Personally, I would go for this option because I find it cleaner and more "correct". We're adding a custom validation function to our profile field here.
<?php
function mycustomvalidation_form_alter(&$form, $form_state, $form_id) {
// Check if we are loading 'user_register' or 'user_edit' forms.
if ($form_id == 'user_register' || $form_id == 'user_edit') {
// Add a custom validation function to the element.
$form['User information']['profile_fullname']['#element_validate'] = array('mycustomvalidation_profile_fullname_validate');
}
}
function mycustomvalidation_profile_fullname_validate($field) {
// Checking for an empty 'profile_fullname' field here, but you should adjust it to your needs.
if ($field['#value'] != '') {
form_set_error('profile_fullname', t("Field %title must not be empty.", array('%title' => $field['#title']));
}
}
?>