/products/photocrati_nextgen/modules/nextgen_gallery_display/package.module.nextgen_gallery_display.php

  1. <?php 
  2. class A_Display_Settings_Controller extends Mixin 
  3. /** 
  4. * Static resources required for the Display Settings page 
  5. */ 
  6. public function enqueue_backend_resources() 
  7. $this->call_parent('enqueue_backend_resources'); 
  8. wp_enqueue_style('nextgen_gallery_display_settings'); 
  9. wp_enqueue_script('nextgen_gallery_display_settings'); 
  10. public function get_page_title() 
  11. return __('Gallery Settings', 'nggallery'); 
  12. public function get_required_permission() 
  13. return 'NextGEN Change options'; 
  14. class A_Display_Settings_Page extends Mixin 
  15. public function setup() 
  16. $this->object->add(NGG_DISPLAY_SETTINGS_SLUG, array('adapter' => 'A_Display_Settings_Controller', 'parent' => NGGFOLDER, 'before' => 'ngg_other_options')); 
  17. return $this->call_parent('setup'); 
  18. class A_Displayed_Gallery_Trigger_Element extends Mixin 
  19. public function render_object() 
  20. $root_element = $this->call_parent('render_object'); 
  21. if (($displayed_gallery = $this->object->get_param('displayed_gallery')) && $this->object->get_param('display_type_rendering')) { 
  22. $triggers = C_Displayed_Gallery_Trigger_Manager::get_instance(); 
  23. $triggers->render($root_element, $displayed_gallery); 
  24. return $root_element; 
  25. class A_Displayed_Gallery_Trigger_Resources extends Mixin 
  26. protected $run_once = FALSE; 
  27. public function enqueue_frontend_resources($displayed_gallery) 
  28. $this->call_parent('enqueue_frontend_resources', $displayed_gallery); 
  29. return $this->enqueue_displayed_gallery_trigger_buttons_resources($displayed_gallery); 
  30. public function enqueue_displayed_gallery_trigger_buttons_resources($displayed_gallery = FALSE) 
  31. $retval = FALSE; 
  32. M_Gallery_Display::enqueue_fontawesome(); 
  33. if (!$this->run_once && !empty($displayed_gallery) && !empty($displayed_gallery->display_settings['ngg_triggers_display']) && $displayed_gallery->display_settings['ngg_triggers_display'] !== 'never') { 
  34. $pro_active = FALSE; 
  35. if (defined('NGG_PRO_PLUGIN_VERSION')) { 
  36. $pro_active = 'NGG_PRO_PLUGIN_VERSION'; 
  37. if (defined('NEXTGEN_GALLERY_PRO_VERSION')) { 
  38. $pro_active = 'NEXTGEN_GALLERY_PRO_VERSION'; 
  39. if (!empty($pro_active)) { 
  40. $pro_active = constant($pro_active); 
  41. if (!is_admin() && (empty($pro_active) || version_compare($pro_active, '1.0.11') >= 0)) { 
  42. wp_enqueue_style('fontawesome'); 
  43. $retval = TRUE; 
  44. $this->run_once = TRUE; 
  45. return $retval; 
  46. class A_Gallery_Display_Factory extends Mixin 
  47. /** 
  48. * Instantiates a Display Type 
  49. * @param C_DataMapper $mapper 
  50. * @param array|stdClass|C_DataMapper_Model $properties 
  51. * @param string|array|FALSE $context 
  52. */ 
  53. public function display_type($properties = array(), $mapper = FALSE, $context = FALSE) 
  54. return new C_Display_Type($properties, $mapper, $context); 
  55. /** 
  56. * Instantiates a Displayed Gallery 
  57. * @param C_DataMapper $mapper 
  58. * @param array|stdClass|C_DataMapper_Model $properties 
  59. * @param string|array|FALSE $context 
  60. */ 
  61. public function displayed_gallery($properties = array(), $mapper = FALSE, $context = FALSE) 
  62. return new C_Displayed_Gallery($properties, $mapper, $context); 
  63. class A_Gallery_Display_View extends Mixin 
  64. /** 
  65. * Check whether to render certain kinds of extra additions to the view for a displayed gallery 
  66. * @param object $displayed_gallery 
  67. * @param string $template_id 
  68. * @param C_MVC_View_Element $root_element 
  69. * @param string $addition_type what kind of addition is being made 'layout', 'decoration', 'style', 'logic' etc. 
  70. * @return string|NULL 
  71. */ 
  72. public function _check_addition_rendering($displayed_gallery, $template_id, $root_element, $addition_type) 
  73. $view = $root_element->get_object(); 
  74. $mode = $view->get_param('render_mode'); 
  75. $ret = true; 
  76. switch ($addition_type) { 
  77. case 'layout': 
  78. $ret = !in_array($mode, array('bare', 'basic')); 
  79. break; 
  80. case 'decoration': 
  81. break; 
  82. case 'style': 
  83. break; 
  84. case 'logic': 
  85. break; 
  86. return $ret; 
  87. /** 
  88. * A Display Type is a component which renders a collection of images 
  89. * in a "gallery". 
  90. * 
  91. * Properties: 
  92. * - entity_types (gallery, album) 
  93. * - name (nextgen_basic-thumbnails) 
  94. * - title (NextGEN Basic Thumbnails) 
  95. */ 
  96. class C_Display_Type extends C_DataMapper_Model 
  97. public $_mapper_interface = 'I_Display_Type_Mapper'; 
  98. public function define($properties = array(), $mapper = FALSE, $context = FALSE) 
  99. parent::define($mapper, $properties, $context); 
  100. $this->add_mixin('Mixin_Display_Type_Validation'); 
  101. $this->add_mixin('Mixin_Display_Type_Instance_Methods'); 
  102. $this->implement('I_Display_Type'); 
  103. /** 
  104. * Initializes a display type with properties 
  105. * @param FALSE|C_Display_Type_Mapper $mapper 
  106. * @param array|stdClass|C_Display_Type $properties 
  107. * @param FALSE|string|array $context 
  108. */ 
  109. public function initialize($properties = array(), $mapper = FALSE, $context = FALSE) 
  110. // If no mapper was specified, then get the mapper 
  111. if (!$mapper) { 
  112. $mapper = $this->get_registry()->get_utility($this->_mapper_interface); 
  113. // Construct the model 
  114. parent::initialize($mapper, $properties); 
  115. /** 
  116. * Allows a setting to be retrieved directly, rather than through the 
  117. * settings property 
  118. * @param string $property 
  119. * @return mixed 
  120. */ 
  121. public function &__get($property) 
  122. if (isset($this->settings) && isset($this->settings[$property])) { 
  123. $retval =& $this->settings[$property]; 
  124. return $retval; 
  125. } else { 
  126. return parent::__get($property); 
  127. class Mixin_Display_Type_Validation extends Mixin 
  128. public function validation() 
  129. $this->object->validates_presence_of('entity_types'); 
  130. $this->object->validates_presence_of('name'); 
  131. $this->object->validates_presence_of('title'); 
  132. return $this->object->is_valid(); 
  133. /** 
  134. * Provides methods available for class instances 
  135. */ 
  136. class Mixin_Display_Type_Instance_Methods extends Mixin 
  137. /** 
  138. * Determines if this display type is compatible with a displayed gallery 
  139. * source 
  140. * @param stdClass 
  141. * @return bool 
  142. */ 
  143. public function is_compatible_with_source($source) 
  144. return C_Displayed_Gallery_Source_Manager::get_instance()->is_compatible($source, $this); 
  145. public function get_order() 
  146. return NGG_DISPLAY_PRIORITY_BASE; 
  147. /** 
  148. * A Controller which displays the settings form for the display type, as 
  149. * well as the front-end display 
  150. */ 
  151. class C_Display_Type_Controller extends C_MVC_Controller 
  152. static $_instances = array(); 
  153. public function define($context = FALSE) 
  154. parent::define($context); 
  155. $this->add_mixin('Mixin_Display_Type_Controller'); 
  156. $this->implement('I_Display_Type_Controller'); 
  157. /** 
  158. * Gets a singleton of the mapper 
  159. * @param string|array $context 
  160. * @return C_Display_Type_Controller 
  161. */ 
  162. public static function get_instance($context = FALSE) 
  163. if (!isset(self::$_instances[$context])) { 
  164. self::$_instances[$context] = new C_Display_Type_Controller($context); 
  165. return self::$_instances[$context]; 
  166. /** 
  167. * Provides instance methods for the C_Display_Type_Controller class 
  168. */ 
  169. class Mixin_Display_Type_Controller extends Mixin 
  170. public $_render_mode; 
  171. /** 
  172. * Enqueues static resources required for lightbox effects 
  173. * @param type $displayed_gallery 
  174. */ 
  175. public function enqueue_lightbox_resources($displayed_gallery) 
  176. C_Lightbox_Library_Manager::get_instance()->enqueue(); 
  177. public function is_cachable() 
  178. return TRUE; 
  179. /** 
  180. * This method should be overwritten by other adapters/mixins, and call 
  181. * wp_enqueue_script() / wp_enqueue_style() 
  182. */ 
  183. public function enqueue_frontend_resources($displayed_gallery) 
  184. // This script provides common JavaScript among all display types 
  185. wp_enqueue_script('ngg_common'); 
  186. // Enqueue the display type library 
  187. wp_enqueue_script($displayed_gallery->display_type, $this->object->_get_js_lib_url($displayed_gallery), FALSE, NGG_SCRIPT_VERSION); 
  188. // Add "galleries = {};" 
  189. $this->object->_add_script_data('ngg_common', 'galleries', new stdClass(), TRUE, FALSE); 
  190. // Add "galleries.gallery_1 = {};" 
  191. $this->object->_add_script_data('ngg_common', 'galleries.gallery_' . $displayed_gallery->id(), (array) $displayed_gallery->get_entity(), FALSE); 
  192. $this->object->_add_script_data('ngg_common', 'galleries.gallery_' . $displayed_gallery->id() . '.wordpress_page_root', get_permalink(), FALSE); 
  193. // Enqueue trigger button resources 
  194. C_Displayed_Gallery_Trigger_Manager::get_instance()->enqueue_resources($displayed_gallery); 
  195. // Enqueue lightbox library 
  196. $this->object->enqueue_lightbox_resources($displayed_gallery); 
  197. public function enqueue_ngg_styles() 
  198. $settings = C_NextGen_Settings::get_instance(); 
  199. if ((!is_multisite() || is_multisite() && $settings->wpmuStyle) && $settings->activateCSS) { 
  200. wp_enqueue_style('nggallery', C_NextGen_Style_Manager::get_instance()->get_selected_stylesheet_url(), FALSE, NGG_SCRIPT_VERSION); 
  201. public function get_render_mode() 
  202. return $this->object->_render_mode; 
  203. public function set_render_mode($mode) 
  204. $this->object->_render_mode = $mode; 
  205. /** 
  206. * Ensures that the minimum configuration of parameters are sent to a view 
  207. * @param $displayed_gallery 
  208. * @param null $params 
  209. * @return array|null 
  210. */ 
  211. public function prepare_display_parameters($displayed_gallery, $params = null) 
  212. if ($params == null) { 
  213. $params = array(); 
  214. $params['display_type_rendering'] = true; 
  215. $params['displayed_gallery'] = $displayed_gallery; 
  216. $params['render_mode'] = $this->object->get_render_mode(); 
  217. return $params; 
  218. /** 
  219. * Renders the frontend display of the display type 
  220. */ 
  221. public function index_action($displayed_gallery, $return = FALSE) 
  222. return $this->object->render_partial('photocrati-nextgen_gallery_display#index', array(), $return); 
  223. /** 
  224. * Returns the url for the JavaScript library required 
  225. * @return null|string 
  226. */ 
  227. public function _get_js_lib_url() 
  228. return NULL; 
  229. public function does_lightbox_support_displayed_gallery($displayed_gallery, $lightbox = NULL) 
  230. if (!$lightbox) { 
  231. $lightbox = C_Lightbox_Library_Manager::get_instance()->get_selected(); 
  232. $retval = FALSE; 
  233. if ($lightbox) { 
  234. // HANDLE COMPATIBILITY BREAK 
  235. // In NGG 2.1.48 and earlier, lightboxes were stdClass objects, and it was assumed 
  236. // that they only supported galleries that contained images, not albums that contained galleries. 
  237. // After NGG 2.1.48, lightboxes are now C_NGG_Lightbox instances which have a 'is_supported()' method 
  238. // to test if the lightbox can work with the displayed gallery settings 
  239. if (get_class($lightbox) == 'stdClass') { 
  240. $retval = !in_array($displayed_gallery->source, array('album', 'albums')); 
  241. } else { 
  242. $retval = $lightbox->is_supported($displayed_gallery); 
  243. return $retval; 
  244. /** 
  245. * Returns the effect HTML code for the displayed gallery 
  246. * @param type $displayed_gallery 
  247. */ 
  248. public function get_effect_code($displayed_gallery) 
  249. $retval = ''; 
  250. if ($lightbox = C_Lightbox_Library_Manager::get_instance()->get_selected()) { 
  251. if ($this->does_lightbox_support_displayed_gallery($displayed_gallery, $lightbox)) { 
  252. $retval = $lightbox->code; 
  253. $retval = str_replace('%GALLERY_ID%', $displayed_gallery->id(), $retval); 
  254. $retval = str_replace('%GALLERY_NAME%', $displayed_gallery->id(), $retval); 
  255. global $post; 
  256. if ($post && isset($post->ID) && $post->ID) { 
  257. $retval = str_replace('%PAGE_ID%', $post->ID, $retval); 
  258. // allow for customization 
  259. $retval = apply_filters('ngg_effect_code', $retval, $displayed_gallery); 
  260. return $retval; 
  261. /** 
  262. * Adds data to the DOM which is then accessible by a script 
  263. * @param string $handle 
  264. * @param string $object_name 
  265. * @param mixed $object_value 
  266. * @param bool $define 
  267. */ 
  268. public function _add_script_data($handle, $object_name, $object_value, $define = TRUE, $override = FALSE) 
  269. $retval = FALSE; 
  270. // wp_localize_script allows you to add data to the DOM, associated 
  271. // with a particular script. You can even call wp_localize_script 
  272. // multiple times to add multiple objects to the DOM. However, there 
  273. // are a few problems with wp_localize_script: 
  274. // 
  275. // - If you call it with the same object_name more than once, you're 
  276. // overwritting the first call. 
  277. // - You cannot namespace your objects due to the "var" keyword always 
  278. // - being used. 
  279. // 
  280. // To circumvent the above issues, we're going to use the WP_Scripts 
  281. // object to workaround the above issues 
  282. global $wp_scripts; 
  283. // Has the script been registered or enqueued yet? 
  284. if (isset($wp_scripts->registered[$handle])) { 
  285. // Get the associated data with this script 
  286. $script =& $wp_scripts->registered[$handle]; 
  287. $data = isset($script->extra['data']) ? $script->extra['data'] : ''; 
  288. // Construct the addition 
  289. $addition = $define ? "\nvar {$object_name} = " . json_encode($object_value) . ';' : "\n{$object_name} = " . json_encode($object_value) . ';'; 
  290. // Add the addition 
  291. if ($override) { 
  292. $data .= $addition; 
  293. $retval = TRUE; 
  294. } else { 
  295. if (strpos($data, $object_name) === FALSE) { 
  296. $data .= $addition; 
  297. $retval = TRUE; 
  298. $script->extra['data'] = $data; 
  299. unset($script); 
  300. return $retval; 
  301. // Returns the longest and widest dimensions from a list of entities 
  302. public function get_entity_statistics($entities, $named_size, $style_images = FALSE) 
  303. $longest = $widest = 0; 
  304. $storage = C_Gallery_Storage::get_instance(); 
  305. $image_mapper = FALSE; 
  306. // we'll fetch this if needed 
  307. // Calculate longest and 
  308. foreach ($entities as $entity) { 
  309. // Get the image 
  310. $image = FALSE; 
  311. if (isset($entity->pid)) { 
  312. $image = $entity; 
  313. } elseif (isset($entity->previewpic)) { 
  314. if (!$image_mapper) { 
  315. $image_mapper = C_Image_Mapper::get_instance(); 
  316. $image = $image_mapper->find($entity->previewpic); 
  317. // Once we have the image, get it's dimensions 
  318. if ($image) { 
  319. $dimensions = $storage->get_image_dimensions($image, $named_size); 
  320. if ($dimensions['width'] > $widest) { 
  321. $widest = $dimensions['width']; 
  322. if ($dimensions['height'] > $longest) { 
  323. $longest = $dimensions['height']; 
  324. // Second loop to style images 
  325. if ($style_images) { 
  326. foreach ($entities as &$entity) { 
  327. // Get the image 
  328. $image = FALSE; 
  329. if (isset($entity->pid)) { 
  330. $image = $entity; 
  331. } elseif (isset($entity->previewpic)) { 
  332. if (!$image_mapper) { 
  333. $image_mapper = C_Image_Mapper::get_instance(); 
  334. $image = $image_mapper->find($entity->previewpic); 
  335. // Once we have the image, get it's dimension and calculate margins 
  336. if ($image) { 
  337. $dimensions = $storage->get_image_dimensions($image, $named_size); 
  338. return array('entities' => $entities, 'longest' => $longest, 'widest' => $widest); 
  339. /** 
  340. * Provides a datamapper to perform CRUD operations for Display Types 
  341. */ 
  342. class C_Display_Type_Mapper extends C_CustomPost_DataMapper_Driver 
  343. public static $_instances = array(); 
  344. public function define($context = FALSE, $not_used = FALSE) 
  345. $object_name = 'display_type'; 
  346. // Add the object name to the context of the object as well 
  347. // This allows us to adapt the driver itself, if required 
  348. if (!is_array($context)) { 
  349. $context = array($context); 
  350. array_push($context, $object_name); 
  351. parent::define($object_name, $context); 
  352. $this->add_mixin('Mixin_Display_Type_Mapper'); 
  353. $this->implement('I_Display_Type_Mapper'); 
  354. $this->set_model_factory_method($object_name); 
  355. // Define columns 
  356. $this->define_column('ID', 'BIGINT', 0); 
  357. $this->define_column('name', 'VARCHAR(255)'); 
  358. $this->define_column('title', 'VARCHAR(255)'); 
  359. $this->define_column('preview_image_relpath', 'VARCHAR(255)'); 
  360. $this->define_column('default_source', 'VARCHAR(255)'); 
  361. $this->define_column('view_order', 'BIGINT', NGG_DISPLAY_PRIORITY_BASE); 
  362. $this->add_serialized_column('settings'); 
  363. $this->add_serialized_column('entity_types'); 
  364. public function initialize($context = FALSE) 
  365. parent::initialize('display_type'); 
  366. /** 
  367. * Gets a singleton of the mapper 
  368. * @param string|array $context 
  369. * @return C_Display_Type_Mapper 
  370. */ 
  371. public static function get_instance($context = False) 
  372. if (!isset(self::$_instances[$context])) { 
  373. self::$_instances[$context] = new C_Display_Type_Mapper($context); 
  374. return self::$_instances[$context]; 
  375. /** 
  376. * Provides instance methods for the display type mapper 
  377. */ 
  378. class Mixin_Display_Type_Mapper extends Mixin 
  379. /** 
  380. * Locates a Display Type by names 
  381. * @param string $name 
  382. */ 
  383. public function find_by_name($name, $model = FALSE) 
  384. $retval = NULL; 
  385. $this->object->select(); 
  386. $this->object->where(array('name = %s', $name)); 
  387. $results = $this->object->run_query(FALSE, $model); 
  388. if ($results) { 
  389. $retval = $results[0]; 
  390. return $retval; 
  391. /** 
  392. * Finds display types used to display specific types of entities 
  393. * @param string|array $entity_type e.g. image, gallery, album 
  394. * @return array 
  395. */ 
  396. public function find_by_entity_type($entity_type, $model = FALSE) 
  397. $find_entity_types = is_array($entity_type) ? $entity_type : array($entity_type); 
  398. $retval = NULL; 
  399. foreach ($this->object->find_all($model) as $display_type) { 
  400. foreach ($find_entity_types as $entity_type) { 
  401. if (isset($display_type->entity_types) && in_array($entity_type, $display_type->entity_types)) { 
  402. $retval[] = $display_type; 
  403. break; 
  404. return $retval; 
  405. /** 
  406. * Uses the title attribute as the post title 
  407. * @param stdClass $entity 
  408. * @return string 
  409. */ 
  410. public function get_post_title($entity) 
  411. return $entity->title; 
  412. /** 
  413. * Sets default values needed for display types 
  414. */ 
  415. public function set_defaults($entity) 
  416. if (!isset($entity->settings)) { 
  417. $entity->settings = array(); 
  418. $this->_set_default_value($entity, 'preview_image_relpath', ''); 
  419. $this->_set_default_value($entity, 'default_source', ''); 
  420. $this->_set_default_value($entity, 'view_order', NGG_DISPLAY_PRIORITY_BASE); 
  421. $this->_set_default_value($entity, 'settings', 'use_lightbox_effect', TRUE); 
  422. $this->_set_default_value($entity, 'hidden_from_ui', FALSE); 
  423. return $this->call_parent('set_defaults', $entity); 
  424. /** 
  425. * Associates a Display Type with a collection of images 
  426. * 
  427. * * Properties: 
  428. * - source (gallery, album, recent_images, random_images, etc) 
  429. * - container_ids (gallery ids, album ids, tag ids, etc) 
  430. * - display_type (name of the display type being used) 
  431. * - display_settings (settings for the display type) 
  432. * - exclusions (excluded entity ids) 
  433. * - entity_ids (specific images/galleries to include, sorted) 
  434. * - order_by 
  435. * - order_direction 
  436. */ 
  437. class C_Displayed_Gallery extends C_DataMapper_Model 
  438. public $_mapper_interface = 'I_Displayed_Gallery_Mapper'; 
  439. public function define($properties = array(), $mapper = FALSE, $context = FALSE) 
  440. parent::define($mapper, $properties, $context); 
  441. $this->add_mixin('Mixin_Displayed_Gallery_Validation'); 
  442. $this->add_mixin('Mixin_Displayed_Gallery_Instance_Methods'); 
  443. $this->add_mixin('Mixin_Displayed_Gallery_Queries'); 
  444. $this->implement('I_Displayed_Gallery'); 
  445. /** 
  446. * Initializes a display type with properties 
  447. * @param FALSE|C_Displayed_Gallery_Mapper $mapper 
  448. * @param array|stdClass|C_Displayed_Gallery $properties 
  449. * @param FALSE|string|array $context 
  450. */ 
  451. public function initialize($properties = array(), $mapper = FALSE, $context = FALSE) 
  452. if (!$mapper) { 
  453. $mapper = $this->get_registry()->get_utility($this->_mapper_interface); 
  454. parent::initialize($mapper, $properties); 
  455. $this->select_random_variation(); 
  456. /** 
  457. * Provides validation 
  458. */ 
  459. class Mixin_Displayed_Gallery_Validation extends Mixin 
  460. public function validation() 
  461. // Valid sources 
  462. $this->object->validates_presence_of('source'); 
  463. // Valid display type? 
  464. $this->object->validates_presence_of('display_type'); 
  465. if ($display_type = $this->object->get_display_type()) { 
  466. foreach ($this->object->display_settings as $key => $val) { 
  467. $display_type->settings[$key] = $val; 
  468. $this->object->display_settings = $display_type->settings; 
  469. if (!$display_type->validate()) { 
  470. foreach ($display_type->get_errors() as $property => $errors) { 
  471. foreach ($errors as $error) { 
  472. $this->object->add_error($error, $property); 
  473. // Is the display type compatible with the source? E.g., if we're 
  474. // using a display type that expects images, we can't be feeding it 
  475. // galleries and albums 
  476. if ($source = $this->object->get_source()) { 
  477. if (!$display_type->is_compatible_with_source($source)) { 
  478. $this->object->add_error(__('Source not compatible with selected display type', 'nggallery'), 'display_type'); 
  479. // Allow ONLY recent & random galleries to have their own maximum_entity_count 
  480. if (!empty($this->object->display_settings['maximum_entity_count']) && in_array($this->object->source, array('random_images', 'recent_images', 'random', 'recent'))) { 
  481. $this->object->maximum_entity_count = $this->object->display_settings['maximum_entity_count']; 
  482. // If no maximum_entity_count has been given, then set a maximum 
  483. if (!isset($this->object->maximum_entity_count)) { 
  484. $settings = C_NextGen_Settings::get_instance(); 
  485. $this->object->maximum_entity_count = $settings->get('maximum_entity_count', 500); 
  486. } else { 
  487. $this->object->add_error('Invalid display type', 'display_type'); 
  488. return $this->object->is_valid(); 
  489. class Mixin_Displayed_Gallery_Queries extends Mixin 
  490. public function select_random_variation() 
  491. $retval = FALSE; 
  492. $source_obj = $this->object->get_source(); 
  493. if ($source_obj && $source_obj->has_variations) { 
  494. $max = 0; 
  495. if (!defined('NGG_MAX_VARIATIONS')) { 
  496. $settings = C_Photocrati_Global_Settings_Manager::get_instance(); 
  497. $max = $settings->get('max_variations', 5); 
  498. define('NGG_MAX_VARIATIONS', $max); 
  499. } else { 
  500. $max = NGG_MAX_VARIATIONS; 
  501. $this->object->variation = floor(rand(1, $max)); 
  502. $retval = $this->object->variation; 
  503. return $retval; 
  504. public function get_entities($limit = FALSE, $offset = FALSE, $id_only = FALSE, $returns = 'included') 
  505. $retval = array(); 
  506. $source_obj = $this->object->get_source(); 
  507. $max = $this->object->get_maximum_entity_count(); 
  508. if (!$limit || is_numeric($limit) && $limit > $max) { 
  509. $limit = $max; 
  510. // Ensure that all parameters have values that are expected 
  511. if ($this->object->_parse_parameters()) { 
  512. // Is this an image query? 
  513. if (in_array('image', $source_obj->returns)) { 
  514. $retval = $this->object->_get_image_entities($source_obj, $limit, $offset, $id_only, $returns); 
  515. } elseif (in_array('gallery', $source_obj->returns)) { 
  516. $retval = $this->object->_get_album_and_gallery_entities($source_obj, $limit, $offset, $id_only, $returns); 
  517. return $retval; 
  518. /** 
  519. * Gets all images in the displayed gallery 
  520. * @param stdClass $source_obj 
  521. * @param int $limit 
  522. * @param int $offset 
  523. * @param boolean $id_only 
  524. * @param string $returns 
  525. */ 
  526. public function _get_image_entities($source_obj, $limit, $offset, $id_only, $returns) 
  527. // TODO: This method is very long, and therefore more difficult to read 
  528. // Find a way to minimalize or segment 
  529. $mapper = C_Image_Mapper::get_instance(); 
  530. $image_key = $mapper->get_primary_key_column(); 
  531. $select = $id_only ? $image_key : $mapper->get_table_name() . '.*'; 
  532. $sort_direction = $this->object->order_direction; 
  533. $sort_by = $this->object->order_by; 
  534. // Here's what this method is doing: 
  535. // 1) Determines what results need returned 
  536. // 2) Determines from what container ids the results should come from 
  537. // 3) Applies ORDER BY clause 
  538. // 4) Applies LIMIT/OFFSET clause 
  539. // 5) Executes the query and returns the result 
  540. // We start with the most difficult query. When returns is "both", we 
  541. // need to return a list of both included and excluded entity ids, and 
  542. // mark specifically which entities are excluded 
  543. if ($returns == 'both') { 
  544. // We need to add two dynamic columns, one called "sortorder" and 
  545. // the other called "exclude". 
  546. $if_true = 1; 
  547. $if_false = 0; 
  548. $excluded_set = $this->object->entity_ids; 
  549. if (!$excluded_set) { 
  550. $if_true = 0; 
  551. $if_false = 1; 
  552. $excluded_set = $this->object->exclusions; 
  553. $sortorder_set = $this->object->sortorder ? $this->object->sortorder : $excluded_set; 
  554. // Add sortorder column 
  555. if ($sortorder_set) { 
  556. $select = $this->object->_add_find_in_set_column($select, $image_key, $sortorder_set, 'new_sortorder', TRUE); 
  557. // A user might want to sort the results by the order of 
  558. // images that they specified to be included. For that,  
  559. // we need some trickery by reversing the order direction 
  560. $sort_direction = $this->object->order_direction == 'ASC' ? 'DESC' : 'ASC'; 
  561. $sort_by = 'new_sortorder'; 
  562. // Add exclude column 
  563. if ($excluded_set) { 
  564. $select = $this->object->_add_find_in_set_column($select, $image_key, $excluded_set, 'exclude'); 
  565. $select .= ", IF (exclude = 0 AND @exclude = 0, {$if_true}, {$if_false}) AS 'exclude'"; 
  566. // Select what we want 
  567. $mapper->select($select); 
  568. // When returns is "included", the query is relatively simple. We 
  569. // just provide a where clause to limit how many images we're returning 
  570. // based on the entity_ids, exclusions, and container_ids parameters 
  571. if ($returns == 'included') { 
  572. // If the sortorder propery is available, then we need to override 
  573. // the sortorder 
  574. if ($this->object->sortorder) { 
  575. $select = $this->object->_add_find_in_set_column($select, $image_key, $this->object->sortorder, 'new_sortorder', TRUE); 
  576. $sort_direction = $this->object->order_direction == 'ASC' ? 'DESC' : 'ASC'; 
  577. $sort_by = 'new_sortorder'; 
  578. $mapper->select($select); 
  579. // Filter based on entity_ids selection 
  580. if ($this->object->entity_ids) { 
  581. $mapper->where(array("{$image_key} IN %s", $this->object->entity_ids)); 
  582. // Filter based on exclusions selection 
  583. if ($this->object->exclusions) { 
  584. $mapper->where(array("{$image_key} NOT IN %s", $this->object->exclusions)); 
  585. // Ensure that no images marked as excluded at the gallery level are returned 
  586. if (empty($this->object->skip_excluding_globally_excluded_images)) { 
  587. $mapper->where(array('exclude = %d', 0)); 
  588. } elseif ($returns == 'excluded') { 
  589. // If the sortorder propery is available, then we need to override 
  590. // the sortorder 
  591. if ($this->object->sortorder) { 
  592. $select = $this->object->_add_find_in_set_column($select, $image_key, $this->object->sortorder, 'new_sortorder', TRUE); 
  593. $sort_direction = $this->object->order_direction == 'ASC' ? 'DESC' : 'ASC'; 
  594. $sort_by = 'new_sortorder'; 
  595. // Mark each result as excluded 
  596. $select .= ', 1 AS exclude'; 
  597. $mapper->select($select); 
  598. // Is this case, entity_ids become the exclusions 
  599. $exclusions = $this->object->entity_ids; 
  600. // Remove the exclusions always takes precedence over entity_ids, so 
  601. // we adjust the list of ids 
  602. if ($this->object->exclusions) { 
  603. foreach ($this->object->exclusions as $excluded_entity_id) { 
  604. if (($index = array_search($excluded_entity_id, $exclusions)) !== FALSE) { 
  605. unset($exclusions[$index]); 
  606. // Filter based on exclusions selection 
  607. if ($exclusions) { 
  608. $mapper->where(array("{$image_key} NOT IN %s", $exclusions)); 
  609. } else { 
  610. if ($this->object->exclusions) { 
  611. $mapper->where(array("{$image_key} IN %s", $this->object->exclusions)); 
  612. // Ensure that images marked as excluded are returned as well 
  613. $mapper->where(array('exclude = 1')); 
  614. // Filter based on containers_ids. Container ids is a little more 
  615. // complicated as it can contain gallery ids or tags 
  616. if ($this->object->container_ids) { 
  617. // Container ids are tags 
  618. if ($source_obj->name == 'tags') { 
  619. $term_ids = $this->object->get_term_ids_for_tags($this->object->container_ids); 
  620. $mapper->where(array("{$image_key} IN %s", get_objects_in_term($term_ids, 'ngg_tag'))); 
  621. } else { 
  622. $mapper->where(array('galleryid IN %s', $this->object->container_ids)); 
  623. // Filter based on excluded container ids 
  624. if ($this->object->excluded_container_ids) { 
  625. // Container ids are tags 
  626. if ($source_obj->name == 'tags') { 
  627. $term_ids = $this->object->get_term_ids_for_tags($this->object->excluded_container_ids); 
  628. $mapper->where(array("{$image_key} NOT IN %s", get_objects_in_term($term_ids, 'ngg_tag'))); 
  629. } else { 
  630. $mapper->where(array('galleryid NOT IN %s', $this->object->excluded_container_ids)); 
  631. // Adjust the query more based on what source was selected 
  632. if (in_array($this->object->source, array('recent', 'recent_images'))) { 
  633. $sort_direction = 'DESC'; 
  634. $sort_by = 'imagedate'; 
  635. } elseif ($this->object->source == 'random_images' && empty($this->object->entity_ids)) { 
  636. $table_name = $mapper->get_table_name(); 
  637. $where_clauses = array(); 
  638. $sub_where_sql = ''; 
  639. foreach ($mapper->_where_clauses as $where) { 
  640. $where_clauses[] = '(' . $where . ')'; 
  641. if ($where_clauses) { 
  642. $sub_where_sql = 'WHERE ' . implode(' AND ', $where_clauses); 
  643. $mapper->_where_clauses = array(" /*NGG_NO_EXTRAS_TABLE*/ `{$image_key}` IN (SELECT `{$image_key}` FROM (SELECT `{$image_key}` FROM `{$table_name}` i {$sub_where_sql} ORDER BY RAND() LIMIT {$this->object->maximum_entity_count}) o) /*NGG_NO_EXTRAS_TABLE*/"); 
  644. // Apply a sorting order 
  645. if ($sort_by) { 
  646. $mapper->order_by($sort_by, $sort_direction); 
  647. // Apply a limit 
  648. if ($limit) { 
  649. if ($offset) { 
  650. $mapper->limit($limit, $offset); 
  651. } else { 
  652. $mapper->limit($limit); 
  653. $results = $mapper->run_query(); 
  654. return $results; 
  655. /** 
  656. * Gets all gallery and album entities from albums specified, if any 
  657. * @param stdClass $source_obj 
  658. * @param int $limit 
  659. * @param int $offset 
  660. * @param boolean $id_only 
  661. * @param array $returns 
  662. */ 
  663. public function _get_album_and_gallery_entities($source_obj, $limit = FALSE, $offset = FALSE, $id_only = FALSE, $returns = 'included') 
  664. // Albums queries and difficult and inefficient to perform due to the 
  665. // database schema. To complicate things, we're returning two different 
  666. // types of entities - galleries, and sub-albums. 
  667. // The user prefixes entity_id's with an 'a' to distinguish album ids 
  668. // from gallery ids. E.g. entity_ids=[1, "a2", 3] 
  669. $album_mapper = C_Album_Mapper::get_instance(); 
  670. $album_key = $album_mapper->get_primary_key_column(); 
  671. $gallery_mapper = C_Gallery_Mapper::get_instance(); 
  672. $gallery_key = $gallery_mapper->get_primary_key_column(); 
  673. $select = $id_only ? $album_key . ', sortorder' : $album_mapper->get_table_name() . '.*'; 
  674. $retval = array(); 
  675. // If no exclusions are specified, are entity_ids are specified,  
  676. // and we're to return is "included", then we have a relatively easy 
  677. // query to perform - we just fetch each entity listed in 
  678. // the entity_ids field 
  679. if ($returns == 'included' && $this->object->entity_ids && empty($this->object->exclusions)) { 
  680. $retval = $this->object->_entities_to_galleries_and_albums($this->object->entity_ids, $id_only, array(), $limit, $offset); 
  681. } else { 
  682. // Start the query 
  683. $album_mapper->select($select); 
  684. // Fetch the albums, and find the entity ids of the sub-albums and galleries 
  685. $entity_ids = array(); 
  686. $excluded_ids = array(); 
  687. // Filter by container ids. If container_ids === '0' we retrieve all existing gallery_ids and use 
  688. // them as the available entity_ids for comparability with 1.9x 
  689. $container_ids = $this->object->container_ids; 
  690. if ($container_ids) { 
  691. if ($container_ids !== array('0') && $container_ids !== array('')) { 
  692. $album_mapper->where(array("{$album_key} IN %s", $container_ids)); 
  693. foreach ($album_mapper->run_query() as $album) { 
  694. $entity_ids = array_merge($entity_ids, (array) $album->sortorder); 
  695. } else { 
  696. if ($container_ids === array('0') || $container_ids === array('')) { 
  697. foreach ($gallery_mapper->select($gallery_key)->run_query() as $gallery) { 
  698. $entity_ids[] = $gallery->{$gallery_key}; 
  699. // Break the list of entities into two groups, included entities 
  700. // and excluded entity ids 
  701. // -- 
  702. // If a specific list of entity ids have been specified, then 
  703. // we know what entity ids are meant to be included. We can compute 
  704. // the intersect and also determine what entity ids are to be 
  705. // excluded 
  706. if ($this->object->entity_ids) { 
  707. // Determine the real list of included entity ids. Exclusions 
  708. // always take precedence 
  709. $included_ids = $this->object->entity_ids; 
  710. foreach ($this->object->exclusions as $excluded_id) { 
  711. if (($index = array_search($excluded_id, $included_ids)) !== FALSE) { 
  712. unset($included_ids[$index]); 
  713. $excluded_ids = array_diff($entity_ids, $included_ids); 
  714. } elseif ($this->object->exclusions) { 
  715. $included_ids = array_diff($entity_ids, $this->object->exclusions); 
  716. $excluded_ids = array_diff($entity_ids, $included_ids); 
  717. } else { 
  718. $included_ids = $entity_ids; 
  719. // We've built our two groups. Let's determine how we'll focus on them 
  720. // -- 
  721. // We're interested in only the included ids 
  722. if ($returns == 'included') { 
  723. $retval = $this->object->_entities_to_galleries_and_albums($included_ids, $id_only, array(), $limit, $offset); 
  724. } elseif ($returns == 'excluded') { 
  725. $retval = $this->object->_entities_to_galleries_and_albums($excluded_ids, $id_only, $excluded_ids, $limit, $offset); 
  726. } else { 
  727. $retval = $this->object->_entities_to_galleries_and_albums($entity_ids, $id_only, $excluded_ids, $limit, $offset); 
  728. return $retval; 
  729. /** 
  730. * Takes a list of entities, and returns the mapped galleries and sub-albums 
  731. * 
  732. * @param array $entity_ids 
  733. * @param bool $id_only 
  734. * @param array $exclusions 
  735. * @param int $limit 
  736. * @param int $offset 
  737. * @return array 
  738. */ 
  739. public function _entities_to_galleries_and_albums($entity_ids, $id_only = FALSE, $exclusions = array(), $limit = FALSE, $offset = FALSE) 
  740. $retval = array(); 
  741. $gallery_ids = array(); 
  742. $album_ids = array(); 
  743. $album_mapper = C_Album_Mapper::get_instance(); 
  744. $album_key = $album_mapper->get_primary_key_column(); 
  745. $gallery_mapper = C_Gallery_Mapper::get_instance(); 
  746. $image_mapper = C_Image_Mapper::get_instance(); 
  747. $gallery_key = $gallery_mapper->get_primary_key_column(); 
  748. $album_select = ($id_only ? $album_key : $album_mapper->get_table_name() . '.*') . ', 1 AS is_album, 0 AS is_gallery, name AS title, albumdesc AS galdesc'; 
  749. $gallery_select = ($id_only ? $gallery_key : $gallery_mapper->get_table_name() . '.*') . ', 1 AS is_gallery, 0 AS is_album'; 
  750. // Modify the sort order of the entities 
  751. if ($this->object->sortorder) { 
  752. $sortorder = array_intersect($this->object->sortorder, $entity_ids); 
  753. $entity_ids = array_merge($sortorder, array_diff($entity_ids, $sortorder)); 
  754. // Segment entity ids into two groups - galleries and albums 
  755. foreach ($entity_ids as $entity_id) { 
  756. if (substr($entity_id, 0, 1) == 'a') { 
  757. $album_ids[] = intval(substr($entity_id, 1)); 
  758. } else { 
  759. $gallery_ids[] = intval($entity_id); 
  760. // Adjust query to include an exclude property 
  761. if ($exclusions) { 
  762. $album_select = $this->object->_add_find_in_set_column($album_select, $album_key, $this->object->exclusions, 'exclude'); 
  763. $album_select = $this->object->_add_if_column($album_select, 'exclude', 0, 1); 
  764. $gallery_select = $this->object->_add_find_in_set_column($gallery_select, $gallery_key, $this->object->exclusions, 'exclude'); 
  765. $gallery_select = $this->object->_add_if_column($gallery_select, 'exclude', 0, 1); 
  766. // Add sorting parameter to the gallery and album queries 
  767. if ($gallery_ids) { 
  768. $gallery_select = $this->object->_add_find_in_set_column($gallery_select, $gallery_key, $gallery_ids, 'ordered_by', TRUE); 
  769. } else { 
  770. $gallery_select .= ', 0 AS ordered_by'; 
  771. if ($album_ids) { 
  772. $album_select = $this->object->_add_find_in_set_column($album_select, $album_key, $album_ids, 'ordered_by', TRUE); 
  773. } else { 
  774. $album_select .= ', 0 AS ordered_by'; 
  775. // Fetch entities 
  776. $galleries = $gallery_mapper->select($gallery_select)->where(array("{$gallery_key} IN %s", $gallery_ids))->order_by('ordered_by', 'DESC')->run_query(); 
  777. $counts = $image_mapper->select('galleryid, COUNT(*) as counter')->where(array(array('galleryid IN %s', $gallery_ids), array('exclude = %d', 0)))->group_by('galleryid')->run_query(FALSE, FALSE, TRUE); 
  778. $albums = $album_mapper->select($album_select)->where(array("{$album_key} IN %s", $album_ids))->order_by('ordered_by', 'DESC')->run_query(); 
  779. // Reorder entities according to order specified in entity_ids 
  780. foreach ($entity_ids as $entity_id) { 
  781. if (substr($entity_id, 0, 1) == 'a') { 
  782. $album = array_shift($albums); 
  783. if ($album) { 
  784. $retval[] = $album; 
  785. } else { 
  786. $gallery = array_shift($galleries); 
  787. if ($gallery) { 
  788. foreach ($counts as $id => $gal_count) { 
  789. if ($gal_count->galleryid == $gallery->gid) { 
  790. $gallery->counter = intval($gal_count->counter); 
  791. unset($counts[$id]); 
  792. $retval[] = $gallery; 
  793. // Sort the entities 
  794. if ($this->object->order_by && $this->object->order_by != 'sortorder') { 
  795. usort($retval, array(&$this, '_sort_album_result')); 
  796. if ($this->object->order_direction == 'DESC') { 
  797. $retval = array_reverse($retval); 
  798. // Limit the entities 
  799. if ($limit) { 
  800. $retval = array_slice($retval, $offset, $limit); 
  801. return $retval; 
  802. /** 
  803. * Returns the total number of entities in this displayed gallery 
  804. * @param string $returns 
  805. * @returns int 
  806. */ 
  807. public function get_entity_count($returns = 'included') 
  808. $retval = 0; 
  809. // Is this an image query? 
  810. $source_obj = $this->object->get_source(); 
  811. if (in_array('image', $source_obj->returns)) { 
  812. $retval = count($this->object->_get_image_entities($source_obj, FALSE, FALSE, TRUE, $returns)); 
  813. } elseif (in_array('gallery', $source_obj->returns)) { 
  814. $retval = count($this->object->_get_album_and_gallery_entities($source_obj, FALSE, FALSE, TRUE, $returns)); 
  815. $max = $this->get_maximum_entity_count(); 
  816. if ($retval > $max) { 
  817. $retval = $max; 
  818. return $retval; 
  819. // Honor the gallery 'maximum_entity_count' setting ONLY when dealing with random & recent galleries. All 
  820. // others will always obey the *global* 'maximum_entity_count' setting. 
  821. public function get_maximum_entity_count() 
  822. $max = intval(C_NextGen_Settings::get_instance()->get('maximum_entity_count', 500)); 
  823. $sources = C_Displayed_Gallery_Source_Manager::get_instance(); 
  824. $source_obj = $this->object->get_source(); 
  825. if (in_array($source_obj, array($sources->get('random'), $sources->get('random_images'), $sources->get('recent'), $sources->get('recent_images')))) { 
  826. $max = intval($this->object->maximum_entity_count); 
  827. return $max; 
  828. /** 
  829. * Returns all included entities for the displayed gallery 
  830. * @param int $limit 
  831. * @param int $offset 
  832. * @param boolean $id_only 
  833. * @return array 
  834. */ 
  835. public function get_included_entities($limit = FALSE, $offset = FALSE, $id_only = FALSE) 
  836. return $this->object->get_entities($limit, $offset, $id_only, 'included'); 
  837. /** 
  838. * Adds a FIND_IN_SET call to the select portion of the query, and 
  839. * optionally defines a dynamic column 
  840. * @param string $select 
  841. * @param string $key 
  842. * @param array $array 
  843. * @param string $alias 
  844. * @param boolean $add_column 
  845. * @return string 
  846. */ 
  847. public function _add_find_in_set_column($select, $key, $array, $alias, $add_column = FALSE) 
  848. $array = array_map('intval', $array); 
  849. $set = implode(', ', array_reverse($array)); 
  850. if (!$select) { 
  851. $select = '1'; 
  852. $select .= ", @{$alias} := FIND_IN_SET({$key}, '{$set}')"; 
  853. if ($add_column) { 
  854. $select .= " AS {$alias}"; 
  855. return $select; 
  856. public function _add_if_column($select, $alias, $true = 1, $false = 0) 
  857. if (!$select) { 
  858. $select = '1'; 
  859. $select .= ", IF(@{$alias} = 0, {$true}, {$false}) AS {$alias}"; 
  860. return $select; 
  861. /** 
  862. * Parses the list of parameters provided in the displayed gallery, and 
  863. * ensures everything meets expectations 
  864. * @return boolean 
  865. */ 
  866. public function _parse_parameters() 
  867. $valid = FALSE; 
  868. // Ensure that the source is valid 
  869. if (C_Displayed_Gallery_Source_Manager::get_instance()->get($this->object->source)) { 
  870. $valid = TRUE; 
  871. // Ensure that exclusions, entity_ids, and sortorder have valid elements. 
  872. // IE likes to send empty array as an array with a single element that 
  873. // has no value 
  874. if ($this->object->exclusions && !$this->object->exclusions[0]) { 
  875. $this->object->exclusions = array(); 
  876. if ($this->object->entity_ids && !$this->object->entity_ids[0]) { 
  877. $this->object->entity_ids = array(); 
  878. if ($this->object->sortorder && !$this->object->sortorder[0]) { 
  879. $this->object->sortorder = array(); 
  880. return $valid; 
  881. /** 
  882. * Returns a list of term ids for the list of tags 
  883. * @global wpdb $wpdb 
  884. * @param array $tags 
  885. * @return array 
  886. */ 
  887. public function get_term_ids_for_tags($tags = FALSE) 
  888. global $wpdb; 
  889. // If no tags were provided, get them from the container_ids 
  890. if (!$tags || !is_array($tags)) { 
  891. $tags = $this->object->container_ids; 
  892. // Convert container ids to a string suitable for WHERE IN 
  893. $container_ids = array(); 
  894. if (is_array($tags) && !in_array('all', array_map('strtolower', $tags))) { 
  895. foreach ($tags as $ndx => $container) { 
  896. $container_ids[] = "'{$container}'"; 
  897. $container_ids = implode(', ', $container_ids); 
  898. // Construct query 
  899. $query = "SELECT {$wpdb->term_taxonomy}.term_id FROM {$wpdb->term_taxonomy}\n INNER JOIN {$wpdb->terms} ON {$wpdb->term_taxonomy}.term_id = {$wpdb->terms}.term_id\n WHERE {$wpdb->term_taxonomy}.term_id = {$wpdb->terms}.term_id\n AND {$wpdb->term_taxonomy}.taxonomy = %s"; 
  900. if (!empty($container_ids)) { 
  901. $query .= " AND ({$wpdb->terms}.slug IN ({$container_ids}) OR {$wpdb->terms}.name IN ({$container_ids}))"; 
  902. $query .= " ORDER BY {$wpdb->terms}.term_id"; 
  903. $query = $wpdb->prepare($query, 'ngg_tag'); 
  904. // Get all term_ids for each image tag slug 
  905. $term_ids = array(); 
  906. $results = $wpdb->get_results($query); 
  907. if (is_array($results) && !empty($results)) { 
  908. foreach ($results as $row) { 
  909. $term_ids[] = $row->term_id; 
  910. return $term_ids; 
  911. /** 
  912. * Sorts the results of an album query 
  913. * @param stdClass $a 
  914. * @param stdClass $b 
  915. */ 
  916. public function _sort_album_result($a, $b) 
  917. $key = $this->object->order_by; 
  918. return strcmp($a->{$key}, $b->{$key}); 
  919. /** 
  920. * Provides instance methods useful for working with the C_Displayed_Gallery 
  921. * model 
  922. */ 
  923. class Mixin_Displayed_Gallery_Instance_Methods extends Mixin 
  924. public function get_entity() 
  925. $entity = $this->call_parent('get_entity'); 
  926. unset($entity->post_author); 
  927. unset($entity->post_date); 
  928. unset($entity->post_date_gmt); 
  929. unset($entity->post_title); 
  930. unset($entity->post_excerpt); 
  931. unset($entity->post_status); 
  932. unset($entity->comment_status); 
  933. unset($entity->ping_status); 
  934. unset($entity->post_name); 
  935. unset($entity->to_ping); 
  936. unset($entity->pinged); 
  937. unset($entity->post_modified); 
  938. unset($entity->post_modified_gmt); 
  939. unset($entity->post_parent); 
  940. unset($entity->guid); 
  941. unset($entity->post_type); 
  942. unset($entity->post_mime_type); 
  943. unset($entity->comment_count); 
  944. unset($entity->filter); 
  945. unset($entity->post_content_filtered); 
  946. return $entity; 
  947. /** 
  948. * Gets the display type object used in this displayed gallery 
  949. * @return C_Display_Type 
  950. */ 
  951. public function get_display_type() 
  952. return C_Display_Type_Mapper::get_instance()->find_by_name($this->object->display_type, TRUE); 
  953. /** 
  954. * Gets the corresponding source instance 
  955. * @return stdClass 
  956. */ 
  957. public function get_source() 
  958. return C_Displayed_Gallery_Source_Manager::get_instance()->get($this->object->source); 
  959. /** 
  960. * Returns the galleries queries in this displayed gallery 
  961. * @return array 
  962. */ 
  963. public function get_galleries() 
  964. $retval = array(); 
  965. if ($source = $this->object->get_source()) { 
  966. if (in_array('image', $source->returns)) { 
  967. $mapper = C_Gallery_Mapper::get_instance(); 
  968. $gallery_key = $mapper->get_primary_key_column(); 
  969. $mapper->select(); 
  970. if ($this->object->container_ids) { 
  971. $mapper->where(array("{$gallery_key} IN %s", $this->object->container_ids)); 
  972. $retval = $mapper->run_query(); 
  973. return $retval; 
  974. /** 
  975. * Gets albums queried in this displayed gallery 
  976. * @return array 
  977. */ 
  978. public function get_albums() 
  979. $retval = array(); 
  980. if ($source = $this->object->get_source()) { 
  981. if (in_array('album', $source->returns)) { 
  982. $mapper = C_Album_Mapper::get_instance(); 
  983. $album_key = $mapper->get_primary_key_column(); 
  984. if ($this->object->container_ids) { 
  985. $mapper->select()->where(array("{$album_key} IN %s", $this->object->container_ids)); 
  986. $retval = $mapper->run_query(); 
  987. return $retval; 
  988. /** 
  989. * Returns a transient for the displayed gallery 
  990. * @return string 
  991. */ 
  992. public function to_transient() 
  993. $params = $this->object->get_entity(); 
  994. unset($params->transient_id); 
  995. $key = C_Photocrati_Transient_Manager::create_key('displayed_galleries', $params); 
  996. if (is_null(C_Photocrati_Transient_Manager::fetch($key, NULL))) { 
  997. C_Photocrati_Transient_Manager::update($key, $params, NGG_DISPLAYED_GALLERY_CACHE_TTL); 
  998. $this->object->transient_id = $key; 
  999. if (!$this->object->id()) { 
  1000. $this->object->id($key); 
  1001. return $key; 
  1002. /** 
  1003. * Applies the values of a transient to this object 
  1004. * @param string $transient_id 
  1005. */ 
  1006. public function apply_transient($transient_id = NULL) 
  1007. $retval = FALSE; 
  1008. if (!$transient_id && isset($this->object->transient_id)) { 
  1009. $transient_id = $this->object->transient_id; 
  1010. if ($transient_id && ($transient = C_Photocrati_Transient_Manager::fetch($transient_id, FALSE))) { 
  1011. // Ensure that the transient is an object, not array 
  1012. if (is_array($transient)) { 
  1013. $obj = new stdClass(); 
  1014. foreach ($transient as $key => $value) { 
  1015. $obj->{$key} = $value; 
  1016. $transient = $obj; 
  1017. $this->object->_stdObject = $transient; 
  1018. // Ensure that the display settings are an array 
  1019. $this->object->display_settings = $this->_object_to_array($this->object->display_settings); 
  1020. // Ensure that we have the most accurate transient id 
  1021. $this->object->transient_id = $transient_id; 
  1022. if (!$this->object->id()) { 
  1023. $this->object->id($transient_id); 
  1024. $retval = TRUE; 
  1025. } else { 
  1026. unset($this->object->transient_id); 
  1027. unset($this->object->_stdObject->transient_id); 
  1028. $this->object->to_transient(); 
  1029. return $retval; 
  1030. public function _object_to_array($object) 
  1031. $retval = $object; 
  1032. if (is_object($retval)) { 
  1033. $retval = get_object_vars($object); 
  1034. if (is_array($retval)) { 
  1035. foreach ($retval as $key => $val) { 
  1036. if (is_object($val)) { 
  1037. $retval[$key] = $this->_object_to_array($val); 
  1038. return $retval; 
  1039. class C_Displayed_Gallery_Mapper extends C_CustomPost_DataMapper_Driver 
  1040. static $_instances = array(); 
  1041. public function define($context = FALSE, $not_used = FALSE) 
  1042. parent::define('displayed_gallery', array($context, 'displayed_gallery', 'display_gallery')); 
  1043. $this->add_mixin('Mixin_Displayed_Gallery_Defaults'); 
  1044. $this->implement('I_Displayed_Gallery_Mapper'); 
  1045. $this->set_model_factory_method('displayed_gallery'); 
  1046. /** 
  1047. * Initializes the mapper 
  1048. * @param string|array|FALSE $context 
  1049. */ 
  1050. public function initialize() 
  1051. parent::initialize('displayed_gallery'); 
  1052. /** 
  1053. * Gets a singleton of the mapper 
  1054. * @param string|array $context 
  1055. * @return C_Displayed_Gallery_Mapper 
  1056. */ 
  1057. public static function get_instance($context = False) 
  1058. if (!isset(self::$_instances[$context])) { 
  1059. self::$_instances[$context] = new C_Displayed_Gallery_Mapper($context); 
  1060. return self::$_instances[$context]; 
  1061. /** 
  1062. * Adds default values for the displayed gallery 
  1063. */ 
  1064. class Mixin_Displayed_Gallery_Defaults extends Mixin 
  1065. /** 
  1066. * Gets a display type object for a particular entity 
  1067. * @param stdClass|C_DataMapper_Model $entity 
  1068. * @return null|stdClass 
  1069. */ 
  1070. public function get_display_type($entity) 
  1071. $mapper = C_Display_Type_Mapper::get_instance(); 
  1072. return $mapper->find_by_name($entity->display_type); 
  1073. /** 
  1074. * Sets defaults needed for the entity 
  1075. * @param type $entity 
  1076. */ 
  1077. public function set_defaults($entity) 
  1078. // Ensure that we have a settings array 
  1079. if (!isset($entity->display_settings)) { 
  1080. $entity->display_settings = array(); 
  1081. // If the display type is set, then get it's settings and apply them as 
  1082. // defaults to the "display_settings" of the displayed gallery 
  1083. if (isset($entity->display_type)) { 
  1084. // Get display type mapper 
  1085. if ($display_type = $this->object->get_display_type($entity)) { 
  1086. $entity->display_settings = $this->array_merge_assoc($display_type->settings, $entity->display_settings, TRUE); 
  1087. // Default ordering 
  1088. $settings = C_NextGen_Settings::get_instance(); 
  1089. $this->object->_set_default_value($entity, 'order_by', $settings->galSort); 
  1090. $this->object->_set_default_value($entity, 'order_direction', $settings->galSortDir); 
  1091. // Ensure we have an exclusions array 
  1092. $this->object->_set_default_value($entity, 'exclusions', array()); 
  1093. // Ensure other properties exist 
  1094. $this->object->_set_default_value($entity, 'container_ids', array()); 
  1095. $this->object->_set_default_value($entity, 'excluded_container_ids', array()); 
  1096. $this->object->_set_default_value($entity, 'sortorder', array()); 
  1097. $this->object->_set_default_value($entity, 'entity_ids', array()); 
  1098. $this->object->_set_default_value($entity, 'returns', 'included'); 
  1099. // Set maximum_entity_count 
  1100. $this->object->_set_default_value($entity, 'maximum_entity_count', $settings->maximum_entity_count); 
  1101. class C_Displayed_Gallery_Renderer extends C_Component 
  1102. static $_instances = array(); 
  1103. /** 
  1104. * Returns an instance of the class 
  1105. * @param mixed $context 
  1106. * @return C_Displayed_Gallery_Renderer 
  1107. */ 
  1108. static function get_instance($context = FALSE) 
  1109. if (!isset(self::$_instances[$context])) { 
  1110. $klass = __CLASS__; 
  1111. self::$_instances[$context] = new $klass($context); 
  1112. return self::$_instances[$context]; 
  1113. /** 
  1114. * Defines the object 
  1115. * @param bool $context 
  1116. */ 
  1117. public function define($context = FALSE) 
  1118. parent::define($context); 
  1119. $this->add_mixin('Mixin_Displayed_Gallery_Renderer'); 
  1120. $this->implement('I_Displayed_Gallery_Renderer'); 
  1121. /** 
  1122. * Provides the ability to render a display type 
  1123. */ 
  1124. class Mixin_Displayed_Gallery_Renderer extends Mixin 
  1125. /** 
  1126. * Displays a "displayed gallery" instance 
  1127. * 
  1128. * Alias Properties: 
  1129. * gallery_ids/album_ids/tag_ids == container_ids 
  1130. * image_ids/gallery_ids == entity_ids 
  1131. * 
  1132. * Default Behavior: 
  1133. * - if order_by and order_direction are missing, the default settings 
  1134. * are used from the "Other Options" page. The exception to this is 
  1135. * when entity_ids are selected, in which the order is custom unless 
  1136. * specified. 
  1137. * 
  1138. * How to use: 
  1139. * 
  1140. * To retrieve images from gallery 1 & 3, but exclude images 4 & 6: 
  1141. * [ngg_images gallery_ids="1, 3" exclusions="4, 6" display_type="photocrati-nextgen_basic_thumbnails"] 
  1142. * 
  1143. * To retrieve images 1 & 2 from gallery 1: 
  1144. * [ngg_images gallery_ids="1" image_ids="1, 2" display_type="photocrati-nextgen_basic_thumbnails"] 
  1145. * 
  1146. * To retrieve images matching tags "landscapes" and "wedding shoots": 
  1147. * [ngg_images tag_ids="landscapes, wedding shoots" display_type="photocrati-nextgen_basic_thumbnails"] 
  1148. * 
  1149. * To retrieve galleries from albums 1 & #, but exclude sub-album 1: 
  1150. * [ngg_images album_ids="1, 2" exclusions="a1" display_type="photocrati-nextgen_basic_compact_album"] 
  1151. * 
  1152. * To retrieve galleries from albums 1 & 2, but exclude gallery 1: 
  1153. * [ngg_images album_ids="1, 2" exclusions="1" display_type="photocrati-nextgen_basic_compact_album"] 
  1154. * 
  1155. * To retrieve image 2, 3, and 5 - independent of what container is used 
  1156. * [ngg_images image_ids="2, 3, 5" display_type="photocrati-nextgen_basic_thumbnails"] 
  1157. * 
  1158. * To retrieve galleries 3 & 5, custom sorted, in album view 
  1159. * [ngg_images source="albums" gallery_ids="3, 5" display_type="photocrati-nextgen_basic_compact_album"] 
  1160. * 
  1161. * To retrieve recent images, sorted by alt/title text 
  1162. * [ngg_images source="recent" order_by="alttext" display_type="photocrati-nextgen_basic_thumbnails"] 
  1163. * 
  1164. * To retrieve random image 
  1165. * [ngg_images source="random" display_type="photocrati-nextgen_basic_thumbnails"] 
  1166. * 
  1167. * To retrieve a single image 
  1168. * [ngg_images image_ids='8' display_type='photocrati-nextgen_basic_singlepic'] 
  1169. * 
  1170. * To retrieve a tag cloud 
  1171. * [ngg_images tagcloud=yes display_type='photocrati-nextgen_basic_tagcloud'] 
  1172. */ 
  1173. public function display_images($params, $inner_content = NULL, $mode = NULL) 
  1174. $retval = ''; 
  1175. $displayed_gallery = NULL; 
  1176. // Get the NextGEN settings to provide some defaults 
  1177. $settings = C_NextGen_Settings::get_instance(); 
  1178. // Configure the arguments 
  1179. $defaults = array('id' => NULL, 'source' => '', 'container_ids' => array(), 'gallery_ids' => array(), 'album_ids' => array(), 'tag_ids' => array(), 'display_type' => '', 'exclusions' => array(), 'order_by' => $settings->galSort, 'order_direction' => $settings->galSortOrder, 'image_ids' => array(), 'entity_ids' => array(), 'tagcloud' => FALSE, 'inner_content' => $inner_content, 'returns' => 'included', 'slug' => NULL); 
  1180. $args = shortcode_atts($defaults, $params); 
  1181. // Are we loading a specific displayed gallery that's persisted? 
  1182. $mapper = C_Displayed_Gallery_Mapper::get_instance(); 
  1183. if (!is_null($args['id'])) { 
  1184. $displayed_gallery = $mapper->find($args['id']); 
  1185. unset($mapper); 
  1186. } else { 
  1187. // Perform some conversions... 
  1188. // Galleries? 
  1189. if ($args['gallery_ids']) { 
  1190. if ($args['source'] != 'albums' and $args['source'] != 'album') { 
  1191. $args['source'] = 'galleries'; 
  1192. $args['container_ids'] = $args['gallery_ids']; 
  1193. if ($args['image_ids']) { 
  1194. $args['entity_ids'] = $args['image_ids']; 
  1195. } elseif ($args['source'] == 'albums') { 
  1196. $args['entity_ids'] = $args['gallery_ids']; 
  1197. unset($args['gallery_ids']); 
  1198. } elseif ($args['album_ids'] || $args['album_ids'] === '0') { 
  1199. $args['source'] = 'albums'; 
  1200. $args['container_ids'] = $args['album_ids']; 
  1201. unset($args['albums_ids']); 
  1202. } elseif ($args['tag_ids']) { 
  1203. $args['source'] = 'tags'; 
  1204. $args['container_ids'] = $args['tag_ids']; 
  1205. unset($args['tag_ids']); 
  1206. } elseif ($args['image_ids']) { 
  1207. $args['source'] = 'galleries'; 
  1208. $args['entity_ids'] = $args['image_ids']; 
  1209. unset($args['image_ids']); 
  1210. } elseif ($args['tagcloud']) { 
  1211. $args['source'] = 'tags'; 
  1212. // Convert strings to arrays 
  1213. if (!is_array($args['container_ids'])) { 
  1214. $args['container_ids'] = preg_split('/, |\\|/', $args['container_ids']); 
  1215. if (!is_array($args['exclusions'])) { 
  1216. $args['exclusions'] = preg_split('/, |\\|/', $args['exclusions']); 
  1217. if (!is_array($args['entity_ids'])) { 
  1218. $args['entity_ids'] = preg_split('/, |\\|/', $args['entity_ids']); 
  1219. // Get the display settings 
  1220. foreach (array_keys($defaults) as $key) { 
  1221. unset($params[$key]); 
  1222. $args['display_settings'] = $params; 
  1223. // Create the displayed gallery 
  1224. $factory = C_Component_Factory::get_instance(); 
  1225. $displayed_gallery = $factory->create('displayed_gallery', $args, $mapper); 
  1226. unset($factory); 
  1227. // Validate the displayed gallery 
  1228. if ($displayed_gallery) { 
  1229. if ($displayed_gallery->validate()) { 
  1230. // Display! 
  1231. return $this->object->render($displayed_gallery, TRUE, $mode); 
  1232. } else { 
  1233. if (C_NextGEN_Bootstrap::$debug) { 
  1234. $retval = __('We cannot display this gallery', 'nggallery') . $this->debug_msg($displayed_gallery->get_errors()) . $this->debug_msg($displayed_gallery->get_entity()); 
  1235. } else { 
  1236. $retval = __('We cannot display this gallery', 'nggallery'); 
  1237. } else { 
  1238. $retval = __('We cannot display this gallery', 'nggallery'); 
  1239. return $retval; 
  1240. public function debug_msg($msg, $print_r = FALSE) 
  1241. $retval = ''; 
  1242. if (C_NextGEN_Bootstrap::$debug) { 
  1243. ob_start(); 
  1244. if ($print_r) { 
  1245. echo '<pre>'; 
  1246. print_r($msg); 
  1247. echo '</pre>'; 
  1248. } else { 
  1249. var_dump($msg); 
  1250. $retval = ob_get_clean(); 
  1251. return $retval; 
  1252. /** 
  1253. * Renders a displayed gallery on the frontend 
  1254. * @param C_Displayed_Gallery|stdClass $displayed_gallery 
  1255. */ 
  1256. public function render($displayed_gallery, $return = FALSE, $mode = null) 
  1257. $retval = ''; 
  1258. $lookup = TRUE; 
  1259. // Simply throwing our rendered gallery into a feed will most likely not work correctly. 
  1260. // The MediaRSS option in NextGEN is available as an alternative. 
  1261. if (!C_NextGen_Settings::get_instance()->galleries_in_feeds && is_feed()) { 
  1262. return sprintf(__(' [<a href="%s">See image gallery at %s</a>] ', 'nggallery'), esc_url(apply_filters('the_permalink_rss', get_permalink())), $_SERVER['SERVER_NAME']); 
  1263. if ($mode == null) { 
  1264. $mode = 'normal'; 
  1265. if (apply_filters('ngg_cache_displayed_galleries', FALSE)) { 
  1266. // Save the displayed gallery as a transient if it hasn't already. Allows for ajax operations 
  1267. // to add or modify the gallery without losing a retrievable ID 
  1268. if (!$displayed_gallery->apply_transient()) { 
  1269. $displayed_gallery->to_transient(); 
  1270. } else { 
  1271. if (is_null($displayed_gallery->id())) { 
  1272. $displayed_gallery->id(md5(json_encode($displayed_gallery->get_entity()))); 
  1273. // Get the display type controller 
  1274. $controller = $this->get_registry()->get_utility('I_Display_Type_Controller', $displayed_gallery->display_type); 
  1275. // Get routing info 
  1276. $router = C_Router::get_instance(); 
  1277. $url = $router->get_url($router->get_request_uri(), TRUE); 
  1278. // Should we lookup in cache? 
  1279. if (is_array($displayed_gallery->container_ids) && in_array('All', $displayed_gallery->container_ids)) { 
  1280. $lookup = FALSE; 
  1281. } elseif ($displayed_gallery->source == 'albums' && $controller->param('gallery') or $controller->param('album')) { 
  1282. $lookup = FALSE; 
  1283. } elseif ($controller->param('show')) { 
  1284. $lookup = FALSE; 
  1285. } elseif ($controller->is_cachable() === FALSE) { 
  1286. $lookup = FALSE; 
  1287. } elseif (!NGG_RENDERING_CACHE_ENABLED) { 
  1288. $lookup = FALSE; 
  1289. // Enqueue any necessary static resources 
  1290. if (!defined('NGG_SKIP_LOAD_SCRIPTS') || !NGG_SKIP_LOAD_SCRIPTS) { 
  1291. $controller->enqueue_frontend_resources($displayed_gallery); 
  1292. // Try cache lookup, if we're to do so 
  1293. $key = NULL; 
  1294. $html = FALSE; 
  1295. if ($lookup) { 
  1296. // The display type may need to output some things 
  1297. // even when serving from the cache 
  1298. if ($controller->has_method('cache_action')) { 
  1299. $retval = $controller->cache_action($displayed_gallery); 
  1300. // Output debug message 
  1301. $retval .= $this->debug_msg('Lookup!'); 
  1302. // Some settings affect display types 
  1303. $settings = C_NextGen_Settings::get_instance(); 
  1304. $key_params = apply_filters('ngg_displayed_gallery_cache_params', array($displayed_gallery->get_entity(), $url, $mode, $settings->activateTags, $settings->appendType, $settings->maxImages, $settings->thumbEffect, $settings->thumbCode, $settings->galSort, $settings->galSortDir)); 
  1305. // Any displayed gallery links on the home page will need to be regenerated if the permalink structure 
  1306. // changes 
  1307. if (is_home() or is_front_page()) { 
  1308. $key_params[] = get_option('permalink_structure'); 
  1309. // Try getting the rendered HTML from the cache 
  1310. $key = C_Photocrati_Transient_Manager::create_key('displayed_gallery_rendering', $key_params); 
  1311. $html = C_Photocrati_Transient_Manager::fetch($key, FALSE); 
  1312. // Output debug message
  1313. if ($html) { 
  1314. $retval .= $this->debug_msg('HIT!'); 
  1315. } else { 
  1316. $retval .= $this->debug_msg('MISS!'); 
  1317. // TODO: This is hack. We need to figure out a more uniform way of detecting dynamic image urls 
  1318. if (strpos($html, C_Photocrati_Settings_Manager::get_instance()->dynamic_thumbnail_slug . '/') !== FALSE) { 
  1319. $html = FALSE; 
  1320. } else { 
  1321. $retval .= $this->debug_msg('Not looking up in cache as per rules'); 
  1322. // If we're displaying a variant, I want to know it 
  1323. if (isset($displayed_gallery->variation) && is_numeric($displayed_gallery->variation) && $displayed_gallery->variation > 0) { 
  1324. $retval .= $this->debug_msg("Using variation #{$displayed_gallery->variation}!"); 
  1325. // If a cached version doesn't exist, then create the cache 
  1326. if (!$html) { 
  1327. $retval .= $this->debug_msg('Rendering displayed gallery'); 
  1328. $current_mode = $controller->get_render_mode(); 
  1329. $controller->set_render_mode($mode); 
  1330. $html = apply_filters('ngg_displayed_gallery_rendering', $controller->index_action($displayed_gallery, TRUE), $displayed_gallery); 
  1331. if ($key != null) { 
  1332. C_Photocrati_Transient_Manager::update($key, $html, NGG_RENDERING_CACHE_TTL); 
  1333. $retval .= $html; 
  1334. if (!$return) { 
  1335. echo $retval; 
  1336. return $retval; 
  1337. class C_Displayed_Gallery_Source_Manager 
  1338. private $_sources = array(); 
  1339. private $_entity_types = array(); 
  1340. private $_registered_defaults = array(); 
  1341. /** @var C_Displayed_Gallery_Source_Manager */ 
  1342. static $_instance = NULL; 
  1343. static function get_instance() 
  1344. if (!isset(self::$_instance)) { 
  1345. $klass = get_class(); 
  1346. self::$_instance = new $klass(); 
  1347. return self::$_instance; 
  1348. public function register_defaults() 
  1349. // Entity types must be registered first!!! 
  1350. // ---------------------------------------- 
  1351. $this->register_entity_type('gallery', 'galleries'); 
  1352. $this->register_entity_type('image', 'images'); 
  1353. $this->register_entity_type('album', 'albums'); 
  1354. // Galleries 
  1355. $galleries = new stdClass(); 
  1356. $galleries->name = 'galleries'; 
  1357. $galleries->title = __('Galleries', 'nggallery'); 
  1358. $galleries->aliases = array('gallery', 'images', 'image'); 
  1359. $galleries->returns = array('image'); 
  1360. $this->register($galleries->name, $galleries); 
  1361. // Albums 
  1362. $albums = new stdClass(); 
  1363. $albums->name = 'albums'; 
  1364. $albums->title = __('Albums', 'nggallery'); 
  1365. $albums->aliases = array('album'); 
  1366. $albums->returns = array('album', 'gallery'); 
  1367. $this->register($albums->name, $albums); 
  1368. // Tags 
  1369. $tags = new stdClass(); 
  1370. $tags->name = 'tags'; 
  1371. $tags->title = __('Tags', 'nggallery'); 
  1372. $tags->aliases = array('tag', 'image_tags', 'image_tag'); 
  1373. $tags->returns = array('image'); 
  1374. $this->register($tags->name, $tags); 
  1375. // Random Images; 
  1376. $random = new stdClass(); 
  1377. $random->name = 'random_images'; 
  1378. $random->title = __('Random Images', 'nggallery'); 
  1379. $random->aliases = array('random', 'random_image'); 
  1380. $random->returns = array('image'); 
  1381. $random->has_variations = TRUE; 
  1382. $this->register($random->name, $random); 
  1383. // Recent Images 
  1384. $recent = new stdClass(); 
  1385. $recent->name = 'recent_images'; 
  1386. $recent->title = __('Recent Images', 'nggallery'); 
  1387. $recent->aliases = array('recent', 'recent_image'); 
  1388. $recent->returns = array('image'); 
  1389. $this->register($recent->name, $recent); 
  1390. $this->_registered_defaults = TRUE; 
  1391. public function register($name, $properties) 
  1392. // We'll use an object to represent the source 
  1393. $object = $properties; 
  1394. if (!is_object($properties)) { 
  1395. $object = new stdClass(); 
  1396. foreach ($properties as $k => $v) { 
  1397. $object->{$k} = $v; 
  1398. // Set default properties 
  1399. $object->name = $name; 
  1400. if (!isset($object->title)) { 
  1401. $object->title = $name; 
  1402. if (!isset($object->returns)) { 
  1403. $object->returns = array(); 
  1404. if (!isset($object->aliases)) { 
  1405. $object->aliases = array(); 
  1406. if (!isset($object->has_variations)) { 
  1407. $object->has_variations = FALSE; 
  1408. // Add internal reference 
  1409. $this->_sources[$name] = $object; 
  1410. foreach ($object->aliases as $name) { 
  1411. $this->_sources[$name] = $object; 
  1412. public function register_entity_type() 
  1413. $aliases = func_get_args(); 
  1414. $name = array_shift($aliases); 
  1415. $this->_entity_types[] = $name; 
  1416. foreach ($aliases as $alias) { 
  1417. $this->_entity_types[$alias] = $name; 
  1418. public function deregister($name) 
  1419. if ($source = $this->get($name)) { 
  1420. unset($this->_sources[$name]); 
  1421. foreach ($source->aliases as $alias) { 
  1422. unset($this->_sources[$alias]); 
  1423. public function deregister_entity_type($name) 
  1424. unset($this->_entity_types[$name]); 
  1425. public function get($name_or_alias) 
  1426. if (!$this->_registered_defaults) { 
  1427. $this->register_defaults(); 
  1428. $retval = NULL; 
  1429. if (isset($this->_sources[$name_or_alias])) { 
  1430. $retval = $this->_sources[$name_or_alias]; 
  1431. return $retval; 
  1432. public function get_entity_type($name) 
  1433. if (!$this->_registered_defaults) { 
  1434. $this->register_defaults(); 
  1435. $found = array_search($name, $this->_entity_types); 
  1436. if ($found) { 
  1437. return $this->_entity_types[$found]; 
  1438. } else { 
  1439. return NULL; 
  1440. public function get_all() 
  1441. if (!$this->_registered_defaults) { 
  1442. $this->register_defaults(); 
  1443. $retval = array(); 
  1444. foreach (array_values($this->_sources) as $source_obj) { 
  1445. if (!in_array($source_obj, $retval)) { 
  1446. $retval[] = $source_obj; 
  1447. usort($retval, array(&$this, '__sort_by_name')); 
  1448. return $retval; 
  1449. public function __sort_by_name($a, $b) 
  1450. return strcmp($a->name, $b->name); 
  1451. public function get_all_entity_types() 
  1452. if (!$this->_registered_defaults) { 
  1453. $this->register_defaults(); 
  1454. return array_unique(array_values($this->_entity_types)); 
  1455. public function is_registered($name) 
  1456. return !is_null($this->get($name)); 
  1457. public function is_valid_entity_type($name) 
  1458. return !is_null($this->get_entity_type($name)); 
  1459. public function deregister_all() 
  1460. $this->_sources = array(); 
  1461. $this->_entity_types = array(); 
  1462. $this->_registered_defaults = FALSE; 
  1463. public function is_compatible($source, $display_type) 
  1464. $retval = FALSE; 
  1465. if ($source = $this->get($source->name)) { 
  1466. // Get the real entity type names for the display type 
  1467. $display_type_entity_types = array(); 
  1468. foreach ($display_type->entity_types as $type) { 
  1469. $result = $this->get_entity_type($type); 
  1470. if ($result) { 
  1471. $display_type_entity_types[] = $result; 
  1472. foreach ($source->returns as $entity_type) { 
  1473. if (in_array($entity_type, $display_type_entity_types, TRUE)) { 
  1474. $retval = TRUE; 
  1475. break; 
  1476. return $retval; 
  1477. abstract class C_Displayed_Gallery_Trigger 
  1478. static function is_renderable($name, $displayed_gallery) 
  1479. return TRUE; 
  1480. public function get_css_class() 
  1481. return 'fa fa-circle'; 
  1482. public function get_attributes() 
  1483. return array('class' => $this->get_css_class()); 
  1484. public function render() 
  1485. $attributes = array(); 
  1486. foreach ($this->get_attributes() as $k => $v) { 
  1487. $k = esc_attr($k); 
  1488. $v = esc_attr($v); 
  1489. $attributes[] = "{$k}='{$v}'"; 
  1490. $attributes = implode(' ', $attributes); 
  1491. return "<i {$attributes}></i>"; 
  1492. /** 
  1493. * The Trigger Manager displays "trigger buttons" for a displayed gallery. 
  1494. * 
  1495. * Each display type can register a "handler", which is a class with a render method, which is used 
  1496. * to render the display of the trigger buttons. 
  1497. * 
  1498. * Each trigger button is registered with a handler, which is also a class with a render() method. 
  1499. * Class C_Displayed_Gallery_Trigger_Manager 
  1500. */ 
  1501. class C_Displayed_Gallery_Trigger_Manager 
  1502. static $_instance = NULL; 
  1503. private $_triggers = array(); 
  1504. private $_trigger_order = array(); 
  1505. private $_display_type_handlers = array(); 
  1506. private $_default_display_type_handler = NULL; 
  1507. private $css_class = 'ngg-trigger-buttons'; 
  1508. private $_default_image_types = array('photocrati-nextgen_basic_thumbnails', 'photocrati-nextgen_basic_singlepic', 'photocrati-nextgen_pro_thumbnail_grid', 'photocrati-nextgen_pro_blog_gallery', 'photocrati-nextgen_pro_film'); 
  1509. /** 
  1510. * @return C_Displayed_Gallery_Trigger_Manager 
  1511. */ 
  1512. static function get_instance() 
  1513. if (!self::$_instance) { 
  1514. $klass = get_class(); 
  1515. self::$_instance = new $klass(); 
  1516. return self::$_instance; 
  1517. public function __construct() 
  1518. $this->_default_display_type_handler = 'C_Displayed_Gallery_Trigger_Handler'; 
  1519. foreach ($this->_default_image_types as $display_type) { 
  1520. $this->register_display_type_handler($display_type, 'C_Displayed_Gallery_Image_Trigger_Handler'); 
  1521. public function register_display_type_handler($display_type, $klass) 
  1522. $this->_display_type_handlers[$display_type] = $klass; 
  1523. public function deregister_display_type_handler($display_type) 
  1524. unset($this->_display_type_handlers[$display_type]); 
  1525. public function add($name, $handler) 
  1526. $this->_triggers[$name] = $handler; 
  1527. $this->_trigger_order[] = $name; 
  1528. return $this; 
  1529. public function remove($name) 
  1530. $order = array(); 
  1531. unset($this->_triggers[$name]); 
  1532. foreach ($this->_trigger_order as $trigger) { 
  1533. if ($trigger != $name) { 
  1534. $order[] = $trigger; 
  1535. $this->_trigger_order = $order; 
  1536. return $this; 
  1537. public function _rebuild_index() 
  1538. $order = array(); 
  1539. foreach ($this->_trigger_order as $name) { 
  1540. $order[] = $name; 
  1541. $this->_trigger_order = $order; 
  1542. return $this; 
  1543. public function increment_position($name) 
  1544. if (($current_index = array_search($name, $this->_trigger_order)) !== FALSE) { 
  1545. $next_index = $current_index += 1; 
  1546. // 1, 2, 3, 4, 5 => 1, 2, 4, 3, 5 
  1547. if (isset($this->_trigger_order[$next_index])) { 
  1548. $next = $this->_trigger_order[$next_index]; 
  1549. $this->_trigger_order[$next_index] = $name; 
  1550. $this->_trigger_order[$current_index] = $next; 
  1551. return $this->position_of($name); 
  1552. public function decrement_position($name) 
  1553. if (($current_index = array_search($name, $this->_trigger_order)) !== FALSE) { 
  1554. $previous_index = $current_index -= 1; 
  1555. if (isset($this->_trigger_order[$previous_index])) { 
  1556. $previous = $this->_trigger_order[$previous_index]; 
  1557. $this->_trigger_order[$previous_index] = $name; 
  1558. $this->_trigger_order[$current_index] = $previous; 
  1559. return $this->position_of($name); 
  1560. public function position_of($name) 
  1561. return array_search($name, $this->_trigger_order); 
  1562. public function move_to_position($name, $position_index) 
  1563. if (($current_index = $this->position_of($name)) !== FALSE) { 
  1564. $func = 'increment_position'; 
  1565. if ($current_index < $position_index) { 
  1566. $func = 'decrement_position'; 
  1567. while ($this->position_of($name) != $position_index) { 
  1568. $this->{$func}($name); 
  1569. return $this->position_of($name); 
  1570. public function move_to_start($name) 
  1571. if ($index = $this->position_of($name)) { 
  1572. unset($this->_trigger_order[$index]); 
  1573. array_unshift($this->_trigger_order, $name); 
  1574. $this->_rebuild_index(); 
  1575. return $this->position_of($name); 
  1576. public function count() 
  1577. return count($this->_trigger_order); 
  1578. public function move_to_end($name) 
  1579. $index = $this->position_of($name); 
  1580. if ($index !== FALSE or $index != $this->count() - 1) { 
  1581. unset($this->_trigger_order[$index]); 
  1582. $this->_trigger_order[] = $name; 
  1583. $this->_rebuild_index(); 
  1584. return $this->position_of($name); 
  1585. public function get_handler_for_displayed_gallery($displayed_gallery) 
  1586. // Find the trigger handler for the current display type. 
  1587. // First, check the display settings for the displayed gallery. Some third-party 
  1588. // display types might specify their own handler 
  1589. $klass = NULL; 
  1590. if (isset($displayed_gallery->display_settings['trigger_handler'])) { 
  1591. $klass = $displayed_gallery->display_settings['trigger_handler']; 
  1592. } else { 
  1593. $klass = $this->_default_display_type_handler; 
  1594. if (isset($this->_display_type_handlers[$displayed_gallery->display_type])) { 
  1595. $klass = $this->_display_type_handlers[$displayed_gallery->display_type]; 
  1596. return $klass; 
  1597. public function render($view, $displayed_gallery) 
  1598. if ($klass = $this->get_handler_for_displayed_gallery($displayed_gallery)) { 
  1599. $handler = new $klass(); 
  1600. $handler->view = $view; 
  1601. $handler->displayed_gallery = $displayed_gallery; 
  1602. $handler->manager = $this; 
  1603. if (method_exists($handler, 'render')) { 
  1604. $handler->render(); 
  1605. return $view; 
  1606. public function render_trigger($name, $view, $displayed_gallery) 
  1607. $retval = ''; 
  1608. if (isset($this->_triggers[$name])) { 
  1609. $klass = $this->_triggers[$name]; 
  1610. if (call_user_func(array($klass, 'is_renderable'), $name, $displayed_gallery)) { 
  1611. $handler = new $klass(); 
  1612. $handler->name = $name; 
  1613. $handler->view = $this->view = $view; 
  1614. $handler->displayed_gallery = $displayed_gallery; 
  1615. $retval = $handler->render(); 
  1616. return $retval; 
  1617. public function render_triggers($view, $displayed_gallery) 
  1618. $output = FALSE; 
  1619. $css_class = esc_attr($this->css_class); 
  1620. $retval = array("<div class='{$css_class}'>"); 
  1621. foreach ($this->_trigger_order as $name) { 
  1622. if ($markup = $this->render_trigger($name, $view, $displayed_gallery)) { 
  1623. $output = TRUE; 
  1624. $retval[] = $markup; 
  1625. if ($output) { 
  1626. $retval[] = '</div>'; 
  1627. $retval = implode(' 
  1628. ', $retval); 
  1629. } else { 
  1630. $retval = ''; 
  1631. return $retval; 
  1632. public function enqueue_resources($displayed_gallery) 
  1633. if ($handler = $this->get_handler_for_displayed_gallery($displayed_gallery)) { 
  1634. wp_enqueue_style('fontawesome'); 
  1635. wp_enqueue_style('ngg_trigger_buttons'); 
  1636. if (method_exists($handler, 'enqueue_resources')) { 
  1637. call_user_func(array($handler, 'enqueue_resources'), $displayed_gallery); 
  1638. foreach ($this->_trigger_order as $name) { 
  1639. $handler = $this->_triggers[$name]; 
  1640. $renderable = TRUE; 
  1641. if (method_exists($handler, 'is_renderable')) { 
  1642. $renderable = call_user_func($handler, 'is_renderable', $name, $displayed_gallery); 
  1643. if ($renderable && method_exists($handler, 'enqueue_resources')) { 
  1644. call_user_func(array($handler, 'enqueue_resources', $name, $displayed_gallery)); 
  1645. class C_Displayed_Gallery_Image_Trigger_Handler 
  1646. public function render() 
  1647. foreach ($this->view->find('nextgen_gallery.image', true) as $image_element) { 
  1648. $image_element->append($this->manager->render_triggers($image_element, $this->displayed_gallery)); 
  1649. class C_Displayed_Gallery_Trigger_Handler 
  1650. public function render() 
  1651. $this->view->append($this->manager->render_triggers($this->view, $this->displayed_gallery)); 
  1652. class Mixin_Display_Type_Form extends Mixin 
  1653. public $_model = null; 
  1654. public function initialize() 
  1655. $this->object->implement('I_Display_Type_Form'); 
  1656. /** 
  1657. * Returns the name of the display type. Sub-class should override 
  1658. * @throws Exception 
  1659. * @returns string 
  1660. */ 
  1661. public function get_display_type_name() 
  1662. throw new Exception(__METHOD__ . ' not implemented'); 
  1663. /** 
  1664. * Returns the model (display type) used in the form 
  1665. * @return stdClass 
  1666. */ 
  1667. public function get_model() 
  1668. if ($this->_model == null) { 
  1669. $mapper = C_Display_Type_Mapper::get_instance(); 
  1670. $this->_model = $mapper->find_by_name($this->object->get_display_type_name(), TRUE); 
  1671. return $this->_model; 
  1672. /** 
  1673. * Returns the title of the form, which is the title of the display type 
  1674. * @returns string 
  1675. */ 
  1676. public function get_title() 
  1677. return __($this->object->get_model()->title, 'nggallery'); 
  1678. /** 
  1679. * Saves the settings for the display type 
  1680. * @param array $attributes 
  1681. * @return boolean 
  1682. */ 
  1683. public function save_action($attributes = array()) 
  1684. return $this->object->get_model()->save(array('settings' => $attributes)); 
.