7 * @since 2.9.0 |
7 * @since 2.9.0 |
8 */ |
8 */ |
9 class WP_Embed { |
9 class WP_Embed { |
10 public $handlers = array(); |
10 public $handlers = array(); |
11 public $post_ID; |
11 public $post_ID; |
12 public $usecache = true; |
12 public $usecache = true; |
13 public $linkifunknown = true; |
13 public $linkifunknown = true; |
14 public $last_attr = array(); |
14 public $last_attr = array(); |
15 public $last_url = ''; |
15 public $last_url = ''; |
16 |
16 |
17 /** |
17 /** |
18 * When a URL cannot be embedded, return false instead of returning a link |
18 * When a URL cannot be embedded, return false instead of returning a link |
19 * or the URL. |
19 * or the URL. |
20 * |
20 * |
79 * an Ajax request that will call WP_Embed::cache_oembed(). |
79 * an Ajax request that will call WP_Embed::cache_oembed(). |
80 */ |
80 */ |
81 public function maybe_run_ajax_cache() { |
81 public function maybe_run_ajax_cache() { |
82 $post = get_post(); |
82 $post = get_post(); |
83 |
83 |
84 if ( ! $post || empty( $_GET['message'] ) ) |
84 if ( ! $post || empty( $_GET['message'] ) ) { |
85 return; |
85 return; |
86 |
86 } |
87 ?> |
87 |
|
88 ?> |
88 <script type="text/javascript"> |
89 <script type="text/javascript"> |
89 jQuery(document).ready(function($){ |
90 jQuery(document).ready(function($){ |
90 $.get("<?php echo admin_url( 'admin-ajax.php?action=oembed-cache&post=' . $post->ID, 'relative' ); ?>"); |
91 $.get("<?php echo admin_url( 'admin-ajax.php?action=oembed-cache&post=' . $post->ID, 'relative' ); ?>"); |
91 }); |
92 }); |
92 </script> |
93 </script> |
93 <?php |
94 <?php |
94 } |
95 } |
95 |
96 |
96 /** |
97 /** |
97 * Registers an embed handler. |
98 * Registers an embed handler. |
98 * |
99 * |
104 * @param string $regex The regex that will be used to see if this handler should be used for a URL. |
105 * @param string $regex The regex that will be used to see if this handler should be used for a URL. |
105 * @param callable $callback The callback function that will be called if the regex is matched. |
106 * @param callable $callback The callback function that will be called if the regex is matched. |
106 * @param int $priority Optional. Used to specify the order in which the registered handlers will be tested (default: 10). Lower numbers correspond with earlier testing, and handlers with the same priority are tested in the order in which they were added to the action. |
107 * @param int $priority Optional. Used to specify the order in which the registered handlers will be tested (default: 10). Lower numbers correspond with earlier testing, and handlers with the same priority are tested in the order in which they were added to the action. |
107 */ |
108 */ |
108 public function register_handler( $id, $regex, $callback, $priority = 10 ) { |
109 public function register_handler( $id, $regex, $callback, $priority = 10 ) { |
109 $this->handlers[$priority][$id] = array( |
110 $this->handlers[ $priority ][ $id ] = array( |
110 'regex' => $regex, |
111 'regex' => $regex, |
111 'callback' => $callback, |
112 'callback' => $callback, |
112 ); |
113 ); |
113 } |
114 } |
114 |
115 |
154 $this->last_attr = $attr; |
155 $this->last_attr = $attr; |
155 return ''; |
156 return ''; |
156 } |
157 } |
157 |
158 |
158 $rawattr = $attr; |
159 $rawattr = $attr; |
159 $attr = wp_parse_args( $attr, wp_embed_defaults( $url ) ); |
160 $attr = wp_parse_args( $attr, wp_embed_defaults( $url ) ); |
160 |
161 |
161 $this->last_attr = $attr; |
162 $this->last_attr = $attr; |
162 |
163 |
163 // kses converts & into & and we need to undo this |
164 // kses converts & into & and we need to undo this |
164 // See https://core.trac.wordpress.org/ticket/11311 |
165 // See https://core.trac.wordpress.org/ticket/11311 |
167 // Look for known internal handlers |
168 // Look for known internal handlers |
168 ksort( $this->handlers ); |
169 ksort( $this->handlers ); |
169 foreach ( $this->handlers as $priority => $handlers ) { |
170 foreach ( $this->handlers as $priority => $handlers ) { |
170 foreach ( $handlers as $id => $handler ) { |
171 foreach ( $handlers as $id => $handler ) { |
171 if ( preg_match( $handler['regex'], $url, $matches ) && is_callable( $handler['callback'] ) ) { |
172 if ( preg_match( $handler['regex'], $url, $matches ) && is_callable( $handler['callback'] ) ) { |
172 if ( false !== $return = call_user_func( $handler['callback'], $matches, $attr, $url, $rawattr ) ) |
173 if ( false !== $return = call_user_func( $handler['callback'], $matches, $attr, $url, $rawattr ) ) { |
173 /** |
174 /** |
174 * Filters the returned embed handler. |
175 * Filters the returned embed handler. |
175 * |
176 * |
176 * @since 2.9.0 |
177 * @since 2.9.0 |
177 * |
178 * |
180 * @param mixed $return The shortcode callback function to call. |
181 * @param mixed $return The shortcode callback function to call. |
181 * @param string $url The attempted embed URL. |
182 * @param string $url The attempted embed URL. |
182 * @param array $attr An array of shortcode attributes. |
183 * @param array $attr An array of shortcode attributes. |
183 */ |
184 */ |
184 return apply_filters( 'embed_handler_html', $return, $url, $attr ); |
185 return apply_filters( 'embed_handler_html', $return, $url, $attr ); |
|
186 } |
185 } |
187 } |
186 } |
188 } |
187 } |
189 } |
188 |
190 |
189 $post_ID = ( ! empty( $post->ID ) ) ? $post->ID : null; |
191 $post_ID = ( ! empty( $post->ID ) ) ? $post->ID : null; |
214 $cache_time = 0; |
216 $cache_time = 0; |
215 |
217 |
216 $cached_post_id = $this->find_oembed_post_id( $key_suffix ); |
218 $cached_post_id = $this->find_oembed_post_id( $key_suffix ); |
217 |
219 |
218 if ( $post_ID ) { |
220 if ( $post_ID ) { |
219 $cache = get_post_meta( $post_ID, $cachekey, true ); |
221 $cache = get_post_meta( $post_ID, $cachekey, true ); |
220 $cache_time = get_post_meta( $post_ID, $cachekey_time, true ); |
222 $cache_time = get_post_meta( $post_ID, $cachekey_time, true ); |
221 |
223 |
222 if ( ! $cache_time ) { |
224 if ( ! $cache_time ) { |
223 $cache_time = 0; |
225 $cache_time = 0; |
224 } |
226 } |
283 // Prevent KSES from corrupting JSON in post_content. |
285 // Prevent KSES from corrupting JSON in post_content. |
284 kses_remove_filters(); |
286 kses_remove_filters(); |
285 } |
287 } |
286 |
288 |
287 $insert_post_args = array( |
289 $insert_post_args = array( |
288 'post_name' => $key_suffix, |
290 'post_name' => $key_suffix, |
289 'post_status' => 'publish', |
291 'post_status' => 'publish', |
290 'post_type' => 'oembed_cache', |
292 'post_type' => 'oembed_cache', |
291 ); |
293 ); |
292 |
294 |
293 if ( $html ) { |
295 if ( $html ) { |
294 if ( $cached_post_id ) { |
296 if ( $cached_post_id ) { |
295 wp_update_post( wp_slash( array( |
297 wp_update_post( |
296 'ID' => $cached_post_id, |
298 wp_slash( |
297 'post_content' => $html, |
299 array( |
298 ) ) ); |
300 'ID' => $cached_post_id, |
|
301 'post_content' => $html, |
|
302 ) |
|
303 ) |
|
304 ); |
299 } else { |
305 } else { |
300 wp_insert_post( wp_slash( array_merge( |
306 wp_insert_post( |
301 $insert_post_args, |
307 wp_slash( |
302 array( |
308 array_merge( |
303 'post_content' => $html, |
309 $insert_post_args, |
|
310 array( |
|
311 'post_content' => $html, |
|
312 ) |
|
313 ) |
304 ) |
314 ) |
305 ) ) ); |
315 ); |
306 } |
316 } |
307 } elseif ( ! $cache ) { |
317 } elseif ( ! $cache ) { |
308 wp_insert_post( wp_slash( array_merge( |
318 wp_insert_post( |
309 $insert_post_args, |
319 wp_slash( |
310 array( |
320 array_merge( |
311 'post_content' => '{{unknown}}', |
321 $insert_post_args, |
|
322 array( |
|
323 'post_content' => '{{unknown}}', |
|
324 ) |
|
325 ) |
312 ) |
326 ) |
313 ) ) ); |
327 ); |
314 } |
328 } |
315 |
329 |
316 if ( $has_kses ) { |
330 if ( $has_kses ) { |
317 kses_init_filters(); |
331 kses_init_filters(); |
318 } |
332 } |
333 * |
347 * |
334 * @param int $post_ID Post ID to delete the caches for. |
348 * @param int $post_ID Post ID to delete the caches for. |
335 */ |
349 */ |
336 public function delete_oembed_caches( $post_ID ) { |
350 public function delete_oembed_caches( $post_ID ) { |
337 $post_metas = get_post_custom_keys( $post_ID ); |
351 $post_metas = get_post_custom_keys( $post_ID ); |
338 if ( empty($post_metas) ) |
352 if ( empty( $post_metas ) ) { |
339 return; |
353 return; |
|
354 } |
340 |
355 |
341 foreach ( $post_metas as $post_meta_key ) { |
356 foreach ( $post_metas as $post_meta_key ) { |
342 if ( '_oembed_' == substr( $post_meta_key, 0, 8 ) ) |
357 if ( '_oembed_' == substr( $post_meta_key, 0, 8 ) ) { |
343 delete_post_meta( $post_ID, $post_meta_key ); |
358 delete_post_meta( $post_ID, $post_meta_key ); |
|
359 } |
344 } |
360 } |
345 } |
361 } |
346 |
362 |
347 /** |
363 /** |
348 * Triggers a caching of all oEmbed results. |
364 * Triggers a caching of all oEmbed results. |
356 /** |
372 /** |
357 * Filters the array of post types to cache oEmbed results for. |
373 * Filters the array of post types to cache oEmbed results for. |
358 * |
374 * |
359 * @since 2.9.0 |
375 * @since 2.9.0 |
360 * |
376 * |
361 * @param array $post_types Array of post types to cache oEmbed results for. Defaults to post types with `show_ui` set to true. |
377 * @param string[] $post_types Array of post type names to cache oEmbed results for. Defaults to post types with `show_ui` set to true. |
362 */ |
378 */ |
363 if ( empty( $post->ID ) || ! in_array( $post->post_type, apply_filters( 'embed_cache_oembed_types', $post_types ) ) ){ |
379 if ( empty( $post->ID ) || ! in_array( $post->post_type, apply_filters( 'embed_cache_oembed_types', $post_types ) ) ) { |
364 return; |
380 return; |
365 } |
381 } |
366 |
382 |
367 // Trigger a caching |
383 // Trigger a caching |
368 if ( ! empty( $post->post_content ) ) { |
384 if ( ! empty( $post->post_content ) ) { |
369 $this->post_ID = $post->ID; |
385 $this->post_ID = $post->ID; |
370 $this->usecache = false; |
386 $this->usecache = false; |
371 |
387 |
372 $content = $this->run_shortcode( $post->post_content ); |
388 $content = $this->run_shortcode( $post->post_content ); |
373 $this->autoembed( $content ); |
389 $this->autoembed( $content ); |
374 |
390 |
404 * |
420 * |
405 * @param array $match A regex match array. |
421 * @param array $match A regex match array. |
406 * @return string The embed HTML on success, otherwise the original URL. |
422 * @return string The embed HTML on success, otherwise the original URL. |
407 */ |
423 */ |
408 public function autoembed_callback( $match ) { |
424 public function autoembed_callback( $match ) { |
409 $oldval = $this->linkifunknown; |
425 $oldval = $this->linkifunknown; |
410 $this->linkifunknown = false; |
426 $this->linkifunknown = false; |
411 $return = $this->shortcode( array(), $match[2] ); |
427 $return = $this->shortcode( array(), $match[2] ); |
412 $this->linkifunknown = $oldval; |
428 $this->linkifunknown = $oldval; |
413 |
429 |
414 return $match[1] . $return . $match[3]; |
430 return $match[1] . $return . $match[3]; |
415 } |
431 } |
416 |
432 |
423 public function maybe_make_link( $url ) { |
439 public function maybe_make_link( $url ) { |
424 if ( $this->return_false_on_fail ) { |
440 if ( $this->return_false_on_fail ) { |
425 return false; |
441 return false; |
426 } |
442 } |
427 |
443 |
428 $output = ( $this->linkifunknown ) ? '<a href="' . esc_url($url) . '">' . esc_html($url) . '</a>' : $url; |
444 $output = ( $this->linkifunknown ) ? '<a href="' . esc_url( $url ) . '">' . esc_html( $url ) . '</a>' : $url; |
429 |
445 |
430 /** |
446 /** |
431 * Filters the returned, maybe-linked embed URL. |
447 * Filters the returned, maybe-linked embed URL. |
432 * |
448 * |
433 * @since 2.9.0 |
449 * @since 2.9.0 |
452 |
468 |
453 if ( $oembed_post_id && 'oembed_cache' === get_post_type( $oembed_post_id ) ) { |
469 if ( $oembed_post_id && 'oembed_cache' === get_post_type( $oembed_post_id ) ) { |
454 return $oembed_post_id; |
470 return $oembed_post_id; |
455 } |
471 } |
456 |
472 |
457 $oembed_post_query = new WP_Query( array( |
473 $oembed_post_query = new WP_Query( |
458 'post_type' => 'oembed_cache', |
474 array( |
459 'post_status' => 'publish', |
475 'post_type' => 'oembed_cache', |
460 'name' => $cache_key, |
476 'post_status' => 'publish', |
461 'posts_per_page' => 1, |
477 'name' => $cache_key, |
462 'no_found_rows' => true, |
478 'posts_per_page' => 1, |
463 'cache_results' => true, |
479 'no_found_rows' => true, |
464 'update_post_meta_cache' => false, |
480 'cache_results' => true, |
465 'update_post_term_cache' => false, |
481 'update_post_meta_cache' => false, |
466 'lazy_load_term_meta' => false, |
482 'update_post_term_cache' => false, |
467 ) ); |
483 'lazy_load_term_meta' => false, |
|
484 ) |
|
485 ); |
468 |
486 |
469 if ( ! empty( $oembed_post_query->posts ) ) { |
487 if ( ! empty( $oembed_post_query->posts ) ) { |
470 // Note: 'fields'=>'ids' is not being used in order to cache the post object as it will be needed. |
488 // Note: 'fields'=>'ids' is not being used in order to cache the post object as it will be needed. |
471 $oembed_post_id = $oembed_post_query->posts[0]->ID; |
489 $oembed_post_id = $oembed_post_query->posts[0]->ID; |
472 wp_cache_set( $cache_key, $oembed_post_id, $cache_group ); |
490 wp_cache_set( $cache_key, $oembed_post_id, $cache_group ); |