Use Routing to rewrite URLs

This section will show you how you can rewrite the URLs for news using Routing Enhancers and Aspects. TYPO3 Explained has a chapter Introduction to routing that you can read if you are not familiar with the concept yet. You will no longer need third party extensions like RealURL or CoolUri to rewrite and beautify your URLs.

Quick start

This section explains in short how to rewrite the URLs for the detail page in a project where there is only one detail view page on the whole site and where rewriting of things like pagination is not desired or needed.

Open the configuration of the site. You should find it at /config/sites/<your_identifier>/config.yaml.

At the bottom of the file include the following:

/config/sites/<your_identifier>/config.yaml
routeEnhancers:
  News:
    type: Extbase
    limitToPages:
      - <uid of single page>
    extension: News
    plugin: Pi1
    routes:
      - routePath: '/{news-title}'
        _controller: 'News::detail'
        _arguments:
          news-title: news
    aspects:
      news-title:
        type: NewsTitle
Copied!

Save the file, delete all caches and try it out

Troubleshooting

  • Did you save the site configuration file?
  • Did you delete all caches?
  • In the format YAML indentation matters. The code above must be indentated exactly as shown, the keyword routeEnhancers must not be indeted.
  • The configuration above is limited to only one page containing a single view of news. Did you put the correct pid of page containing the news plugin displaying single news?

Detailed explaination and advanced use cases

How to rewrite URLs with news parameters

On setting up your page you should already have created a site configuration. You can do this in the backend module Site Managements > Sites.

Your site configuration will be stored in /config/sites/<your_identifier>/config.yaml. The following configurations have to be applied to this file.

Any URL parameters can be rewritten with the Routing Enhancers and Aspects. These are added manually in the config.yaml:

  1. Add a section routeEnhancers, if one does not already exist.
  2. Choose an unique identifier for your Routing Enhancer. It doesn't have to match any extension key.
  3. type: For news, the Extbase Plugin Enhancer (Extbase) is used.
  4. extension: the extension key, converted to UpperCamelCase.
  5. plugin: the plugin name of news is just Pi1.
  6. After that you will configure individual routes and aspects depending on your use case.
/config/sites/<your_identifier>/config.yaml
routeEnhancers:
  News:
    type: Extbase
    extension: News
    plugin: Pi1
    # routes and aspects will follow here
Copied!

Using limitToPages

It is recommended to limit routeEnhancers to the pages where they are needed. This will speed up performance for building page routes of all other pages.

/config/sites/<your_identifier>/config.yaml
routeEnhancers:
  News:
    type: Extbase
    limitToPages:
      - 8
      - 10
      - 11
    extension: News
    plugin: Pi1
    # routes and aspects will follow here
Copied!

Multiple routeEnhancers for news

If you use the news extension for different purposes on the same website (for example news and events), you may want different URL paths for them (for example /article/ and /event/). It is possible to configure more than one routing enhancer for the news plugin on the same website.

Use limitToPages to assign the appropriate configuration to the desired pages.

/config/sites/<your_identifier>/config.yaml
routeEnhancers:
  News:
    type: Extbase
    limitToPages:
      - 8
      - 10
      - 11
    extension: News
    plugin: Pi1
    # etc.
  NewsEvents:
    type: Extbase
    limitToPages:
      - 17
      - 18
    extension: News
    plugin: Pi1
    # etc.
Copied!

About routes and aspects

In a nutshell:

  • routes will extend an existing route (means: your domain and page
    path) with arguments from GET parameters, like the following controller/action pair of the news detail view.
  • aspects can be used to modify these arguments. You could for
    example map the title (or better: the optimized path segment) of the current news. Different types of Mappers and Modifiers are available, depending on the case.
  1. URL of detail page without routing:
https://www.example.com/news/detail?tx_news_pi1[action]=detail&tx_news_pi1[controller]=News&tx_news_pi1[news]=5&cHash=
Copied!
  1. URL of detail page with routes:
https://www.example.com/news/detail/5?cHash=
Copied!
  1. URL of detail page with routes and aspects:
https://www.example.com/news/detail/title-of-news-article
Copied!

The following example will only provide routing for the detail view:

/config/sites/<your_identifier>/config.yaml
routeEnhancers:
  News:
    type: Extbase
    extension: News
    plugin: Pi1
    routes:
      - routePath: '/{news-title}'
        _controller: 'News::detail'
        _arguments:
          news-title: news
    aspects:
      news-title:
        type: NewsTitle
Copied!

Please note the placeholder {news-title}:

  1. First, you assign the value of the news parameter (tx_news_pi1[news]) in _arguments.
  2. Next, in routePath you add it to the existing route.
  3. Last, you use aspects to map the path_segment of the given argument.

Both routes and aspects are only available within the current Routing Enhancer.

The names of placeholders are freely selectable.

Common routeEnhancer configurations

Basic setup (including categories, tags and the RSS/Atom feed)

Prerequisites:

The plugins for List View and Detail View are on separate pages.

If you use the Category Menu or Tag List plugins to filter news records, their titles (slugs) are used.

Result:

  • Detail view: https://www.example.com/news/detail/the-news-title
  • Pagination: https://www.example.com/news/page-2
  • Category filter: https://www.example.com/news/my-category
  • Tag filter: https://www.example.com/news/my-tag
/config/sites/<your_identifier>/config.yaml
routeEnhancers:
  News:
    type: Extbase
    extension: News
    plugin: Pi1
    routes:
      - routePath: '/'
        _controller: 'News::list'
      - routePath: '/page-{page}'
        _controller: 'News::list'
        _arguments:
          page: 'currentPage'
      - routePath: '/{news-title}'
        _controller: 'News::detail'
        _arguments:
          news-title: news
      - routePath: '/{category-name}'
        _controller: 'News::list'
        _arguments:
          category-name: overwriteDemand/categories
      - routePath: '/{tag-name}'
        _controller: 'News::list'
        _arguments:
          tag-name: overwriteDemand/tags
    defaultController: 'News::list'
    defaults:
      page: '0'
    aspects:
      news-title:
        type: NewsTitle
      page:
        type: StaticRangeMapper
        start: '1'
        end: '100'
      category-name:
        type: NewsCategory
      tag-name:
        type: NewsTag
  PageTypeSuffix:
    type: PageType
    map:
      'feed.xml': 9818
      'calendar.ical': 9819
Copied!

Localized pagination

Prerequisites:

The website provides several frontend languages.

Result:

  • English: https://www.example.com/news/page-2
  • Danish: https://www.example.com/da/news/side-2
  • German: https://www.example.com/de/news/seite-2
/config/sites/<your_identifier>/config.yaml
routeEnhancers:
  News:
    type: Extbase
    extension: News
    plugin: Pi1
    routes:
      - routePath: '/{page-label}-{page}'
        _controller: 'News::list'
        _arguments: {'page': 'currentPage'}
    defaultController: 'News::list'
    defaults:
      page: ''
    requirements:
      page: '\d+'
    aspects:
      page:
        type: StaticRangeMapper
        start: '1'
        end: '100'
      page-label:
        type: LocaleModifier
        default: 'page'
        localeMap:
          - locale: 'da_DK.*'
            value: 'side'
          - locale: 'de_DE.*'
            value: 'seite'
Copied!

Explanation:

The LocaleModifier aspect type will set a default value for the English language. You're then able to add as many localeMap configurations as you need for the page translations of your website. The value of locale refers to the value in your site configuration.

Human readable dates

Prerequisites:

For List View with a Date Menu plugin, to filter by date. Also includes configuration for the pagination.

Result:

  • https://www.example.com/news/2018/march
  • https://www.example.com/news/2018/march/page-2
/config/sites/<your_identifier>/config.yaml
routeEnhancers:
  DateMenu:
    type: Extbase
    extension: News
    plugin: Pi1
    routes:
      # Pagination:
      - routePath: '/'
        _controller: 'News::list'
      - routePath: '/page-{page}'
        _controller: 'News::list'
        _arguments:
          page: 'currentPage'
      - routePath: '/{news-title}'
        _controller: 'News::detail'
        _arguments:
          news-title: news
      # Date year:
      - routePath: '/{date-year}'
        _controller: 'News::list'
        _arguments:
          date-month: 'overwriteDemand/month'
          date-year: 'overwriteDemand/year'
          page: 'currentPage'
      # Date year + pagination:
      - routePath: '/{date-year}/page-{page}'
        _controller: 'News::list'
        _arguments:
          date-year: 'overwriteDemand/year'
          page: 'currentPage'
      # Date year/month:
      - routePath: '/{date-year}/{date-month}'
        _controller: 'News::list'
        _arguments:
          date-month: 'overwriteDemand/month'
          date-year: 'overwriteDemand/year'
          page: 'currentPage'
       # Date year/month + pagination:
      - routePath: '/{date-year}/{date-month}/page-{page}'
        _controller: 'News::list'
        _arguments:
          date-month: 'overwriteDemand/month'
          date-year: 'overwriteDemand/year'
          page: 'currentPage'
    defaultController: 'News::list'
    defaults:
      page: '0'
      date-month: ''
      date-year: ''
    requirements:
      date-month: '\d+'
      date-year: '\d+'
      page: '\d+'
    aspects:
      news-title:
        type: NewsTitle
      page:
        type: StaticRangeMapper
        start: '1'
        end: '25'
      date-month:
        type: StaticValueMapper
        map:
          january: '01'
          february: '02'
          march: '03'
          april: '04'
          may: '05'
          june: '06'
          july: '07'
          august: '08'
          september: '09'
          october: '10'
          november: '11'
          december: '12'
      date-year:
        type: StaticRangeMapper
        start: '2000'
        end: '2030'
Copied!

Explanation:

You will need a new routePath for every possible combination of arguments (pagination, month with/without pagination, ...).

Potential errors:

If you want 2018/march but get 2018/3 instead, compare your StaticValueMapper for months with your date arguments. Are you using different date formats (with/without leading zeros)?

You can either remove the leading zero in your aspects or adapt the TypoScript setting:

TypoScript setup
plugin.tx_news.settings.link {
    hrDate = 1
    hrDate {
        day = j
        // 'n' for 1 through 12. 'm' for 01 through 12.
        month = m
        year = Y
    }
}
Copied!

You can configure each argument (day/month/year) separately by using the configuration of PHP function date.

How to create URLs in PHP

The following snippet is a good example how an URL can be generated properly

PHP Code
protected function generateUrl(SiteInterface $site, int $recordId, int $detailPageId): string
    {
        $additionalQueryParams = [
            'tx_news_pi1' => [
                'action' => 'detail',
                'controller' => 'News',
                'news' => $recordId
            ]
        ];
        return (string)$site->getRouter()->generateUri(
            (string)$detailPageId,
            $additionalQueryParams
        );
    }
Copied!

References