skip to Main Content

For SEO purposes I want to redirect my old non-Yii2 URLs to the new ones. So I need to intercept the 404 that Yii throws and respond with a 301 redirection. Where is the best place to do that?

3

Answers


  1. Chosen as BEST ANSWER

    So far I myself found these possible ways of doing it:

    Method 1:

    This method does it before the request is being handled - based on known URLs. They only take effect when the URL doesn't point to directly to existing files/folders (since otherwise .htaccess will never redirect the rquest to Yii).

    In config/web.php add the following to the config array:

    $config = [
        'id' => '...',
        'components' => '...',
        'params' => '...',
        ...
        'on beforeAction' => function($event) {
            $redirects = [
                'your/old/url.php' => '/my/new-route',
                'contact.php' => '/site/contact',
            ];
            if (($newRoute = $redirects[Yii::$app->requestedRoute]) || ($newRoute = $redirects[Yii::$app->requestedRoute .'/'])) {
                // maybe you want to add some logging here on this line
                Yii::$app->response->redirect(yiihelpersUrl::to($newRoute), 301);
                Yii::$app->end();
            }
        },
    ];
    

    Method 2:

    This method does it after the request has been handled - based on no route and having ended up with a 404. This has the advantage that we can also handle unknown URLs that ended up in a 404.

    Add a bootstrap class as per documentation here and here. Then add this to your bootstrap() method:

    Yii::$app->on(yiiwebApplication::EVENT_BEFORE_ACTION, function($event) use (&$app) {
        if ($event->sender->getStatusCode() == 404) {
            // maybe you want to add some logging here on this line
            if (in_array($app->requestedRoute, ['your/old/url.php', 'contact.php'])) {
                // determine new route and redirect the same way as we do in method 1
            } else {
                // here you do redirect eg. to the homepage or do nothing if you still want to throw a 404
            }
        }
    });
    

    Here is also another variant.


  2. I would add the old URLs to config/url-manager.php (or backend/config/url-manager.php in case of advanced template) to process them by the appropriate controller action, and do the redirection in the controller.

    An example, assumed that pretty URL is enabled and the old URL is posts/list and the new one simple posts, than add the following to the rules in url-manager:

    'posts/list' => 'posts/post/index-redirect',
    'posts' => 'posts/post/index',
    

    This will route the old URL to the PostController of the posts module. Add the following action to the controller:

    public function actionIndexRedirect()
    {
        return $this->redirect(['index'], 301);
    }
    

    Of course you could have a lot of old URLs and you do not want process them one by one, than add parameters to the rule and process the parameters in the redirect action.

    Login or Signup to reply.
  3. You could create a class that implements yiiwebUrlRuleInterface. You need two functions for that interface:

    1. parseRequest: use this method to check if the request matches an old url. If so, redirect to the new url else return false. You could check against a db table or a list of old urls, whatever you like.
    2. createUrl: as these old urls are not functional anymore, the createUrl just needs to return false.
    public function createUrl($manager, $route, $params)
    {
        return false; // this rule does not apply
    }
    

    Also, I would put this as the last rule of your rules of the UrlManager so it doesn’t affect your other pages at all, in performance or hiding new urls.

    See docs at Yii for full explanation: https://www.yiiframework.com/doc/guide/2.0/en/runtime-routing#creating-rules

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search