コード例 #1
0
ファイル: tags.php プロジェクト: ConversionWorks/ExplainGTM
function getGeneralDetails($tag, $typeString = '', $whatItDoes = '')
{
    global $tagLibrary, $tagTypes, $container, $usedTriggers, $trigLibrary, $trigTypes, $untriggeredTags, $userIdUsed, $legacyTags, $folderArray, $usedUdvs, $udvUsage;
    $technicalDetails = '';
    $rawHTML = getParam($tag, 'html');
    $deets = '<table class="table table-bordered table-striped">';
    $deets = $deets . '<tr><th>Name</th><td>' . $tag['name'] . '</td></tr>';
    $deets = $deets . '<tr><th>Type</th><td>' . $typeString . '</td></tr>';
    $deets = $deets . '<tr><th>What it does</th>';
    if ($whatItDoes === '') {
        if ($rawHTML !== '') {
            $containsScript = strpos($rawHTML, '<script') > -1 ? 'contains JavaScript' : 'contains HTML';
            $deets = $deets . '<td>This tag ' . $containsScript . '. Being a custom tag, you need to make sure this is carefully reviewed by your developers.<br />';
            $deets = $deets . '<textarea class="form-control" rows="10" cols="60" disabled="disabled">' . $rawHTML . '</textarea></td></tr>';
            if (getParam($tag, 'supportDocumentWrite') === 'true') {
                $deets = $deets . '<tr><th></th><td>This tag supports document.write.</td></tr>';
            }
        }
        if (getParam($tag, 'trackType') !== '') {
            $deets = $deets . humanDetails(getParam($tag, 'trackType'), $tag);
        }
        if (getParam($tag, 'enableEcommerce') === 'true') {
            $deets = $deets . '<br />This tag uses Enhanced Ecommerce tracking features.<br />';
            if (getParam($tag, 'useEcommerceDataLayer') === 'true') {
                $deets = $deets . 'The Data Layer is used to record the Enhanced Ecommerce data (<b>Technical!</b>)<br />';
            } else {
                if (getParamTemplate($tag, 'ecommerceMacroData') !== '' && array_key_exists('value', getParamTemplate($tag, 'ecommerceMacroData'))) {
                    $deets = $deets . variablise(getParamTemplate($tag, 'ecommerceMacroData')['value'], $tag, true) . ' is used to record the Enhanced Ecommerce data (<b>Technical!</b>)<br />';
                }
            }
            $deets = $deets . '</td></tr>';
        } else {
            $deets = $deets . '</tr>';
        }
        if (getParam($tag, 'trackingId') !== '') {
            $deets = $deets . '<tr><th>The GA property ID is</th><td>' . translateToHuman(getParam($tag, 'trackingId'), $tag, true) . '</td></tr>';
        }
    } else {
        $deets = $deets . $whatItDoes;
    }
    $deets = $deets . '<tr><th>When it does it</th>';
    /******************************************************************************
       Firing triggers
       ******************************************************************************/
    if (array_key_exists('firingTriggerId', $tag) && count($tag['firingTriggerId']) > 0) {
        $triggerFound = false;
        $triggerLink = '';
        $firingTrigArray = [];
        if (count($tag['firingTriggerId']) > 1) {
            $triggerLink = '<td>This tag is fired by the following triggers:<ul>';
            foreach ($tag['firingTriggerId'] as $tagFiringKey => $tagFiringVal) {
                if (!array_search($tag['firingTriggerId'][$tagFiringKey], $usedTriggers)) {
                    array_push($usedTriggers, $tag['firingTriggerId'][$tagFiringKey]);
                }
                $triggerFound = false;
                foreach ($trigTypes as $trigTypeKey => $trigTypeVal) {
                    foreach ($trigLibrary[$trigTypeVal] as $trigKey => $trigVal) {
                        if ($tag['firingTriggerId'][$tagFiringKey] === $trigLibrary[$trigTypeVal][$trigKey]['triggerId']) {
                            $triggerLink = $triggerLink . buildTriggerLink($tag['firingTriggerId'][$tagFiringKey], '<li>', '</li> ', $trigLibrary, $trigTypes);
                            $triggerFound = true;
                        }
                    }
                }
                if ($triggerFound === false) {
                    $triggerLink = $triggerLink . '<li>Built-in <span title="This tag will fire on literally ALL PAGES!" style="background-color: #CCC"><b>All Pages</b></span> trigger.</li>';
                }
            }
            $deets = $deets . $triggerLink . '</ul></td></tr>';
        } else {
            if (!array_search($tag['firingTriggerId'][0], $usedTriggers)) {
                array_push($usedTriggers, $tag['firingTriggerId'][0]);
            }
            $triggerLink = buildTriggerLink($tag['firingTriggerId'][0], '<td>This tag is fired by the ', ' trigger. </td></tr>', $trigLibrary, $trigTypes);
            if ($triggerLink === '') {
                $deets = $deets . '<td>This tag is fired by the built-in <span title="This tag will fire on literally ALL PAGES!" style="background-color: #CCC"><b>All Pages</b></span> trigger.</td></tr>';
            } else {
                $deets = $deets . $triggerLink;
            }
        }
    } else {
        $deets = $deets . '<td>This tag <i>appears</i> to have <span title="This tag will NOT fire." style="background-color: #CCC"><b>no firing triggers</b></span>.</td></tr>';
        array_push($untriggeredTags, $tag);
    }
    /******************************************************************************
       Blocking triggers
       ******************************************************************************/
    if (array_key_exists('blockingTriggerId', $tag) && count($tag['blockingTriggerId']) > 0) {
        $deets = $deets . '<tr><th>When it is <b>stopped</b> from doing it</th>';
        $triggerFound = false;
        $blockingTrigArray = [];
        if (count($tag['blockingTriggerId']) > 1) {
            $triggerLink = '<td>This tag is blocked by the following triggers.<ul>';
            foreach ($tag['blockingTriggerId'] as $blockingTrigKey => $blockingTrigVal) {
                $triggerFound = false;
                foreach ($trigTypes as $trigTypeKey => $trigTypeVal) {
                    foreach ($trigLibrary[$trigTypeVal] as $trigKey => $trigVal) {
                        if ($tag['blockingTriggerId'][$blockingTrigKey] === $trigLibrary[$trigTypeVal][$trigKey]['triggerId']) {
                            $triggerLink = $triggerLink . buildTriggerLink($tag['blockingTriggerId'][$blockingTrigKey], '<li>', '</li> ');
                            $triggerFound = true;
                        }
                    }
                }
                if ($triggerFound === false) {
                    $triggerLink = $triggerLink . '<li>Built-in <span title="This tag will be blocked on literally ALL PAGES!" style="background-color: #CCC"><b>All Pages</b></span> trigger.</li>';
                }
            }
            $deets = $deets . $triggerLink . '</ul></td></tr>';
        } else {
            $triggerLink = buildTriggerLink($tag['blockingTriggerId'][0], '<td>This tag is <b>BLOCKED</b> by the ', ' trigger. </td></tr>', $trigLibrary, $trigTypes);
            if ($triggerLink === '') {
                $deets = $deets . '<td>This tag is <b>BLOCKED</b> by the built-in <span title="This tag be blocked on literally ALL PAGES!" style="background-color: #CCC"><b>All Pages</b></span> trigger.</td></tr>';
            } else {
                $deets = $deets . $triggerLink;
            }
        }
    }
    if (array_key_exists('scheduleStartMs', $tag)) {
        $deets = $deets . '<tr><th>Custom firing schedule start</th><td>The tag will only be live from ' . date('Y-m-d H:i:s', (int) $tag['scheduleStartMs'] / 1000);
        $nowDate = new DateTime();
        $startDate = new DateTime();
        $startDate->setTimestamp((int) $tag['scheduleStartMs'] / 1000);
        $interval = date_diff($nowDate, $startDate);
        if ($interval->invert === 1) {
            $deets = $deets . ' - this tag went live ' . $interval->format('%a days ago') . '.</td><tr>';
        }
        if ($interval->invert === 0) {
            $deets = $deets . ' - this will go live in ' . $interval->format('%a days') . '.</td><tr>';
        }
    }
    if (array_key_exists('scheduleEndMs', $tag)) {
        $deets = $deets . '<tr><th>Custom firing schedule end</th><td>The tag will only be live before ' . date('Y-m-d H:i:s', (int) $tag['scheduleEndMs'] / 1000);
        $nowDate = new DateTime();
        $endDate = new DateTime();
        $endDate->setTimestamp((int) $tag['scheduleEndMs'] / 1000);
        $interval = date_diff($nowDate, $endDate);
        if ($interval->invert === 1) {
            $deets = $deets . ' - this tag ended ' . $interval->format('%a days ago') . '. </td><tr>';
        }
        if ($interval->invert === 0) {
            $deets = $deets . ' - this tag will end in ' . $interval->format('%a days') . '.</td><tr>';
        }
    }
    /******************************************************************************
       Sequencing
       ******************************************************************************/
    $deets = $deets . sequence($tag);
    /******************************************************************************
       Firing priority
       ******************************************************************************/
    $deets = $deets . priority($tag);
    /******************************************************************************
       Firing Options
       ******************************************************************************/
    $humanFiringOption = array_key_exists('tagFiringOption', $tag) ? translateToHuman($tag['tagFiringOption'], $tag) : false;
    if ($humanFiringOption !== false) {
        $deets = $deets . '<tr><th></th><td>' . $humanFiringOption . '</td></tr>';
    }
    /******************************************************************************
       Published containers
       ******************************************************************************/
    if ($tag['liveOnly'] === 'true') {
        $deets = $deets . '<tr><th></th><td>This tag will only fire in published containers</td></tr>';
    }
    $deets = $deets . '<tr><th>Where it lives</th>';
    if (array_key_exists('parentFolderId', $tag)) {
        $deets = $deets . '<td>' . folderisation($tag['parentFolderId'], 'tag') . '</td></tr>';
    } else {
        $deets = $deets . '<td>' . folderisation(null, 'tag') . '</td></tr>';
    }
    if ($rawHTML !== '') {
        $varRefs = getVarRefs($rawHTML, $tag);
        if ($varRefs !== '') {
            $technicalDetails = $technicalDetails . 'Variables referenced in this tag:<br />' . $varRefs;
        }
    }
    /******************************************************************************
       Fields to Set (UA only)
       ******************************************************************************/
    $technicalDetails = $technicalDetails . fieldsToSet($tag);
    /******************************************************************************
       Custom Dimensions
       ******************************************************************************/
    $technicalDetails = $technicalDetails . dimensions($tag);
    /******************************************************************************
       Custom Metrics
       ******************************************************************************/
    $technicalDetails = $technicalDetails . metrics($tag);
    /******************************************************************************
       Custom Variables
       ******************************************************************************/
    $technicalDetails = $technicalDetails . cvars($tag);
    /******************************************************************************
       Mop up gnarly details
       ******************************************************************************/
    $technicalDetails = $technicalDetails . getGnarlyDetails($tag);
    if ($technicalDetails !== '') {
        $deets = $deets . '<tr><th></th><td>' . $technicalDetails . '</td></tr>';
    }
    $deets = $deets . '</table><br />';
    return $deets;
}
コード例 #2
0
ファイル: udvs.php プロジェクト: ConversionWorks/ExplainGTM
function udvDetail($udv, $typeString = '', $usage = '')
{
    $attributeName = '';
    $selectorType = '';
    $deets = '<h3>Details for User-defined variable <i>' . $udv['name'] . '</i></h3>';
    $deets = $deets . '<a href="https://tagmanager.google.com/#/container/accounts/' . $udv['accountId'] . '/containers/' . $udv['containerId'] . '/variables/' . $udv['variableId'] . '"';
    $deets = $deets . ' style="position:relative;float:right;top:-40px;right:10px;" class="udvEdit">edit</a>';
    $deets = $deets . '<table class="table table-bordered table-striped">';
    $deets = $deets . '<tr><th>Name</th><td>' . $udv['name'] . '</td></tr>';
    $deets = $deets . '<tr><th>What it\'s for</th><td>' . $typeString . '</td></tr>';
    $deets = $deets . '<tr><th>What it does</th>';
    $deets = $deets . '<td>' . $usage;
    if ($udv['type'] === 'd') {
        if (getParamTemplate($udv, 'attributeName') !== '') {
            $attributeName = array_key_exists('value', getParamTemplate($udv, 'attributeName')) ? getParamTemplate($udv, 'attributeName')['value'] : '';
        }
        if (getParamTemplate($udv, 'selectorType') !== '') {
            $selectorType = array_key_exists('value', getParamTemplate($udv, 'selectorType')) ? getParamTemplate($udv, 'selectorType')['value'] : '';
        }
        if ($selectorType !== '') {
            $selectorType = getParamTemplate($udv, 'selectorType')['value'];
            if ($selectorType === 'CSS') {
                $elementSelector = getParamTemplate($udv, 'elementSelector')['value'];
                $deets = $deets . '<br /><br />This variable will extract the "<b>' . variablise($attributeName, $udv) . '</b>" attribute from the first element on the page that matches the CSS selector "<b>' . variablise($elementSelector, $udv) . '</b>".<br /><br />';
                $deets = $deets . '<b>Warning</b>: This is not supported in IE7. IE8 and only supports CSS 2.1 selectors.<br />';
            }
            if ($selectorType === 'ID') {
                $elementId = getParamTemplate($udv, 'elementId')['value'];
                $deets = $deets . '<br /><br />This variable will extract the "<b>' . variablise($attributeName, $udv) . '</b>" attribute from the first element on the page with the ID "<b>' . variablise($elementId, $udv) . '</b>".<br /><br />';
                $deets = $deets . 'Of course, there should only be one element with this ID so if there are multiple elements with the same ID, have a word with your front-end development team.<br />';
            }
        }
    }
    if ($udv['type'] === 'aev') {
        $varType = getParamTemplate($udv, 'varType')['value'];
        $hostSource = 'Element URL';
        switch ($varType) {
            case 'ELEMENT':
                $deets = $deets . 'The variable returns the value of the "gtm.element" key on the data layer. If populated by an Auto-Event, the result will be the DOM element that triggered the event.<br /><br />In other words, the <i>thing</i> on the page that was clicked or the form that was submitted.<br /><br />';
                break;
            case 'ATTRIBUTE':
                $deets = $deets . 'The variable returns the value of the "' . getParamTemplate($udv, 'attribute')['value'] . '" attribute for the element that triggered the last click or form submit event.<br /><br /><br />';
                break;
            case 'CLASSES':
                $deets = $deets . 'The variable returns the value of the "gtm.elementClasses" key on the data layer. If populated by an Auto-Event, the result will be the "class" attribute of the DOM element that triggered the event (the <i>thing</i> that was clicked or the form that was submitted).<br /><br />';
                break;
            case 'ID':
                $deets = $deets . 'The variable returns the value of the "gtm.elementId" key on the data layer. If populated by an Auto-Event, the result will be the "id" attribute of the DOM element that triggered the event (the <i>thing</i> that was clicked or the form that was submitted).<br /><br />';
                break;
            case 'TARGET':
                $deets = $deets . 'The variable returns the value of the "gtm.elementTarget" key on the data layer. If populated by an Auto-Event, the result will be the "target" attribute of the DOM element that triggered the event (the <i>thing</i> that was clicked or the form that was submitted).<br /><br />';
                break;
            case 'TEXT':
                $deets = $deets . 'The variable returns the value of the "gtm.element" key on the data layer and its text content if there is any.<br />If populated by a click or link-click Auto-Event, the text content will be the "innerText" or the "textContent" attribute of the DOM element that triggered the event.<br /><b>Technical:</b> The text will be trimmed and normalised (white-spaces will be consolidated) to account for browsers variations.<br /><br />';
                break;
            case 'URL':
                $deets = $deets . 'The variable returns the value of the "gtm.elementUrl" key on the data layer.<br />If populated by an Auto-Event, the result will be the "href" or "action" attribute of the DOM element that triggered the event, depending on the type of element (the <i>thing</i> that was clicked or the form that was submitted).<br /><br />';
                $URLComponent = getParamTemplate($udv, 'component') !== '' ? getParamTemplate($udv, 'component')['value'] : '';
                if ($URLComponent !== '') {
                    switch ($URLComponent) {
                        case 'HOST':
                            $deets = $deets . 'The "hostname" part of the ' . $hostSource;
                            if (getParam($udv, 'stripWww') !== null && getParam($udv, 'stripWww') === 'true') {
                                $deets = $deets . ' - minus the www part - ';
                            }
                            $deets = $deets . ' will be returned.<br />';
                            break;
                        case 'PATH':
                            $deets = $deets . 'The path of the ' . $hostSource . ' will be returned.<br />';
                            if (strlen(getParamList($udv, 'defaultPages')) > 0) {
                                $deets = $deets . 'The list of default pages to ignore is:<ul>';
                                $defaultPages = getParamList($udv, 'defaultPages');
                                foreach ($defaultPages as $defPageIndex => $defPageVal) {
                                    $deets = $deets . '<li>' . $defaultPages[$defPageIndex]['value'] . '</li>';
                                }
                                $deets = $deets . '</ul><br />';
                                $deets = $deets . 'The last non-directory segment in the path will be stripped if it matches any of the default pages. For instance, if a default page is "index.html" and the URL is "http://a.com/x/index.html", the variable value will be "/x/".<br />';
                            }
                            break;
                        case 'QUERY':
                            $queryKey = '';
                            if (getParamTemplate($udv, 'queryKey') !== '') {
                                $queryKey = variablise(getParamTemplate($udv, 'queryKey')['value'], $udv);
                            }
                            $deets = $deets . 'The value of the querystring variable (the part after the ? on the ' . $hostSource . ') "' . $queryKey . '" will be returned.<br />';
                            break;
                        case 'FRAGMENT':
                            $deets = $deets . 'The fragment (the part after the # on the ' . $hostSource . ') will be returned.<br />';
                            break;
                        case 'PORT':
                            $deets = $deets . 'The port (80 or 443 for example) of the ' . $hostSource . ' will be returned.<br />';
                            break;
                        case 'PROTOCOL':
                            $deets = $deets . 'The protocol (http or https) of the ' . $hostSource . ' will be returned.<br />';
                            break;
                        case 'URL':
                            $deets = $deets . 'The full URL of the ' . $hostSource . ' will be returned.<br />';
                            break;
                    }
                }
                break;
            case 'HISTORY_NEW_URL_FRAGMENT':
                $deets = $deets . 'The value is determined by reading the "gtm.newUrlFragment" key from the data layer. If populated by an Auto-Event, the result will be the new URL fragment set on a history change event (Used by AJAX forms - <b>Technical</b>).<br />';
                break;
            case 'HISTORY_OLD_URL_FRAGMENT':
                $deets = $deets . 'The value is determined by reading the "gtm.oldUrlFragment" key from the data layer. If populated by an Auto-Event, the result will be the old URL fragment set on the previous history change event (Used by AJAX forms - <b>Technical</b>).<br />';
                break;
            case 'HISTORY_NEW_STATE':
                $deets = $deets . 'The value is determined by reading the "gtm.newHistoryState" key from the data layer. If populated by an Auto-Event, the result will be the new history state set on a history change event (Used by AJAX forms - <b>Technical</b>).<br />';
                break;
            case 'HISTORY_OLD_STATE':
                $deets = $deets . 'The value is determined by reading the "gtm.oldHistoryState" key from the data layer. If populated by an Auto-Event, the result will be the old history state set on the previous history change event (Used by AJAX forms - <b>Technical</b>).<br />';
                break;
            case 'HISTORY_CHANGE_SOURCE':
                $deets = $deets . 'The value is determined by reading the "gtm.historyChangeSource" key from the data layer. If populated by an Auto-Event, the result will be the source of the gtm.historyChange event, which can be: "popstate", "pushState", "replaceState" or "polling" (Used by AJAX forms - <b>Technical</b>).<br />';
                break;
        }
    }
    if ($udv['type'] === 'k') {
        if (getParam($udv, 'decodeCookie') === 'true') {
            $deets = $deets . "<br /><br />The value of the cookie will be URI-decoded. This is a nice thing to do to make your data human readable.<br />";
        } else {
            $deets = $deets . "<br /><br />The value of the cookie will not be URI-decoded.<br />";
            $deets = $deets . "If enabled, the value of the cookie 'xxx%3Dyyy' would become 'xxx=yyy'.<br />";
            $deets = $deets . "This might be a nice thing to do to make your data human readable.<br />";
        }
    }
    if ($udv['type'] === 'f') {
        if (array_key_exists('parameter', $udv)) {
            $component = getParam($udv, 'component');
            if ($component === 'QUERY' || $component === 'FRAGMENT') {
                $deets = $deets . 'It returns the ' . translateToHuman($component, $udv) . ' part of the referring page URL using the ';
                if ($component === 'QUERY') {
                    $deets = $deets . getParam($udv, 'queryKey') . ' querystring parameter.<br />';
                } else {
                    $deets = $deets . ' part of the URL after the "#" without the leading "#".<br />';
                }
            } else {
                $deets = $deets . 'It returns the ' . translateToHuman($component, $udv) . ' the user just came from.<br />';
            }
            if (getParam($udv, 'stripWww') === 'true') {
                $deets = $deets . 'The returned value will have the "www" part of the hostname stripped off.';
            }
        } else {
            $deets = $deets . 'It returns the full URL of the last page the user was on.<br /><br />';
            $deets = $deets . 'Why not just use the \'Referrer\' built in variable? It does the same thing.';
        }
    }
    if ($udv['type'] === 'u') {
        $hostSource = 'URL';
        $URLComponent = getParamTemplate($udv, 'component')['value'];
        $hostSource = getParamTemplate($udv, 'customUrlSource') !== '' ? translateToHuman(getParamTemplate($udv, 'customUrlSource')['value'], $udv) : $hostSource;
        switch ($URLComponent) {
            case 'HOST':
                $deets = $deets . 'The "hostname" part of the ' . $hostSource;
                if (getParam($udv, 'stripWww') !== null && getParam($udv, 'stripWww') === 'true') {
                    $deets = $deets . ' - minus the www part - ';
                }
                $deets = $deets . ' will be returned.<br />';
                break;
            case 'PATH':
                $deets = $deets . 'The path of the ' . $hostSource . ' will be returned.<br />';
                if (strlen(getParamList($udv, 'defaultPages')) > 0) {
                    $deets = $deets . 'The list of default pages to ignore is:<ul>';
                    $defaultPages = getParamList($udv, 'defaultPages');
                    foreach ($defaultPages as $defPageIndex => $defPageVal) {
                        $deets = $deets . '<li>' . $defaultPages[$defPageIndex]['value'] . '</li>';
                    }
                    $deets = $deets . '</ul><br />';
                }
                break;
            case 'QUERY':
                $queryKey = '';
                if (getParamTemplate($udv, 'queryKey') !== '') {
                    $queryKey = variablise(getParamTemplate($udv, 'queryKey')['value'], $udv);
                }
                $deets = $deets . 'The value of the querystring variable (the part after the ? on the ' . $hostSource . ') "' . $queryKey . '" will be returned.<br /><br />';
                break;
            case 'FRAGMENT':
                $deets = $deets . 'The fragment (the part after the # on the ' . $hostSource . ') will be returned.<br />';
                break;
            case 'PORT':
                $deets = $deets . 'The port (80 or 443 for example) of the ' . $hostSource . ' will be returned.<br />';
                break;
            case 'PROTOCOL':
                $deets = $deets . 'The protocol (http or https) of the ' . $hostSource . ' will be returned.<br />';
                break;
            case 'URL':
                $deets = $deets . 'The full URL of the ' . $hostSource . ' will be returned.<br />';
                break;
        }
    }
    if ($udv['type'] === 'smm') {
        $deets = $deets . 'The <i>input</i> variable for the lookup table is ' . variablise(getParamTemplate($udv, 'input')['value'] . '.<br /><br />', $udv);
        $deets = $deets . '<table class="table table-bordered table-striped"><tr><th>' . variablise(getParamTemplate($udv, 'input')['value'] . '', $udv) . '</th><th>Returned value</th></tr>';
        $lookup = getParamList($udv, 'map');
        foreach ($lookup as $lRow => $lRowVal) {
            $deets = $deets . '<tr><td>' . variablise($lookup[$lRow]['map'][0]['value'], $udv) . '</td>';
            $deets = $deets . '<td>' . variablise($lookup[$lRow]['map'][1]['value'], $udv) . '</td></tr>';
        }
        $deets = $deets . '</table>';
        if (getParamTemplate($udv, 'defaultValue') !== '' && getParamTemplate($udv, 'defaultValue') !== null) {
            $deets = $deets . 'The default value returned if no matches are found in the table is "' . variablise(getParamTemplate($udv, 'defaultValue')['value'], $udv) . '".<br />';
        }
    }
    if ($udv['type'] === 'jsm') {
        $varRefs = '';
        $rawJS = getParam($udv, 'javascript');
        $varRefs = getVarRefs($rawJS, $udv);
        findPushyVars($udv);
        if ($varRefs !== '') {
            $deets = $deets . 'Variables referenced in this variable:<br />' . $varRefs;
        }
        if ($rawJS !== '') {
            $deets = $deets . '<p style="margin:5px;"><textarea class="form-control" rows="10" cols="60" disabled="disabled">' . $rawJS . '</textarea></p><br />';
        }
    }
    if ($udv['type'] !== 'c' && $udv['type'] !== 'smm') {
        $deets = $deets . defaultValue($udv);
    }
    $deets = $deets . '<tr><th>Where it\'s used</th>';
    $deets = $deets . getUsage($udv);
    $deets = $deets . '<tr><th>Where it lives</th>';
    if (array_key_exists('parentFolderId', $udv)) {
        $deets = $deets . '<td>' . folderisation($udv['parentFolderId'], 'User Defined Variable') . '</td></tr>';
    } else {
        $deets = $deets . '<td>' . folderisation(null, 'User Defined Variable') . '</td></tr>';
    }
    $deets = $deets . '</table>';
    return $deets;
}