Score:3

String substitution in Views Contextual filter parameter?

nr flag

In Drupal 9, I have a View called News.

The View is displayed at the following path:

/news

I can edit it at the following path:

/admin/structure/views/view/news/edit

It has the following Contextual filter:

Content datasource: Content type

The contextual filter values are provided by the URL.

When the filter value is NOT in the URL: Provide default value

Type: Fixed

Fixed value: all

Exception value: all

If this value is received, the filter will be ignored; i.e, "all values"

This works well for content types like article and blog_post.

When the View is displayed for the path /news/article, the contextual filter shows only Content type article.

When the View is displayed for the path /news/blog_post, the contextual filter shows only Content type blog_post.

So far, so good.

Now, the client has a custom content type called "Youtube Video" with machine name youtube_video.

When this View is displayed for the path /news/youtube_video. the contextual filter shows only Content type youtube_video.

But the client wants the path to be /news/video.

What are my options?

Some constraints:

  • The client definitely wants the path to be /news/video, and not something like /news?type=video.
  • I don't think that it's trivial to match /news/foo and substitute bar for foo as the input for a contextual filter.
  • I know how to use positional parameters in a route, but I don't think I can easily override the route for just /news/foo while preserving the contextual filter as it is for the other content types.

Some flexibility:

  • The Drupal 9 site is brand new, and I'm about to migrate the content from Drupal 7 via Migrate API, so it's possible to change the machine name of the youtube_video content type to video during the migration. Then this View would work without modification. (The problem would be figuring out everything else that references the machine name youtube_video and changing that to video also -- potentially a lot of effort.)
  • It may be possible to alter the query parameters conditionally using hook_views_pre_view() or hook_views_query_alter(), but I only want to do this if a specific parameter is matched.
Score:3
gf flag

Would hook_views_pre_view() do the trick?

function hook_views_pre_view(ViewExecutable $view, $display_id, array &$args) {
  if ($view->id() == 'my_view' &&
    $display_id == 'my_display' &&
    $args[0] == 'news' &&
    $args[1] == 'video') {
    $args[1] = 'youtube_video';
  }
}

Replace my_view and my_display with the appropriate values.

hotwebmatter avatar
nr flag
Thanks @uberhacker. I accepted your answer, which basically set me on the right path.
Score:1
nr flag

Here's my first working proof-of-concept based on the answer above:

/**
 * Implements hook_view_pre_view().
 */
function my_module_views_pre_view(ViewExecutable $view, $display_id, array &$args) {
  if ($view->id() == 'news' && isset($args[0])) {
    if ($args[0] == 'video') {
      $args[0] = 'youtube_video';
    }
  }
}

The first arg in the path /news/video actually just calls the View with $view_id = 'news', so the contextual filter parameters don't start until the second segment in that path, which is $arg[0].

And it's important to check that $arg[0] is set before checking its value; otherwise, the /news path will throw errors when no filters are passed.

Finally, in my case there's no need to check for a specific $display_id, since I want the string substitution to occur for all displays of this particular View.

Other than that, the answer above got it just right.

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.