PluginProbe
Document Gallery / 2.2.4
Document Gallery v2.2.4
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
← All changes | document-gallery.php +330 -288 1.32.2.4 View file →
@@ -1,320 +1,362 @@
1 1 <?php
2 +defined('WPINC') OR exit;
3 +
2 4 /*
3 -Plugin Name: Document Gallery
4 -Description: Display non-images (and images) in gallery format on a page or post with the [dg] shortcode.
5 -Version: 1.3
6 -Author: Dan Rossiter
7 -Author URI: http://danrossiter.org/
8 -License: GPL2
9 -*/
5 + Plugin Name: Document Gallery
6 + Plugin URI: http://wordpress.org/extend/plugins/document-gallery/
7 + Description: Display non-images (and images) in gallery format on a page or post with the [dg] shortcode.
8 + Version: 2.2.4
9 + Author: Dan Rossiter
10 + Author URI: http://danrossiter.org/
11 + License: GPLv2
12 + Text Domain: document-gallery
13 + */
10 14
11 -define( 'DG_URL', plugin_dir_url( __FILE__ ) );
12 -define( 'DG_IMG_STRING', '<img src="%s" title="%s" alt="%s" />' );
13 -define( 'DG_DOC_ICON',
14 - ' <div class="document-icon">'.PHP_EOL.
15 - ' <a href="%s">%s<br>%s</a>'.PHP_EOL.
16 - ' </div>'.PHP_EOL );
15 +define('DG_VERSION', '2.2.4');
17 16
18 -// CREATE GALLERY STRING //
19 -function dg_get_attachment_icons($atts) {
20 - extract( shortcode_atts( array(
21 - 'descriptions' => FALSE,
22 - 'orderby' => 'menu_order',
23 - 'order' => 'ASC',
24 - 'attachment_pg' => FALSE, // default: link directly to file (true to link to attachment pg)
25 - 'images' => FALSE, // if enabled, all images attached to current page will be included also
26 - 'ids' => FALSE // comma-separated list of attachment ids
27 - ), $atts) );
17 +// define helper paths & URLs
18 +define('DG_BASENAME', plugin_basename(__FILE__));
19 +define('DG_URL', plugin_dir_url(__FILE__));
20 +define('DG_PATH', plugin_dir_path(__FILE__));
21 +define('DG_WPINC_PATH', ABSPATH . WPINC . '/');
22 +define('DG_WPADMIN_PATH', ABSPATH . 'wp-admin/');
28 23
29 - // INIT
30 - $attachments = array();
31 - $count = 0;
32 - $errs = array();
24 +// init DG options for use throughout plugin
25 +global $dg_options;
26 +define('DG_OPTION_NAME', 'document_gallery');
27 +$dg_options = get_option(DG_OPTION_NAME, null);
33 28
29 +// logging functionality
30 +include_once DG_PATH . 'inc/class-logger.php';
34 31
35 - // ATTRIBUTE VALIDATION
36 - $descriptions = strtolower($descriptions) == "false" ? FALSE : TRUE;
32 +// handle activation, updates, and uninstallation
33 +include_once DG_PATH . 'inc/class-setup.php';
34 +register_activation_hook(__FILE__, array('DG_Setup', 'activate'));
35 +add_action('wpmu_new_blog', array('DG_Setup','activateNewBlog'));
36 +register_uninstall_hook(__FILE__, array('DG_Setup', 'uninstall'));
37 +DG_Setup::maybeUpdate();
37 38
38 - $order = strtoupper( $order );
39 - if($order != 'ASC' && $order != 'DEC')
40 - $errs[] = "The order attribute must be either ASC or DEC. You entered $order.";
39 +// validate options if desired
40 +if ($dg_options['validation']) {
41 + add_action('init', array('DocumentGallery', 'addValidation'));
42 +}
41 43
42 - $attachment_pg = strtolower($attachment_pg) == "false" ? FALSE : TRUE;
44 +// I18n
45 +add_action('plugins_loaded', array('DocumentGallery', 'loadTextDomain'));
43 46
44 - $images = strtolower($images) == "false" ? FALSE : TRUE;
47 +// cleanup cached data when thumbed attachment deleted
48 +include_once DG_PATH . 'inc/class-thumber.php';
49 +add_action('delete_attachment', array('DG_Thumber', 'deleteThumbMeta'));
45 50
46 - if( strtolower($ids) == "false" ){ $ids = FALSE; }
51 +if (is_admin()) {
52 + // admin house keeping
53 + include_once DG_PATH . 'admin/class-admin.php';
47 54
48 - // http://www.youtube.com/watch?v=ClnSMCdw6E8
49 - if( $errs ) return implode(' ', $errs);
50 - // END VALIDATION (WE MADE IT!)
55 + // add settings link
56 + add_filter('plugin_action_links_' . DG_BASENAME, array('DG_Admin', 'addSettingsLink'));
57 +
58 + // build options page
59 + add_action('admin_menu', array('DG_Admin', 'addAdminPage'));
60 + if (DG_Admin::doRegisterSettings()) {
61 + add_action('admin_init', array('DG_Admin', 'registerSettings'));
62 + }
63 +} else {
64 + // styling for gallery
65 + if (empty($dg_options['css']['text'])) {
66 + add_action('wp_enqueue_scripts', array('DocumentGallery', 'enqueueGalleryStyle'));
67 + } else {
68 + add_action('template_redirect', array('DocumentGallery', 'buildCustomCss'));
69 + add_action('wp_enqueue_scripts', array('DocumentGallery', 'enqueueCustomStyle'));
70 + add_filter('query_vars', array('DocumentGallery', 'addCustomStyleQueryVar'));
71 + }
72 +}
51 73
74 +// adds 'dg' shortcode
75 +add_shortcode('dg', array('DocumentGallery', 'doShortcode'));
52 76
53 - // LET'S GET SOME DOCUMENTS!
54 - if( $ids && ( $ids = explode( ',', $ids ) ) )
55 - $attachments = dg_get_attachments_by_ids( $ids );
77 +/**
78 + * DocumentGallery wraps basic functionality to setup the plugin.
79 + *
80 + * @author drossiter
81 + */
82 +class DocumentGallery {
56 83
57 - // if 'ids' was used, skip this
58 - if( !$attachments ){
59 - $args = array(
60 - 'numberposts' => -1,
61 - 'orderby' => $orderby,
62 - 'order' => $order,
63 - 'post_type' => 'attachment',
64 - 'post_mime_type' => 'application,video,text,audio',
65 - 'post_parent' => get_the_ID() );
66 - if( $images ) $args['post_mime_type'] .= ',image';
84 + /**
85 + * @var str Name of the query var used to check whether we should print custom CSS.
86 + */
87 + private static $query_var = 'document-gallery-css';
67 88
68 - $attachments = get_posts($args);
69 - }
70 -
71 - if ( $attachments ) {
72 - $attachment_str = PHP_EOL.'<!-- Generated using Document Gallery. Get yours here: '.
73 - 'http://wordpress.org/extend/plugins/document-gallery -->'.PHP_EOL;
89 + /*==========================================================================
90 + * THE SHORTCODE
91 + *=========================================================================*/
74 92
75 - // DOCUMENT LOOP
76 - foreach( $attachments as $attachment ) {
77 - // INIT ATTACHMENT-SPECIFIC VARS
78 - $url = $attachment->guid;
79 - $filename = basename( $url );
93 + /**
94 + * Takes values passed from attributes and returns sutable HTML to represent
95 + * all valid attachments requested.
96 + *
97 + * @param multitype:string $atts Arguments from the user.
98 + * @return string HTML for the Document Gallery.
99 + */
100 + public static function doShortcode($atts) {
101 + include_once 'inc/class-gallery.php';
80 102
81 - if( $attachment_pg ) // link to attachment page
82 - $url = get_attachment_link( $attachment->ID );
103 + $start = microtime(true);
104 + $gallery = (string)new DG_Gallery($atts);
105 + DG_Logger::writeLog(DG_LogLevel::Detail, 'Generation Time: ' . sprintf('%.2f', (microtime(true) - $start)) . ' s');
83 106
84 - $title = get_the_title( $attachment->ID );
85 - $icon = dg_get_attachment_image( $attachment->ID, $title, $filename );
107 + return $gallery;
108 + }
86 109
87 - // GENERATE OUTPUT
88 - if($descriptions) { // start description wrapper
89 - $attachment_str .= '<div class="document-icon-wrapper descriptions">'.PHP_EOL;
110 + /**
111 + * Enqueue standard DG CSS.
112 + */
113 + public static function enqueueGalleryStyle() {
114 + wp_enqueue_style('document-gallery', DG_URL . 'assets/css/style.css', null, DG_VERSION);
115 + }
90 116
91 - } elseif( $count % 4 == 0 ) { // no description
92 - $attachment_str .= '<div id="document-icon-wrapper">'.PHP_EOL;
93 - }
117 + /**
118 + * Enqueue user's custom DG CSS.
119 + */
120 + public static function enqueueCustomStyle() {
121 + global $dg_options;
122 + wp_register_style('document-gallery', add_query_arg(self::$query_var, 1, home_url('/')),
123 + null, DG_VERSION . ':' . $dg_options['css']['version']);
124 + wp_enqueue_style('document-gallery');
125 + }
94 126
95 - // insert filtered document-icon
96 - $attachment_str .= apply_filters( 'dg_doc_icon',
97 - sprintf( DG_DOC_ICON, $url, $icon, $title ), $attachment->ID );
127 + /**
128 + * Add query custom CSS query string.
129 + * Taken from here: http://ottopress.com/2010/dont-include-wp-load-please/
130 + * @param multitype:string $vars Variables to be added.
131 + * @return multitype:string All variables to be included in query string.
132 + */
133 + public static function addCustomStyleQueryVar($vars) {
134 + $vars[] = self::$query_var;
135 + return $vars;
136 + }
98 137
99 - if($descriptions) { // add description
100 - $attachment_str .= " <p>$attachment->post_content</p>".
101 - PHP_EOL.'</div>'.PHP_EOL;
138 + /**
139 + * Constructs user's custom CSS dynamically, then instructs
140 + * browser to cache for a year. Cache is busted by versioning
141 + * CSS any time the user makes a change.
142 + */
143 + public static function buildCustomCss() {
144 + if (1 == intval(get_query_var(self::$query_var))) {
145 + global $dg_options;
146 +
147 + header('Content-type: text/css');
148 + header('Cache-Control: no-transform,public,maxage=' . 31536000);
149 + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT');
150 + header('Last-Modified: ' . $dg_options['css']['last-modified']);
151 + header('ETag: ' . $dg_options['css']['etag']);
152 +
153 + echo $dg_options['css']['minified'];
154 + exit;
155 + }
156 + }
102 157
103 - } elseif( ++$count % 4 == 0 ) { // end wrapper
104 - $attachment_str .= '</div>'.PHP_EOL;
105 - }
106 - } // END DOCUMENT LOOP
158 + /*==========================================================================
159 + * I18n
160 + *=========================================================================*/
107 161
108 - // for galleries w/ number of docs != mult of 4
109 - if( $count % 4 != 0 && !$descriptions ) // end wrapper
110 - $attachment_str .= '</div>'.PHP_EOL;
162 + /**
163 + * Loads language files into WP core.
164 + */
165 + public static function loadTextDomain() {
166 + load_plugin_textdomain('document-gallery', false, dirname(DG_BASENAME) . '/languages/');
167 + }
111 168
112 - return $attachment_str;
113 - } // END IF
169 + /*==========================================================================
170 + * HELPER FUNCTIONS
171 + *=========================================================================*/
172 +
173 + /**
174 + * @param int $blog ID of the blog to be retrieved in multisite env.
175 + * @return multitype:unknown Options for the blog.
176 + */
177 + public static function getOptions($blog = null) {
178 + global $dg_options;
179 + return is_null($blog)
180 + ? $dg_options
181 + : get_blog_option($blog, DG_OPTION_NAME, null);
182 + }
183 +
184 + /**
185 + * @param multitype:unknown $options
186 + * @param int $blog ID of the blog to be set in multisite env.
187 + */
188 + public static function setOptions($options, $blog = null) {
189 + if (is_null($blog)) {
190 + global $dg_options;
191 + update_option(DG_OPTION_NAME, $options);
192 + $dg_options = $options;
193 + } else {
194 + update_blog_option($blog, DG_OPTION_NAME, $options);
195 + }
196 + }
197 +
198 + /**
199 + * @param int $blog ID of the blog to be deleted in multisite env.
200 + */
201 + public static function deleteOptions($blog = null) {
202 + if (is_null($blog)) {
203 + delete_option(DG_OPTION_NAME);
204 + } else {
205 + delete_blog_option($blog, DG_OPTION_NAME);
206 + }
207 + }
208 +
209 + /**
210 + * Adds hook to validate DG options every time save is attempted.
211 + */
212 + public static function addValidation() {
213 + add_filter('pre_update_option_' . DG_OPTION_NAME, array('DocumentGallery', 'validateOptionsStructure'), 10, 2);
214 + }
215 +
216 + /**
217 + * Checks whether the given options match the option schema.
218 + * @param multivar $new The new options to be validated.
219 + * @param multivar $old The old options.
220 + * @return array The options to be saved.
221 + */
222 + public static function validateOptionsStructure($new, $old) {
223 + if (self::isValidOptionsStructure($new)) {
224 + $ret = $new;
225 + } else {
226 + $ret = $old;
227 + DG_Logger::writeLog(DG_LogLevel::Error, 'Attempted to save invalid options.' . PHP_EOL . print_r($new, true), true, true);
228 + }
229 +
230 + return $ret;
231 + }
232 +
233 + /**
234 + * @param multivar|unknown $o The options structure to validate.
235 + * @param multivar $schema The schema to validate against (note that only keys matter -- non-array values are ignored).
236 + * @return bool Whether the given options structure matches the schema.
237 + */
238 + private static function isValidOptionsStructure($o, $schema = null) {
239 + if (is_null($schema)) {
240 + include_once DG_PATH . 'inc/class-setup.php';
241 + $schema = DG_Setup::getDefaultOptions(true);
242 + }
243 +
244 + // simple checks first
245 + $valid = is_array($o) && (count($schema) === count($o));
246 +
247 + if ($valid) {
248 + foreach ($schema as $sk => $sv) {
249 + $valid = array_key_exists($sk, $o);
250 + if (is_array($sv) && !empty($sv)) {
251 + $valid = $valid && self::isValidOptionsStructure($o[$sk], $sv);
252 + }
253 +
254 + if (!$valid) {
255 + break;
256 + }
257 + }
258 + }
259 +
260 + return $valid;
261 + }
262 +
263 + /**
264 + * Function takes a GMT timestamp and returns a date/time string in the
265 + * current timezone and WP format.
266 + * @param int $timestamp The GMT timestamp to translate.
267 + * @return string The local time in the WP date/time format.
268 + */
269 + public static function localDateTimeFromTimestamp($timestamp) {
270 + static $gmt_offet = null;
271 + static $wp_format = null;
272 + if (is_null($gmt_offet)) {
273 + $gmt_offet = get_option('gmt_offset');
274 + $wp_format = get_option('date_format').' '.get_option('time_format');
275 + }
276 +
277 + return date($wp_format, $timestamp + $gmt_offet * 3600);
278 + }
279 +
280 + /**
281 + * Compiles any custom CSS plus the default CSS together,
282 + * minifying in the process.
283 + * @param string $custom The custom CSS to compile.
284 + * @return string Compiled CSS, including both standard and any custom.
285 + */
286 + public static function compileCustomCss($custom) {
287 + $css = file_get_contents(DG_PATH . 'assets/css/style.css');
288 + $css .= str_replace('&gt;', '>', esc_html($custom));
289 +
290 + return $css;
291 + }
292 +
293 + /**
294 + * Removes all comments & space from CSS string.
295 + * Source: http://stackoverflow.com/a/15195752/866618
296 + */
297 + private static function minifyCss($css) {
298 + # remove comments first (simplifies the other regex)
299 + $re1 = <<<EOS
300 +(?sx)
301 + # quotes
302 + (
303 + "(?:[^"\\]++|\\.)*+"
304 + | '(?:[^'\\]++|\\.)*+'
305 + )
306 +|
307 + # comments
308 + /\* (?> .*? \*/ )
309 +EOS;
114 310
115 - // NO DOCUMENTS
116 - return PHP_EOL.'<!-- Document Gallery: No attachments to display. How boring... -->'.PHP_EOL;
117 -}
118 -add_shortcode('dg', 'dg_get_attachment_icons');
311 + $re2 = <<<EOS
312 +(?six)
313 + # quotes
314 + (
315 + "(?:[^"\\]++|\\.)*+"
316 + | '(?:[^'\\]++|\\.)*+'
317 + )
318 +|
319 + # ; before } (and the spaces after it while we're here)
320 + \s*+ ; \s*+ ( } ) \s*+
321 +|
322 + # all spaces around meta chars/operators
323 + \s*+ ( [*$~^|]?+= | [{};,>~+-] | !important\b ) \s*+
324 +|
325 + # spaces right of ( [ :
326 + ( [[(:] ) \s++
327 +|
328 + # spaces left of ) ]
329 + \s++ ( [])] )
330 +|
331 + # spaces left (and right) of :
332 + \s++ ( : ) \s*+
333 + # but not in selectors: not followed by a {
334 + (?!
335 + (?>
336 + [^{}"']++
337 + | "(?:[^"\\]++|\\.)*+"
338 + | '(?:[^'\\]++|\\.)*+'
339 + )*+
340 + {
341 + )
342 +|
343 + # spaces at beginning/end of string
344 + ^ \s++ | \s++ \z
345 +|
346 + # double spaces to single
347 + (\s)\s+
348 +EOS;
119 349
120 -// 'document gallery' shortcode depreciated as of v1.0. left for backward compatibility
121 -add_shortcode('document gallery', 'dg_get_attachment_icons');
350 + $css = preg_replace("%$re1%", '$1', $css);
351 + return preg_replace("%$re2%", '$1$2$3$4$5$6$7', $css);
352 + }
122 353
354 + /**
355 + * Blocks instantiation. All functions are static.
356 + */
357 + private function __construct() {
123 358
124 -// HELPERS //
125 -function dg_get_attachments_by_ids( $ids ){
126 - $attachments = array();
127 - foreach( $ids as $id ){
128 - $attachment = get_post( $id );
129 - if( $attachment->post_type == 'attachment' )
130 - $attachments[] = $attachment;
131 - // else: not an attachment so skip
132 - }
133 - return $attachments;
359 + }
134 360 }
135 361
136 -// pass in $title & $filename to avoid mult function calls
137 -function dg_get_attachment_image( $id, $title, $filename ) {
138 - $filetype = wp_check_filetype( $filename );
139 -
140 - // identify extension
141 - switch( $filetype['ext'] ) {
142 - // Most Common First
143 - case 'pdf':
144 - $icon = DG_URL.'icons/pdf.png';
145 - break;
146 - // MS Office
147 - case 'doc':
148 - case 'docx':
149 - case 'docm':
150 - case 'dotx':
151 - case 'dotm':
152 - $icon = DG_URL.'icons/msdoc.png';
153 - break;
154 - case 'ppt':
155 - case 'pot':
156 - case 'pps':
157 - case 'pptx':
158 - case 'pptm':
159 - case 'ppsx':
160 - case 'ppsm':
161 - case 'potx':
162 - case 'potm':
163 - case 'ppam':
164 - case 'sldx':
165 - case 'sldm':
166 - $icon = DG_URL.'icons/msppt.png';
167 - break;
168 - case 'xla':
169 - case 'xls':
170 - case 'xlt':
171 - case 'xlw':
172 - case 'xlsx':
173 - case 'xlsm':
174 - case 'xlsb':
175 - case 'xltx':
176 - case 'xltm':
177 - case 'xlam':
178 - $icon = DG_URL.'icons/msxls.png';
179 - break;
180 - case 'mdb':
181 - $icon = DG_URL.'icons/msaccess.png';
182 - break;
183 - // Video formats
184 - case 'avi':
185 - $icon = DG_URL.'icons/avi.png';
186 - break;
187 - case 'divx':
188 - $icon = DG_URL.'icons/divx.png';
189 - break;
190 - case 'flv':
191 - $icon = DG_URL.'icons/flv.png';
192 - break;
193 - case 'qt':
194 - case 'mov':
195 - $icon = DG_URL.'icons/mov.png';
196 - break;
197 - case 'asf':
198 - case 'asx':
199 - case 'wax':
200 - case 'wmv':
201 - case 'wmx':
202 - $icon = DG_URL.'icons/wmv.png';
203 - break;
204 - case 'mkv':
205 - $icon = DG_URL.'icons/mkv.png';
206 - break;
207 - // Audio formats
208 - case 'mp3':
209 - $icon = DG_URL.'icons/mp3.png';
210 - break;
211 - case 'wav':
212 - $icon = DG_URL.'icons/wav.png';
213 - break;
214 - case 'ogg':
215 - case 'oga':
216 - $icon = DG_URL.'icons/ogg.png';
217 - break;
218 - case 'midi':
219 - case 'mid':
220 - $icon = DG_URL.'icons/midi.png';
221 - break;
222 - case 'wma':
223 - $icon = DG_URL.'icons/wma.png';
224 - break;
225 - // Text formats
226 - case 'rtx':
227 - $icon = DG_URL.'icons/rtx.png';
228 - break;
229 - case 'ics':
230 - $icon = DG_URL.'icons/ics.png';
231 - break;
232 - case 'csv':
233 - $icon = DG_URL.'icons/csv.png';
234 - break;
235 - // Msc application formats
236 - case 'html':
237 - case 'htm': // death to all who use this!
238 - $icon = DG_URL.'icons/html.png';
239 - break;
240 - case 'css':
241 - $icon = DG_URL.'icons/css.png';
242 - break;
243 - case 'js':
244 - $icon = DG_URL.'icons/javascript.png';
245 - break;
246 - case 'class':
247 - $icon = DG_URL.'icons/java.png';
248 - break;
249 - case 'zip':
250 - $icon = DG_URL.'icons/zip.png';
251 - break;
252 - case 'tar':
253 - case 'gzip':
254 - case 'gz':
255 - case 'bz2': // not yet WP-supported
256 - case 'tgz': // not yet WP-supported
257 - $icon = DG_URL.'icons/compressed.png';
258 - break;
259 - case 'rar': // RAWR!!!
260 - $icon = DG_URL.'icons/rar.png';
261 - break;
262 - case '7z':
263 - $icon = DG_URL.'icons/7zip.png';
264 - break;
265 - case 'exec':
266 - $icon = DG_URL.'icons/exec.png';
267 - break;
268 - case 'rtf':
269 - $icon = DG_URL.'icons/rtf.png';
270 - break;
271 - case 'swf':
272 - $icon = DG_URL.'icons/shockwave.png';
273 - break;
274 - // OpenOffice formats
275 - case 'odt':
276 - $icon = DG_URL.'icons/opendocument-text.png';
277 - break;
278 - case 'odp':
279 - $icon = DG_URL.'icons/opendocument-presentation.png';
280 - break;
281 - case 'ods':
282 - $icon = DG_URL.'icons/opendocument-spreadsheet.png';
283 - break;
284 - case 'odg':
285 - $icon = DG_URL.'icons/opendocument-graphics.png';
286 - break;
287 - case 'odb':
288 - $icon = DG_URL.'icons/opendocument-database.png';
289 - break;
290 - case 'odf':
291 - $icon = DG_URL.'icons/opendocument-formula.png';
292 - break;
293 - default:
294 - // handle images
295 - if( strpos( $filetype['type'], 'image' ) === 0 &&
296 - ( $icon = wp_get_attachment_image_src( $id, 'thumbnail', false ) ) ){
297 - $icon = $icon[0];
298 - break;
299 - }
300 -
301 - // fallback to default icons if not recognized
302 - if( $icon = wp_get_attachment_image_src( $id, null, true ) ){
303 - $icon = $icon[0];
304 - break;
305 - }
306 -
307 - // everything failed. This is bad...
308 - return "<!-- Failed to retrive icon for attachment #$id -->";
309 - }
310 -
311 - return sprintf( DG_IMG_STRING, $icon, $title, $title );
312 -}
313 -
314 -// ADD SOME STYLING
315 -function dg_add_header_css() {
316 - wp_enqueue_style( 'document-gallery-css', plugins_url('style.css', __FILE__) );
317 -}
318 -add_action( 'wp_print_styles', 'dg_add_header_css');
319 -
320 -?>
362 +?>