WordPress.org

Make WordPress Core

Ticket #10337: oembed.php

File oembed.php, 7.7 KB (added by Viper007Bond, 5 years ago)

Shortcode-based oEmbed proof-of-concept plugin by mdawaffe

Line 
1<?php
2
3/*
4Plugin Name: WP Oembed
5Description: Embed oembed compatible resources in your blog.
6Plugin URL: http://wordpress.org/extend/plugins/wp-oembed/
7Author: Automattic, Inc.
8Author URL: http://automattic.com/
9Tags: shortcodes
10Version: 0.1
11*/
12
13/*
14Requires PHP 5
15*/
16
17class WP_OEmbed_Consumer {
18        var $url;
19        var $args   = array();
20        var $config = array();
21
22        var $types = array( 'photo', 'video', 'link', 'rich' );
23
24        var $request, $response, $output;
25
26        function __construct( $url, $args = array(), $config = null ) {
27                $this->url = $url;
28                $default_config = array(
29                        'format' => false,
30                        'endpoint' => false
31                );
32                $this->config = wp_parse_args( $config, $default_config );
33                if ( is_array( $args ) )
34                        $this->args = $args;
35        }
36
37        function get() {
38                // Could class out the request
39                if ( !$this->request = $this->generate_request( $this->url, $this->args, $this->config ) )
40                        return false;
41                // Could class out the response handlers
42                if ( !$this->response = $this->parse_response( $this->request ) )
43                        return false;
44                return true;
45        }
46
47        function get_endpoint( $url, $format = false ) {
48                $endpoints = wp_oembed_producers();
49                $r = false;
50                foreach ( array_keys( $endpoints ) as $match ) {
51                        $p_match = preg_quote( $match, '#' );
52                        $p_match = str_replace( '\://\*\.', '\://(.*?\.)?', $p_match );
53                        $p_match = str_replace( '\*', '(.*?)', $p_match );
54                        if ( preg_match( "#$p_match#i", $url ) ) {
55                                if ( is_scalar( $endpoints[$match] ) && $endpoints[$match] != $match && isset( $endpoints[$endpoints[$match]] ) )
56                                        $r = $endpoints[$endpoints[$match]];
57                                elseif ( isset( $endpoints[$match]['endpoint'] ) )
58                                        $r = $endpoints[$match];
59                                break;
60                        }
61                }
62
63                if ( $r )
64                        $r['endpoint'] = str_replace( '{format}', $format ? $format : $r['format'], $r['endpoint'] );
65               
66                return $r;
67        }
68
69        function generate_request( $url, $args = array(), $config = null ) {
70                $format = isset($config['format']) ? $config['format'] : false;
71                if ( isset($config['endpoint']) && $config['endpoint'] ) {
72                        $endpoint = $config['endpoint'];
73                } elseif ( $endpoint = $this->get_endpoint( $url, $format ) ) {
74                        if ( !$format )
75                                $format = $endpoint['format'];
76                        $endpoint = $endpoint['endpoint'];
77                } else {
78                        return false;
79                }
80
81                return add_query_arg( array_merge( array( 'url' => $url, 'format' => $format ), $args ), $endpoint );
82        }
83
84        function parse_response( $request ) {
85                if ( !$content = trim( wp_remote_fopen( $request ) ) )
86                        return false;
87
88                if ( '<' === $content[0] ) { // XML
89                        if ( !function_exists( 'simplexml_load_string' ) )
90                                return false;
91                        if ( !$xml = simplexml_load_string( $content ) )
92                                return false;
93                        $r = array();
94                        foreach ( $xml->children() as $key => $val ) {
95                                if ( $html = (string) $val ) { // Values should be escaped PCDATA
96                                        $r[$key] = $html;
97                                } else { // sometimes they're not
98                                        $r[$key] = '';
99                                        foreach ( $val->children() as $child )
100                                                $r[$key] .= $child->asXML();
101                                }
102                        }
103                        $r = (object) $r; // watch out, (bool) (object) array() == true
104                } else { // JSON
105                        if ( !function_exists( 'json_decode' ) )
106                                return false;
107                        $r = json_decode( $content );
108                }
109
110                if ( !$r )
111                        return false;
112
113                if ( !isset($r->version) || '1.0' != $r->version )
114                        return false;
115
116                if ( !isset($r->type) || !in_array($r->type, $this->types) )
117                        return false;
118
119                return $r;
120        }
121
122        function html() {
123                if ( !$this->response )
124                        return '';
125
126                if ( !is_callable( array( $this, 'html_' . $this->response->type ) ) )
127                        return false;
128
129                call_user_func( array( $this, 'html_' . $this->response->type ) );
130
131                return $this->output;
132        }
133
134        function html_photo() {
135                foreach ( array( 'url', 'height', 'width' ) as $req )
136                        if ( empty($this->response->$req) )
137                                return false;
138
139                $src = clean_url( $this->response->url );
140                $height = (int) $this->response->height;
141                $width  = (int) $this->response->width;
142
143                if ( empty( $this->response->title ) ) {
144                        $alt = '';
145                } else {
146                        $alt = attribute_escape( $this->response->title );
147                }
148
149                do_action_ref_array( 'wp_oembed_html_photo', array( &$this ) );
150
151                if ( is_null($this->output) )
152                        $this->output = "<img src='$src' height='$height' width='$width' alt='$alt' />";
153        }
154
155        // Not sanitized!
156        function html_video() {
157                foreach ( array( 'html', 'height', 'width' ) as $req )
158                        if ( empty($this->response->$req) )
159                                return false;
160
161                do_action_ref_array( 'wp_oembed_html_video', array( &$this ) );
162
163                if ( is_null($this->output) )
164                        $this->output = $this->response->html;
165        }
166
167        function html_link() {
168                do_action_ref_array( 'wp_oembed_html_link', array( &$this ) );
169
170                if ( !is_null($this->output) )
171                        return;
172
173                $title = $this->url;
174                $quote = '';
175
176                if ( isset($this->response->title) && $this->response->title )
177                        $title = $this->response->title;
178
179                $url = clean_url( $this->url );
180                $title = wp_specialchars( $title );
181
182                $this->output = "<a href='$url'>$title</a>";
183
184                if ( isset($this->response->html) && $this->response->html ) {
185                        $quote = strip_tags( $this->response->html );
186                        if ( 120 < strlen( $quote ) )
187                                $quote = substr( $quote, 0, 120 ) . '&hellip;';
188
189                        if ( $quote = wp_specialchars( $quote ) )
190                                $this->output .= "\n<blockquote cite='$url'><p>$quote</p></blockquote>";
191                }
192        }
193
194        function html_rich() {
195                // do nothing
196        }
197
198}
199
200/*
201[oembed http://example.com/object]
202[oembed http://example.com/object http://example.com/oembed-endpoint/]
203[oembed
204        0/url=object_URL
205        1/endpoint=endpount_URL
206        ... attributes to send to endpoint
207*/
208
209// Should probably be combined with some sort of post_content_filtered plugin
210function wp_oembed_shortcode($atts) {
211        global $shortcode_tags;
212        $url = isset($atts['url']) ? $atts['url'] : $atts[0];
213
214        if ( isset($atts['endpoint']) ) {
215                $endpoint = $atts['endpoint'];
216        } elseif ( isset($atts[1]) ) {
217                $endpoint = $atts[1];
218        } elseif ( !$endpoint = WP_OEmbed_Consumer::get_endpoint( $url ) )
219                return "<!-- invalid oembed url -->";
220
221        $config = null;
222
223        // if there's a compatible shortcode, use it instead
224        if ( isset($endpoint['shortcode']) && isset($shortcode_tags[$endpoint['shortcode']]) ) {
225                $r = wp_shortcode_create( $endpoint['shortcode'], $atts );
226                return do_shortcode("$r");
227        } elseif ( is_string($endpoint) ) { // if an endpoint was provided, use it
228                $config = array( 'endpoint' => $endpoint );
229                foreach ( array_keys($atts) as $k )
230                        if ( is_numeric($k) )
231                                unset($atts[$k]);
232        }
233
234        $oembed = new WP_OEmbed_Consumer( $url, $atts, $config );
235        $oembed->get();
236        return $oembed->html();
237}
238
239function wp_oembed_producers() {
240        return apply_filters( 'wp_oembed_producers', array( 
241                'http://*.flickr.com/*' => array(
242                        'id' => 'flickr',
243                        'endpoint' => 'http://www.flickr.com/services/oembed/',
244                        'format' => 'json'
245                ),
246
247                'http://*.viddler.com/*' => array(
248                        'id' => 'viddler',
249                        'endpoint' => 'http://lab.viddler.com/services/oembed/',
250                        'format' => 'json',
251                        'args' => array(
252                                'type' => array( 'simple', 'player' )
253                        )
254                ),
255
256                'http://qik.com/*' => array(
257                        'id' => 'qik',
258                        'endpoint' => 'http://qik.com/api/oembed.{format}',
259                        'format' => 'json'
260                ),
261
262                'http://*.pownce.com/*' => array(
263                        'id' => 'pownce',
264                        'endpoint' => 'http://api.pownce.com/2.1/oembed.{format}',
265                        'format' => 'json'
266                ),
267
268                'http://*.revision3.com/*' => array(
269                        'id' => 'revision3',
270                        'endpoint' => 'http://revision3.com/api/oembed/',
271                        'format' => 'json'
272                ),
273
274                'http://www.hulu.com/watch/*' => array(
275                        'id' => 'hulu',
276                        'endpoint' => 'http://www.hulu.com/api/oembed.{format}',
277                        'format' => 'xml'
278                ),
279
280                'http://www.vimeo.com/*' => array(
281                        'id' => 'vimeo',
282                        'endpoint' => 'http://www.vimeo.com/api/oembed.{format}',
283                        'format' => 'json',
284                        'shortcode' => 'vimeo',
285                        'args' => array(
286                                'byline' => array( 'true', 'false' ),
287                                'title' => array( 'true', 'false' ),
288                                'portrait' => array( 'true', 'false' ),
289                                'color' => '#a-f0-9{6}'
290                        )
291                )
292        ) );
293}
294
295add_shortcode( 'oembed', 'wp_oembed_shortcode' );