Search code examples
silverstripegoogle-amp

SilverStripe 3.5.1 - Redirect to AbsoluteLink of SilverStripe page if user tries to navigate to amp.html version


I am working on a fork of the SilverStripe AMP module (https://github.com/thezenmonkey/silverstripe-amp) and have to prevent anyone from navigating to the amp.html version of a SilverStripe page if the amp.html link has not been generated into the head of the page.

A little additional info: We have added 2 fields that are meant to appear on the AMP versions of every page: AmpImage and AmpContent (a rich text editor). If either of these is empty, I have the code setup to NOT generate an AMP page for the SilverStripe page in question. This would seem to be enough but an additional requirement has been added, which is the redirect functionality mentioned about so no one can actually navigate to the amp.html page.

I was thinking of doing a redirect with the AmpSiteTreeExtension file but it does not appear to allow for redirects, then I thought of having a function in Page.php that would check if the url contains amp.html, then referencing it with AmpSiteTreeExtension, but every time I try, I get an error saying the function does not exist on "Page" or it's not public.

Is there a good way to handle this kind of situation? Is it best to do it with Page.php or using some other method?

Here are the files that I am working with:

AmpSiteTreeExtension

    public function MetaTags(&$tags)
    {
        if ($this->owner->AmpContent != "" && $this->owner->AmpImageID != "") {

            if ($this->owner->class != "HomePage") {
                $ampLink = $this->owner->AbsoluteLink() . "amp.html";
            } else {
                $ampLink = $this->owner->AbsoluteLink() . "home/" . "amp.html";
            }

            $tags .= "<link rel='amphtml' href='$ampLink' /> \n";
        }

      //add a redirect here? Referencing a function from Page.php like so: $this->owner->functionName() causes the error mentioned above
    }
}

<?php

AmpController

class AmpController extends Extension
{

    private static $allowed_actions = array('amp');

    private static $url_handlers = array(
        'amp.html' => 'amp'
    );

    public function amp()
    {
        Requirements::clear();

        $class = Controller::curr()->ClassName;
        $page = $this->owner->renderWith(array("$class"."_amp", "Amp"));

        return $this->AmplfyHTML($page);
    }


    public function AmplfyHTML($content)
    {
        if (!$content) {
            return false;
        }

        $content = preg_replace('/style=\\"[^\\"]*\\"/', '', $content);
        $content = str_replace("<img", "<amp-img", $content);

        return $content;
    }
}

Solution

  • From what I can tell, you're trying to redirect in the MetaTags() method of the SiteTree extension... and from what I can tell, that MetaTags() method it's probably used in some Silverstripe templates like this: $MetaTags

    ...and there's no way you can apply redirects this way.

    You should do all this redirect stuff in a controller class, and from your example that controller it's probably the AmpController class which is probalby extending the functionality of the Page_Controller class.

    Now I'll assume that AmpController it's an extension of Page_Controller, so I would do it like this:

    class Page_Controller extends ContentController {
    
      public function init() {
        parent::init();
    
        // you might have some other stuff here
    
        // make sure this is the last line in this method
        $this->extend('updateInit');
      }
    
      public function yourRedirectMethod() {
        // do your redirect thing here
      }
    
    }
    

    Key here is the following:

    1. I extend the init() method in the controller - this will allow me to extend the page controller's init() functionality using the updateInit() method in the extension class (AmpController in this case).

    2. Instead of adding the method that's doing the redirect, to the Page class, I added it to the Page_Controller class (the yourRedirectMethod() method).

    Now here comes the AmpController class, where I implement the updateInit() method:

    class AmpController extends Extension {
    
        private static $allowed_actions = array('amp');
    
        private static $url_handlers = array(
            'amp.html' => 'amp'
        );
    
        public function amp()
        {
            Requirements::clear();
    
            $class = Controller::curr()->ClassName;
            $page = $this->owner->renderWith(array("$class"."_amp", "Amp"));
    
            return $this->AmplfyHTML($page);
        }
    
    
        public function AmplfyHTML($content)
        {
            if (!$content) {
                return false;
            }
    
            $content = preg_replace('/style=\\"[^\\"]*\\"/', '', $content);
            $content = str_replace("<img", "<amp-img", $content);
    
            return $content;
        }
    
        public function updateInit() {
          $should_redirect = true;  // of course you add your own condition here to decide wether to redirect or not
    
          if ($should_redirect) {
            $this->owner->yourRedirectFunction();
          }
        }
    
    }
    

    The only thing here, is that you'll need to update the $should_redirect variable above (I've set it to true by default for this example - but here's where you decide if you should redirect or not)... and yes, you can reference here in the AmpController class stuff from the Page class I think, like this for exmaple: $this->owner->Title