{"id":13756586,"url":"https://github.com/nystudio107/retour","last_synced_at":"2025-03-29T23:10:34.608Z","repository":{"id":57029564,"uuid":"56884560","full_name":"nystudio107/retour","owner":"nystudio107","description":"DEPRECATED Retour allows you to intelligently redirect legacy URLs, so that you don't lose SEO value when rebuilding \u0026 restructuring a website.","archived":false,"fork":false,"pushed_at":"2019-01-01T23:47:14.000Z","size":1925,"stargazers_count":168,"open_issues_count":23,"forks_count":25,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-04-29T18:08:49.500Z","etag":null,"topics":["craft-plugin","craftcms","deprecated","redirects"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nystudio107.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-04-22T20:52:48.000Z","updated_at":"2023-12-13T00:15:52.000Z","dependencies_parsed_at":"2022-08-23T17:40:53.992Z","dependency_job_id":null,"html_url":"https://github.com/nystudio107/retour","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nystudio107%2Fretour","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nystudio107%2Fretour/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nystudio107%2Fretour/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nystudio107%2Fretour/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nystudio107","download_url":"https://codeload.github.com/nystudio107/retour/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246254099,"owners_count":20747948,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["craft-plugin","craftcms","deprecated","redirects"],"created_at":"2024-08-03T11:00:48.369Z","updated_at":"2025-03-29T23:10:34.588Z","avatar_url":"https://github.com/nystudio107.png","language":"PHP","funding_links":[],"categories":["SEO"],"sub_categories":[],"readme":"[![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/)\n\n# DEPRECATED\n\nThis Craft CMS 2.x plugin is no longer supported, but it is fully functional, and you may continue to use it as you see fit. The license also allows you to fork it and make changes as needed for legacy support reasons.\n\nThe Craft CMS 3.x version of this plugin can be found here: [craft-retour](https://github.com/nystudio107/craft-retour) and can also be installed via the Craft Plugin Store in the Craft CP.\n\n# Retour plugin for Craft CMS\n\nRetour allows you to intelligently redirect legacy URLs, so that you don't lose SEO value when rebuilding \u0026 restructuring a website.\n\n![Screenshot](resources/screenshots/retour01.png)\n\nRelated: [Retour for Craft 3.x](https://github.com/nystudio107/craft-retour)\n\n## Installation\n\nTo install Retour, follow these steps:\n\n1. Download \u0026 unzip the file and place the `retour` directory into your `craft/plugins` directory\n2.  -OR- do a `git clone https://github.com/nystudio107/retour.git` directly into your `craft/plugins` folder.  You can then update it with `git pull`\n3.  -OR- install with Composer via `composer require nystudio107/retour`\n4. Install plugin in the Craft Control Panel under Settings \u003e Plugins\n5. The plugin folder should be named `retour` for Craft to see it.  GitHub recently started appending `-master` (the branch name) to the name of the folder for zip file downloads.\n\nRetour works on Craft 2.4.x, Craft 2.5.x, and Craft 2.6.x.\n\n## Retour Overview\n\nRetour allows you to intelligently redirect legacy URLs, so that you don't lose SEO value when rebuilding \u0026 restructuring a website.\n\nIn addition to supporting traditional exact and RegEx matching of URL patterns, Retour also has a Retour Redirect FieldType that you can add to your entries. This allows you to have dynamic entry redirects that have access to the data in your entries when matching URL patterns.\n\nRetour will also automatically create a redirect for you if you change an entry's slug, or move an entry around in a Structure.\n\nRetour is written to be performant. There is no impact on your website's performance until a 404 exception happens; and even then the resulting matching happens with minimal impact.\n\nDon't just rebuild a website. Transition it with Retour.\n\n## Why Use a Plugin for Redirects?\n\nIf you have just a few static redirects, then your best bet is to put them in your `.htaccess` file, or better yet, in your `.conf` file for your virtual host.  However, there are a number of cases where using a plugin to handle it is a **better** solution:\n\n1. If you have a large number of redirects, it will slow down every single request your web server handles unnecessarily if they are in `.htaccess` or `.conf`\n2. Often the URL patterns from the legacy website do not match the new website URLs in a deterministic way, which makes creating redirects difficult\n3. Sometimes you don't have access to the server config files, or you want to give your client the ability to manage redirects easily\n\nRetour solves these problems:\n\n1. Retour only attempts to do a redirect after the web server has already thrown a 404 exception.  Once a redirect mapping is successfully determined, it also caches the result for speedy resolution of the next redirect request.\n2. Retour also gives you the ability to do Dynamic Entry Redirects that allow you to import a piece of legacy data into your entries to use as a key for determining the new URL mapping.  In this way, utterly dissimilar URLs can be mapped for redirection effectively.\n3. It provides an easy to use GUI that the client can use from Craft's AdminCP, and keeps statistics on the 404 hits (and misses)\n\n### A Word about .htaccess\n\nPeople using the Apache webserver are familiar with the `.htaccess` file, and may even be using it for redirects.  It's very likely that you should not be using `.htaccess` at all; instead you should disable `.htaccess` via `AllowOverride none` and make your configuration changes in your webserver configuration files.  From [Apache HTTP Server Tutorial: .htaccess files](https://httpd.apache.org/docs/current/howto/htaccess.html)\n\n    There are two main reasons to avoid the use of .htaccess files.\n\n    The first of these is performance. When AllowOverride is set to allow the\n    use of .htaccess files, httpd will look in every directory for .htaccess\n    files. Thus, permitting .htaccess files causes a performance hit, whether or\n    not you actually even use them! Also, the .htaccess file is loaded every\n    time a document is requested.\n\n    Further note that httpd must look for .htaccess files in all higher-level\n    directories, in order to have a full complement of directives that it must\n    apply. (See section on how directives are applied.) Thus, if a file is\n    requested out of a directory /www/htdocs/example, httpd must look for the\n    following files:\n\n    /.htaccess\n    /www/.htaccess\n    /www/htdocs/.htaccess\n    /www/htdocs/example/.htaccess\n\n    And so, for each file access out of that directory, there are 4 additional\n    file-system accesses, even if none of those files are present. (Note that\n    this would only be the case if .htaccess files were enabled for /, which is\n    not usually the case.)\n\n    In the case of RewriteRule directives, in .htaccess context these regular\n    expressions must be re-compiled with every request to the directory, whereas\n    in main server configuration context they are compiled once and cached.\n    Additionally, the rules themselves are more complicated, as one must work\n    around the restrictions that come with per-directory context and\n    mod_rewrite. Consult the Rewrite Guide for more detail on this subject.\n\nAs you can see, avoiding the use of `.htaccess` completely is best if at all possible, and especially avoid it for `RewriteRule` directives, such as 404 rewrites.\n\n## Dynamic Entry Redirects\n\nRetour implements a Retour Redirect FieldType that you can add to your Entry Types.  Retour will look for 404 (Not Found) URLs that match the Legacy URL Pattern, and redirect them to this entry's URL.\n\nYou also get the context of the `entry` that you can use when matching legacy URLs; so if you've imported a field called `recipeid` into your new website, you can the Retour Redirect FieldType look for it in your Legacy URL Pattern, e.g.: `/old-recipes/{recipeid}`\n\nThis allows you to key off of a piece of legacy data that was imported, for the cases when the new URL patterns don't look anything like the Legacy URL Patterns, or follow any pattern that RegEx is useful for matching.\n\n![Screenshot](resources/screenshots/retour02.png)\n\n### Creating a Retour Redirect Field\n\nCreate a Retour Redirect field as you would any other field; then set the default values for it.  For new entries, it will default to the values entered here, so you can put your matching pattern in once, rather than having to do it for each entry.\n\n* **Default Legacy URL Pattern** - Enter the URL pattern that Retour should match. This matches against the path, the part of the URL after the domain name. You can include tags that output entry properties, such as `{title}` or `{myCustomField}` in the text field below. e.g.: Exact Match: `/recipes/{recipeid}` or RegEx Match: `.*RecipeID={recipeid}$` where `{recipeid}` is a field handle to a field in this entry.\n* **Default Pattern Match Type** - What type of matching should be done with the Legacy URL Pattern. Details on RegEx matching can be found at [regexr.com](http://regexr.com). If a plugin provides a custom matching function, you can select it here.\n* **Default Redirect Type** - Select whether the redirect should be permanent or temporary.\n* **Redirect Changeable** - Whether to allow the user to change the redirect while editing the entry.\n\n### Configuring a Retour Redirect Field\n\n\n* **Legacy URL Pattern** - Enter the URL pattern that Retour should match. This matches against the path, the part of the URL after the domain name. You can include tags that output entry properties, such as `{title}` or `{myCustomField}` in the text field below. e.g.: Exact Match: `/recipes/{recipeid}` or RegEx Match: `.*RecipeID={recipeid}$` where `{recipeid}` is a field handle to a field in this entry.\n* **Pattern Match Type** - What type of matching should be done with the Legacy URL Pattern. Details on RegEx matching can be found at [regexr.com](http://regexr.com). If a plugin provides a custom matching function, you can select it here.\n* **Redirect Type** - Select whether the redirect should be permanent or temporary.\n\n**Note:** if you add a Retour Redirect FieldType to an existing Section, or you import data from a foreign source into a Section with a Retour Redirect FieldType, the default values you set for the Retour Redirect FieldType will not be propagated to the entry yet.  To cause that to happen, go to **Settings-\u003eSections** then click on the Section to edit it, and hit **Save**.  This will cause all of the entries in that section to be re-saved, and Retour will fill in the default field values.\n\n## Static Redirects\n\n### Manually Creating Static Redirects\n\nStatic Redirects are useful when the Legacy URL Patterns and the new URL patterns are deterministic.  You can create them by clicking on **Retour-\u003eRedirects** and then clicking on the **+ New Static Redirect** button.\n\n* **Legacy URL Pattern** - Enter the URL pattern that Retour should match. This matches against the path, the part of the URL after the domain name. e.g.: Exact Match: `/recipes/` or RegEx Match: `.*RecipeID=(.*)`\n* **Destination URL** - Enter the destination URL that should be redirected to. This can either be a fully qualified URL or a relative URL. e.g.: Exact Match: `/new-recipes/` or RegEx Match: `/new-recipes/$1`\n* **Pattern Match Type** - What type of matching should be done with the Legacy URL Pattern. Details on RegEx matching can be found at [regexr.com](http://regexr.com). If a plugin provides a custom matching function, you can select it here.\n* **Redirect Type** - Select whether the redirect should be permanent or temporary.\n\n### Importing an Existing .htaccess file\n\nRetour also allows you to import an existing `.htaccess` file and all of the redirects it contains into Retour by clicking on **Retour-\u003eRedirects** and then clicking on the **Import .htaccess File** button.\n\nIt will import redirects from `Redirect` and `RedirectMatch` directives in the file.  It will **ignore** `RewriteRule`s because they don't necessarily have a 1:1 mapping, you can have several `RewriteRule`s that are strung together to figure out the final redirect.\n\nIt asks your browser to look for only `text` files to upload; if the `.htaccess` file you have isn't a `.txt` file, you can force it to allow you to upload it by choosing **Format: All Files**.\n\n### Renamed Slug Redirects\n\nIf you rename an entry's `slug` (and the Section the entry is in has URLs), Retour will automatically create a static redirect for you to keep traffic going to the right place.  It will also automatically create a static redirect if you move an entry around in a Structure.\n\nIt will appear listed under the \"Static Redirects\" section like any other static redirect.\n\n## Retour Statistics\n\nRetour keeps track of every 404 your website receives.  You can view them by clicking on **Retour-\u003eStatistics**.  \n\nOnly one record is saved per URL Pattern, so the database won't get clogged with a ton of records.\n\n### Retour Widget\n\nIf you'd like to see an overview of the Retour Statistics in your dashboard, you can add a Retour widget to your Dashboard:\n\n![Screenshot](resources/screenshots/retour03.png)\n\nIt displays the total number of handled and not handled 404s, and the 5 most recent 404 URLs in each category right in your dashboard.\n\n## Developer Info\n\n### Custom Match Functions via Plugin\n\nRetour allows you to implement a custom matching function via plugin, if the Exact and RegEx matching are not sufficient for your purposes.\n\nIn your main plugin class file, simply add this function:\n\n    /**\n     * retourMatch gives your plugin a chance to use whatever custom logic is needed for URL redirection.  You are passed\n     * in an array that contains the details of the redirect.  Do whatever matching logic, then return true if is a\n     * matched, false if it is not.\n     *\n     * You can alter the 'redirectDestUrl' to change what URL they should be redirected to, as well as the 'redirectHttpCode'\n     * to change the type of redirect.  None of the changes made are saved in the database.\n     *\n     * @param mixed An array of arguments that define the redirect\n     *            $args = array(\n     *                'redirect' =\u003e array(\n     *                    'id' =\u003e the id of the redirect record in the retour_redirects table\n     *                    'associatedElementId' =\u003e the id of the entry if this is a Dynamic Entry Redirect; 0 otherwise\n     *                    'redirectSrcUrl' =\u003e the legacy URL as entered by the user\n     *                    'redirectSrcUrlParsed' =\u003e the redirectSrcUrl after it has been parsed as a micro template for {variables}\n     *                        via renderObjectTemplate().  This is typically what you would want to match against.\n     *                    'redirectMatchType' =\u003e the type of match; this will be set to your plugin's ClassHandle\n     *                    'redirectDestUrl' =\u003e the destination URL for the entry this redirect is associated with, or the\n     *                        destination URL that was manually entered by the user\n     *                    'redirectHttpCode' =\u003e the redirect HTTP code (typically 301 or 302)\n     *                    'hitCount' =\u003e the number of times this redirect has been matched, and the redirect done in the browser\n     *                    'hitLastTime' =\u003e the date and time of the when this redirect was matched\n     *                    'locale' =\u003e the locale of this redirect\n     *                )\n     *            );\n     * @return bool Return true if it's a match, false otherwise\n     */\n    public function retourMatch($args)\n    {\n        return true;\n    }\n\nYour plugin will then appear in the list of Pattern Match Types that can be chosen from via Retour-\u003eRedirects or via the Retour Redirect FieldType.\n\n### Utility Functions\n\n`craft.retour.getHttpStatus` in your templates will return the HTTP Status code for the current template, so you can display a special message for people who end up on a page via a `301` or `302` redirect.\n\n## Retour Roadmap\n\nSome things to do, and ideas for potential features:\n\n* Craft 3 compatibility\n* Add the ability to mass-import redirects from a CSV file\n\nBrought to you by [nystudio107](http://nystudio107.com)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnystudio107%2Fretour","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnystudio107%2Fretour","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnystudio107%2Fretour/lists"}