WordPress.org

Make WordPress Core

Ticket #10337: 10337.workinprogress.3.patch

File 10337.workinprogress.3.patch, 14.0 KB (added by Viper007Bond, 5 years ago)

Move oEmbed caching to an AJAX request after the post is saved

  • wp-admin/admin-ajax.php

     
    111111 
    112112        die('0'); 
    113113        break; 
     114case 'oembed-cache' : 
     115        $return = ( $wp_embed->cache_oembed( $_GET['post'] ) ) ? '1' : '0'; 
     116        die($return); 
     117        break; 
    114118default : 
    115119        do_action( 'wp_ajax_' . $_GET['action'] ); 
    116120        die('0'); 
  • wp-includes/class-oembed.php

     
     1<?php 
     2 
     3class WP_oEmbed { 
     4        var $providers = array(); 
     5 
     6        function WP_oEmbed() { 
     7                return $this->__construct(); 
     8        } 
     9 
     10        function __construct() { 
     11                // List out some popular sites, mainly ones that don't have discovery tags in their <head> 
     12                $this->providers = apply_filters( 'oembed_providers', array( 
     13                        'http://*.flickr.com/*'       => 'http://www.flickr.com/services/oembed/', 
     14                        'http://*.viddler.com/*'      => 'http://lab.viddler.com/services/oembed/', 
     15                        'http://qik.com/*'            => 'http://qik.com/api/oembed.{format}', 
     16                        'http://*.revision3.com/*'    => 'http://revision3.com/api/oembed/', 
     17                        'http://www.hulu.com/watch/*' => 'http://www.hulu.com/api/oembed.{format}', 
     18                        //'http://www.vimeo.com/*'      => 'http://www.vimeo.com/api/oembed.{format}', // Discovery tag supported, leave it commented to use as a discovery test 
     19 
     20                        //'http://*.youtube.com/watch*' => 'http://oohembed.com/oohembed/', 
     21                ) ); 
     22        } 
     23 
     24        // Pass a URL, returns false or HTML result 
     25        function getHTML( $url, $args = '' ) { 
     26                $provider = false; 
     27 
     28                foreach ( $this->providers as $scheme => $providerurl ) { // Needs a better variable name 
     29 
     30                        // Turn the asterisk-type provider URLs into regex 
     31                        $regex = '#' . str_replace( '___wildcard___', '(.+)', preg_quote( str_replace( '*', '___wildcard___', $scheme ) ) ) . '#i'; 
     32 
     33                        if ( preg_match( $regex, $url ) ) { 
     34                                $provider = str_replace( '{format}', 'json', $providerurl ); // JSON is easier to deal with than XML 
     35                                break; 
     36                        } 
     37                } 
     38 
     39                if ( !$provider ) 
     40                        $provider = $this->discover( $url ); 
     41 
     42                if ( !$provider || false === $data = $this->fetch( $provider, $url, $args ) ) 
     43                        return false; 
     44 
     45                return $this->data2html( $data, $url ); 
     46        } 
     47 
     48        // Pass a URL, returns the oEmbed provider URL(s) if it can find them in the <head> 
     49        function discover( $url ) { 
     50                $providers = array(); 
     51 
     52                // Fetch URL content 
     53                if ( $html = wp_remote_retrieve_body( wp_remote_get( $url ) ) ) { 
     54 
     55                        // <link> types that contain oEmbed provider URLs 
     56                        $linktypes = apply_filters( 'oembed_linktypes', array( 
     57                                'application/json+oembed' => 'json', 
     58                                'text/xml+oembed' => 'xml', 
     59                                'application/xml+oembed' => 'xml', // Incorrect, but used by at least Vimeo 
     60                        ) ); 
     61 
     62                        // Strip <body> 
     63                        $html = substr( $html, 0, stripos( $html, '</head>' ) ); 
     64 
     65                        // Do a quick check 
     66                        $tagfound = false; 
     67                        foreach ( $linktypes as $linktype => $format ) { 
     68                                if ( stripos($html, $linktype) ) { 
     69                                        $tagfound = true; 
     70                                        break; 
     71                                } 
     72                        } 
     73 
     74                        if ( $tagfound && preg_match_all( '/<link([^<>]+)>/i', $html, $links ) ) { 
     75                                foreach ( $links[1] as $link ) { 
     76                                        $atts = shortcode_parse_atts( $link ); 
     77 
     78                                        if ( !empty($atts['type']) && !empty($linktypes[$atts['type']]) && !empty($atts['href']) ) { 
     79                                                $providers[$linktypes[$atts['type']]] = $atts['href']; 
     80 
     81                                                // Stop here if it's JSON (that's all we need) 
     82                                                if ( 'json' == $linktypes[$atts['type']] ) 
     83                                                        break; 
     84                                        } 
     85                                } 
     86                        } 
     87                } 
     88 
     89                // JSON is preferred to XML 
     90                if ( !empty($providers['json']) ) 
     91                        return $providers['json']; 
     92                elseif ( !empty($providers['xml']) ) 
     93                        return $providers['xml']; 
     94                else 
     95                        return false; 
     96        } 
     97 
     98        // Connects to an oEmbed provider and returns the result 
     99        function fetch( $provider, $url, $args = '' ) { 
     100                $args = wp_parse_args( $args, wp_embed_defaults() ); 
     101 
     102                $provider = add_query_arg( 'format', 'json', $provider ); // JSON is easier to deal with than XML 
     103 
     104                $provider = add_query_arg( 'maxwidth', $args['width'], $provider ); 
     105                $provider = add_query_arg( 'maxheight', $args['height'], $provider ); 
     106                $provider = add_query_arg( 'url', urlencode($url), $provider ); 
     107 
     108                if ( !$result = wp_remote_retrieve_body( wp_remote_get( $provider ) ) ) 
     109                        return false; 
     110 
     111                $data = false; 
     112 
     113                // JSON? 
     114                // Example: http://vimeo.com/api/oembed.json?url=http%3A%2F%2Fvimeo.com%2F240975 
     115                if ( $data = json_decode($result) ) { 
     116                        return $data; 
     117                } 
     118 
     119                // Must be XML. Start out with the super-easy PHP5 functions. 
     120                // Example: http://vimeo.com/api/oembed.xml?url=http%3A%2F%2Fvimeo.com%2F240975 
     121                elseif ( function_exists('simplexml_load_string') ) { 
     122                        libxml_use_internal_errors('true'); 
     123 
     124                        $data = simplexml_load_string($result); 
     125 
     126                        if ( is_object($data) ) 
     127                                return $data; 
     128                } 
     129 
     130                // Still must be XML, but no PHP5 support. Use PHP4 (ugh). 
     131                // Example: http://vimeo.com/api/oembed.xml?url=http%3A%2F%2Fvimeo.com%2F240975 
     132                else { 
     133                        // Code me! 
     134                } 
     135 
     136                return false; 
     137        } 
     138 
     139        // Takes a data set and returns the HTML 
     140        function data2html( $data, $url ) { 
     141                if ( !is_object($data) || empty($data->type) ) 
     142                        return false; 
     143 
     144                switch ( $data->type ) { 
     145                        case 'photo': 
     146                                if ( empty($data->url) || empty($data->width) || empty($data->height) ) 
     147                                        return false; 
     148 
     149                                $title = ( !empty($data->title) ) ? $data->title : ''; 
     150                                return '<img src="' . esc_attr( clean_url( $data->url ) ) . '" alt="' . esc_attr($title) . '" width="' . esc_attr($data->width) . '" height="' . esc_attr($data->height) . '" />'; 
     151 
     152                        case 'video': 
     153                        case 'rich': 
     154                                return ( !empty($data->html) ) ? $data->html : false; 
     155 
     156                        case 'link': 
     157                                return ( !empty($data->title) ) ? '<a href="' . clean_url($url) . '">' . esc_html($data->title) . '</a>' : false; 
     158                } 
     159 
     160                return false; 
     161        } 
     162} 
     163 
     164function &_wp_oembed_get_object() { 
     165        static $oembed; 
     166 
     167        if ( is_null($oembed) ) 
     168                $oembed = new WP_oEmbed(); 
     169 
     170        return $oembed; 
     171} 
  • wp-includes/media.php

     
    933933 
    934934        return false; 
    935935} 
     936 
     937 
     938 
     939 
     940 
     941 
     942 
     943 
     944 
     945// Embed class 
     946class WP_Embed { 
     947        var $handlers = array(); 
     948        var $post_ID; 
     949        var $usecache = true; 
     950        var $linkifunknown = true; 
     951 
     952        // PHP4 constructor 
     953        function WP_Embed() { 
     954                return $this->__construct(); 
     955        } 
     956 
     957        // PHP5 constructor 
     958        function __construct() { 
     959                // After a post is saved, cache oEmbed items via AJAX 
     960                add_action( 'edit_form_advanced', array(&$this, 'maybe_run_ajax_cache') ); 
     961 
     962                // Hack to get the [embed] shortcode to run before wpautop() 
     963                add_filter( 'the_content', array(&$this, 'runshortcode'), 9 ); 
     964 
     965                // Per Matt's idea, this attempts to embed all URLs in a post 
     966                add_filter( 'the_content', array(&$this, 'autoembed'), 9 ); 
     967        } 
     968 
     969 
     970        // Run do_shortcode() with only the [embed] shortcode active 
     971        // This is so it can be run earlier than normal 
     972        function runshortcode( $content ) { 
     973                global $shortcode_tags; 
     974 
     975                // Backup current registered shortcodes and clear them all out 
     976                $orig_shortcode_tags = $shortcode_tags; 
     977                remove_all_shortcodes(); 
     978 
     979                add_shortcode( 'embed', array(&$this, 'shortcode') ); 
     980 
     981                // Do the shortcode (only the [embed] one is registered) 
     982                $content = do_shortcode( $content ); 
     983 
     984                // Put the original shortcodes back 
     985                $shortcode_tags = $orig_shortcode_tags; 
     986 
     987                return $content; 
     988        } 
     989 
     990        // If a post was saved, then cache oEmbed results via AJAX 
     991        function maybe_run_ajax_cache() { 
     992                global $post_ID; 
     993 
     994                if ( empty($_GET['message']) || 1 != $_GET['message'] ) 
     995                        return; 
     996 
     997?> 
     998<script type="text/javascript"> 
     999/* <![CDATA[ */ 
     1000        jQuery(document).ready(function($){ 
     1001                $.get("<?php echo admin_url( 'admin-ajax.php?action=oembed-cache&post=' . $post_ID ); ?>"); 
     1002        }); 
     1003/* ]]> */ 
     1004</script> 
     1005<?php 
     1006        } 
     1007 
     1008 
     1009        // Register a handler for WP_Embed::shortcode() 
     1010        // wp_embed_register_handler() is a wrapper for this 
     1011        function register_handler( $id, $regex, $callback, $priority = 10 ) { 
     1012                $this->handlers[$priority][$id] = array( 
     1013                        'regex'    => $regex, 
     1014                        'callback' => $callback, 
     1015                ); 
     1016        } 
     1017 
     1018        // [embed] handler 
     1019        function shortcode( $atts, $url = '' ) { 
     1020                global $post; 
     1021 
     1022                $atts = wp_parse_args( $atts, wp_embed_defaults() ); 
     1023 
     1024                // Allow plugins to add their own handler 
     1025                if ( false !== $filter = apply_filters( 'embed_other_before', false, $atts, $url ) ) 
     1026                        return $filter; 
     1027 
     1028                // Look for known internal handlers 
     1029                ksort( $this->handlers ); 
     1030                foreach ( $this->handlers as $handlers ) { 
     1031                        foreach ( $handlers as $id => $handler ) { 
     1032                                if ( preg_match( $handler['regex'], $url, $matches ) && is_callable( $handler['callback'] ) ) { 
     1033                                        return call_user_func( $handler['callback'], $matches, $atts, $url ); 
     1034                                } 
     1035                        } 
     1036                } 
     1037 
     1038                // Unknown URL format. Let oEmbed have a go. 
     1039                if ( current_user_can('unfiltered_html') ) { 
     1040                        $cachekey = '_oembed_' . md5( $url . implode( '|', $atts ) ); 
     1041 
     1042                        $post_ID = ( !empty($post->ID) ) ? $post->ID : null; 
     1043                        if ( !empty($this->post_ID) ) // Potentially set by WP_Embed::cache_oembed() 
     1044                                $post_ID = $this->post_ID; 
     1045 
     1046                        // Check for a cached result (stored in the post meta) 
     1047                        if ( $post_ID && $this->usecache ) { 
     1048                                $cache = get_post_meta( $post_ID, $cachekey, true ); 
     1049 
     1050                                // Failures are cached 
     1051                                if ( '{{unknown}}' === $cache ) 
     1052                                        return $this->make_link( $url ); 
     1053 
     1054                                if ( !empty($cache) ) 
     1055                                        return $cache; 
     1056                        } 
     1057 
     1058                        $html = wp_oembed_get( $url, $atts ); 
     1059 
     1060                        // Cache the result 
     1061                        if ( $post_ID ) { 
     1062                                $cache = ( $html ) ? $html : '{{unknown}}'; 
     1063                                update_post_meta( $post_ID, $cachekey, $cache ); 
     1064                        } 
     1065 
     1066                        if ( $html ) 
     1067                                return $html; 
     1068                } 
     1069 
     1070                // Allow plugins to add their own handler 
     1071                if ( false !== $filter = apply_filters( 'embed_other_after', false, $atts, $url ) ) 
     1072                        return $filter; 
     1073 
     1074                // Still unknown 
     1075                return $this->make_link( $url ); 
     1076        } 
     1077 
     1078        // On save_post, run the shortcode on the post in order to trigger WP_Embed::shortcode() to cache oEmbed results 
     1079        function cache_oembed( $post_ID ) { 
     1080                $post = get_post( $post_ID ); 
     1081 
     1082                if ( empty($post->ID) ) 
     1083                        return false; 
     1084 
     1085                if ( !in_array( $post->post_type, array( 'post', 'page' ) ) ) 
     1086                        return; 
     1087 
     1088                // Dump existing caches 
     1089                $post_metas = get_post_custom_keys( $post->ID ); 
     1090                foreach( $post_metas as $post_meta_key ) { 
     1091                        if ( '_oembed_' == substr( $post_meta_key, 0, 8 ) ) 
     1092                                delete_post_meta($post->ID, $post_meta_key ); 
     1093                } 
     1094 
     1095                // Trigger a caching 
     1096                if ( !empty($post->post_content) ) { 
     1097                        $this->post_ID = $post->ID; 
     1098                        $this->usecache = false; 
     1099                        $this->autoembed( $this->runshortcode( $post->post_content ) ); 
     1100                        $this->usecache = true; 
     1101                } 
     1102 
     1103                return true; 
     1104        } 
     1105 
     1106        // Helper function that makes a HTML link to the passed URL 
     1107        function make_link( $url ) { 
     1108                return ( $this->linkifunknown ) ? apply_filters( 'embed_urllink', '<a href="' . esc_attr($url) . '">' . esc_html($url) . '</a>' ) : $url; 
     1109        } 
     1110 
     1111        // With help from WP_Emebed::_autoembed(), this attempts to convert all URLs in a post into embeds 
     1112        // This incorrectly turns links where the clickable text is a URL into an embed 
     1113        // For example, it incorectly processes this: <a href="http://example.com/">http://example.com/</a> 
     1114        function autoembed( $content ) { 
     1115                // Stolen from make_clickable() 
     1116                $content = ' ' . $content; 
     1117                $content = preg_replace_callback('#(?<=[\s>])(\()?([\w]+?://(?:[\w\\x80-\\xff\#$%&~/\-=?@\[\](+]|[.,;:](?![\s<])|(?(1)\)(?![\s<])|\)))+)#is',  array(&$this, '_autoembed'), $content); 
     1118                return trim( $content ); 
     1119        } 
     1120 
     1121        // A helper function for WP_Embed::autoembed() that converts a URL into an embed 
     1122        function _autoembed( $match ) { 
     1123                $this->linkifunknown = false; 
     1124                $return = $this->shortcode( array(), $match[2] ); 
     1125                $this->linkifunknown = true; 
     1126                return $return; 
     1127        } 
     1128} 
     1129 
     1130$wp_embed = new WP_Embed(); 
     1131 
     1132// Wrapper to register a new hander for a URL format inside [embed] 
     1133function wp_embed_register_handler( $id, $regex, $callback ) { 
     1134        global $wp_embed; 
     1135        return $wp_embed->register_handler( $id, $regex, $callback ); 
     1136} 
     1137 
     1138// A helper function to return some default attributes for embeds 
     1139function wp_embed_defaults() { 
     1140        return apply_filters( 'embed_defaults', array( 
     1141                'width' => 500, 
     1142                'height' => 700, 
     1143        ) ); 
     1144} 
     1145 
     1146// Based on a supplied width/height ratio, return the biggest possible dimensions based on the max width/height 
     1147function wp_embed_calcdims( $example_width, $example_height, $max_width, $max_height ) { 
     1148        return wp_constrain_dimensions( $example_width * 1000000, $example_height * 1000000, $max_width, $max_height ); 
     1149} 
     1150 
     1151// Wrapper to load the WP_oEmbed class and use it to get some HTML 
     1152function wp_oembed_get( $url, $args = '' ) { 
     1153        require_once( 'class-oembed.php' ); 
     1154        $oembed_object = _wp_oembed_get_object(); 
     1155        return $oembed_object->getHTML( $url, $args ); 
     1156} 
     1157 
     1158 
     1159 
     1160// YouTube doesn't support oEmbed, so handle it internally 
     1161wp_embed_register_handler( 'youtube', '#http://(www.youtube|youtube|[A-Za-z]{2}.youtube)\.com/(watch\?v=|w/\?v=|\?v=)([\w-]+)(.*?)#i', 'wp_embed_handler_youtube' ); 
     1162function wp_embed_handler_youtube( $matches, $atts, $url ) { 
     1163        list($width, $height) = wp_embed_calcdims( 425, 344, $atts['width'], $atts['height'] ); 
     1164        return "<object width='$width' height='$height'><param name='movie' value='http://www.youtube.com/v/{$matches[3]}&amp;hl=en&amp;fs=1'></param><param name='allowFullScreen' value='true'></param><param name='allowscriptaccess' value='always'></param><embed src='http://www.youtube.com/v/{$matches[3]}&amp;hl=en&amp;fs=1' type='application/x-shockwave-flash' allowscriptaccess='always' allowfullscreen='true' width='$width' height='$height'></embed></object>"; 
     1165} 
     1166 
     1167 
     1168// PollDaddy 
     1169wp_embed_register_handler( 'polldaddy', '#http://answers.polldaddy.com/poll/(\d+)(.*?)#i', 'wp_embed_handler_polldaddy' ); 
     1170function wp_embed_handler_polldaddy( $matches, $atts, $url ) { 
     1171        return '<script type="text/javascript" src="http://s3.polldaddy.com/p/' . esc_attr($matches[1]) . '"></script>'; 
     1172} 
     1173 No newline at end of file