PluginProbe
Document Gallery / 1.4.2
Document Gallery v1.4.2
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 / models / class-gallery.php

class-gallery.php in Document Gallery 1.4.2, at models/class-gallery.php

405 lines 13.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Description of Gallery
5 *
6 * @author drossiter
7 */
8 class DG_Gallery {
9 private $atts, $taxa;
10 private $docs = array();
11 private $errs = array();
12
13 private static $defaults = array(
14 // default: link directly to file (true to link to attachment pg)
15 'attachment_pg' => FALSE,
16 'descriptions' => FALSE,
17 // include thumbnail of actual document in gallery display
18 //'fancy_thumbs' => FALSE,
19 // comma-separated list of attachment ids
20 'ids' => FALSE,
21 // if true, all images attached to current page will be included also
22 'images' => FALSE,
23 'localpost' => TRUE,
24 'order' => 'ASC',
25 'orderby' => 'menu_order',
26 // only relevant if tax_query used (WP >= 3.1)
27 'relation' => 'AND'
28 );
29
30 // templates for HTML output
31 private static $no_docs = '<!-- No attachments to display. How boring! :( -->';
32 private static $icon_wrapper = false;
33 private static $comment = false;
34
35 /**
36 * Builds a gallery object with attributes passed.
37 * @param array $atts Array of attributes used in shortcode.
38 */
39 public function __construct($atts) {
40 // init templates for HTML output
41 if(self::$comment === false)
42 {
43 self::$comment =
44 PHP_EOL . '<!-- Generated using Document Gallery. Get yours here: ' .
45 'http://wordpress.org/extend/plugins/document-gallery -->' . PHP_EOL;
46 self::$icon_wrapper = '<div class="%s">'. PHP_EOL . '%s</div>' . PHP_EOL;
47 }
48
49 // values used to construct tax query (may be empty)
50 $this->taxa = array_diff_key($atts, self::$defaults);
51
52 // all recognized attributes go here
53 $this->atts = shortcode_atts(self::$defaults, $atts);
54
55 // goes through all values in $this->atts, setting $this->errs as needed
56 $this->sanitizeDefaults();
57
58 // query DB for all documents requested
59 try {
60 $docs = $this->getDocuments();
61 include_once(DG_PATH . 'models/class-document.php');
62 foreach($docs as $doc) {
63 $this->docs[] = new DG_Document($doc, $this);
64 }
65 } catch(InvalidArgumentException $e) {
66 // errors will be printed in __toString()
67 }
68 }
69
70 /**
71 * Gets all valid Documents based on the attributes passed by the user.
72 * @return array Contains all documents matching the query.
73 * @throws InvalidArgumentException Thrown when $this->errs is not empty.
74 */
75 private function getDocuments() {
76 $mime_types = array('application', 'video', 'text', 'audio');
77 if ($this->atts['images']) {
78 $mime_types[] = 'image';
79 }
80
81 $query = array(
82 'numberposts' => -1,
83 'orderby' => $this->atts['orderby'],
84 'order' => $this->atts['order'],
85 'post_status' => 'any',
86 'post_type' => 'attachment',
87 'post_mime_type' => implode(',', $mime_types));
88
89 $query['post_parent'] =
90 $this->atts['localpost']
91 && ($post = get_post()) ? $post->ID : '';
92
93 $this->setTaxa($query);
94
95 if(!empty($this->errs)) {
96 throw new InvalidArgumentException();
97 }
98
99 return ($this->atts['ids'] !== FALSE)
100 ? $this->getAttachmentsByIds()
101 : get_posts($query);
102 }
103
104 /**
105 * Cleans up user input, making sure we don't pass crap on to WP core.
106 * @global string $wp_version
107 */
108 private function sanitizeDefaults() {
109 global $wp_version;
110
111 if($this->atts['attachment_pg'] !== self::$defaults['attachment_pg']) {
112 $attachment_pg =
113 filter_var($this->atts['attachment_pg'],
114 FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
115
116 if($attachment_pg === null) {
117 $this->errs[] =
118 'The attachment_pg parameter may only be \'true\' or \'false.\' ' .
119 "You entered {$this->atts['attachment_pg']}.";
120 } else {
121 $this->atts['attachment_pg'] = $attachment_pg;
122 }
123 }
124
125 if($this->atts['descriptions'] !== self::$defaults['descriptions']) {
126 $descriptions =
127 filter_var($this->atts['descriptions'],
128 FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
129
130 if($descriptions === null) {
131 $this->errs[] =
132 'The descriptions parameter may only be \'true\' or \'false.\' ' .
133 "You entered {$this->atts['descriptions']}.";
134 } else {
135 $this->atts['descriptions'] = $descriptions;
136 }
137 }
138
139 if($this->atts['ids'] !== self::$defaults['ids']) {
140 if(strcasecmp('false', $this->atts['ids']) == 0) {
141 $this->atts['ids'] = FALSE;
142 } else {
143 $ids = explode(',', $this->atts['ids']);
144 $bad = array_filter($ids, array(__CLASS__, 'negativeInt'));
145
146 if(!empty($bad)) {
147 $this->errs[] =
148 'The following ID(s) are not valid: ' .
149 implode(', ', $bad) . '.';
150 } else {
151 $this->atts['ids'] = $ids;
152 }
153 }
154 }
155
156 if($this->atts['images'] !== self::$defaults['images']) {
157 $images =
158 filter_var($this->atts['images'],
159 FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
160
161 if($images === null) {
162 $this->errs[] =
163 'The images parameter may only be \'true\' or \'false.\' ' .
164 "You entered {$this->atts['images']}.";
165 } else {
166 $this->atts['images'] = $images;
167 }
168 }
169
170 if($this->atts['localpost'] !== self::$defaults['localpost']) {
171 $localpost =
172 filter_var($this->atts['localpost'],
173 FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
174 if($localpost === null) {
175 $this->errs[] =
176 'The localpost parameter may only be \'true\' or \'false.\' ' .
177 "You entered {$this->atts['localpost']}.";
178 } else {
179 $this->atts['localpost'] = $localpost;
180 }
181 }
182
183 $order = strtoupper($this->atts['order']);
184 if('ASC' !== $order && 'DEC' !== $order) {
185 $this->errs[] =
186 'The order parameter must be either \'ASC\' or \'DEC.\' '.
187 "You entered {$this->atts['order']}.";
188 }
189
190 $orderby = strtoupper($this->atts['orderby']) === 'ID'
191 ? 'ID' : strtolower($this->atts['orderby']);
192 if ($orderby !== 'ID' && $orderby !== 'menu_order'
193 && $orderby !== 'author' && $orderby !== 'title'
194 && $orderby !== 'name' && $orderby !== 'date'
195 && $orderby !== 'modified' && $orderby !== 'parent'
196 && $orderby !== 'rand' /* && $orderby !== 'meta_value' */
197 // check version-specific parameters
198 && version_compare($wp_version, '2.8', '>=') && $orderby !== 'none' /* && $orderby !== 'meta_value_num' */
199 && version_compare($wp_version, '2.9', '>=') && $orderby !== 'comment_count'
200 && version_compare($wp_version, '3.5', '>=') && $orderby !== 'post__in') {
201 $this->errs[] =
202 "The orderby parameter value entered, {$this->atts['orderby']}, " .
203 "is not valid in WP $wp_version.";
204 } else {
205 $this->atts['orderby'] = $orderby;
206 }
207
208 $relation = strtoupper($this->atts['relation']);
209 if ('AND' !== $relation && 'OR' !== $relation) {
210 $this->errs[] =
211 'The relation parameter must be either \'AND\' or \'OR.\' ' .
212 "You entered {$this->atts['relation']}.";
213 } else {
214 $this->atts['relation'] = $relation;
215 }
216 }
217
218 /**
219 * Returns whether to link to attachment pg.
220 * @return bool
221 */
222 public function linkToAttachmentPg() {
223 return $this->atts['attachment_pg'];
224 }
225
226 /**
227 * Returns whether descriptions should be included in output.
228 * @return bool
229 */
230 public function useDescriptions() {
231 return $this->atts['descriptions'];
232 }
233
234 /**
235 * Function loops through all attributes passed that did not match
236 * self::$defaults. If they are the name of a taxonomy, they are plugged
237 * into the query, otherwise $this->errs is appended with an error string.
238 * @global string $wp_version Determines which tax query to use.
239 * @param array $query Query to insert tax query into.
240 */
241 private function setTaxa(&$query) {
242 if(!empty($this->taxa)) {
243 global $wp_version;
244 $taxa = array();
245
246 // use preferred tax_query if supported
247 if (version_compare($wp_version, '3.1', '>=')) {
248 // only include relation if we have multiple taxa
249 if(count($this->taxa) > 1) {
250 $taxa['relation'] = $this->atts['relation'];
251 }
252
253 foreach ($this->taxa as $taxon => $terms) {
254 $terms = $this->getTermIdsByNames($taxon, explode(',', $terms));
255
256 $taxa[] = array(
257 'taxonomy' => $taxon,
258 'field' => 'id',
259 'terms' => $terms
260 );
261 }
262
263 // create nested structure
264 $query['tax_query'] = $taxa;
265 } // fallback to deprecated {tax_name} => {term_slug} construct
266 elseif (version_compare($wp_version, '2.3', '>=')) {
267 foreach ($this->taxa as $taxon => $terms) {
268 $taxa[$taxon] = ($taxon == 'category')
269 ? implode(',', $this->getTermIdsByNames($taxon, explode(',', $terms)))
270 : implode(',', $this->getTermSlugsByNames($taxon, explode(',', $terms)));
271 }
272
273 $query = array_merge($taxa, $query);
274 } // WP < 2.3 not supported for category/custom taxa
275 else {
276 $this->errs[] = 'The following attributes are invalid: ' .
277 implode(', ', array_keys($this->taxa));
278 }
279 }
280 }
281
282
283 /**
284 * Returns an array of term ids when provided with a list of term names.
285 * Also appends an entry onto $errs if any invalid names are found.
286 * @param string $taxon
287 * @param array $term_names
288 * @param &array $errs
289 * @return array
290 */
291 private function getTermIdsByNames($taxon, $term_names) {
292 return $this->getTermXByNames('term_id', $taxon, $term_names);
293 }
294
295 /**
296 * Returns an array of term slugs when provided with a list of term names.
297 * Also appends an entry onto $errs if any invalid names are found.
298 * @param string $taxon
299 * @param array $term_names
300 * @param &array $errs
301 * @return array
302 */
303 private function getTermSlugsByNames($taxon, $term_names) {
304 return $this->getTermXByNames('slug', $taxon, $term_names);
305 }
306
307 /**
308 * (WP >= 2.3) Returns a list of x, where x may be any of the fields within a
309 * term object, when provided with a list of term names (not slugs).
310 * (http://codex.wordpress.org/Function_Reference/get_term_by#Return_Values)
311 *
312 * Also appends an entry onto $errs if any invalid names are found.
313 * @param string $x
314 * @param string $taxon
315 * @param array $term_names
316 * @param &array $errs
317 * @return array
318 */
319 private function getTermXByNames($x, $taxon, $term_names) {
320 $ret = array();
321
322 foreach ($term_names as $name) {
323 if (($term = get_term_by('name', $name, $taxon))) {
324 $ret[] = $term->{$x};
325 }
326 else {
327 $this->errs[] = "$name is not a valid term name in $taxon.";
328 }
329 }
330
331 return $ret;
332 }
333
334 /**
335 * Given a list of IDs, all attachments represented by these IDs are returned.
336 * @return array post objects
337 */
338 private function getAttachmentsByIds() {
339 $attachments = array();
340 foreach ($this->atts['ids'] as $id) {
341 $attachment = get_post($id);
342 if ($attachment->post_type === 'attachment')
343 $attachments[] = $attachment;
344 // else: not an attachment so skip
345 }
346
347 return $attachments;
348 }
349
350 /**
351 * Function returns false for positive ints, true otherwise.
352 * @param var $var could be anything.
353 * @return boolean indicating whether $var is not a positive int.
354 */
355 private static function negativeInt($var) {
356 return !is_numeric($var) // isn't numeric
357 || (int)$var != $var // isn't int
358 || (int)$var < 0; // isn't positive
359 }
360
361
362 /**
363 * Returns HTML representing this Gallery.
364 * @return string
365 */
366 public function __toString() {
367 if(!empty($this->errs)) {
368 return '<p>' . implode('</p><p>', $this->errs) . '</p>';
369 }
370
371 if(empty($this->docs)) {
372 return $this->no_docs;
373 }
374
375 $core = '';
376 $classes = array('document-icon-wrapper');
377 if($this->useDescriptions()) {
378 $classes[] = 'descriptions';
379 }
380
381 $icon_wrapper = sprintf(self::$icon_wrapper, implode(' ', $classes), '%s');
382
383 if($this->useDescriptions()) {
384 foreach($this->docs as $doc) {
385 $core .= sprintf($icon_wrapper, (string)$doc);
386 }
387 } else {
388 for($i = 0; $i < count($this->docs); $i+=4) {
389 $row = '';
390
391 $min = min($i+4, count($this->docs));
392 for($x = $i; $x < $min; $x++) {
393 $row .= (string)$this->docs[$x];
394 }
395
396 $core .= sprintf($icon_wrapper, $row);
397 }
398 }
399
400 return self::$comment . $core;
401 }
402 }
403
404 ?>
405