NextGEN Gallery – WordPress Gallery Plugin - Version 3.1.14

Version Description

  • 03.26.2019 =
  • Changed: Restored original behavior of ngg_after_new_images_added hook
  • Changed: Images with EXIF rotation metadata are now rotated automatically at upload
  • Changed: Moved confirmation message presented after editing a thumbnail
  • Fixed: Ability to import zips of images
  • Fixed: Gallery folder not created on filesystem after adding new gallery
  • Fixed: IGW not working with Gutenberg / Block Editor
  • Fixed: Compatibility with EWWW Image Optimizer
  • Fixed: Compatibility with Elementor
  • Fixed: Compatibility with Imagify
  • Fixed: NextGen 3.1.11 passed an incorrect path to load_plugin_textdomain()
  • Fixed: Simplelightbox initialization was opening more than once for certain images
Download this release

Release Info

Developer photocrati
Plugin Icon 128x128 NextGEN Gallery – WordPress Gallery Plugin
Version 3.1.14
Comparing to
See all releases

Code changes from version 3.1.11 to 3.1.14

changelog.txt CHANGED
@@ -1,7 +1,20 @@
1
  NextGEN Gallery
2
  by Imagely
3
 
4
- = V3.1.11 - 03.020.2019 =
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  * NEW: Many performance enhancements
6
  * Fixed: Broken Overview page on WordPress 5.1
7
  * Fixed: Problem with notices not being dismissible
1
  NextGEN Gallery
2
  by Imagely
3
 
4
+ = V3.1.14 - 03.26.2019 =
5
+ * Changed: Restored original behavior of ngg_after_new_images_added hook
6
+ * Changed: Images with EXIF rotation metadata are now rotated automatically at upload
7
+ * Changed: Moved confirmation message presented after editing a thumbnail
8
+ * Fixed: Ability to import zips of images
9
+ * Fixed: Gallery folder not created on filesystem after adding new gallery
10
+ * Fixed: IGW not working with Gutenberg / Block Editor
11
+ * Fixed: Compatibility with EWWW Image Optimizer
12
+ * Fixed: Compatibility with Elementor
13
+ * Fixed: Compatibility with Imagify
14
+ * Fixed: NextGen 3.1.11 passed an incorrect path to load_plugin_textdomain()
15
+ * Fixed: Simplelightbox initialization was opening more than once for certain images
16
+
17
+ = V3.1.11 - 03.20.2019 =
18
  * NEW: Many performance enhancements
19
  * Fixed: Broken Overview page on WordPress 5.1
20
  * Fixed: Problem with notices not being dismissible
nggallery.php CHANGED
@@ -4,7 +4,7 @@ if(preg_match('#' . basename(__FILE__) . '#', $_SERVER['PHP_SELF'])) { die('You
4
  /**
5
  * Plugin Name: NextGEN Gallery
6
  * Description: The most popular gallery plugin for WordPress and one of the most popular plugins of all time with over 25 million downloads.
7
- * Version: 3.1.11
8
  * Author: Imagely
9
  * Plugin URI: https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/
10
  * Author URI: https://www.imagely.com
@@ -393,7 +393,10 @@ class C_NextGEN_Bootstrap
393
  {
394
  // Register the (de)activation routines
395
  add_action('deactivate_' . NGG_PLUGIN_BASENAME, array(get_class(), 'deactivate'));
396
- add_action('activate_' . NGG_PLUGIN_BASENAME, array(get_class(), 'activate'), -10);
 
 
 
397
 
398
  // Register our test suite
399
  add_filter('simpletest_suites', array(&$this, 'add_testsuite'));
@@ -451,6 +454,14 @@ class C_NextGEN_Bootstrap
451
  return $enabled;
452
  }
453
 
 
 
 
 
 
 
 
 
454
  function fix_autoupdate_api_requests($args, $url)
455
  {
456
  // Is this an HTTP request to the licensing server?
@@ -689,7 +700,9 @@ class C_NextGEN_Bootstrap
689
 
690
  foreach ($capabilities as $capability) {
691
  $role->add_cap($capability);
692
- }
 
 
693
  }
694
 
695
  /**
@@ -707,7 +720,7 @@ class C_NextGEN_Bootstrap
707
  define('NGG_PRODUCT_URL', path_join(str_replace("\\" , '/', NGG_PLUGIN_URL), 'products'));
708
  define('NGG_MODULE_URL', path_join(str_replace("\\", '/', NGG_PRODUCT_URL), 'photocrati_nextgen/modules'));
709
  define('NGG_PLUGIN_STARTED_AT', microtime());
710
- define('NGG_PLUGIN_VERSION', '3.1.11');
711
 
712
  define(
713
  'NGG_SCRIPT_VERSION',
@@ -1012,13 +1025,13 @@ function ngg_fs( $activate_for_all = false ) {
1012
  } else {
1013
  // Don't run Freemius for plugin updates.
1014
  $run_freemius = false;
1015
- if (is_null($ngg_run_freemius))
1016
- update_option('ngg_run_freemius', FALSE);
1017
- }
1018
 
1019
- if ( ! $run_freemius ) {
1020
- return false;
1021
- }
1022
  }
1023
 
1024
  if ( ! isset( $ngg_fs ) ) {
@@ -1062,9 +1075,10 @@ function ngg_fs( $activate_for_all = false ) {
1062
  return $ngg_fs;
1063
  }
1064
 
1065
- // Init Freemius.
1066
- ngg_fs();
 
1067
 
1068
- #endregion Freemius
1069
 
1070
  new C_NextGEN_Bootstrap();
4
  /**
5
  * Plugin Name: NextGEN Gallery
6
  * Description: The most popular gallery plugin for WordPress and one of the most popular plugins of all time with over 25 million downloads.
7
+ * Version: 3.1.14
8
  * Author: Imagely
9
  * Plugin URI: https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/
10
  * Author URI: https://www.imagely.com
393
  {
394
  // Register the (de)activation routines
395
  add_action('deactivate_' . NGG_PLUGIN_BASENAME, array(get_class(), 'deactivate'));
396
+ add_action('activate_' . NGG_PLUGIN_BASENAME, array(get_class(), 'activate'), -10);
397
+
398
+ // Handle activation redirect to overview page
399
+ add_action('init', array($this, 'handle_activation_redirect'));
400
 
401
  // Register our test suite
402
  add_filter('simpletest_suites', array(&$this, 'add_testsuite'));
454
  return $enabled;
455
  }
456
 
457
+ function handle_activation_redirect()
458
+ {
459
+ if (get_transient('ngg-activated')) {
460
+ delete_transient('ngg-activated');
461
+ wp_redirect(admin_url("?page=nextgen-gallery"));
462
+ }
463
+ }
464
+
465
  function fix_autoupdate_api_requests($args, $url)
466
  {
467
  // Is this an HTTP request to the licensing server?
700
 
701
  foreach ($capabilities as $capability) {
702
  $role->add_cap($capability);
703
+ }
704
+
705
+ set_transient('ngg-activated', time());
706
  }
707
 
708
  /**
720
  define('NGG_PRODUCT_URL', path_join(str_replace("\\" , '/', NGG_PLUGIN_URL), 'products'));
721
  define('NGG_MODULE_URL', path_join(str_replace("\\", '/', NGG_PRODUCT_URL), 'photocrati_nextgen/modules'));
722
  define('NGG_PLUGIN_STARTED_AT', microtime());
723
+ define('NGG_PLUGIN_VERSION', '3.1.14');
724
 
725
  define(
726
  'NGG_SCRIPT_VERSION',
1025
  } else {
1026
  // Don't run Freemius for plugin updates.
1027
  $run_freemius = false;
1028
+ if (is_null($ngg_run_freemius))
1029
+ update_option('ngg_run_freemius', FALSE);
1030
+ }
1031
 
1032
+ if ( ! $run_freemius ) {
1033
+ return false;
1034
+ }
1035
  }
1036
 
1037
  if ( ! isset( $ngg_fs ) ) {
1075
  return $ngg_fs;
1076
  }
1077
 
1078
+ // // Init Freemius.
1079
+ // Update 2019-03-19: don't run on any instances
1080
+ // ngg_fs();
1081
 
1082
+ // #endregion Freemius
1083
 
1084
  new C_NextGEN_Bootstrap();
products/photocrati_nextgen/modules/datamapper/module.datamapper.php CHANGED
@@ -14,7 +14,7 @@ class M_DataMapper extends C_Base_Module
14
  'photocrati-datamapper',
15
  'DataMapper',
16
  'Provides a database abstraction layer following the DataMapper pattern',
17
- '3.1.4.2',
18
  'https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/',
19
  'Imagely',
20
  'https://www.imagely.com'
14
  'photocrati-datamapper',
15
  'DataMapper',
16
  'Provides a database abstraction layer following the DataMapper pattern',
17
+ '3.1.14',
18
  'https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/',
19
  'Imagely',
20
  'https://www.imagely.com'
products/photocrati_nextgen/modules/datamapper/package.module.datamapper.php CHANGED
@@ -673,6 +673,10 @@ class C_DataMapper_Driver_Base extends C_Component
673
  return $default;
674
  }
675
  }
 
 
 
 
676
  }
677
  /**
678
  * Provides instance methods for C_CustomTable_DataMapper_Driver
673
  return $default;
674
  }
675
  }
676
+ function flush_query_cache()
677
+ {
678
+ $this->_cache = array();
679
+ }
680
  }
681
  /**
682
  * Provides instance methods for C_CustomTable_DataMapper_Driver
products/photocrati_nextgen/modules/i18n/module.i18n.php CHANGED
@@ -20,7 +20,7 @@ class M_I18N extends C_Base_Module
20
  'photocrati-i18n',
21
  'Internationalization',
22
  "Adds I18N resources and methods",
23
- '3.1.8',
24
  'https://www.imagely.com/languages/',
25
  'Imagely',
26
  'https://www.imagely.com'
@@ -48,9 +48,9 @@ class M_I18N extends C_Base_Module
48
  function register_translation_hooks()
49
  {
50
  $dir = str_replace(
51
- wp_normalize_path(WP_CONTENT_DIR),
52
  "",
53
- M_Static_Assets::get_static_abspath('photocrati-i18n#lang')
54
  );
55
 
56
  // Load text domain
20
  'photocrati-i18n',
21
  'Internationalization',
22
  "Adds I18N resources and methods",
23
+ '3.1.14',
24
  'https://www.imagely.com/languages/',
25
  'Imagely',
26
  'https://www.imagely.com'
48
  function register_translation_hooks()
49
  {
50
  $dir = str_replace(
51
+ wp_normalize_path(WP_PLUGIN_DIR),
52
  "",
53
+ wp_normalize_path(__DIR__ . DIRECTORY_SEPARATOR . 'lang')
54
  );
55
 
56
  // Load text domain
products/photocrati_nextgen/modules/lightbox/module.lightbox.php CHANGED
@@ -23,7 +23,7 @@ class M_Lightbox extends C_Base_Module
23
  'photocrati-lightbox',
24
  'Lightbox',
25
  "Provides integration with several JavaScript lightbox effect libraries",
26
- '3.0.0',
27
  'https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/',
28
  'Imagely',
29
  'https://www.imagely.com'
23
  'photocrati-lightbox',
24
  'Lightbox',
25
  "Provides integration with several JavaScript lightbox effect libraries",
26
+ '3.1.11.1',
27
  'https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/',
28
  'Imagely',
29
  'https://www.imagely.com'
products/photocrati_nextgen/modules/lightbox/static/simplelightbox/nextgen_simple_lightbox_init.js CHANGED
@@ -1,7 +1,9 @@
1
  jQuery(function($) {
2
 
 
 
3
  var nextgen_simplelightbox_init = function() {
4
- var selector = nextgen_lightbox_filter_selector($, $(".ngg-simplelightbox"));
5
  selector.simpleLightbox({
6
  history: false,
7
  animationSlide: false,
@@ -9,6 +11,10 @@ jQuery(function($) {
9
  });
10
  };
11
 
12
- $(window).bind('refreshed', nextgen_simplelightbox_init);
13
  nextgen_simplelightbox_init();
14
- });
 
 
 
 
 
1
  jQuery(function($) {
2
 
3
+ var selector = null;
4
+
5
  var nextgen_simplelightbox_init = function() {
6
+ selector = nextgen_lightbox_filter_selector($, $(".ngg-simplelightbox"));
7
  selector.simpleLightbox({
8
  history: false,
9
  animationSlide: false,
11
  });
12
  };
13
 
 
14
  nextgen_simplelightbox_init();
15
+
16
+ $(window).bind('refreshed', function() {
17
+ var gallery = selector.simpleLightbox();
18
+ gallery.refresh();
19
+ });
20
+ });
products/photocrati_nextgen/modules/lightbox/static/simplelightbox/nextgen_simple_lightbox_init.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(function(i){var e=function(){nextgen_lightbox_filter_selector(i,i(".ngg-simplelightbox")).simpleLightbox({history:!1,animationSlide:!1,animationSpeed:100})};i(window).bind("refreshed",e),e()});
1
+ jQuery(function(i){var e=null;!function(){e=nextgen_lightbox_filter_selector(i,i(".ngg-simplelightbox")),e.simpleLightbox({history:!1,animationSlide:!1,animationSpeed:100})}(),i(window).bind("refreshed",function(){e.simpleLightbox().refresh()})});
products/photocrati_nextgen/modules/nextgen_data/module.nextgen_data.php CHANGED
@@ -22,7 +22,7 @@ class M_NextGen_Data extends C_Base_Module
22
  'photocrati-nextgen-data',
23
  'NextGEN Data Tier',
24
  "Provides a data tier for NextGEN gallery based on the DataMapper module",
25
- '3.1.10',
26
  'https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/',
27
  'Imagely',
28
  'https://www.imagely.com'
22
  'photocrati-nextgen-data',
23
  'NextGEN Data Tier',
24
  "Provides a data tier for NextGEN gallery based on the DataMapper module",
25
+ '3.1.14',
26
  'https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/',
27
  'Imagely',
28
  'https://www.imagely.com'
products/photocrati_nextgen/modules/nextgen_data/package.module.nextgen_data.php CHANGED
@@ -622,6 +622,18 @@ class C_Exif_Writer_Wrapper
622
  self::load_pel();
623
  return @C_Exif_Writer::read_metadata($filename);
624
  }
 
 
 
 
 
 
 
 
 
 
 
 
625
  /**
626
  * @param $filename
627
  * @param $metadata
@@ -827,10 +839,10 @@ class Mixin_Gallery_Mapper extends Mixin
827
  }
828
  function _save_entity($entity)
829
  {
 
830
  // A bug in NGG 2.1.24 allowed galleries to be created with spaces in the directory name, unreplaced by dashes
831
  // This causes a few problems everywhere, so we here allow users a way to fix those galleries by just re-saving
832
  if (FALSE !== strpos($entity->path, ' ')) {
833
- $storage = C_Gallery_Storage::get_instance();
834
  $abspath = $storage->get_gallery_abspath($entity->{$entity->id_field});
835
  $pre_path = $entity->path;
836
  $entity->path = str_replace(' ', '-', $entity->path);
@@ -859,6 +871,7 @@ class Mixin_Gallery_Mapper extends Mixin
859
  }
860
  $retval = $this->call_parent('_save_entity', $entity);
861
  if ($retval) {
 
862
  do_action('ngg_created_new_gallery', $entity->{$entity->id_field});
863
  C_Photocrati_Transient_Manager::flush('displayed_gallery_rendering');
864
  }
@@ -3662,6 +3675,9 @@ class Mixin_GalleryStorage_Base_Dynamic extends Mixin
3662
  }
3663
  if ($rotation && in_array(abs($rotation), array(90, 180, 270))) {
3664
  $thumbnail->rotateImageAngle($rotation);
 
 
 
3665
  }
3666
  $flip = strtolower($flip);
3667
  if ($flip && in_array($flip, array('h', 'v', 'hv'))) {
@@ -3679,6 +3695,11 @@ class Mixin_GalleryStorage_Base_Dynamic extends Mixin
3679
  $thumbnail = apply_filters('ngg_before_save_thumbnail', $thumbnail);
3680
  $exif_iptc = @C_Exif_Writer_Wrapper::read_metadata($image_path);
3681
  $thumbnail->save($destpath, $quality);
 
 
 
 
 
3682
  @C_Exif_Writer_Wrapper::write_metadata($destpath, $exif_iptc);
3683
  }
3684
  }
@@ -4011,16 +4032,57 @@ class Mixin_GalleryStorage_Base_Dynamic extends Mixin
4011
  $image_abspath = $this->object->get_image_abspath($image, 'full');
4012
  $generated = $this->object->generate_image_clone($image_abspath, $image_abspath, $this->object->get_image_size_params($image, 'full'));
4013
  if ($generated && $save) {
4014
- // Ensure that fullsize dimensions are added to metadata array
4015
- $dimensions = getimagesize($image_abspath);
4016
- $full_meta = array('width' => $dimensions[0], 'height' => $dimensions[1], 'md5' => $this->object->get_image_checksum($image, 'full'));
4017
- if (!isset($image->meta_data) or is_string($image->meta_data) && strlen($image->meta_data) == 0 or is_bool($image->meta_data)) {
4018
- $image->meta_data = array();
4019
- }
4020
- $image->meta_data = array_merge($image->meta_data, $full_meta);
4021
- $image->meta_data['full'] = $full_meta;
4022
- // Don't forget to append the 'full' entry in meta_data in the db
4023
- $this->object->_image_mapper->save($image);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4024
  }
4025
  }
4026
  /**
@@ -4477,7 +4539,7 @@ class Mixin_GalleryStorage_Base_Getters extends Mixin
4477
  * Returns the named sizes available for images
4478
  * @return array
4479
  */
4480
- function get_image_sizes($image)
4481
  {
4482
  $retval = array('full', 'thumbnail');
4483
  if (is_numeric($image)) {
@@ -4878,12 +4940,14 @@ class Mixin_GalleryStorage_Base_Management extends Mixin
4878
  if (is_writable($full_abspath) && is_writable(dirname($full_abspath))) {
4879
  // Copy the backup
4880
  if (@copy($backup_abspath, $full_abspath)) {
 
 
4881
  // Re-create non-fullsize image sizes
4882
  foreach ($this->object->get_image_sizes($image) as $named_size) {
4883
  if ($named_size == 'full') {
4884
  continue;
4885
  }
4886
- $this->object->generate_image_clone($backup_abspath, $this->object->get_image_abspath($image, $named_size), $this->object->get_image_size_params($image, $named_size));
4887
  }
4888
  do_action('ngg_recovered_image', $image);
4889
  // Reimport all metadata
@@ -4983,73 +5047,80 @@ class Mixin_GalleryStorage_Base_MediaLibrary extends Mixin
4983
  */
4984
  class Mixin_GalleryStorage_Base_Upload extends Mixin
4985
  {
4986
- function import_gallery_from_fs($abspath, $gallery = FALSE, $create_new_gallerypath = TRUE, $gallery_title = NULL, $filenames = array())
 
 
 
 
 
 
 
 
4987
  {
4988
- $retval = FALSE;
4989
- if (@file_exists($abspath)) {
4990
- $fs = C_Fs::get_instance();
4991
- // Ensure that this folder has images
4992
- // Ensure that this folder has images
4993
- $i = 0;
4994
- $files = array();
4995
- foreach (scandir($abspath) as $file) {
4996
- if ($file == '.' || $file == '..') {
4997
- continue;
4998
- }
4999
- $file_abspath = $fs->join_paths($abspath, $file);
5000
- // The first directory is considered valid
5001
- if (is_dir($file_abspath) && $i === 0) {
 
 
 
5002
  $files[] = $file_abspath;
5003
- } elseif ($this->is_image_file($file_abspath)) {
5004
- if ($filenames && array_search($file_abspath, $filenames) !== FALSE) {
5005
  $files[] = $file_abspath;
5006
- } else {
5007
- if (!$filenames) {
5008
- $files[] = $file_abspath;
5009
- }
5010
  }
5011
  }
5012
  }
5013
- if (!empty($files)) {
5014
- // Get needed utilities
5015
- $gallery_mapper = C_Gallery_Mapper::get_instance();
5016
- // Sometimes users try importing a directory, which actually has all images under another directory
5017
- if (is_dir($files[0])) {
5018
- return $this->object->import_gallery_from_fs($files[0], $gallery_id, $create_new_gallerypath, $gallery_title, $filenames);
5019
- }
5020
- // If no gallery has been specified, then use the directory name as the gallery name
5021
- if (!$gallery) {
5022
- // Create the gallery
5023
- $gallery = $gallery_mapper->create(array('title' => $gallery_title ? $gallery_title : M_I18n::mb_basename($abspath)));
5024
- if (!$create_new_gallerypath) {
5025
- $gallery_root = $fs->get_document_root('gallery');
5026
- $gallery->path = str_ireplace($gallery_root, '', $abspath);
5027
- }
5028
- // Save the gallery
5029
- if ($gallery->save()) {
5030
- $gallery_id = $gallery->id();
5031
- }
5032
- }
5033
- // Ensure that we have a gallery id
5034
- if ($gallery_id) {
5035
- $retval = array('gallery_id' => $gallery_id, 'image_ids' => array());
5036
- foreach ($files as $file_abspath) {
5037
- if (!preg_match("/\\.(jpg|jpeg|gif|png)\$/i", $file_abspath)) {
5038
- continue;
5039
- }
5040
- $image = null;
5041
- if ($image_id = $this->import_image_file($gallery_id, $file_abspath, FALSE, FALSE, FALSE, FALSE)) {
5042
- $retval['image_ids'][] = $image;
5043
- }
5044
- }
5045
- // Add the gallery name to the result
5046
- $gallery = $gallery_mapper->find($gallery_id);
5047
- $retval['gallery_name'] = $gallery->title;
5048
- unset($gallery);
5049
  }
5050
  }
 
 
 
 
 
 
5051
  }
5052
- return $retval;
5053
  }
5054
  function is_current_user_over_quota()
5055
  {
@@ -5061,6 +5132,10 @@ class Mixin_GalleryStorage_Base_Upload extends Mixin
5061
  }
5062
  return $retval;
5063
  }
 
 
 
 
5064
  function is_image_file($filename = NULL)
5065
  {
5066
  $retval = FALSE;
@@ -5158,7 +5233,6 @@ class Mixin_GalleryStorage_Base_Upload extends Mixin
5158
  throw new E_InsufficientWriteAccessException(FALSE, $gallery_abspath, FALSE);
5159
  }
5160
  // Sanitize the filename for storing in the DB
5161
- $original_filename = $filename = preg_replace("#^/#", "", $filename ? $filename : basename($image_abspath));
5162
  $filename = $this->sanitize_filename_for_db($filename);
5163
  // Ensure that the filename is valid
5164
  if (!preg_match("/(png|jpeg|jpg|gif)\$/i", $filename)) {
@@ -5224,6 +5298,8 @@ class Mixin_GalleryStorage_Base_Upload extends Mixin
5224
  if ($settings->get('imgBackup', FALSE)) {
5225
  $this->object->backup_image($image, TRUE);
5226
  }
 
 
5227
  // Create resized version of image
5228
  if ($settings->get('imgAutoResize', FALSE)) {
5229
  $this->object->generate_resized_image($image, TRUE);
@@ -5237,7 +5313,7 @@ class Mixin_GalleryStorage_Base_Upload extends Mixin
5237
  // delete dirsize after adding new images
5238
  delete_transient('dirsize_cache');
5239
  // Seems redundant to above hook. Maintaining for legacy purposes
5240
- do_action('ngg_after_new_images_added', is_numeric($dst_gallery) ? $dst_gallery : $dst_gallery->gid, array($image));
5241
  return $image_id;
5242
  } else {
5243
  throw new E_EntityNotFoundException();
@@ -5320,7 +5396,7 @@ class Mixin_GalleryStorage_Base_Upload extends Mixin
5320
  $fs = C_Fs::get_instance();
5321
  // Uses the WordPress ZIP abstraction API
5322
  include_once $fs->join_paths(ABSPATH, 'wp-admin', 'includes', 'file.php');
5323
- WP_Filesystem();
5324
  // Ensure that we truly have the gallery id
5325
  $gallery_id = $this->_get_gallery_id($gallery_id);
5326
  $zipfile = $_FILES['file']['tmp_name'];
622
  self::load_pel();
623
  return @C_Exif_Writer::read_metadata($filename);
624
  }
625
+ /**
626
+ * @param array $exif
627
+ * @return array
628
+ */
629
+ public static function reset_orientation($exif = array())
630
+ {
631
+ if (!M_NextGen_Data::check_pel_min_php_requirement()) {
632
+ return array();
633
+ }
634
+ self::load_pel();
635
+ return @C_Exif_Writer::reset_orientation($exif);
636
+ }
637
  /**
638
  * @param $filename
639
  * @param $metadata
839
  }
840
  function _save_entity($entity)
841
  {
842
+ $storage = C_Gallery_Storage::get_instance();
843
  // A bug in NGG 2.1.24 allowed galleries to be created with spaces in the directory name, unreplaced by dashes
844
  // This causes a few problems everywhere, so we here allow users a way to fix those galleries by just re-saving
845
  if (FALSE !== strpos($entity->path, ' ')) {
 
846
  $abspath = $storage->get_gallery_abspath($entity->{$entity->id_field});
847
  $pre_path = $entity->path;
848
  $entity->path = str_replace(' ', '-', $entity->path);
871
  }
872
  $retval = $this->call_parent('_save_entity', $entity);
873
  if ($retval) {
874
+ wp_mkdir_p($storage->get_gallery_abspath($entity));
875
  do_action('ngg_created_new_gallery', $entity->{$entity->id_field});
876
  C_Photocrati_Transient_Manager::flush('displayed_gallery_rendering');
877
  }
3675
  }
3676
  if ($rotation && in_array(abs($rotation), array(90, 180, 270))) {
3677
  $thumbnail->rotateImageAngle($rotation);
3678
+ $remove_orientation_exif = TRUE;
3679
+ } else {
3680
+ $remove_orientation_exif = FALSE;
3681
  }
3682
  $flip = strtolower($flip);
3683
  if ($flip && in_array($flip, array('h', 'v', 'hv'))) {
3695
  $thumbnail = apply_filters('ngg_before_save_thumbnail', $thumbnail);
3696
  $exif_iptc = @C_Exif_Writer_Wrapper::read_metadata($image_path);
3697
  $thumbnail->save($destpath, $quality);
3698
+ // We've just rotated the image however the EXIF metadata contains an Orientation tag. To prevent
3699
+ // certain browsers from rotating our already-rotated image we reset the Orientation tag to the default.
3700
+ if ($remove_orientation_exif && !empty($exif_iptc['exif'])) {
3701
+ $exif_iptc['exif'] = @C_Exif_Writer_Wrapper::reset_orientation($exif_iptc['exif']);
3702
+ }
3703
  @C_Exif_Writer_Wrapper::write_metadata($destpath, $exif_iptc);
3704
  }
3705
  }
4032
  $image_abspath = $this->object->get_image_abspath($image, 'full');
4033
  $generated = $this->object->generate_image_clone($image_abspath, $image_abspath, $this->object->get_image_size_params($image, 'full'));
4034
  if ($generated && $save) {
4035
+ $this->object->update_image_dimension_metadata($image, $image_abspath);
4036
+ }
4037
+ }
4038
+ public function update_image_dimension_metadata($image, $image_abspath)
4039
+ {
4040
+ // Ensure that fullsize dimensions are added to metadata array
4041
+ $dimensions = getimagesize($image_abspath);
4042
+ $full_meta = array('width' => $dimensions[0], 'height' => $dimensions[1], 'md5' => $this->object->get_image_checksum($image, 'full'));
4043
+ if (!isset($image->meta_data) or is_string($image->meta_data) && strlen($image->meta_data) == 0 or is_bool($image->meta_data)) {
4044
+ $image->meta_data = array();
4045
+ }
4046
+ $image->meta_data = array_merge($image->meta_data, $full_meta);
4047
+ $image->meta_data['full'] = $full_meta;
4048
+ // Don't forget to append the 'full' entry in meta_data in the db
4049
+ $this->object->_image_mapper->save($image);
4050
+ }
4051
+ /**
4052
+ * Most major browsers do not honor the Orientation meta found in EXIF. To prevent display issues we inspect
4053
+ * the EXIF data and rotate the image so that the EXIF field is not necessary to display the image correctly.
4054
+ * Note: generate_image_clone() will handle the removal of the Orientation tag inside the image EXIF.
4055
+ * Note: This only handles single-dimension rotation; at the time this method was written there are no known
4056
+ * camera manufacturers that both rotate and flip images.
4057
+ * @param $image
4058
+ * @param bool $save
4059
+ */
4060
+ public function correct_exif_rotation($image, $save = TRUE)
4061
+ {
4062
+ $image_abspath = $this->object->get_image_abspath($image, 'full');
4063
+ // This method is necessary
4064
+ if (!function_exists('exif_read_data')) {
4065
+ return;
4066
+ }
4067
+ // We only need to continue if the Orientation tag is set
4068
+ $exif = @exif_read_data($image_abspath, 'exif');
4069
+ if (empty($exif['Orientation']) || $exif['Orientation'] == 1) {
4070
+ return;
4071
+ }
4072
+ $degree = 0;
4073
+ if ($exif['Orientation'] == 3) {
4074
+ $degree = 180;
4075
+ }
4076
+ if ($exif['Orientation'] == 6) {
4077
+ $degree = 90;
4078
+ }
4079
+ if ($exif['Orientation'] == 8) {
4080
+ $degree = 270;
4081
+ }
4082
+ $parameters = array('rotation' => $degree);
4083
+ $generated = $this->object->generate_image_clone($image_abspath, $image_abspath, $this->object->get_image_size_params($image, 'full', $parameters), $parameters);
4084
+ if ($generated && $save) {
4085
+ $this->object->update_image_dimension_metadata($image, $image_abspath);
4086
  }
4087
  }
4088
  /**
4539
  * Returns the named sizes available for images
4540
  * @return array
4541
  */
4542
+ function get_image_sizes($image = FALSE)
4543
  {
4544
  $retval = array('full', 'thumbnail');
4545
  if (is_numeric($image)) {
4940
  if (is_writable($full_abspath) && is_writable(dirname($full_abspath))) {
4941
  // Copy the backup
4942
  if (@copy($backup_abspath, $full_abspath)) {
4943
+ // Backup images are not altered at all; we must re-correct the EXIF/Orientation tag
4944
+ $this->object->correct_exif_rotation($image, TRUE);
4945
  // Re-create non-fullsize image sizes
4946
  foreach ($this->object->get_image_sizes($image) as $named_size) {
4947
  if ($named_size == 'full') {
4948
  continue;
4949
  }
4950
+ $this->object->generate_image_clone($full_abspath, $this->object->get_image_abspath($image, $named_size), $this->object->get_image_size_params($image, $named_size));
4951
  }
4952
  do_action('ngg_recovered_image', $image);
4953
  // Reimport all metadata
5047
  */
5048
  class Mixin_GalleryStorage_Base_Upload extends Mixin
5049
  {
5050
+ /**
5051
+ * @param string $abspath
5052
+ * @param int $gallery_id
5053
+ * @param bool $create_new_gallerypath
5054
+ * @param null|string $gallery_title
5055
+ * @param array[string] $filenames
5056
+ * @return array|bool FALSE on failure
5057
+ */
5058
+ function import_gallery_from_fs($abspath, $gallery_id = NULL, $create_new_gallerypath = TRUE, $gallery_title = NULL, $filenames = array())
5059
  {
5060
+ if (@(!file_exists($abspath))) {
5061
+ return FALSE;
5062
+ }
5063
+ $fs = C_Fs::get_instance();
5064
+ // Ensure that this folder has images
5065
+ $i = 0;
5066
+ $files = array();
5067
+ foreach (scandir($abspath) as $file) {
5068
+ if ($file == '.' || $file == '..') {
5069
+ continue;
5070
+ }
5071
+ $file_abspath = $fs->join_paths($abspath, $file);
5072
+ // The first directory is considered valid
5073
+ if (is_dir($file_abspath) && $i === 0) {
5074
+ $files[] = $file_abspath;
5075
+ } elseif ($this->is_image_file($file_abspath)) {
5076
+ if ($filenames && array_search($file_abspath, $filenames) !== FALSE) {
5077
  $files[] = $file_abspath;
5078
+ } else {
5079
+ if (!$filenames) {
5080
  $files[] = $file_abspath;
 
 
 
 
5081
  }
5082
  }
5083
  }
5084
+ }
5085
+ if (empty($files)) {
5086
+ return FALSE;
5087
+ }
5088
+ // Get needed utilities
5089
+ $gallery_mapper = C_Gallery_Mapper::get_instance();
5090
+ // Sometimes users try importing a directory, which actually has all images under another directory
5091
+ if (is_dir($files[0])) {
5092
+ return $this->object->import_gallery_from_fs($files[0], $gallery_id, $create_new_gallerypath, $gallery_title, $filenames);
5093
+ }
5094
+ // If no gallery has been specified, then use the directory name as the gallery name
5095
+ if (!$gallery_id) {
5096
+ // Create the gallery
5097
+ $gallery = $gallery_mapper->create(array('title' => $gallery_title ? $gallery_title : M_I18n::mb_basename($abspath)));
5098
+ if (!$create_new_gallerypath) {
5099
+ $gallery_root = $fs->get_document_root('gallery');
5100
+ $gallery->path = str_ireplace($gallery_root, '', $abspath);
5101
+ }
5102
+ // Save the gallery
5103
+ if ($gallery->save()) {
5104
+ $gallery_id = $gallery->id();
5105
+ }
5106
+ }
5107
+ // Ensure that we have a gallery id
5108
+ if ($gallery_id) {
5109
+ $retval = array('gallery_id' => $gallery_id, 'image_ids' => array());
5110
+ foreach ($files as $file_abspath) {
5111
+ $basename = pathinfo($file_abspath, PATHINFO_BASENAME);
5112
+ if ($image_id = $this->import_image_file($gallery_id, $file_abspath, $basename, FALSE, FALSE, FALSE)) {
5113
+ $retval['image_ids'][] = $image_id;
 
 
 
 
 
 
5114
  }
5115
  }
5116
+ // Add the gallery name to the result
5117
+ if (!isset($gallery)) {
5118
+ $gallery = $gallery_mapper->find($gallery_id);
5119
+ }
5120
+ $retval['gallery_name'] = $gallery->title;
5121
+ return $retval;
5122
  }
5123
+ return FALSE;
5124
  }
5125
  function is_current_user_over_quota()
5126
  {
5132
  }
5133
  return $retval;
5134
  }
5135
+ /**
5136
+ * @param string? $filename
5137
+ * @return bool
5138
+ */
5139
  function is_image_file($filename = NULL)
5140
  {
5141
  $retval = FALSE;
5233
  throw new E_InsufficientWriteAccessException(FALSE, $gallery_abspath, FALSE);
5234
  }
5235
  // Sanitize the filename for storing in the DB
 
5236
  $filename = $this->sanitize_filename_for_db($filename);
5237
  // Ensure that the filename is valid
5238
  if (!preg_match("/(png|jpeg|jpg|gif)\$/i", $filename)) {
5298
  if ($settings->get('imgBackup', FALSE)) {
5299
  $this->object->backup_image($image, TRUE);
5300
  }
5301
+ // Most browsers do not honor EXIF's Orientation header: rotate the image to prevent display issues
5302
+ $this->object->correct_exif_rotation($image, TRUE);
5303
  // Create resized version of image
5304
  if ($settings->get('imgAutoResize', FALSE)) {
5305
  $this->object->generate_resized_image($image, TRUE);
5313
  // delete dirsize after adding new images
5314
  delete_transient('dirsize_cache');
5315
  // Seems redundant to above hook. Maintaining for legacy purposes
5316
+ do_action('ngg_after_new_images_added', is_numeric($dst_gallery) ? $dst_gallery : $dst_gallery->gid, array($image_id));
5317
  return $image_id;
5318
  } else {
5319
  throw new E_EntityNotFoundException();
5396
  $fs = C_Fs::get_instance();
5397
  // Uses the WordPress ZIP abstraction API
5398
  include_once $fs->join_paths(ABSPATH, 'wp-admin', 'includes', 'file.php');
5399
+ WP_Filesystem(FALSE, get_temp_dir(), TRUE);
5400
  // Ensure that we truly have the gallery id
5401
  $gallery_id = $this->_get_gallery_id($gallery_id);
5402
  $zipfile = $_FILES['file']['tmp_name'];
products/photocrati_nextgen/modules/nextgen_data/pel-0.9.6/class.exif_writer.php CHANGED
@@ -16,6 +16,8 @@ use lsolesen\pel\PelJpeg;
16
  use lsolesen\pel\PelTiff;
17
  use lsolesen\pel\PelExif;
18
  use lsolesen\pel\PelIfd;
 
 
19
 
20
  use lsolesen\pel\PelInvalidArgumentException;
21
  use lsolesen\pel\PelIfdException;
@@ -210,4 +212,31 @@ class C_Exif_Writer
210
  $extension = M_I18n::mb_pathinfo($filename, PATHINFO_EXTENSION);
211
  return in_array(strtolower($extension), array('jpeg', 'jpg', 'jpeg_backup', 'jpg_backup')) ? TRUE : FALSE;
212
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  }
16
  use lsolesen\pel\PelTiff;
17
  use lsolesen\pel\PelExif;
18
  use lsolesen\pel\PelIfd;
19
+ use lsolesen\pel\PelTag;
20
+ use lsolesen\pel\PelEntryShort;
21
 
22
  use lsolesen\pel\PelInvalidArgumentException;
23
  use lsolesen\pel\PelIfdException;
212
  $extension = M_I18n::mb_pathinfo($filename, PATHINFO_EXTENSION);
213
  return in_array(strtolower($extension), array('jpeg', 'jpg', 'jpeg_backup', 'jpg_backup')) ? TRUE : FALSE;
214
  }
215
+
216
+ /**
217
+ * Sets the EXIF' Orientation field to 1 aka Default or "TopLeft"
218
+ *
219
+ * This method is necessary to prevent images rotated by NextGen to appear even further rotated.
220
+ * @param array $exif
221
+ * @return array
222
+ */
223
+ static public function reset_orientation($exif = array())
224
+ {
225
+ $tiff = $exif->getTiff();
226
+ if (empty($tiff))
227
+ return $exif;
228
+
229
+ $ifd0 = $tiff->getIfd();
230
+ if (empty($ifd0))
231
+ return $exif;
232
+
233
+ $orientation = $ifd0->getEntry(PelTag::ORIENTATION);
234
+ if (empty($orientation))
235
+ return $exif;
236
+
237
+ $orientation = new PelEntryShort(PelTag::ORIENTATION, 1);
238
+ $ifd0->addEntry($orientation);
239
+
240
+ return $exif;
241
+ }
242
  }
products/photocrati_nextgen/modules/nextgen_gallery_display/module.nextgen_gallery_display.php CHANGED
@@ -23,10 +23,10 @@ class M_Gallery_Display extends C_Base_Module
23
  'photocrati-nextgen_gallery_display',
24
  'Gallery Display',
25
  'Provides the ability to display gallery of images',
26
- '3.1.8',
27
  'https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/',
28
- 'Imagely',
29
- 'https://www.imagely.com'
30
  );
31
 
32
  C_Photocrati_Installer::add_handler($this->module_id, 'C_Display_Type_Installer');
@@ -523,7 +523,8 @@ class C_Display_Type_Installer
523
  // Try to find the existing entity. If it doesn't exist, we'll create
524
  $fs = C_Fs::get_instance();
525
  $mapper = C_Display_Type_Mapper::get_instance();
526
- $display_type = $mapper->find_by_name($name);
 
527
  if (!$display_type) $display_type = new stdClass;
528
 
529
  // Update the properties of the display type
@@ -534,7 +535,7 @@ class C_Display_Type_Installer
534
  }
535
 
536
  // Save the entity
537
- $retval = $mapper->save($display_type);
538
  return $retval;
539
  }
540
 
@@ -562,7 +563,16 @@ class C_Display_Type_Installer
562
  */
563
  function install($reset=FALSE)
564
  {
565
- // Display types are registered in other modules
 
 
 
 
 
 
 
 
 
566
  }
567
 
568
  /**
23
  'photocrati-nextgen_gallery_display',
24
  'Gallery Display',
25
  'Provides the ability to display gallery of images',
26
+ '3.1.14',
27
  'https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/',
28
+ 'Imagely',
29
+ 'https://www.imagely.com'
30
  );
31
 
32
  C_Photocrati_Installer::add_handler($this->module_id, 'C_Display_Type_Installer');
523
  // Try to find the existing entity. If it doesn't exist, we'll create
524
  $fs = C_Fs::get_instance();
525
  $mapper = C_Display_Type_Mapper::get_instance();
526
+ $display_type = $mapper->find_by_name($name);
527
+ $mapper->flush_query_cache();
528
  if (!$display_type) $display_type = new stdClass;
529
 
530
  // Update the properties of the display type
535
  }
536
 
537
  // Save the entity
538
+ $retval = $mapper->save($display_type);
539
  return $retval;
540
  }
541
 
563
  */
564
  function install($reset=FALSE)
565
  {
566
+ // Note: NGG Display types are registered in other modules
567
+
568
+ // Force Pro display types to register themselves
569
+ if (class_exists('C_NextGen_Pro_Installer')) {
570
+ $pro_installer = new C_NextGen_Pro_Installer();
571
+ $pro_installer->install_display_types();
572
+ } elseif (class_exists('C_NextGen_Plus_Installer')) {
573
+ $plus_installer = new C_NextGen_Plus_Installer();
574
+ $plus_installer->install_display_types();
575
+ }
576
  }
577
 
578
  /**
products/photocrati_nextgen/modules/ngglegacy/admin/edit-thumbnail.php CHANGED
@@ -142,7 +142,7 @@ if ($thumbnail_crop_frame != null)
142
 
143
  jQuery('#thumbMsg').html("<?php _e('Thumbnail updated', 'nggallery') ?>");
144
  jQuery('#thumbMsg').css({'display':'block'});
145
- setTimeout(function(){ jQuery('#thumbMsg').fadeOut('slow'); }, 1500);
146
  },
147
  error: function() {
148
  jQuery('#thumbMsg').html("<?php _e('Error updating thumbnail', 'nggallery') ?>");
@@ -177,8 +177,8 @@ if ($thumbnail_crop_frame != null)
177
  </tr>
178
  </table>
179
  <div id="ngg-overlay-dialog-bottom">
 
180
  <input type="button" name="update" value="<?php esc_attr_e('Update', 'nggallery'); ?>" onclick="updateThumb()" class="button-secondary" />
181
- <div id="thumbMsg" ></div>
182
  </div>
183
 
184
  <script type="text/javascript">
142
 
143
  jQuery('#thumbMsg').html("<?php _e('Thumbnail updated', 'nggallery') ?>");
144
  jQuery('#thumbMsg').css({'display':'block'});
145
+ setTimeout(function(){ jQuery('#thumbMsg').html(''); }, 1500);
146
  },
147
  error: function() {
148
  jQuery('#thumbMsg').html("<?php _e('Error updating thumbnail', 'nggallery') ?>");
177
  </tr>
178
  </table>
179
  <div id="ngg-overlay-dialog-bottom">
180
+ <div id="thumbMsg"></div>
181
  <input type="button" name="update" value="<?php esc_attr_e('Update', 'nggallery'); ?>" onclick="updateThumb()" class="button-secondary" />
 
182
  </div>
183
 
184
  <script type="text/javascript">
products/photocrati_nextgen/modules/ngglegacy/admin/manage-images.php CHANGED
@@ -161,6 +161,11 @@ jQuery(function (){
161
  var height = ( results ) ? results[1] : 500;
162
  var container = window;
163
 
 
 
 
 
 
164
  if (window.parent) {
165
  container = window.parent;
166
  }
@@ -634,7 +639,21 @@ jQuery(document).ready( function($) {
634
 
635
  <script type="text/javascript">
636
  /* <![CDATA[ */
637
- jQuery(document).ready(function(){columns.init('nggallery-manage-images');});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
638
  /* ]]> */
639
  </script>
640
  <?php
161
  var height = ( results ) ? results[1] : 500;
162
  var container = window;
163
 
164
+ var screen_width = window.innerWidth - 120;
165
+ var screen_height = window.innerHeight - 200;
166
+ width = (width > screen_width) ? screen_width : width;
167
+ height = (height > screen_height) ? screen_height : height;
168
+
169
  if (window.parent) {
170
  container = window.parent;
171
  }
639
 
640
  <script type="text/javascript">
641
  /* <![CDATA[ */
642
+ jQuery(document).ready(function($){
643
+ columns.init('nggallery-manage-images');
644
+
645
+ // Ensure that thumb preview images are always up-to-date
646
+ $('#ngg-listimages img.thumb').each(function(){
647
+ var $this = $(this);
648
+ var src = $this.attr('src');
649
+ var matchData = src.match(/\?i=(\d+)$/)
650
+ if (matchData) {
651
+ var i = parseInt(matchData[1])+1
652
+ src = src.replace(matchData[0], "?i="+i.toString())
653
+ $this.attr('src', src);
654
+ }
655
+ })
656
+ });
657
  /* ]]> */
658
  </script>
659
  <?php
products/photocrati_nextgen/modules/ngglegacy/module.ngglegacy.php CHANGED
@@ -23,7 +23,7 @@ class M_NggLegacy extends C_Base_Module
23
  'photocrati-nextgen-legacy',
24
  'NextGEN Legacy',
25
  'Embeds the original version of NextGEN 1.9.3 by Alex Rabe',
26
- '3.1.10',
27
  'https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/',
28
  'Imagely',
29
  'https://www.imagely.com'
23
  'photocrati-nextgen-legacy',
24
  'NextGEN Legacy',
25
  'Embeds the original version of NextGEN 1.9.3 by Alex Rabe',
26
+ '3.1.14',
27
  'https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/',
28
  'Imagely',
29
  'https://www.imagely.com'
products/photocrati_nextgen/modules/third_party_compat/module.third_party_compat.php CHANGED
@@ -16,7 +16,7 @@ class M_Third_Party_Compat extends C_Base_Module
16
  'photocrati-third_party_compat',
17
  'Third Party Compatibility',
18
  "Adds Third party compatibility hacks, adjustments, and modifications",
19
- '3.1.4.2',
20
  'https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/',
21
  'Imagely',
22
  'https://www.imagely.com'
@@ -91,6 +91,12 @@ class M_Third_Party_Compat extends C_Base_Module
91
  if (!defined('NGG_DISABLE_FILTER_THE_CONTENT')) define('NGG_DISABLE_FILTER_THE_CONTENT', TRUE);
92
  if (!defined('NGG_DISABLE_RESOURCE_MANAGER')) define('NGG_DISABLE_RESOURCE_MANAGER', TRUE);
93
  }
 
 
 
 
 
 
94
  }
95
 
96
  function _register_adapters()
16
  'photocrati-third_party_compat',
17
  'Third Party Compatibility',
18
  "Adds Third party compatibility hacks, adjustments, and modifications",
19
+ '3.1.11.1',
20
  'https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/',
21
  'Imagely',
22
  'https://www.imagely.com'
91
  if (!defined('NGG_DISABLE_FILTER_THE_CONTENT')) define('NGG_DISABLE_FILTER_THE_CONTENT', TRUE);
92
  if (!defined('NGG_DISABLE_RESOURCE_MANAGER')) define('NGG_DISABLE_RESOURCE_MANAGER', TRUE);
93
  }
94
+
95
+ // Elementor's graphical builder is broken by our resource manager
96
+ if (defined('ELEMENTOR_VERSION'))
97
+ {
98
+ if (!defined('NGG_DISABLE_RESOURCE_MANAGER')) define('NGG_DISABLE_RESOURCE_MANAGER', TRUE);
99
+ }
100
  }
101
 
102
  function _register_adapters()
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Contributors: photocrati, imagely
3
  Tags: wordpress gallery plugin, gallery, nextgen, nextgen gallery, photo gallery, image gallery, photography, slideshow, images, photo, photo album, watermark
4
  Requires at least: 4.0.0
5
- Stable tag: 3.1.11
6
  Tested up to: 5.1.1
7
  License: GPLv2
8
 
@@ -183,6 +183,19 @@ For more information, feel free to visit the official website for the NextGEN Ga
183
 
184
  == Changelog ==
185
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  = V3.1.11 - 03.020.2019 =
187
  * NEW: Many performance enhancements
188
  * Fixed: Broken Overview page on WordPress 5.1
2
  Contributors: photocrati, imagely
3
  Tags: wordpress gallery plugin, gallery, nextgen, nextgen gallery, photo gallery, image gallery, photography, slideshow, images, photo, photo album, watermark
4
  Requires at least: 4.0.0
5
+ Stable tag: 3.1.14
6
  Tested up to: 5.1.1
7
  License: GPLv2
8
 
183
 
184
  == Changelog ==
185
 
186
+ = V3.1.14 - 03.26.2019 =
187
+ * Changed: Restored original behavior of ngg_after_new_images_added hook
188
+ * Changed: Images with EXIF rotation metadata are now rotated automatically at upload
189
+ * Changed: Moved confirmation message presented after editing a thumbnail
190
+ * Fixed: Ability to import zips of images
191
+ * Fixed: Gallery folder not created on filesystem after adding new gallery
192
+ * Fixed: IGW not working with Gutenberg / Block Editor
193
+ * Fixed: Compatibility with EWWW Image Optimizer
194
+ * Fixed: Compatibility with Elementor
195
+ * Fixed: Compatibility with Imagify
196
+ * Fixed: NextGen 3.1.11 passed an incorrect path to load_plugin_textdomain()
197
+ * Fixed: Simplelightbox initialization was opening more than once for certain images
198
+
199
  = V3.1.11 - 03.020.2019 =
200
  * NEW: Many performance enhancements
201
  * Fixed: Broken Overview page on WordPress 5.1