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

578 lines 16.9 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 $taxa = array();
410
411 // only include relation if we have multiple taxa
412 if(count($this->taxa) > 1) {
413 $taxa['relation'] = $this->atts['relation'];
414 }
415
416 foreach ($this->taxa as $taxon => $terms) {
417 $terms = $this->getTermIdsByNames($taxon, explode(',', $terms));
418
419 $taxa[] = array(
420 'taxonomy' => $taxon,
421 'field' => 'id',
422 'terms' => $terms
423 );
424 }
425
426 // create nested structure
427 $query['tax_query'] = $taxa;
428 }
429 }
430
431 /*==========================================================================
432 * HELPER FUNCTIONS
433 *=========================================================================*/
434
435 /**
436 * Returns an array of term ids when provided with a list of term names.
437 * Also appends an entry onto $errs if any invalid names are found.
438 * @param string $taxon
439 * @param array $term_names
440 * @return array
441 */
442 private function getTermIdsByNames($taxon, $term_names) {
443 return $this->getTermXByNames('term_id', $taxon, $term_names);
444 }
445
446 /**
447 * Returns an array of term slugs when provided with a list of term names.
448 * Also appends an entry onto $errs if any invalid names are found.
449 * @param string $taxon
450 * @param array $term_names
451 * @return array
452 */
453 private function getTermSlugsByNames($taxon, $term_names) {
454 return $this->getTermXByNames('slug', $taxon, $term_names);
455 }
456
457 /**
458 * (WP >= 2.3) Returns a list of x, where x may be any of the fields within a
459 * term object, when provided with a list of term names (not slugs).
460 * (http://codex.wordpress.org/Function_Reference/get_term_by#Return_Values)
461 *
462 * Also appends an entry onto $errs if any invalid names are found.
463 * @param string $x
464 * @param string $taxon
465 * @param array $term_names
466 * @return array
467 */
468 private function getTermXByNames($x, $taxon, $term_names) {
469 $ret = array();
470
471 foreach ($term_names as $name) {
472 if (($term = get_term_by('name', $name, $taxon))) {
473 $ret[] = $term->{$x};
474 } else {
475 $this->errs[] = sprintf(__('%s is not a valid term name in %s.',
476 'document-gallery'), $name, $taxon);
477 }
478 }
479
480 return $ret;
481 }
482
483 /**
484 * Given a list of IDs, all attachments represented by these IDs are returned.
485 * @return array post objects
486 */
487 private function getAttachmentsByIds() {
488 $args = array(
489 'post_type' => 'attachment',
490 'post_status' => 'inherit',
491 'post_per_page' => -1,
492 'post__in' => $this->atts['ids']
493 );
494
495 return count($args['post__in']) ? get_posts($args) : array();
496 }
497
498 /**
499 * Function returns false for positive ints, true otherwise.
500 * @param string $var could be anything.
501 * @return boolean indicating whether $var is not a positive int.
502 */
503 private static function negativeInt($var) {
504 return !is_numeric($var) // isn't numeric
505 || (int)$var != $var // isn't int
506 || (int)$var < 0; // isn't positive
507 }
508
509 private static function toBool($val) {
510 if (is_bool($val)) {
511 return $val;
512 }
513
514 if (is_string($val)) {
515 $val = strtolower($val);
516 if ('true' === $val || '1' === $val) {
517 return true;
518 }
519
520 if ('false' === $val || '0' === $val) {
521 return false;
522 }
523 }
524
525 if (is_null($val)) {
526 return false;
527 }
528
529 return null;
530 }
531
532 /*==========================================================================
533 * OUTPUT HTML STRING
534 *=========================================================================*/
535
536 /**
537 * Returns HTML representing this Gallery.
538 * @return string
539 */
540 public function __toString() {
541 if(!empty($this->errs)) {
542 return '<p>' . implode('</p><p>', $this->errs) . '</p>';
543 }
544
545 if(empty($this->docs)) {
546 return self::$no_docs;
547 }
548
549 $core = '';
550 $classes = array('document-icon-wrapper');
551 if($this->useDescriptions()) {
552 $classes[] = 'descriptions';
553 }
554
555 $icon_wrapper = sprintf(self::$icon_wrapper, implode(' ', $classes), '%s');
556
557 if($this->useDescriptions()) {
558 foreach($this->docs as $doc) {
559 $core .= sprintf($icon_wrapper, $doc);
560 }
561 } else {
562 for($i = 0; $i < count($this->docs); $i+=4) {
563 $row = '';
564
565 $min = min($i+4, count($this->docs));
566 for($x = $i; $x < $min; $x++) {
567 $row .= $this->docs[$x];
568 }
569
570 $core .= sprintf($icon_wrapper, $row);
571 }
572 }
573
574 return self::$comment . $core;
575 }
576 }
577
578 ?>