PluginProbe ʕ •ᴥ•ʔ
Permalink Manager Lite / 2.4.4.3
Permalink Manager Lite v2.4.4.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 1 year ago permalink-manager-seo-plugins.php 1 year ago permalink-manager-third-parties.php 1 year ago permalink-manager-woocommerce.php 1 year ago
permalink-manager-seo-plugins.php
343 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_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'] ) ) {
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 $custom_uri = ( ! empty( $element_id ) ) ? Permalink_Manager_URI_Functions::get_single_uri( $element_id, false, true, null ) : '';
161
162 if ( ! empty( $custom_uri ) ) {
163 $custom_uri = preg_replace( "/([^\/]+)$/", '', $custom_uri );
164 } else {
165 return $links;
166 }
167
168 $custom_uri_parts = explode( '/', trim( $custom_uri ) );
169 $breadcrumbs = array();
170 $snowball = '';
171 $available_taxonomies = Permalink_Manager_Helper_Functions::get_taxonomies_array( null, null, true );
172 $available_post_types = Permalink_Manager_Helper_Functions::get_post_types_array( null, null, true );
173 $available_post_types_archive = Permalink_Manager_Helper_Functions::get_post_types_array( 'archive_slug', null, true );
174 $current_filter = end( $wp_current_filter );
175
176 // Get Yoast Meta (the breadcrumbs titles can be changed in Yoast metabox)
177 $yoast_meta_terms = get_option( 'wpseo_taxonomy_meta' );
178
179 // Check what array keys should be used for breadcrumbs ("All In One SEO" uses a more complicated schema)
180 if ( $current_filter == 'aioseo_breadcrumbs_trail' ) {
181 $breadcrumb_key_text = 'label';
182 $breadcrumb_key_url = 'link';
183 $is_aioseo = true;
184 } else if ( in_array( $current_filter, array( 'wpseo_breadcrumb_links', 'slim_seo_breadcrumbs_links' ) ) ) {
185 $breadcrumb_key_text = 'text';
186 $breadcrumb_key_url = 'url';
187 $is_aioseo = false;
188 } else {
189 $breadcrumb_key_text = 0;
190 $breadcrumb_key_url = 1;
191 $is_aioseo = false;
192 }
193
194 // Get internal breadcrumb elements
195 foreach ( $custom_uri_parts as $slug ) {
196 if ( empty( $slug ) ) {
197 continue;
198 }
199
200 $snowball = ( empty( $snowball ) ) ? $slug : "{$snowball}/{$slug}";
201
202 // 1A. Try to match any custom URI
203 $uri = trim( $snowball, "/" );
204 $element = Permalink_Manager_URI_Functions::find_uri( $uri, true );
205
206 if ( ! empty( $element ) && strpos( $element, 'tax-' ) !== false ) {
207 $element_id = intval( preg_replace( "/[^0-9]/", "", $element ) );
208 $element = get_term( $element_id );
209 } else if ( is_numeric( $element ) ) {
210 $element = get_post( $element );
211 }
212
213 // 1B. Try to get term
214 if ( empty( $element ) && ! empty( $available_taxonomies ) ) {
215 $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 ) ) );
216
217 $element = $wpdb->get_row( $sql );
218 }
219
220 // 1C. Try to get page/post
221 if ( empty( $element ) && ! empty( $available_post_types ) ) {
222 $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 ) ) );
223
224 $element = $wpdb->get_row( $sql );
225 }
226
227 // 1D. Try to get post type archive
228 if ( empty( $element ) && ! empty( $available_post_types_archive ) && in_array( $snowball, $available_post_types_archive ) ) {
229 $post_type_slug = array_search( $snowball, $available_post_types_archive );
230 $element = get_post_type_object( $post_type_slug );
231 }
232
233 // 2A. When the term is found, we can add it to the breadcrumbs
234 if ( ! empty( $element->term_id ) ) {
235 $term_id = apply_filters( 'wpml_object_id', $element->term_id, $element->taxonomy, true );
236 $term = ( ( $element->term_id !== $term_id ) || $is_aioseo ) ? get_term( $term_id ) : $element;
237
238 // Alternative title
239 if ( $current_filter == 'wpseo_breadcrumb_links' ) {
240 $alt_title = ( ! empty( $yoast_meta_terms[ $term->taxonomy ][ $term->term_id ]['wpseo_bctitle'] ) ) ? $yoast_meta_terms[ $term->taxonomy ][ $term->term_id ]['wpseo_bctitle'] : '';
241 } else if ( $current_filter == 'seopress_pro_breadcrumbs_crumbs' ) {
242 $alt_title = get_term_meta( $term->term_id, '_seopress_robots_breadcrumbs', true );
243 } else if ( $current_filter == 'rank_math/frontend/breadcrumb/items' ) {
244 $alt_title = get_term_meta( $term->term_id, 'rank_math_breadcrumb_title', true );
245 }
246
247 $title = ( ! empty( $alt_title ) ) ? $alt_title : $term->name;
248
249 if ( $is_aioseo ) {
250 $breadcrumbs[] = array(
251 $breadcrumb_key_text => wp_strip_all_tags( $title ),
252 $breadcrumb_key_url => get_term_link( (int) $term->term_id, $term->taxonomy ),
253 'type' => 'taxonomy',
254 'subType' => 'parent',
255 'reference' => $term,
256 );
257 } else {
258 $breadcrumbs[] = array(
259 $breadcrumb_key_text => wp_strip_all_tags( $title ),
260 $breadcrumb_key_url => get_term_link( (int) $term->term_id, $term->taxonomy )
261 );
262 }
263 } // 2B. When the post/page is found, we can add it to the breadcrumbs
264 else if ( ! empty( $element->ID ) ) {
265 $page_id = apply_filters( 'wpml_object_id', $element->ID, $element->post_type, true );
266 $page = ( ( $element->ID !== $page_id ) || $is_aioseo ) ? get_post( $page_id ) : $element;
267
268 // Alternative title
269 if ( $current_filter == 'wpseo_breadcrumb_links' ) {
270 $alt_title = get_post_meta( $page->ID, '_yoast_wpseo_bctitle', true );
271 } else if ( $current_filter == 'seopress_pro_breadcrumbs_crumbs' ) {
272 $alt_title = get_post_meta( $page->ID, '_seopress_robots_breadcrumbs', true );
273 } else if ( $current_filter == 'rank_math/frontend/breadcrumb/items' ) {
274 $alt_title = get_post_meta( $page->ID, 'rank_math_breadcrumb_title', true );
275 }
276
277 $title = ( ! empty( $alt_title ) ) ? $alt_title : $page->post_title;
278
279 if ( $is_aioseo ) {
280 $breadcrumbs[] = array(
281 $breadcrumb_key_text => wp_strip_all_tags( $title ),
282 $breadcrumb_key_url => get_permalink( $page->ID ),
283 'type' => 'single',
284 'subType' => '',
285 'reference' => $page
286 );
287 } else {
288 $breadcrumbs[] = array(
289 $breadcrumb_key_text => wp_strip_all_tags( $title ),
290 $breadcrumb_key_url => get_permalink( $page->ID )
291 );
292 }
293 } // 2C. When the post archive is found, we can add it to the breadcrumbs
294 else if ( ! empty( $element->rewrite ) && ( ! empty( $element->labels->name ) ) ) {
295 if ( $is_aioseo ) {
296 $breadcrumbs[] = array(
297 $breadcrumb_key_text => apply_filters( 'post_type_archive_title', $element->labels->name, $element->name ),
298 $breadcrumb_key_url => get_post_type_archive_link( $element->name ),
299 'type' => 'postTypeArchive',
300 'subType' => '',
301 'reference' => $element
302 );
303 } else {
304 $breadcrumbs[] = array(
305 $breadcrumb_key_text => apply_filters( 'post_type_archive_title', $element->labels->name, $element->name ),
306 $breadcrumb_key_url => get_post_type_archive_link( $element->name )
307 );
308 }
309 }
310 }
311
312 // Add new links to current breadcrumbs array
313 if ( ! empty( $links ) && is_array( $links ) ) {
314 $first_element = reset( $links );
315 $last_element = end( $links );
316 $b_last_element = ( count( $links ) > 2 && ( ! is_singular() || is_home() ) ) ? prev( $links ) : "";
317 $breadcrumbs = ( ! empty( $breadcrumbs ) ) ? $breadcrumbs : array();
318
319 // Support RankMath/SEOPress/WooCommerce/Slim SEO/AIOSEO breadcrumbs
320 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' ) ) ) {
321 if ( $current_filter == 'slim_seo_breadcrumbs_links' ) {
322 $links = array_merge( array( $first_element ), $breadcrumbs );
323 } // 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)
324 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 ] ) ) {
325 $links = array_merge( array( $first_element ), $breadcrumbs, array( $b_last_element ), array( $last_element ) );
326 } else {
327 $links = array_merge( array( $first_element ), $breadcrumbs, array( $last_element ) );
328 }
329 } // Support Avia/Enfold breadcrumbs
330 else if ( $current_filter == 'avia_breadcrumbs_trail' ) {
331 foreach ( $breadcrumbs as &$breadcrumb ) {
332 if ( isset( $breadcrumb[ $breadcrumb_key_text ] ) ) {
333 $breadcrumb = sprintf( '<a href="%s" title="%2$s">%2$s</a>', esc_attr( $breadcrumb[ $breadcrumb_key_url ] ), esc_attr( $breadcrumb[ $breadcrumb_key_text ] ) );
334 }
335 }
336
337 $links = array_merge( array( $first_element ), $breadcrumbs, array( 'trail_end' => $last_element ) );
338 }
339 }
340
341 return array_filter( $links );
342 }
343 }