Skip to content

Instantly share code, notes, and snippets.

@hereswhatidid
Last active December 11, 2019 08:50
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hereswhatidid/8c8edef106ee95138b03 to your computer and use it in GitHub Desktop.
Save hereswhatidid/8c8edef106ee95138b03 to your computer and use it in GitHub Desktop.
PrestaShop Media class override to allow for forcing some inline JavaScripts to remain inline.
<p>Some HTML goes here</p>
<script type="text/javascript" data-keepinline="true">
// this script will remain here when rendered
alert( "hello!" );
</script>
<script type="text/javascript">
// this script will be forced to the bottom of the page
alert( "hello again!" );
</script>
<?php
Class Media extends MediaCore
{
public static function deferScript($matches)
{
if (!is_array($matches))
return false;
$inline = '';
if (isset($matches[0]))
$original = trim($matches[0]);
if (isset($matches[1]))
$inline = trim($matches[1]);
/* This is an inline script, add its content to inline scripts stack then remove it from content */
if (!empty($inline) && preg_match('/<\s*script(?!.*data-keepinline)[^>]*>/ims', $original) !== 0 && Media::$inline_script[] = $inline)
return '';
/* This is an external script, if it already belongs to js_files then remove it from content */
preg_match('/src\s*=\s*["\']?([^"\']*)[^>]/ims', $original, $results);
if (isset($results[1]) && (in_array($results[1], Context::getContext()->controller->js_files) || in_array($results[1], Media::$inline_script_src)))
return '';
/* return original string because no match was found */
return $original;
}
}
@pgumiela
Copy link

I found it very helpful on PrestaShop 1.6.0.8. Thank you.

@michaelhjulskov
Copy link

Thank You very much - this almost solved all my problems.
I still have an issue though (tag manager telling me "Missing line breaks may cause issues.")
when I turn on compress javascript, the minify/compress function alters the content inside the script tag.
Im looking for a way to avoid that any changes at all is made inside script. I tried using literal, didnt work.

@michaelhjulskov
Copy link

I made an approach.
But there are some issues with it.
among them is that // become //
resulting in error from tag manager "Missing CDATA comments."

public static function packJSinHTML($html_content)
{
    if (strlen($html_content) > 0)
    {
        // Michael Hjulskov
        // This is an inline script, add its content to inline scripts stack then remove it from content
        if (preg_match('/<\s*script(?!.*data-keepinline)[^>]*>/ims', $html_content) == 0)
            return $html_content;
        // end Michael Hjulskov
        return parent::packJSinHTML($html_content);
    }
    return false;
}

@testers3
Copy link

hi, may i know the correct way of inserting the file?
1.) paste the media.php file to override/classes.
2.) paste the following code to cache/class_index.php
'Media' =>
array (
'path' => 'override/classes/Media.php',
'type' => 'class',
)

Problem: i cannot find cache/class_index.php
I only have cache/index.php file

Do we need to place example.tpl to anywhere?

Hope some guru can advice a little. thanks

@gRoussac
Copy link

gRoussac commented Sep 1, 2015

Hi,

Thank you for your gist and sorry for late reply

I made this PR https://github.com/PrestaShop/PrestaShop/pull/3875/files that should enable your recommandation.

Regards

@javiBertos
Copy link

If you want to prevent to compress a block of JS code to prevent problems (f.e. google retargeting code), I've added this code to the Media override class:

public static function packJSinHTMLpregCallback($preg_matches)
  {
    if (!(trim($preg_matches[2])))
      return $preg_matches[0];

      $preg_matches[1] = $preg_matches[1].'/* <![CDATA[ */';
    if (preg_match('/<\s*script.*(data-nocompress)[^>]*>/ims', $preg_matches[1]) !== 0) {
      $preg_matches[2] = preg_replace('/\n?\s*\/\*\s*\*\/\n?/ims', "\n", $preg_matches[2]);
    } else {
      $preg_matches[2] = Media::packJS($preg_matches[2]);
    }
      $preg_matches[count($preg_matches) - 1] = '/* ]]> */'.$preg_matches[count($preg_matches) - 1];

    unset($preg_matches[0]);

    $output = implode('', $preg_matches);
    return $output;
  }

And in your script line, you must add data-nocompress="true"

I hope it would be helpful for you.

Regards!

@patrykmarek
Copy link

hello gRoussac there is one problem with Your commit original code written by hereswhatidid do keep-inline as well for external js code and that was important for code like conversion sale form gogole, i developed many modules which i sell in addons marketplace and now their are not working at all because of that changes you made :-) can you add as well to keep-inline work on external files.

@Hop-Seb
Copy link

Hop-Seb commented Sep 7, 2016

Hi everybody !

I am using prestashop 1.6.1.4. And these codes don't work for me.

The most important for me it's this code :

public static function packJSinHTMLpregCallback($preg_matches)
  {
    if (!(trim($preg_matches[2])))
      return $preg_matches[0];

      $preg_matches[1] = $preg_matches[1].'/* <![CDATA[ */';
    if (preg_match('/<\s*script.*(data-nocompress)[^>]*>/ims', $preg_matches[1]) !== 0) {
      $preg_matches[2] = preg_replace('/\n?\s*\/\*\s*\*\/\n?/ims', "\n", $preg_matches[2]);
    } else {
      $preg_matches[2] = Media::packJS($preg_matches[2]);
    }
      $preg_matches[count($preg_matches) - 1] = '/* ]]> */'.$preg_matches[count($preg_matches) - 1];

    unset($preg_matches[0]);

    $output = implode('', $preg_matches);
    return $output;
  }

By

javiBertos

I have overrided the Media class and deleted the index cache but when I add a script like Google Tag Manager or another, it doesn't work.
When I want to call the function I do :

<script data-nocompress="true" >
[...]
</script>

May I have help please !

Thank you so much...

@jayasilen
Copy link

Hi,

With regards to the script below, is it necessary? Also how do we know that the script already belongs to js_files? Which file/folder should we refer to?

/* This is an external script, if it already belongs to js_files then remove it from content */ preg_match('/src\s*=\s*["\']?([^"\']*)[^>]/ims', $original, $results); if (array_key_exists(1, $results)) { if (substr($results[1], 0, 2) == '//') { $protocol_link = Tools::getCurrentUrlProtocolPrefix(); $results[1] = $protocol_link.ltrim($results[1], '/'); } if (preg_match('/<\s*script(?!.*data-keepinline)[^>]*>/ims', $original) !== 0) { if (in_array($results[1], Context::getContext()->controller->js_files) || in_array($results[1], Media::$inline_script_src)) return ''; } else { Context::getContext()->controller->removeJS($results[1]); } }

@mikemania
Copy link

mikemania commented Apr 13, 2017

In PS 1.6.1.11 it seems a set of empty script tags are created at the end for me.

<script type="text/javascript">
<script>
</script>

@Alkarin
Copy link

Alkarin commented Sep 20, 2017

I can not seem to find override/classes/Media.php in my wordpress project.
Is this directory specific to the prestashop theme? As I'm having this issue with the Scalia theme, and can not find where to place this code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment