# Solr sort: ignore leading articles Adds the `string_sort_ignore_articles` Solr field type and uses it for the Search API sort field(s) listed in `solr_sort_ignore_articles.settings`, so "The Matrix" sorts under M and "!Introduction" sorts under I. ## Requirements * Drupal 10 or 11 * `search_api_solr` 4.3 or later * Write access to the `conf` directory of the Solr core, and the ability to reload the core ## How it works `search_api_solr` never sorts on the field you index. For every string and fulltext field it copies the first value into a companion field named `sort_;_` (encoded as `sort_X3b_en_title`), and sorting resolves to that field. Those companion fields are matched by the dynamic field `sort_X3b__*`, which is typed as the language's ICU collation — one collation per language, with no per-field override. This module subscribes to `PostConfigFilesGenerationEvent` and appends an explicit `` for the fields you name to `schema_extra_fields.xml`, plus the field type to `schema_extra_types.xml`. In Solr an explicit field always wins over a matching `dynamicField`, so only the named fields get the new analysis and every other sort keeps the default collation. The module never talks to Solr itself. It only changes what `search-api-solr:get-server-config` generates — deploying that to the core is a manual step. ## Deployment ### 1. Install and enable ```bash composer require roblib/solr_sort_ignore_articles drush en solr_sort_ignore_articles ``` ### 2. Add a sort field to the index At `/admin/config/search/search-api/index//fields`, add *Content » Title* a second time, change its machine name to `title_sort` and set its type to **String**. In config it looks like this: ```yaml # search_api.index..yml, under field_settings: title_sort: label: 'Title (sort, ignore articles)' datasource_id: 'entity:node' property_path: title type: string dependencies: module: - node ``` Using a separate field keeps sorting on the existing `title` field unchanged. To change `title` itself instead, put `title` in `solr_sort_ignore_articles.settings:fields` and skip this step. The module ships with `title_sort` as the default. To override: ```bash drush config:set solr_sort_ignore_articles.settings fields.0 title_sort drush config:set solr_sort_ignore_articles.settings fields.1 field_alt_title ``` Export config, and remember that any later change here means repeating steps 3 and 4. ### 3. Update the Solr schema Generate the config set, matching the Solr version actually running on the target server: ```bash drush search-api-solr:get-server-config /tmp/solr_config.zip ``` Sanity check the two generated files before deploying: ```bash unzip -p /tmp/solr_config.zip schema_extra_types.xml | grep -A3 string_sort_ignore_articles unzip -p /tmp/solr_config.zip schema_extra_fields.xml | grep 'sort_X3b_.*_title_sort' ``` Then deploy to the core's `conf` directory by one of two routes. **Full replacement** — only when the core belongs to this site alone and the config set was generated for the same Solr version the server runs: ```bash unzip -o /tmp/solr_config.zip -d /path/to/solr/server/solr//conf ``` **Hand-append ** — required when the core is shared with other Drupal sites, or when the target runs a different Solr major version than the config set was generated for. A full replacement would discard other sites' additions, and a config set for the wrong Solr version brings an incompatible `solrconfig.xml` along with it. Append the module's block to the end of each of the two files in the core's `conf` directory. Both files are bare XML fragments with no root element, and field types do not have to precede the fields that use them. `schema_extra_types.xml`: ```xml ``` `schema_extra_fields.xml`, one line per language, copied from the generated zip: ```xml ``` Keep the comment markers — they are what makes the block findable and cleanly removable later. Both blocks load unchanged on Solr 8.11 and 9.x. `ICUFoldingFilterFactory` needs the ICU analysis jar, but any core running the stock `search_api_solr` config set already has it — every `collated_*` field type is a `solr.ICUCollationField` from that same jar, and the core would not load at all without it. On Solr 8 the config set loads it through the `contrib/analysis-extras` `` directives; on Solr 9 it comes from `SOLR_MODULES` including `analysis-extras`. Reload the core: ```bash curl -sS "http://:8983/solr/admin/cores?action=RELOAD&core=" ``` A malformed fragment fails the reload with a schema parse error and the core keeps its previous schema, so this is safe to retry. ### 4. Reindex The sort field is only populated at index time, so existing documents keep their old values until reindexed: ```bash drush search-api:reset-tracker && drush search-api:index ``` ### 5. Add the sort criterion In Views, add the new sort criterion (*Title (sort, ignore articles)*) to the search view. ## Verifying At `/solr/#//analysis`, field type `string_sort_ignore_articles` should reduce each of these to a single token: | Input | Token | Checks | | --- | --- | --- | | `The !Matrix` | `matrix` | article and punctuation both stripped | | `A Tale of Two Cities` | `tale of two cities` | one token, not one per word | | `Theory of Everything` | `theory of everything` | a word starting with an article is left alone | | `Ökonomie` | `okonomie` | diacritics folded, so it sorts under O | The field itself can be confirmed with the Schema API: ```bash curl -sS "http://:8983/solr//schema/fields/sort_X3b_en_title_sort" ```