• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Yoast / wordpress-seo / b01973fe2ec02214545b7597987dd7199ae93ce7

04 Aug 2026 12:31PM UTC coverage: 55.45% (-0.3%) from 55.778%
b01973fe2ec02214545b7597987dd7199ae93ce7

Pull #23538

github

web-flow
Merge a4ea615a3 into 0de900db2
Pull Request #23538: fix(bulk-editor): resolve post type default template when SEO title/description is empty

9798 of 17512 branches covered (55.95%)

Branch coverage included in aggregate %.

47 of 60 new or added lines in 3 files covered. (78.33%)

1 existing line in 1 file now uncovered.

39310 of 71051 relevant lines covered (55.33%)

42358.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.12
/src/bulk-editor/infrastructure/posts/default-template-resolver.php
1
<?php
2

3
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Needed in the folder structure.
4
namespace Yoast\WP\SEO\Bulk_Editor\Infrastructure\Posts;
5

6
use Yoast\WP\SEO\Helpers\Options_Helper;
7

8
/**
9
 * Resolves a post's SEO/social fields from the post type's default template when the stored value
10
 * is empty, matching the single-post editor's fallback behaviour.
11
 */
12
class Default_Template_Resolver {
13

14
        /**
15
         * The options helper.
16
         *
17
         * @var Options_Helper
18
         */
19
        private $options_helper;
20

21
        /**
22
         * The constructor.
23
         *
24
         * @param Options_Helper $options_helper The options helper.
25
         */
NEW
26
        public function __construct( Options_Helper $options_helper ) {
×
NEW
27
                $this->options_helper = $options_helper;
×
28
        }
29

30
        /**
31
         * Returns the SEO title for a post, falling back to the post type's configured template when empty.
32
         *
33
         * Priority mirrors the presentation layer: stored value → user-configured post type template
34
         * (SEO > Settings, `title-{post_type}`) → installation default.
35
         *
36
         * @param int    $post_id      The post ID.
37
         * @param string $post_type    The post type slug.
38
         * @param string $stored_value The raw stored title (empty string when never explicitly saved).
39
         *
40
         * @return string The resolved SEO title.
41
         */
42
        public function resolve_seo_title( int $post_id, string $post_type, string $stored_value ): string {
8✔
43
                if ( $stored_value !== '' ) {
8✔
44
                        return $stored_value;
2✔
45
                }
46

47
                $template = (string) $this->options_helper->get( 'title-' . $post_type, '' );
6✔
48
                if ( $template === '' ) {
6✔
49
                        $template = (string) $this->options_helper->get_title_default( 'title-' . $post_type );
4✔
50
                }
51
                if ( $template === '' ) {
6✔
52
                        return '';
2✔
53
                }
54

55
                return (string) \wpseo_replace_vars( $template, \get_post( $post_id ) );
4✔
56
        }
57

58
        /**
59
         * Returns the meta description for a post, falling back to the post type's configured template when empty.
60
         *
61
         * @param int    $post_id      The post ID.
62
         * @param string $post_type    The post type slug.
63
         * @param string $stored_value The raw stored description (empty string when never explicitly saved).
64
         *
65
         * @return string The resolved meta description.
66
         */
67
        public function resolve_meta_description( int $post_id, string $post_type, string $stored_value ): string {
6✔
68
                if ( $stored_value !== '' ) {
6✔
69
                        return $stored_value;
2✔
70
                }
71

72
                $template = (string) $this->options_helper->get( 'metadesc-' . $post_type, '' );
4✔
73
                if ( $template === '' ) {
4✔
74
                        return '';
2✔
75
                }
76

77
                return (string) \wpseo_replace_vars( $template, \get_post( $post_id ) );
2✔
78
        }
79

80
        /**
81
         * Returns the social title for a post, falling back to the post type's configured template when empty.
82
         *
83
         * Priority mirrors the presentation layer: stored value → user-configured post type template
84
         * (SEO > Settings, `social-title-{post_type}`) → installation default (typically `%%title%%`).
85
         *
86
         * @param int    $post_id      The post ID.
87
         * @param string $post_type    The post type slug.
88
         * @param string $stored_value The raw stored social title (empty string when never explicitly saved).
89
         *
90
         * @return string The resolved social title.
91
         */
92
        public function resolve_social_title( int $post_id, string $post_type, string $stored_value ): string {
8✔
93
                if ( $stored_value !== '' ) {
8✔
94
                        return $stored_value;
2✔
95
                }
96

97
                $template = (string) $this->options_helper->get( 'social-title-' . $post_type, '' );
6✔
98
                if ( $template === '' ) {
6✔
99
                        $template = (string) $this->options_helper->get_title_default( 'social-title-' . $post_type );
4✔
100
                }
101
                if ( $template === '' ) {
6✔
102
                        return '';
2✔
103
                }
104

105
                return (string) \wpseo_replace_vars( $template, \get_post( $post_id ) );
4✔
106
        }
107

108
        /**
109
         * Returns the social description for a post, falling back to the post type's configured template when empty.
110
         *
111
         * @param int    $post_id      The post ID.
112
         * @param string $post_type    The post type slug.
113
         * @param string $stored_value The raw stored social description (empty string when never explicitly saved).
114
         *
115
         * @return string The resolved social description.
116
         */
117
        public function resolve_social_description( int $post_id, string $post_type, string $stored_value ): string {
6✔
118
                if ( $stored_value !== '' ) {
6✔
119
                        return $stored_value;
2✔
120
                }
121

122
                $template = (string) $this->options_helper->get( 'social-description-' . $post_type, '' );
4✔
123
                if ( $template === '' ) {
4✔
124
                        return '';
2✔
125
                }
126

127
                return (string) \wpseo_replace_vars( $template, \get_post( $post_id ) );
2✔
128
        }
129
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc