5

I am trying to use PathMatcher::matchPath() to match a string of paths using a wildcard pattern.

I'd like to match any path containing /topic* so if the path matches, I'd like to add a body class for pages that have /topic, /topic/foo, /topic/bar, etc..

The code I am using is the following.

function mytheme_preprocess_html(array &$vars) {
  // Define the current path.
  $current_path = \Drupal::service('path.current')->getPath();
  // Define the pattern using a string.
  $patterns = "/topic/*";
  // If the path matches the pattern.
  if (\Drupal::service('path.matcher')->matchPath($current_path, $patterns)) {
    $vars['attributes']['class'][] = 'is-topic';
  }
}

The code doesn't work to match this pattern so no class is added when I am on any of these pages.

My Xdebug info is as follows for the page that has the path topic/review-procedures

$current_path = /node/62
$path_alias = topic/review-procedures

Note that some pages with /topic/ in the path will not be nodes however, that is why I am trying to do the path matching.

Am I correctly using PathMatcher::matchPath()?

8
  • 1
    doesn't work is a broad statement. What exactly doesn't work as expected? How you are calling matchPath() is how Drupal core calls that method, and how the example in the documentation page does.
    – avpaderno
    Commented Apr 14, 2020 at 12:48
  • Updated summary as to why it does not work. Commented Apr 14, 2020 at 12:53
  • 1
    It looks a bit as if matchPath maybe is only looking at internal paths or route names? What does \Drupal::service('path.current')->getPath() return you? Install the Devel submodule Kint and tell us what ksm(\Drupal::service('path.current')->getPath()); inside that preprocess function returns you on the screen when visiting a relevant path. Is topic a node type for itself? Then you could check the route parameter to get the node, from there you have the type and can add a body class.
    – leymannx
    Commented Apr 14, 2020 at 13:02
  • 2
    It's pretty much what @leymannx said - the path.current service gets you the raw, un-aliased path , whereas you need to be matching against the alias
    – Clive
    Commented Apr 14, 2020 at 13:24
  • 3
    You'll need to do both - look for a node object in the current route parameters, if you find one test against the URL alias (if it's still even required after testing the content type etc). Once you've eliminated that possibility, check against the current system path if you still need to. You may also need to add a url.path cache context, but being at the top level of html.html.twig it might already be covered
    – Clive
    Commented Apr 14, 2020 at 13:27

1 Answer 1

5

In your sample you were comparing the internal path (/node/123) with a path alias pattern (/topic/*). This won't work. You need to do the matching with the path alias instead.

/**
 * Implements template_preprocess_html().
 */
function MYTHEME_preprocess_html(&$variables) {
  $current_path = \Drupal::service('path.current')->getPath();
  $current_alias = \Drupal::service('path.alias_manager')->getAliasByPath($current_path);
  if (\Drupal::service('path.matcher')->matchPath($current_alias, '/topic/*')) {
    $variables['attributes']['class'][] = 'is-topic';
  }
}

You could achieve the same by exploding the current request URI and then see if the first key is topic.

/**
 * Implements template_preprocess_html().
 */
function MYTHEME_preprocess_html(&$variables) {
  $request_uri = ltrim(\Drupal::request()->getRequestUri(), '/');
  $args = explode('/', $request_uri);
  if (isset($args[0]) && $args[0] === 'topic') {
    $variables['attributes']['class'][] = 'is-topic';
  }
}
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.