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

Yoast / wordpress-seo / 7004843404

27 Nov 2023 11:48AM UTC coverage: 49.206% (-0.03%) from 49.232%
7004843404

push

github

web-flow
Merge pull request #20858 from Yoast/improve-copy-in-the-ftc-57

15305 of 31104 relevant lines covered (49.21%)

4.03 hits per line

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

87.23
/src/integrations/watchers/primary-category-quick-edit-watcher.php
1
<?php
2

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

5
use WP_Post;
6
use WPSEO_Meta;
7
use Yoast\WP\SEO\Builders\Indexable_Hierarchy_Builder;
8
use Yoast\WP\SEO\Conditionals\Admin\Doing_Post_Quick_Edit_Save_Conditional;
9
use Yoast\WP\SEO\Conditionals\Migrations_Conditional;
10
use Yoast\WP\SEO\Helpers\Options_Helper;
11
use Yoast\WP\SEO\Helpers\Post_Type_Helper;
12
use Yoast\WP\SEO\Integrations\Integration_Interface;
13
use Yoast\WP\SEO\Models\Indexable;
14
use Yoast\WP\SEO\Repositories\Indexable_Repository;
15
use Yoast\WP\SEO\Repositories\Primary_Term_Repository;
16

17
/**
18
 * Class Primary_Category_Quick_Edit_Watcher
19
 */
20
class Primary_Category_Quick_Edit_Watcher implements Integration_Interface {
21

22
        /**
23
         * Holds the options helper.
24
         *
25
         * @var Options_Helper
26
         */
27
        protected $options_helper;
28

29
        /**
30
         * Holds the primary term repository.
31
         *
32
         * @var Primary_Term_Repository
33
         */
34
        protected $primary_term_repository;
35

36
        /**
37
         * The post type helper.
38
         *
39
         * @var Post_Type_Helper
40
         */
41
        protected $post_type_helper;
42

43
        /**
44
         * The indexable repository.
45
         *
46
         * @var Indexable_Repository
47
         */
48
        protected $indexable_repository;
49

50
        /**
51
         * The indexable hierarchy builder.
52
         *
53
         * @var Indexable_Hierarchy_Builder
54
         */
55
        protected $indexable_hierarchy_builder;
56

57
        /**
58
         * Primary_Category_Quick_Edit_Watcher constructor.
59
         *
60
         * @param Options_Helper              $options_helper              The options helper.
61
         * @param Primary_Term_Repository     $primary_term_repository     The primary term repository.
62
         * @param Post_Type_Helper            $post_type_helper            The post type helper.
63
         * @param Indexable_Repository        $indexable_repository        The indexable repository.
64
         * @param Indexable_Hierarchy_Builder $indexable_hierarchy_builder The indexable hierarchy repository.
65
         */
66
        public function __construct(
2✔
67
                Options_Helper $options_helper,
68
                Primary_Term_Repository $primary_term_repository,
69
                Post_Type_Helper $post_type_helper,
70
                Indexable_Repository $indexable_repository,
71
                Indexable_Hierarchy_Builder $indexable_hierarchy_builder
72
        ) {
1✔
73
                $this->options_helper              = $options_helper;
2✔
74
                $this->primary_term_repository     = $primary_term_repository;
2✔
75
                $this->post_type_helper            = $post_type_helper;
2✔
76
                $this->indexable_repository        = $indexable_repository;
2✔
77
                $this->indexable_hierarchy_builder = $indexable_hierarchy_builder;
2✔
78
        }
1✔
79

80
        /**
81
         * Initializes the integration.
82
         *
83
         * This is the place to register hooks and filters.
84
         *
85
         * @return void
86
         */
87
        public function register_hooks() {
2✔
88
                \add_action( 'set_object_terms', [ $this, 'validate_primary_category' ], 10, 4 );
2✔
89
        }
1✔
90

91
        /**
92
         * Returns the conditionals based on which this loadable should be active.
93
         *
94
         * @return array The conditionals.
95
         */
96
        public static function get_conditionals() {
2✔
97
                return [ Migrations_Conditional::class, Doing_Post_Quick_Edit_Save_Conditional::class ];
2✔
98
        }
99

100
        /**
101
         * Validates if the current primary category is still present. If not just remove the post meta for it.
102
         *
103
         * @param int    $object_id Object ID.
104
         * @param array  $terms     Unused. An array of object terms.
105
         * @param array  $tt_ids    An array of term taxonomy IDs.
106
         * @param string $taxonomy  Taxonomy slug.
107
         */
108
        public function validate_primary_category( $object_id, $terms, $tt_ids, $taxonomy ) {
16✔
109
                $post = \get_post( $object_id );
16✔
110
                if ( $post === null ) {
16✔
111
                        return;
2✔
112
                }
113

114
                $main_taxonomy = $this->options_helper->get( 'post_types-' . $post->post_type . '-maintax' );
14✔
115
                if ( ! $main_taxonomy || $main_taxonomy === '0' ) {
14✔
116
                        return;
4✔
117
                }
118

119
                if ( $main_taxonomy !== $taxonomy ) {
10✔
120
                        return;
2✔
121
                }
122

123
                $primary_category = $this->get_primary_term_id( $post->ID, $main_taxonomy );
8✔
124
                if ( $primary_category === false ) {
8✔
125
                        return;
2✔
126
                }
127

128
                // The primary category isn't removed.
129
                if ( \in_array( (string) $primary_category, $tt_ids, true ) ) {
6✔
130
                        return;
4✔
131
                }
132

133
                $this->remove_primary_term( $post->ID, $main_taxonomy );
2✔
134

135
                // Rebuild the post hierarchy for this post now the primary term has been changed.
136
                $this->build_post_hierarchy( $post );
2✔
137
        }
1✔
138

139
        /**
140
         * Returns the primary term id of a post.
141
         *
142
         * @param int    $post_id       The post ID.
143
         * @param string $main_taxonomy The main taxonomy.
144
         *
145
         * @return int|false The ID of the primary term, or `false` if the post ID is invalid.
146
         */
147
        private function get_primary_term_id( $post_id, $main_taxonomy ) {
6✔
148
                $primary_term = $this->primary_term_repository->find_by_post_id_and_taxonomy( $post_id, $main_taxonomy, false );
6✔
149

150
                if ( $primary_term ) {
6✔
151
                        return $primary_term->term_id;
2✔
152
                }
153

154
                return \get_post_meta( $post_id, WPSEO_Meta::$meta_prefix . 'primary_' . $main_taxonomy, true );
4✔
155
        }
156

157
        /**
158
         * Removes the primary category.
159
         *
160
         * @param int    $post_id       The post id to set primary taxonomy for.
161
         * @param string $main_taxonomy Name of the taxonomy that is set to be the primary one.
162
         */
163
        private function remove_primary_term( $post_id, $main_taxonomy ) {
2✔
164
                $primary_term = $this->primary_term_repository->find_by_post_id_and_taxonomy( $post_id, $main_taxonomy, false );
2✔
165
                if ( $primary_term ) {
2✔
166
                        $primary_term->delete();
2✔
167
                }
168

169
                // Remove it from the post meta.
170
                \delete_post_meta( $post_id, WPSEO_Meta::$meta_prefix . 'primary_' . $main_taxonomy );
2✔
171
        }
1✔
172

173
        /**
174
         * Builds the hierarchy for a post.
175
         *
176
         * @param WP_Post $post The post.
177
         */
178
        public function build_post_hierarchy( $post ) {
×
179
                if ( $this->post_type_helper->is_excluded( $post->post_type ) ) {
×
180
                        return;
×
181
                }
182

183
                $indexable = $this->indexable_repository->find_by_id_and_type( $post->ID, 'post' );
×
184

185
                if ( $indexable instanceof Indexable ) {
×
186
                        $this->indexable_hierarchy_builder->build( $indexable );
×
187
                }
188
        }
189
}
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