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 +336 -257 1.12.2.4 View file →
@@ -1,283 +1,362 @@
1 1 <?php
2 +defined('WPINC') OR exit;
3 +
2 4 /*
3 -Plugin Name: Document Gallery
4 -Description: Display non-images in gallery format on page.
5 -Version: 1.1
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__ ) );
15 +define('DG_VERSION', '2.2.4');
12 16
13 -// CREATE GALLERY STRING //
14 -function dg_get_attachment_icons($atts) {
15 - extract( shortcode_atts( array(
16 - 'descriptions' => FALSE,
17 - 'orderby' => 'menu_order',
18 - 'order' => 'ASC',
19 - 'attachment_pg' => FALSE, // default: link directly to file (true to link to attachment pg)
20 - 'ids' => FALSE // not yet supported
21 - ), $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/');
22 23
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);
23 28
24 - // Some validation of user values
25 - $errs = array();
29 +// logging functionality
30 +include_once DG_PATH . 'inc/class-logger.php';
26 31
27 - if($descriptions != FALSE){ $descriptions = 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();
28 38
29 - $order = strtoupper( $order );
30 - if($order != 'ASC' && $order != 'DEC')
31 - $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 +}
32 43
33 - if($attachment_pg != FALSE){ $attachment_pg = TRUE; }
34 - if($ids != FALSE){ $ids = FALSE; } // not yet supported
44 +// I18n
45 +add_action('plugins_loaded', array('DocumentGallery', 'loadTextDomain'));
35 46
36 - // http://www.youtube.com/watch?v=ClnSMCdw6E8
37 - if( $errs ) return implode(' ', $errs);
38 - // All's well. Carry on, my wayward son.
39 -
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'));
40 50
41 - $args = array(
42 - 'numberposts' => -1,
43 - 'orderby' => $orderby,
44 - 'order' => $order,
45 - 'post_type' => 'attachment',
46 - 'post_mime_type' => 'application,video,text,audio',
47 - 'post_parent' => get_the_ID() );
48 -
49 - if ( $attachments = get_posts($args) ) {
50 - $attachment_str = array( PHP_EOL.'<!-- Generated using Document Gallery. Get yours here: '.
51 - 'http://wordpress.org/extend/plugins/document-gallery -->'.PHP_EOL );
51 +if (is_admin()) {
52 + // admin house keeping
53 + include_once DG_PATH . 'admin/class-admin.php';
52 54
53 - $count = 0;
54 - foreach( $attachments as $attachment ) { //setup array for more than one file attachment
55 - $url = $attachment->guid;
56 - $filename = basename( $url );
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 +}
57 73
58 - if( $attachment_pg ) // link to attachment page
59 - $url = get_attachment_link( $attachment->ID );
74 +// adds 'dg' shortcode
75 +add_shortcode('dg', array('DocumentGallery', 'doShortcode'));
60 76
61 - $title = get_the_title( $attachment->ID );
62 - $icon = dg_get_attachment_image( $attachment->ID, $title, $filename );
63 -
64 - if($descriptions) { // start wrapper
65 - $attachment_str[] = '<div class="document-icon-wrapper descriptions">'.PHP_EOL.
66 - ' <div class="document-icon">'.PHP_EOL;
67 - } else { // no description
68 - if( $count % 4 == 0 ) { // start wrapper
69 - $attachment_str[] = '<div id="document-icon-wrapper">'.PHP_EOL;
70 - }
71 - $attachment_str[] = ' <div class="document-icon">'.PHP_EOL;
72 - }
77 +/**
78 + * DocumentGallery wraps basic functionality to setup the plugin.
79 + *
80 + * @author drossiter
81 + */
82 +class DocumentGallery {
73 83
74 - $attachment_str[] = " <a href=\"$url\">$icon<br>$title</a>".PHP_EOL;
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';
75 88
76 - if($descriptions) { // end icon & add description
77 - $attachment_str[] = ' </div>'.PHP_EOL.
78 - " <p>$attachment->post_content</p>".
79 - PHP_EOL.'</div>'.PHP_EOL;
80 - } else { // end icon
81 - $attachment_str[] = ' </div>'.PHP_EOL;
82 - if( ++$count % 4 == 0 ) { // end wrapper
83 - $attachment_str[] = '</div>'.PHP_EOL;
84 - }
85 - }
86 - } // end looping attachments
89 + /*==========================================================================
90 + * THE SHORTCODE
91 + *=========================================================================*/
87 92
88 - // for galleries w/ number of docs != mult of 4
89 - if( $count % 4 != 0 && !$descriptions ){ // end wrapper
90 - $attachment_str[] = '</div>'.PHP_EOL;
91 - }
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';
92 102
93 - // join array & return
94 - return implode( '', $attachment_str );
95 - } // end if attachments
96 -
97 - return PHP_EOL.'<!-- Document Gallery: No attachments to display. -->'.PHP_EOL;
98 -}
99 -add_shortcode('dg', 'dg_get_attachment_icons');
100 -// Depreciated as of v1.0. left for backward compatibility
101 -add_shortcode('document gallery', 'dg_get_attachment_icons');
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');
102 106
107 + return $gallery;
108 + }
103 109
104 -// ADD SOME STYLING //
105 -function dg_add_header_css() {
106 - wp_enqueue_style( 'document-gallery-css', plugins_url('style.css', __FILE__) );
107 -}
108 -add_action( 'wp_print_styles', 'dg_add_header_css');
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 + }
109 116
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 + }
110 126
111 -// HELPERS //
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 + }
112 137
113 -// pass in $title & $url to avoid mult function calls
114 -function dg_get_attachment_image( $id, $title, $filename ) {
115 - $filetype = wp_check_filetype( $filename );
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 + }
116 157
117 - // identify extension
118 - switch( $filetype['ext'] ) {
119 - // Most Common First
120 - case 'pdf':
121 - $icon = 'pdf.png';
122 - break;
123 - // MS Office
124 - case 'doc':
125 - case 'docx':
126 - case 'docm':
127 - case 'dotx':
128 - case 'dotm':
129 - $icon = 'msdoc.png';
130 - break;
131 - case 'ppt':
132 - case 'pot':
133 - case 'pps':
134 - case 'pptx':
135 - case 'pptm':
136 - case 'ppsx':
137 - case 'ppsm':
138 - case 'potx':
139 - case 'potm':
140 - case 'ppam':
141 - case 'sldx':
142 - case 'sldm':
143 - $icon = 'msppt.png';
144 - break;
145 - case 'xla':
146 - case 'xls':
147 - case 'xlt':
148 - case 'xlw':
149 - case 'xlsx':
150 - case 'xlsm':
151 - case 'xlsb':
152 - case 'xltx':
153 - case 'xltm':
154 - case 'xlam':
155 - $icon = 'msxls.png';
156 - break;
157 - case 'mdb':
158 - $icon = 'msaccess.png';
159 - break;
160 - // Video formats
161 - case 'avi':
162 - $icon = 'avi.png';
163 - break;
164 - case 'divx':
165 - $icon = 'divx.png';
166 - break;
167 - case 'flv':
168 - $icon = 'flv.png';
169 - break;
170 - case 'qt':
171 - case 'mov':
172 - $icon = 'mov.png';
173 - break;
174 - case 'asf':
175 - case 'asx':
176 - case 'wax':
177 - case 'wmv':
178 - case 'wmx':
179 - $icon = 'wmv.png';
180 - break;
181 - case 'mkv':
182 - $icon = 'mkv.png';
183 - break;
184 - // Audio formats
185 - case 'mp3':
186 - $icon = 'mp3.png';
187 - break;
188 - case 'wav':
189 - $icon = 'wav.png';
190 - break;
191 - case 'ogg':
192 - case 'oga':
193 - $icon = 'ogg.png';
194 - break;
195 - case 'midi':
196 - case 'mid':
197 - $icon = 'midi.png';
198 - break;
199 - case 'wma':
200 - $icon = 'wma.png';
201 - break;
202 - // Text formats
203 - case 'rtx':
204 - $icon = 'rtx.png';
205 - break;
206 - case 'ics':
207 - $icon = 'ics.png';
208 - break;
209 - case 'csv':
210 - $icon = 'csv.png';
211 - break;
212 - // Msc application formats
213 - case 'html':
214 - case 'htm': // death to all who use this!
215 - $icon = 'html.png';
216 - break;
217 - case 'css':
218 - $icon = 'css.png';
219 - break;
220 - case 'js':
221 - $icon = 'javascript.png';
222 - break;
223 - case 'class':
224 - $icon = 'java.png';
225 - break;
226 - case 'zip':
227 - $icon = 'zip.png';
228 - break;
229 - case 'tar':
230 - case 'gzip':
231 - case 'gz':
232 - case 'bz2': // not yet WP-supported
233 - case 'tgz': // not yet WP-supported
234 - $icon = 'compressed.png';
235 - break;
236 - case 'rar': // RAWR!!!
237 - $icon = 'rar.png';
238 - break;
239 - case '7z':
240 - $icon = '7zip.png';
241 - break;
242 - case 'exec':
243 - $icon = 'exec.png';
244 - break;
245 - case 'rtf':
246 - $icon = 'rtf.png';
247 - break;
248 - case 'swf':
249 - $icon = 'shockwave.png';
250 - break;
251 - // OpenOffice formats
252 - case 'odt':
253 - $icon = 'opendocument-text.png';
254 - break;
255 - case 'odp':
256 - $icon = 'opendocument-presentation.png';
257 - break;
258 - case 'ods':
259 - $icon = 'opendocument-spreadsheet.png';
260 - break;
261 - case 'odg':
262 - $icon = 'opendocument-graphics.png';
263 - break;
264 - case 'odb':
265 - $icon = 'opendocument-database.png';
266 - break;
267 - case 'odf':
268 - $icon = 'opendocument-formula.png';
269 - break;
270 - // fallback to default icons if not recognized
271 - default:
272 - // get_attachment_icon is DEPRECIATED! (replaced in v1.1)
273 - return wp_get_attachment_image( $id, null, true );
274 - }
158 + /*==========================================================================
159 + * I18n
160 + *=========================================================================*/
275 161
276 - return '<img src="'.DG_URL.'icons/'.$icon."\" title=\"$title\" alt=\"$title\"/>";
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 + }
168 +
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;
310 +
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;
349 +
350 + $css = preg_replace("%$re1%", '$1', $css);
351 + return preg_replace("%$re2%", '$1$2$3$4$5$6$7', $css);
352 + }
353 +
354 + /**
355 + * Blocks instantiation. All functions are static.
356 + */
357 + private function __construct() {
358 +
359 + }
277 360 }
278 -// Filtering attachment_icon was considered, then dismissed in v1.0.3 because it would mean almost
279 -// doubling the amount of processing for each icon. The native WP function would create the icon,
280 -// then 99% of the time this function would replace it. Better to just call the native WP function
281 -// at the end when needed. Filter would look like this:
282 -// add_filter( 'attachment_icon', 'dg_get_attachment_icon', 10, 2 );v
283 -?>
361 +
362 +?>