3

I have a multi-locale site set up with the different locales in different domains

  • phoseon.craft.dev - English site
  • phoseon.it.craft.dev - Italian site

etc.

I am having problems getting Live Preview to work with a locale other than English.

The page I am trying to get this to work on, test-single, is a single, with a template that just displays the title (so no complexity there).

When I try to use Live Preview in a locale other than English, I get this error in the console:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://phoseon.it.craft.dev/. This can be fixed by moving the resource to the same domain or enabling CORS.

And no Live Preview, just a white screen.

Based on this answer I added this to .htaccess for http://phoseon.it.craft.dev

Header add Access-Control-Allow-Origin "http://phoseon.craft.dev"

And now I see these requests, and still a white screen for the Live Preview:

POST http://phoseon.it/craft.dev/test-single 302 Found
  Request Headers:
    Accept  */*
    Accept-Encoding gzip, deflate
    Accept-Language en-US,en;q=0.5
    Content-Length  198
    Content-Type  application/x-www-form-urlencoded; charset=UTF-8
    Host  phoseon.it.craft.dev
    Origin  http://phoseon.craft.dev
    Referer http://phoseon.craft.dev/admin/entries/testSingle/1742-testsingle/it_it
    User-Agent  Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:35.0) Gecko/20100101 Firefox/35.0
  Response Headers:
    Access-Control-Allow-Orig...  http://phoseon.craft.dev
    Cache-Control no-store, no-cache, must-revalidate, post-check=0, pre-check=0
    Connection  Keep-Alive
    Content-Encoding  gzip
    Content-Length  2346
    Content-Type  text/html
    Date  Mon, 16 Feb 2015 20:38:14 GMT
    Expires Thu, 19 Nov 1981 08:52:00 GMT
    Keep-Alive  timeout=5, max=100
    Location  http://phoseon.it.craft.dev/login
    Pragma  no-cache
    Server  Apache/2.2.26 (Unix) DAV/2 PHP/5.4.30 mod_ssl/2.2.26 OpenSSL/0.9.8zc
    Set-Cookie  CraftSessionId=gtm75r2a9it49820uueam9hpe2; path=/; HttpOnly
    Vary  User-Agent,Accept-Encoding
    X-Powered-By  PHP/5.4.30

  And the response is the site's 404 page

GET http://phoseon.it.craft.dev/login 404 Not Found
  Request Headers:
    Accept  */*
    Accept-Encoding gzip, deflate
    Accept-Language en-US,en;q=0.5
    Content-Type  application/x-www-form-urlencoded; charset=UTF-8
    Host  phoseon.it.craft.dev
    Origin  http://phoseon.craft.dev
    Referer http://phoseon.craft.dev/admin/entries/testSingle/1742-testsingle/it_it
    User-Agent  Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:35.0) Gecko/20100101 Firefox/35.0
  Response Headers:
    Access-Control-Allow-Orig...  http://phoseon.craft.dev
    Cache-Control no-store, no-cache, must-revalidate, post-check=0, pre-check=0
    Connection  close
    Content-Encoding  gzip
    Content-Length  42163
    Content-Type  text/html; charset=utf-8
    Date  Mon, 16 Feb 2015 20:38:14 GMT
    Expires Thu, 19 Nov 1981 08:52:00 GMT
    Pragma  no-cache
    Server  Apache/2.2.26 (Unix) DAV/2 PHP/5.4.30 mod_ssl/2.2.26 OpenSSL/0.9.8zc
    Set-Cookie  CraftSessionId=isldd40afpu41mr9as659f6rs7; path=/; HttpOnly
    Vary  User-Agent,Accept-Encoding
    X-Powered-By  PHP/5.4.30
    charset utf-8

  And the response is agin the site's 404 page

Anyone else encountered this? Know what's going on? Recommended fixes?

1

I was having the same issue... but given that there are 15 domains, having the client access the admin cp from each domain isn't really an option.

The key appears to be making sure that you have the following in both the admin cp domain and in the domain being previewed's .htaccess file:

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header set Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"

...because you're setting there the origin is allowed. Caveat regarding overriding CORS apply.

| improve this answer | |
  • I think part of my complication is that the site (thank you MediaTemple) has apache and nginx both, and I need to figure out how to turn on cross-origin requests for both. Will post more if/when I get it solved. Meanwhile, I think you have it nailed for basic apache. – Marion Newlevant Sep 17 '15 at 0:54
  • This should help you getting it configured with nginx -> serverfault.com/questions/162429/… – andrew.welch Sep 18 '15 at 1:44
  • This isn't working as you need to be logged in. You get redirected to /login and still get a blank preview. – jlcharette Apr 12 '16 at 19:06
3

Only setting headers in .htaccess doesn't fix the problem. As Marion Newlevant points out in her answer the cross domain works with the headers set. But you still get a white page as a preview.

Looking further into the problem, I've found that the page tries to do a post request to the other domain. It calls upon the action function actionPreviewEntry() in the EntriesController.php file (Location: /craft/app/controllers/ )

But because the user isn't logged in on the other domain and anonymous access isn't allowed for this action. You get redirected to /login to login on that domain.

I came up with a quick solution for the problem. It's a bit dirty for now, but the authors of Craft aren't coming with a solution either.

Solution

  1. Delete (If you have set them) the headers for Access-Control-Allow in your .htaccess file. We don't need them.

  2. Open the file EntriesController.php in the folder /craft/app/controllers/

  3. Replace the code.

    protected $allowAnonymous = array('actionViewSharedEntry');

With:

protected $allowAnonymous = array('actionViewSharedEntry','actionPreviewEntry');
  1. Add the following code in the public function actionPreviewEntry():

    // Set a boolean for logout admin user if cross-domain access
    $crossDomainAccess = FALSE;
    
    // Check if the user isn't logged in. Likely meaning that the action is called from another domain.
    if ( !craft()->userSession->isLoggedIn() ) {
    
      // Get allowed origins
      $locales = array('en','nl');
      $allowedOrigins = array();
      foreach ( $locales as $locale ) {
        $allowedOrigins[] = craft()->config->getLocalized('siteUrl', $locale);
      }
    
      // Check origin and give access if allowed
      $httpOrigin = $_SERVER['HTTP_ORIGIN'];
      if ( in_array($httpOrigin, $allowedOrigins) ) {
        header('Access-Control-Allow-Origin: ' . $httpOrigin);
        header('Access-Control-Allow-Credentials: true');
        craft()->userSession->loginByUserId(1);
        $crossDomainAccess = TRUE;
      }
    }
    

Explanation of the code:

As you can see I set the locales to en and nl. Because that's the only locales for my website.

$locales = array('en','nl');

The domains that are allowed to communicate with each other are set in the general config file under siteUrl. See step 4 of the localization guide for more information. We will fetch them here and put them in an array for checking.

$allowedOrigins = array();
foreach ( $locales as $locale ) {
    $allowedOrigins[] = craft()->config->getLocalized('siteUrl', $locale);
}

We check the origin of the request and if it's allowed to communicate with this domain. If so, then set the header to allow cross-domain access.

And automatically login as the admin user to get full access for the preview page to load as if you are logged in on the other domain.

$httpOrigin = $_SERVER['HTTP_ORIGIN'];
if ( in_array($httpOrigin, $allowedOrigins) ) {
    header('Access-Control-Allow-Origin: ' . $httpOrigin);
    header('Access-Control-Allow-Credentials: true');
    craft()->userSession->loginByUserId(1);
    $crossDomainAccess = TRUE;
}
  1. Next we need to logout the admin user on the other domain. Add the following code:

    if ( $crossDomainAccess == TRUE ) { craft()->userSession->logout(); }

Before the line (In the same function, public function actionPreviewEntry()):

$this->_showEntry($entry);

And that's it. A quickfix for anyone that has come across this problem and wants to fix it quick but dirty for now.

Note: If you update your craft cms, then this code will get deleted, so you have to add it again after you updated.

If you're using baseCpUrl

Slight modification if you're using the baseCpUrl setting and/or have paths in your settings file:

if ( !craft()->userSession->isLoggedIn() ) {

  // Get allowed origins
  $allowedOrigins = array(
          parse_url(craft()->config->get('baseCpUrl'), PHP_URL_HOST),
          parse_url(craft()->config->getLocalized('siteUrl', 'en_us'), PHP_URL_HOST)
  );

  // Check origin and give access if allowed
  $httpOrigin = parse_url($_SERVER['HTTP_ORIGIN'], PHP_URL_HOST);
  if ( in_array($httpOrigin, $allowedOrigins) ) {
          header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
          header('Access-Control-Allow-Credentials: true');
          craft()->userSession->loginByUserId(1);
          $crossDomainAccess = TRUE;
  }
}

Here I've hard-coded the language in, but it can be combined with the answer above instead.

| improve this answer | |
  • Where do you add the first bit of code inside function actionPreviewEntry() ? At the very beginning ? – jlcharette Apr 13 '16 at 12:16
  • Something has changed in that time in the Craft? – Vitaliy Badalov May 24 '16 at 15:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.