Implemented Email templates relative paths
- Sakis Terz
-
Topic Author
- Offline
Less
More
- Posts: 37
- Thank you received: 0
6 months 4 days ago #3121
by Sakis Terz
Email templates relative paths was created by Sakis Terz
Hi Ruud
I am using some links and some images in my email templates, but every time i re-open them the urls become relevant (e.g. <a href="subscribe").
Not sure if there is some filtering from the editor or is coming from your code.
Any idea?
Kind regards,
I am using some links and some images in my email templates, but every time i re-open them the urls become relevant (e.g. <a href="subscribe").
Not sure if there is some filtering from the editor or is coming from your code.
Any idea?
Kind regards,
Please Log in to join the conversation.
- Ruud van Lent
-
- Offline
Less
More
- Posts: 1700
- Thank you received: 110
6 months 4 days ago #3122
by Ruud van Lent
Replied by Ruud van Lent on topic Email templates relative paths
Hi Sakis,
that is a editor 'feature' that (depending on your editor) can be turned on / off: note that this is then generic so when turning it off it will also be turned off in other extensions.
What I do is before saving the email template, turn off the editor (and check if all URL's are still absolute)
that is a editor 'feature' that (depending on your editor) can be turned on / off: note that this is then generic so when turning it off it will also be turned off in other extensions.
What I do is before saving the email template, turn off the editor (and check if all URL's are still absolute)
Please Log in to join the conversation.
- Ruud van Lent
-
- Offline
Less
More
- Posts: 1700
- Thank you received: 110
6 months 3 days ago - 6 months 3 days ago #3123
by Ruud van Lent
Replied by Ruud van Lent on topic Email templates relative paths
Hi Sakis,
so did a deeper dive into this to see if I can improve
In the email send ochSubscriptions adds the following line:
<base href="[your domain]" />
What this does / should do, is instruct the email client to make a relative url (e.g. test-url) absolute (so: [your domain]/test-url)
This way you can use both absolute and relative urls in your email templates as these will then be handled by the email client.
but... what if the email client doesn't use / respect the 'base href' setting? Then the absolute urls will work, but the relative urls will not (as these point to nowhere).
tinyMCE can be configured to store urls as relative or absolute: this has impact on everything the editor is used for, so when changing it to store absolute urls (which we want in emails) then also in articles all urls will be absolute (which we don't want)...
So in the version above I have a version of ochSubscriptions that will convert all elements (a, img, link, script, form, input, video, audio, source) in the email template to absolute URLs when rendering and sending the email (so not in the template itself).
This way you can either use absolute or relative urls: absolute will stay unchanged 9as these can also point to another website) and relative urls will be made absolute pointing to your site.
Can you give this a test to see if it works as intended and solves this url nightmare
so did a deeper dive into this to see if I can improve

In the email send ochSubscriptions adds the following line:
<base href="[your domain]" />
What this does / should do, is instruct the email client to make a relative url (e.g. test-url) absolute (so: [your domain]/test-url)
This way you can use both absolute and relative urls in your email templates as these will then be handled by the email client.
but... what if the email client doesn't use / respect the 'base href' setting? Then the absolute urls will work, but the relative urls will not (as these point to nowhere).
tinyMCE can be configured to store urls as relative or absolute: this has impact on everything the editor is used for, so when changing it to store absolute urls (which we want in emails) then also in articles all urls will be absolute (which we don't want)...
So in the version above I have a version of ochSubscriptions that will convert all elements (a, img, link, script, form, input, video, audio, source) in the email template to absolute URLs when rendering and sending the email (so not in the template itself).
This way you can either use absolute or relative urls: absolute will stay unchanged 9as these can also point to another website) and relative urls will be made absolute pointing to your site.
Can you give this a test to see if it works as intended and solves this url nightmare

Last edit: 6 months 3 days ago by Ruud van Lent. Reason: new download versions!
Please Log in to join the conversation.
- Sakis Terz
-
Topic Author
- Offline
Less
More
- Posts: 37
- Thank you received: 0
3 months 3 weeks ago - 3 months 3 weeks ago #3171
by Sakis Terz
Replied by Sakis Terz on topic Email templates relative paths
Hi Ruud
Sorry for the late reply. I tried both the [your domain] and [your_domain] and they do not work.
Btw. I see that the email placeholders are using curly braces {}
Kind regards,
Sakis
Sorry for the late reply. I tried both the [your domain] and [your_domain] and they do not work.
Btw. I see that the email placeholders are using curly braces {}
Kind regards,
Sakis
Last edit: 3 months 3 weeks ago by Sakis Terz.
Please Log in to join the conversation.
- Ruud van Lent
-
- Offline
Less
More
- Posts: 1700
- Thank you received: 110
3 months 3 weeks ago - 3 months 3 weeks ago #3172
by Ruud van Lent
Replied by Ruud van Lent on topic Email templates relative paths
Hi Sakis,
I think there is some confusion. With [you domain] I mean you actual website domain.
So on my server that would be:
I think there is some confusion. With [you domain] I mean you actual website domain.
So on my server that would be:
- https
/onlinecommunityhub .nl/testlink
- or /testlink
Last edit: 3 months 3 weeks ago by Ruud van Lent.
Please Log in to join the conversation.
- Sakis Terz
-
Topic Author
- Offline
Less
More
- Posts: 37
- Thank you received: 0
3 months 3 weeks ago #3173
by Sakis Terz
Replied by Sakis Terz on topic Email templates relative paths
But my problem is exactly that, when I enter my actual domain, it gets stripped. This happen only with my domain. If I use urls pointing to outside domains it works.
Is there a placeholder I could use, instead of my actual domain?
Is there a placeholder I could use, instead of my actual domain?
Please Log in to join the conversation.
- Sakis Terz
-
Topic Author
- Offline
Less
More
- Posts: 37
- Thank you received: 0
3 months 3 weeks ago #3174
by Sakis Terz
Replied by Sakis Terz on topic Email templates relative paths
Btw /testlink stays as is in the actual email message, leading nowhere
Please Log in to join the conversation.
- Ruud van Lent
-
- Offline
Less
More
- Posts: 1700
- Thank you received: 110
3 months 3 weeks ago #3175
by Ruud van Lent
Replied by Ruud van Lent on topic Email templates relative paths
What version of ochSubscriptions do you have installed?
In version 4.0.1 I have added the updated logic to always add the local domain name to the url: so when the editor strips it, when ochSubscriptions renders the email text from the template it will add it back
In version 4.0.1 I have added the updated logic to always add the local domain name to the url: so when the editor strips it, when ochSubscriptions renders the email text from the template it will add it back
Please Log in to join the conversation.
- Sakis Terz
-
Topic Author
- Offline
Less
More
- Posts: 37
- Thank you received: 0
3 months 3 weeks ago #3176
by Sakis Terz
Replied by Sakis Terz on topic Email templates relative paths
Thanks for that!
I am currently on 3.13.3
Is 4.0.1 compatible with J4?
I am currently on 3.13.3
Is 4.0.1 compatible with J4?
Please Log in to join the conversation.
- Ruud van Lent
-
- Offline
Less
More
- Posts: 1700
- Thank you received: 110
3 months 3 weeks ago #3177
by Ruud van Lent
Replied by Ruud van Lent on topic Email templates relative paths
No it is not.
in your current install, locate file ContentConstructor.php and replace the function "prepareEmailBody" with the one below:
BACKUP and TEST
in your current install, locate file ContentConstructor.php and replace the function "prepareEmailBody" with the one below:
BACKUP and TEST

Code:
/**
* Function to prepare the Email body; add necessary HTML elements and framework
*
* @param string $body The body of the email
* @param string $subject The subject of the email
* @param string $style The style (css) of the email
*
* @return string
*/
private function prepareEmailBody($body, $subject, $style)
{
$charset = Factory::getApplication()->getDocument()->getCharset();
$preparedBody = '<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">' . "\n";
$preparedBody .= '<head>' . "\n";
$preparedBody .= '<!--[if gte mso 9]><xml><o:OfficeDocumentSettings><o:AllowPNG/><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml><![endif]-->' . "\n";
$preparedBody .= '<meta http-equiv="Content-Type" content="text/html; charset=' . strtolower($charset) . '" />' . "\n";
$preparedBody .= '<meta name="viewport" content="width=device-width, initial-scale=1.0" />' . "\n";
$preparedBody .= '<base href="' . Uri::root(false) . '" />' . "\n";
$preparedBody .= '<title>' . $subject . '</title>' . "\n";
$preparedBody .= $style;
$preparedBody .= '</head>' . "\n";
$preparedBody .= '<body yahoo="fix">' . $body . '</body>' . "\n";
$preparedBody .= '</html>';
// Load HTML content into DOMDocument
$dom = new \DOMDocument();
libxml_use_internal_errors(true); // Suppress warnings due to malformed HTML
$dom->loadHTML($preparedBody);
libxml_clear_errors();
$baseUrl = Uri::root(false);
// Define elements and attributes to be checked for relative URLs
$elementsToCheck = [
'a' => 'href',
'img' => 'src',
'link' => 'href',
'script' => 'src',
'form' => 'action',
'input' => 'src',
'video' => 'src',
'audio' => 'src',
'source' => ['src', 'srcset']
];
// Loop through each element and attribute in the list
foreach ($elementsToCheck as $tag => $attributes) {
$attributes = (array) $attributes; // Ensure it's an array for easy iteration
foreach ($dom->getElementsByTagName($tag) as $element) {
foreach ($attributes as $attribute) {
$url = $element->getAttribute($attribute);
// Check if the attribute value is a relative URL
if ($url) {
if (\strpos($url, $baseUrl) === 0) {
// Remove the base URL portion to make it relative
$url = \substr($url, \strlen($baseUrl));
$element->setAttribute($attribute, $url);
}
if (\parse_url($url, PHP_URL_SCHEME) === null) {
// Prepend base URL if it's a relative path
$element->setAttribute($attribute, \rtrim($baseUrl, '/') . '/' . \ltrim($url, '/'));
}
}
}
}
}
// // Handle inline styles (for background images)
// foreach ($dom->getElementsByTagName('*') as $element) {
// $style = $element->getAttribute('style');
// if (preg_match('/url\([\'"]?\/([^\'")]+)[\'"]?\)/i', $style, $matches)) {
// // Replace relative URL with absolute URL in the style attribute
// $absoluteUrl = rtrim($baseUrl, '/') . '/' . ltrim($matches[1], '/');
// $newStyle = str_replace($matches[0], "url('$absoluteUrl')", $style);
// $element->setAttribute('style', $newStyle);
// }
// }
// Save updated HTML content
$preparedBody = $dom->saveHTML();
return $preparedBody;
}
Please Log in to join the conversation.