So one way this can be done is by creating a filter to check for a custom query string parameter that represents a tag name or names.
I added a function similar to this to my theme. It modifies the global WP_Query object before a request is made for posts by the REST API.
add_filter('pre_get_posts', function ($query) {
// I couldn't read from query_vars for some reason, so using global $_GET
$exclude_tag_name = isset($_GET['exclude_tag_name']);
if (!$exclude_tag_name) {
return; // Nothing to do
}
// Whitelist for security
// Add to this list as needed
$whitelist = ['SomeExcludedTagNameHere'];
$tag_name = $exclude_tag_name;
// Additional logic goes here to handle multiple names, such as splitting
// Check if tag name is in white list (with strict type checking)
// For security, you could also probably use a REGEX to sanitize
// or one of WP's built in sanitizing functions.
if (!in_array($tag_name, $whitelist, true)) {
return; // nothing to do
}
// Get all tags that contain this name (case insensitive)
// Or just use the tag directly if it doesn't matter to you.
$tags = get_tags([
'search' => $tag_name
]);
$tag_ids = [];
foreach ($tags as $tag) {
$tag_ids[] = $tag->term_id;
}
// Exclude these category IDs from the query
if (!empty($tag_ids)) {
// Modify the query object that was passed in by reference
// This function uses the tag ID's not names!
$query->set('tag__not_in', $tag_ids);
}
});
Similar code can be used to include only posts that have been tagged with a particular tag.