PluginProbe ʕ •ᴥ•ʔ
Permalink Manager Lite / 2.4.3.3
Permalink Manager Lite v2.4.3.3
2.5.4 2.5.3.4 2.2.18 2.2.19.2 2.2.19.3 2.2.19.3.1 2.2.2 2.2.20 2.2.20.1 2.2.20.3 2.2.4 2.2.5 2.2.6 2.2.7.2 2.2.7.3 2.2.7.5 2.2.7.6 2.2.8.4 2.2.8.5 2.2.8.6 2.2.8.7 2.2.8.9 2.2.9.1 2.2.9.2 2.2.9.2.1 2.2.9.3 2.2.9.4 2.2.9.6 2.2.9.7 2.2.9.9 2.3.0 2.3.1.1 2.4.0 2.4.1 2.4.1.2 2.4.1.3 2.4.1.4 2.4.1.5 2.4.1.6 2.4.2 2.4.2.1 2.4.3 2.4.3.1 2.4.3.2 2.4.3.3 2.4.3.4 2.4.4 2.4.4.1 2.4.4.2 2.4.4.3 2.5.0 2.5.1 2.5.1.1 2.5.1.2 2.5.1.3 2.5.1.4 2.5.2 2.5.2.1 2.5.2.2 2.5.2.3 2.5.2.4 2.5.3 2.5.3.1 2.5.3.2 2.5.3.3 trunk 0.2 0.3 0.3.1 0.3.2 0.3.3 0.3.4 0.4 0.4.1 0.4.2 0.4.3 0.4.4 0.4.6 0.4.7 0.4.8 0.4.9 0.5.3 0.5.4 1.0.0 1.0.1 1.0.4 1.1.0 1.1.1 1.1.2 1.11.6.3 2.0.0 2.0.3 2.0.4 2.0.4.3 2.0.5.1 2.0.5.2 2.0.5.3 2.0.5.3.1 2.0.5.4 2.0.5.4a 2.0.5.5 2.0.5.6 2.0.5.6.1 2.0.5.7 2.0.5.9a 2.0.6.2.1 2.0.6.2a 2.0.6.3 2.1.0 2.1.1 2.1.2.4 2.2.0 2.2.1.1 2.2.1.2 2.2.11 2.2.12 2.2.13.1 2.2.14 2.2.15.1 2.2.16 2.2.17
permalink-manager / includes / integrations / permalink-manager-seo-plugins.php
permalink-manager / includes / integrations Last commit date
permalink-manager-language-plugins.php 2 years ago permalink-manager-seo-plugins.php 2 years ago permalink-manager-third-parties.php 2 years ago permalink-manager-woocommerce.php 2 years ago
permalink-manager-seo-plugins.php
342 lines
1 <?php
2
3 /**
4 * SEO plugins integration
5 */
6 class Permalink_Manager_SEO_Plugins {
7
8 public function __construct() {
9 add_action( 'init', array( $this, 'init_hooks' ), 99 );
10 }
11
12 /**
13 * Add support for SEO plugins using their hooks
14 */
15 function init_hooks() {
16 // Yoast SEO
17 add_filter( 'wpseo_xml_sitemap_post_url', array( $this, 'yoast_fix_sitemap_urls' ), 9 );
18 if ( defined( 'WPSEO_VERSION' ) && version_compare( WPSEO_VERSION, '14.0', '>=' ) ) {
19 add_action( 'permalink_manager_updated_post_uri', array( $this, 'yoast_update_indexable_permalink' ), 10, 3 );
20 add_action( 'permalink_manager_updated_term_uri', array( $this, 'yoast_update_indexable_permalink' ), 10, 3 );
21 add_filter( 'wpseo_canonical', array( $this, 'yoast_fix_canonical' ), 10 );
22 add_filter( 'wpseo_opengraph_url', array( $this, 'yoast_fix_canonical' ), 10 );
23 add_filter( 'wpseo_dynamic_permalinks_enabled', '__return_true', 5 );
24 }
25
26 // Breadcrumbs
27 add_filter( 'wpseo_breadcrumb_links', array( $this, 'filter_breadcrumbs' ), 9 );
28 add_filter( 'rank_math/frontend/breadcrumb/items', array( $this, 'filter_breadcrumbs' ), 9 );
29 add_filter( 'seopress_pro_breadcrumbs_crumbs', array( $this, 'filter_breadcrumbs' ), 9 );
30 add_filter( 'woocommerce_get_breadcrumb', array( $this, 'filter_breadcrumbs' ), 9 );
31 add_filter( 'slim_seo_breadcrumbs_links', array( $this, 'filter_breadcrumbs' ), 9 );
32 add_filter( 'aioseo_breadcrumbs_trail', array( $this, 'filter_breadcrumbs' ), 9 );
33 add_filter( 'avia_breadcrumbs_trail', array( $this, 'filter_breadcrumbs' ), 100 );
34 }
35
36 /**
37 * Get the HTTP protocol of the home URL and use it in Yoast SEO sitemap permalinks
38 *
39 * @param string $permalink The permalink in the sitemap
40 *
41 * @return string The sitemap's permalink
42 */
43 function yoast_fix_sitemap_urls( $permalink ) {
44 if ( class_exists( 'WPSEO_Utils' ) ) {
45 $home_url = WPSEO_Utils::home_url();
46 $home_protocol = parse_url( $home_url, PHP_URL_SCHEME );
47
48 $permalink = preg_replace( "/^http(s)?/", $home_protocol, $permalink );
49 }
50
51 return $permalink;
52 }
53
54 /**
55 * Update the permalink in the Yoast SEO indexable table when the permalink is changed
56 *
57 * @param int $element_id The ID of the post/term element that was updated.
58 * @param string $new_uri The new URI of the element.
59 * @param string $old_uri The old URI of the element.
60 */
61 function yoast_update_indexable_permalink( $element_id, $new_uri, $old_uri ) {
62 global $wpdb;
63
64 if ( ! empty( $new_uri ) && ! empty( $old_uri ) && $new_uri !== $old_uri ) {
65 if ( current_filter() == 'permalink_manager_updated_term_uri' ) {
66 $permalink = get_term_link( (int) $element_id );
67 $object_type = 'term';
68 } else {
69 $permalink = get_permalink( $element_id );
70 $object_type = 'post';
71 }
72
73 if ( ! empty( $permalink ) ) {
74 $permalink_hash = strlen( $permalink ) . ':' . md5( $permalink );
75 $wpdb->update( "{$wpdb->prefix}yoast_indexable", array( 'permalink' => $permalink, 'permalink_hash' => $permalink_hash ), array( 'object_id' => $element_id, 'object_type' => $object_type ), array( '%s', '%s' ), array( '%d', '%s' ) );
76 }
77 }
78 }
79
80 /**
81 * Filter the canonical permalink used by SEO using 'wpseo_canonical' & 'wpseo_opengraph_url' hooks
82 *
83 * @param string $url The canonical URL that Yoast SEO has generated.
84 *
85 * @return string the URL.
86 */
87 function yoast_fix_canonical( $url ) {
88 global $pm_query, $wp_rewrite;
89
90 if ( ! empty( $pm_query['id'] ) ) {
91 $element = get_queried_object();
92
93 if ( ! empty( $element->ID ) && ! empty( $element->post_type ) ) {
94 $new_url = get_permalink( $element->ID );
95
96 // Do not filter if custom canonical URL is set
97 $yoast_canonical_url = get_post_meta( $element->ID, '_yoast_wpseo_canonical', true );
98 if ( ! empty( $yoast_canonical_url ) ) {
99 return $url;
100 }
101
102 if ( is_home() ) {
103 $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
104 $new_url = ( $paged > 1 ) ? sprintf( '%s/%s/%d', trim( $new_url, '/' ), $wp_rewrite->pagination_base, $paged ) : $new_url;
105 } else {
106 $paged = ( get_query_var( 'page' ) ) ? get_query_var( 'page' ) : 1;
107 $new_url = ( $paged > 1 ) ? sprintf( '%s/%d', trim( $new_url, '/' ), $paged ) : $new_url;
108 }
109 } else if ( ! empty( $element->taxonomy ) && ! empty( $element->term_id ) ) {
110 $new_url = get_term_link( $element, $element->taxonomy );
111
112 // Do not filter if custom canonical URL is set
113 if ( class_exists( 'WPSEO_Taxonomy_Meta' ) ) {
114 $yoast_canonical_url = WPSEO_Taxonomy_Meta::get_term_meta( $element, $element->taxonomy, 'canonical' );
115 if ( ! empty( $yoast_canonical_url ) ) {
116 return $url;
117 }
118 }
119
120 $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
121 if ( $paged > 1 ) {
122 $new_url = sprintf( '%s/%s/%d', trim( $new_url, '/' ), $wp_rewrite->pagination_base, $paged );
123 }
124 }
125
126 $url = ( ! empty( $new_url ) ) ? $new_url : $url;
127 $url = Permalink_Manager_Core_Functions::control_trailing_slashes( $url );
128 }
129
130 return $url;
131 }
132
133 /**
134 * Filter the breadcrumbs array to match the structure of currently requested URL
135 *
136 * @param array $links The current breadcrumb links.
137 *
138 * @return array The $links array.
139 */
140 function filter_breadcrumbs( $links ) {
141 // Get post type permastructure settings
142 global $permalink_manager_uris, $permalink_manager_options, $post, $wpdb, $wp, $wp_current_filter;
143
144 // Check if the filter should be activated
145 if ( empty( $permalink_manager_options['general']['yoast_breadcrumbs'] ) || empty( $permalink_manager_uris ) ) {
146 return $links;
147 }
148
149 // Get current post/page/term (if available)
150 $queried_element = get_queried_object();
151 if ( ! empty( $queried_element->ID ) ) {
152 $element_id = $queried_element->ID;
153 } else if ( ! empty( $queried_element->term_id ) ) {
154 $element_id = "tax-{$queried_element->term_id}";
155 } else if ( defined( 'REST_REQUEST' ) && ! empty( $post->ID ) ) {
156 $element_id = $post->ID;
157 }
158
159 // Get the custom permalink (if available) or the current request URL (if unavailable)
160 if ( ! empty( $element_id ) && ! empty( $permalink_manager_uris[ $element_id ] ) ) {
161 $custom_uri = preg_replace( "/([^\/]+)$/", '', $permalink_manager_uris[ $element_id ] );
162 } else {
163 $custom_uri = trim( preg_replace( "/([^\/]+)$/", '', $wp->request ), "/" );
164 }
165
166 $all_uris = array_flip( $permalink_manager_uris );
167 $custom_uri_parts = explode( '/', trim( $custom_uri ) );
168 $breadcrumbs = array();
169 $snowball = '';
170 $available_taxonomies = Permalink_Manager_Helper_Functions::get_taxonomies_array( null, null, true );
171 $available_post_types = Permalink_Manager_Helper_Functions::get_post_types_array( null, null, true );
172 $available_post_types_archive = Permalink_Manager_Helper_Functions::get_post_types_array( 'archive_slug', null, true );
173 $current_filter = end( $wp_current_filter );
174
175 // Get Yoast Meta (the breadcrumbs titles can be changed in Yoast metabox)
176 $yoast_meta_terms = get_option( 'wpseo_taxonomy_meta' );
177
178 // Check what array keys should be used for breadcrumbs ("All In One SEO" uses a more complicated schema)
179 if ( $current_filter == 'aioseo_breadcrumbs_trail' ) {
180 $breadcrumb_key_text = 'label';
181 $breadcrumb_key_url = 'link';
182 $is_aioseo = true;
183 } else if ( in_array( $current_filter, array( 'wpseo_breadcrumb_links', 'slim_seo_breadcrumbs_links' ) ) ) {
184 $breadcrumb_key_text = 'text';
185 $breadcrumb_key_url = 'url';
186 $is_aioseo = false;
187 } else {
188 $breadcrumb_key_text = 0;
189 $breadcrumb_key_url = 1;
190 $is_aioseo = false;
191 }
192
193 // Get internal breadcrumb elements
194 foreach ( $custom_uri_parts as $slug ) {
195 if ( empty( $slug ) ) {
196 continue;
197 }
198
199 $snowball = ( empty( $snowball ) ) ? $slug : "{$snowball}/{$slug}";
200
201 // 1A. Try to match any custom URI
202 $uri = trim( $snowball, "/" );
203 $element = ( ! empty( $all_uris[ $uri ] ) ) ? $all_uris[ $uri ] : false;
204
205 if ( ! empty( $element ) && strpos( $element, 'tax-' ) !== false ) {
206 $element_id = intval( preg_replace( "/[^0-9]/", "", $element ) );
207 $element = get_term( $element_id );
208 } else if ( is_numeric( $element ) ) {
209 $element = get_post( $element );
210 }
211
212 // 1B. Try to get term
213 if ( empty( $element ) && ! empty( $available_taxonomies ) ) {
214 $sql = sprintf( "SELECT t.term_id, t.name, tt.taxonomy FROM {$wpdb->terms} AS t LEFT JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE slug = '%s' AND tt.taxonomy IN ('%s') LIMIT 1", esc_sql( $slug ), implode( "','", array_keys( $available_taxonomies ) ) );
215
216 $element = $wpdb->get_row( $sql );
217 }
218
219 // 1C. Try to get page/post
220 if ( empty( $element ) && ! empty( $available_post_types ) ) {
221 $sql = sprintf( "SELECT ID, post_title, post_type FROM {$wpdb->posts} WHERE post_name = '%s' AND post_status = 'publish' AND post_type IN ('%s') AND post_type != 'attachment' LIMIT 1", esc_sql( $slug ), implode( "','", array_keys( $available_post_types ) ) );
222
223 $element = $wpdb->get_row( $sql );
224 }
225
226 // 1D. Try to get post type archive
227 if ( empty( $element ) && ! empty( $available_post_types_archive ) && in_array( $snowball, $available_post_types_archive ) ) {
228 $post_type_slug = array_search( $snowball, $available_post_types_archive );
229 $element = get_post_type_object( $post_type_slug );
230 }
231
232 // 2A. When the term is found, we can add it to the breadcrumbs
233 if ( ! empty( $element->term_id ) ) {
234 $term_id = apply_filters( 'wpml_object_id', $element->term_id, $element->taxonomy, true );
235 $term = ( ( $element->term_id !== $term_id ) || $is_aioseo ) ? get_term( $term_id ) : $element;
236
237 // Alternative title
238 if ( $current_filter == 'wpseo_breadcrumb_links' ) {
239 $alt_title = ( ! empty( $yoast_meta_terms[ $term->taxonomy ][ $term->term_id ]['wpseo_bctitle'] ) ) ? $yoast_meta_terms[ $term->taxonomy ][ $term->term_id ]['wpseo_bctitle'] : '';
240 } else if ( $current_filter == 'seopress_pro_breadcrumbs_crumbs' ) {
241 $alt_title = get_term_meta( $term->term_id, '_seopress_robots_breadcrumbs', true );
242 } else if ( $current_filter == 'rank_math/frontend/breadcrumb/items' ) {
243 $alt_title = get_term_meta( $term->term_id, 'rank_math_breadcrumb_title', true );
244 }
245
246 $title = ( ! empty( $alt_title ) ) ? $alt_title : $term->name;
247
248 if ( $is_aioseo ) {
249 $breadcrumbs[] = array(
250 $breadcrumb_key_text => wp_strip_all_tags( $title ),
251 $breadcrumb_key_url => get_term_link( (int) $term->term_id, $term->taxonomy ),
252 'type' => 'taxonomy',
253 'subType' => 'parent',
254 'reference' => $term,
255 );
256 } else {
257 $breadcrumbs[] = array(
258 $breadcrumb_key_text => wp_strip_all_tags( $title ),
259 $breadcrumb_key_url => get_term_link( (int) $term->term_id, $term->taxonomy )
260 );
261 }
262 } // 2B. When the post/page is found, we can add it to the breadcrumbs
263 else if ( ! empty( $element->ID ) ) {
264 $page_id = apply_filters( 'wpml_object_id', $element->ID, $element->post_type, true );
265 $page = ( ( $element->ID !== $page_id ) || $is_aioseo ) ? get_post( $page_id ) : $element;
266
267 // Alternative title
268 if ( $current_filter == 'wpseo_breadcrumb_links' ) {
269 $alt_title = get_post_meta( $page->ID, '_yoast_wpseo_bctitle', true );
270 } else if ( $current_filter == 'seopress_pro_breadcrumbs_crumbs' ) {
271 $alt_title = get_post_meta( $page->ID, '_seopress_robots_breadcrumbs', true );
272 } else if ( $current_filter == 'rank_math/frontend/breadcrumb/items' ) {
273 $alt_title = get_post_meta( $page->ID, 'rank_math_breadcrumb_title', true );
274 }
275
276 $title = ( ! empty( $alt_title ) ) ? $alt_title : $page->post_title;
277
278 if ( $is_aioseo ) {
279 $breadcrumbs[] = array(
280 $breadcrumb_key_text => wp_strip_all_tags( $title ),
281 $breadcrumb_key_url => get_permalink( $page->ID ),
282 'type' => 'single',
283 'subType' => '',
284 'reference' => $page
285 );
286 } else {
287 $breadcrumbs[] = array(
288 $breadcrumb_key_text => wp_strip_all_tags( $title ),
289 $breadcrumb_key_url => get_permalink( $page->ID )
290 );
291 }
292 } // 2C. When the post archive is found, we can add it to the breadcrumbs
293 else if ( ! empty( $element->rewrite ) && ( ! empty( $element->labels->name ) ) ) {
294 if ( $is_aioseo ) {
295 $breadcrumbs[] = array(
296 $breadcrumb_key_text => apply_filters( 'post_type_archive_title', $element->labels->name, $element->name ),
297 $breadcrumb_key_url => get_post_type_archive_link( $element->name ),
298 'type' => 'postTypeArchive',
299 'subType' => '',
300 'reference' => $element
301 );
302 } else {
303 $breadcrumbs[] = array(
304 $breadcrumb_key_text => apply_filters( 'post_type_archive_title', $element->labels->name, $element->name ),
305 $breadcrumb_key_url => get_post_type_archive_link( $element->name )
306 );
307 }
308 }
309 }
310
311 // Add new links to current breadcrumbs array
312 if ( ! empty( $links ) && is_array( $links ) ) {
313 $first_element = reset( $links );
314 $last_element = end( $links );
315 $b_last_element = prev( $links );
316 $breadcrumbs = ( ! empty( $breadcrumbs ) ) ? $breadcrumbs : array();
317
318 // Support RankMath/SEOPress/WooCommerce/Slim SEO/AIOSEO breadcrumbs
319 if ( in_array( $current_filter, array( 'wpseo_breadcrumb_links', 'rank_math/frontend/breadcrumb/items', 'seopress_pro_breadcrumbs_crumbs', 'woocommerce_get_breadcrumb', 'slim_seo_breadcrumbs_links', 'aioseo_breadcrumbs_trail' ) ) ) {
320 if ( $current_filter == 'slim_seo_breadcrumbs_links' ) {
321 $links = array_merge( array( $first_element ), $breadcrumbs );
322 } // Append the element before the last element if the last breadcrumb does not have a URL set (e.g. if the /page/ endpoint is used)
323 else if ( ! in_array( $current_filter, array( 'aioseo_breadcrumbs_trail', 'slim_seo_breadcrumbs_links' ) ) && ! empty( $wp->query_vars['paged'] ) && $wp->query_vars['paged'] > 1 && ! empty( $b_last_element[ $breadcrumb_key_url ] ) ) {
324 $links = array_merge( array( $first_element ), $breadcrumbs, array( $b_last_element ), array( $last_element ) );
325 } else {
326 $links = array_merge( array( $first_element ), $breadcrumbs, array( $last_element ) );
327 }
328 } // Support Avia/Enfold breadcrumbs
329 else if ( $current_filter == 'avia_breadcrumbs_trail' ) {
330 foreach ( $breadcrumbs as &$breadcrumb ) {
331 if ( isset( $breadcrumb[ $breadcrumb_key_text ] ) ) {
332 $breadcrumb = sprintf( '<a href="%s" title="%2$s">%2$s</a>', esc_attr( $breadcrumb[ $breadcrumb_key_url ] ), esc_attr( $breadcrumb[ $breadcrumb_key_text ] ) );
333 }
334 }
335
336 $links = array_merge( array( $first_element ), $breadcrumbs, array( 'trail_end' => $last_element ) );
337 }
338 }
339
340 return array_filter( $links );
341 }
342 }