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
← All changes | document-gallery.php +260 -48 2.02.2.6 View file →
@@ -2,10 +2,11 @@
2 2 defined('WPINC') OR exit;
3 3
4 4 /*
5 5 Plugin Name: Document Gallery
6 + Plugin URI: http://wordpress.org/extend/plugins/document-gallery/
6 7 Description: Display non-images (and images) in gallery format on a page or post with the [dg] shortcode.
7 - Version: 2.0
8 + Version: 2.2.6
8 9 Author: Dan Rossiter
9 10 Author URI: http://danrossiter.org/
10 11 License: GPLv2
11 12 Text Domain: document-gallery
@@ -10,28 +11,37 @@
10 11 License: GPLv2
11 12 Text Domain: document-gallery
12 13 */
13 14
15 +define('DG_VERSION', '2.2.6');
16 +
14 17 // define helper paths & URLs
18 +define('DG_BASENAME', plugin_basename(__FILE__));
15 19 define('DG_URL', plugin_dir_url(__FILE__));
16 20 define('DG_PATH', plugin_dir_path(__FILE__));
17 -if(!defined('WP_INCLUDE_DIR')) {
18 - define('WP_INCLUDE_DIR', preg_replace('/wp-content$/', 'wp-includes', WP_CONTENT_DIR));
19 -}
20 -if(!defined('WP_ADMIN_DIR')) {
21 - define('WP_ADMIN_DIR', preg_replace('/wp-content$/', 'wp-admin', WP_CONTENT_DIR));
22 -}
21 +define('DG_WPINC_PATH', ABSPATH . WPINC . '/');
22 +define('DG_WPADMIN_PATH', ABSPATH . 'wp-admin/');
23 23
24 24 // init DG options for use throughout plugin
25 25 global $dg_options;
26 26 define('DG_OPTION_NAME', 'document_gallery');
27 -$dg_options = get_option(DG_OPTION_NAME);
27 +$dg_options = get_option(DG_OPTION_NAME, null);
28 28
29 -// handle activation and uninstallation
29 +// logging functionality
30 +include_once DG_PATH . 'inc/class-logger.php';
31 +
32 +// handle activation, updates, and uninstallation
30 33 include_once DG_PATH . 'inc/class-setup.php';
31 -register_activation_hook(__FILE__, array('DG_Setup', 'activation'));
34 +register_activation_hook(__FILE__, array('DG_Setup', 'activate'));
35 +add_action('wpmu_new_blog', array('DG_Setup','activateNewBlog'));
32 36 register_uninstall_hook(__FILE__, array('DG_Setup', 'uninstall'));
37 +DG_Setup::maybeUpdate();
33 38
39 +// validate options if desired
40 +if ($dg_options['validation']) {
41 + add_action('init', array('DocumentGallery', 'addValidation'));
42 +}
43 +
34 44 // I18n
35 45 add_action('plugins_loaded', array('DocumentGallery', 'loadTextDomain'));
36 46
37 47 // cleanup cached data when thumbed attachment deleted
@@ -42,22 +52,24 @@
42 52 // admin house keeping
43 53 include_once DG_PATH . 'admin/class-admin.php';
44 54
45 55 // add settings link
46 - add_filter('plugin_action_links_' . plugin_basename(__FILE__),
47 - array('DG_Admin', 'addSettingsLink'));
48 -
56 + add_filter('plugin_action_links_' . DG_BASENAME, array('DG_Admin', 'addSettingsLink'));
57 +
49 58 // build options page
50 59 add_action('admin_menu', array('DG_Admin', 'addAdminPage'));
51 - if (!empty($GLOBALS['pagenow'])
52 - && ('options-general.php' === $GLOBALS['pagenow'] // output
53 - || 'options.php' === $GLOBALS['pagenow'])) { // validation
54 - add_action('admin_init', array('DG_Admin', 'registerAdminStyle'));
55 - add_action('admin_init', array('DG_Admin', 'registerSettings'));
60 + if (DG_Admin::doRegisterSettings()) {
61 + add_action('admin_init', array('DG_Admin', 'registerSettings'));
56 62 }
57 63 } else {
58 64 // styling for gallery
59 - add_action('wp_enqueue_scripts', array('DocumentGallery', 'enqueueGalleryStyle'));
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 + }
60 72 }
61 73
62 74 // adds 'dg' shortcode
63 75 add_shortcode('dg', array('DocumentGallery', 'doShortcode'));
@@ -68,8 +80,13 @@
68 80 * @author drossiter
69 81 */
70 82 class DocumentGallery {
71 83
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';
88 +
72 89 /*==========================================================================
73 90 * THE SHORTCODE
74 91 *=========================================================================*/
75 92
@@ -76,14 +93,19 @@
76 93 /**
77 94 * Takes values passed from attributes and returns sutable HTML to represent
78 95 * all valid attachments requested.
79 96 *
80 - * @param array $atts Arguments from the user.
81 - * @return string HTML for the Document Gallery.
97 + * @param multitype:string $atts Arguments from the user.
98 + * @return string HTML for the Document Gallery.
82 99 */
83 100 public static function doShortcode($atts) {
84 101 include_once 'inc/class-gallery.php';
85 - return new DG_Gallery($atts);
102 +
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');
106 +
107 + return $gallery;
86 108 }
87 109
88 110 /**
89 111 * Enqueue standard DG CSS.
@@ -88,24 +110,50 @@
88 110 /**
89 111 * Enqueue standard DG CSS.
90 112 */
91 113 public static function enqueueGalleryStyle() {
114 + wp_enqueue_style('document-gallery', DG_URL . 'assets/css/style.css', null, DG_VERSION);
115 + }
116 +
117 + /**
118 + * Enqueue user's custom DG CSS.
119 + */
120 + public static function enqueueCustomStyle() {
92 121 global $dg_options;
93 - wp_register_style('dg-main', DG_URL . 'assets/css/style.css', null,
94 - self::version() . ':' . $dg_options['css']['version']);
95 - wp_enqueue_style('dg-main');
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');
96 125 }
97 126
98 - public static function updateUserGalleryStyle($css) {
99 - $ret = false;
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 + }
100 137
101 - if ($css_file = file_get_contents(DG_PATH . 'assets/css/style.css')) {
102 - $css_file = preg_replace('#/\* CUSTOM USER CSS \*/.*#s',
103 - "/* CUSTOM USER CSS */\n" . $css, $css_file);
104 - $ret = (bool)file_put_contents(DG_PATH . 'assets/css/style.css', $css_file, LOCK_EX);
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;
105 155 }
106 -
107 - return $ret;
108 156 }
109 157
110 158 /*==========================================================================
111 159 * I18n
@@ -110,34 +158,198 @@
110 158 /*==========================================================================
111 159 * I18n
112 160 *=========================================================================*/
113 161
162 + /**
163 + * Loads language files into WP core.
164 + */
114 165 public static function loadTextDomain() {
115 - load_plugin_textdomain('document-gallery', false, DG_PATH . 'languages');
166 + load_plugin_textdomain('document-gallery', false, dirname(DG_BASENAME) . '/languages/');
116 167 }
117 168
118 169 /*==========================================================================
119 170 * HELPER FUNCTIONS
120 171 *=========================================================================*/
121 -
172 +
122 173 /**
123 - * Gets the current version of the plugin.
124 - * @param bool recalculate Whether to re-read the file for version number.
125 - * @return str DG version installed.
174 + * @param int $blog ID of the blog to be retrieved in multisite env.
175 + * @return multitype:unknown Options for the blog.
126 176 */
127 - public static function version($recalculate = false) {
128 - static $version = null;
129 -
130 - if ($recalculate) {
131 - include_once WP_ADMIN_DIR . '/includes/plugin.php';
132 - $data = get_plugin_data(__FILE__, false);
133 - $version = $data['Version'];
134 - } elseif(is_null($version)) {
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)) {
135 190 global $dg_options;
136 - $version = $dg_options['version'];
191 + update_option(DG_OPTION_NAME, $options);
192 + $dg_options = $options;
193 + } else {
194 + update_blog_option($blog, DG_OPTION_NAME, $options);
137 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('>', '>', 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;
138 310
139 - return $version;
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);
140 352 }
141 353
142 354 /**
143 355 * Blocks instantiation. All functions are static.