Add external.

Parameters

array $js: JS array.

array $scripts_found: An array of inline scripts found and locations for them in the file.

Related topics

2 calls to advagg_relocate_js_script_rewrite()
advagg_relocate_advagg_get_js_file_contents_alter in advagg_relocate/advagg_relocate.advagg.inc
Implements hook_advagg_get_js_file_contents_alter().
advagg_relocate_js_post_alter in advagg_relocate/advagg_relocate.module
Alter the js array.

File

advagg_relocate/advagg_relocate.module, line 547

Code

function advagg_relocate_js_script_rewrite(array &$js, array $scripts_found) {
    // Move inline code to external if possible.
    foreach ($scripts_found as $key_name => $values) {
        if ($key_name === 'analytics.js') {
            list($key, $start, $middle, $end) = $values;
            $value = $js[$key];
            // Get analytics.js URL and add it to the js array.
            $analytics_js_url = substr($value['data'], $middle + 29, $end - strlen($value['data']) - 1);
            $insert = array(
                $analytics_js_url => array(
                    'data' => $analytics_js_url,
                    'type' => 'external',
                    'async' => TRUE,
                    'defer' => TRUE,
                    'noasync' => FALSE,
                    'nodefer' => FALSE,
                ),
            );
            $js = advagg_insert_into_array_at_key($js, $insert, $key);
            $js[$analytics_js_url] += $value;
            // Fix if analytics.js is already local.
            $http_pos = strpos($analytics_js_url, 'http://');
            $https_pos = strpos($analytics_js_url, 'https://');
            $double_slash_pos = strpos($analytics_js_url, '//');
            if ($http_pos !== 0 && $https_pos !== 0 && $double_slash_pos !== 0) {
                $js[$analytics_js_url]['type'] = 'file';
            }
            // Shorten function arguments.
            $value['data'] = substr($value['data'], 0, $middle + 27) . substr($value['data'], $end);
            // Strip loader string.
            $value['data'] = substr($value['data'], 0, $start + 132) . substr($value['data'], $middle);
            // Shorten function parameters.
            $value['data'] = str_replace('function(i,s,o,g,r,a,m){i["GoogleAnalyticsObject"]', 'function(i,s,o,r){i["GoogleAnalyticsObject"]', $value['data']);
            $js[$key]['pre_relocate_data'] = $js[$key]['data'];
            $js[$key]['data'] = $value['data'];
            // Pin to header as the js expects ga to be there.
            $js[$key]['scope'] = 'header';
            $js[$key]['scope_lock'] = TRUE;
            // Handle ga("require", ...) calls for external scripts to be loaded.
            $matches = array();
            preg_match_all('/ga\\([\'"]require[\'"],\\s*[\'"][a-zA-Z0-9_ ]*[\'"],\\s*[\'"](.*?)[\'"]\\)/', $value['data'], $matches, PREG_SET_ORDER);
            foreach ($matches as $match) {
                // Remove inline js loader code.
                $start = strpos($js[$key]['data'], $match[0]);
                if ($start === FALSE) {
                    continue;
                }
                $strlen = strlen($match[0]);
                $js[$key]['data'] = substr($js[$key]['data'], 0, $start) . substr($js[$key]['data'], $start + $strlen);
                // Add script to the drupal js array.
                $url = '//www.google-analytics.com/plugins/ua/' . $match[1];
                $insert = array(
                    $url => array(
                        'data' => $url,
                        'type' => 'external',
                        'async' => TRUE,
                        'defer' => TRUE,
                        'noasync' => FALSE,
                        'nodefer' => FALSE,
                    ),
                );
                $js = advagg_insert_into_array_at_key($js, $insert, $analytics_js_url);
                $js[$url] += $value;
            }
        }
        if ($key_name === 'piwik.js') {
            list($key, $start, $middle) = $values;
            $value = $js[$key];
            // Get URL.
            $url = variable_get('matomo_url_http', '');
            if ($GLOBALS['is_https']) {
                // Use HTTPS.
                $url = variable_get('matomo_url_https', '');
            }
            if (is_callable('_matomo_cache') && variable_get('matomo_cache', 0) && ($matomo_cache = _matomo_cache($url . 'piwik.js'))) {
                // Try cache.
                $url = $matomo_cache;
            }
            if (empty($url)) {
                // Extract info from inline script.
                // "https:" == document.location.protocol ? "https://.../piwik/" : "http://.../piwik/".
                $pattern = '/[\'"]https\\:[\'"]\\s*==\\s*document\\.location\\.protocol.*?[\'"](.*?)[\'"]\\s*\\:\\s*[\'"](.*?)[\'"]/';
                preg_match($pattern, $value['data'], $matches);
                if ($GLOBALS['is_https'] && !empty($matches[1])) {
                    $url = $matches[1];
                }
                elseif (empty($GLOBALS['is_https']) && !empty($matches[2])) {
                    $url = $matches[2];
                }
            }
            if (!empty($url)) {
                // Use HTTP.
                // The $url may or may not have "piwik.js" at the end (it has if it came from _matomo_cache call above, otherwise not). Add if needed.
                $url = check_url($url);
                if (basename($url) != 'piwik.js') {
                    $url = $url . 'piwik.js';
                }
            }
            // Final checks.
            if (!empty($url)) {
                $scope = variable_get('matomo_js_scope', $value['scope']);
                $url = advagg_convert_abs_to_rel($url, TRUE);
                $type = 'file';
                if (advagg_is_external($url)) {
                    $parsed = parse_url($url);
                    if (strpos($parsed['path'], $GLOBALS['base_path']) === 0) {
                        $path = substr($parsed['path'], strlen($GLOBALS['base_path']));
                        if (file_exists($path)) {
                            $url = $path;
                        }
                        else {
                            $type = 'external';
                        }
                    }
                    else {
                        $type = 'external';
                    }
                }
                // Add to js array.
                $insert = array(
                    $url => array(
                        'scope' => $scope,
                        'data' => $url,
                        'type' => $type,
                        'async' => TRUE,
                        'defer' => TRUE,
                        'noasync' => FALSE,
                        'nodefer' => FALSE,
                    ),
                );
                $js = advagg_insert_into_array_at_key($js, $insert, $key);
                $matches = array();
                // s.parentNode.insertBefore(g,s);.
                $pattern = '/\\,?\\s*[\\w]{1,2}\\.parentNode\\.insertBefore\\(\\s*[\\w]{1,2}\\s*,\\s*[\\w]{1,2}\\s*\\)\\s*\\;*/';
                preg_match($pattern, $value['data'], $matches);
                // Strip loader string.
                $value['data'] = str_replace($matches[0], '', $value['data']);
                $js[$key]['pre_relocate_data'] = $js[$key]['data'];
                $js[$key]['data'] = $value['data'];
                // Pin to header as the js expects paq to be loaded before the file.
                $js[$key]['scope'] = 'header';
                $js[$key]['scope_lock'] = TRUE;
                $js[$key]['weight'] = -50000;
                $js[$key]['movable'] = FALSE;
            }
        }
        if ($key_name === 'gtm.js') {
            list($key, $start, $middle, $end) = $values;
            $value = $js[$key];
            // Get URL for script.
            $matches_a = array();
            preg_match('/j.src\\s*=\\s*[\'"](.*?);/', $value['data'], $matches_a);
            $matches_b = array();
            preg_match('/\\}\\)\\(window,document,[\'"]script[\'"],[\'"](.*?)[\'"],[\'"](.*?)[\'"]\\);/', $value['data'], $matches_b);
            if (empty($matches_a[1]) || empty($matches_b[1])) {
                continue;
            }
            if ($matches_b[1] !== 'dataLayer') {
                $matches_b[1] = '&l=' . $matches_b[1];
            }
            else {
                $matches_b[1] = '';
            }
            $gtm_url = trim(str_replace(array(
                "'+i",
                "+dl+'",
                "+dl",
            ), array(
                $matches_b[2],
                $matches_b[1],
                $matches_b[1],
            ), $matches_a[1]), "'");
            // Add script to the drupal js array.
            $insert = array(
                $gtm_url => array(
                    'data' => $gtm_url,
                    'type' => 'external',
                    'async' => TRUE,
                    'defer' => TRUE,
                    'noasync' => FALSE,
                    'nodefer' => FALSE,
                ),
            );
            $js = advagg_insert_into_array_at_key($js, $insert, $key);
            $js[$gtm_url] += $value;
            // Shorten function arguments.
            $args = explode(',', substr($value['data'], $end + 3, -2));
            $value['data'] = substr($value['data'], 0, $end + 9) . ",{$args[3]});";
            // Strip loader string.
            $value['data'] = substr($value['data'], 0, $middle) . substr($value['data'], $end);
            // Shorten function parameters.
            $value['data'] = str_replace('(function(w,d,s,l,i){', '(function(w,l){', $value['data']);
            // Add back.
            $js[$key]['pre_relocate_data'] = $js[$key]['data'];
            $js[$key]['data'] = $value['data'];
            // Pin to header as the js expects dataLayer to be there.
            $js[$key]['scope'] = 'header';
            $js[$key]['scope_lock'] = TRUE;
        }
        if ($key_name === 'fbds.js') {
            list($key, $start, $middle, $end) = $values;
            $value = $js[$key];
            // Get URL for script.
            $matches = array();
            preg_match('/fbds.src\\s*=\\s*[\'"](.*?)[\'"];/', $value['data'], $matches);
            if (empty($matches[1])) {
                continue;
            }
            $url = trim($matches[1]);
            // Add script to the drupal js array.
            $insert = array(
                $url => array(
                    'data' => $url,
                    'type' => 'external',
                    'async' => TRUE,
                    'defer' => TRUE,
                    'noasync' => FALSE,
                    'nodefer' => FALSE,
                ),
            );
            $js = advagg_insert_into_array_at_key($js, $insert, $key);
            $js[$url] += $value;
            // Strip loader string.
            $matches = array();
            preg_match('/if\\s*\\(!_fbq.loaded\\)\\s*\\{/', $value['data'], $matches, PREG_OFFSET_CAPTURE);
            $new_js = substr($value['data'], 0, $matches[0][1]);
            // Set loaded TRUE.
            $matches = array();
            preg_match('/_fbq.loaded\\s*=\\s*true/', $value['data'], $matches, PREG_OFFSET_CAPTURE);
            $new_js .= $matches[0][0] . ';';
            // Get the rest of the JS string.
            $end = strpos($value['data'], '}', $matches[0][1]);
            $new_js .= trim(substr($value['data'], $end + 1));
            $js[$key]['pre_relocate_data'] = $js[$key]['data'];
            $js[$key]['data'] = $new_js;
            // Pin to header as the js expects _fbq to be there.
            $js[$key]['scope'] = 'header';
            $js[$key]['scope_lock'] = TRUE;
        }
        if ($key_name === 'fbevents.js') {
            list($key, $start, $middle, $end) = $values;
            $value = $js[$key];
            // Add script to the drupal js array.
            $url = 'https://connect.facebook.net/en_US/fbevents.js';
            $insert = array(
                $url => array(
                    'data' => $url,
                    'type' => 'external',
                ),
            );
            $js = advagg_insert_into_array_at_key($js, $insert, $key);
            $js[$url] += $value;
            $before = substr($value['data'], 0, $start);
            $after = ltrim(substr($value['data'], $end + 40), ';');
            // Get all facebook pixel ids.
            $fb_ids = array_filter(array_map('trim', explode("\n", variable_get('advagg_relocate_js_fbevents_local_ids', ADVAGG_RELOCATE_JS_FBEVENTS_LOCAL_IDS))));
            $matches = array();
            preg_match('/fbq\\(\\s*[\'"]init[\'"]\\s*,\\s*[\'"](\\d+)[\'"]\\s*\\)/', $value['data'], $matches);
            if (!empty($matches[1])) {
                $fb_ids[] = $matches[1];
            }
            $fb_ids = array_filter($fb_ids);
            // Update in place the ids if any others were found inline.
            $GLOBALS['conf']['advagg_relocate_js_fbevents_local_ids'] = implode("\n", $fb_ids);
            // Get scripts before and after; replace middle of script.
            $new_js = $before . "!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;t.src=v;s=b.getElementsByTagName(e)[0]}(window,document,'script','//connect.facebook.net/en_US/fbevents.js');" . $after;
            $js[$key]['pre_relocate_data'] = $js[$key]['data'];
            $js[$key]['data'] = $new_js;
            // Pin to header as the js expects fbq to be there.
            $js[$key]['scope'] = 'header';
            $js[$key]['scope_lock'] = TRUE;
        }
        if ($key_name === 'perfectaudience.js') {
            list($key, $start, $middle, $end) = $values;
            $value = $js[$key];
            // Reindex.
            $matches = array();
            preg_match('/window\\._pa\\s*=\\s*window._pa\\s*\\|\\|\\s*\\{\\s*\\}\\s*;/', $value['data'], $matches, PREG_OFFSET_CAPTURE);
            if (!empty($matches[0][1])) {
                $start = $matches[0][1];
                $middle = strpos($value['data'], '//tag.perfectaudience.com/serve/', $start);
                $end = strpos($value['data'], 's.parentNode.insertBefore(pa, s);', $middle);
                $substr = substr($value['data'], $start, $end - $start + 35);
                $matches = array();
                preg_match('/\\.src\\s*=\\s*[\'"](\\/\\/tag.perfectaudience.com\\/serve\\/.*\\.js)[\'"]/', $substr, $matches);
                if (!empty($matches[1])) {
                    $url = $matches[1];
                    // Add script to the drupal js array.
                    $insert = array(
                        $url => array(
                            'data' => $url,
                            'type' => 'external',
                            'async' => TRUE,
                            'defer' => TRUE,
                            'noasync' => FALSE,
                            'nodefer' => FALSE,
                        ),
                    );
                    $js = advagg_insert_into_array_at_key($js, $insert, $key);
                    $js[$url] += $value;
                    // s.parentNode.insertBefore(pa, s);.
                    $pattern = '/\\,?\\s*[\\w]{1,2}\\.parentNode\\.insertBefore\\(\\s*[\\w]{1,2}\\s*,\\s*[\\w]{1,2}\\s*\\)\\s*\\;*/';
                    // Strip loader string.
                    $new_substr = preg_replace($pattern, '', $substr);
                    $js[$key]['data'] = str_replace($substr, $new_substr, $value['data']);
                }
            }
        }
        if ($key_name === 'uwt.js') {
            list($key, $start, $middle, $end) = $values;
            $value = $js[$key];
            $url = '//static.ads-twitter.com/uwt.js';
            // Add script to the drupal js array.
            $insert = array(
                $url => array(
                    'data' => $url,
                    'type' => 'external',
                    'scope_lock' => FALSE,
                    'scope' => 'footer',
                ),
            );
            $js = advagg_insert_into_array_at_key($js, $insert, $key);
            $js[$url] += $value;
            // Reindex.
            $start = strpos($value['data'], '!function(e,t,n,s,u,a){e.twq||');
            $middle = strpos($value['data'], '//static.ads-twitter.com/uwt.js', $start);
            $end = strpos($value['data'], "a.parentNode.insertBefore(u,a))}(window,document,'script');", $middle);
            $substr = substr($value['data'], $start, $end - $start + 61);
            // a.parentNode.insertBefore(u,a).
            $pattern = '/\\,?\\s*[\\w]{1,2}\\.parentNode\\.insertBefore\\(\\s*[\\w]{1,2}\\s*,\\s*[\\w]{1,2}\\s*\\)\\s*\\;*/';
            // Strip loader string.
            $new_substr = preg_replace($pattern, '', $substr);
            $js[$key]['data'] = str_replace($substr, $new_substr, $value['data']);
        }
        if ($key_name === 'linkedin_insight.js') {
            list($key, $start, $middle, $end) = $values;
            $value = $js[$key];
            $url = 'https://snap.licdn.com/li.lms-analytics/insight.min.js';
            // Add script to the drupal js array.
            $insert = array(
                $url => array(
                    'data' => $url,
                    'type' => 'external',
                    'async' => TRUE,
                    'defer' => TRUE,
                    'noasync' => FALSE,
                    'nodefer' => FALSE,
                ),
            );
            $js = advagg_insert_into_array_at_key($js, $insert, $key);
            $js[$url] += $value;
            $start = strpos($value['data'], '_linkedin_data_partner_id');
            $middle = strpos($value['data'], '//snap.licdn.com/li.lms-analytics/insight.min.js', $start);
            $end = strpos($value['data'], "s.parentNode.insertBefore(b, s)", $middle);
            $substr = substr($value['data'], $start, $end - $start + 35);
            // a.parentNode.insertBefore(u,a).
            $pattern = '/\\,?\\s*[\\w]{1,2}\\.parentNode\\.insertBefore\\(\\s*[\\w]{1,2}\\s*,\\s*[\\w]{1,2}\\s*\\)\\s*\\;*/';
            // Strip loader string.
            $new_substr = preg_replace($pattern, '', $substr);
            $js[$key]['data'] = str_replace($substr, $new_substr, $value['data']);
        }
    }
}