diff --git a/src/Plugin/facets/url_processor/FacetsPrettyPathsUrlProcessor.php b/src/Plugin/facets/url_processor/FacetsPrettyPathsUrlProcessor.php index 4273b4d..d345930 100644 --- a/src/Plugin/facets/url_processor/FacetsPrettyPathsUrlProcessor.php +++ b/src/Plugin/facets/url_processor/FacetsPrettyPathsUrlProcessor.php @@ -5,12 +5,15 @@ namespace Drupal\facets_pretty_paths\Plugin\facets\url_processor; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\Routing\RouteProviderInterface; use Drupal\Core\Url; use Drupal\facets\Entity\Facet; use Drupal\facets\FacetInterface; use Drupal\facets\UrlProcessor\UrlProcessorPluginBase; use Drupal\facets_pretty_paths\PrettyPathsActiveFilters; +use Drupal\views\ViewExecutable; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; /** @@ -31,6 +34,13 @@ class FacetsPrettyPathsUrlProcessor extends UrlProcessorPluginBase implements Co */ protected $routeMatch; + /** + * The router.route_provider service. + * + * @var \Drupal\Core\Routing\RouteProviderInterface + */ + protected $routeProvider; + /** * The service responsible for determining the active filters. * @@ -58,9 +68,10 @@ class FacetsPrettyPathsUrlProcessor extends UrlProcessorPluginBase implements Co * * @throws \Drupal\facets\Exception\InvalidProcessorException */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, Request $request, EntityTypeManagerInterface $entity_type_manager, RouteMatchInterface $routeMatch, PrettyPathsActiveFilters $activeFilters) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, Request $request, EntityTypeManagerInterface $entity_type_manager, RouteMatchInterface $routeMatch, PrettyPathsActiveFilters $activeFilters, RouteProviderInterface $routeProvider) { parent::__construct($configuration, $plugin_id, $plugin_definition, $request, $entity_type_manager); $this->routeMatch = $routeMatch; + $this->routeProvider = $routeProvider; $this->activeFiltersService = $activeFilters; $this->initializeActiveFilters(); } @@ -76,7 +87,8 @@ class FacetsPrettyPathsUrlProcessor extends UrlProcessorPluginBase implements Co $container->get('request_stack')->getMasterRequest(), $container->get('entity_type.manager'), $container->get('current_route_match'), - $container->get('facets_pretty_paths.active_filters') + $container->get('facets_pretty_paths.active_filters'), + $container->get('router.route_provider') ); } @@ -162,7 +174,42 @@ class FacetsPrettyPathsUrlProcessor extends UrlProcessorPluginBase implements Co } $pretty_paths_presort_data = $this->sortByWeightAndName($pretty_paths_presort_data); $pretty_paths_string = implode('', array_column($pretty_paths_presort_data, 'pretty_path_alias')); - $url = Url::fromUri('internal:' . $facet->getFacetSource()->getPath() . $pretty_paths_string); + + $facetSourcePlugin = $facet->getFacetSource(); + + if (is_callable([$facetSourcePlugin, 'getViewsDisplay']) && $view = $facetSourcePlugin->getViewsDisplay()) { + /* @var ViewExecutable $view */ + + // We need the base path, with contextual filters replaced, but without + // any of the facets pretty paths filters. To do this, get the route + // name for the facet source and all route parameters for the current + // route, remove any parameters that are not part of the route definition + // and regenerate the path + $routeName = $view->getUrl()->getRouteName(); + + $route = $this->routeProvider->getRouteByName($routeName); + $routeArgs = array_values($route->getOption('_view_argument_map')); + + // clone the ParameterBag to avoid messing with the original request + // in case other parts of the request need the original + /* @var ParameterBag $parameters */ + $parameters = clone $this->routeMatch->getRawParameters(); + + // iterate the params and remove any that are not part of the original + // route definition for the view + foreach($parameters as $key => $val){ + if(!in_array($key, $routeArgs)){ + $parameters->remove($key); + } + } + + $path = Url::fromRoute($routeName, $parameters->all())->toString(); + } + else { + $path = $facetSourcePlugin->getPath(); + } + + $url = Url::fromUri('internal:' . $path . $pretty_paths_string); $url->setOption('attributes', ['rel' => 'nofollow']); // First get the current list of get parameters. diff --git a/src/RouteSubscriber.php b/src/RouteSubscriber.php index 4e5e1c8..fa561e7 100644 --- a/src/RouteSubscriber.php +++ b/src/RouteSubscriber.php @@ -36,7 +36,6 @@ class RouteSubscriber extends RouteSubscriberBase { $sources = $this->facetSourcePluginManager->getDefinitions(); foreach ($sources as $source) { $sourcePlugin = $this->facetSourcePluginManager->createInstance($source['id']); - $path = $sourcePlugin->getPath(); $storage = \Drupal::entityTypeManager()->getStorage('facets_facet_source'); $source_id = str_replace(':', '__', $sourcePlugin->getPluginId()); @@ -49,8 +48,19 @@ class RouteSubscriber extends RouteSubscriberBase { } try { - $url = Url::fromUri('internal:' . $path); - $sourceRoute = $collection->get($url->getRouteName()); + // We need to get to route object for the facet source so we can add + // our own slug at the end. If the facet source is based on views, we + // can retrieve the route object directly. Otherwise, try to determine + // the route based on the path. + if (is_callable([$sourcePlugin, 'getViewsDisplay']) && $view = $sourcePlugin->getViewsDisplay()) { + /* @var \Drupal\views\ViewExecutable $view */ + $sourceRoute = $collection->get($view->getUrl()->getRouteName()); + } + else { + $path = $sourcePlugin->getPath(); + $url = Url::fromUri('internal:' . $path); + $sourceRoute = $collection->get($url->getRouteName()); + } // Ensure this only triggers once per route. // See https://www.drupal.org/project/facets_pretty_paths/issues/2984105