After trying a few ideas this is what really solved this issue:
- First the utm should be captured before the redirection happens and thus the 'wp' hook should be used.
- To persists the captured utms, those are stored in a session variable
- When the post is called in single.php file, pull the session variable
in functions.php
function capture_utm () {
if (!session_id()) {
session_start();
}
if (is_single()) {
$requested_url = $_SERVER['REQUEST_URI'];
if (strpos($requested_url, 'utm_') !== false) {
parse_str($_SERVER['QUERY_STRING'], $query_params);
$utm_params = array_filter($query_params, function ($key) {
return strpos($key, 'utm_') === 0;
}, ARRAY_FILTER_USE_KEY);
$_SESSION['utm_params'] = $utm_params;
}
}
}
add_action('wp', 'capture_utm');
Then in single.php file:
<?php
if (isset($_SESSION['utm_params']) && !empty($_SESSION['utm_params'])) {
$utm_query = json_encode($_SESSION['utm_params']);
?>
<script>
document.addEventListener('DOMContentLoaded', function(){
let currentURL = window.location.href;
let utmParameters = <?php echo $utm_query; ?>
if (Object.keys(utmParameters).length > 0) {
utmQueryString = Object.entries(utmParameters)
.map(function (entry) {
return entry.join('=');
})
.join('&');
let newURL = currentURL + (currentURL.includes('?') ? '&' : '?') + utmQueryString;
window.history.replaceState({}, document.title, newURL);
}
}, false);
</script>
<?php
unset($_SESSION['utm_params']);
}
This pass the utms to the page and any click on it is captured by Google GTM. Single PHP file should start a session somewhere though with session_start().