Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drupal multilingual with path prefix, template url #567

Open
adixon opened this issue Feb 2, 2023 · 14 comments
Open

Drupal multilingual with path prefix, template url #567

adixon opened this issue Feb 2, 2023 · 14 comments

Comments

@adixon
Copy link

adixon commented Feb 2, 2023

Similar to #543

On a Drupal 9 multilingual site using path prefixes, the 'template' value stored in the metadata field of civicrm_mosaico_template is getting messed up when the template is saved, rendering it unuseable (i.e., when trrying to use the template, you get the dreaded mosaico "blank" (all grey) screen.

On a mono-lingual site, I can see that the template used to be stored as a url, unescaped, and it's now stored with forward slashes escaped and the domain removed. That's nice as far as being able to swap domains for a dev copy!

What's happening for multilingual sites with a path prefix (and possibly with the related issues including the one above) is that the template url is getting saved as

en\/\/sites\/default\/files\/civicrm\/ext\/uk.co.vedaconsulting.mosaico\/packages\/mosaico\/templates\/versafix-1\/template-versafix-1.html

There are two issues here:

  1. the double forward slash after the 'en' [which may not be critical]
  2. how that path gets implemented when creating a new mailing based on the template, which is the not-found-url
    https://domain.org/en/en//sites/default/files/civicrm/ext/uk.co.vedaconsulting.mosaico/packages/mosaico/templates/versafix-1/template-versafix-1.html

This could be resolved in either how the template value gets saved, or how it gets used. Since it's broken in use both for using a template and for editing it, I think the main issue is how it's getting stored.

My quick reading of the changes here: https://github.com/veda-consulting-company/uk.co.vedaconsulting.mosaico/pull/529/files
is that urls are being constructed by combining the civicrm base url and the path, which doesn't always work (i.e. when the cms is fairly sophisticated with the request routing).

@AlainBenbassat
Copy link
Contributor

I noticed exactly the same issue on a multilingual site.

@adixon
Copy link
Author

adixon commented Feb 10, 2023

Not Drupal 9 specific, I get the same symptom on a Drupal 7 multilingual with path prefix as well.

On a parallel note - a version of this has been an issue for a while, I have the following aliases in my apache config that works around some parts of this problem:

Alias /en/sites/default/files/ /var/www/drupal/web/sites/default/files/
Alias /fr/sites/default/files/ /var/www/drupal/web/sites/default/files/

@AlainBenbassat
Copy link
Contributor

Not Drupal 9 specific, I get the same symptom on a Drupal 7 multilingual with path prefix as well.

On a parallel note - a version of this has been an issue for a while, I have the following aliases in my apache config that works around some parts of this problem:

Alias /en/sites/default/files/ /var/www/drupal/web/sites/default/files/ Alias /fr/sites/default/files/ /var/www/drupal/web/sites/default/files/

The alias is indeed a quick fix. Thanks for posting this temporary solution.

@CsarRamos
Copy link

Hello, thanks for reporting it, detected the same problem in D9 multilingual, I think its not saved in the database, the problem is how its called the url here: https://github.com/veda-consulting-company/uk.co.vedaconsulting.mosaico/blob/2.11/api/v3/MosaicoTemplate.php#L81

A possible solution could be using the settings variable that contains the url:

diff --git a/api/v3/MosaicoTemplate.php b/api/v3/MosaicoTemplate.php
index 5477cdad8..6fb748495 100644
--- a/api/v3/MosaicoTemplate.php
+++ b/api/v3/MosaicoTemplate.php
@@ -78,7 +78,7 @@ function civicrm_api3_mosaico_template_get($params) {
     if (_civicrm_api3_mosaico_template_getDomainFrom($baseTemplateURL)) {
       $urlParts = parse_url($baseTemplateURL);
       $templatePath = $urlParts['path'];
-      $currentURL = CRM_Utils_System::baseURL() . $templatePath;
+      $currentURL = CRM_Utils_File::addTrailingSlash(CIVICRM_UF_BASEURL, '/') . $templatePath;
     } else {
       $currentURL = $baseTemplateURL;
     }

Maybe this can be a general solution, awaiting further comments.

@Femonic
Copy link

Femonic commented May 3, 2023

Same here, Drupal 9 with language prefix in path + Mosaico 2.11.1676403645.

In our use-case, whilst the mod_alias workaround will enable the loading of a existing template and for it to be edited, after saving it again the next time the template is loaded we get a 404 again as the path has had an additional language prefix added. This happens on every save (ie /en/en/en/en/...ad infinitum..../sites/default/files/[etc]).

ie works around until resaved (in this case). Maybe we have a different problem, but this is the context in which it has been noted.

I don't know the extension well,, but agree that amending the file as per CsarRamos diff seems to resolve the loading issues, so +1 for a patch/fix, especially when the function concerned seems quite limited in scope.

Thank you!

@francescbassas
Copy link
Contributor

Also seen it today in a D7 multilanguage CiviCRM 5.60.

@pbatroff
Copy link
Contributor

Can also confirm with 2.11, d9 and multi language active. If Multi language isn't needed it can also be deactivated here: /admin/config/regional/language/detection. Simply turn off the URL detection method and mosaico works as intended after a cache clear.

@IProSoft
Copy link

IProSoft commented Jul 18, 2023

I was working on client site and can't disable multilanguage in url so i found temporary and fast solution in comenting some lines in api/v3/MosaicoTemplate.php

  1. Condition after "if (isset($params['metadata'])) {" in civicrm_api3_mosaico_template_create
  2. Condition after comment "// Check if domain name exists in the URL and append ....."

@lshaw1968
Copy link

Solution from CsarRamos is working for us.

Debian 11, Apache2, php 7.4
Drupal 9.5.10
Civicrm 5.63.1

File: api/v3/MosaicoTemplate.php b/api/v3/MosaicoTemplate.php
Changing the line 81:

From: $currentURL = CRM_Utils_System::baseURL() . $templatePath;
To: $currentURL = CRM_Utils_File::addTrailingSlash(CIVICRM_UF_BASEURL, '/') . $templatePath; } else {

:-)

@Rar9
Copy link

Rar9 commented Sep 28, 2023

Ubuntu 22.04 + plesk Nginx
Drupal 7.98
php 7.4
CiviCRM 5.65.2
Mosaico: Version 3.2.1691060437

applied [CsarRamos] patch to get civicrm/mosaico-template-list to show again, as before i got an api error

Same on D9.5xx with php 8.1

But my versafix-1 is still showing up GREY..... any hints?

@MegaphoneJon
Copy link
Contributor

MegaphoneJon commented Oct 17, 2023

@Rar9 I had the same situation. When I ran this SQL:

SELECT id, metadata from civicrm_mosaico_template;

I saw that many of my template paths as stored in the database already had the language prefaced. See below. Template 42 is fine, template 43 has the unwanted fr\/fr\/fr\/fr\.

| 42 | {"template":"sites\/all\/civicrm\/mosaico_tpl\/versafix-myorg\/template-versafix-myorg.html","name":"No name","created":1687878458444,"editorversion":"0.15.0","template
version":"1.0.5","changed":1687878493374}                                                      |                                                                             
| 43 | {"template":"fr\/fr\/fr\/fr\/sites\/all\/civicrm\/mosaico_tpl\/versafix-myorg\/template-versafix-myorg.html","name":"No name","created":1626442188977,"editorversion":"0
.18.10","templateversion":"1.0.5","changed":1696345747532}                                     |  

To fix this, I ran this query. Note that the preface might be different for you, mine is fr for French.

UPDATE civicrm_mosaico_template  SET metadata = REPLACE(metadata, 'fr\\/', '')

@Rar9
Copy link

Rar9 commented Oct 18, 2023

@MegaphoneJon

with SELECT id, metadata from civicrm_mosaico_template;
i get all templates. The

This works

{"template":"sites\/default\/files\/civicrm\/ext\/uk.co.vedaconsulting.mosaico\/packages\/mosaico\/templates\/tedc15\/template-tedc15.html","name":"No name","created":1683882714705,"editorversion":"0.15.0","changed":1683882718721}

this only shows gray with Mosaico Version 3.3.1697392242 - See Screenshot also path looks good.

{"template":"sites\/default\/files\/civicrm\/ext\/uk.co.vedaconsulting.mosaico\/packages\/mosaico\/templates\/versafix-1\/template-versafix-1.html","name":"No name","created":1683889421065,"editorversion":"0.15.0","templateversion":"1.0.6","changed":1683896178235}

Console Error - Ignor Url as it was form other debug

2023-10-18_11-28

@demeritcowboy
Copy link
Contributor

demeritcowboy commented Dec 7, 2023

I am confused by a few things in the mosaicotemplate api functions:

  1. In create, it seems intended to store a relative path. Let's assume for the moment that the template path comes in without the prefix and so is ok (this matches my testing):
    // Check if domain name exists in the URL and remove it. Storing the relative path to get the templates work with multi domain sites.
    if (_civicrm_api3_mosaico_template_getDomainFrom($baseTemplateURL)) {
    $urlParts = parse_url($baseTemplateURL);
    $templatePath = trim($urlParts['path'], '/');
    } else {
    $templatePath = $baseTemplateURL;
    }
    $metaData['template'] = $templatePath;
    $params['metadata'] = json_encode($metaData);
    }
    return _civicrm_api3_basic_create('CRM_Mosaico_BAO_MosaicoTemplate', $params);
  2. Now, keeping in mind we've always stored a relative path, let's look at the get() function:
    if (_civicrm_api3_mosaico_template_getDomainFrom($baseTemplateURL)) {
    $urlParts = parse_url($baseTemplateURL);
    $templatePath = $urlParts['path'];
    $currentURL = CRM_Utils_System::baseURL() . $templatePath;
    } else {
    $currentURL = $baseTemplateURL;
    }
  3. Look at the _civicrm_api3_mosaico_template_getDomainFrom() function that get() calls:
    $pieces = parse_url($url);
    $domain = isset($pieces['host']) ? $pieces['host'] : $pieces['path'];
    if (preg_match('/(?P<domain>[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i', $domain, $regs)) {
    return $regs['domain'];
  4. First it parses the url, but remember we're storing a relative path, so host will always be empty and so it sets the $domain to check to the path part. (Why this fallback? Why not return as FALSE at this point?)
  5. Then look at that regex. It looks at the last 2 dot-separated components of the string. Well, in a path, that's always going to be template-versafix-1.html or whatever the filename is. Unless your template file is weirdly named, this will ALWAYS match. So it ALWAYS thinks it's a multisite (not multilingual, but multisite which is what this function was added for).
  6. Now go back and look at line 81. It will then take the path and prepend CRM_Utils_System::baseURL(). At /admin/config/regional/language/detection/url, you have an option to set a prefix or not for the default language. Assuming it's english, and you put "en" in there, then baseURL() will return the url with "en" in it. So that's where the "en" is coming from.

Even if I hack it to think it's not multisite, I still run into another problem, which seems to be more related to #624.

@jofranz
Copy link

jofranz commented Jan 9, 2024

I created #629 as a PR with a suggested fix. People testing it would be appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests