| 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 |
// Media Manager integration |
| 126 |
add_action( 'admin_print_footer_scripts', array( |
| 127 |
'DG_Admin', |
| 128 |
'loadCustomTemplates' |
| 129 |
) ); //wp_print_scripts || wp_footer |
| 130 |
|
| 131 |
DG_Util::enqueueAsset( 'dg-media-manager', 'assets/js/media_manager.js', array( 'media-views' ) ); |
| 132 |
wp_localize_script( 'dg-media-manager', 'DGl10n', array( |
| 133 |
'dgMenuTitle' => __( 'Create Document Gallery', 'document-gallery' ), |
| 134 |
'dgButton' => __( 'Create a new Document Gallery', 'document-gallery' ), |
| 135 |
'canceldgTitle' => '← ' . __( 'Cancel Document Gallery', 'document-gallery' ), |
| 136 |
'updatedg' => __( 'Update Document Gallery', 'document-gallery' ), |
| 137 |
'insertdg' => __( 'Insert Document Gallery', 'document-gallery' ), |
| 138 |
'addTodg' => __( 'Add to Document Gallery', 'document-gallery' ), |
| 139 |
'addTodgTitle' => __( 'Add to Document Gallery', 'document-gallery' ), |
| 140 |
'editdgTitle' => __( 'Edit Document Gallery', 'document-gallery' ), |
| 141 |
'unfitSCalert' => __( 'This DG shortcode is an advanced one. '. |
| 142 |
'Sorry there is no way to use standard edit dialog for it. '. |
| 143 |
'You should switch to text mode to edit shortcode itself.', 'document-gallery' ), |
| 144 |
) ); |
| 145 |
wp_localize_script( 'dg-media-manager', 'dgDefaults', $dg_options['gallery'] ); |
| 146 |
|
| 147 |
// TinyMCE visual editor |
| 148 |
add_filter( 'mce_external_plugins', array( __CLASS__, 'mce_external_plugins' ) ); |
| 149 |
add_filter( 'mce_css', array( __CLASS__, 'dg_plugin_mce_css' ) ); |
| 150 |
} else { |
| 151 |
DG_Util::enqueueAsset( 'document-gallery-admin', 'assets/js/admin.js', array( 'jquery' ) ); |
| 152 |
wp_localize_script( 'document-gallery-admin', 'dg_admin_vars', array( 'upload_limit' => wp_max_upload_size() ) ); |
| 153 |
} |
| 154 |
} |
| 155 |
} |
| 156 |
|
| 157 |
/** |
| 158 |
* Adds assets/js/gallery.js as registered TinyMCE plugin |
| 159 |
* |
| 160 |
* @param string[] $plugins An array of default TinyMCE plugins. |
| 161 |
* |
| 162 |
* @return string[] Default TinyMCE plugins plus custom DG plugin. |
| 163 |
*/ |
| 164 |
public static function mce_external_plugins( $plugins ) { |
| 165 |
$plugins['dg'] = DG_Util::getAssetPath( 'assets/js/gallery.js' ); |
| 166 |
|
| 167 |
return $plugins; |
| 168 |
} |
| 169 |
|
| 170 |
/** |
| 171 |
* Adds assets/css/style.css as registered TinyMCE CSS |
| 172 |
* |
| 173 |
* @param string $stylesheets Comma-delimited list of stylesheets. |
| 174 |
* |
| 175 |
* @return string Comma-delimited list of stylesheets. |
| 176 |
*/ |
| 177 |
public static function dg_plugin_mce_css( $stylesheets ) { |
| 178 |
if ( ! empty( $stylesheets ) ) { |
| 179 |
$stylesheets .= ','; |
| 180 |
} |
| 181 |
$stylesheets .= str_replace( ',', '%2C', DG_Util::getAssetPath( 'assets/css/style.css' ) ); |
| 182 |
|
| 183 |
return $stylesheets; |
| 184 |
} |
| 185 |
|
| 186 |
/** |
| 187 |
* Load Document Gallery Custom templates. |
| 188 |
*/ |
| 189 |
public static function loadCustomTemplates() { |
| 190 |
include_once DG_PATH . 'admin/media-manager-template.php'; |
| 191 |
} |
| 192 |
|
| 193 |
/** |
| 194 |
* Registers settings for the Document Gallery options page. |
| 195 |
*/ |
| 196 |
public static function registerSettings() { |
| 197 |
self::initCurrentTab(); |
| 198 |
|
| 199 |
register_setting( DG_OPTION_NAME, DG_OPTION_NAME, array( __CLASS__, 'validateSettings' ) ); |
| 200 |
|
| 201 |
include_once DG_PATH . 'admin/tabs/' . self::$current . '.php'; |
| 202 |
dg_register_settings(); |
| 203 |
} |
| 204 |
|
| 205 |
/** |
| 206 |
* Validates submitted options, sanitizing any invalid options. |
| 207 |
* |
| 208 |
* @param mixed[] $values User-submitted new options. |
| 209 |
* @return mixed[] Sanitized new options. |
| 210 |
*/ |
| 211 |
public static function validateSettings( $values ) { |
| 212 |
// NOTE: WP double-calls this function -- below logic prevents potential |
| 213 |
// side effects by processing a maximum of one call to validate |
| 214 |
// per page load, re-returning the previous result on any |
| 215 |
// subsequent calls. |
| 216 |
static $ret = null; |
| 217 |
if ( is_null( $ret ) ) { |
| 218 |
self::initCurrentTab(); |
| 219 |
|
| 220 |
if ( isset( $values['ajax'] ) ) { |
| 221 |
unset( $values['ajax'] ); |
| 222 |
define( 'DOING_AJAX', true ); |
| 223 |
} |
| 224 |
|
| 225 |
DG_Logger::writeLog( DG_LogLevel::Detail, 'Validating ' . self::$current . ' tab.' ); |
| 226 |
include_once DG_PATH . 'admin/tabs/' . self::$current . '.php'; |
| 227 |
$ret = dg_validate_settings( $values ); |
| 228 |
} |
| 229 |
|
| 230 |
return $ret; |
| 231 |
} |
| 232 |
|
| 233 |
/** |
| 234 |
* Validates uploaded file as a semi for potential thumbnail. |
| 235 |
* |
| 236 |
* @param string $var File field name. |
| 237 |
* |
| 238 |
* @return bool|string False on failure, path to temp file on success. |
| 239 |
*/ |
| 240 |
public static function validateUploadedFile( $var = 'file' ) { |
| 241 |
// checking if any file was delivered |
| 242 |
if ( ! isset( $_FILES[ $var ] ) ) { |
| 243 |
return false; |
| 244 |
} |
| 245 |
// we gonna process only first one |
| 246 |
if ( ! is_array( $_FILES[ $var ]['error'] ) ) { |
| 247 |
$upload_err = $_FILES[ $var ]['error']; |
| 248 |
$upload_path = $_FILES[ $var ]['tmp_name']; |
| 249 |
$upload_size = $_FILES[ $var ]['size']; |
| 250 |
$upload_type = $_FILES[ $var ]['type']; |
| 251 |
$upload_name = $_FILES[ $var ]['name']; |
| 252 |
} else { |
| 253 |
$upload_err = $_FILES[ $var ]['error'][0]; |
| 254 |
$upload_path = $_FILES[ $var ]['tmp_name'][0]; |
| 255 |
$upload_size = $_FILES[ $var ]['size'][0]; |
| 256 |
$upload_type = $_FILES[ $var ]['type'][0]; |
| 257 |
$upload_name = $_FILES[ $var ]['name'][0]; |
| 258 |
} |
| 259 |
$info = getimagesize( $upload_path ); |
| 260 |
if ( $info ) { |
| 261 |
if ( $info['mime'] !== $upload_type ) {// in DG_Thumber::getExt() we'll define and set appropriate extension |
| 262 |
DG_Logger::writeLog( |
| 263 |
DG_LogLevel::Warning, |
| 264 |
__( 'File extension doesn\'t match the MIME type of the image: ', 'document-gallery' ) . |
| 265 |
$upload_name . ' - ' . $info['mime'] ); |
| 266 |
} |
| 267 |
if ( $upload_size > wp_max_upload_size() ) { |
| 268 |
DG_Logger::writeLog( |
| 269 |
DG_LogLevel::Warning, |
| 270 |
__( 'Uploaded file size exceeds the allowable limit: ', 'document-gallery' ) . |
| 271 |
$upload_name . ' - ' . $upload_size . 'b' ); |
| 272 |
|
| 273 |
return false; |
| 274 |
} |
| 275 |
} else { |
| 276 |
DG_Logger::writeLog( |
| 277 |
DG_LogLevel::Warning, |
| 278 |
__( 'Uploaded file is not an image: ', 'document-gallery' ) . |
| 279 |
$upload_name ); |
| 280 |
|
| 281 |
return false; |
| 282 |
} |
| 283 |
if ( $upload_err == UPLOAD_ERR_OK && $upload_size > 0 ) { |
| 284 |
$temp_file = $upload_path; |
| 285 |
} else { |
| 286 |
DG_Logger::writeLog( |
| 287 |
DG_LogLevel::Error, |
| 288 |
__( 'Failed to get uploaded file: ', 'document-gallery' ) . |
| 289 |
$upload_err ); |
| 290 |
|
| 291 |
return false; |
| 292 |
} |
| 293 |
|
| 294 |
return $temp_file; |
| 295 |
} |
| 296 |
|
| 297 |
/** |
| 298 |
* @return bool Whether to register settings. |
| 299 |
*/ |
| 300 |
public static function doRegisterSettings() { |
| 301 |
if ( ! is_multisite() ) { |
| 302 |
$script = ! empty( $GLOBALS['pagenow'] ) ? $GLOBALS['pagenow'] : null; |
| 303 |
} else { |
| 304 |
$script = parse_url( $_SERVER['REQUEST_URI'] ); |
| 305 |
$script = basename( $script['path'] ); |
| 306 |
} |
| 307 |
|
| 308 |
return ! empty( $script ) && ( 'options-general.php' === $script || 'options.php' === $script ); |
| 309 |
} |
| 310 |
|
| 311 |
/** |
| 312 |
* Adds meta box to the attachments' edit pages. |
| 313 |
*/ |
| 314 |
public static function addMetaBox() { |
| 315 |
$screens = array( 'attachment' ); |
| 316 |
foreach ( $screens as $screen ) { |
| 317 |
add_meta_box( |
| 318 |
DG_OPTION_NAME . '_gen_box', |
| 319 |
__( '<b>Thumbnail</b> for <i><b>Document Gallery</b></i>', 'document-gallery' ), |
| 320 |
array( __CLASS__, 'renderMetaBox' ), |
| 321 |
$screen, |
| 322 |
'normal' |
| 323 |
); |
| 324 |
} |
| 325 |
add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueueScriptsAndStyles' ) ); |
| 326 |
} |
| 327 |
|
| 328 |
/** |
| 329 |
* Render a Meta Box. |
| 330 |
* @param $post WP_Post The post. |
| 331 |
*/ |
| 332 |
public static function renderMetaBox( $post ) { |
| 333 |
// Disabling scripts that have nothing to do with Edit Media pages |
| 334 |
wp_dequeue_script( 'dg-media-manager' ); |
| 335 |
remove_filter( 'mce_external_plugins', array( __CLASS__, 'mce_external_plugins' ) ); |
| 336 |
remove_filter( 'mce_css', array( __CLASS__, 'dg_plugin_mce_css' ) ); |
| 337 |
|
| 338 |
wp_nonce_field( DG_OPTION_NAME . '_meta_box', DG_OPTION_NAME . '_meta_box_nonce' ); |
| 339 |
$ID = $post->ID; |
| 340 |
$options = DG_Thumber::getOptions(); |
| 341 |
$thumb = DG_Thumb::getThumb( $ID, $options['width'] . 'x' . $options['height'] ); |
| 342 |
$icon = ! is_null( $thumb ) && $thumb->isSuccess() |
| 343 |
? $thumb->getUrl() |
| 344 |
: DG_DefaultThumber::getInstance()->getThumbnail( $ID ); |
| 345 |
|
| 346 |
echo '<table id="ThumbsTable" class="wp-list-table widefat fixed media" cellpadding="0" cellspacing="0">' . |
| 347 |
'<tbody><tr data-entry="' . $ID . '"><td class="column-icon media-icon"><img src="' . |
| 348 |
$icon . '" />' . '</td><td class="column-thumbupload">' . |
| 349 |
'<span class="manual-download">' . |
| 350 |
'<span class="dashicons dashicons-upload"></span>' . |
| 351 |
'<span class="html5dndmarker">Drop file here<span> or </span></span>' . |
| 352 |
'<span class="buttons-area">' . |
| 353 |
'<input id="upload-button' . $ID . '" type="file" />' . |
| 354 |
'<input id="trigger-button' . $ID . '" type="button" value="Select File" class="button" />' . |
| 355 |
'</span>' . |
| 356 |
'</span>' . |
| 357 |
'</td></tr></tbody></table>' . |
| 358 |
( is_null( $thumb ) ? '<span class="dashicons dashicons-info"></span><span class="">Please note this attachment hasn'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; |
| 359 |
} |
| 360 |
|
| 361 |
/** |
| 362 |
* Save a Meta Box. |
| 363 |
*/ |
| 364 |
public static function saveMetaBox( $post_id ) { |
| 365 |
// Check if our nonce is set. |
| 366 |
// Verify that the nonce is valid. |
| 367 |
// If this is an autosave, our form has not been submitted, so we don't want to do anything. |
| 368 |
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 ) ) { |
| 369 |
return; |
| 370 |
} |
| 371 |
|
| 372 |
$responseArr = array( 'result' => false ); |
| 373 |
if ( isset( $_POST[ DG_OPTION_NAME ]['entry'] ) ) { |
| 374 |
$ID = intval( $_POST[ DG_OPTION_NAME ]['entry'] ); |
| 375 |
} else { |
| 376 |
$ID = - 1; |
| 377 |
} |
| 378 |
|
| 379 |
if ( isset( $_POST[DG_OPTION_NAME]['upload'] ) && isset( $_FILES['file'] ) ) { |
| 380 |
$uploaded_filename = self::validateUploadedFile(); |
| 381 |
if ( $uploaded_filename && ( $thumb = DG_Thumber::setThumbnail( $ID, $uploaded_filename ) ) ) { |
| 382 |
$responseArr['result'] = true; |
| 383 |
$responseArr['url'] = $thumb->getUrl(); |
| 384 |
} |
| 385 |
} |
| 386 |
|
| 387 |
if ( isset( $_POST[ DG_OPTION_NAME ]['ajax'] ) ) { |
| 388 |
wp_send_json( $responseArr ); |
| 389 |
} |
| 390 |
} |
| 391 |
|
| 392 |
/** |
| 393 |
* Render a checkbox field. |
| 394 |
* |
| 395 |
* @param mixed[] $args |
| 396 |
*/ |
| 397 |
public static function renderCheckboxField( $args ) { |
| 398 |
$args['disabled'] = isset( $args['disabled'] ) ? $args['disabled'] : false; |
| 399 |
printf( '<label><input type="checkbox" value="1" name="%1$s[%2$s]" id="%3$s" %4$s %5$s/> %6$s</label>', |
| 400 |
$args['option_name'], |
| 401 |
$args['name'], |
| 402 |
$args['label_for'], |
| 403 |
checked( $args['value'], 1, false ), |
| 404 |
disabled( $args['disabled'], true, false ), |
| 405 |
$args['description'] ); |
| 406 |
} |
| 407 |
|
| 408 |
/** |
| 409 |
* Render a text field. |
| 410 |
* |
| 411 |
* @param mixed[] $args |
| 412 |
*/ |
| 413 |
public static function renderTextField( $args ) { |
| 414 |
printf( '<input type="%1$s" value="%2$s" name="%3$s[%4$s]" id="%5$s" /> %6$s', |
| 415 |
isset( $args['type'] ) ? $args['type'] : 'text', |
| 416 |
$args['value'], |
| 417 |
$args['option_name'], |
| 418 |
$args['name'], |
| 419 |
$args['label_for'], |
| 420 |
$args['description'] ); |
| 421 |
} |
| 422 |
|
| 423 |
/** |
| 424 |
* Accepts a two-dimensional array where each inner array consists of valid arguments for renderTextField. |
| 425 |
* |
| 426 |
* @param mixed[] $args |
| 427 |
*/ |
| 428 |
public static function renderMultiTextField( $args ) { |
| 429 |
foreach ( $args as $arg ) { |
| 430 |
self::renderTextField( $arg ); |
| 431 |
} |
| 432 |
} |
| 433 |
|
| 434 |
/** |
| 435 |
* Render a select field. |
| 436 |
* |
| 437 |
* @param mixed[] $args |
| 438 |
*/ |
| 439 |
public static function renderSelectField( $args ) { |
| 440 |
printf( '<select name="%1$s[%2$s]" id="%3$s">', |
| 441 |
$args['option_name'], |
| 442 |
$args['name'], |
| 443 |
$args['label_for'] ); |
| 444 |
|
| 445 |
foreach ( $args['options'] as $val ) { |
| 446 |
printf( '<option value="%1$s" %2$s>%3$s</option>', |
| 447 |
$val, |
| 448 |
selected( $val, $args['value'], false ), |
| 449 |
$val, |
| 450 |
$args['description'] ); |
| 451 |
} |
| 452 |
|
| 453 |
print '</select> ' . $args['description']; |
| 454 |
} |
| 455 |
|
| 456 |
/** |
| 457 |
* Initializes the current tab value. |
| 458 |
*/ |
| 459 |
private static function initCurrentTab() { |
| 460 |
if ( empty( $_GET['tab'] ) || ! array_key_exists( $_GET['tab'], self::getTabs() ) ) { |
| 461 |
reset( self::getTabs() ); |
| 462 |
self::$current = key( self::getTabs() ); |
| 463 |
} else { |
| 464 |
self::$current = $_GET['tab']; |
| 465 |
} |
| 466 |
} |
| 467 |
|
| 468 |
/** |
| 469 |
* Blocks instantiation. All functions are static. |
| 470 |
*/ |
| 471 |
private function __construct() { |
| 472 |
|
| 473 |
} |
| 474 |
} |