| | 936 | |
| | 937 | |
| | 938 | |
| | 939 | |
| | 940 | |
| | 941 | |
| | 942 | /* |
| | 943 | |
| | 944 | TODO: |
| | 945 | |
| | 946 | * oEmbed PHP4 XML |
| | 947 | * Videos in feeds? It's currently just a link (handlers manually; WP_Embed class aborts before oEmbed) |
| | 948 | * Phpdoc |
| | 949 | * Auto-embed: Fix aggressive auto-embedding for all URLS. For example, it catches the click text of this: <a href="#">http://google.com/</a> It should ignore inside <a>'s |
| | 950 | * Auto-embed: Ignore inside shortcodes, i.e. don't catch this: [tag]http://google.com/[/tag] |
| | 951 | * Add more default handlers (WP.com ones perhaps?) |
| | 952 | * Should the stuff be wrapped in a div/span for styling purposes? Maybe a filter can do this? |
| | 953 | * Add a bunch more filters (oEmbed output, handler outputs, etc.) |
| | 954 | |
| | 955 | */ |
| | 956 | |
| | 957 | |
| | 958 | // Embed class |
| | 959 | class WP_Embed { |
| | 960 | var $handlers = array(); |
| | 961 | var $post_ID; |
| | 962 | var $usecache = true; |
| | 963 | var $linkifunknown = true; |
| | 964 | |
| | 965 | // PHP4 constructor |
| | 966 | function WP_Embed() { |
| | 967 | return $this->__construct(); |
| | 968 | } |
| | 969 | |
| | 970 | // PHP5 constructor |
| | 971 | function __construct() { |
| | 972 | // After a post is saved, cache oEmbed items via AJAX |
| | 973 | add_action( 'edit_form_advanced', array(&$this, 'maybe_run_ajax_cache') ); |
| | 974 | |
| | 975 | // Hack to get the [embed] shortcode to run before wpautop() |
| | 976 | add_filter( 'the_content', array(&$this, 'runshortcode'), 9 ); |
| | 977 | |
| | 978 | // Per Matt's idea, this attempts to embed all URLs in a post |
| | 979 | // It's a bit buggy, see comments on WP_Embed::autoembed() |
| | 980 | if ( get_option('embed_autourls') ) |
| | 981 | add_filter( 'the_content', array(&$this, 'autoembed'), 9 ); |
| | 982 | } |
| | 983 | |
| | 984 | // Run do_shortcode() with only the [embed] shortcode active |
| | 985 | // This is so it can be run earlier than normal |
| | 986 | function runshortcode( $content ) { |
| | 987 | global $shortcode_tags; |
| | 988 | |
| | 989 | // Backup current registered shortcodes and clear them all out |
| | 990 | $orig_shortcode_tags = $shortcode_tags; |
| | 991 | remove_all_shortcodes(); |
| | 992 | |
| | 993 | add_shortcode( 'embed', array(&$this, 'shortcode') ); |
| | 994 | |
| | 995 | // Do the shortcode (only the [embed] one is registered) |
| | 996 | $content = do_shortcode( $content ); |
| | 997 | |
| | 998 | // Put the original shortcodes back |
| | 999 | $shortcode_tags = $orig_shortcode_tags; |
| | 1000 | |
| | 1001 | return $content; |
| | 1002 | } |
| | 1003 | |
| | 1004 | // If a post was saved, then cache oEmbed results via AJAX |
| | 1005 | function maybe_run_ajax_cache() { |
| | 1006 | global $post_ID; |
| | 1007 | |
| | 1008 | if ( empty($post_ID) || empty($_GET['message']) || 1 != $_GET['message'] ) |
| | 1009 | return; |
| | 1010 | |
| | 1011 | ?> |
| | 1012 | <script type="text/javascript"> |
| | 1013 | /* <![CDATA[ */ |
| | 1014 | jQuery(document).ready(function($){ |
| | 1015 | $.get("<?php echo admin_url( 'admin-ajax.php?action=oembed-cache&post=' . $post_ID ); ?>"); |
| | 1016 | }); |
| | 1017 | /* ]]> */ |
| | 1018 | </script> |
| | 1019 | <?php |
| | 1020 | } |
| | 1021 | |
| | 1022 | // Register a handler for WP_Embed::shortcode() |
| | 1023 | // wp_embed_register_handler() is a wrapper for this, so call that instead |
| | 1024 | function register_handler( $id, $regex, $callback, $priority = 10 ) { |
| | 1025 | $this->handlers[$priority][$id] = array( |
| | 1026 | 'regex' => $regex, |
| | 1027 | 'callback' => $callback, |
| | 1028 | ); |
| | 1029 | } |
| | 1030 | |
| | 1031 | // wp_embed_unregister_handler() is a wrapper for this, so call that instead |
| | 1032 | function unregister_handler( $id, $priority = 10 ) { |
| | 1033 | if ( isset($this->handlers[$priority][$id]) ) |
| | 1034 | unset($this->handlers[$priority][$id]); |
| | 1035 | } |
| | 1036 | |
| | 1037 | // [embed] handler |
| | 1038 | function shortcode( $attr, $url = '' ) { |
| | 1039 | global $post, $_wp_using_ext_object_cache; |
| | 1040 | |
| | 1041 | $rawattr = $attr; |
| | 1042 | $attr = wp_parse_args( $attr, wp_embed_defaults() ); |
| | 1043 | |
| | 1044 | // Look for known internal handlers |
| | 1045 | ksort( $this->handlers ); |
| | 1046 | foreach ( $this->handlers as $priority => $handlers ) { |
| | 1047 | foreach ( $handlers as $id => $handler ) { |
| | 1048 | if ( preg_match( $handler['regex'], $url, $matches ) && is_callable( $handler['callback'] ) ) { |
| | 1049 | return call_user_func( $handler['callback'], $matches, $attr, $url, $rawattr ); |
| | 1050 | } |
| | 1051 | } |
| | 1052 | } |
| | 1053 | |
| | 1054 | if ( empty($url) ) |
| | 1055 | return ''; |
| | 1056 | |
| | 1057 | if ( is_feed() ) |
| | 1058 | return $this->make_link( $url ); |
| | 1059 | |
| | 1060 | // Unknown URL format. Let oEmbed have a go. |
| | 1061 | if ( current_user_can('unfiltered_html') ) { |
| | 1062 | $post_ID = ( !empty($post->ID) ) ? $post->ID : null; |
| | 1063 | if ( !empty($this->post_ID) ) // Potentially set by WP_Embed::cache_oembed() |
| | 1064 | $post_ID = $this->post_ID; |
| | 1065 | |
| | 1066 | // Check for a cached result (stored in the post meta) |
| | 1067 | if ( $post_ID ) { |
| | 1068 | $cachekey = '_oembed_' . md5( $url . implode( '|', $attr ) ); |
| | 1069 | |
| | 1070 | if ( $this->usecache ) { |
| | 1071 | |
| | 1072 | $cache = ( $_wp_using_ext_object_cache ) ? wp_cache_get( "{$post_ID}_{$cachekey}", 'oembed' ) : get_post_meta( $post_ID, $cachekey, true ); |
| | 1073 | |
| | 1074 | // Failures are cached |
| | 1075 | if ( '{{unknown}}' === $cache ) |
| | 1076 | return $this->make_link( $url ); |
| | 1077 | |
| | 1078 | if ( !empty($cache) ) |
| | 1079 | return $cache; |
| | 1080 | } |
| | 1081 | } |
| | 1082 | |
| | 1083 | $html = wp_oembed_get( $url, $attr ); |
| | 1084 | |
| | 1085 | // Cache the result |
| | 1086 | if ( $post_ID ) { |
| | 1087 | $cache = ( $html ) ? $html : '{{unknown}}'; |
| | 1088 | |
| | 1089 | if ( $_wp_using_ext_object_cache ) |
| | 1090 | wp_cache_set( "{$post_ID}_{$cachekey}", $cache, 'oembed' ); |
| | 1091 | else |
| | 1092 | update_post_meta( $post_ID, $cachekey, $cache ); |
| | 1093 | } |
| | 1094 | |
| | 1095 | if ( $html ) |
| | 1096 | return $html; |
| | 1097 | } |
| | 1098 | |
| | 1099 | // Still unknown |
| | 1100 | return $this->make_link( $url ); |
| | 1101 | } |
| | 1102 | |
| | 1103 | // Cache all oEmbed results for the given post ID to it's post meta |
| | 1104 | function cache_oembed( $post_ID ) { |
| | 1105 | $post = get_post( $post_ID ); |
| | 1106 | |
| | 1107 | // post_type check is incase of "save_post" usage |
| | 1108 | if ( empty($post->ID) || !in_array( $post->post_type, array( 'post', 'page' ) ) ) |
| | 1109 | return; |
| | 1110 | |
| | 1111 | // Dump existing caches |
| | 1112 | $post_metas = get_post_custom_keys( $post->ID ); |
| | 1113 | foreach( $post_metas as $post_meta_key ) { |
| | 1114 | if ( '_oembed_' == substr( $post_meta_key, 0, 8 ) ) |
| | 1115 | delete_post_meta( $post->ID, $post_meta_key ); |
| | 1116 | } |
| | 1117 | |
| | 1118 | // Trigger a caching |
| | 1119 | if ( !empty($post->post_content) ) { |
| | 1120 | $this->post_ID = $post->ID; |
| | 1121 | $this->usecache = false; |
| | 1122 | |
| | 1123 | $content = $this->runshortcode( $post->post_content ); |
| | 1124 | if ( get_option('embed_autourls') ) |
| | 1125 | $this->autoembed( $content ); |
| | 1126 | |
| | 1127 | $this->usecache = true; |
| | 1128 | } |
| | 1129 | } |
| | 1130 | |
| | 1131 | // Helper function that makes a HTML link to the passed URL |
| | 1132 | function make_link( $url ) { |
| | 1133 | return ( $this->linkifunknown ) ? make_link($url) : $url; |
| | 1134 | } |
| | 1135 | |
| | 1136 | // With help from WP_Emebed::_autoembed(), this attempts to convert all URLs in a post into embeds |
| | 1137 | // This incorrectly turns links where the clickable text is a URL into an embed |
| | 1138 | // For example, it incorectly processes this: <a href="#">http://example.com/</a> |
| | 1139 | function autoembed( $content ) { |
| | 1140 | // Stolen from make_clickable() |
| | 1141 | $content = ' ' . $content; |
| | 1142 | $content = preg_replace_callback( '#(?<=[\s>])(\()?([\w]+?://(?:[\w\\x80-\\xff\#$%&~/\-=?@\[\](+]|[.,;:](?![\s<])|(?(1)\)(?![\s<])|\)))+)#is', array(&$this, '_autoembed'), $content ); |
| | 1143 | return trim( $content ); |
| | 1144 | } |
| | 1145 | |
| | 1146 | // A helper function for WP_Embed::autoembed() that converts a URL into an embed |
| | 1147 | function _autoembed( $match ) { |
| | 1148 | $this->linkifunknown = false; |
| | 1149 | $return = $this->shortcode( array(), $match[2] ); |
| | 1150 | $this->linkifunknown = true; |
| | 1151 | return $return; |
| | 1152 | } |
| | 1153 | } |
| | 1154 | $wp_embed = new WP_Embed(); |
| | 1155 | |
| | 1156 | |
| | 1157 | // Wrapper to register a new hander for a URL format inside [embed] |
| | 1158 | function wp_embed_register_handler( $id, $regex, $callback, $priority = 10 ) { |
| | 1159 | global $wp_embed; |
| | 1160 | return $wp_embed->register_handler( $id, $regex, $callback, $priority ); |
| | 1161 | } |
| | 1162 | |
| | 1163 | // Wrapper to unregister a new hander for a URL format inside [embed] |
| | 1164 | function wp_embed_unregister_handler( $id, $priority = 10 ) { |
| | 1165 | global $wp_embed; |
| | 1166 | return $wp_embed->unregister_handler( $id, $priority ); |
| | 1167 | } |
| | 1168 | |
| | 1169 | // A helper function to return some default attributes for embeds |
| | 1170 | function wp_embed_defaults() { |
| | 1171 | if ( !empty($GLOBALS['content_width']) ) |
| | 1172 | $theme_width = (int) $GLOBALS['content_width']; |
| | 1173 | |
| | 1174 | if ( !($width = get_option('embed_size_w')) && !empty($theme_width) ) |
| | 1175 | $width = $theme_width; |
| | 1176 | |
| | 1177 | if ( !$width ) |
| | 1178 | $width = 500; |
| | 1179 | |
| | 1180 | return apply_filters( 'embed_defaults', array( |
| | 1181 | 'width' => $width, |
| | 1182 | 'height' => 700, |
| | 1183 | ) ); |
| | 1184 | } |
| | 1185 | |
| | 1186 | // Based on a supplied width/height ratio, return the biggest possible dimensions based on the max width/height |
| | 1187 | function wp_embed_calcdims( $example_width, $example_height, $max_width, $max_height ) { |
| | 1188 | return wp_constrain_dimensions( $example_width * 1000000, $example_height * 1000000, $max_width, $max_height ); |
| | 1189 | } |
| | 1190 | |
| | 1191 | // Wrapper to load the WP_oEmbed class and use it to get some HTML |
| | 1192 | function wp_oembed_get( $url, $args = '' ) { |
| | 1193 | require_once( 'class-oembed.php' ); |
| | 1194 | $oembed_object = _wp_oembed_get_object(); |
| | 1195 | return $oembed_object->getHTML( $url, $args ); |
| | 1196 | } |
| | 1197 | |
| | 1198 | |
| | 1199 | // YouTube doesn't support oEmbed, so handle it internally |
| | 1200 | wp_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' ); |
| | 1201 | function wp_embed_handler_youtube( $matches, $attr, $url, $rawattr ) { |
| | 1202 | if ( is_feed() ) |
| | 1203 | return "<a href='" . get_permalink() . "'><img src='http://img.youtube.com/vi/{$matches[3]}/0.jpg' alt='" . __('YouTube') . "' /></a>"; |
| | 1204 | |
| | 1205 | // If the user supplied a fixed width AND height, use it |
| | 1206 | if ( !empty($rawattr['width']) && !empty($rawattr['height']) ) { |
| | 1207 | $width = (int) $rawattr['width']; |
| | 1208 | $height = (int) $rawattr['height']; |
| | 1209 | } else { |
| | 1210 | list( $width, $height ) = wp_embed_calcdims( 425, 344, $attr['width'], $attr['height'] ); |
| | 1211 | } |
| | 1212 | |
| | 1213 | return apply_filters( 'embed_youtube', "<object width='$width' height='$height'><param name='movie' value='http://www.youtube.com/v/{$matches[3]}&hl=en&fs=1'></param><param name='allowFullScreen' value='true'></param><param name='allowscriptaccess' value='always'></param><embed src='http://www.youtube.com/v/{$matches[3]}&hl=en&fs=1' type='application/x-shockwave-flash' allowscriptaccess='always' allowfullscreen='true' width='$width' height='$height'></embed></object>", $matches, $attr, $url, $rawattr ); |
| | 1214 | } |
| | 1215 | |
| | 1216 | |
| | 1217 | // PollDaddy |
| | 1218 | wp_embed_register_handler( 'polldaddy', '#http://answers.polldaddy.com/poll/(\d+)(.*?)#i', 'wp_embed_handler_polldaddy' ); |
| | 1219 | function wp_embed_handler_polldaddy( $matches, $attr, $url, $rawattr ) { |
| | 1220 | if ( is_feed() ) |
| | 1221 | return make_link($url); |
| | 1222 | |
| | 1223 | return apply_filters( 'embed_polldaddy', '<script type="text/javascript" src="http://s3.polldaddy.com/p/' . esc_attr($matches[1]) . '"></script>', $matches, $attr, $url, $rawattr ); |
| | 1224 | } |
| | 1225 | |
| | 1226 | |
| | 1227 | // DailyMotion |
| | 1228 | // Example: http://www.dailymotion.com/video/x4cqyl_ferrari-p45-owner-exclusive-intervi_auto |
| | 1229 | wp_embed_register_handler( 'dailymotion', '#http://(www.dailymotion|dailymotion)\.com/(.+)/([0-9a-zA-Z]+)\_(.*?)#i', 'wp_embed_handler_dailymotion' ); |
| | 1230 | function wp_embed_handler_dailymotion( $matches, $attr, $url, $rawattr ) { |
| | 1231 | if ( is_feed() ) |
| | 1232 | return make_link($url); |
| | 1233 | |
| | 1234 | // If the user supplied a fixed width AND height, use it |
| | 1235 | if ( !empty($rawattr['width']) && !empty($rawattr['height']) ) { |
| | 1236 | $width = (int) $rawattr['width']; |
| | 1237 | $height = (int) $rawattr['height']; |
| | 1238 | } else { |
| | 1239 | list( $width, $height ) = wp_embed_calcdims( 480, 291, $attr['width'], $attr['height'] ); |
| | 1240 | } |
| | 1241 | |
| | 1242 | return apply_filters( 'embed_dailymotion', "<object width='$width' height='$height' classid='clsid:d27cdb6e-ae6d-11cf-96b8-444553540000'><param name='movie' value='http://www.dailymotion.com/swf/{$matches[3]}&related=0'></param><param name='allowFullScreen' value='true'></param><param name='allowScriptAccess' value='always'></param><embed src='http://www.dailymotion.com/swf/{$matches[3]}&related=0' type='application/x-shockwave-flash' width='$width' height='$height' allowFullScreen='true' allowScriptAccess='always'></embed></object>", $matches, $attr, $url, $rawattr );; |
| | 1243 | } |