resolver = $resolver;
$this->location_evaluator = $location_evaluator;
$this->features = $features;
$this->global_settings = $global_settings;
}
public function register(): void
{
// Priority 99: themes sometimes filter the document title themselves
// — the user's explicit SEO title must win.
add_filter( 'pre_get_document_title', array( $this, 'filter_title' ), 99 );
// Legacy path: themes without `title-tag` support (e.g. Divi in its
// default configuration) build
through wp_title(), which
// never reaches pre_get_document_title — cover it too (same approach
// as other SEO plugins: return the complete title).
add_filter( 'wp_title', array( $this, 'filter_title' ), 99 );
add_filter( 'wp_robots', array( $this, 'filter_robots' ) );
add_filter( 'get_canonical_url', array( $this, 'filter_canonical' ), 10, 2 );
add_action( 'wp_head', array( $this, 'print_meta_tags' ), 5 );
}
public function filter_title( string $title ): string
{
if ( ! $this->should_handle() || ! $this->features->enabled( 'meta_title' ) )
{
return $title;
}
$post = $this->current_post();
if ( null === $post )
{
return $title;
}
$resolved = $this->resolver->title( $post );
return '' !== $resolved ? $resolved : $title;
}
/**
* @param array $robots
*
* @return array
*/
public function filter_robots( array $robots ): array
{
if ( ! $this->should_handle() || ! $this->features->enabled( 'meta_robots' ) )
{
return $robots;
}
$post = $this->current_post();
if ( null === $post )
{
return $robots;
}
$flags = $this->resolver->robots( $post );
if ( ! $flags['index'] )
{
$robots['noindex'] = true;
}
if ( ! $flags['follow'] )
{
$robots['nofollow'] = true;
}
return $robots;
}
public function filter_canonical( string $canonical_url, \WP_Post $post ): string
{
if ( ! $this->should_handle() || ! $this->features->enabled( 'canonical' ) )
{
return $canonical_url;
}
if ( ! in_array( $post->post_type, PostTypes::supported(), true ) )
{
return $canonical_url;
}
if ( ! $this->location_evaluator->applies( $post ) )
{
return $canonical_url;
}
$custom = $this->resolver->canonical( $post );
return '' !== $custom ? $custom : $canonical_url;
}
public function print_meta_tags(): void
{
$handle = $this->should_handle();
// Opt-in "danger zone" exception (SettingsTab): even when deferring to
// a detected conflicting plugin, OG/Twitter alone can still take over
// if the user asked for it AND we have a verified way to suppress
// that plugin's own OG/Twitter output (ConflictOverrideRunner, hooked
// earlier on `wp`). Title/description/canonical stay deferred either way.
$og_override = ! $handle && ConflictOverrideRegistry::is_active( $this->global_settings );
if ( ! $handle && ! $og_override )
{
return;
}
$post = $this->current_post();
if ( null === $post )
{
return;
}
$description = $this->resolver->description( $post );
if ( $handle && '' !== $description && $this->features->enabled( 'meta_description' ) )
{
printf( '' . "\n", esc_attr( $description ) );
}
if ( ( $handle || $og_override ) && $this->features->enabled( 'open_graph' ) )
{
$this->print_open_graph( $post, $description );
}
if ( ( $handle || $og_override ) && $this->features->enabled( 'twitter_cards' ) )
{
$this->print_twitter_card( $post, $description );
}
}
private function print_open_graph( \WP_Post $post, string $description ): void
{
SocialTagsPrinter::open_graph(
is_singular( 'post' ) ? 'article' : 'website',
$this->social_title( $post ),
$this->resolver->canonical( $post ),
$description,
$this->resolver->og_image_url( $post )
);
}
private function print_twitter_card( \WP_Post $post, string $description ): void
{
SocialTagsPrinter::twitter_card(
$this->resolver->twitter_card( $post ),
$this->social_title( $post ),
$description,
$this->resolver->og_image_url( $post )
);
}
private function social_title( \WP_Post $post ): string
{
$title = $this->resolver->title( $post );
return '' !== $title ? $title : get_the_title( $post );
}
private function should_handle(): bool
{
/**
* Filters whether Acez SEO should output its own meta tags at all.
*
* @param bool $should_handle
*/
return (bool) apply_filters( 'acez_seo_should_handle_meta', ! SeoPluginDetector::has_conflict() );
}
private function current_post(): ?\WP_Post
{
$post = CurrentSingularPost::get();
if ( null === $post || ! $this->location_evaluator->applies( $post ) )
{
return null;
}
return $post;
}
}