PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 18.4
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v18.4
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
wordpress-seo / src / integrations / watchers / primary-category-quick-edit-watcher.php

primary-category-quick-edit-watcher.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 18.4, at src/integrations/watchers/primary-category-quick-edit-watcher.php

193 lines 5.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 // phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded -- Base class can't be written shorter without abbreviating.
18
19 /**
20 * Class Primary_Category_Quick_Edit_Watcher
21 */
22 class Primary_Category_Quick_Edit_Watcher implements Integration_Interface {
23
24 /**
25 * Holds the options helper.
26 *
27 * @var Options_Helper
28 */
29 protected $options_helper;
30
31 /**
32 * Holds the primary term repository.
33 *
34 * @var Primary_Term_Repository
35 */
36 protected $primary_term_repository;
37
38 /**
39 * The post type helper.
40 *
41 * @var Post_Type_Helper
42 */
43 protected $post_type_helper;
44
45 /**
46 * The indexable repository.
47 *
48 * @var Indexable_Repository
49 */
50 protected $indexable_repository;
51
52 /**
53 * The indexable hierarchy builder.
54 *
55 * @var Indexable_Hierarchy_Builder
56 */
57 protected $indexable_hierarchy_builder;
58
59 /**
60 * Primary_Category_Quick_Edit_Watcher constructor.
61 *
62 * @param Options_Helper $options_helper The options helper.
63 * @param Primary_Term_Repository $primary_term_repository The primary term repository.
64 * @param Post_Type_Helper $post_type_helper The post type helper.
65 * @param Indexable_Repository $indexable_repository The indexable repository.
66 * @param Indexable_Hierarchy_Builder $indexable_hierarchy_builder The indexable hierarchy repository.
67 */
68 public function __construct(
69 Options_Helper $options_helper,
70 Primary_Term_Repository $primary_term_repository,
71 Post_Type_Helper $post_type_helper,
72 Indexable_Repository $indexable_repository,
73 Indexable_Hierarchy_Builder $indexable_hierarchy_builder
74 ) {
75 $this->options_helper = $options_helper;
76 $this->primary_term_repository = $primary_term_repository;
77 $this->post_type_helper = $post_type_helper;
78 $this->indexable_repository = $indexable_repository;
79 $this->indexable_hierarchy_builder = $indexable_hierarchy_builder;
80 }
81
82 /**
83 * Initializes the integration.
84 *
85 * This is the place to register hooks and filters.
86 *
87 * @return void
88 */
89 public function register_hooks() {
90 \add_action( 'set_object_terms', [ $this, 'validate_primary_category' ], 10, 4 );
91 }
92
93 /**
94 * Returns the conditionals based on which this loadable should be active.
95 *
96 * @return array The conditionals.
97 */
98 public static function get_conditionals() {
99 return [ Migrations_Conditional::class, Doing_Post_Quick_Edit_Save_Conditional::class ];
100 }
101
102 /**
103 * Validates if the current primary category is still present. If not just remove the post meta for it.
104 *
105 * @param int $object_id Object ID.
106 * @param array $terms Unused. An array of object terms.
107 * @param array $tt_ids An array of term taxonomy IDs.
108 * @param string $taxonomy Taxonomy slug.
109 */
110 public function validate_primary_category( $object_id, $terms, $tt_ids, $taxonomy ) {
111 $post = \get_post( $object_id );
112 if ( $post === null ) {
113 return;
114 }
115
116 $main_taxonomy = $this->options_helper->get( 'post_types-' . $post->post_type . '-maintax' );
117 if ( ! $main_taxonomy || $main_taxonomy === '0' ) {
118 return;
119 }
120
121 if ( $main_taxonomy !== $taxonomy ) {
122 return;
123 }
124
125 $primary_category = $this->get_primary_term_id( $post->ID, $main_taxonomy );
126 if ( $primary_category === false ) {
127 return;
128 }
129
130 // The primary category isn't removed.
131 if ( \in_array( (string) $primary_category, $tt_ids, true ) ) {
132 return;
133 }
134
135 $this->remove_primary_term( $post->ID, $main_taxonomy );
136
137 // Rebuild the post hierarchy for this post now the primary term has been changed.
138 $this->build_post_hierarchy( $post );
139 }
140
141 /**
142 * Returns the primary term id of a post.
143 *
144 * @param int $post_id The post ID.
145 * @param string $main_taxonomy The main taxonomy.
146 *
147 * @return int|false The ID of the primary term, or `false` if the post ID is invalid.
148 */
149 private function get_primary_term_id( $post_id, $main_taxonomy ) {
150 $primary_term = $this->primary_term_repository->find_by_post_id_and_taxonomy( $post_id, $main_taxonomy, false );
151
152 if ( $primary_term ) {
153 return $primary_term->term_id;
154 }
155
156 return \get_post_meta( $post_id, WPSEO_Meta::$meta_prefix . 'primary_' . $main_taxonomy, true );
157 }
158
159 /**
160 * Removes the primary category.
161 *
162 * @param int $post_id The post id to set primary taxonomy for.
163 * @param string $main_taxonomy Name of the taxonomy that is set to be the primary one.
164 */
165 private function remove_primary_term( $post_id, $main_taxonomy ) {
166 $primary_term = $this->primary_term_repository->find_by_post_id_and_taxonomy( $post_id, $main_taxonomy, false );
167 if ( $primary_term ) {
168 $primary_term->delete();
169 }
170
171 // Remove it from the post meta.
172 \delete_post_meta( $post_id, WPSEO_Meta::$meta_prefix . 'primary_' . $main_taxonomy );
173 }
174
175 /**
176 * Builds the hierarchy for a post.
177 *
178 * @param WP_Post $post The post.
179 */
180 public function build_post_hierarchy( $post ) {
181 if ( $this->post_type_helper->is_excluded( $post->post_type ) ) {
182 return;
183 }
184
185 $indexable = $this->indexable_repository->find_by_id_and_type( $post->ID, 'post' );
186
187 if ( $indexable instanceof Indexable ) {
188 $this->indexable_hierarchy_builder->build( $indexable );
189 }
190 }
191 }
192 // phpcs:enable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
193