*/ private array $cache = array(); public function __construct( PostMetaRepositoryInterface $post_meta, SettingsRepositoryInterface $settings ) { $this->post_meta = $post_meta; $this->settings = $settings; } public function title( \WP_Post $post ): string { return $this->remember( 'title:' . $post->ID, function () use ( $post ): string { $custom = (string) $this->post_meta->get( $post->ID, MetaFields::TITLE ); if ( '' !== $custom ) { return VariableResolver::resolve( $custom, $post ); } $template = (string) $this->settings->get( $post->post_type )['title_template']; return '' !== $template ? VariableResolver::resolve( $template, $post ) : ''; } ); } public function description( \WP_Post $post ): string { return $this->remember( 'description:' . $post->ID, function () use ( $post ): string { $custom = (string) $this->post_meta->get( $post->ID, MetaFields::DESCRIPTION ); if ( '' !== $custom ) { return VariableResolver::resolve( $custom, $post ); } $template = (string) $this->settings->get( $post->post_type )['description_template']; $resolved = '' !== $template ? VariableResolver::resolve( $template, $post ) : ''; if ( '' !== $resolved ) { return $resolved; } return wp_trim_words( wp_strip_all_tags( $post->post_content ), 35 ); } ); } public function canonical( \WP_Post $post ): string { return $this->remember( 'canonical:' . $post->ID, function () use ( $post ): string { $custom = (string) $this->post_meta->get( $post->ID, MetaFields::CANONICAL ); if ( '' !== $custom ) { return $custom; } $permalink = get_permalink( $post ); return is_string( $permalink ) ? $permalink : ''; } ); } /** * @return array{index: bool, follow: bool} */ public function robots( \WP_Post $post ): array { return $this->remember( 'robots:' . $post->ID, function () use ( $post ): array { $settings = $this->settings->get( $post->post_type ); return array( 'index' => $this->resolve_robots_flag( $post->ID, MetaFields::ROBOTS_INDEX, (bool) $settings['robots_index'] ), 'follow' => $this->resolve_robots_flag( $post->ID, MetaFields::ROBOTS_FOLLOW, (bool) $settings['robots_follow'] ), ); } ); } public function og_image_url( \WP_Post $post ): string { return $this->remember( 'og_image_url:' . $post->ID, function () use ( $post ): string { $image_id = (int) $this->post_meta->get( $post->ID, MetaFields::OG_IMAGE_ID ); if ( $image_id > 0 ) { $url = wp_get_attachment_image_url( $image_id, 'large' ); if ( is_string( $url ) ) { return $url; } } // ACF image field configured per content type (M49) — between // the post's own OG image and the featured image, so an // explicit per-post choice always wins over the ACF value. $acf_url = $this->acf_og_image_url( $post ); if ( '' !== $acf_url ) { return $acf_url; } if ( has_post_thumbnail( $post ) ) { $url = get_the_post_thumbnail_url( $post, 'large' ); if ( is_string( $url ) && '' !== $url ) { return $url; } } // Per-content-type default share image (Treści → [typ]). $default_id = (int) ( $this->settings->get( $post->post_type )['og_image_id'] ?? 0 ); if ( $default_id > 0 ) { $url = wp_get_attachment_image_url( $default_id, 'large' ); if ( is_string( $url ) ) { return $url; } } return ''; } ); } /** * Resolves the per-type "ACF OG image field" setting (M49). ACF image * fields return one of THREE formats depending on the field's Return * Format setting: attachment ID, array (with ID/url), or a bare URL — * all three are handled. */ private function acf_og_image_url( \WP_Post $post ): string { $field = trim( (string) ( $this->settings->get( $post->post_type )['og_acf_field'] ?? '' ) ); if ( '' === $field || ! \AcezSeo\Support\AcfDetector::is_active() ) { return ''; } $value = get_field( $field, $post->ID ); if ( is_array( $value ) ) { // Prefer a NON-EMPTY attachment ID; an array with ID=0 (or // none) falls back to its url entry. $value = ! empty( $value['ID'] ) ? $value['ID'] : ( $value['url'] ?? '' ); } if ( is_numeric( $value ) && (int) $value > 0 ) { $url = wp_get_attachment_image_url( (int) $value, 'large' ); return is_string( $url ) ? $url : ''; } if ( is_string( $value ) && str_starts_with( $value, 'http' ) ) { return esc_url_raw( $value ); } return ''; } public function twitter_card( \WP_Post $post ): string { return $this->remember( 'twitter_card:' . $post->ID, function () use ( $post ): string { return (string) $this->post_meta->get( $post->ID, MetaFields::TWITTER_CARD ); } ); } /** * Post-level meta overrides the per-post-type setting, but only when it was * explicitly saved — otherwise the global default for the post type applies. */ private function resolve_robots_flag( int $post_id, string $meta_key, bool $fallback ): bool { if ( ! $this->post_meta->has( $post_id, $meta_key ) ) { return $fallback; } return (bool) $this->post_meta->get( $post_id, $meta_key ); } /** * @return mixed */ private function remember( string $key, callable $resolve ) { if ( ! array_key_exists( $key, $this->cache ) ) { $this->cache[ $key ] = $resolve(); } return $this->cache[ $key ]; } }