PluginProbe
Document Gallery / 2.2.6
Document Gallery v2.2.6
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.2.6, at inc/class-gallery.php

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