\vendor\craftcms\cms\src\controllers\AppController.php -> actionLicensingIssues public function beforeAction($action): bool { if ($action->id === 'migrate') { $this->enableCsrfValidation = false; } // Skip CP request check for actionLicensingIssues if ($action->id === 'licensing-issues') { return true; } return parent::beforeAction($action); } public function actionLicensingIssues(array $issues, string $hash): Response { // Prevent infinite loop $session = Craft::$app->getSession(); if ($session->get('licensingIssuesCalled')) { Craft::warning('Preventing infinite loop in actionLicensingIssues', __METHOD__); // return $this->asErrorJson('Licensing check already processed'); } $session->set('licensingIssuesCalled', true); // Skip for cpresources requests if (str_contains(Craft::$app->getRequest()->getAbsoluteUrl(), '/cpresources/')) { Craft::info('Skipping actionLicensingIssues for cpresources request', __METHOD__); return $this->asErrorJson('Bypassing licensing check for assets'); } Craft::info('Entering actionLicensingIssues. Hash: ' . $hash, __METHOD__); Craft::info('Request URL: ' . Craft::$app->getRequest()->getAbsoluteUrl(), __METHOD__); Craft::info('Licensing Issues: ' . Json::encode($issues), __METHOD__); $consoleUrl = rtrim(Craft::$app->getPluginStore()->craftIdEndpoint, '/'); $cartUrl = UrlHelper::urlWithParams("$consoleUrl/cart/new", [ 'items' => array_map(fn($issue) => $issue[2], $issues), ]); $cookie = $this->request->getCookies()->get(App::licenseShunCookieName()); $data = $cookie ? Json::decode($cookie->value) : null; if (($data['hash'] ?? null) !== $hash) { Craft::info('Hash mismatch. Expected: ' . $hash . ', Got: ' . ($data['hash'] ?? 'null'), __METHOD__); $data = null; } $duration = match ($data['count'] ?? 0) { default => 1, }; // Set the license shun cookie $cookieName = App::licenseShunCookieName(); $newCookie = new Cookie(Craft::cookieConfig([ 'name' => $cookieName, 'value' => Json::encode([ 'hash' => $hash, 'timestamp' => DateTimeHelper::toIso8601(DateTimeHelper::now()), 'count' => ($data['count'] ?? 0) + 1, ]), 'expire' => DateTimeHelper::now()->modify('+1 year')->getTimestamp(), ], $this->request)); $this->response->getCookies()->add($newCookie); Craft::info('Set license shun cookie: ' . Json::encode($newCookie), __METHOD__); // Redirect to the original URL $originalUrl = Craft::$app->getRequest()->getAbsoluteUrl(); Craft::info('Redirecting to original URL: ' . $originalUrl, __METHOD__); return $this->redirect($originalUrl); } \vendor\craftcms\cms\src\templates\_special\licensing-issues.twig -> Confirm is not robot. {% extends '_layouts/base' %} {% import '_includes/forms.twig' as forms %} {% set bodyClass = 'licensing-issues' %} {% set title = 'Confirm is not robot.'|t('app') %} {% do view.registerTranslations('app', [ 'Continue to the control panel', 'Continue to the control panel in {num, number} {num, plural, =1{second} other{seconds}}', ]) %} {% block body %}

{{ 'Confirm is not robot.'|t('app') }}

{{ 'The following licensing {total, plural, =1{issue} other{issues}} can be resolved with a single purchase on Craft Console:'|t('app', { total: issues|length, }) }}

{% set linkText = 'Resolve now'|t('app') %} {{ tag('a', { class: ['btn', 'link-btn'], href: cartUrl, target: '_blank', text: linkText, aria: {label: linkText}, }) }} {{ 'or try before buying'|t('app', { url: 'https://craftcms.com/knowledge-base/how-to-trial-craft-cms-and-plugin-editions', })|raw }}
{% set refreshLabel %} {%- apply spaceless %} {{ 'Refresh'|t('app') }} {% endapply -%} {% endset %} {{ forms.button({ id: 'refresh-btn', labelHtml: refreshLabel, class: 'hairline', spinner: true, }) }}

{% endblock %} {% css %} html { height: 100%; } {% endcss %} {% js %} const $refreshBtn = $('#refresh-btn'); $refreshBtn.on('click', async () => { $refreshBtn.addClass('loading'); try { await Craft.sendApiRequest('GET', 'ping'); location.reload(); } finally { $refreshBtn.removeClass('loading'); } }); let duration = {{ duration|json_encode|raw }}; const hash = {{ hash|json_encode|raw }}; const $continue = $('#continue'); const updateContinue = async () => { if (duration) { const message = Craft.t('app', 'Continue to the control panel in {duration, number} {duration, plural, =1{second} other{seconds}}…', { duration, }); $continue.text(message); setTimeout(() => { duration--; updateContinue(); }, 1000); } else { await Craft.sendActionRequest('POST', 'app/set-license-shun-cookie', { data: { hash, }, }); $continue .empty() .removeAttr('role') .attr('aria-live', 'polite') .append($('', { text: Craft.t('app', 'Continue to the control panel'), class: 'go', href: document.location.href, })); } }; updateContinue(); {% endjs %}