PluginProbe
Vimeography: Vimeo Video Gallery WordPress Plugin / 2.2
Vimeography: Vimeo Video Gallery WordPress Plugin v2.2
2.4.9 2.4.8 trunk 0.5.1 0.5.2 0.5.3 0.5.4 0.5.5 0.5.6 0.5.7 0.6 0.6.1 0.6.2 0.6.3 0.6.4 0.6.5 0.6.6 0.6.7 0.6.8 0.6.8.1 0.6.9 0.6.9.1 0.6.9.2 0.7 0.8 All 103 releases
← All changes | lib/core.php +472 -310 0.62.2 View file →
@@ -1,316 +1,478 @@
1 1 <?php
2 2
3 -// Require Mustache.php
4 -require_once(VIMEOGRAPHY_PATH . '/vendor/mustache/Mustache.php');
3 +namespace Vimeography;
5 4
6 -class Vimeography_Core extends Vimeography
5 +abstract class Core
7 6 {
8 - const ENDPOINT = 'http://vimeo.com/api/v2/';
9 - const FORMAT = '.json';
10 -
11 - protected $_source;
12 - protected $_type;
13 -
14 - protected $_theme;
15 - protected $_limit;
16 - protected $_featured;
17 - protected $_gallery_id;
18 -
19 - protected $_debug = FALSE;
20 -
21 - public static function factory($class, $settings)
22 - {
23 - require_once(VIMEOGRAPHY_PATH .'lib/'. $class . '.php');
24 - $class_name = 'Vimeography_'. ucfirst($class);
25 -
26 - if (class_exists($class_name))
27 - {
28 - return new $class_name($settings);
29 - }
30 - else
31 - {
32 - throw new Vimeography_Exception('Class not found: '.$class_name);
33 - }
34 - }
35 -
36 - public function __construct($settings)
37 - {
38 - require_once(VIMEOGRAPHY_PATH .'lib/exception.php');
39 -
40 - $this->_theme = $settings['theme'];
41 - $this->_featured = $settings['featured'];
42 - $this->_source = $settings['source'];
43 - $this->_limit = $settings['limit'];
44 - $this->_gallery_id = $settings['id'];
45 - }
46 -
47 - /**
48 - * Overload the constructed debugger to print the data instead of render it.
49 - *
50 - * @access public
51 - * @param mixed $debug (default: TRUE)
52 - * @return void
53 - */
54 - public function debug($debug = TRUE)
55 - {
56 - $this->_debug = $debug;
57 - return $this;
58 - }
59 -
60 - /**
61 - * Retrieves the requested data from Vimeo API.
62 - * This is called by the class loaded in the factory method.
63 - *
64 - * TODO: This could potentially return a 404 page, and we don't want that, nor do we want to show it in the exception.
65 - * @access protected
66 - * @param mixed $data
67 - * @return void
68 - */
69 - protected function _retrieve()
70 - {
71 - $urls = array();
72 - $urls[] = $this->_build_url($this->_source);
73 -
74 - if (!empty($this->_featured))
75 - $urls[] = self::ENDPOINT.'video/'.$this->_featured.self::FORMAT;
76 -
77 - $result = array();
78 - $videos = '';
79 - $main_request = TRUE;
80 -
81 - foreach ($urls as $url)
82 - {
83 - if ($main_request == TRUE)
84 - {
85 - $number_of_requests = ceil($this->_limit / 20);
86 -
87 - for ($video_page = 1; $video_page <= $number_of_requests; $video_page++)
88 - {
89 - $response = $this->_make_vimeo_request($url, $video_page);
90 -
91 - if ($video_page == 1)
92 - {
93 - // If the limit is less than the total videos, we need to remove some videos.
94 - if ($this->_limit < count(json_decode($response)))
95 - {
96 - $video_object = json_decode($response);
97 -
98 - for ($video_to_delete = (count($video_object) - 1); $video_to_delete >= $this->_limit; $video_to_delete--)
99 - {
100 - unset($video_object[$video_to_delete]);
101 - }
102 - $response = json_encode($video_object);
103 - }
104 -
105 - $videos .= $response;
106 - }
107 - else
108 - {
109 - $videos = str_replace(']', ',', $videos);
110 -
111 - if ($this->_limit < ($video_page * 20))
112 - {
113 - $video_object = json_decode($response);
114 -
115 - for ($video_to_delete = count($video_object) - 1; $video_to_delete >= $this->_limit - (($video_page * 20) / 2); $video_to_delete--)
116 - {
117 - unset($video_object[$video_to_delete]);
118 - }
119 - $response = json_encode($video_object);
120 - }
121 -
122 - $response = str_replace('[', ' ', $response);
123 - $videos = $videos.$response;
124 - }
125 -
126 - // This stops the next request from occuring if the total video count on the Vimeo source is less than what the user specified that they would like to see
127 - if (count(json_decode($videos)) < 20) break;
128 -
129 - }
130 - $main_request = FALSE;
131 - $result[] = $videos;
132 - }
133 - else
134 - {
135 - // A featured video was set, let's get it.
136 - $featured_video = $this->_make_vimeo_request($url, 1);
137 -
138 - // Now, we need to check if the featured video already exists in the main video request object.
139 - $video_to_check = json_decode($featured_video, true);
140 - $video_object = json_decode($result[0], true);
141 - $video_found = FALSE;
142 -
143 - // If it does exist, we should remove it.
144 - foreach ($video_object as $video_key => $video_data)
145 - {
146 - if ($video_data['id'] === $video_to_check[0]['id'])
147 - {
148 - unset($video_object[$video_key]);
149 - $video_found = TRUE;
150 - }
151 - }
152 -
153 - // If it does not exist, we need to remove the last video in the array to make room for the featured video.
154 - if ($video_found == FALSE)
155 - unset($video_object[count($video_object) - 1]);
156 -
157 - $result[0] = json_encode(array_values($video_object));
158 - $result[] = $featured_video;
159 - }
160 -
161 - }
162 - return $result;
163 - }
164 -
165 - /**
166 - * Build the endpoint url based on the provided Vimeo URL.
167 - *
168 - * @access private
169 - * @param mixed $data
170 - * @return void
171 - */
172 - private function _build_url($source)
173 - {
7 + public $version = '2.0';
174 8
175 - $scheme = parse_url($source);
176 - if (empty($scheme['scheme'])) $source = 'https://' . $source;
9 + protected $_endpoint = 'https://api.vimeo.com/';
177 10
178 - if ((($url = parse_url($source)) !== FALSE) && (preg_match('~vimeo[.]com$~', $url['host']) > 0))
179 - {
180 - // The URL is a valid Vimeo URL. Break it into an array containing the URL parts
181 - $url = array_filter(explode('/', $url['path']), 'strlen');
182 -
183 - // If the array doesn't contain one of the following strings, it must be either a user or a video
184 - if (in_array($url[1], array('album', 'channels', 'groups')) !== TRUE)
185 - {
186 - if (is_numeric($url[1]))
187 - {
188 - array_unshift($url, 'video');
189 - }
190 - else
191 - {
192 - array_unshift($url, 'users');
193 - }
194 - }
195 -
196 - // Put the URL parts into a conventional array
197 - $parts = array('type' => rtrim(array_shift($url), 's'), 'name' => array_shift($url));
198 - }
199 - else
200 - {
201 - throw new Vimeography_Exception('You must provide a valid Vimeo source from where to retrieve Vimeo videos.');
202 - }
203 -
204 - switch ($parts['type'])
205 - {
206 - case 'album':
207 - $result = 'album/'.$parts['name'].'/'.$this->_type;
208 - break;
209 - case 'channel':
210 - $result = 'channel/'.$parts['name'].'/'.$this->_type;
211 - break;
212 - case 'group':
213 - $result = 'group/'.$parts['name'].'/'.$this->_type;
214 - break;
215 - case 'user':
216 - $result = $parts['name'].'/'.$this->_type;
217 - break;
218 - case 'video':
219 - $result = 'video/'.$parts['name'];
220 - break;
221 - default:
222 - throw new Vimeography_Exception($parts['type'].' is not a valid Vimeo source parameter.');
223 - break;
224 - }
225 -
226 - return self::ENDPOINT.$result.self::FORMAT;
227 - }
228 -
229 - /**
230 - * Send a cURL Wordpress request to retrieve the requested data from the Vimeo simple API.
231 - *
232 - * @access private
233 - * @param mixed $url
234 - * @param mixed $page
235 - * @return void
236 - */
237 - private function _make_vimeo_request($url, $page)
238 - {
239 - $response = wp_remote_get($url.'?page='.$page);
240 -
241 - if (isset($response->errors))
242 - {
243 - foreach ($response->errors as $error)
244 - {
245 - throw new Vimeography_Exception('the plugin did not retrieve data from the Vimeo API! '. $error[0]);
246 - }
247 - }
248 -
249 - if (strpos($response['body'], 'not found'))
250 - throw new Vimeography_Exception('the plugin could not retrieve data from the Vimeo API! '. $response['body']);
251 -
252 - return $response['body'];
253 - }
254 -
255 - public function render($data)
256 - {
257 - if (! $this->_debug)
258 - {
259 - if (! isset($this->_theme))
260 - throw new Vimeography_Exception('You must specify a theme in either the admin panel or the shortcode.');
261 -
262 - if (!@require_once(VIMEOGRAPHY_THEME_PATH . $this->_theme . '/'.$this->_theme.'.php'))
263 - throw new Vimeography_Exception('The "'.$this->_theme.'" theme does not exist or is improperly structured.');
264 -
265 - $class = 'Vimeography_Themes_'.ucfirst($this->_theme);
266 -
267 - if (!class_exists($class))
268 - throw new Vimeography_Exception('The "'.$this->_theme.'" theme class does not exist or is improperly structured.');
269 -
270 - $mustache = new $class;
271 - $theme = $this->_load_theme($this->_theme);
272 -
273 - $mustache->data = json_decode($data[0]);
274 -
275 - if (isset($data[1]))
276 - {
277 - // featured video option is set
278 - $featured = json_decode($data[1]);
279 - }
280 - else
281 - {
282 - $data = json_decode($data[0]);
283 - $featured = $data[0];
284 - }
285 -
286 - $mustache->featured = $featured;
287 - $mustache->gallery_id = $this->_gallery_id;
288 -
289 - return $mustache->render($theme);
290 - }
291 - else
292 - {
293 - echo '<h1>Vimeography Debug</h1>';
294 - echo '<pre>';
295 - print_r(json_decode($data));
296 - echo '</pre>';
297 - die;
298 - }
299 - }
300 -
301 - /**
302 - * Retrieves the contents of a Vimeography theme's mustache template.
303 - *
304 - * @access private
305 - * @static
306 - * @param mixed $name
307 - * @return void
308 - */
309 - private static function _load_theme($name)
310 - {
311 - $path = VIMEOGRAPHY_THEME_PATH . $name . '/videos.mustache';
312 - if (! $result = @file_get_contents($path))
313 - throw new Vimeography_Exception('The gallery template for the "'.$name.'" theme cannot be found.');
314 - return $result;
315 - }
316 -}
11 + /**
12 + * Vimeo library instance
13 + *
14 + * @var instance
15 + */
16 + protected $_vimeo;
17 +
18 + /**
19 + * Access token to send along with the Vimeo request.
20 + *
21 + * @var string
22 + */
23 + protected $_auth;
24 +
25 + /**
26 + * The parameters to send in the Vimeo request.
27 + *
28 + * @var array
29 + */
30 + protected $_params = array();
31 +
32 + /**
33 + * The resource to request in the Vimeo request
34 + *
35 + * example: `/channels/staffpicks/videos`
36 + *
37 + * @var string
38 + */
39 + protected $_resource;
40 +
41 + /**
42 + * Limit a gallery to show only this amount of videos.
43 + *
44 + * @var int
45 + */
46 + protected $_limit = 0;
47 +
48 + /**
49 + * An optional resource string pointing to the video that
50 + * should be featured in the gallery.
51 + *
52 + * @var string
53 + */
54 + protected $_featured;
55 +
56 + /**
57 + * [$_cache description]
58 + * @var [type]
59 + */
60 + protected $_cache;
61 +
62 + /**
63 + * Whether or not to bypass checking and setting
64 + * the cache with relevant video data.
65 + *
66 + * Can be set with $engine->skip_cache()->fetch();
67 + *
68 + * @var bool
69 + */
70 + public $skip_cache = false;
71 +
72 + /**
73 + * Length of time that a cache file is good for,
74 + * in seconds.
75 + *
76 + * @var integer
77 + */
78 + private $_expiration = 3600;
79 +
80 + /**
81 + * Request the following fields to be returned from the Vimeo API.
82 + *
83 + * @var array
84 + */
85 + public $fields = array(
86 + 'name',
87 + 'uri',
88 + 'link',
89 + 'description',
90 + 'duration',
91 + 'width',
92 + 'height',
93 + 'embed',
94 + 'tags.name',
95 + 'tags.canonical',
96 + 'created_time',
97 + 'stats',
98 + 'pictures',
99 + 'status',
100 + 'user.account'
101 + );
102 +
103 + /**
104 + * Set the class properties from the provided
105 + * shortcode settings array.
106 + */
107 + public function __construct($engine)
108 + {
109 + $this->gallery_id = $engine->gallery_id;
110 + $this->gallery_settings = $engine->gallery_settings;
111 +
112 + $this->_resource = $this->gallery_settings['source'];
113 +
114 + if (isset($this->gallery_settings['limit'])) {
115 + $this->_limit = $this->gallery_settings['limit'];
116 + }
117 +
118 + if (
119 + isset($this->gallery_settings['featured']) &&
120 + !empty($this->gallery_settings['featured'])
121 + ) {
122 + $this->_featured =
123 + '/videos/' .
124 + preg_replace("/[^0-9]/", '', $this->gallery_settings['featured']);
125 + }
126 +
127 + if (isset($engine->gallery_settings['cache'])) {
128 + $this->_expiration = intval($engine->gallery_settings['cache']);
129 + }
130 +
131 + require_once VIMEOGRAPHY_PATH . 'lib/cache.php';
132 + $this->_cache = new Cache($engine);
133 + }
134 +
135 + /**
136 + * [_verify_vimeo_resource description]
137 + * @param [type] $resource [description]
138 + * @return [type] [description]
139 + */
140 + abstract protected function _verify_vimeo_resource($resource);
141 +
142 + /**
143 + * Retrieves the videos for the gallery.
144 + *
145 + * @return [type] [description]
146 + */
147 + public function get_videos()
148 + {
149 + if (isset($_GET['vimeography_nocache']) || $this->skip_cache === true) {
150 + return $this->fetch();
151 + }
152 +
153 + // If the cache file exists,
154 + if ($this->_cache->exists()) {
155 + // and the cache file is expired,
156 + if ($this->_cache->expired() === true) {
157 + // make the request with a last modified header.
158 + $result = $this->fetch($this->_cache->last_modified);
159 +
160 + // Here is where we need to check if $video_set exists, or if it
161 + // returned a 304, in which case, we can safely update the
162 + // cache's last modified and return it.
163 + if ($result === null) {
164 + $result = $this->_cache->renew()->get();
165 + } else {
166 + // Cache the updated results if we can.
167 + $this->_set_cache($result);
168 + }
169 + } else {
170 + // If it isn't expired, return it.
171 + $result = $this->_cache->get();
172 +
173 + $result = apply_filters(
174 + 'vimeography.pro.paginate',
175 + $result,
176 + $this->gallery_id
177 + );
178 + }
179 + } else {
180 + // If a cache doesn't exist, go get the videos, dude.
181 + $result = $this->fetch();
182 +
183 + // Cache the results if we can.
184 + $this->_set_cache($result);
185 + }
186 +
187 + return $result;
188 + }
189 +
190 + /**
191 + * Fetch the videos to be displayed in the Vimeography Gallery.
192 + *
193 + * @param $last_modified
194 + * @return string $response Modified response from Vimeo.
195 + */
196 + public function fetch($last_modified = null)
197 + {
198 + if (!$this->_verify_vimeo_resource($this->_resource)) {
199 + throw new \Vimeography_Exception(
200 + sprintf(
201 + __('The "%s" resource is not valid.', 'vimeography'),
202 + $this->_resource
203 + )
204 + );
205 + }
206 +
207 + $response = $this->_make_vimeo_request(
208 + $this->_resource,
209 + $this->_params,
210 + $last_modified
211 + );
212 +
213 + // If 304 not modified, return
214 + if ($response === null) {
215 + return $response;
216 + }
217 +
218 + $video_set = $response->data;
219 +
220 + if (!empty($this->_featured)) {
221 + $featured_video = $this->_make_vimeo_request($this->_featured);
222 + $result_set = $this->_arrange_featured_video($video_set, $featured_video);
223 + } else {
224 + $result_set = $video_set;
225 + }
226 +
227 + unset($response->data);
228 + $response->video_set = $result_set;
229 +
230 + return $response;
231 + }
232 +
233 + /**
234 + * Send a cURL Wordpress request to retrieve the requested data from the Vimeo API.
235 + *
236 + * @param string $endpoint Vimeo API endpoint
237 + * @return array Response Body
238 + */
239 + private function _make_vimeo_request(
240 + $endpoint,
241 + $params = array(),
242 + $last_modified = null
243 + ) {
244 + try {
245 + /**
246 + * Limit the request to return only the fields that
247 + * Vimeography themes actually use.
248 + *
249 + * @var [type]
250 + */
251 + $fields = apply_filters('vimeography.request.fields', $this->fields);
252 +
253 + /**
254 + * Add parameters which are common to all requests
255 + * Note: Signature changed in PHP7.4.0, but we still support 5.3+
256 + */
257 + if (version_compare(phpversion(), '7.4.0', '<')) {
258 + // php version isn't high enough
259 + $imploded_fields = implode($fields, ',');
260 + } else {
261 + $imploded_fields = implode(',', $fields);
262 + }
263 +
264 + $params = array_merge(
265 + array(
266 + 'fields' => $imploded_fields
267 + ),
268 + $params
269 + );
270 +
271 + /**
272 + * Allows Vimeography to disclude videos in the request response
273 + * that cannot be embedded due to their privacy settings or domain restrictions.
274 + */
275 + $filter = apply_filters(
276 + 'vimeography.request.privacy.filter',
277 + 'embeddable',
278 + $this->gallery_id,
279 + $this->gallery_settings
280 + );
281 +
282 + if ($filter === 'embeddable') {
283 + $params['filter'] = 'embeddable';
284 + $params['filter_embeddable'] = 'true';
285 + }
286 +
287 + /**
288 + * Set the headers to send along with the Vimeo request.
289 + */
290 + $headers = array(
291 + 'User-Agent' => sprintf('Vimeography loves you (%s)', home_url())
292 + );
293 +
294 + if ($last_modified !== null) {
295 + $headers['If-Modified-Since'] = $last_modified;
296 + }
297 +
298 + $headers = apply_filters(
299 + 'vimeography.request.headers',
300 + $headers,
301 + $this->gallery_id,
302 + $this->gallery_settings
303 + );
304 +
305 + /**
306 + * Perform the request.
307 + */
308 + $response = $this->_vimeo->request(
309 + $endpoint,
310 + $params,
311 + 'GET',
312 + true,
313 + $headers
314 + );
315 +
316 + do_action(
317 + 'vimeography.request.response',
318 + $response,
319 + $this->gallery_id,
320 + $this->gallery_settings,
321 + $endpoint,
322 + $params,
323 + $headers
324 + );
325 +
326 + // if ( isset( $response['headers']['X-RateLimit-Limit'] ) ) {
327 + // $reset_date = new \DateTime();
328 + // $reset_date->setTimestamp( $response['headers']['X-RateLimit-Reset'] );
329 +
330 + // $this->rate_limit = array(
331 + // 'limit' => $response['headers']['X-RateLimit-Limit'],
332 + // 'remaining' => $response['headers']['X-RateLimit-Remaining'],
333 + // 'reset' => $reset_date,
334 + // );
335 + // }
336 +
337 + switch ($response['status']) {
338 + case 200:
339 + return $response['body'];
340 + case 304:
341 + return null;
342 + case 400:
343 + throw new \Vimeography_Exception(
344 + __('a bad request made was made. ', 'vimeography') .
345 + $response['body']->error
346 + );
347 + case 401:
348 + throw new \Vimeography_Exception(
349 + __(
350 + 'an invalid token was used for the API request. Try removing your Vimeo token on the Vimeography Pro page and following the steps again to create a Vimeo app.',
351 + 'vimeography'
352 + )
353 + );
354 + case 403:
355 + if ($response['body']->error_code) {
356 + $error_code = $response['body']->error_code;
357 + $developer_message = $response['body']->developer_message;
358 +
359 + $error = sprintf(
360 + __(
361 + 'Your server\'s IP address (%1$s) is currently banned from using the Vimeo API. Please contact Vimeo support at https://vimeo.com/help/contact for more information. Make sure you include your server IP address in your support request. (%1$s)',
362 + 'vimeography'
363 + ),
364 + $response['headers']['X-Banned-IP']
365 + );
366 + $error .= sprintf(
367 + __('<br /><br />Error #%1$d: %2$s', 'vimeography'),
368 + $error_code,
369 + $developer_message
370 + );
371 + } else {
372 + $error = __(
373 + 'This site does not have the proper permissions to access that Vimeo collection.',
374 + 'vimeography'
375 + );
376 + }
377 +
378 + throw new \Vimeography_Exception($error);
379 + case 404:
380 + throw new \Vimeography_Exception(
381 + __(
382 + 'the plugin could not retrieve data from the Vimeo API! ',
383 + 'vimeography'
384 + ) . $response['body']->error
385 + );
386 + case 429:
387 + throw new \Vimeography_Exception(
388 + __(
389 + 'too many requests to Vimeo, please wait a moment and try again.',
390 + 'vimeography'
391 + )
392 + );
393 + case 500:
394 + case 503:
395 + throw new \Vimeography_Exception(
396 + __(
397 + 'looks like Vimeo is having some API issues. Try reloading, or, check back in a few minutes. You can also check http://vimeostatus.com for live updates.',
398 + 'vimeography'
399 + )
400 + );
401 + default:
402 + throw new \Vimeography_Exception(
403 + sprintf(
404 + __('Unknown response status %1$d, %2$s', 'vimeography'),
405 + $response['status'],
406 + $response['body']->error
407 + )
408 + );
409 + }
410 + } catch (Exception $e) {
411 + throw new \Vimeography_Exception(
412 + __('the request to Vimeo failed. ', 'vimeography') . $e->getMessage()
413 + );
414 + }
415 + }
416 +
417 + /**
418 + * Arrange the video set to contain the video to be featured at the beginning of the set.
419 + *
420 + * @param array $video_set Vimeo Videos
421 + * @param array $featured_video a Vimeo Video
422 + * @return string $video_set Arranged array of Vimeo Videos
423 + */
424 + private function _arrange_featured_video($video_set, $featured_video)
425 + {
426 + // Does the featured video exist in the set?
427 + // If so, remove it from the set and place at front.
428 + $found = false;
429 +
430 + // We have to do this because if the featured video
431 + // exists in the collection as a contextual video,
432 + // it would not be removed if we only compared resouce urls
433 + // since they would not match.
434 + $featured_id = str_replace('/', '', strrchr($featured_video->link, '/'));
435 +
436 + foreach ($video_set as $key => $video) {
437 + if (strpos($video->uri, $featured_id) !== false) {
438 + unset($video_set[$key]);
439 + $found = true;
440 + }
441 + }
442 +
443 + // If it does not exist, we need to remove the last video in the
444 + // video set and place the featured video up front.
445 + if ($found == false && $this->_limit == count($video_set)) {
446 + array_pop($video_set);
447 + }
448 +
449 + // Add the featured video to the front.
450 + array_unshift($video_set, $featured_video);
451 +
452 + return array_values($video_set);
453 + }
454 +
455 + /**
456 + * Set the cache file contents if our
457 + * gallery settings and response data meet all
458 + * of the required criteria.
459 + *
460 + * @param array $data
461 + */
462 + private function _set_cache($data)
463 + {
464 + if (
465 + !empty($data->video_set) &&
466 + $data->page === 1 &&
467 + $this->_expiration !== 0 &&
468 + isset($this->gallery_id)
469 + ) {
470 + $data = apply_filters(
471 + 'vimeography/cache-videos',
472 + $data,
473 + $this->gallery_id
474 + );
475 + $this->_cache->set($data);
476 + }
477 + }
478 +}