One of my client works with an SEO agency and they ask me to remove the pagination parameter ?page=x (generated by the Views module) and rewrite it like this:





Is there a way to do it with Drupal? I don't see any option in the view or in Pathauto to do this.

Is it possible to handle this with a custom module or should I work with .htaccess file?

I've tried the Clean Pagination module but you have to manually set pages where clean pagination should work and the module doesn't seem to work properly.


1 Answer 1


You should write a PathProcessor that implements:

  • Drupal\Core\PathProcessor\InboundPathProcessorInterface
  • Drupal\Core\PathProcessor\OutboundPathProcessorInterface


file: modules/custom/mymodule/src/PathProcessor/MymodulePathProcessor.php

namespace Drupal\mymodule\PathProcessor;

use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Drupal\Core\Render\BubbleableMetadata;

class MymodulePathProcessor implements InboundPathProcessorInterface, OutboundPathProcessorInterface {

  public function processInbound($path, Request $request) {
    if (strpos($path, '/my-page-') !== 0) {
       return $path;
    $page =  preg_replace("/^\/my-page-(\d+)/", '$1', $path);
      if (ctype_digit($page)) {
        \Drupal::request()->query->set('page', $page);
        return "/my-page";
    else {
      \Drupal::request()->query->set('page', 0);
      return "/my-page";
    return $path;

  public function processOutbound($path, &$options = [], Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
    if ($path === '/my-page' && isset($options['query']['page'])) {
      $page = $options['query']['page'];
      return '/my-page-' . $page;
    return $path;


file: modules/custom/mymodule/mymodule.services.yml

    class: Drupal\mymodule\PathProcessor\MymodulePathProcessor
    - { name: path_processor_outbound}
    - { name: path_processor_inbound}

We also need to do a custom alteration to the pager. For the full pager the links are not created as the usual link render elements, so they don't go through the processOutboud, instead the twig file (classy/templates/navigation/pager.html.twig) uses a custom format. The next hook function does the adjustment.

file: modules/custom/mymodule/mymodule.module

 * Implements hook_preprocess_HOOK().
 * Implements hook_preprocess_pager().
 * @param $variables
function mymodule_preprocess_pager(&$variables) {
  $current_path = \Drupal::service('path.current')->getPath();
  if ($current_path === '/my-page')
  foreach ($variables['items']['pages'] as &$page_link) {
    $page =  preg_replace("/^\?page=(\d+)/", '$1', $page_link['href']);
    $page_link['href'] = 'my-page-' . $page;
  • Since your answer was upvoted multiple times, I guess the solution is here. But when I try it, I have this error : Symfony\Component\HttpKernel\Exception\NotFoundHttpException: No route found for "GET /my-page" in Symfony\Component\HttpKernel\EventListener\RouterListener->onKernelRequest() Do you have any suggestions ? Commented Sep 13, 2018 at 12:29
  • I just updated the code, turns out you can't just pass the page parameter in the $path. You have to add it to the Request object like this: \Drupal::request()->query->set('page', $page); Commented Sep 13, 2018 at 20:18
  • Thank you for taking the time to study this question. Did you test your module or is it untested code ? I’ve tested it, I have no more No route found error but it doesn’t rewrite the url. If it is working for you, I’m doing something wrong, that’s why I ask. Commented Sep 16, 2018 at 20:03
  • You are welcome! I did test it... Commented Sep 16, 2018 at 21:42
  • 3
    Yes, I’ve tested your updated code but I still have some issue (I test it on a clean new Drupal 8 install). For testing, I create a View that list content type article and set pagination. The URL are rewritten but content is not updated and there are issue with next/prev button. Be sure ì will mark your answer as correct when I will be able to make it work. Commented Sep 30, 2018 at 9:06

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.