How to change page title (from a plugin) in twentytwentyone theme

You can do it like so:

function filterDocumentTitle(string $title): string
{
    // don't change title on admin pages or when global $post is not loaded
    if (is_admin() || get_the_ID() === false) {
        return $title;
    }

    // don't change title if shortcode is not present in content
    if (!has_shortcode(get_the_content(), 'caption')) {
        return $title;
    }

    return 'special title';
}

add_filter('pre_get_document_title', 'filterDocumentTitle');

If you’re using Yoast’s SEO plugin, you’ll also need add_filter('wpseo_title', 'filterDocumentTitle');, since the plugin doesn’t play nicely with pre_get_document_title alone. Other SEO plugins might need similar fixes.

In the above code I check for shortcode, which I used locally to test it, replace this with your real shortcode name (without [ and ]).

With this you’ll know when your shortcode is part of a page or not. Now what is left to do, is getting the value you want for your title. For lack of more information I’ll assume that your shortcode looks something like this

add_shortcode('myshortcode', function () {
    $id = intval($_GET['item']);
    $eventData = /* .. get event data via ID */;
    return 'some contents depending on $eventData';
});

So that you don’t have to duplicate your code, let’s refactor this a bit to the following

function gholmesGetEventData(): array {
    if (empty($_GET['item'])) {
        throw new Exception('Only supported when item is provided.');
    }
    $id = intval($_GET['item']);
    $eventData = /* .. get event data via ID, throw Exception if not found */;
    return $eventData;
}

add_shortcode('myshortcode', function (): ?string {
    try {
        $eventData = gholmesGetEventData();
        return 'some contents depending on $eventData';
    } catch (Exception $e) {
        // do something with the exception
        return null;
    }
});

function gholmesFilterDocumentTitle(string $title): string
{
    // don't change title on admin pages or when global $post is not loaded
    if (is_admin() || get_the_ID() === false) {
        return $title;
    }

    // don't change title if shortcode is not present in content
    if (!has_shortcode(get_the_content(), 'caption')) {
        return $title;
    }

    try {
        $eventData = gholmesGetEventData();
        return $eventData['eventtitle'];
    } catch (Exception $e) {
        return $title;
    }
}

add_filter('pre_get_document_title', 'gholmesFilterDocumentTitle');

With this setup you’ll call gholmesGetEventData() twice. Once in the title once in the shortcode body. To optimize this, you can use WordPress’ object cache’s set and get methods inside gholmesGetEventData() to minimize DB requests. (So the second call would just return the cached result.)