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

Yoast / wordpress-seo / 5066322038

pending completion
5066322038

push

github

GitHub
Merge pull request #20316 from Yoast/JRF/ghactions-run-more-selectively

2550 of 29012 relevant lines covered (8.79%)

0.32 hits per line

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

0.0
/src/integrations/front-end/force-rewrite-title.php
1
<?php
2

3
namespace Yoast\WP\SEO\Integrations\Front_End;
4

5
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
6
use Yoast\WP\SEO\Helpers\Options_Helper;
7
use Yoast\WP\SEO\Integrations\Integration_Interface;
8
use Yoast\WP\SEO\Wrappers\WP_Query_Wrapper;
9

10
/**
11
 * Class Force_Rewrite_Title.
12
 */
13
class Force_Rewrite_Title implements Integration_Interface {
14

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

22
        /**
23
         * Toggle indicating whether output buffering has been started.
24
         *
25
         * @var bool
26
         */
27
        private $ob_started = false;
28

29
        /**
30
         * The WP Query wrapper.
31
         *
32
         * @var WP_Query_Wrapper
33
         */
34
        private $wp_query;
35

36
        /**
37
         * Sets the helpers.
38
         *
39
         * @codeCoverageIgnore It just handles dependencies.
40
         *
41
         * @param Options_Helper   $options  Options helper.
42
         * @param WP_Query_Wrapper $wp_query WP query wrapper.
43
         */
44
        public function __construct( Options_Helper $options, WP_Query_Wrapper $wp_query ) {
45
                $this->options  = $options;
46
                $this->wp_query = $wp_query;
47
        }
48

49
        /**
50
         * Returns the conditionals based in which this loadable should be active.
51
         *
52
         * @return array
53
         */
54
        public static function get_conditionals() {
55
                return [ Front_End_Conditional::class ];
×
56
        }
57

58
        /**
59
         * Initializes the integration.
60
         *
61
         * This is the place to register hooks and filters.
62
         *
63
         * @codeCoverageIgnore
64
         *
65
         * @return void
66
         */
67
        public function register_hooks() {
68
                // When the option is disabled.
69
                if ( ! $this->options->get( 'forcerewritetitle', false ) ) {
70
                        return;
71
                }
72

73
                // For WordPress versions below 4.4.
74
                if ( \current_theme_supports( 'title-tag' ) ) {
75
                        return;
76
                }
77

78
                \add_action( 'template_redirect', [ $this, 'force_rewrite_output_buffer' ], 99999 );
79
                \add_action( 'wp_footer', [ $this, 'flush_cache' ], -1 );
80
        }
81

82
        /**
83
         * Used in the force rewrite functionality this retrieves the output, replaces the title with the proper SEO
84
         * title and then flushes the output.
85
         *
86
         * @return bool
87
         */
88
        public function flush_cache() {
89
                if ( $this->ob_started !== true ) {
×
90
                        return false;
×
91
                }
92

93
                $content = $this->get_buffered_output();
×
94

95
                $old_wp_query = $this->wp_query->get_query();
×
96

97
                \wp_reset_query();
×
98

99
                // When the file has the debug mark.
100
                if ( \preg_match( '/(?\'before\'.*)<!-- This site is optimized with the Yoast SEO.*<!-- \/ Yoast SEO( Premium)? plugin. -->(?\'after\'.*)/is', $content, $matches ) ) {
×
101
                        $content = $this->replace_titles_from_content( $content, $matches );
×
102

103
                        unset( $matches );
×
104
                }
105

106
                // phpcs:ignore WordPress.WP.GlobalVariablesOverride -- The query gets reset here with the original query.
107
                $GLOBALS['wp_query'] = $old_wp_query;
×
108

109
                // phpcs:ignore WordPress.Security.EscapeOutput -- The output should already have been escaped, we are only filtering it.
110
                echo $content;
×
111

112
                return true;
×
113
        }
114

115
        /**
116
         * Starts the output buffer so it can later be fixed by flush_cache().
117
         */
118
        public function force_rewrite_output_buffer() {
119
                $this->ob_started = true;
×
120
                $this->start_output_buffering();
×
121
        }
122

123
        /**
124
         * Replaces the titles from the parts that contains a title.
125
         *
126
         * @param string $content          The content to remove the titles from.
127
         * @param array  $parts_with_title The parts containing a title.
128
         *
129
         * @return string The modified content.
130
         */
131
        protected function replace_titles_from_content( $content, $parts_with_title ) {
132
                if ( isset( $parts_with_title['before'] ) && \is_string( $parts_with_title['before'] ) ) {
×
133
                        $content = $this->replace_title( $parts_with_title['before'], $content );
×
134
                }
135

136
                if ( isset( $parts_with_title['after'] ) ) {
×
137
                        $content = $this->replace_title( $parts_with_title['after'], $content );
×
138
                }
139

140
                return $content;
×
141
        }
142

143
        /**
144
         * Removes the title from the part that contains the title and put this modified part back
145
         * into the content.
146
         *
147
         * @param string $part_with_title The part with the title that needs to be replaced.
148
         * @param string $content         The entire content.
149
         *
150
         * @return string The altered content.
151
         */
152
        protected function replace_title( $part_with_title, $content ) {
153
                $part_without_title = \preg_replace( '/<title.*?\/title>/i', '', $part_with_title );
×
154

155
                return \str_replace( $part_with_title, $part_without_title, $content );
×
156
        }
157

158
        /**
159
         * Starts the output buffering.
160
         *
161
         * @codeCoverageIgnore
162
         */
163
        protected function start_output_buffering() {
164
                \ob_start();
165
        }
166

167
        /**
168
         * Retrieves the buffered output.
169
         *
170
         * @codeCoverageIgnore
171
         *
172
         * @return false|string The buffered output.
173
         */
174
        protected function get_buffered_output() {
175
                return \ob_get_clean();
176
        }
177
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc