Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like PostShortcodeTracking often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use PostShortcodeTracking, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
19 | class PostShortcodeTracking |
||
20 | { |
||
21 | |||
22 | /** |
||
23 | * set_hooks_admin |
||
24 | * |
||
25 | * @access public |
||
26 | */ |
||
27 | public static function set_hooks_admin() |
||
28 | { |
||
29 | add_action( |
||
30 | 'save_post', |
||
31 | array( 'EventEspresso\core\admin\PostShortcodeTracking', 'parse_post_content_on_save' ), |
||
32 | 100, |
||
33 | 2 |
||
34 | ); |
||
35 | add_action( |
||
36 | 'delete_post', |
||
37 | array( 'EventEspresso\core\admin\PostShortcodeTracking', 'unset_post_shortcodes_on_delete' ), |
||
38 | 100, |
||
39 | 1 |
||
40 | ); |
||
41 | add_action( |
||
42 | 'add_option_page_for_posts', |
||
43 | array( 'EventEspresso\core\admin\PostShortcodeTracking', 'reset_page_for_posts_on_initial_set' ), |
||
44 | 100, |
||
45 | 2 |
||
46 | ); |
||
47 | add_action( |
||
48 | 'update_option', |
||
49 | array( 'EventEspresso\core\admin\PostShortcodeTracking', 'reset_page_for_posts_on_change' ), |
||
50 | 100, |
||
51 | 3 |
||
52 | ); |
||
53 | add_action( |
||
54 | 'delete_option', |
||
55 | array( 'EventEspresso\core\admin\PostShortcodeTracking', 'reset_page_for_posts_on_delete' ), |
||
56 | 100, |
||
57 | 1 |
||
58 | ); |
||
59 | } |
||
60 | |||
61 | |||
62 | |||
63 | /** |
||
64 | * parse_post_content_on_save |
||
65 | * any time a post is saved, we need to check for any EE shortcodes that may be embedded in the content, |
||
66 | * and then track what posts those shortcodes are on, so that we can initialize shortcodes well before |
||
67 | * the_content() runs. this allows us to do things like enqueue scripts for shortcodes ONLY on the pages the |
||
68 | * shortcodes are actually used on |
||
69 | * |
||
70 | * @access public |
||
71 | * @param int $post_ID |
||
72 | * @param \WP_Post $post |
||
73 | * @return void |
||
74 | */ |
||
75 | public static function parse_post_content_on_save( $post_ID, $post ) |
||
76 | { |
||
77 | // if the post is trashed, then let's remove our post shortcode tracking |
||
78 | if ( $post instanceof \WP_Post && $post->post_status === 'trash' ) { |
||
|
|||
79 | PostShortcodeTracking::unset_post_shortcodes_on_delete( $post_ID ); |
||
80 | return; |
||
81 | } |
||
82 | // default post types |
||
83 | $post_types = array( 'post' => 0, 'page' => 1 ); |
||
84 | // add CPTs |
||
85 | $CPTs = \EE_Register_CPTs::get_CPTs(); |
||
86 | $post_types = array_merge( $post_types, $CPTs ); |
||
87 | // for default or CPT posts... |
||
88 | if ( isset( $post_types[ $post->post_type ] ) ) { |
||
89 | // post on frontpage ? |
||
90 | $page_for_posts = \EE_Config::get_page_for_posts(); |
||
91 | if ( $post->post_name === $page_for_posts ) { |
||
92 | PostShortcodeTracking::set_post_shortcodes_for_posts_page( $page_for_posts ); |
||
93 | return; |
||
94 | } |
||
95 | // array of shortcodes indexed by post name |
||
96 | \EE_Registry::CFG()->core->post_shortcodes = isset( \EE_Registry::CFG()->core->post_shortcodes ) |
||
97 | ? \EE_Registry::CFG()->core->post_shortcodes |
||
98 | : array(); |
||
99 | // whether to proceed with update |
||
100 | $update_post_shortcodes = false; |
||
101 | // empty both arrays |
||
102 | \EE_Registry::CFG()->core->post_shortcodes[ $post->post_name ] = array(); |
||
103 | // check that posts page is already being tracked |
||
104 | if ( ! isset( \EE_Registry::CFG()->core->post_shortcodes[ $page_for_posts ] ) ) { |
||
105 | // if not, then ensure that it is properly added |
||
106 | \EE_Registry::CFG()->core->post_shortcodes[ $page_for_posts ] = array(); |
||
107 | } |
||
108 | // loop thru shortcodes |
||
109 | foreach ( \EE_Registry::instance()->shortcodes as $EES_Shortcode => $shortcode_dir ) { |
||
110 | // convert to UPPERCASE to get actual shortcode |
||
111 | $EES_Shortcode = strtoupper( $EES_Shortcode ); |
||
112 | // is the shortcode in the post_content ? |
||
113 | if ( strpos( $post->post_content, $EES_Shortcode ) !== false ) { |
||
114 | // map shortcode to post names and post IDs |
||
115 | \EE_Registry::CFG()->core->post_shortcodes[ $post->post_name ][ $EES_Shortcode ] = $post_ID; |
||
116 | // and add this shortcode to the tracking for the blog page |
||
117 | PostShortcodeTracking::set_post_shortcode_for_posts_page( $page_for_posts, $EES_Shortcode, |
||
118 | $post_ID ); |
||
119 | $update_post_shortcodes = true; |
||
120 | } else { |
||
121 | // shortcode is not present in post content, so check if we were tracking it previously |
||
122 | // stop tracking if shortcode is not used in this specific post |
||
123 | if ( isset( \EE_Registry::CFG()->core->post_shortcodes[ $post->post_name ][ $EES_Shortcode ] ) ) { |
||
124 | unset( \EE_Registry::CFG()->core->post_shortcodes[ $post->post_name ][ $EES_Shortcode ] ); |
||
125 | $update_post_shortcodes = true; |
||
126 | } |
||
127 | // make sure that something is set for the shortcode posts (even though we may remove this) |
||
128 | $shortcode_posts = isset( |
||
129 | \EE_Registry::CFG()->core->post_shortcodes[ $page_for_posts ][ $EES_Shortcode ] |
||
130 | ) |
||
131 | ? \EE_Registry::CFG()->core->post_shortcodes[ $page_for_posts ][ $EES_Shortcode ] |
||
132 | : array(); |
||
133 | // and stop tracking for this shortcode on the blog page if it is not used |
||
134 | $update_post_shortcodes = PostShortcodeTracking::unset_posts_page_shortcode_for_post( |
||
135 | $post_ID, |
||
136 | $EES_Shortcode, |
||
137 | $shortcode_posts, |
||
138 | $page_for_posts, |
||
139 | $update_post_shortcodes |
||
140 | ) |
||
141 | ? true |
||
142 | : $update_post_shortcodes; |
||
143 | } |
||
144 | } |
||
145 | if ( $update_post_shortcodes ) { |
||
146 | PostShortcodeTracking::update_post_shortcodes( $page_for_posts ); |
||
147 | } |
||
148 | } |
||
149 | } |
||
150 | |||
151 | |||
152 | |||
153 | /** |
||
154 | * set_post_shortcodes_for_posts_page (plz note: shortcodes is plural) |
||
155 | * called when updating the WordPress Posts Page, |
||
156 | * and adds shortcode tracking for the Posts Page, for all shortcodes currently tracked on individual posts |
||
157 | * |
||
158 | * @access protected |
||
159 | * @param string $page_for_posts |
||
160 | * @return void |
||
161 | */ |
||
162 | protected static function set_post_shortcodes_for_posts_page( $page_for_posts ) |
||
163 | { |
||
164 | \EE_Registry::CFG()->core->post_shortcodes[ $page_for_posts ] = array(); |
||
165 | // loop thru shortcodes |
||
166 | foreach ( \EE_Registry::CFG()->core->post_shortcodes as $post_name => $post_shortcodes ) { |
||
167 | foreach ( $post_shortcodes as $EES_Shortcode => $post_ID ) { |
||
168 | PostShortcodeTracking::set_post_shortcode_for_posts_page( $page_for_posts, $EES_Shortcode, $post_ID ); |
||
169 | } |
||
170 | } |
||
171 | PostShortcodeTracking::update_post_shortcodes( $page_for_posts ); |
||
172 | } |
||
173 | |||
174 | |||
175 | |||
176 | /** |
||
177 | * set_post_shortcode_for_posts_page (plz note: shortcode is singular) |
||
178 | * adds Posts Page shortcode tracking for the supplied shortcode for an individual post |
||
179 | * |
||
180 | * @access protected |
||
181 | * @param string $page_for_posts |
||
182 | * @param $EES_Shortcode |
||
183 | * @param $post_ID |
||
184 | */ |
||
185 | protected static function set_post_shortcode_for_posts_page( $page_for_posts, $EES_Shortcode, $post_ID ) |
||
186 | { |
||
187 | // critical page shortcodes that we do NOT want added to the Posts page (blog) |
||
188 | $critical_shortcodes = \EE_Registry::CFG()->core->get_critical_pages_shortcodes_array(); |
||
189 | // if the shortcode is NOT one of the critical page shortcodes like ESPRESSO_TXN_PAGE |
||
190 | if ( in_array( $EES_Shortcode, $critical_shortcodes ) ) { |
||
191 | return; |
||
192 | } |
||
193 | // add shortcode to "Posts page" tracking |
||
194 | if ( isset( \EE_Registry::CFG()->core->post_shortcodes[ $page_for_posts ][ $EES_Shortcode ] ) ) { |
||
195 | // make sure tracking is in form of an array |
||
196 | if ( ! is_array( \EE_Registry::CFG()->core->post_shortcodes[ $page_for_posts ][ $EES_Shortcode ] ) ) { |
||
197 | \EE_Registry::CFG()->core->post_shortcodes[ $page_for_posts ][ $EES_Shortcode ] = array( |
||
198 | \EE_Registry::CFG()->core->post_shortcodes[ $page_for_posts ][ $EES_Shortcode ] => true, |
||
199 | ); |
||
200 | } |
||
201 | \EE_Registry::CFG()->core->post_shortcodes[ $page_for_posts ][ $EES_Shortcode ] += array( $post_ID => true ); |
||
202 | } else { |
||
203 | \EE_Registry::CFG()->core->post_shortcodes[ $page_for_posts ][ $EES_Shortcode ] = array( $post_ID => true ); |
||
204 | } |
||
205 | } |
||
206 | |||
207 | |||
208 | |||
209 | /** |
||
210 | * unset_post_shortcodes_on_delete |
||
211 | * |
||
212 | * @access protected |
||
213 | * @param int $ID |
||
214 | * @return void |
||
215 | */ |
||
216 | public static function unset_post_shortcodes_on_delete( $ID ) |
||
217 | { |
||
218 | $update_post_shortcodes = false; |
||
219 | // post on frontpage ? |
||
220 | $page_for_posts = \EE_Config::get_page_for_posts(); |
||
221 | // looking for any references to this post |
||
222 | foreach ( \EE_Registry::CFG()->core->post_shortcodes as $post_name => $post_shortcodes ) { |
||
223 | // is this the "Posts Page" (blog) ? |
||
224 | if ( $post_name === $page_for_posts ) { |
||
225 | // loop thru shortcodes registered for the posts page |
||
226 | foreach ( $post_shortcodes as $shortcode_class => $shortcode_posts ) { |
||
227 | $update_post_shortcodes = PostShortcodeTracking::unset_posts_page_shortcode_for_post( |
||
228 | $ID, |
||
229 | $shortcode_class, |
||
230 | $shortcode_posts, |
||
231 | $page_for_posts, |
||
232 | $update_post_shortcodes |
||
233 | ) |
||
234 | ? true |
||
235 | : $update_post_shortcodes; |
||
236 | } |
||
237 | } else { |
||
238 | // loop thru shortcodes registered for each page |
||
239 | foreach ( $post_shortcodes as $shortcode_class => $post_ID ) { |
||
240 | // if this is page is being deleted, then don't track any post shortcodes for it |
||
241 | if ( $post_ID === $ID ) { |
||
242 | unset( \EE_Registry::CFG()->core->post_shortcodes[ $post_name ] ); |
||
243 | $update_post_shortcodes = true; |
||
244 | } |
||
245 | } |
||
246 | } |
||
247 | } |
||
248 | if ( $update_post_shortcodes ) { |
||
249 | PostShortcodeTracking::update_post_shortcodes( $page_for_posts ); |
||
250 | } |
||
251 | } |
||
252 | |||
253 | |||
254 | |||
255 | /** |
||
256 | * unset_post_shortcodes_on_delete |
||
257 | * |
||
258 | * @access protected |
||
259 | * @param int $ID |
||
260 | * @param $shortcode_class |
||
261 | * @param $shortcode_posts |
||
262 | * @param $page_for_posts |
||
263 | * @param bool $update_post_shortcodes |
||
264 | * @return bool |
||
265 | */ |
||
266 | protected static function unset_posts_page_shortcode_for_post( |
||
292 | |||
293 | |||
294 | |||
295 | /** |
||
296 | * update_post_shortcodes |
||
297 | * |
||
298 | * @access public |
||
299 | * @param $page_for_posts |
||
300 | * @return void |
||
301 | */ |
||
302 | public static function update_post_shortcodes( $page_for_posts = '' ) |
||
359 | |||
360 | |||
361 | |||
362 | /** |
||
363 | * reset_page_for_posts_on_initial_set |
||
364 | * if an admin is on the WP Reading Settings page and sets the option for "Posts page", |
||
365 | * when it had previously been unset, |
||
366 | * then we need to attribute any actively used shortcodes to the new blog page |
||
367 | * |
||
368 | * @access public |
||
369 | * @param string $option |
||
370 | * @param string $value |
||
371 | * @return void |
||
372 | */ |
||
373 | public static function reset_page_for_posts_on_initial_set( $option, $value ) |
||
377 | |||
378 | |||
379 | |||
380 | /** |
||
381 | * reset_page_for_posts_on_change |
||
382 | * if an admin is on the WP Reading Settings page and changes the option for "Posts page", |
||
383 | * then we need to attribute any actively used shortcodes for the previous blog page to the new blog page |
||
384 | * |
||
385 | * @access public |
||
386 | * @param string $option |
||
387 | * @param string $old_value |
||
388 | * @param string $value |
||
389 | * @return void |
||
390 | */ |
||
391 | public static function reset_page_for_posts_on_change( $option, $old_value = '', $value = '' ) |
||
401 | |||
402 | |||
403 | |||
404 | /** |
||
405 | * reset_page_for_posts_on_delete |
||
406 | * if an admin deletes a page designated as the WP "Posts page", |
||
407 | * then we need to attribute any actively used shortcodes for that blog page to a generic 'posts' page |
||
408 | * |
||
409 | * @access public |
||
410 | * @param string $option |
||
411 | * @return void |
||
412 | */ |
||
413 | public static function reset_page_for_posts_on_delete( $option ) |
||
419 | |||
420 | |||
421 | |||
422 | /** |
||
423 | * @param array|string $shortcodes |
||
424 | * @param bool $index_results if passing more than one shortcode for the $shortcodes parameter above, |
||
425 | * then setting this to true, will return as associative array indexed by |
||
426 | * the shortcodes. If false, then the returned array will be unindexed |
||
427 | * @return array |
||
428 | */ |
||
429 | public static function get_post_ids_for_shortcode( $shortcodes, $index_results = true ) |
||
466 | |||
467 | |||
468 | |||
469 | } |
||
470 | // End of file PostShortcodeTracking.php |
||
471 | // Location: /PostShortcodeTracking.php |
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.