Document Gallery - Version 3.4.1

Version Description

Download this release

Release Info

Developer dan.rossiter
Plugin Icon 128x128 Document Gallery
Version 3.4.1
Comparing to
See all releases

Code changes from version 3.3.1 to 3.4.1

README.txt CHANGED
@@ -2,9 +2,9 @@
2
  Contributors: dan.rossiter, demur
3
  Tags: attachments, thumbnail, documents, gallery, MS office, pdf
4
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=EE5LWRLG933EN&lc=US&item_name=Document%20Gallery%20Plugin&item_number=document%2dgallery&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted
5
- Requires at least: 3.6
6
- Tested up to: 4.2.2
7
- Stable tag: 3.3.1
8
  License: GPLv2
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -438,6 +438,17 @@ To see a list of features planned for the future as well as to propose your own
438
  ideas for future Document Gallery development, take a look at our
439
  [issue tracker](https://github.com/thenadz/document-gallery/issues).
440
 
 
 
 
 
 
 
 
 
 
 
 
441
  = 3.3.1 =
442
  * **Bug Fix:** A couple of the translation files (Finnish & Ukrainian) were named incorrectly, resulting in them
443
  never actually being loaded.
2
  Contributors: dan.rossiter, demur
3
  Tags: attachments, thumbnail, documents, gallery, MS office, pdf
4
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=EE5LWRLG933EN&lc=US&item_name=Document%20Gallery%20Plugin&item_number=document%2dgallery&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted
5
+ Requires at least: 4.1
6
+ Tested up to: 4.3
7
+ Stable tag: 3.4.1
8
  License: GPLv2
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
438
  ideas for future Document Gallery development, take a look at our
439
  [issue tracker](https://github.com/thenadz/document-gallery/issues).
440
 
441
+ = 3.4 =
442
+ * **Enhancement:** To address recent issues resulting from corrupt plugin options, we're making option validation no longer
443
+ optional. This was an advanced feature that most users were likely not aware of, but it allows us to provide more
444
+ robust option management moving forward. Any options that have been previously corrupted will be reset during upgrading
445
+ to this version of DG.
446
+ * **Enhancement:** Various under-the-hood tweaks in preparation for supporting numerous additional file types
447
+ (eg: MS Office). [Stay tuned.](https://wordpress.org/support/topic/notice-google-drive-viewer-not-working)
448
+ * **Bug Fix:** Log purging was not working correctly. Issue is resolved.
449
+ * **Bug Fix:** There were some CSS changes in WP 3.3 which broke some styling in the DG settings dialogs. These have
450
+ been resolved.
451
+
452
  = 3.3.1 =
453
  * **Bug Fix:** A couple of the translation files (Finnish & Ukrainian) were named incorrectly, resulting in them
454
  never actually being loaded.
admin/class-admin.php CHANGED
@@ -15,10 +15,15 @@ class DG_Admin {
15
  /**
16
  * NOTE: This should only ever be accessed through getTabs().
17
  *
18
- * @var multitype: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
  *
@@ -84,6 +89,7 @@ class DG_Admin {
84
  global $dg_options;
85
 
86
  $donate = '<strong><a href="' . $dg_options['meta']['donate_link'] . '">' .
 
87
  __( 'Donate', 'document-gallery' ) . '</a></strong>';
88
  $links[] = $donate;
89
  }
@@ -111,9 +117,15 @@ class DG_Admin {
111
  wp_enqueue_style( 'document-gallery-admin', DG_URL . 'assets/css/admin.css', null, DG_VERSION );
112
 
113
  // gracefully degrade for older WP versions
114
- if ( version_compare( get_bloginfo( 'version' ), '3.8', '<' ) ) {
115
- echo '<style type="text/css">.dashicons, .nav-tab:before, .deleteSelected:before, .clearLog:before, .expandAll:before, .collapseAll:before, .logLabel.date:before, .collapser:after, .expander:after, #ThumbsTable .title a:after, #LogTable>tbody a:after {display: none !important;}</style>' . PHP_EOL;
116
- }
 
 
 
 
 
 
117
 
118
  wp_enqueue_script( 'document-gallery-admin', DG_URL . 'assets/js/admin.js', array( 'jquery' ), DG_VERSION, true );
119
  wp_localize_script( 'document-gallery-admin', 'dg_admin_vars', array( 'upload_limit' => wp_max_upload_size() ) );
@@ -457,18 +469,6 @@ class DG_Admin {
457
  'description' => __( 'Number of days to keep old log entries (0 disables purging).', 'document-gallery' )
458
  ) );
459
 
460
- add_settings_field(
461
- 'advanced_validation', __( 'Option Validation', 'document-gallery' ),
462
- array( __CLASS__, 'renderCheckboxField' ),
463
- DG_OPTION_NAME, 'advanced',
464
- array(
465
- 'label_for' => 'label_advanced_validation',
466
- 'name' => 'validation',
467
- 'value' => esc_attr( $dg_options['validation'] ),
468
- 'option_name' => DG_OPTION_NAME,
469
- 'description' => __( 'Whether option structure should be validated before save. This is not generally necessary.', 'document-gallery' )
470
- ) );
471
-
472
  add_settings_field(
473
  'advanced_thumb_timeout', __( 'Thumbnail Generation Timeout', 'document-gallery' ),
474
  array( __CLASS__, 'renderTextField' ),
@@ -515,11 +515,11 @@ class DG_Admin {
515
  // per page load, re-returning the previous result on any
516
  // subsequent calls.
517
  static $ret = null;
518
- if ( is_null( $ret ) ) {
519
- if ( empty( $values['tab'] ) || ! array_key_exists( $values['tab'], self::getTabs() ) ) {
520
- reset( self::getTabs() );
521
- $values['tab'] = key( self::getTabs() );
522
- }
523
  $funct = 'validate' . $values['tab'] . 'Settings';
524
  unset( $values['tab'] );
525
  $ret = DG_Admin::$funct( $values );
@@ -600,9 +600,9 @@ class DG_Admin {
600
  if ( ! $thumbs_cleared ) {
601
  foreach ( $dg_options['thumber']['active'] as $k => $v ) {
602
  if ( ! $v && $ret['thumber']['active'][ $k ] ) {
603
- foreach ( $dg_options['thumber']['thumbs'] as $k => $v ) {
604
  if ( empty( $v['thumber'] ) ) {
605
- unset( $ret['thumber']['thumbs'][ $k ] );
606
  }
607
  }
608
  break;
@@ -693,8 +693,7 @@ class DG_Admin {
693
  }
694
 
695
  if ( isset( $values['ajax'] ) ) {
696
- echo DG_Util::jsonEncode( $responseArr );
697
- add_filter( 'wp_redirect', array( __CLASS__, '_exit' ), 1, 0 );
698
  }
699
 
700
  return $ret;
@@ -792,9 +791,7 @@ class DG_Admin {
792
  $ret = $dg_options;
793
 
794
  // handle setting the Ghostscript path
795
- if ( isset( $values['gs'] ) &&
796
- 0 != strcmp( $values['gs'], $ret['thumber']['gs'] )
797
- ) {
798
  if ( false === strpos( $values['gs'], ';' ) ) {
799
  $ret['thumber']['gs'] = $values['gs'];
800
  } else {
@@ -814,9 +811,6 @@ class DG_Admin {
814
  }
815
  }
816
 
817
- // validation checkbox
818
- $ret['validation'] = isset( $values['validation'] );
819
-
820
  // logging settings
821
  $ret['logging']['enabled'] = isset( $values['logging_enabled'] );
822
  if ( isset( $values['logging_purge_interval'] ) ) {
@@ -918,98 +912,59 @@ class DG_Admin {
918
  */
919
  public static function renderThumbnailSection() {
920
  include_once DG_PATH . 'inc/class-thumber.php';
 
 
 
921
  $options = DG_Thumber::getOptions();
922
 
923
- $URL_params = array( 'page' => DG_OPTION_NAME, 'tab' => 'Thumbnail' );
924
- $att_ids = array();
925
-
926
- if ( isset( $_REQUEST['orderby'] ) && in_array( strtolower( $_REQUEST['orderby'] ), array(
927
- 'title',
928
- 'date'
929
- ) )
930
- ) {
931
- $orderby = strtolower( $_REQUEST['orderby'] );
932
- $URL_params['orderby'] = $orderby;
933
-
934
- switch ( $orderby ) {
935
- case 'date':
936
- foreach ( $options['thumbs'] as $key => $node ) {
937
- $keyArray[ $key ] = $node['timestamp'];
938
- $options['thumbs'][ $key ]['thumb_id'] = $att_ids[] = $key;
939
- }
940
- break;
941
-
942
- case 'title':
943
- foreach ( $options['thumbs'] as $key => $node ) {
944
- $keyArray[ $key ] = basename( $node['thumb_path'] );
945
- $options['thumbs'][ $key ]['thumb_id'] = $att_ids[] = $key;
946
- }
947
- break;
948
- }
949
-
950
- $order = strtolower( $_REQUEST['order'] );
951
- if ( ! isset( $_REQUEST['order'] ) || ! in_array( $order, array( 'asc', 'desc' ) ) ) {
952
- $order = 'asc';
953
- }
954
- $URL_params['order'] = $order;
955
-
956
- if ( $order == 'asc' ) {
957
- array_multisort( $keyArray, SORT_ASC, $options['thumbs'] );
958
- } else {
959
- array_multisort( $keyArray, SORT_DESC, $options['thumbs'] );
960
- }
961
- } else {
962
- $orderby = '';
963
- foreach ( $options['thumbs'] as $key => $node ) {
964
- $options['thumbs'][ $key ]['thumb_id'] = $att_ids[] = $key;
965
- }
966
- }
967
-
968
- static $limit_options = array( 10, 25, 75 );
969
- if ( ! isset( $_REQUEST['limit'] ) || ! in_array( intval( $_REQUEST['limit'] ), $limit_options ) ) {
970
- $limit = $limit_options[0];
971
- } else {
972
- $limit = intval( $_REQUEST['limit'] );
973
- }
974
 
975
- $URL_params['limit'] = $limit;
976
- $select_limit = '';
977
- foreach ( $limit_options as $l_o ) {
978
- $select_limit .= '<option value="' . $l_o . '"' . selected( $limit, $l_o, false ) . '>' . $l_o . '</option>' . PHP_EOL;
979
- }
980
  $thumbs_number = count( $options['thumbs'] );
981
  $lastsheet = ceil( $thumbs_number / $limit );
982
- $sheet = isset( $_REQUEST['sheet'] ) ? intval( $_REQUEST['sheet'] ) : 1;
983
- if ( $sheet <= 0 || $sheet > $lastsheet ) {
984
  $sheet = 1;
985
  }
986
 
987
  $offset = ( $sheet - 1 ) * $limit;
988
-
989
- $att_ids = array_slice( $att_ids, $offset, $limit );
990
 
991
  // https://core.trac.wordpress.org/ticket/12212
992
- $atts = array();
993
- if ( ! empty( $att_ids ) ) {
994
- $atts = get_posts(
995
  array(
996
  'post_type' => 'any',
997
  'post_status' => 'any',
998
  'numberposts' => - 1,
999
- 'post__in' => $att_ids,
1000
  'orderby' => 'post__in'
1001
  ) );
1002
  }
1003
 
1004
- $titles = array();
1005
- $contents = array();
1006
- foreach ( $atts as $att ) {
1007
- $path_parts = pathinfo( $att->guid );
1008
- $titles[ $att->ID ] = $att->post_title;
1009
- $types[ $att->ID ] = $path_parts['extension'];
1010
- $contents[ $att->ID ] = $att->post_content;
 
 
 
 
 
 
 
 
 
1011
  }
1012
- unset( $atts );
1013
 
1014
  $thead = '<tr>' .
1015
  '<th scope="col" class="manage-column column-cb check-column">' .
@@ -1017,13 +972,13 @@ class DG_Admin {
1017
  '<input id="cb-select-all-%1$d" type="checkbox">' .
1018
  '</th>' .
1019
  '<th scope="col" class="manage-column column-icon">' . __( 'Thumbnail', 'document-gallery' ) . '</th>' .
1020
- '<th scope="col" class="manage-column column-title ' . ( ( $orderby != 'title' ) ? 'sortable desc' : 'sorted ' . $order ) . '"><a href="?' . http_build_query( array_merge( $URL_params, array(
1021
  'orderby' => 'title',
1022
  'order' => ( ( $orderby != 'title' ) ? 'asc' : ( ( $order == 'asc' ) ? 'desc' : 'asc' ) )
1023
  ) ) ) . '"><span>' . __( 'File name', 'document-gallery' ) . '</span><span class="sorting-indicator"></span></th>' .
1024
  '<th scope="col" class="manage-column column-description">' . __( 'Description', 'document-gallery' ) . '</th>' .
1025
  '<th scope="col" class="manage-column column-thumbupload"></th>' .
1026
- '<th scope="col" class="manage-column column-date ' . ( ( $orderby != 'date' ) ? 'sortable asc' : 'sorted ' . $order ) . '"><a href="?' . http_build_query( array_merge( $URL_params, array(
1027
  'orderby' => 'date',
1028
  'order' => ( ( $orderby != 'date' ) ? 'desc' : ( ( $order == 'asc' ) ? 'desc' : 'asc' ) )
1029
  ) ) ) . '"><span>' . __( 'Date', 'document-gallery' ) . '</span><span class="sorting-indicator"></span></th>' .
@@ -1034,12 +989,12 @@ class DG_Admin {
1034
  $thumbs_number . ' ' . _n( 'item', 'items', $thumbs_number ) .
1035
  '</span>' . ( $lastsheet > 1 ?
1036
  '<span class="pagination-links">' .
1037
- '<a class="first-page' . ( $sheet == 1 ? ' disabled' : '' ) . '" title="' . __( 'Go to the first page', 'document-gallery' ) . '"' . ( $sheet == 1 ? '' : ' href="?' . http_build_query( $URL_params ) . '"' ) . '>«</a>' .
1038
- '<a class="prev-page' . ( $sheet == 1 ? ' disabled' : '' ) . '" title="' . __( 'Go to the previous page', 'document-gallery' ) . '"' . ( $sheet == 1 ? '' : ' href="?' . http_build_query( array_merge( $URL_params, array( 'sheet' => $sheet - 1 ) ) ) . '"' ) . '>‹</a>' .
1039
  '<span class="paging-input">' .
1040
  '<input class="current-page" title="' . __( 'Current page', 'document-gallery' ) . '" type="text" name="paged" value="' . $sheet . '" size="' . strlen( $sheet ) . '" maxlength="' . strlen( $sheet ) . '"> ' . __( 'of', 'document-gallery' ) . ' <span class="total-pages">' . $lastsheet . '</span></span>' .
1041
- '<a class="next-page' . ( $sheet == $lastsheet ? ' disabled' : '' ) . '" title="' . __( 'Go to the next page', 'document-gallery' ) . '"' . ( $sheet == $lastsheet ? '' : ' href="?' . http_build_query( array_merge( $URL_params, array( 'sheet' => $sheet + 1 ) ) ) . '"' ) . '>›</a>' .
1042
- '<a class="last-page' . ( $sheet == $lastsheet ? ' disabled' : '' ) . '" title="' . __( 'Go to the last page', 'document-gallery' ) . '"' . ( $sheet == $lastsheet ? '' : ' href="?' . http_build_query( array_merge( $URL_params, array( 'sheet' => $lastsheet ) ) ) . '"' ) . '>»</a>' .
1043
  '</span>' : ' <b>|</b> ' ) .
1044
  '<span class="displaying-num"><select dir="rtl" class="limit_per_page">' . $select_limit . '</select> ' . __( 'items per page', 'document-gallery' ) . '</span>' .
1045
  '</div>' .
@@ -1047,7 +1002,7 @@ class DG_Admin {
1047
  ?>
1048
 
1049
  <script type="text/javascript">
1050
- var URL_params = <?php echo DG_Util::jsonEncode($URL_params); ?>;
1051
  </script>
1052
  <div class="thumbs-list-wrapper">
1053
  <div>
@@ -1061,38 +1016,63 @@ class DG_Admin {
1061
  <?php printf( $thead, 2 ); ?>
1062
  </tfoot>
1063
  <tbody><?php
1064
- $i = 0;
1065
- foreach ( $options['thumbs'] as $v ) {
1066
- if ( $i < $offset ) {
1067
- $i ++;
1068
- continue;
1069
- }
1070
- if ( ++ $i > $offset + $limit ) {
1071
- break;
1072
- }
1073
-
1074
- $icon = isset( $v['thumb_url'] ) ? $v['thumb_url'] : DG_Thumber::getDefaultThumbnail( $v['thumb_id'] );
1075
- $title = isset( $titles[ $v['thumb_id'] ] ) ? $titles[ $v['thumb_id'] ] : '';
1076
- $type = $types[ $v['thumb_id'] ];
1077
- $description = $contents[ $v['thumb_id'] ];
1078
- $date = DocumentGallery::localDateTimeFromTimestamp( $v['timestamp'] );
1079
-
1080
- echo '<tr data-entry="' . $v['thumb_id'] . '"><td scope="row" class="check-column"><input type="checkbox" class="cb-ids" name="' . DG_OPTION_NAME . '[ids][]" value="' .
1081
- $v['thumb_id'] . '"></td><td class="column-icon media-icon"><img src="' .
1082
- $icon . '" />' . '</td><td class="title column-title">' .
1083
- ( $title ? '<strong><a href="' . home_url( '/?attachment_id=' . $v['thumb_id'] ) . '" target="_blank" title="' . sprintf( __( "View '%s' attachment page", 'document-gallery' ), $title ) . '"><span class="editable-title">' . $title . '</span> <sup>' . $type . '</sup></a></strong>' : __( 'Attachment not found', 'document-gallery' ) ) .
1084
- '<span class="dashicons dashicons-edit"></span><span class="edit-controls"><span class="dashicons dashicons-yes"></span> <span class="dashicons dashicons-no"></span></span></td><td class="column-description"><div class="editable-description">' . $description . '</div><span class="dashicons dashicons-edit"></span><span class="edit-controls"><span class="dashicons dashicons-yes"></span> <span class="dashicons dashicons-no"></span><span class="dashicons dashicons-update"></span></span>' .
1085
- '</td><td class="column-thumbupload">' .
1086
- '<span class="manual-download">' .
1087
- '<span class="dashicons dashicons-upload"></span>' .
1088
- '<span class="html5dndmarker">Drop file here<span> or </span></span>' .
1089
- '<span class="buttons-area">' .
1090
- '<input id="upload-button' . $v['thumb_id'] . '" type="file" />' .
1091
- '<input id="trigger-button' . $v['thumb_id'] . '" type="button" value="Select File" class="button" />' .
1092
- '</span>' .
1093
- '</span>' .
1094
- '<div class="progress animate invis"><span><span></span></span></div>' .
1095
- '</td><td class="date column-date">' . $date . '</td></tr>' . PHP_EOL;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1096
  } ?>
1097
  </tbody>
1098
  </table>
@@ -1101,6 +1081,35 @@ class DG_Admin {
1101
  </div>
1102
  <?php }
1103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1104
  /**
1105
  * Adds meta box to the attchements' edit pages.
1106
  */
@@ -1172,8 +1181,7 @@ class DG_Admin {
1172
  }
1173
  }
1174
  if ( isset( $_POST[ DG_OPTION_NAME ]['ajax'] ) ) {
1175
- echo DG_Util::jsonEncode( $responseArr );
1176
- wp_die();
1177
  }
1178
  }
1179
 
@@ -1241,13 +1249,13 @@ class DG_Admin {
1241
  $date = DocumentGallery::localDateTimeFromTimestamp( $log_entry[0] );
1242
 
1243
  // convert attachment names to links
1244
- $log_entry[2] = preg_replace( '/[ ^](attachment #)(\d+)[., ]/i', ' <a href="' . home_url() . '/?attachment_id=\2" target="_blank">\1<strong>\2</strong></a> ', $log_entry[2] );
1245
 
1246
  // bold the place where log entry was submitted
1247
- $log_entry[2] = preg_replace( '/^(\(\w+::\w+\)) /', '<strong>\1</strong> ', $log_entry[2] );
1248
 
1249
  // italicize any function references within log entry
1250
- $log_entry[2] = preg_replace( '/(\(?\w+::\w+\)?)/m', '<i>\1</i>', $log_entry[2] );
1251
 
1252
  echo '<tr><td class="date column-date" data-sort-value="' . $log_entry[0] . '"><span class="logLabel date">' . $date . '</span></td>' .
1253
  '<td class="column-level">' . $levels[ $log_entry[1] ] . '</td>' .
@@ -1347,10 +1355,24 @@ class DG_Admin {
1347
  }
1348
 
1349
  /**
1350
- * Wraps the PHP exit language construct.
 
 
 
1351
  */
1352
- public static function _exit() {
1353
- exit;
 
 
 
 
 
 
 
 
 
 
 
1354
  }
1355
 
1356
  /**
15
  /**
16
  * NOTE: This should only ever be accessed through getTabs().
17
  *
18
+ * @var array Associative array containing all tab names, keyed by tab slug.
19
  */
20
  private static $tabs;
21
 
22
+ /**
23
+ * @var array The URL parameters. Currently only used in the thumbnail mgmt tab.
24
+ */
25
+ private static $URL_params;
26
+
27
  /**
28
  * Returns reference to tabs array, initializing if needed.
29
  *
89
  global $dg_options;
90
 
91
  $donate = '<strong><a href="' . $dg_options['meta']['donate_link'] . '">' .
92
+ '<span class="dashicons dashicons-heart"></span> ' .
93
  __( 'Donate', 'document-gallery' ) . '</a></strong>';
94
  $links[] = $donate;
95
  }
117
  wp_enqueue_style( 'document-gallery-admin', DG_URL . 'assets/css/admin.css', null, DG_VERSION );
118
 
119
  // gracefully degrade for older WP versions
120
+ if ( version_compare( get_bloginfo( 'version' ), '3.8', '<' ) ) { ?>
121
+ <style type="text/css">
122
+ .dashicons, .nav-tab:before, .deleteSelected:before, .clearLog:before, .expandAll:before,
123
+ .collapseAll:before, .logLabel.date:before, .collapser:after, .expander:after,
124
+ #ThumbsTable .title a:after, #LogTable>tbody a:after {
125
+ display: none !important;
126
+ }
127
+ </style>
128
+ <?php }
129
 
130
  wp_enqueue_script( 'document-gallery-admin', DG_URL . 'assets/js/admin.js', array( 'jquery' ), DG_VERSION, true );
131
  wp_localize_script( 'document-gallery-admin', 'dg_admin_vars', array( 'upload_limit' => wp_max_upload_size() ) );
469
  'description' => __( 'Number of days to keep old log entries (0 disables purging).', 'document-gallery' )
470
  ) );
471
 
 
 
 
 
 
 
 
 
 
 
 
 
472
  add_settings_field(
473
  'advanced_thumb_timeout', __( 'Thumbnail Generation Timeout', 'document-gallery' ),
474
  array( __CLASS__, 'renderTextField' ),
515
  // per page load, re-returning the previous result on any
516
  // subsequent calls.
517
  static $ret = null;
518
+ if ( is_null( $values ) ) {
519
+ $ret = $values;
520
+ }
521
+
522
+ if ( array_key_exists( 'tab', $values ) && array_key_exists( $values['tab'], self::getTabs() ) ) {
523
  $funct = 'validate' . $values['tab'] . 'Settings';
524
  unset( $values['tab'] );
525
  $ret = DG_Admin::$funct( $values );
600
  if ( ! $thumbs_cleared ) {
601
  foreach ( $dg_options['thumber']['active'] as $k => $v ) {
602
  if ( ! $v && $ret['thumber']['active'][ $k ] ) {
603
+ foreach ( $dg_options['thumber']['thumbs'] as $k2 => $v2 ) {
604
  if ( empty( $v['thumber'] ) ) {
605
+ unset( $ret['thumber']['thumbs'][ $k2 ] );
606
  }
607
  }
608
  break;
693
  }
694
 
695
  if ( isset( $values['ajax'] ) ) {
696
+ wp_send_json( $responseArr );
 
697
  }
698
 
699
  return $ret;
791
  $ret = $dg_options;
792
 
793
  // handle setting the Ghostscript path
794
+ if ( isset( $values['gs'] ) && 0 != strcmp( $values['gs'], $ret['thumber']['gs'] ) ) {
 
 
795
  if ( false === strpos( $values['gs'], ';' ) ) {
796
  $ret['thumber']['gs'] = $values['gs'];
797
  } else {
811
  }
812
  }
813
 
 
 
 
814
  // logging settings
815
  $ret['logging']['enabled'] = isset( $values['logging_enabled'] );
816
  if ( isset( $values['logging_purge_interval'] ) ) {
912
  */
913
  public static function renderThumbnailSection() {
914
  include_once DG_PATH . 'inc/class-thumber.php';
915
+ static $limit_options = array( 10, 25, 75 );
916
+ static $order_options = array( 'asc', 'desc' );
917
+ static $orderby_options = array( 'date', 'title' );
918
  $options = DG_Thumber::getOptions();
919
 
920
+ // find subset of thumbs to be included
921
+ self::$URL_params = array( 'page' => DG_OPTION_NAME, 'tab' => 'Thumbnail' );
922
+ $orderby = self::$URL_params['orderby'] = self::getOrderbyParam($orderby_options);
923
+ $order = self::$URL_params['order'] = self::getOrderParam($order_options);
924
+ $limit = self::$URL_params['limit'] = self::getLimitParam($limit_options);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
925
 
926
+ $thumbs = $options['thumbs'];
927
+ uasort( $thumbs, array( __CLASS__, 'cmpThumb' ) );
 
 
 
928
  $thumbs_number = count( $options['thumbs'] );
929
  $lastsheet = ceil( $thumbs_number / $limit );
930
+ $sheet = array_key_exists( 'sheet', $_REQUEST ) ? absint( $_REQUEST['sheet'] ) : 1;
931
+ if ( $sheet === 0 || $sheet > $lastsheet ) {
932
  $sheet = 1;
933
  }
934
 
935
  $offset = ( $sheet - 1 ) * $limit;
936
+ $thumbs = array_slice( $thumbs, $offset, $limit, true );
 
937
 
938
  // https://core.trac.wordpress.org/ticket/12212
939
+ $posts = array();
940
+ if ( ! empty( $thumbs ) ) {
941
+ $posts = get_posts(
942
  array(
943
  'post_type' => 'any',
944
  'post_status' => 'any',
945
  'numberposts' => - 1,
946
+ 'post__in' => array_keys( $thumbs ),
947
  'orderby' => 'post__in'
948
  ) );
949
  }
950
 
951
+ foreach ( $posts as $post ) {
952
+ $path_parts = pathinfo( $post->guid );
953
+
954
+ $t = &$thumbs[$post->ID];
955
+ $t['title'] = !empty( $post->post_title ) ? $post->post_title : $path_parts['filename'];
956
+ $t['ext'] = array_key_exists( 'extension', $path_parts ) ? $path_parts['extension'] : '';
957
+ $t['description'] = $post->post_content;
958
+ $t['icon'] = array_key_exists( 'thumb_url', $t )
959
+ ? $t['thumb_url']
960
+ : DG_Thumber::getDefaultThumbnail( $post->ID );
961
+ }
962
+ unset( $posts );
963
+
964
+ $select_limit = '';
965
+ foreach ( $limit_options as $l_o ) {
966
+ $select_limit .= '<option value="' . $l_o . '"' . selected( $limit, $l_o, false ) . '>' . $l_o . '</option>' . PHP_EOL;
967
  }
 
968
 
969
  $thead = '<tr>' .
970
  '<th scope="col" class="manage-column column-cb check-column">' .
972
  '<input id="cb-select-all-%1$d" type="checkbox">' .
973
  '</th>' .
974
  '<th scope="col" class="manage-column column-icon">' . __( 'Thumbnail', 'document-gallery' ) . '</th>' .
975
+ '<th scope="col" class="manage-column column-title ' . ( ( $orderby != 'title' ) ? 'sortable desc' : 'sorted ' . $order ) . '"><a href="?' . http_build_query( array_merge( self::$URL_params, array(
976
  'orderby' => 'title',
977
  'order' => ( ( $orderby != 'title' ) ? 'asc' : ( ( $order == 'asc' ) ? 'desc' : 'asc' ) )
978
  ) ) ) . '"><span>' . __( 'File name', 'document-gallery' ) . '</span><span class="sorting-indicator"></span></th>' .
979
  '<th scope="col" class="manage-column column-description">' . __( 'Description', 'document-gallery' ) . '</th>' .
980
  '<th scope="col" class="manage-column column-thumbupload"></th>' .
981
+ '<th scope="col" class="manage-column column-date ' . ( ( $orderby != 'date' ) ? 'sortable asc' : 'sorted ' . $order ) . '"><a href="?' . http_build_query( array_merge( self::$URL_params, array(
982
  'orderby' => 'date',
983
  'order' => ( ( $orderby != 'date' ) ? 'desc' : ( ( $order == 'asc' ) ? 'desc' : 'asc' ) )
984
  ) ) ) . '"><span>' . __( 'Date', 'document-gallery' ) . '</span><span class="sorting-indicator"></span></th>' .
989
  $thumbs_number . ' ' . _n( 'item', 'items', $thumbs_number ) .
990
  '</span>' . ( $lastsheet > 1 ?
991
  '<span class="pagination-links">' .
992
+ '<a class="first-page' . ( $sheet == 1 ? ' disabled' : '' ) . '" title="' . __( 'Go to the first page', 'document-gallery' ) . '"' . ( $sheet == 1 ? '' : ' href="?' . http_build_query( self::$URL_params ) . '"' ) . '>«</a>' .
993
+ '<a class="prev-page' . ( $sheet == 1 ? ' disabled' : '' ) . '" title="' . __( 'Go to the previous page', 'document-gallery' ) . '"' . ( $sheet == 1 ? '' : ' href="?' . http_build_query( array_merge( self::$URL_params, array( 'sheet' => $sheet - 1 ) ) ) . '"' ) . '>‹</a>' .
994
  '<span class="paging-input">' .
995
  '<input class="current-page" title="' . __( 'Current page', 'document-gallery' ) . '" type="text" name="paged" value="' . $sheet . '" size="' . strlen( $sheet ) . '" maxlength="' . strlen( $sheet ) . '"> ' . __( 'of', 'document-gallery' ) . ' <span class="total-pages">' . $lastsheet . '</span></span>' .
996
+ '<a class="next-page' . ( $sheet == $lastsheet ? ' disabled' : '' ) . '" title="' . __( 'Go to the next page', 'document-gallery' ) . '"' . ( $sheet == $lastsheet ? '' : ' href="?' . http_build_query( array_merge( self::$URL_params, array( 'sheet' => $sheet + 1 ) ) ) . '"' ) . '>›</a>' .
997
+ '<a class="last-page' . ( $sheet == $lastsheet ? ' disabled' : '' ) . '" title="' . __( 'Go to the last page', 'document-gallery' ) . '"' . ( $sheet == $lastsheet ? '' : ' href="?' . http_build_query( array_merge( self::$URL_params, array( 'sheet' => $lastsheet ) ) ) . '"' ) . '>»</a>' .
998
  '</span>' : ' <b>|</b> ' ) .
999
  '<span class="displaying-num"><select dir="rtl" class="limit_per_page">' . $select_limit . '</select> ' . __( 'items per page', 'document-gallery' ) . '</span>' .
1000
  '</div>' .
1002
  ?>
1003
 
1004
  <script type="text/javascript">
1005
+ var URL_params = <?php echo wp_json_encode( self::$URL_params ); ?>;
1006
  </script>
1007
  <div class="thumbs-list-wrapper">
1008
  <div>
1016
  <?php printf( $thead, 2 ); ?>
1017
  </tfoot>
1018
  <tbody><?php
1019
+ foreach ( $thumbs as $tid => $thumb ) {
1020
+ $icon = $thumb['icon'];
1021
+ $title = $thumb['title'];
1022
+ $ext = $thumb['ext'];
1023
+ $description = $thumb['description'];
1024
+ $date = DocumentGallery::localDateTimeFromTimestamp( $thumb['timestamp'] );
1025
+ ?>
1026
+ <tr data-entry="<?php echo $tid; ?>">
1027
+ <td scope="row" class="check-column">
1028
+ <input
1029
+ type="checkbox"
1030
+ class="cb-ids"
1031
+ name="<?php echo DG_OPTION_NAME; ?>[ids][]"
1032
+ value="<?php echo $tid; ?>">
1033
+ </td>
1034
+ <td class="column-icon media-icon"><img src="<?php echo $icon; ?>" /></td>
1035
+ <td class="title column-title">
1036
+ <strong>
1037
+ <a
1038
+ href="<?php echo home_url( '/?attachment_id=' . $tid ); ?>"
1039
+ target="_blank"
1040
+ title="<?php sprintf( __( "View '%s' attachment page", 'document-gallery' ), $title ); ?>">
1041
+ <span class="editable-title"><?php echo $title; ?></span>
1042
+ <sup><?php echo $ext; ?></sup>
1043
+ </a>
1044
+ </strong>
1045
+ <span class="dashicons dashicons-edit"></span>
1046
+ <span class="edit-controls">
1047
+ <span class="dashicons dashicons-yes"></span>
1048
+ <span class="dashicons dashicons-no"></span>
1049
+ </span>
1050
+ </td>
1051
+ <td class="column-description">
1052
+ <div class="editable-description"><?php echo $description; ?></div>
1053
+ <span class="dashicons dashicons-edit"></span>
1054
+ <span class="edit-controls">
1055
+ <span class="dashicons dashicons-yes"></span>
1056
+ <span class="dashicons dashicons-no"></span>
1057
+ <span class="dashicons dashicons-update"></span>
1058
+ </span>
1059
+ </td>
1060
+ <td class="column-thumbupload">
1061
+ <span class="manual-download">
1062
+ <span class="dashicons dashicons-upload"></span>
1063
+ <span class="html5dndmarker">Drop file here<span> or </span></span>
1064
+ <span class="buttons-area">
1065
+ <input id="upload-button<?php echo $tid; ?>" type="file" />
1066
+ <input id="trigger-button<?php echo $tid; ?>" type="button" value="Select File" class="button" />
1067
+ </span>
1068
+ </span>
1069
+ <div class="progress animate invis">
1070
+ <span><span></span></span>
1071
+ </div>
1072
+ </td>
1073
+ <td class="date column-date"><?php echo $date; ?></td>
1074
+ </tr>
1075
+ <?php
1076
  } ?>
1077
  </tbody>
1078
  </table>
1081
  </div>
1082
  <?php }
1083
 
1084
+ /**
1085
+ * @param $limit_options array The possible options for limit. If no limit was provided then this is used to find a default limit.
1086
+ *
1087
+ * @return int The limit, which may or may not be a member of $limit_options.
1088
+ */
1089
+ private static function getLimitParam($limit_options) {
1090
+ return array_key_exists( 'limit', $_REQUEST ) ? DG_Util::posint( $_REQUEST['limit'] ) : $limit_options[0];
1091
+ }
1092
+
1093
+ /**
1094
+ * @param $order_options array The possible options for order.
1095
+ *
1096
+ * @return string The order value.
1097
+ */
1098
+ private static function getOrderParam($order_options) {
1099
+ $ret = array_key_exists( 'order', $_REQUEST ) ? strtolower( $_REQUEST['order'] ) : '';
1100
+ return in_array($ret, $order_options) ? $ret : $order_options[0];
1101
+ }
1102
+
1103
+ /**
1104
+ * @param $orderby_options array The possible options for orderby.
1105
+ *
1106
+ * @return string The orderby value.
1107
+ */
1108
+ private static function getOrderbyParam($orderby_options) {
1109
+ $ret = array_key_exists( 'orderby', $_REQUEST ) ? strtolower( $_REQUEST['orderby'] ) : '';
1110
+ return in_array($ret, $orderby_options) ? $ret : $orderby_options[0];
1111
+ }
1112
+
1113
  /**
1114
  * Adds meta box to the attchements' edit pages.
1115
  */
1181
  }
1182
  }
1183
  if ( isset( $_POST[ DG_OPTION_NAME ]['ajax'] ) ) {
1184
+ wp_send_json($responseArr);
 
1185
  }
1186
  }
1187
 
1249
  $date = DocumentGallery::localDateTimeFromTimestamp( $log_entry[0] );
1250
 
1251
  // convert attachment names to links
1252
+ $log_entry[2] = preg_replace( '/[ ^](attachment #)(\d+)[.,: ]/i', ' <a href="' . home_url() . '/?attachment_id=\2" target="_blank">\1<strong>\2</strong></a> ', $log_entry[2] );
1253
 
1254
  // bold the place where log entry was submitted
1255
+ $log_entry[2] = preg_replace( '/^(\((?:\w+(?:::|->))?\w+\)) /', '<strong>\1</strong> ', $log_entry[2] );
1256
 
1257
  // italicize any function references within log entry
1258
+ $log_entry[2] = preg_replace( '/(\(?\w+(?:::|->)\w+\)?)/m', '<i>\1</i>', $log_entry[2] );
1259
 
1260
  echo '<tr><td class="date column-date" data-sort-value="' . $log_entry[0] . '"><span class="logLabel date">' . $date . '</span></td>' .
1261
  '<td class="column-level">' . $levels[ $log_entry[1] ] . '</td>' .
1355
  }
1356
 
1357
  /**
1358
+ * @param $t1 array Thumbnail array #1.
1359
+ * @param $t2 array Thumbnail array #2
1360
+ *
1361
+ * @return int The result of comparing the two thumbnail arrays using arguments in $URL_params.
1362
  */
1363
+ public static function cmpThumb($t1, $t2) {
1364
+ $ret = 0;
1365
+ switch (self::$URL_params['orderby']) {
1366
+ case 'date':
1367
+ $ret = $t1['timestamp'] - $t2['timestamp'];
1368
+ break;
1369
+
1370
+ case 'title':
1371
+ $ret = strcmp( basename( $t1['thumb_path'] ), basename( $t2['thumb_path'] ) );
1372
+ break;
1373
+ }
1374
+
1375
+ return 'asc' === self::$URL_params['order'] ? $ret : -$ret;
1376
  }
1377
 
1378
  /**
assets/css/admin.css CHANGED
@@ -89,6 +89,18 @@ td.title.column-title, .column-thumbupload {
89
  text-align: left !important;
90
  }
91
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  #ThumbsTable img {
93
  display: block;
94
  margin: 5px auto;
@@ -110,7 +122,7 @@ tr.selected:hover {
110
 
111
  .check-column, .column-icon {
112
  white-space: nowrap;
113
- width: 1%;
114
  }
115
 
116
  .column-entry, .column-title {
89
  text-align: left !important;
90
  }
91
 
92
+ td.column-icon.media-icon {
93
+ height: 70px;
94
+ }
95
+
96
+ td.media-icon img {
97
+ width: auto;
98
+ height: auto;
99
+ max-width: 80px;
100
+ max-height: 60px;
101
+ border: none;
102
+ }
103
+
104
  #ThumbsTable img {
105
  display: block;
106
  margin: 5px auto;
122
 
123
  .check-column, .column-icon {
124
  white-space: nowrap;
125
+ width: 80px;
126
  }
127
 
128
  .column-entry, .column-title {
assets/js/admin.js CHANGED
@@ -33,22 +33,16 @@ jQuery(document).ready(function () {
33
  '&document_gallery%5Bajax%5D=true' +
34
  '&document_gallery%5Bcleanup%5D=true';
35
  jQuery('.deleteSelected').addClass('waiting').attr('disabled', 'disabled');
36
- jQuery.post(a, b, function (response) {
37
- if (response.indexOf("\n") == -1) {
38
- eval('var reply = ' + response + ';');
39
- if (reply.result) {
40
- var result = reply.deleted;
41
- for (var index in result) {
42
- jQuery('input[type=checkbox][value=' + result[index] + ']').closest('tr').fadeOut('slow', 0.00, function () {
43
- jQuery(this).slideUp('slow', function () {
44
- jQuery(this).remove();
45
- });
46
  });
47
- }
48
  }
49
- } else {
50
- console.log('Invalid response from server:');
51
- console.log(response);
52
  }
53
  jQuery('.deleteSelected').removeClass('waiting').removeAttr('disabled');
54
  }).fail(function () {
@@ -313,7 +307,7 @@ jQuery(document).ready(function () {
313
  if (cell.find('.editable-description').css('display') == 'none') {
314
  return;
315
  }
316
- cell.find('.editable-description').hide().after('<textarea>' + cell.find('.editable-description').text() + '</textarea>');
317
  cell.find('textarea').focus();
318
  } else {
319
  return;
@@ -364,7 +358,7 @@ jQuery(document).ready(function () {
364
  } else {
365
  return;
366
  }
367
- if (newContent.val() == updateGoal.text()) {
368
  jQuery(this).next('.dashicons-no').click();
369
  return;
370
  }
@@ -377,7 +371,11 @@ jQuery(document).ready(function () {
377
  if (xhr.responseText.indexOf("\n") == -1) {
378
  eval('var response = ' + xhr.responseText + ';');
379
  if (response.result) {
380
- updateGoal.text(newContent.val());
 
 
 
 
381
  cell.find('.dashicons-no').click();
382
  cell.addClass('responseSuccess').delay(2000).queue(function () {
383
  jQuery(this).removeClass('responseSuccess').dequeue();
33
  '&document_gallery%5Bajax%5D=true' +
34
  '&document_gallery%5Bcleanup%5D=true';
35
  jQuery('.deleteSelected').addClass('waiting').attr('disabled', 'disabled');
36
+ jQuery.post(a, b, function (reply) {
37
+ if (reply.result) {
38
+ var result = reply.deleted;
39
+ for (var index in result) {
40
+ jQuery('input[type=checkbox][value=' + result[index] + ']').closest('tr').fadeOut('slow', 0.00, function () {
41
+ jQuery(this).slideUp('slow', function () {
42
+ jQuery(this).remove();
 
 
 
43
  });
44
+ });
45
  }
 
 
 
46
  }
47
  jQuery('.deleteSelected').removeClass('waiting').removeAttr('disabled');
48
  }).fail(function () {
307
  if (cell.find('.editable-description').css('display') == 'none') {
308
  return;
309
  }
310
+ cell.find('.editable-description').hide().after('<textarea>' + cell.find('.editable-description').html() + '</textarea>');
311
  cell.find('textarea').focus();
312
  } else {
313
  return;
358
  } else {
359
  return;
360
  }
361
+ if (newContent.val() == updateGoal.text() || ( cell.hasClass('column-description') && newContent.val() == updateGoal.html() )) {
362
  jQuery(this).next('.dashicons-no').click();
363
  return;
364
  }
371
  if (xhr.responseText.indexOf("\n") == -1) {
372
  eval('var response = ' + xhr.responseText + ';');
373
  if (response.result) {
374
+ if (cell.hasClass('column-description')) {
375
+ updateGoal.html(newContent.val());
376
+ } else {
377
+ updateGoal.text(newContent.val());
378
+ }
379
  cell.find('.dashicons-no').click();
380
  cell.addClass('responseSuccess').delay(2000).queue(function () {
381
  jQuery(this).removeClass('responseSuccess').dequeue();
document-gallery.php CHANGED
@@ -5,14 +5,14 @@ defined( 'WPINC' ) OR exit;
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: 3.3.1
9
  Author: Dan Rossiter
10
  Author URI: http://danrossiter.org/
11
  License: GPLv2
12
  Text Domain: document-gallery
13
  */
14
 
15
- define( 'DG_VERSION', '3.3.1' );
16
 
17
  // define helper paths & URLs
18
  define( 'DG_BASENAME', plugin_basename( __FILE__ ) );
@@ -43,10 +43,8 @@ add_action( 'wpmu_new_blog', array( 'DG_Setup', 'activateNewBlog' ) );
43
  register_uninstall_hook( __FILE__, array( 'DG_Setup', 'uninstall' ) );
44
  DG_Setup::maybeUpdate();
45
 
46
- // validate options if desired
47
- if ( $dg_options['validation'] ) {
48
- add_action( 'init', array( 'DocumentGallery', 'addValidation' ) );
49
- }
50
 
51
  // I18n
52
  add_action( 'plugins_loaded', array( 'DocumentGallery', 'loadTextDomain' ) );
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: 3.4.1
9
  Author: Dan Rossiter
10
  Author URI: http://danrossiter.org/
11
  License: GPLv2
12
  Text Domain: document-gallery
13
  */
14
 
15
+ define( 'DG_VERSION', '3.4.1' );
16
 
17
  // define helper paths & URLs
18
  define( 'DG_BASENAME', plugin_basename( __FILE__ ) );
43
  register_uninstall_hook( __FILE__, array( 'DG_Setup', 'uninstall' ) );
44
  DG_Setup::maybeUpdate();
45
 
46
+ // ensure we don't allow invalid option structure
47
+ add_action( 'init', array( 'DocumentGallery', 'addValidation' ) );
 
 
48
 
49
  // I18n
50
  add_action( 'plugins_loaded', array( 'DocumentGallery', 'loadTextDomain' ) );
inc/class-document-gallery.php CHANGED
@@ -123,19 +123,23 @@ class DocumentGallery {
123
  $ret = $new;
124
  } else {
125
  $ret = $old;
126
- DG_Logger::writeLog( DG_LogLevel::Error, 'Attempted to save invalid options.' . PHP_EOL . print_r( $new, true ), true, true );
 
 
 
 
127
  }
128
 
129
  return $ret;
130
  }
131
 
132
  /**
133
- * @param array|unknown $o The options structure to validate.
134
  * @param array $schema The schema to validate against (note that only keys matter -- non-array values are ignored).
135
  *
136
  * @return bool Whether the given options structure matches the schema.
137
  */
138
- private static function isValidOptionsStructure( $o, $schema = null ) {
139
  if ( is_null( $schema ) ) {
140
  $schema = DG_Setup::getDefaultOptions( true );
141
  }
123
  $ret = $new;
124
  } else {
125
  $ret = $old;
126
+ DG_Logger::writeLog(
127
+ DG_LogLevel::Error,
128
+ 'Attempted to save invalid options.' . PHP_EOL . preg_replace( '/\s+/', ' ', print_r( $new, true ) ),
129
+ true,
130
+ true );
131
  }
132
 
133
  return $ret;
134
  }
135
 
136
  /**
137
+ * @param array|mixed $o The options structure to validate.
138
  * @param array $schema The schema to validate against (note that only keys matter -- non-array values are ignored).
139
  *
140
  * @return bool Whether the given options structure matches the schema.
141
  */
142
+ public static function isValidOptionsStructure( $o, $schema = null ) {
143
  if ( is_null( $schema ) ) {
144
  $schema = DG_Setup::getDefaultOptions( true );
145
  }
inc/class-gallery.php CHANGED
@@ -206,10 +206,10 @@ class DG_Gallery {
206
  /**
207
  *
208
  * @param string $key The key to reference the current value in the defaults array.
209
- * @param unknown $value The value to be sanitized.
210
  * @param array $errs The array of errors, which will be appended with any errors found.
211
  *
212
- * @return unknown The sanitized value, falling back to the current default value when invalid value given.
213
  */
214
  private static function sanitizeParameter( $key, $value, &$errs ) {
215
  // all sanitize methods must be in the following form: sanitize<UpperCammelCaseKey>
@@ -829,11 +829,11 @@ class DG_Gallery {
829
  $core .= str_replace( $find, $repl, $icon_wrapper );
830
  }
831
  } else {
832
- global $dg_gallery_style;
833
-
834
  $count = count( $this->docs );
835
  $cols = ! is_null( $this->atts['columns'] ) ? $this->atts['columns'] : $count;
836
 
 
 
837
  if ( apply_filters( 'dg_use_default_gallery_style', true ) ) {
838
  $itemwidth = $cols > 0 ? ( floor( 100 / $cols ) - 1 ) : 100;
839
  $core .= "<style type='text/css'>#$selector .document-icon{width:$itemwidth%}</style>";
206
  /**
207
  *
208
  * @param string $key The key to reference the current value in the defaults array.
209
+ * @param mixed $value The value to be sanitized.
210
  * @param array $errs The array of errors, which will be appended with any errors found.
211
  *
212
+ * @return mixed The sanitized value, falling back to the current default value when invalid value given.
213
  */
214
  private static function sanitizeParameter( $key, $value, &$errs ) {
215
  // all sanitize methods must be in the following form: sanitize<UpperCammelCaseKey>
829
  $core .= str_replace( $find, $repl, $icon_wrapper );
830
  }
831
  } else {
 
 
832
  $count = count( $this->docs );
833
  $cols = ! is_null( $this->atts['columns'] ) ? $this->atts['columns'] : $count;
834
 
835
+ // TODO: Invalid HTML. WP Core does it this way for [gallery], but consider setting width for each
836
+ // .document-icon as style attribute in element.
837
  if ( apply_filters( 'dg_use_default_gallery_style', true ) ) {
838
  $itemwidth = $cols > 0 ? ( floor( 100 / $cols ) - 1 ) : 100;
839
  $core .= "<style type='text/css'>#$selector .document-icon{width:$itemwidth%}</style>";
inc/class-logger.php CHANGED
@@ -31,9 +31,13 @@ class DG_Logger {
31
  unset( $trace[0] );
32
  $fields[] = self::getStackTraceString( $trace );
33
  } else {
34
- // Remove first item from backtrace as it's this function which is redundant.
35
  $caller = $trace[1];
36
- $caller = ( isset( $caller['class'] ) ? $caller['class'] : '' ) . $caller['type'] . $caller['function'];
 
 
 
 
37
  $fields[2] = '(' . $caller . ') ' . $fields[2];
38
  }
39
 
@@ -110,14 +114,14 @@ class DG_Logger {
110
  foreach ( $blogs as $blog ) {
111
  $blog_num = ! is_null( $blog ) ? $blog : get_current_blog_id();
112
  $options = self::getOptions( $blog );
113
- $purge_interval = $options['purge_interval'] * DAY_IN_SECONDS;
114
 
115
  // purging is disabled for this blog
116
- if ( $purge_interval <= 0 ) {
117
  continue;
118
  }
119
 
120
- // do perge for this blog
121
  $file = self::getLogFileName( $blog_num );
122
  if ( file_exists( $file ) ) {
123
  $fp = @fopen( $file, 'r' );
@@ -128,16 +132,17 @@ class DG_Logger {
128
 
129
  // find the first non-expired entry
130
  while ( ( $fields = fgetcsv( $fp ) ) !== false ) {
131
- if ( ! is_null( $fields ) && $time > ( $fields[0] + $purge_interval ) ) {
132
  // we've reached the recent entries -- nothing beyond here will be removed
133
  break;
134
  }
135
 
136
- $truncate = true;
137
  $offset = @ftell( $fp );
138
  if ( false === $offset ) {
139
  break;
140
  }
 
 
141
  }
142
 
143
  @fclose( $fp );
@@ -221,8 +226,9 @@ class DG_Logger {
221
  }
222
 
223
  if ( isset( $node['function'] ) ) {
 
224
  $args = '';
225
- if ( isset( $node['args'] ) ) {
226
  $args = implode( ', ', array_map( array( __CLASS__, 'print_r' ), $node['args'] ) );
227
  }
228
 
@@ -237,12 +243,12 @@ class DG_Logger {
237
  /**
238
  * Wraps print_r passing true for the return argument.
239
  *
240
- * @param unknown $v Value to be printed.
241
  *
242
  * @return string Printed value.
243
  */
244
  private static function print_r( $v ) {
245
- return print_r( $v, true );
246
  }
247
 
248
  /**
31
  unset( $trace[0] );
32
  $fields[] = self::getStackTraceString( $trace );
33
  } else {
34
+ // Ignore first item from backtrace as it's this function which is redundant.
35
  $caller = $trace[1];
36
+
37
+ $class = isset( $caller['class'] ) ? $caller['class'] : '';
38
+ $type = isset( $caller['type'] ) ? $caller['type'] : '';
39
+ $caller = $class . $type . $caller['function'];
40
+
41
  $fields[2] = '(' . $caller . ') ' . $fields[2];
42
  }
43
 
114
  foreach ( $blogs as $blog ) {
115
  $blog_num = ! is_null( $blog ) ? $blog : get_current_blog_id();
116
  $options = self::getOptions( $blog );
117
+ $purge_time = $time - $options['purge_interval'] * DAY_IN_SECONDS;
118
 
119
  // purging is disabled for this blog
120
+ if ( $purge_time >= $time ) {
121
  continue;
122
  }
123
 
124
+ // do purge for this blog
125
  $file = self::getLogFileName( $blog_num );
126
  if ( file_exists( $file ) ) {
127
  $fp = @fopen( $file, 'r' );
132
 
133
  // find the first non-expired entry
134
  while ( ( $fields = fgetcsv( $fp ) ) !== false ) {
135
+ if ( ! is_null( $fields ) && intval( $fields[0] ) >= $purge_time ) {
136
  // we've reached the recent entries -- nothing beyond here will be removed
137
  break;
138
  }
139
 
 
140
  $offset = @ftell( $fp );
141
  if ( false === $offset ) {
142
  break;
143
  }
144
+
145
+ $truncate = true;
146
  }
147
 
148
  @fclose( $fp );
226
  }
227
 
228
  if ( isset( $node['function'] ) ) {
229
+ // only include args for first item in stack trace
230
  $args = '';
231
+ if ( 1 === $i && isset( $node['args'] ) ) {
232
  $args = implode( ', ', array_map( array( __CLASS__, 'print_r' ), $node['args'] ) );
233
  }
234
 
243
  /**
244
  * Wraps print_r passing true for the return argument.
245
  *
246
+ * @param mixed $v Value to be printed.
247
  *
248
  * @return string Printed value.
249
  */
250
  private static function print_r( $v ) {
251
+ return preg_replace( '/\s+/', ' ', print_r( $v, true ) );
252
  }
253
 
254
  /**
inc/class-setup.php CHANGED
@@ -78,12 +78,10 @@ class DG_Setup {
78
  // logging options
79
  'logging' => array(
80
  // TODO: more granular -- log_level instead of blanket enable/disable
81
- 'enabled' => false,
82
  // max age of log entry (days)
83
  'purge_interval' => 7
84
- ),
85
- // whether to validate DG option structure on save
86
- 'validation' => false
87
  );
88
  }
89
 
@@ -99,9 +97,15 @@ class DG_Setup {
99
  */
100
  public static function maybeUpdate() {
101
  global $dg_options;
 
 
 
 
 
 
 
 
102
 
103
- // do update
104
- if ( ! is_null( $dg_options ) && ( isset( $dg_options['version'] ) || DG_VERSION !== $dg_options['meta']['version'] ) ) {
105
  $blogs = array( null );
106
 
107
  if ( is_multisite() ) {
@@ -133,6 +137,7 @@ class DG_Setup {
133
  self::threePointOne( $options );
134
  self::threePointTwo( $options );
135
  self::threePointThree( $options );
 
136
 
137
  // update plugin meta data
138
  $options['meta']['version'] = DG_VERSION;
@@ -312,6 +317,27 @@ class DG_Setup {
312
  }
313
  }
314
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  /**
316
  * Sets up Document Gallery on all blog(s) activated.
317
  *
78
  // logging options
79
  'logging' => array(
80
  // TODO: more granular -- log_level instead of blanket enable/disable
81
+ 'enabled' => defined( 'WP_DEBUG' ) && WP_DEBUG,
82
  // max age of log entry (days)
83
  'purge_interval' => 7
84
+ )
 
 
85
  );
86
  }
87
 
97
  */
98
  public static function maybeUpdate() {
99
  global $dg_options;
100
+ if ( is_null( $dg_options ) ) {
101
+ return;
102
+ }
103
+
104
+ // version has historically been in two locations -- must check both to continue supporting upgrading from those old versions
105
+ $old_version = array_key_exists( 'version', $dg_options ) ? $dg_options['version'] : $dg_options['meta']['version'];
106
+ if ( ! is_null( $dg_options ) && DG_VERSION !== $old_version ) {
107
+ DG_Logger::writeLog( DG_LogLevel::Detail, "Upgrading Document Gallery from version $old_version to " . DG_VERSION );
108
 
 
 
109
  $blogs = array( null );
110
 
111
  if ( is_multisite() ) {
137
  self::threePointOne( $options );
138
  self::threePointTwo( $options );
139
  self::threePointThree( $options );
140
+ self::threePointFour( $options );
141
 
142
  // update plugin meta data
143
  $options['meta']['version'] = DG_VERSION;
317
  }
318
  }
319
 
320
+ /**
321
+ * Removes the validation option. Validation is now non-optional.
322
+ * Adds the meta items_per_page default value.
323
+ *
324
+ * @param array $options The options to be modified.
325
+ */
326
+ private static function threePointFour( &$options ) {
327
+ if ( version_compare( $options['meta']['version'], '3.4', '<' ) ) {
328
+ unset( $options['validation'] );
329
+
330
+ if ( ! DocumentGallery::isValidOptionsStructure( $options ) ) {
331
+ DG_Logger::writeLog(
332
+ DG_LogLevel::Error,
333
+ "Found invalid options structure. Reverting to default options.",
334
+ false,
335
+ true );
336
+ $options = self::getDefaultOptions();
337
+ }
338
+ }
339
+ }
340
+
341
  /**
342
  * Sets up Document Gallery on all blog(s) activated.
343
  *
inc/class-thumber.php CHANGED
@@ -576,7 +576,7 @@ class DG_Thumber {
576
  if ( count( $thumbers ) > 0 ) {
577
  $entry = __( 'Thumbnail Generators: ', 'document-gallery' );
578
  foreach ( $thumbers as $k => $v ) {
579
- $thumber = is_array( $v ) ? implode( '::', $v ) : print_r( $v, true );
580
 
581
  // TODO: The following works for all internal regexes, but may have unpredictable
582
  // results if developer adds additional thumbnail generators using different regexes
576
  if ( count( $thumbers ) > 0 ) {
577
  $entry = __( 'Thumbnail Generators: ', 'document-gallery' );
578
  foreach ( $thumbers as $k => $v ) {
579
+ $thumber = DG_Util::callableToString($v);
580
 
581
  // TODO: The following works for all internal regexes, but may have unpredictable
582
  // results if developer adds additional thumbnail generators using different regexes
inc/class-util.php CHANGED
@@ -7,78 +7,21 @@ defined( 'WPINC' ) OR exit;
7
  * @author drossiter
8
  */
9
  class DG_Util {
10
- /**
11
- * @var callable Either native JSON encode or custom JSON encode if needed.
12
- */
13
- private static $nativeJsonEncode;
14
-
15
- /**
16
- * Wraps JSON encoding functionality, utilizing native functions if available.
17
- *
18
- * @param unknown $decoded Value to be encoded.
19
- *
20
- * @return string The JSON string.
21
- */
22
- public static function jsonEncode( $decoded ) {
23
- if ( ! isset( self::$nativeJsonEncode ) ) {
24
- self::$nativeJsonEncode = function_exists( 'json_encode' );
25
- }
26
-
27
- // do encoding
28
- return self::$nativeJsonEncode ? json_encode( $decoded ) : self::_jsonEncode( $decoded );
29
- }
30
 
31
  /**
32
- * Home-made JSON encode to replace missing json_encode when needed.
33
- *
34
- * @param unknown $decoded Value to be encoded.
35
- *
36
- * @return string The JSON string.
37
  */
38
- private static function _jsonEncode( $decoded ) {
39
- if ( self::isJsonObj( $decoded ) ) {
40
- $ret = '';
41
- $first = true;
42
- foreach ( $decoded as $k => $v ) {
43
- if ( ! $first ) {
44
- $ret .= ',';
45
- }
46
- $ret .= "\"$k\":" . self::_jsonEncode( $v );
47
- $first = false;
48
  }
49
 
50
- return "\{$ret\}";
51
- } elseif ( is_array( $decoded ) ) {
52
- return '[' . implode( ',', array_map( array( __CLASS__, __FUNCTION__ ), $decoded ) ) . ']';
53
- } elseif ( is_bool( $decoded ) ) {
54
- static $boolMap = array( 'false', 'true' );
55
-
56
- return $boolMap[ (int) $decoded ];
57
- } elseif ( is_string( $decoded ) ) {
58
- return '"' . str_replace( array( '\\', '"' ), array( '\\\\', '\\"' ), $decoded ) . '"';
59
- }
60
-
61
- return (string) $decoded;
62
- }
63
-
64
- /**
65
- * Returns true for PHP objects and associative arrays.
66
- *
67
- * @param unknown $decoded Value to be checked.
68
- *
69
- * @return bool Whether passed value should be encoded as a JSON object.
70
- */
71
- private static function isJsonObj( $decoded ) {
72
- $ret = is_object( $decoded );
73
-
74
- if ( ! $ret && is_array( $decoded ) ) {
75
- $next = 0;
76
- foreach ( array_keys( $decoded ) as $k ) {
77
- if ( $next ++ !== $k ) {
78
- $ret = true;
79
- break;
80
- }
81
- }
82
  }
83
 
84
  return $ret;
@@ -92,10 +35,19 @@ class DG_Util {
92
  return $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" );
93
  }
94
 
 
 
 
 
 
 
 
 
 
95
  /**
96
  * Converts provided value to bool.
97
  *
98
- * @param unknown $val To be converted.
99
  * @param bool|NULL $default The value to return if unable to parse $val.
100
  *
101
  * @return bool|NULL Bool value if can be parsed, else NULL.
7
  * @author drossiter
8
  */
9
  class DG_Util {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
  /**
12
+ * @param callable $callable The callable.
13
+ * @return string The string representation of the callable.
 
 
 
14
  */
15
+ public static function callableToString($callable) {
16
+ $ret = $callable;
17
+ if ( is_array( $callable ) ) {
18
+ $sep = '::';
19
+ if ( !is_string( $callable[0] ) ) {
20
+ $callable[0] = get_class( $callable[0] );
21
+ $sep = '->';
 
 
 
22
  }
23
 
24
+ $ret = "{$callable[0]}$sep{$callable[1]}";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  }
26
 
27
  return $ret;
35
  return $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" );
36
  }
37
 
38
+ /**
39
+ * @param mixed $maybeint Data you wish to have converted to a positive integer.
40
+ *
41
+ * @return int A positive integer.
42
+ */
43
+ public static function posint($maybeint) {
44
+ return max(absint($maybeint), 1);
45
+ }
46
+
47
  /**
48
  * Converts provided value to bool.
49
  *
50
+ * @param mixed $val To be converted.
51
  * @param bool|NULL $default The value to return if unable to parse $val.
52
  *
53
  * @return bool|NULL Bool value if can be parsed, else NULL.