Routing (Speaking URLs)

Speaking URLs (for TYPO3 9 and greater) can be achieved by adding a route enhancer configuration to the site configuration (see example below).

Speaking URLs can be configured for the search word, for filters, for the sorting and for the pagination.

There are two mappers provided to map tags to slugs (KeSearchTagToSlugMapper) and to use the search word as part of the route (KeSearchUrlEncodeMapper).

Example URL

https://example.org/search-page/score/desc/0/1/news-cat-1/search+word

Notes

  • Adjust the values for the parameter sortByField as it fits your needs (you may have different fields to sort by in your website).

  • For filters of type select and textlink you need one rule per filter. The rule is defined by using "filter" + "_" + the UID of the filter.

  • For filters of type checkbox (multi-select filters) you need one rule per filter option. The rules are defined by using filter + "_" + the UID of the filter + "_" + the UID of the filter option. Unfortunately this may render your URL very long if you have many filter options. Maybe there will be a better solution in the future.

  • Search words will be url encoded (eg. "schön" will become "sch%25C3%25B6n").

  • The StaticMappableAspectInterface can also be used for filters. In this case not the slug is used for URL generation but the tag. This may be useful in cases where you use the same tag for different filter options or if you have huge amounts of tags and want to improve performance (the KeSearchTagToSlugMapper accesses the database once for each routing parameter on every request).

  • For filters of type "select" or "list" you will need to set one character default value. That will be ignored in the filtering, but that is necessary to differentiate if the value is coming from the routing configuration or if the user wants to reset the filter (in that case an empty value is given). See also https://github.com/tpwd/ke_search/issues/126

Examples

These are examples for the site configuration file (config.yaml).

You need to adjust the filter UIDs (like in filter_13 where 13 is the UID of the filter) and the filter option UIDs (like in filter_3_267 where 267 is the UID of the filter option).

Simple example

This is a simple example with one filter and the search word mapped to a speaking URL.

If only a filter is given, this will give URLs like

https://www.example.org/search-page/filter-option

If additionally a searchword is given, this will result in

https://www.example.org/search-page/filter-option/score/desc/0/1/search-word

routeEnhancers:
   KeSearch:
      type: Plugin
      routePath: '{filter_13}/{sortByField}/{sortByDir}/{resetFilters}/{page}/{sword}'
      namespace: 'tx_kesearch_pi1'
      defaults:
         sortByField: 'score'
         sortByDir: 'desc'
         resetFilters: '0'
         page: '1'
         sword: ''
         filter_13: '-'
      requirements:
         sortByField: '(score|title|customranking|sortdate)?'
         sortByDir: '(asc|desc)?'
         resetFilters: '[0-9]?'
         page: '\d+'
         filter_13: '[0-9a-zA-Z-]*'
      aspects:
         sortByField:
            type: StaticValueMapper
            map:
               score: 'score'
               customranking: 'customranking'
               title: 'title'
         sortByDir:
            type: StaticValueMapper
            map:
               asc: 'asc'
               desc: 'desc'
         resetFilters:
            type: StaticRangeMapper
            start: '0'
            end: '1'
         page:
            type: StaticRangeMapper
            start: '1'
            end: '99'
         filter_13:
            type: KeSearchTagToSlugMapper
         sword:
            type: KeSearchUrlEncodeMapper

Full example

This is an example for a site configuration which adds multiple filters to the routing configuration. Filter no. 3 is a "checkbox" filter, therefore each filter option has to be a configured individually.

routeEnhancers:
   KeSearch:
      type: Plugin
      routePath: '{sortByField}/{sortByDir}/{resetFilters}/{page}/{filter_14}/{filter_13}/{filter_3_267}/{filter_3_273}/{filter_3_278}/{filter_3_283}/{sword}'
      namespace: 'tx_kesearch_pi1'
      defaults:
         sortByField: 'score'
         sortByDir: 'desc'
         resetFilters: '0'
         page: '1'
         filter_13: '-'
         filter_14: '-'
         filter_3_267: ''
         filter_3_273: ''
         filter_3_278: ''
         filter_3_283: ''
         sword: ''
      requirements:
         sortByField: '(score|title|customranking)?'
         sortByDir: '(asc|desc)?'
         resetFilters: '[0-9]?'
         page: '\d+'
         filter_13: '[0-9a-zA-Z-]*'
         filter_14: '[0-9a-zA-Z-]*'
         filter_3_267: '[0-9a-zA-Z-]*'
         filter_3_273: '[0-9a-zA-Z-]*'
         filter_3_278: '[0-9a-zA-Z-]*'
         filter_3_283: '[0-9a-zA-Z-]*'
      aspects:
         sortByField:
            type: StaticValueMapper
            map:
               score: 'score'
               customranking: 'customranking'
               title: 'title'
         sortByDir:
            type: StaticValueMapper
            map:
               asc: 'asc'
               desc: 'desc'
         resetFilters:
            type: StaticRangeMapper
            start: '0'
            end: '1'
         page:
            type: StaticRangeMapper
            start: '1'
            end: '99'
         filter_13:
            type: KeSearchTagToSlugMapper
         filter_14:
            type: KeSearchTagToSlugMapper
         filter_3_267:
            type: KeSearchTagToSlugMapper
         filter_3_273:
            type: KeSearchTagToSlugMapper
         filter_3_278:
            type: KeSearchTagToSlugMapper
         filter_3_283:
            type: KeSearchTagToSlugMapper
         sword:
            type: KeSearchUrlEncodeMapper

Upgrading

If you are upgrading from ke_search 3.3.1 or below and you are using your own templates, you will have to do a few adjustments to the templates as shown below.

Resources/Private/Templates/SearchForm.html

  1. Add the kesearch namespace to the beginning of the file

    <html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
          xmlns:kesearch="http://typo3.org/ns/Tpwd/KeSearch/ViewHelpers"
          data-namespace-typo3-fluid="true">
    
  2. Add the snippet to rewrite the url to the beginning of the form

    <f:comment> // Replace the URL with the speaking URL </f:comment>
    <f:format.raw><script type="text/javascript">history.replaceState(null,'','</f:format.raw><kesearch:link keepPiVars="1" uriOnly="1" /><f:format.raw>');</script></f:format.raw>
    
  3. Add conditions to the hidden fields

    <f:if condition="{page}">
       <input id="kesearchpagenumber" type="hidden" name="tx_kesearch_pi1[page]" value="{page}" />
    </f:if>
    <input id="resetFilters" type="hidden" name="tx_kesearch_pi1[resetFilters]" value="0" />
    <f:if condition="{sortByField}">
       <input id="sortByField" type="hidden" name="tx_kesearch_pi1[sortByField]" value="{sortByField}" />
    </f:if>
    <f:if condition="{sortByDir}">
       <input id="sortByDir" type="hidden" name="tx_kesearch_pi1[sortByDir]" value="{sortByDir}" />
    </f:if>
    

Resources/Private/Templates/Widget/Pagination.html

  1. Add the kesearch namespace to the beginning of the file

    <html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
          xmlns:kesearch="http://typo3.org/ns/Tpwd/KeSearch/ViewHelpers"
          data-namespace-typo3-fluid="true">
    
  2. Change the links using the kesearch:link view helper

    <f:spaceless>
       <ul>
          <f:if condition="{pagination.previous}">
             <li>
                <kesearch:link piVars="{page: pagination.previous}" keepPiVars="1" class="prev">{f:translate(key: 'LLL:EXT:ke_search/Resources/Private/Language/locallang_searchbox.xlf:pagebrowser_prev')}</kesearch:link>
             </li>
          </f:if>
          <f:for each="{pagination.pages}" as="page">
             <li>
                <kesearch:link piVars="{page: page}" keepPiVars="1" class="{f:if(condition: '{page} == {pagination.currentPage}', then: 'current')}">{page}</kesearch:link>
             </li>
          </f:for>
          <f:if condition="{pagination.next}">
             <li>
                <kesearch:link piVars="{page: pagination.next}" keepPiVars="1" class="next">{f:translate(key: 'LLL:EXT:ke_search/Resources/Private/Language/locallang_searchbox.xlf:pagebrowser_next')}</kesearch:link>
             </li>
          </f:if>
       </ul>
    </f:spaceless>
    

Resources/Private/Partials/Filters/Checkbox.html

  1. Change the "name" attribute of the options

    <input type="checkbox" name="{option.key}" id="{option.id}" value="{option.tag}" {f:if(condition: '{option.selected}', then: ' checked="checked"')} {f:if(condition: '{option.disabled}', then: 'disabled = "disabled"')} />