PluginProbe
Document Gallery / 2.0.1
Document Gallery v2.0.1
trunk 0.8 0.8.5 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.1 1.2 1.2.1 1.3 1.3.1 1.4 1.4.1 1.4.2 1.4.3 2.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 94 releases
document-gallery / inc / class-gallery.php

class-gallery.php in Document Gallery 2.0.1, at inc/class-gallery.php

595 lines 17.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 defined('WPINC') OR exit;
3
4 DG_Gallery::init();
5
6 /**
7 * Holds data specific to a given document gallery.
8 *
9 * @author drossiter
10 */
11 class DG_Gallery {
12
13 /*==========================================================================
14 * PRIVATE FIELDS
15 *=========================================================================*/
16
17 private $atts, $taxa;
18 private $docs = array();
19 private $errs = array();
20
21 // templates for HTML output
22 private static $no_docs = false;
23 private static $icon_wrapper = false;
24 private static $comment = false;
25
26 private static $binary_err = false;
27
28 /*==========================================================================
29 * PUBLIC FUNCTIONS
30 *=========================================================================*/
31
32 /**
33 * Returns whether to link to attachment pg.
34 * @return bool
35 */
36 public function linkToAttachmentPg() {
37 return $this->atts['attachment_pg'];
38 }
39
40 public function useFancyThumbs() {
41 return $this->atts['fancy'];
42 }
43
44 /**
45 * Returns whether descriptions should be included in output.
46 * @return bool
47 */
48 public function useDescriptions() {
49 return $this->atts['descriptions'];
50 }
51
52 /*==========================================================================
53 * GET AND SET OPTIONS
54 *=========================================================================*/
55
56 /**
57 * Gets the DG options specific to Gallery.
58 * @return array
59 */
60 public static function getOptions() {
61 global $dg_options;
62 return $dg_options['gallery'];
63 }
64
65 /**
66 * Sets the DG options specific to Gallery.
67 * @param array $options
68 */
69 public static function setOptions($options) {
70 global $dg_options;
71 $dg_options['gallery'] = $options;
72 update_option(DG_OPTION_NAME, $dg_options);
73 }
74
75 public static function getDefaults() {
76 $options = self::getOptions();
77 return $options['defaults'];
78 }
79
80 public static function setDefaults($defaults) {
81 $options = self::getOptions();
82 $options['defaults'] = $defaults;
83 self::setOptions($options);
84 }
85
86 /*==========================================================================
87 * INIT GALLERY
88 *=========================================================================*/
89
90 public static function init() {
91 self::$comment =
92 PHP_EOL . '<!-- ' . __('Generated using Document Gallery. Get yours here: ', 'document-gallery') .
93 'http://wordpress.org/extend/plugins/document-gallery -->' . PHP_EOL;
94 self::$icon_wrapper = '<div class="%s">'. PHP_EOL . '%s</div>' . PHP_EOL;
95 self::$no_docs = '<!-- ' . __('No attachments to display. How boring! :(', 'document-gallery') . ' -->';
96 self::$binary_err = __('The %s parameter may only be "%s" or "%s." You entered "%s."', 'document-gallery');
97 }
98
99 /**
100 * Builds a gallery object with attributes passed.
101 * @param array $atts Array of attributes used in shortcode.
102 */
103 public function __construct($atts) {
104 // empty string is passed when no arguments are given, but constructor expects an array
105 $atts = empty($atts) ? array() : $atts;
106 $defaults = self::getDefaults();
107
108 // values used to construct tax query (may be empty)
109 $this->taxa = array_diff_key($atts, $defaults);
110
111 // all recognized attributes go here
112 $this->atts = shortcode_atts($defaults, $atts);
113
114 // goes through all values in $this->atts, setting $this->errs as needed
115 $this->atts = self::sanitizeDefaults($this->atts, $this->errs);
116
117 // query DB for all documents requested
118 include_once DG_PATH . 'inc/class-document.php';
119 try {
120 $docs = $this->getDocuments();
121
122 foreach($docs as $doc) {
123 $this->docs[] = new DG_Document($doc, $this);
124 }
125 } catch(InvalidArgumentException $e) {
126 // errors will be printed in __toString()
127 }
128 }
129
130 /**
131 * Cleans up user input, making sure we don't pass crap on to WP core.
132 * @global string $wp_version
133 */
134 public static function sanitizeDefaults($defaults, &$errs) {
135 $old_defaults = self::getDefaults();
136
137 // remove invalid keys
138 $defaults = array_intersect_key($defaults, $old_defaults);
139
140 // add any missing keys
141 foreach ($old_defaults as $k => $v) {
142 if (!isset($defaults[$k])) {
143 if (is_bool($v)) {
144 // checkbox
145 $defaults[$k] = false;
146 } else {
147 // missing value
148 $defaults[$k] = $v;
149 }
150 }
151 }
152
153 $defaults['attachment_pg'] = self::sanitizeAttachmentPg($defaults['attachment_pg'], $err);
154 if (isset($err)) {
155 $errs['attachment_pg'] = $err;
156 unset($err);
157 }
158
159 $defaults['descriptions'] = self::sanitizeDescriptions($defaults['descriptions'], $err);
160 if (isset($err)) {
161 $errs['descriptions'] = $err;
162 unset($err);
163 }
164
165 $defaults['fancy'] = self::sanitizeFancy($defaults['fancy'], $err);
166 if (isset($err)) {
167 $errs['fancy'] = $err;
168 unset($err);
169 }
170
171 $defaults['ids'] = self::sanitizeIds($defaults['ids'], $err);
172 if (isset($err)) {
173 $errs['ids'] = $err;
174 unset($err);
175 }
176
177 $defaults['images'] = self::sanitizeImages($defaults['images'], $err);
178 if (isset($err)) {
179 $errs['images'] = $err;
180 unset($err);
181 }
182
183 $defaults['localpost'] = self::sanitizeLocalpost($defaults['localpost'], $err);
184 if (isset($err)) {
185 $errs['localpost'] = $err;
186 unset($err);
187 }
188
189 $defaults['order'] = self::sanitizeOrder($defaults['order'], $err);
190 if (isset($err)) {
191 $errs['order'] = $err;
192 unset($err);
193 }
194
195 $defaults['orderby'] = self::sanitizeOrderby($defaults['orderby'], $err);
196 if (isset($err)) {
197 $errs['orderby'] = $err;
198 unset($err);
199 }
200
201 $defaults['relation'] = self::sanitizeRelation($defaults['relation'], $err);
202 if (isset($err)) {
203 $errs['relation'] = $err;
204 unset($err);
205 }
206
207 return $defaults;
208 }
209
210 private static function sanitizeAttachmentPg($value, &$err) {
211 $defaults = self::getDefaults();
212 $ret = $defaults['attachment_pg'];
213
214 $attachment_pg = self::toBool($value);
215
216 if(is_null($attachment_pg)) {
217 $err = sprintf(self::$binary_err, 'attachment_pg', 'true', 'false', $value);
218 } else {
219 $ret = $attachment_pg;
220 }
221
222 return $ret;
223 }
224
225 private static function sanitizeDescriptions($value, &$err) {
226 $defaults = self::getDefaults();
227 $ret = $defaults['descriptions'];
228
229 $descriptions = self::toBool($value);
230
231 if(is_null($descriptions)) {
232 $err = sprintf(self::$binary_err, 'descriptions', 'true', 'false', $value);
233 } else {
234 $ret = $descriptions;
235 }
236
237 return $ret;
238 }
239
240 private static function sanitizeFancy($value, &$err) {
241 $defaults = self::getDefaults();
242 $ret = $defaults['fancy'];
243
244 $fancy = self::toBool($value);
245
246 if(is_null($fancy)) {
247 $err = sprintf(self::$binary_err, 'fancy', 'true', 'false', $value);
248 } else {
249 $ret = $fancy;
250 }
251
252 return $ret;
253 }
254
255 private static function sanitizeIds($value, &$err) {
256 $defaults = self::getDefaults();
257 $ret = $defaults['ids'];
258
259 if(false === self::toBool($value)) {
260 $ret = false;
261 } else {
262 $value = trim($value);
263 $ids = $value ? explode(',', $value) : array();
264 $bad = array_filter($ids, array(__CLASS__, 'negativeInt'));
265
266 if(!empty($bad)) {
267 $err = _n('The following ID is invalid: ',
268 'The following IDs are invalid: ',
269 count($bad), 'document-gallery') . implode(', ', $bad);
270 } else {
271 $ret = $ids;
272 }
273 }
274
275 return $ret;
276 }
277
278 private static function sanitizeImages($value, &$err) {
279 $defaults = self::getDefaults();
280 $ret = $defaults['images'];
281
282 $images = self::toBool($value);
283
284 if(is_null($images)) {
285 $err = sprintf(self::$binary_err, 'images', 'true', 'false', $value);
286 } else {
287 $ret = $images;
288 }
289
290 return $ret;
291 }
292
293 private static function sanitizeLocalpost($value, &$err) {
294 $defaults = self::getDefaults();
295 $ret = $defaults['localpost'];
296
297 $localpost = self::toBool($value);
298
299 if(is_null($localpost)) {
300 $err = sprintf(self::$binary_err, 'localpost', 'true', 'false', $value);
301 } else {
302 $ret = $localpost;
303 }
304
305 return $ret;
306 }
307
308 private static function sanitizeOrder($value, &$err) {
309 $defaults = self::getDefaults();
310 $ret = $defaults['order'];
311
312 $order = strtoupper($value);
313 if(!in_array($order, self::getOrderOptions())) {
314 $err = sprintf(self::$binary_err, 'order', 'ASC', 'DEC', $value);
315 } else {
316 $ret = $order;
317 }
318
319 return $ret;
320 }
321
322 public static function getOrderOptions() {
323 return array('ASC', 'DEC');
324 }
325
326 private static function sanitizeOrderby($value, &$err) {
327 $defaults = self::getDefaults();
328 $ret = $defaults['orderby'];
329
330 $orderby = 'ID' === strtoupper($value) ? 'ID' : strtolower($value);
331 if (!in_array($orderby, self::getOrderbyOptions())) {
332 $err = sprintf(
333 __('The orderby value entered, "%s," is not valid.', 'document-gallery'),
334 $value);
335 } else {
336 $ret = $orderby;
337 }
338
339 return $ret;
340 }
341
342 public static function getOrderbyOptions() {
343 return array('author', 'comment_count', 'date', 'ID',
344 'menu_order', 'modified', 'name', 'none',
345 'parent', 'post__in', 'rand', 'title');
346 }
347
348 private static function sanitizeRelation($value, &$err) {
349 $defaults = self::getDefaults();
350 $ret = $defaults['relation'];
351
352 $relation = strtoupper($value);
353 if(!in_array($relation, self::getRelationOptions())) {
354 $err = sprintf(self::$binary_err, 'relation', 'AND', 'OR', $value);
355 } else {
356 $ret = $relation;
357 }
358
359 return $ret;
360 }
361
362 public static function getRelationOptions() {
363 return array('AND', 'OR');
364 }
365
366 /**
367 * Gets all valid Documents based on the attributes passed by the user.
368 * @return array Contains all documents matching the query.
369 * @throws InvalidArgumentException Thrown when $this->errs is not empty.
370 */
371 private function getDocuments() {
372 $mime_types = array('application', 'video', 'text', 'audio');
373 if ($this->atts['images']) {
374 $mime_types[] = 'image';
375 }
376
377 $query = array(
378 'numberposts' => -1,
379 'orderby' => $this->atts['orderby'],
380 'order' => $this->atts['order'],
381 'post_status' => 'any',
382 'post_type' => 'attachment',
383 'post_mime_type' => implode(',', $mime_types));
384
385 $query['post_parent'] =
386 $this->atts['localpost']
387 && ($post = get_post()) ? $post->ID : '';
388
389 $this->setTaxa($query);
390
391 if(!empty($this->errs)) {
392 throw new InvalidArgumentException();
393 }
394
395 return (false !== $this->atts['ids'])
396 ? $this->getAttachmentsByIds()
397 : get_posts($query);
398 }
399
400 /**
401 * Function loops through all attributes passed that did not match
402 * self::$defaults. If they are the name of a taxonomy, they are plugged
403 * into the query, otherwise $this->errs is appended with an error string.
404 * @global string $wp_version Determines which tax query to use.
405 * @param array $query Query to insert tax query into.
406 */
407 private function setTaxa(&$query) {
408 if(!empty($this->taxa)) {
409 global $wp_version;
410 $taxa = array();
411
412 // use preferred tax_query if supported
413 if (version_compare($wp_version, '3.1', '>=')) {
414 // only include relation if we have multiple taxa
415 if(count($this->taxa) > 1) {
416 $taxa['relation'] = $this->atts['relation'];
417 }
418
419 foreach ($this->taxa as $taxon => $terms) {
420 $terms = $this->getTermIdsByNames($taxon, explode(',', $terms));
421
422 $taxa[] = array(
423 'taxonomy' => $taxon,
424 'field' => 'id',
425 'terms' => $terms
426 );
427 }
428
429 // create nested structure
430 $query['tax_query'] = $taxa;
431 } elseif (version_compare($wp_version, '2.3', '>=')) {
432 // fallback to deprecated {tax_name} => {term_slug} construct
433 foreach ($this->taxa as $taxon => $terms) {
434 $taxa[$taxon] = ($taxon == 'category')
435 ? implode(',', $this->getTermIdsByNames($taxon, explode(',', $terms)))
436 : implode(',', $this->getTermSlugsByNames($taxon, explode(',', $terms)));
437 }
438
439 $query = array_merge($taxa, $query);
440 } else {
441 // WP < 2.3 not supported for category/custom taxa
442 $this->errs[] = __('The following attributes are invalid: ', 'document-gallery') .
443 implode(', ', array_keys($this->taxa));
444 }
445 }
446 }
447
448 /*==========================================================================
449 * HELPER FUNCTIONS
450 *=========================================================================*/
451
452 /**
453 * Returns an array of term ids when provided with a list of term names.
454 * Also appends an entry onto $errs if any invalid names are found.
455 * @param string $taxon
456 * @param array $term_names
457 * @return array
458 */
459 private function getTermIdsByNames($taxon, $term_names) {
460 return $this->getTermXByNames('term_id', $taxon, $term_names);
461 }
462
463 /**
464 * Returns an array of term slugs when provided with a list of term names.
465 * Also appends an entry onto $errs if any invalid names are found.
466 * @param string $taxon
467 * @param array $term_names
468 * @return array
469 */
470 private function getTermSlugsByNames($taxon, $term_names) {
471 return $this->getTermXByNames('slug', $taxon, $term_names);
472 }
473
474 /**
475 * (WP >= 2.3) Returns a list of x, where x may be any of the fields within a
476 * term object, when provided with a list of term names (not slugs).
477 * (http://codex.wordpress.org/Function_Reference/get_term_by#Return_Values)
478 *
479 * Also appends an entry onto $errs if any invalid names are found.
480 * @param string $x
481 * @param string $taxon
482 * @param array $term_names
483 * @return array
484 */
485 private function getTermXByNames($x, $taxon, $term_names) {
486 $ret = array();
487
488 foreach ($term_names as $name) {
489 if (($term = get_term_by('name', $name, $taxon))) {
490 $ret[] = $term->{$x};
491 } else {
492 $this->errs[] = sprintf(__('%s is not a valid term name in %s.',
493 'document-gallery'), $name, $taxon);
494 }
495 }
496
497 return $ret;
498 }
499
500 /**
501 * Given a list of IDs, all attachments represented by these IDs are returned.
502 * @return array post objects
503 */
504 private function getAttachmentsByIds() {
505 $args = array(
506 'post_type' => 'attachment',
507 'post_status' => 'inherit',
508 'post_per_page' => -1,
509 'post__in' => $this->atts['ids']
510 );
511
512 return count($args['post__in']) ? get_posts($args) : array();
513 }
514
515 /**
516 * Function returns false for positive ints, true otherwise.
517 * @param string $var could be anything.
518 * @return boolean indicating whether $var is not a positive int.
519 */
520 private static function negativeInt($var) {
521 return !is_numeric($var) // isn't numeric
522 || (int)$var != $var // isn't int
523 || (int)$var < 0; // isn't positive
524 }
525
526 private static function toBool($val) {
527 if (is_bool($val)) {
528 return $val;
529 }
530
531 if (is_string($val)) {
532 $val = strtolower($val);
533 if ('true' === $val || '1' === $val) {
534 return true;
535 }
536
537 if ('false' === $val || '0' === $val) {
538 return false;
539 }
540 }
541
542 if (is_null($val)) {
543 return false;
544 }
545
546 return null;
547 }
548
549 /*==========================================================================
550 * OUTPUT HTML STRING
551 *=========================================================================*/
552
553 /**
554 * Returns HTML representing this Gallery.
555 * @return string
556 */
557 public function __toString() {
558 if(!empty($this->errs)) {
559 return '<p>' . implode('</p><p>', $this->errs) . '</p>';
560 }
561
562 if(empty($this->docs)) {
563 return self::$no_docs;
564 }
565
566 $core = '';
567 $classes = array('document-icon-wrapper');
568 if($this->useDescriptions()) {
569 $classes[] = 'descriptions';
570 }
571
572 $icon_wrapper = sprintf(self::$icon_wrapper, implode(' ', $classes), '%s');
573
574 if($this->useDescriptions()) {
575 foreach($this->docs as $doc) {
576 $core .= sprintf($icon_wrapper, $doc);
577 }
578 } else {
579 for($i = 0; $i < count($this->docs); $i+=4) {
580 $row = '';
581
582 $min = min($i+4, count($this->docs));
583 for($x = $i; $x < $min; $x++) {
584 $row .= $this->docs[$x];
585 }
586
587 $core .= sprintf($icon_wrapper, $row);
588 }
589 }
590
591 return self::$comment . $core;
592 }
593 }
594
595 ?>