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

Yoast / duplicate-post / 22267764076

22 Feb 2026 01:05AM UTC coverage: 59.933%. Remained the same
22267764076

push

github

web-flow
Merge pull request #466 from Yoast/JRF/CSQA/no-is_null

CS/QA: no need for `is_null()`

6 of 7 new or added lines in 3 files covered. (85.71%)

5 existing lines in 1 file now uncovered.

1614 of 2693 relevant lines covered (59.93%)

7.36 hits per line

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

88.15
/src/ui/classic-editor.php
1
<?php
2

3
namespace Yoast\WP\Duplicate_Post\UI;
4

5
use WP_Post;
6
use Yoast\WP\Duplicate_Post\Permissions_Helper;
7
use Yoast\WP\Duplicate_Post\Utils;
8

9
/**
10
 * Duplicate Post class to manage the classic editor UI.
11
 */
12
class Classic_Editor {
13

14
        /**
15
         * Holds the object to create the action link to duplicate.
16
         *
17
         * @var Link_Builder
18
         */
19
        protected $link_builder;
20

21
        /**
22
         * Holds the permissions helper.
23
         *
24
         * @var Permissions_Helper
25
         */
26
        protected $permissions_helper;
27

28
        /**
29
         * Holds the asset manager.
30
         *
31
         * @var Asset_Manager
32
         */
33
        protected $asset_manager;
34

35
        /**
36
         * Initializes the class.
37
         *
38
         * @param Link_Builder       $link_builder       The link builder.
39
         * @param Permissions_Helper $permissions_helper The permissions helper.
40
         * @param Asset_Manager      $asset_manager      The asset manager.
41
         */
42
        public function __construct( Link_Builder $link_builder, Permissions_Helper $permissions_helper, Asset_Manager $asset_manager ) {
2✔
43
                $this->link_builder       = $link_builder;
2✔
44
                $this->permissions_helper = $permissions_helper;
2✔
45
                $this->asset_manager      = $asset_manager;
2✔
46
        }
47

48
        /**
49
         * Adds hooks to integrate with WordPress.
50
         *
51
         * @return void
52
         */
53
        public function register_hooks() {
2✔
54
                \add_action( 'post_submitbox_misc_actions', [ $this, 'add_check_changes_link' ], 90 );
2✔
55

56
                if ( (int) Utils::get_option( 'duplicate_post_show_link_in', 'submitbox' ) === 1 ) {
2✔
57
                        if ( (int) Utils::get_option( 'duplicate_post_show_link', 'new_draft' ) === 1 ) {
2✔
58
                                \add_action( 'post_submitbox_start', [ $this, 'add_new_draft_post_button' ] );
2✔
59
                        }
60

61
                        if ( (int) Utils::get_option( 'duplicate_post_show_link', 'rewrite_republish' ) === 1 ) {
2✔
62
                                \add_action( 'post_submitbox_start', [ $this, 'add_rewrite_and_republish_post_button' ] );
2✔
63
                        }
64
                }
65

66
                \add_action( 'load-post.php', [ $this, 'hook_translations' ] );
2✔
67
                \add_filter( 'post_updated_messages', [ $this, 'change_scheduled_notice_classic_editor' ] );
2✔
68

69
                \add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_classic_editor_scripts' ] );
2✔
70
                if ( (int) Utils::get_option( 'duplicate_post_show_link_in', 'submitbox' ) === 1 ) {
2✔
71
                        if ( (int) Utils::get_option( 'duplicate_post_show_link', 'new_draft' ) === 1
2✔
72
                                || (int) Utils::get_option( 'duplicate_post_show_link', 'rewrite_republish' ) === 1
2✔
73
                        ) {
74
                                \add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_classic_editor_styles' ] );
2✔
75
                        }
76
                }
77

78
                // Remove slug editing from Classic Editor.
79
                \add_action( 'add_meta_boxes', [ $this, 'remove_slug_meta_box' ], 10, 2 );
2✔
80
                \add_filter( 'get_sample_permalink_html', [ $this, 'remove_sample_permalink_slug_editor' ], 10, 5 );
2✔
81
        }
82

83
        /**
84
         * Hooks the functions to change the translations.
85
         *
86
         * @return void
87
         */
88
        public function hook_translations() {
2✔
89
                        \add_filter( 'gettext', [ $this, 'change_republish_strings_classic_editor' ], 10, 3 );
2✔
90
                        \add_filter( 'gettext_with_context', [ $this, 'change_schedule_strings_classic_editor' ], 10, 4 );
2✔
91
        }
92

93
        /**
94
         * Enqueues the necessary JavaScript code for the Classic editor.
95
         *
96
         * @return void
97
         */
98
        public function enqueue_classic_editor_scripts() {
2✔
99
                if ( $this->permissions_helper->is_classic_editor() && isset( $_GET['post'] ) ) {
2✔
100
                        $id   = \intval( \wp_unslash( $_GET['post'] ) );
2✔
101
                        $post = \get_post( $id );
2✔
102

103
                        if ( $post !== null && $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
2✔
104
                                $this->asset_manager->enqueue_strings_script();
2✔
105
                        }
106
                }
107
        }
108

109
        /**
110
         * Enqueues the necessary styles for the Classic editor.
111
         *
112
         * @return void
113
         */
114
        public function enqueue_classic_editor_styles() {
2✔
115
                if ( $this->permissions_helper->is_classic_editor()
2✔
116
                        && isset( $_GET['post'] ) ) {
2✔
117
                        $id   = \intval( \wp_unslash( $_GET['post'] ) );
2✔
118
                        $post = \get_post( $id );
2✔
119

120
                        if ( $post !== null && $this->permissions_helper->should_links_be_displayed( $post ) ) {
2✔
121
                                $this->asset_manager->enqueue_styles();
2✔
122
                        }
123
                }
124
        }
125

126
        /**
127
         * Adds a button in the post/page edit screen to create a clone
128
         *
129
         * @param WP_Post|null $post The post object that's being edited.
130
         *
131
         * @return void
132
         */
133
        public function add_new_draft_post_button( $post = null ) {
8✔
134
                if ( $post === null ) {
8✔
135
                        if ( isset( $_GET['post'] ) ) {
4✔
136
                                $id   = \intval( \wp_unslash( $_GET['post'] ) );
2✔
137
                                $post = \get_post( $id );
2✔
138
                        }
139
                }
140

141
                if ( $post instanceof WP_Post && $this->permissions_helper->should_links_be_displayed( $post ) ) {
8✔
142
                        ?>
143
                        <div id="duplicate-action">
4✔
144
                                <a class="submitduplicate duplication"
4✔
145
                                        href="<?php echo \esc_url( $this->link_builder->build_new_draft_link( $post ) ); ?>"><?php \esc_html_e( 'Copy to a new draft', 'duplicate-post' ); ?>
4✔
146
                                </a>
4✔
147
                        </div>
4✔
148
                        <?php
4✔
149
                }
150
        }
151

152
        /**
153
         * Adds a button in the post/page edit screen to create a clone for Rewrite & Republish.
154
         *
155
         * @param WP_Post|null $post The post object that's being edited.
156
         *
157
         * @return void
158
         */
159
        public function add_rewrite_and_republish_post_button( $post = null ) {
10✔
160
                if ( $post === null ) {
10✔
161
                        if ( isset( $_GET['post'] ) ) {
6✔
162
                                $id   = \intval( \wp_unslash( $_GET['post'] ) );
2✔
163
                                $post = \get_post( $id );
2✔
164
                        }
165
                }
166

167
                if (
168
                        $post instanceof WP_Post
10✔
169
                        && $this->permissions_helper->should_rewrite_and_republish_be_allowed( $post )
10✔
170
                        && $this->permissions_helper->should_links_be_displayed( $post )
10✔
171
                ) {
172
                        ?>
173
                        <div id="rewrite-republish-action">
4✔
174
                                <a class="submitduplicate duplication" href="<?php echo \esc_url( $this->link_builder->build_rewrite_and_republish_link( $post ) ); ?>"><?php \esc_html_e( 'Rewrite & Republish', 'duplicate-post' ); ?>
4✔
175
                                </a>
4✔
176
                        </div>
4✔
177
                        <?php
4✔
178
                }
179
        }
180

181
        /**
182
         * Adds a message in the post/page edit screen to create a clone for Rewrite & Republish.
183
         *
184
         * @param WP_Post|null $post The post object that's being edited.
185
         *
186
         * @return void
187
         */
188
        public function add_check_changes_link( $post = null ) {
×
NEW
189
                if ( $post === null ) {
×
190
                        if ( isset( $_GET['post'] ) ) {
×
191
                                $id   = \intval( \wp_unslash( $_GET['post'] ) );
×
UNCOV
192
                                $post = \get_post( $id );
×
193
                        }
194
                }
195

UNCOV
196
                if ( $post instanceof WP_Post && $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
×
197
                        ?>
198
                                <div id="check-changes-action" class="misc-pub-section">
×
199
                                        <?php \esc_html_e( 'Do you want to compare your changes with the original version before merging? Please save any changes first.', 'duplicate-post' ); ?>
×
200
                                        <br><br>
×
201
                                        <a class='button' href=<?php echo \esc_url( $this->link_builder->build_check_link( $post ) ); ?>>
×
202
                                                <?php \esc_html_e( 'Compare', 'duplicate-post' ); ?>
×
203
                                        </a>
×
204
                                </div>
×
UNCOV
205
                                <?php
×
206
                }
207
        }
208

209
        /**
210
         * Changes the 'Publish' copies in the submitbox to 'Republish' if a post is intended for republishing.
211
         *
212
         * @param string $translation The translated text.
213
         * @param string $text        The text to translate.
214
         * @param string $domain      The translation domain.
215
         *
216
         * @return string The to-be-used copy of the text.
217
         */
218
        public function change_republish_strings_classic_editor( $translation, $text, $domain ) {
10✔
219
                if ( $domain !== 'default' ) {
10✔
220
                        return $translation;
2✔
221
                }
222

223
                if ( $text === 'Publish'
8✔
224
                        && $this->should_change_rewrite_republish_copy( \get_post() ) ) {
8✔
225
                                return \__( 'Republish', 'duplicate-post' );
2✔
226
                }
227
                elseif ( $text === 'Publish on: %s'
6✔
228
                        && $this->should_change_rewrite_republish_copy( \get_post() ) ) {
6✔
229
                        /* translators: %s: Date on which the post is to be republished. */
230
                        return \__( 'Republish on: %s', 'duplicate-post' );
2✔
231
                }
232

233
                return $translation;
4✔
234
        }
235

236
        /**
237
         * Changes the 'Schedule' copy in the submitbox to 'Schedule republish' if a post is intended for republishing.
238
         *
239
         * @param string $translation The translated text.
240
         * @param string $text        The text to translate.
241
         * @param string $context     The translation context.
242
         * @param string $domain      The translation domain.
243
         *
244
         * @return string The to-be-used copy of the text.
245
         */
246
        public function change_schedule_strings_classic_editor( $translation, $text, $context, $domain ) {
10✔
247
                if ( $domain !== 'default' || $context !== 'post action/button label' ) {
10✔
248
                        return $translation;
4✔
249
                }
250

251
                if ( $text === 'Schedule'
6✔
252
                        && $this->should_change_rewrite_republish_copy( \get_post() ) ) {
6✔
253
                        return \__( 'Schedule republish', 'duplicate-post' );
2✔
254
                }
255

256
                return $translation;
4✔
257
        }
258

259
        /**
260
         * Changes the post-scheduled notice when a post or page intended for republishing is scheduled.
261
         *
262
         * @param array<string, array<int, string>> $messages Post updated messaged.
263
         *
264
         * @return array<string, array<int, string>> The to-be-used messages.
265
         */
266
        public function change_scheduled_notice_classic_editor( $messages ) {
4✔
267
                $post = \get_post();
4✔
268
                if ( ! $this->should_change_rewrite_republish_copy( $post ) ) {
4✔
UNCOV
269
                        return $messages;
×
270
                }
271

272
                $permalink      = \get_permalink( $post->ID );
4✔
273
                $scheduled_date = \get_the_time( \get_option( 'date_format' ), $post );
4✔
274
                $scheduled_time = \get_the_time( \get_option( 'time_format' ), $post );
4✔
275

276
                if ( $post->post_type === 'post' ) {
4✔
277
                        $messages['post'][9] = \sprintf(
2✔
278
                                /* translators: 1: The post title with a link to the frontend page, 2: The scheduled date and time. */
279
                                \esc_html__(
2✔
280
                                        'This rewritten post %1$s is now scheduled to replace the original post. It will be published on %2$s.',
2✔
281
                                        'duplicate-post',
2✔
282
                                ),
2✔
283
                                '<a href="' . $permalink . '">' . $post->post_title . '</a>',
2✔
284
                                '<strong>' . $scheduled_date . ' ' . $scheduled_time . '</strong>',
2✔
285
                        );
2✔
286
                        return $messages;
2✔
287
                }
288

289
                if ( $post->post_type === 'page' ) {
2✔
290
                        $messages['page'][9] = \sprintf(
2✔
291
                                /* translators: 1: The page title with a link to the frontend page, 2: The scheduled date and time. */
292
                                \esc_html__(
2✔
293
                                        'This rewritten page %1$s is now scheduled to replace the original page. It will be published on %2$s.',
2✔
294
                                        'duplicate-post',
2✔
295
                                ),
2✔
296
                                '<a href="' . $permalink . '">' . $post->post_title . '</a>',
2✔
297
                                '<strong>' . $scheduled_date . ' ' . $scheduled_time . '</strong>',
2✔
298
                        );
2✔
299
                }
300

301
                return $messages;
2✔
302
        }
303

304
        /**
305
         * Determines if the Rewrite & Republish copies for the post should be used.
306
         *
307
         * @param WP_Post $post The current post object.
308
         *
309
         * @return bool True if the Rewrite & Republish copies should be used.
310
         */
311
        public function should_change_rewrite_republish_copy( $post ) {
10✔
312
                global $pagenow;
10✔
313
                if ( ! \in_array( $pagenow, [ 'post.php', 'post-new.php' ], true ) ) {
10✔
314
                        return false;
2✔
315
                }
316

317
                if ( ! $post instanceof WP_Post ) {
8✔
318
                        return false;
2✔
319
                }
320

321
                return $this->permissions_helper->is_rewrite_and_republish_copy( $post );
6✔
322
        }
323

324
        /**
325
         * Removes the slug meta box in the Classic Editor when the post is a Rewrite & Republish copy.
326
         *
327
         * @param string  $post_type Post type.
328
         * @param WP_Post $post      Post object.
329
         *
330
         * @return void
331
         */
332
        public function remove_slug_meta_box( $post_type, $post ) {
4✔
333
                if ( $post instanceof WP_Post && $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
4✔
334
                        \remove_meta_box( 'slugdiv', $post_type, 'normal' );
2✔
335
                }
336
        }
337

338
        /**
339
         * Removes the sample permalink slug editor in the Classic Editor when the post is a Rewrite & Republish copy.
340
         *
341
         * @param string  $html      Sample permalink HTML markup.
342
         * @param int     $post_id   Post ID.
343
         * @param string  $new_title New sample permalink title.
344
         * @param string  $new_slug  New sample permalink slug.
345
         * @param WP_Post $post      Post object.
346
         *
347
         * @return string The filtered HTML of the sample permalink slug editor.
348
         */
349
        public function remove_sample_permalink_slug_editor( $html, $post_id, $new_title, $new_slug, $post ) {
4✔
350
                if ( ! $post instanceof WP_Post ) {
4✔
UNCOV
351
                        return $html;
×
352
                }
353

354
                if ( $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
4✔
355
                        return '';
2✔
356
                }
357

358
                return $html;
2✔
359
        }
360
}
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