views

ExistsSubqueryField.php
<?php

declare(strict_types=1);

namespace Drupal\my_module\Plugin\views\field;

use Drupal\views\Attribute\ViewsField;
use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\views\ResultRow;

/**
 * Sortable yes/no column backed by an EXISTS subquery from views data.
 *
 * '@base' in the 'exists subquery' definition is replaced with the alias of
 * the base table.
 */
#[ViewsField('exists_subquery')]
class ExistsSubquery extends FieldPluginBase {

  public function query() {
    $this->ensureMyTable();
    $exists = 'EXISTS (' . str_replace('@base', $this->tableAlias, $this->definition['exists subquery']) . ')';
    $this->field_alias = $this->query->addField(NULL, "CASE WHEN $exists THEN 1 ELSE 0 END", $this->realField);
  }

  public function clickSort($order) {
    $this->query->addOrderBy(NULL, NULL, $order, $this->field_alias);
  }

  public function render(ResultRow $values) {
    return $this->getValue($values) ? $this->t('yes') : $this->t('no');
  }

}
ExistsSubqueryFilter.php
<?php

declare(strict_types=1);

namespace Drupal\my_module\Plugin\views\filter;

use Drupal\views\Attribute\ViewsFilter;
use Drupal\views\Plugin\views\filter\BooleanOperator;

/**
 * Yes/no filter backed by an EXISTS subquery from views data.
 */
#[ViewsFilter('exists_subquery')]
class ExistsSubquery extends BooleanOperator {

  public function defaultExposeOptions() {
    parent::defaultExposeOptions();
    // BooleanOperator exposes as required without a stored value, which fails
    // form validation. Default to "- Any -" instead.
    $this->options['expose']['required'] = FALSE;
    $this->options['value'] = 'All';
  }

  public function query() {
    if ($this->value === 'All') {
      return;
    }
    $this->ensureMyTable();
    $exists = 'EXISTS (' . str_replace('@base', $this->tableAlias, $this->definition['exists subquery']) . ')';
    $this->query->addWhereExpression($this->options['group'], empty($this->value) ? "NOT $exists" : $exists);
  }

}
MyModuleViewsHooks.php
<?php

declare(strict_types=1);

namespace Drupal\my_module\Hook;

use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\StringTranslation\StringTranslationTrait;

final class MyModuleViewsHooks {

  use StringTranslationTrait;

  #[Hook('views_data_alter')]
  public function viewsDataAlter(array &$data): void {
    $subquery = 'SELECT 1 FROM {node__field_related_content} ref WHERE ref.field_related_content_target_id = @base.nid';
    $data['node_field_data']['is_referenced'] = [
      'title' => $this->t('Is referenced'),
      'field' => ['id' => 'exists_subquery', 'click sortable' => TRUE, 'exists subquery' => $subquery],
      'filter' => ['id' => 'exists_subquery', 'label' => $this->t('Is referenced'), 'exists subquery' => $subquery],
    ];
  }

}

my_module.module
<?php

use Drupal\Component\Utility\Html;
use Drupal\Core\Form\FormStateInterface;


/**
 * Implements hook_form_FORM_ID_alter() for 'views_exposed_form'.
 */
function hook_form_views_exposed_form_alter(&$form, FormStateInterface $form_state) {
  // Configure the values to your needs.
  $view_name = 'my_view';
  $display_name = 'my_display';
  $entity_type_id = 'taxonomy_term';
  $reference_field = 'field_category';
  // The field on the referenced entity.
  $flag_on_reference_field = 'field_hide_on_exposed_form';

  if ($form['#id'] == Html::getId("views-exposed-form-{$view_name}-{$display_name}")) {
    $entity_storage = \Drupal::entityTypeManager()->getStorage($entity_type_id);
    $options = &$form[$reference_field]['#options'];
    foreach ($entity_storage->loadMultiple(array_keys($options)) as $id => $entity) {
      if ($entity->hasField($flag_on_reference_field) && !$entity->{$flag_on_reference_field}->isEmpty()) {
        unset($options[$id]);
      }
    }
  }
}