PluginProbe
Document Gallery / trunk
Document Gallery vtrunk
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 / src / admin / class-admin.php

class-admin.php in Document Gallery trunk, at src/admin/class-admin.php

553 lines 18.8 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 class DG_Admin {
5 /**
6 * @var string The hook for the Document Gallery settings page.
7 */
8 private static $hook;
9
10 /**
11 * @var string The current tab being rendered.
12 */
13 private static $current;
14
15 /**
16 * NOTE: This should only ever be accessed through getTabs().
17 *
18 * @var string[] Associative array containing all tab names, keyed by tab slug.
19 */
20 private static $tabs;
21
22 /**
23 * Returns reference to tabs array, initializing if needed.
24 *
25 * NOTE: This cannot be done in a static constructor due to timing with i18n.
26 */
27 public static function &getTabs() {
28 if ( ! isset( self::$tabs ) ) {
29 self::$tabs = array(
30 'general-tab' => __( 'General', 'document-gallery' ),
31 /*'thumber-co-tab' => __( 'Thumber.co', 'document-gallery' ),*/
32 'thumbnail-management-tab' => __( 'Thumbnail Management', 'document-gallery' ),
33 'logging-tab' => __( 'Logging', 'document-gallery' ),
34 'advanced-tab' => __( 'Advanced', 'document-gallery' )
35 );
36 }
37
38 return self::$tabs;
39 }
40
41 /**
42 * Renders Document Gallery options page.
43 */
44 public static function renderOptions() { ?>
45 <div class="wrap">
46 <h2><?php echo __( 'Document Gallery Settings', 'document-gallery' ); ?></h2>
47
48 <h2 class="nav-tab-wrapper">
49 <?php foreach ( self::getTabs() as $tab => $name ) {
50 $class = ( $tab === self::$current ) ? ' nav-tab-active' : '';
51 echo '<a id="' . $tab . '-header" class="nav-tab' . $class . '" href="?page=' . DG_OPTION_NAME . '&tab=' . $tab . '">' . $name . '</a>';
52 } ?>
53 </h2>
54
55 <form method="post" action="options.php?tab=<?php echo self::$current; ?>" id="<?php echo self::$current ?>">
56 <?php
57 settings_fields( DG_OPTION_NAME );
58 do_settings_sections( DG_OPTION_NAME );
59 if ( self::$current !== 'thumbnail-management-tab' && self::$current !== 'logging-tab' ) {
60 submit_button();
61 }
62 ?>
63 </form>
64 </div>
65 <?php }
66
67 /**
68 * Adds settings link to main plugin view.
69 * @param $links string[] The links being prepended.
70 * @return string[] The given array with settings link prepended.
71 */
72 public static function addSettingsLink( $links ) {
73 $settings = '<a href="options-general.php?page=' . DG_OPTION_NAME . '">' .
74 __( 'Settings', 'document-gallery' ) . '</a>';
75 array_unshift( $links, $settings );
76
77 return $links;
78 }
79
80 /**
81 * Adds donate link to main plugin view.
82 * @param $links string[] The links.
83 * @param $file string The file.
84 * @return string[] The given array with donate link appended.
85 */
86 public static function addDonateLink( $links, $file ) {
87 if ( $file === DG_BASENAME ) {
88 global $dg_options;
89
90 $donate = '<strong><a href="' . $dg_options['meta']['donate_link'] . '">' .
91 '<span class="dashicons dashicons-heart"></span> ' .
92 __( 'Donate', 'document-gallery' ) . '</a></strong>';
93 $links[] = $donate;
94 }
95
96 return $links;
97 }
98
99 /**
100 * Adds Document Gallery settings page to admin navigation.
101 */
102 public static function addAdminPage() {
103 DG_Admin::$hook = add_options_page(
104 __( 'Document Gallery Settings', 'document-gallery' ),
105 __( 'Document Gallery', 'document-gallery' ),
106 'manage_options', DG_OPTION_NAME, array( __CLASS__, 'renderOptions' ) );
107 add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueueScriptsAndStyles' ) );
108 }
109
110 /**
111 * Enqueues styles and scripts for the admin settings page.
112 * @param $hook string The hook.
113 */
114 public static function enqueueScriptsAndStyles( $hook ) {
115 include_once DG_PATH . 'admin/class-feature-pointers.php';
116 DG_FeaturePointers::enqueueScripts();
117
118 if ( in_array( $hook, array( DG_Admin::$hook, 'post.php', 'post-new.php' ), true ) ) {
119 // Settings Page
120 DG_Util::enqueueAsset( 'document-gallery-admin', 'assets/css/admin.css' );
121
122 if ( $hook !== self::$hook && get_post_type( get_the_ID() ) !== 'attachment' ) { //if $hook is 'post.php' or 'post-new.php' and it's not an attachment page
123 global $dg_options;
124
125 add_action( 'admin_print_footer_scripts', array( __CLASS__, 'loadCustomTemplates' ) );
126
127 DG_Util::enqueueAsset( 'dg-media-manager', 'assets/js/media_manager.js', array( 'media-views' ) );
128
129 wp_localize_script( 'dg-media-manager', 'DGl10n', array(
130 'dgMenuTitle' => __( 'Create Document Gallery', 'document-gallery' ),
131 'dgButton' => __( 'Create a new Document Gallery', 'document-gallery' ),
132 'canceldgTitle' => '&#8592; ' . __( 'Cancel Document Gallery', 'document-gallery' ),
133 'updatedg' => __( 'Update Document Gallery', 'document-gallery' ),
134 'insertdg' => __( 'Insert Document Gallery', 'document-gallery' ),
135 'addTodg' => __( 'Add to Document Gallery', 'document-gallery' ),
136 'addTodgTitle' => __( 'Add to Document Gallery', 'document-gallery' ),
137 'editdgTitle' => __( 'Edit Document Gallery', 'document-gallery' ),
138 'unfitSCalert' => __( 'This DG shortcode is an advanced one. '.
139 'Sorry there is no way to use standard edit dialog for it. '.
140 'You should switch to text mode to edit shortcode itself.', 'document-gallery' ),
141 ) );
142 wp_localize_script( 'dg-media-manager', 'dgDefaults', $dg_options['gallery'] );
143
144 // TinyMCE visual editor
145 add_filter( 'mce_external_plugins', array( __CLASS__, 'mce_external_plugins' ) );
146 add_filter( 'mce_css', array( __CLASS__, 'dg_plugin_mce_css' ) );
147 } else {
148 DG_Util::enqueueAsset( 'document-gallery-admin', 'assets/js/admin.js', array( 'jquery' ) );
149 wp_localize_script( 'document-gallery-admin', 'dg_admin_vars', array( 'upload_limit' => wp_max_upload_size() ) );
150 }
151 }
152 }
153
154 /**
155 * Adds assets/js/gallery.js as registered TinyMCE plugin.
156 *
157 * @param string[] $plugins An array of default TinyMCE plugins.
158 *
159 * @return string[] Default TinyMCE plugins plus custom DG plugin.
160 */
161 public static function mce_external_plugins( $plugins ) {
162 DG_Logger::writeLog( DG_LogLevel::Detail, 'Entering mce_external_plugins' );
163 $plugins['dg'] = DG_Util::getAssetPath( 'assets/js/gallery.js' );
164 return $plugins;
165 }
166
167 /**
168 * Adds assets/css/style.css as registered TinyMCE CSS.
169 *
170 * @param string $stylesheets Comma-delimited list of stylesheets.
171 *
172 * @return string Comma-delimited list of stylesheets.
173 */
174 public static function dg_plugin_mce_css( $stylesheets ) {
175 if ( ! empty( $stylesheets ) ) {
176 $stylesheets .= ',';
177 }
178 $stylesheets .= str_replace( ',', '%2C', DG_Util::getAssetPath( 'assets/css/style.css' ) );
179 return $stylesheets;
180 }
181
182 /**
183 * Load Document Gallery custom templates for classic editor media modal.
184 */
185 public static function loadCustomTemplates() {
186 include_once DG_PATH . 'admin/media-manager-template.php';
187 }
188
189 /**
190 * Overrides the default media library filters to include custom mime types for document galleries.
191 * This ensures Document Gallery block can display all attachment types while regular galleries remain image-only.
192 */
193 public static function dg_override_filter_object() {
194 DG_Logger::writeLog( DG_LogLevel::Detail, 'Entering dg_override_filter_object' );
195 global $dg_options;
196 ?>
197 <script type="text/javascript">
198 (function() {
199 // Get Document Gallery's MIME types
200 var dgMimeTypes = '<?php echo esc_js( $dg_options['gallery']['mime_types'] ); ?>';
201
202 /**
203 * Check if this is a Document Gallery media frame.
204 * Document Gallery's MediaUpload component passes allowedTypes which becomes mimeType array.
205 */
206 function isDocumentGalleryFrame(controller) {
207 if (!controller || !controller.options || !controller.options.mimeType) {
208 return false;
209 }
210
211 var mimeType = controller.options.mimeType;
212 if (Array.isArray(mimeType)) {
213 return mimeType.join(',') === dgMimeTypes;
214 }
215
216 return false;
217 }
218
219 // Override createFilters to set the correct mime type for Document Gallery
220 var originalCreateFilters = wp.media.view.AttachmentFilters.Uploaded.prototype.createFilters;
221 wp.media.view.AttachmentFilters.Uploaded.prototype.createFilters = function() {
222 var controller = this.options.controller;
223
224 if (isDocumentGalleryFrame(controller)) {
225 this.model.set('type', dgMimeTypes);
226 }
227
228 originalCreateFilters.apply(this, arguments);
229
230 if (isDocumentGalleryFrame(controller)) {
231 this.filters.all.props.type = dgMimeTypes;
232 }
233 };
234
235 // Override GalleryEdit to ensure Document Gallery frames use correct MIME types
236 var originalGalleryEdit = wp.media.controller.GalleryEdit;
237 wp.media.controller.GalleryEdit = originalGalleryEdit.extend({
238 activate: function() {
239 var library = this.get('library');
240 library.observe(wp.Uploader.queue);
241
242 if (isDocumentGalleryFrame(this.frame) && library && library.props) {
243 library.props.set('type', dgMimeTypes);
244 }
245
246 this.frame.on('content:render:browse', this.gallerySettings, this);
247 },
248
249 deactivate: function() {
250 this.get('library').unobserve(wp.Uploader.queue);
251 this.frame.off('content:render:browse', this.gallerySettings, this);
252 },
253
254 gallerySettings: function(browser) {
255 if (!this.get('sortable')) {
256 return;
257 }
258
259 var library = this.get('library');
260 if (isDocumentGalleryFrame(this.frame) && library && library.props) {
261 library.props.set('type', dgMimeTypes);
262 }
263
264 return originalGalleryEdit.prototype.gallerySettings.apply(this, arguments);
265 }
266 });
267 })();
268 </script>
269 <?php }
270
271 /**
272 * Registers settings for the Document Gallery options page.
273 */
274 public static function registerSettings() {
275 self::initCurrentTab();
276
277 register_setting( DG_OPTION_NAME, DG_OPTION_NAME, array( __CLASS__, 'validateSettings' ) );
278
279 include_once DG_PATH . 'admin/tabs/' . self::$current . '.php';
280 dg_register_settings();
281 }
282
283 /**
284 * Validates submitted options, sanitizing any invalid options.
285 *
286 * @param mixed[] $values User-submitted new options.
287 * @return mixed[] Sanitized new options.
288 */
289 public static function validateSettings( $values ) {
290 // NOTE: WP double-calls this function -- below logic prevents potential
291 // side effects by processing a maximum of one call to validate
292 // per page load, re-returning the previous result on any
293 // subsequent calls.
294 static $ret = null;
295 if ( is_null( $ret ) ) {
296 self::initCurrentTab();
297
298 if ( isset( $values['ajax'] ) ) {
299 unset( $values['ajax'] );
300 define( 'DOING_AJAX', true );
301 }
302
303 DG_Logger::writeLog( DG_LogLevel::Detail, 'Validating ' . self::$current . ' tab.' );
304 include_once DG_PATH . 'admin/tabs/' . self::$current . '.php';
305 $ret = dg_validate_settings( $values );
306 }
307
308 return $ret;
309 }
310
311 /**
312 * Validates uploaded file as a semi for potential thumbnail.
313 *
314 * @param string $var File field name.
315 *
316 * @return bool|string False on failure, path to temp file on success.
317 */
318 public static function validateUploadedFile( $var = 'file' ) {
319 // checking if any file was delivered
320 if ( ! isset( $_FILES[ $var ] ) ) {
321 return false;
322 }
323 // we gonna process only first one
324 if ( ! is_array( $_FILES[ $var ]['error'] ) ) {
325 $upload_err = $_FILES[ $var ]['error'];
326 $upload_path = $_FILES[ $var ]['tmp_name'];
327 $upload_size = $_FILES[ $var ]['size'];
328 $upload_type = $_FILES[ $var ]['type'];
329 $upload_name = $_FILES[ $var ]['name'];
330 } else {
331 $upload_err = $_FILES[ $var ]['error'][0];
332 $upload_path = $_FILES[ $var ]['tmp_name'][0];
333 $upload_size = $_FILES[ $var ]['size'][0];
334 $upload_type = $_FILES[ $var ]['type'][0];
335 $upload_name = $_FILES[ $var ]['name'][0];
336 }
337 $info = getimagesize( $upload_path );
338 if ( $info ) {
339 if ( $info['mime'] !== $upload_type ) {// in DG_Thumber::getExt() we'll define and set appropriate extension
340 DG_Logger::writeLog(
341 DG_LogLevel::Warning,
342 __( 'File extension doesn\'t match the MIME type of the image: ', 'document-gallery' ) .
343 $upload_name . ' - ' . $info['mime'] );
344 }
345 if ( $upload_size > wp_max_upload_size() ) {
346 DG_Logger::writeLog(
347 DG_LogLevel::Warning,
348 __( 'Uploaded file size exceeds the allowable limit: ', 'document-gallery' ) .
349 $upload_name . ' - ' . $upload_size . 'b' );
350
351 return false;
352 }
353 } else {
354 DG_Logger::writeLog(
355 DG_LogLevel::Warning,
356 __( 'Uploaded file is not an image: ', 'document-gallery' ) .
357 $upload_name );
358
359 return false;
360 }
361 if ( $upload_err == UPLOAD_ERR_OK && $upload_size > 0 ) {
362 $temp_file = $upload_path;
363 } else {
364 DG_Logger::writeLog(
365 DG_LogLevel::Error,
366 __( 'Failed to get uploaded file: ', 'document-gallery' ) .
367 $upload_err );
368
369 return false;
370 }
371
372 return $temp_file;
373 }
374
375 /**
376 * @return bool Whether to register settings.
377 */
378 public static function doRegisterSettings() {
379 if ( ! is_multisite() ) {
380 $script = ! empty( $GLOBALS['pagenow'] ) ? $GLOBALS['pagenow'] : null;
381 } else {
382 $script = parse_url( $_SERVER['REQUEST_URI'] );
383 $script = basename( $script['path'] );
384 }
385
386 return ! empty( $script ) && ( 'options-general.php' === $script || 'options.php' === $script );
387 }
388
389 /**
390 * Adds meta box to the attachments' edit pages.
391 */
392 public static function addMetaBox() {
393 $screens = array( 'attachment' );
394 foreach ( $screens as $screen ) {
395 add_meta_box(
396 DG_OPTION_NAME . '_gen_box',
397 __( '<b>Thumbnail</b> for <i><b>Document Gallery</b></i>', 'document-gallery' ),
398 array( __CLASS__, 'renderMetaBox' ),
399 $screen,
400 'normal'
401 );
402 }
403 add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueueScriptsAndStyles' ) );
404 }
405
406 /**
407 * Render a Meta Box.
408 * @param $post WP_Post The post.
409 */
410 public static function renderMetaBox( $post ) {
411 // Disabling scripts that have nothing to do with Edit Media pages
412 wp_dequeue_script( 'dg-media-manager' );
413 remove_filter( 'mce_external_plugins', array( __CLASS__, 'mce_external_plugins' ) );
414 remove_filter( 'mce_css', array( __CLASS__, 'dg_plugin_mce_css' ) );
415
416 wp_nonce_field( DG_OPTION_NAME . '_meta_box', DG_OPTION_NAME . '_meta_box_nonce' );
417 $ID = $post->ID;
418 $options = DG_Thumber::getOptions();
419 $thumb = DG_Thumb::getThumb( $ID, $options['width'] . 'x' . $options['height'] );
420 $icon = ! is_null( $thumb ) && $thumb->isSuccess()
421 ? $thumb->getUrl()
422 : DG_DefaultThumber::getInstance()->getThumbnail( $ID );
423
424 echo '<table id="ThumbsTable" class="wp-list-table widefat fixed media" cellpadding="0" cellspacing="0">' .
425 '<tbody><tr data-entry="' . $ID . '"><td class="column-icon media-icon"><img src="' .
426 $icon . '" />' . '</td><td class="column-thumbupload">' .
427 '<span class="manual-download">' .
428 '<span class="dashicons dashicons-upload"></span>' .
429 '<span class="html5dndmarker">Drop file here<span> or </span></span>' .
430 '<span class="buttons-area">' .
431 '<input id="upload-button' . $ID . '" type="file" />' .
432 '<input id="trigger-button' . $ID . '" type="button" value="Select File" class="button" />' .
433 '</span>' .
434 '</span>' .
435 '<div class="progress animate invis"><span><span></span></span></div>' .
436 '</td></tr></tbody></table>' .
437 ( is_null( $thumb ) ? '<span class="dashicons dashicons-info"></span><span class="">Please note this attachment hasn&#39;t been used in any Document Gallery instance and so there is no autogenerated thumbnail, in the meantime default one is used instead.</span>' : '' ) . PHP_EOL;
438 }
439
440 /**
441 * Save a Meta Box.
442 */
443 public static function saveMetaBox( $post_id ) {
444 // Check if our nonce is set.
445 // Verify that the nonce is valid.
446 // If this is an autosave, our form has not been submitted, so we don't want to do anything.
447 if ( ! isset( $_POST[ DG_OPTION_NAME . '_meta_box_nonce' ] ) || ! wp_verify_nonce( $_POST[ DG_OPTION_NAME . '_meta_box_nonce' ], DG_OPTION_NAME . '_meta_box' ) || ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) ) {
448 return;
449 }
450
451 $responseArr = array( 'result' => false );
452 if ( isset( $_POST[ DG_OPTION_NAME ]['entry'] ) ) {
453 $ID = intval( $_POST[ DG_OPTION_NAME ]['entry'] );
454 } else {
455 $ID = - 1;
456 }
457
458 if ( isset( $_POST[DG_OPTION_NAME]['upload'] ) && isset( $_FILES['file'] ) ) {
459 $uploaded_filename = self::validateUploadedFile();
460 if ( $uploaded_filename && ( $thumb = DG_Thumber::setThumbnail( $ID, $uploaded_filename ) ) ) {
461 $responseArr['result'] = true;
462 $responseArr['url'] = $thumb->getUrl();
463 }
464 }
465
466 if ( isset( $_POST[ DG_OPTION_NAME ]['ajax'] ) ) {
467 wp_send_json( $responseArr );
468 }
469 }
470
471 /**
472 * Render a checkbox field.
473 *
474 * @param mixed[] $args
475 */
476 public static function renderCheckboxField( $args ) {
477 $args['disabled'] = isset( $args['disabled'] ) ? $args['disabled'] : false;
478 printf( '<label><input type="checkbox" value="1" name="%1$s[%2$s]" id="%3$s" %4$s %5$s/> %6$s</label>',
479 $args['option_name'],
480 $args['name'],
481 $args['label_for'],
482 checked( $args['value'], 1, false ),
483 disabled( $args['disabled'], true, false ),
484 $args['description'] );
485 }
486
487 /**
488 * Render a text field.
489 *
490 * @param mixed[] $args
491 */
492 public static function renderTextField( $args ) {
493 printf( '<input type="%1$s" value="%2$s" name="%3$s[%4$s]" id="%5$s" /> %6$s',
494 isset( $args['type'] ) ? $args['type'] : 'text',
495 $args['value'],
496 $args['option_name'],
497 $args['name'],
498 $args['label_for'],
499 $args['description'] );
500 }
501
502 /**
503 * Accepts a two-dimensional array where each inner array consists of valid arguments for renderTextField.
504 *
505 * @param mixed[] $args
506 */
507 public static function renderMultiTextField( $args ) {
508 foreach ( $args as $arg ) {
509 self::renderTextField( $arg );
510 }
511 }
512
513 /**
514 * Render a select field.
515 *
516 * @param mixed[] $args
517 */
518 public static function renderSelectField( $args ) {
519 printf( '<select name="%1$s[%2$s]" id="%3$s">',
520 $args['option_name'],
521 $args['name'],
522 $args['label_for'] );
523
524 foreach ( $args['options'] as $val ) {
525 printf( '<option value="%1$s" %2$s>%3$s</option>',
526 $val,
527 selected( $val, $args['value'], false ),
528 $val,
529 $args['description'] );
530 }
531
532 print '</select> ' . $args['description'];
533 }
534
535 /**
536 * Initializes the current tab value.
537 */
538 private static function initCurrentTab() {
539 if ( empty( $_GET['tab'] ) || ! array_key_exists( $_GET['tab'], self::getTabs() ) ) {
540 reset( self::getTabs() );
541 self::$current = key( self::getTabs() );
542 } else {
543 self::$current = $_GET['tab'];
544 }
545 }
546
547 /**
548 * Blocks instantiation. All functions are static.
549 */
550 private function __construct() {
551
552 }
553 }