photocrati_nextgen/modules/ajax/module.ajax.php000064400000003453150212224050015761 0ustar00get_registry()->add_utility( 'I_Ajax_Controller', 'C_Ajax_Controller' ); } public function _register_hooks() { add_action( 'ngg_routes', [ $this, 'define_routes' ] ); add_action( 'init', [ $this, 'serve_ajax_request' ] ); } public function serve_ajax_request() { // This method only begins NextGEN's AJAX endpoint handler, individual endpoints are responsible for // their own nonce and other security checks. // // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( isset( $_REQUEST[ NGG_AJAX_SLUG ] ) ) { $controller = C_Ajax_Controller::get_instance(); $controller->index_action(); exit(); } } public function define_routes( $router ) { $app = $router->create_app( '/photocrati_ajax' ); $app->route( '/', 'I_Ajax_Controller#index' ); } /** * Pass PHP object or array to JS, preserving numeric and boolean value * * @param string $handle * @param string $var_name * @param object|array $data */ static function pass_data_to_js( $handle, $var_name, $data ) { $var_name = esc_js( $var_name ); return wp_add_inline_script( $handle, "let {$var_name} = " . json_encode( $data, JSON_NUMERIC_CHECK ) ); } public function get_type_list() { return [ 'C_Ajax_Controller' => 'class.ajax_controller.php' ]; } } new M_Ajax(); photocrati_nextgen/modules/ajax/package.module.ajax.php000064400000004714150212224050017354 0ustar00implement('I_Ajax_Controller'); } public function index_action($return = false) { $retval = null; define('DOING_AJAX', true); // Inform the MVC framework what type of content we're returning. $this->set_content_type('json'); // Start an output buffer to avoid displaying any PHP warnings/errors. ob_start(); // Get the action requested & find and execute the related method. if ($action = $this->param('action')) { $method = "{$action}_action"; if ($this->has_method($method)) { $retval = $this->call_method($method); } else { $retval = ['error' => 'Not a valid AJAX action']; } } else { $retval = ['error' => 'No action specified']; } // Flush the buffer. $buffer_limit = 0; $zlib = ini_get('zlib.output_compression'); if (!is_numeric($zlib) && $zlib == 'On') { $buffer_limit = 1; } elseif (is_numeric($zlib) && $zlib > 0) { $buffer_limit = 1; } while (ob_get_level() != $buffer_limit) { ob_end_clean(); } // Return the JSON to the browser. wp_send_json($retval); } public function validate_ajax_request($action = null, $token = false) { // Security::verify_nonce() is a wrapper to wp_verify_nonce(). // // phpcs:disable WordPress.Security.NonceVerification.Recommended if (true === $token && (!isset($_REQUEST['nonce']) || !\Imagely\NGG\Util\Security::verify_nonce(sanitize_text_field(wp_unslash($_REQUEST['nonce'])), $action))) { return false; } // phpcs:enable WordPress.Security.NonceVerification.Recommended return \Imagely\NGG\Util\Security::is_allowed($action); } }photocrati_nextgen/modules/ajax/README.txt000064400000002164150212224050014535 0ustar00AJAX MODULE ====================== == Introduction == ------------------- This module provides a means for executing AJAX actions through the C_Ajax_Controller class. This controller is registed as a route, trigged by "/photocrati_ajax" It's designed in mind with the intention that other modules will adapt this controller to provide custom AJAX actions. This module also adds some client-side variables to assist with executing your AJAX actions: => photocrati_ajax.url, the url used to post your AJAX requests to => photacrati_ajax.wp_site_url, the url of the WordPress site To call an AJAX method using jQuery, you'd do the following: jQuery.post(photocrati_ajax.url, {action: "get_gallery", id: 1}, function(response){ if (typeof response != 'object) response = JSON.parse(response); }); The above AJAX request will execute C_Ajax_Controller->get_gallery_action(), which is expected to return valid JSON (even if there is an error) == Caveats == ------------- This module does not currently have any built-in security mechanisms. Any actions you mixin using an adapter need to perform their own authorization checks.photocrati_nextgen/modules/nextgen_basic_album/package.module.nextgen_basic_album.php000064400000036672150212224050025500 0ustar00are_breadcrumbs_enabled($display_settings['original_settings'])) { $retval = true; } return $retval; } public function get_original_album_entities($display_settings) { $retval = []; if (isset($display_settings['original_album_entities'])) { $retval = $display_settings['original_album_entities']; } elseif (isset($display_settings['original_settings']) && $this->get_original_album_entities($display_settings['original_settings'])) { $retval = $this->get_original_album_entities($display_settings['original_settings']); } return $retval; } public function render_object() { $root_element = $this->call_parent('render_object'); if ($displayed_gallery = $this->object->get_param('displayed_gallery')) { $ds = $displayed_gallery->display_settings; if ($this->are_breadcrumbs_enabled($ds) && ($original_entities = $this->get_original_album_entities($ds))) { $original_entities = $this->get_original_album_entities($ds); if (!empty($ds['original_album_id'])) { $ids = $ds['original_album_id']; } else { $ids = $displayed_gallery->container_ids; } $breadcrumbs = $this->object->generate_breadcrumb($ids, $original_entities); foreach ($root_element->find('nextgen_gallery.gallery_container', true) as $container) { $container->insert($breadcrumbs); } } } return $root_element; } public function render_legacy_template_breadcrumbs($displayed_gallery, $entities, $gallery_id = false) { $ds = $displayed_gallery->display_settings; if (!empty($entities) && !empty($ds['template']) && $this->are_breadcrumbs_enabled($ds)) { if ($gallery_id) { if (is_array($gallery_id)) { $ids = $gallery_id; } else { $ids = [$gallery_id]; } } elseif (!empty($ds['original_album_id'])) { $ids = $ds['original_album_id']; } else { $ids = $displayed_gallery->container_ids; } // Prevent galleries with the same ID as the parent album being displayed as the root // breadcrumb when viewing the album page. if (is_array($ids) && count($ids) == 1 && strpos($ids[0], 'a') !== 0) { $ids = []; } if (!empty($ds['original_album_entities'])) { $breadcrumb_entities = $ds['original_album_entities']; } else { $breadcrumb_entities = $entities; } return $this->object->generate_breadcrumb($ids, $breadcrumb_entities); } else { return ''; } } public function find_gallery_parent($gallery_id, $sortorder) { $map = \Imagely\NGG\DataMappers\Album::get_instance(); $found = []; foreach ($sortorder as $order) { if (strpos($order, 'a') === 0) { $album_id = ltrim($order, 'a'); if (empty($this->breadcrumb_cache[$order])) { $album = $map->find($album_id); $this->breadcrumb_cache[$order] = $album; if (in_array($gallery_id, $album->sortorder)) { $found[] = $album; break; } else { $found = $this->find_gallery_parent($gallery_id, $album->sortorder); if ($found) { $found[] = $album; break; } } } } } return $found; } public function generate_breadcrumb($gallery_id, $entities) { $found = []; $router = \Imagely\NGG\Util\Router::get_instance(); $app = $router->get_routed_app(); if (is_array($gallery_id)) { $gallery_id = array_shift($gallery_id); } if (is_array($gallery_id)) { $gallery_id = $gallery_id[0]; } foreach ($entities as $ndx => $entity) { $tmpid = (isset($entity->albumdesc) ? 'a' : '') . $entity->{$entity->id_field}; $this->breadcrumb_cache[$tmpid] = $entity; if (isset($entity->albumdesc) && in_array($gallery_id, $entity->sortorder)) { $found[] = $entity; break; } } if (empty($found)) { foreach ($entities as $entity) { if (!empty($entity->sortorder)) { $found = $this->object->find_gallery_parent($gallery_id, $entity->sortorder); } if (!empty($found)) { $found[] = $entity; break; } } } $found = array_reverse($found); if (strpos($gallery_id, 'a') === 0) { $album_found = false; foreach ($found as $found_item) { if ($found_item->{$found_item->id_field} == $gallery_id) { $album_found = true; } } if (!$album_found) { $album_id = ltrim($gallery_id, 'a'); $album = \Imagely\NGG\DataMappers\Album::get_instance()->find($album_id); $found[] = $album; $this->breadcrumb_cache[$gallery_id] = $album; } } else { $gallery_found = false; foreach ($entities as $entity) { if (isset($entity->is_gallery) && $entity->is_gallery && $gallery_id == $entity->{$entity->id_field}) { $gallery_found = true; $found[] = $entity; break; } } if (!$gallery_found) { $gallery = \Imagely\NGG\DataMappers\Gallery::get_instance()->find($gallery_id); if ($gallery != null) { $found[] = $gallery; $this->breadcrumb_cache[$gallery->{$gallery->id_field}] = $gallery; } } } $crumbs = []; if (!empty($found)) { $end = end($found); reset($found); foreach ($found as $found_item) { $type = isset($found_item->albumdesc) ? 'album' : 'gallery'; $id = ($type == 'album' ? 'a' : '') . $found_item->{$found_item->id_field}; $entity = $this->breadcrumb_cache[$id]; $link = null; if ($type == 'album') { $name = $entity->name; if ($entity->pageid > 0) { $link = @get_page_link($entity->pageid); } if (empty($link) && $found_item !== $end) { $link = $app->get_routed_url(); $link = $app->strip_param_segments($link); $link = $app->set_parameter_value('album', $entity->slug, null, false, $link); } } else { $name = $entity->title; } $crumbs[] = ['type' => $type, 'name' => $name, 'url' => $link]; } } // free this memory immediately. $this->breadcrumb_cache = []; $view = new C_MVC_View('photocrati-nextgen_basic_album#breadcrumbs', ['breadcrumbs' => $crumbs, 'divisor' => apply_filters('ngg_breadcrumb_separator', ' » ')]); return $view->render(true); } } /** * Because enqueueing an albums child entities (for use in lightboxes) is slow to do inside of cache_action() and * we can't guarantee index_action() will run on every hit (thanks to page caching) we inline those entities into * our basic albums templates under a window.load listener. * * @mixin C_MVC_View * @adapts I_MVC_View */ class A_NextGen_Album_Child_Entities extends Mixin { protected static $_runonce = false; public static $_entities = array(); /** * The album controller will invoke this filter when its _render_album() method is called */ public function __construct() { if (!self::$_runonce) { add_filter('ngg_album_prepared_child_entity', [$this, 'register_child_gallery'], 10, 2); } else { self::$_runonce = true; } } /** * Register each gallery belonging to the album that has just been rendered, so that when the MVC controller * system 'catches up' and runs $this->render_object() that method knows what galleries to inline as JS. * * @param array $galleries * @param $displayed_gallery * @return array mixed */ public function register_child_gallery($galleries, $displayed_gallery) { if (!$this->is_basic_album($displayed_gallery)) { return $galleries; } $id = $displayed_gallery->ID(); foreach ($galleries as $gallery) { if ($gallery->is_album) { continue; } self::$_entities[$id][] = $gallery; } return $galleries; } public function is_basic_album($displayed_gallery) { return in_array($displayed_gallery->display_type, [NGG_BASIC_COMPACT_ALBUM, NGG_BASIC_EXTENDED_ALBUM]); } /** * Determine if we need to append the JS to the current template. This method static for the basic album controller to access. * * @param $display_settings * @return bool */ static function are_child_entities_enabled($display_settings) { $retval = false; if (empty($display_settings['open_gallery_in_lightbox'])) { $display_settings['open_gallery_in_lightbox'] = 0; } if ($display_settings['open_gallery_in_lightbox'] == 1) { $retval = true; } return $retval; } /** * Search inside the template for the inside of the container and append our inline JS */ public function render_object() { $root_element = $this->call_parent('render_object'); if ($displayed_gallery = $this->object->get_param('displayed_gallery')) { if (!$this->is_basic_album($displayed_gallery)) { return $root_element; } $ds = $displayed_gallery->display_settings; if (self::are_child_entities_enabled($ds)) { $id = $displayed_gallery->ID(); foreach ($root_element->find('nextgen_gallery.gallery_container', true) as $container) { $container->append(self::generate_script(self::$_entities[$id])); } } } return $root_element; } /** * Generate the JS that will be inserted into the template. This method static for the basic album controller to access. * * @param array $galleries * @return string */ static function generate_script($galleries) { $retval = ''; return $retval; } } /** * Class A_NextGen_Album_Descriptions * * @mixin C_MVC_View * @adapts I_MVC_View */ class A_NextGen_Album_Descriptions extends Mixin { // When viewing a child gallery the album controller's add_description_to_legacy_templates() method will be // called for the gallery and then again for the root album; we only want to run once. public static $_description_added_once = false; public function are_descriptions_enabled($display_settings) { $retval = false; if (isset($display_settings['enable_descriptions']) && $display_settings['enable_descriptions']) { $retval = true; } elseif (isset($display_settings['original_settings']) && $this->are_descriptions_enabled($display_settings['original_settings'])) { $retval = true; } return $retval; } public function render_object() { $root_element = $this->call_parent('render_object'); if ($displayed_gallery = $this->object->get_param('displayed_gallery')) { $ds = $displayed_gallery->display_settings; if ($this->are_descriptions_enabled($ds)) { $description = $this->object->generate_description($displayed_gallery); foreach ($root_element->find('nextgen_gallery.gallery_container', true) as $container) { // Determine where (to be compatible with breadcrumbs) in the container to insert. $pos = 0; foreach ($container->_list as $ndx => $item) { if (is_string($item)) { $pos = $ndx; } else { break; } } $container->insert($description, $pos); } } } return $root_element; } public function render_legacy_template_description($displayed_gallery) { if (!empty($displayed_gallery->display_settings['template']) && $this->are_descriptions_enabled($displayed_gallery->display_settings)) { return $this->object->generate_description($displayed_gallery); } else { return ''; } } public function generate_description($displayed_gallery) { if (self::$_description_added_once) { return ''; } self::$_description_added_once = true; $description = $this->get_description($displayed_gallery); $view = new C_MVC_View('photocrati-nextgen_basic_album#descriptions', ['description' => $description]); return $view->render(true); } public function get_description($displayed_gallery) { $description = ''; // Important: do not array_shift() $displayed_gallery->container_ids as it will affect breadcrumbs. $container_ids = $displayed_gallery->container_ids; if ($displayed_gallery->source == 'galleries') { $gallery_id = array_shift($container_ids); $gallery = \Imagely\NGG\DataMappers\Gallery::get_instance()->find($gallery_id); if ($gallery && !empty($gallery->galdesc)) { $description = $gallery->galdesc; } } elseif ($displayed_gallery->source == 'albums') { $album_id = array_shift($container_ids); $album = \Imagely\NGG\DataMappers\Album::get_instance()->find($album_id); if ($album && !empty($album->albumdesc)) { $description = $album->albumdesc; } } return $description; } }photocrati_nextgen/modules/nextgen_basic_album/module.nextgen_basic_album.php000064400000002170150212224050024070 0ustar00get_registry()->add_adapter( 'I_MVC_View', 'A_NextGen_Album_Breadcrumbs' ); $this->get_registry()->add_adapter( 'I_MVC_View', 'A_NextGen_Album_Descriptions' ); $this->get_registry()->add_adapter( 'I_MVC_View', 'A_NextGen_Album_Child_Entities' ); } public function get_type_list() { return [ 'A_NextGen_Album_Breadcrumbs' => 'adapter.nextgen_album_breadcrumbs.php', 'A_NextGen_Album_Child_Entities' => 'adapter.nextgen_album_child_entities.php', 'A_NextGen_Album_Descriptions' => 'adapter.nextgen_album_descriptions.php', ]; } } new M_NextGen_Basic_Album(); photocrati_nextgen/modules/nextgen_basic_album/templates/descriptions.php000064400000000230150212224050023312 0ustar00

photocrati_nextgen/modules/nextgen_basic_album/templates/breadcrumbs.php000064400000001166150212224050023106 0ustar00photocrati_nextgen/modules/nextgen_basic_album/static/breadcrumbs.css000064400000000767150212224050022406 0ustar00.ngg-breadcrumbs { list-style: none; overflow: hidden; margin: 0; padding: .5em 0 .5em 0; margin-left: 0 !important; text-transform: uppercase; font-size: 14px; margin: 30px 0 30px !important; } ul.ngg-breadcrumbs > li { float: left; padding: 0 .3em 0 .15em; margin: 0; vertical-align: middle; border: none; list-style-type: none; } .ngg-breadcrumbs li a { } .ngg-breadcrumbs .ngg-breadcrumb-divisor { margin: 0; padding: 0 0 0 .15em; }photocrati_nextgen/modules/nextgen_basic_album/static/breadcrumbs.min.css000064400000000553150212224050023161 0ustar00.ngg-breadcrumbs{list-style:none;overflow:hidden;margin:0;padding:.5em 0 .5em 0;margin-left:0!important;text-transform:uppercase;font-size:14px;margin:30px 0 30px!important}ul.ngg-breadcrumbs>li{float:left;padding:0 .3em 0 .15em;margin:0;vertical-align:middle;border:none;list-style-type:none}.ngg-breadcrumbs .ngg-breadcrumb-divisor{margin:0;padding:0 0 0 .15em}photocrati_nextgen/modules/mvc/module.mvc.php000064400000002076150212224050015465 0ustar00get_registry()->add_utility( 'I_MVC_Controller', 'C_MVC_Controller' ); } public function _register_adapters() { $this->get_registry()->add_adapter( 'I_Component_Factory', 'A_MVC_Factory' ); } public function get_type_list() { return [ 'A_Mvc_Factory' => 'adapter.mvc_factory.php', 'C_Mvc_Installer' => 'class.mvc_installer.php', 'C_Mvc_Controller' => 'class.mvc_controller.php', 'C_Mvc_View' => 'class.mvc_view.php', 'C_Mvc_View_Element' => 'class.mvc_view_element.php', ]; } } new M_MVC(); photocrati_nextgen/modules/mvc/package.module.mvc.php000064400000047274150212224050017070 0ustar00add_mixin('Mixin_MVC_Controller_Instance_Methods'); $this->implement('I_MVC_Controller'); } public function set_content_type($type) { switch ($type) { case 'html': case 'xhtml': $type = 'text/html'; break; case 'xml': $type = 'text/xml'; break; case 'rss': case 'rss2': $type = 'application/rss+xml'; break; case 'css': $type = 'text/css'; break; case 'javascript': case 'jscript': case 'emcascript': $type = 'text/javascript'; break; case 'json': $type = 'application/json'; break; case 'jpeg': case 'jpg': case 'jpe': $type = 'image/jpeg'; break; case 'gif': $type = 'image/gif'; break; case 'png': $type = 'image/x-png'; break; case 'tiff': case 'tif': $type = 'image/tiff'; break; case 'pdf': $type = 'application/pdf'; break; case 'webp': $type = 'image/webp'; break; } $this->object->_content_type = $type; return $type; } public function expires($time) { $time = strtotime($time); if (!headers_sent()) { header('Expires: ' . strftime('%a, %d %b %Y %H:%M:%S %Z', $time)); } } public function http_error($message, $code = 501) { $this->message = $message; $method = "http_{$code}_action"; $this->{$method}(); } public function is_valid_request($method) { return true; } public function is_post_request() { return 'POST' == $this->object->get_router()->get_request_method(); } public function is_get_request() { return 'GET' == $this->object->get_router()->get_request_method(); } public function is_delete_request() { return 'DELETE' == $this->object->get_router()->get_request_method(); } public function is_put_request() { return 'PUT' == $this->object->get_router()->get_request_method(); } public function do_not_cache() { if (!headers_sent()) { header('Cache-Control: no-cache'); header('Pragma: no-cache'); } } public function is_custom_request($type) { return strtolower($type) == strtolower($this->object->get_router()->get_request_method()); } /** * @return \Imagely\NGG\Util\Router */ public function get_router() { return \Imagely\NGG\Util\Router::get_instance(); } /** * @return C_Routing_App */ public function get_routed_app() { return $this->object->get_router()->get_routed_app(); } public function remove_param_for($url, $key, $id = null) { $app = $this->object->get_routed_app(); $retval = $app->remove_parameter($key, $id, $url); return $retval; } /** * Gets the absolute path of a static resource * * @param string $path * @param string|false $module (optional). * @return string */ public function get_static_abspath($path, $module = false) { return \Imagely\NGG\Display\StaticPopeAssets::get_abspath($path, $module); } /** * @param string $path * @param string|false $module (optional). * @return string */ public function get_static_url($path, $module = false) { return \Imagely\NGG\Display\StaticPopeAssets::get_url($path, $module); } /** * Renders a template and outputs the response headers * * @param string $name * @param array $vars (optional). * @param bool $return (optional). * @return string */ public function render_view($name, $vars = array(), $return = false) { $this->object->render(); return $this->object->render_partial($name, $vars, $return); } /** * @param string $template Path to the POPE module#filename. * @param array $params Array of parameters to be extract()ed to the template file. * @param bool $return When true results will be returned instead of printed. * @param null $context Application context. * @param string $new_template_path Path to the new non-POPE file located under the plugin root's '/templates' directory. * @return mixed */ public function render_partial($template, $params = array(), $return = false, $context = null, $new_template_path = '') { /** @var C_MVC_View $view */ $view = $this->object->create_view($template, $params, $context, $new_template_path); return $view->render($return); } } /** * Adds methods for MVC Controller * * @property C_MVC_Controller $object */ class Mixin_MVC_Controller_Instance_Methods extends Mixin { // Provide a default view. public function index_action($return = false) { return $this->render_view('photocrati-mvc#index', [], $return); } /** * Returns the value of a parameters * * @param string $key * @param string|null $prefix (optional). * @return string */ public function param($key, $prefix = null, $default = null) { return $this->object->get_routed_app()->get_parameter($key, $prefix, $default); } public function set_param($key, $value, $id = null, $use_prefix = false) { return $this->object->get_routed_app()->set_parameter($key, $value, $id, $use_prefix); } public function set_param_for($url, $key, $value, $id = null, $use_prefix = false) { return $this->object->get_routed_app()->set_parameter($key, $value, $id, $use_prefix, $url); } public function remove_param($key, $id = null) { return $this->object->get_routed_app()->remove_parameter($key, $id); } /** * Gets the routed url, generated by the Routing App * * @param bool $with_qs (optional) With QueryString. * @return string */ public function get_routed_url($with_qs = false) { return $this->object->get_routed_app()->get_app_url(false, $with_qs); } /** * Outputs the response headers * * TODO: Determine if this can be moved into C_MVC_Controller */ public function render() { if (!headers_sent() && !defined('DOING_AJAX') && !defined('REST_REQUEST')) { header('Content-Type: ' . $this->object->_content_type . '; charset=' . get_option('blog_charset'), true); } } /** * @param string $template Path to the POPE module#filename. * @param array $params Array of parameters to be extract()ed to the template file. * @param null $context Application context. * @param string $new_template_path Path to the new non-POPE file located under the plugin root's '/templates' directory. * @return mixed */ public function create_view($template, $params = array(), $context = null, $new_template_path = '') { if (!$context) { $context = $this->object->context; } return C_Component_Factory::get_instance()->create('mvc_view', $template, $params, null, $context, $new_template_path); } } /** * Class C_MVC_View * * @mixin Mixin_Mvc_View_Instance_Methods * @property C_MVC_View $object */ class C_MVC_View extends C_Component { public $_template = ''; public $_engine = ''; public $_params = array(); public $_queue = array(); public $_new_template = ''; public function __construct($template, $params = array(), $engine = 'php', $context = false, $new_template_path = '') { $this->_template = $template; $this->_params = (array) $params; $this->_engine = $engine; $this->_new_template = $new_template_path; $context = $context ? array_unique([$context, $template], SORT_REGULAR) : $template; parent::__construct($context); } public function define($context = false) { parent::define($context); $this->implement('I_MVC_View'); $this->add_mixin('Mixin_Mvc_View_Instance_Methods'); } /** * Returns the variables to be used in the template * * @return array */ public function get_template_vars() { $retval = []; foreach ($this->object->_params as $key => $value) { if (strpos($key, '_template') === 0) { $value = $this->object->get_template_abspath($value); } $retval[$key] = $value; } return $retval; } /** * @param string $value (optional). * @return string */ public function get_template_abspath($value = null) { if (!$value) { $value = $this->object->_template; } $new_template_path = !empty($this->object->_new_template) ? $this->object->_new_template : ''; if (strpos($value, DIRECTORY_SEPARATOR) !== false && @file_exists($value)) { // key is already abspath. } else { $value = $this->object->find_template_abspath($value, false, $new_template_path); } return $value; } public function rasterize_object($element) { return $element->rasterize(); } public function start_element($id, $type = null, $context = null) { if ($type == null) { $type = 'element'; } $count = count($this->object->_queue); $element = new C_MVC_View_Element($id, $type); if ($context != null) { if (!is_array($context)) { $context = ['object' => $context]; } foreach ($context as $context_name => $context_value) { $element->set_context($context_name, $context_value); } } $this->object->_queue[] = $element; if ($count > 0) { $old_element = $this->object->_queue[$count - 1]; $content = ob_get_contents(); ob_clean(); $old_element->append($content); $old_element->append($element); } ob_start(); return $element; } public function end_element() { $content = ob_get_clean(); $element = array_pop($this->object->_queue); if ($content != null) { $element->append($content); } return $element; } /** * Renders a sub-template for the view * * @param string $__template. * @param array $__params. * @param bool $__return Unused. * @return NULL */ public function include_template($__template, $__params = null, $__return = false) { // We use underscores to prefix local variables to avoid conflicts wth // template vars. if ($__params == null) { $__params = []; } $__params['template_origin'] = $this->object->_template; $__target = $this->object->get_template_abspath($__template); $__origin_target = $this->object->get_template_abspath($this->object->_template); $__image_before_target = $this->object->get_template_abspath('photocrati-nextgen_gallery_display#image/before'); $__image_after_target = $this->object->get_template_abspath('photocrati-nextgen_gallery_display#image/after'); if ($__origin_target != $__target) { if ($__target == $__image_before_target) { $__image = isset($__params['image']) ? $__params['image'] : null; $this->start_element('nextgen_gallery.image_panel', 'item', $__image); } if ($__target == $__image_after_target) { $this->end_element(); } extract($__params); include $__target; if ($__target == $__image_before_target) { $__image = isset($__params['image']) ? $__params['image'] : null; $this->start_element('nextgen_gallery.image', 'item', $__image); } if ($__target == $__image_after_target) { $this->end_element(); } } return null; } /** * Gets the absolute path of an MVC template file * * @param string $path * @param string|false $module (optional). * @param string $new_template_path Non-POPE path coming from 'templates' in the plugin root. * @return string */ public function find_template_abspath($path, $module = false, $new_template_path = '') { $fs = \Imagely\NGG\Util\Filesystem::get_instance(); $settings = \Imagely\NGG\Settings\Settings::get_instance(); // We also accept module_name#path, which needs parsing. if (!$module) { list($path, $module) = $fs->parse_formatted_path($path); } // Append the suffix. $path = $path . '.php'; // First check if the template is in the override dir. $retval = $this->object->get_template_override_abspath($module, $path); if (!$retval && $new_template_path) { $retval = path_join(NGG_PLUGIN_DIR, 'templates' . DIRECTORY_SEPARATOR . $new_template_path . '.php'); } else { $retval = $fs->join_paths($this->object->get_registry()->get_module_dir($module), $settings->mvc_template_dirname, $path); } if (!@file_exists($retval)) { throw new RuntimeException("{$retval} is not a valid MVC template"); } return $retval; } /** * @param null|string $module_id * @return string */ public function get_template_override_dir($module_id = null) { $root = trailingslashit(path_join(WP_CONTENT_DIR, 'ngg')); if (!@file_exists($root) && is_writable(trailingslashit(WP_CONTENT_DIR))) { wp_mkdir_p($root); } $modules = trailingslashit(path_join($root, 'modules')); if (!@file_exists($modules) && is_writable($root)) { wp_mkdir_p($modules); } if ($module_id) { $module_dir = trailingslashit(path_join($modules, $module_id)); if (!@file_exists($module_dir) && is_writable($modules)) { wp_mkdir_p($module_dir); } $template_dir = trailingslashit(path_join($module_dir, 'templates')); if (!@file_exists($template_dir) && is_writable($module_dir)) { wp_mkdir_p($template_dir); } return $template_dir; } return $modules; } /** * @param $module * @param $filename * @return string|null */ public function get_template_override_abspath($module, $filename) { $fs = \Imagely\NGG\Util\Filesystem::get_instance(); $retval = null; $abspath = $fs->join_paths($this->object->get_template_override_dir($module), $filename); if (@file_exists($abspath)) { $retval = $abspath; } return $retval; } } class Mixin_Mvc_View_Instance_Methods extends Mixin { /** * Renders the view (template) * * @param bool $return (optional). * @return string|NULL */ public function render($return = false) { $element = $this->object->render_object(); $content = $this->object->rasterize_object($element); if (!$return) { echo $content; } return $content; } public function render_object() { // We use underscores to prefix local variables to avoid conflicts wth // template vars. $__element = $this->start_element($this->object->_template, 'template', $this->object); $template_vars = $this->object->get_template_vars(); extract($template_vars); include $this->object->get_template_abspath(); $this->end_element(); if (($displayed_gallery = $this->object->get_param('displayed_gallery')) && $this->object->get_param('display_type_rendering')) { $triggers = \Imagely\NGG\DisplayedGallery\TriggerManager::get_instance(); $triggers->render($__element, $displayed_gallery); } return $__element; } /** * Adds a template parameter * * @param $key * @param $value */ public function set_param($key, $value) { $this->object->_params[$key] = $value; } /** * Removes a template parameter * * @param $key */ public function remove_param($key) { unset($this->object->_params[$key]); } /** * Gets the value of a template parameter * * @param $key * @param null $default * @return mixed */ public function get_param($key, $default = null) { if (isset($this->object->_params[$key])) { return $this->object->_params[$key]; } else { return $default; } } } class C_MVC_View_Element { var $_id; var $_type; var $_list; var $_context; public function __construct($id, $type = null) { $this->_id = $id; $this->_type = $type; $this->_list = []; $this->_context = []; } public function get_id() { return $this->_id; } public function append($child) { $this->_list[] = $child; } public function insert($child, $position = 0) { array_splice($this->_list, $position, 0, $child); } public function delete($child) { $index = array_search($child, $this->_list); if ($index !== false) { array_splice($this->_list, $index, 1); } } public function find($id, $recurse = false) { $list = []; $this->_find($list, $id, $recurse); return $list; } public function _find(array &$list, $id, $recurse = false) { foreach ($this->_list as $index => $element) { if ($element instanceof C_MVC_View_Element) { if ($element->get_id() == $id) { $list[] = $element; } if ($recurse) { $element->_find($list, $id, $recurse); } } } } public function get_context($name) { if (isset($this->_context[$name])) { return $this->_context[$name]; } return null; } public function set_context($name, $value) { $this->_context[$name] = $value; } public function get_object() { return $this->get_context('object'); } // XXX not implemented. public function parse() { } public function rasterize() { $ret = null; foreach ($this->_list as $index => $element) { if ($element instanceof C_MVC_View_Element) { $ret .= $element->rasterize(); } else { $ret .= (string) $element; } } return $ret; } }photocrati_nextgen/modules/mvc/templates/index.php000064400000001146150212224050016516 0ustar00object; $template_dir = implode( DIRECTORY_SEPARATOR, [ $obj->get_class_definition_dir(), 'templates' ] ); $default_template_dir = $settings->mvc_template_dir; ?>

Welcome to Pope MVC!

You have not yet created a index.php file in:

So, you're being served the index.php from the default directory:

photocrati_nextgen/modules/mvc/templates/404.php000064400000000357150212224050015721 0ustar00 Error 404: <?php echo esc_html( $message ); ?>

Error 404:

We're sorry, but the page you've requested cannot be found.

photocrati_nextgen/modules/mvc/templates/500.php000064400000000345150212224050015713 0ustar00 Error 500 <?php echo esc_html( $message ); ?>

Error:

You requested something the server doesn't understand.

photocrati_nextgen/modules/mvc/README.txt000064400000006636150212224050014407 0ustar00 VIEW ELEMENTS Elements are sub-pieces of a template/view identified by a "unique" ID. The ID is unique in the sense that it uniquely defines the "origin" or creator for the element itself. For instance if you have a module called pro_lightbox and specific adapter for trigger buttons and you add an element for it the unique ID identifying the element could be nextgen_pro_lightbox.trigger_buttons The ID doesn't however need to be unique in the view itself, meaning you can have multiple elements with the same ID if for instance the element is being rendered for multiple images. We might add an extra "context" parameter to elements together to the ID if we want to uniquely identify element objects. Example of how elements are initiated: $elem = $this->start_element('flash_cont'); echo 'cont'; $this->start_element('flash_test'); echo 'test'; $this->start_element('flash_stuff'); echo 'stuff'; $this->end_element(); $this->end_element(); $this->end_element(); var_dump($elem); This would create this output: object(C_MVC_View_Element)#775 (3) { ["_id"]=>string(10) "flash_cont" ["_type"]=>string(7) "element" ["_list"]=>array(2) { [0]=>string(4) "cont" [1]=>object(C_MVC_View_Element)#768 (3) { ["_id"]=>string(10) "flash_test" ["_type"]=>string(7) "element" ["_list"]=>array(2) { [0]=>string(4) "test" [1]=>object(C_MVC_View_Element)#769 (3) { ["_id"]=>string(11) "flash_stuff" ["_type"]=>string(7) "element" ["_list"]=>array(1) { [0]=>string(5) "stuff" } } } } } } The way the MVC view will render these is by creating a root View Element that contains the entire template rendered in the view and which is then "rasterized" e.g. converted to markup/text ready for output The rendering from template to element will occur in the render_object() method while rasterization will occur in a method called rasterize_object() Elements created for templates will have ID corresponding to template name/path so for instance _id would equal 'photocrati-nextgen_basic_gallery#slideshow/index' this way adapters adapting rasterize_object() can easily distinguish between for which template rasterization is occurring and act accordingly (for instance trigger buttons being enabled only for certain display types) Sub-templates will also be automatically rendered to elements meaning image/before and image/after etc. will become sub-elements of the root template element. I don't think this will affect performance much but if so we could easily replace the before/after mechanism to use elements directly So for instance instead of: $this->include_template('image/before');
...
$this->include_template('image/after'); We would have: $this->start_element('nextgen_gallery.image'); $this->include_template('image/before');
...
$this->include_template('image/after'); $this->end_element(); Then you could have an adapter like: function rasterize_object($root_element) { if ($root_element->get_id() == 'photocrati-nextgen_basic_gallery#slideshow/index') { $list = $root_element->find('nextgen_gallery.image'); foreach ($list as $element) { $element->append('
description
'); } } } This would reduce the amount of elements overall and improve performance and possibly readability. Then the before/after templates could be left untouched as in the example above. photocrati_nextgen/modules/datamapper/module.datamapper.php000064400000003131150212224050020340 0ustar00get_registry()->add_adapter( 'I_Component_Factory', 'A_DataMapper_Factory' ); } /** * Deserializes data * * @deprecated Used only by the Pro Lightbox * @param string $value * @return mixed * @throws Exception */ public static function unserialize( $value ) { return \Imagely\NGG\Util\Serializable::unserialize( $value ); } /** * Serializes the data * * @deprecated Used only by the Pro Lightbox * @param mixed $value * @return string */ public static function serialize( $value ) { return \Imagely\NGG\Util\Serializable::serialize( $value ); } public function get_type_list() { return [ 'A_Datamapper_Factory' => 'adapter.datamapper_factory.php', 'C_Custompost_Datamapper_Driver' => 'class.custompost_datamapper_driver.php', 'C_Customtable_Datamapper_Driver' => 'class.customtable_datamapper_driver.php', 'C_Datamapper_Driver_Base' => 'class.datamapper_driver_base.php', 'C_Datamapper_Model' => 'class.datamapper_model.php', ]; } } new M_DataMapper(); photocrati_nextgen/modules/datamapper/package.module.datamapper.php000064400000200477150212224050021746 0ustar00add_mixin('Mixin_DataMapper_Driver_Base'); $this->implement('I_DataMapper_Driver'); $this->_object_name = $object_name; } public function initialize() { parent::initialize(); $this->_cache = []; if ($this->has_method('define_columns')) { $this->define_columns(); } $this->lookup_columns(); } /** * Gets the object name * * @return string */ public function get_object_name() { return $this->_object_name; } /** * Gets the name of the table * * @global string $table_prefix * @return string */ public function get_table_name() { global $table_prefix; global $wpdb; $prefix = $table_prefix; if ($wpdb != null && $wpdb->prefix != null) { $prefix = $wpdb->prefix; } return apply_filters('ngg_datamapper_table_name', $prefix . $this->_object_name, $this->_object_name); } /** * Looks up using SQL the columns existing in the database, result is cached. */ public function lookup_columns() { // Avoid doing multiple SHOW COLUMNS if we can help it. $key = \Imagely\NGG\Util\Transient::create_key('col_in_' . $this->get_table_name(), 'columns'); $this->_table_columns = \Imagely\NGG\Util\Transient::fetch($key, false); if (!$this->_table_columns) { $this->object->update_columns_cache(); } return $this->_table_columns; } /** * Looks up using SQL the columns existing in the database */ public function update_columns_cache() { $key = \Imagely\NGG\Util\Transient::create_key('col_in_' . $this->get_table_name(), 'columns'); global $wpdb; $this->_table_columns = []; // $wpdb->prepare() cannot be used just yet as it only supported the %i placeholder for column names as of // WordPress 6.2 which is newer than NextGEN's current minimum WordPress version. // // TODO: Once NextGEN's minimum WP version is 6.2 or higher use wpdb->prepare() here. // // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared foreach ($wpdb->get_results("SHOW COLUMNS FROM {$this->get_table_name()}") as $row) { $this->_table_columns[] = $row->Field; } \Imagely\NGG\Util\Transient::update($key, $this->_table_columns); } /** * Determines whether a column is present for the table * * @param string $column_name * @return bool */ public function has_column($column_name) { if (empty($this->object->_table_columns)) { $this->object->lookup_columns(); } return array_search($column_name, $this->object->_table_columns) !== false; } /** * Sets the name of the factory method used to create a model for this entity * * @param string $method_name */ public function set_model_factory_method($method_name) { $this->_model_factory_method = $method_name; } /** * Gets the name of the factory method used to create a model for this entity */ public function get_model_factory_method() { return $this->_model_factory_method; } /** * Gets the name of the primary key column * * @return string */ public function get_primary_key_column() { return $this->_primary_key_column; } /** * Gets the class name of the driver used * * @return string */ public function get_driver_class_name() { return get_called_class(); } public function cache($key, $results) { if ($this->object->_use_cache) { $this->_cache[$key] = $results; } } public function get_from_cache($key, $default = null) { if ($this->object->_use_cache && isset($this->_cache[$key])) { return $this->_cache[$key]; } else { return $default; } } public function flush_query_cache() { $this->_cache = []; } /** * Used to clean column or table names in a SQL query * * @param string $val * @return string */ public function _clean_column($val) { return str_replace([';', "'", '"', '`'], [''], $val); } /** * Notes that a particular columns is serialized, and should be unserialized when converted to an entity * * @param $column */ public function add_serialized_column($column) { $this->object->_serialized_columns[] = $column; } public function unserialize_columns($object) { foreach ($this->object->_serialized_columns as $column) { if (isset($object->{$column}) && is_string($object->{$column})) { $object->{$column} = \Imagely\NGG\Util\Serializable::unserialize($object->{$column}); } } } /** * Fetches the first row * * @param array $conditions (optional) * @param object|bool $model (optional) * @return null|object */ public function find_first($conditions = array(), $model = false) { $results = $this->object->select()->where_and($conditions)->limit(1, 0)->run_query(); if ($results) { return $model ? $this->object->convert_to_model($results[0]) : $results[0]; } else { return null; } } /** * Queries all rows * * @param array $conditions (optional) * @param object|bool $model (optional) * @return array */ public function find_all($conditions = array(), $model = false) { // Sometimes users will forget that the first parameter is conditions, and think it's $model instead. if ($conditions === true) { $conditions = []; $model = true; } if ($conditions === false) { $conditions = []; } $results = $this->object->select()->where_and($conditions)->run_query(); if ($results && $model) { foreach ($results as &$r) { $r = $this->object->convert_to_model($r); } } return $results; } /** * Filters the query using conditions: * E.g. * array("post_title = %s", "Foo") * array( * array("post_title = %s", "Foo"), * * ) * * @param array $conditions (optional) * @return self */ public function where_and($conditions = array()) { return $this->object->_where($conditions, 'AND'); } /** * @param array $conditions (optional) * @return self */ public function where_or($conditions = array()) { return $this->object->where($conditions, 'OR'); } /** * @param array $conditions (optional) * @return self */ public function where($conditions = array()) { return $this->object->_where($conditions, 'AND'); } /** Parses the where clauses * They could look like the following: * * array( * "post_id = 1" * array("post_id = %d", 1), * ) * * or simply "post_id = 1" * * @param array|string $conditions * @param string $operator * @return ExtensibleObject */ public function _where($conditions, $operator) { $where_clauses = []; // If conditions is not an array, make it one. if (!is_array($conditions)) { $conditions = [$conditions]; } elseif (!empty($conditions) && !is_array($conditions[0])) { // Just a single condition was passed, but with a bind. $conditions = [$conditions]; } // Iterate through each condition. foreach ($conditions as $condition) { if (is_string($condition)) { $clause = $this->object->_parse_where_clause($condition); if ($clause) { $where_clauses[] = $clause; } } else { $clause = array_shift($condition); $clause = $this->object->_parse_where_clause($clause, $condition); if ($clause) { $where_clauses[] = $clause; } } } // Add where clause to query. if ($where_clauses) { $this->object->_add_where_clause($where_clauses, $operator); } return $this->object; } /** * Parses a where clause and returns an associative array * representing the query * * E.g. parse_where_clause("post_title = %s", "Foo Bar") * * @global wpdb $wpdb * @param string $condition * @return array */ public function _parse_where_clause($condition) { $column = ''; $operator = ''; $value = ''; $numeric = true; // Substitute any placeholders. global $wpdb; $binds = func_get_args(); $binds = isset($binds[1]) ? $binds[1] : []; // first argument is the condition. foreach ($binds as &$bind) { // A bind could be an array, used for the 'IN' operator // or a simple scalar value. We need to convert arrays // into scalar values. if (is_object($bind)) { $bind = (array) $bind; } if (is_array($bind) && !empty($bind)) { foreach ($bind as &$val) { if (!is_numeric($val)) { $val = '"' . addslashes($val) . '"'; $numeric = false; } } $bind = implode(',', $bind); } elseif (is_array($bind) && empty($bind)) { $bind = 'NULL'; } elseif (!is_numeric($bind)) { $numeric = false; } } if ($binds) { // PHPCS triggers a false positive on this; $condition is a string that contains the placeholders. // // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $condition = $wpdb->prepare($condition, $binds); } // Parse the where clause. if (preg_match('/^[^\\s]+/', $condition, $match)) { $column = trim(array_shift($match)); $condition = str_replace($column, '', $condition); } if (preg_match('/(NOT )?IN|(NOT )?LIKE|(NOT )?BETWEEN|[=!<>]+/i', $condition, $match)) { $operator = trim(array_shift($match)); $condition = str_replace($operator, '', $condition); $operator = strtolower($operator); $value = trim($condition); } // Values will automatically be quoted, so remove them // If the value is part of an IN clause or BETWEEN clause and // has multiple values, we attempt to split the values apart into an // array and iterate over them individually. if ($operator == 'in') { $values = preg_split("/'?\\s?(,)\\s?'?/i", $value); } elseif ($operator == 'between') { $values = preg_split("/'?\\s?(AND)\\s?'?/i", $value); } // If there's a single value, treat it as an array so that we // can still iterate. if (empty($values)) { $values = [$value]; } foreach ($values as $index => $value) { $value = preg_replace("/^(\\()?'/", '', $value); $value = preg_replace("/'(\\))?\$/", '', $value); $values[$index] = $value; } if (count($values) > 1) { $value = $values; } // Return the WP Query meta query parameters. $retval = ['column' => $column, 'value' => $value, 'compare' => strtoupper($operator), 'type' => $numeric ? 'numeric' : 'string']; return $retval; } public function strip_slashes($stdObject_or_array_or_string) { /** * Some objects have properties that are recursive objects. To avoid this we have to keep track * of what objects we've already processed when we're running this method recursively */ static $level = 0; static $processed_objects = array(); ++$level; $processed_objects[] = $stdObject_or_array_or_string; if (is_string($stdObject_or_array_or_string)) { $stdObject_or_array_or_string = str_replace("\\'", "'", str_replace('\\"', '"', str_replace('\\\\', '\\', $stdObject_or_array_or_string))); } elseif (is_object($stdObject_or_array_or_string) && !in_array($stdObject_or_array_or_string, $processed_objects)) { foreach (get_object_vars($stdObject_or_array_or_string) as $key => $val) { if ($val != $stdObject_or_array_or_string && $key != '_mapper') { $stdObject_or_array_or_string->{$key} = $this->strip_slashes($val); } } $processed_objects[] = $stdObject_or_array_or_string; } elseif (is_array($stdObject_or_array_or_string)) { foreach ($stdObject_or_array_or_string as $key => $val) { if ($key != '_mixins') { $stdObject_or_array_or_string[$key] = $this->strip_slashes($val); } } } --$level; if ($level == 0) { $processed_objects = []; } return $stdObject_or_array_or_string; } /** * Converts a stdObject entity to a model * * @param object $stdObject * @param string|bool $context (optional) * @return object */ public function convert_to_model($stdObject, $context = false) { // Create a factory. $retval = null; try { $this->object->_convert_to_entity($stdObject); } catch (Exception $ex) { throw new E_InvalidEntityException($ex); } $retval = $this->object->create($stdObject, $context); return $retval; } /** * Determines whether an object is actually a model * * @param mixed $obj * @return bool */ public function is_model($obj) { return is_subclass_of($obj, 'C_DataMapper_Model') or get_class($obj) == 'C_DataMapper_Model'; } /** * If a field has no value, then use the default value. * * @param stdClass|C_DataMapper_Model $object */ public function _set_default_value($object) { $array = null; $field = null; $default_value = null; // The first argument MUST be an object. if (!is_object($object)) { throw new E_InvalidEntityException(); } // This method has two signatures: // 1) _set_default_value($object, $field, $default_value) // 2) _set_default_value($object, $array_field, $field, $default_value). // Handle #1. $args = func_get_args(); if (count($args) == 4) { list($object, $array, $field, $default_value) = $args; if (!isset($object->{$array})) { $object->{$array} = []; $object->{$array}[$field] = null; } else { $arr =& $object->{$array}; if (!isset($arr[$field])) { $arr[$field] = null; } } $array =& $object->{$array}; $value =& $array[$field]; if ($value === '' or is_null($value)) { $value = $default_value; } } else { list($object, $field, $default_value) = $args; if (!isset($object->{$field})) { $object->{$field} = null; } $value = $object->{$field}; if ($value === '' or is_null($value)) { $object->{$field} = $default_value; } } } public function get_defined_column_names() { return array_keys($this->object->_columns); } public function has_defined_column($name) { $columns = $this->object->_columns; return isset($columns[$name]); } public function cast_columns($entity) { foreach ($this->object->_columns as $key => $properties) { $value = property_exists($entity, $key) ? $entity->{$key} : null; $default_value = $properties['default_value']; if (!is_null($value) && $value !== $default_value) { $column_type = $this->object->_columns[$key]['type']; if (preg_match('/varchar|text/i', $column_type)) { if (!is_array($value) && !is_object($value)) { $entity->{$key} = strval($value); } } elseif (preg_match('/decimal|numeric|double|float/i', $column_type)) { $entity->{$key} = floatval($value); } elseif (preg_match('/int/i', $column_type)) { $entity->{$key} = intval($value); } elseif (preg_match('/bool/i', $column_type)) { $entity->{$key} = $value ? true : false; } } else { $entity->{$key} = $default_value; } } return $entity; } } /** * Provides instance methods for C_CustomPost_DataMapper_Driver * * @mixin C_CustomPost_DataMapper_Driver */ class Mixin_CustomPost_DataMapper_Driver extends Mixin { /** * Used to select which fields should be returned. NOT currently used by * this implementation of the datamapper driver * * @param string $fields * @return C_DataMapper_Driver_Base */ public function select($fields = '*') { $this->object->_query_args = ['post_type' => $this->object->get_object_name(), 'paged' => false, 'fields' => $fields, 'post_status' => 'any', 'datamapper' => true, 'posts_per_page' => -1, 'is_select' => true, 'is_delete' => false]; return $this->object; } /** * Destroys/deletes an entity from the database * * @param object|C_DataMapper_Model $entity * @param bool $skip_trash (optional) Default = true * @return bool */ public function destroy($entity, $skip_trash = true) { $retval = false; $key = $this->object->get_primary_key_column(); // Find the id of the entity. if (is_object($entity) && isset($entity->{$key})) { $id = (int) $entity->{$key}; } else { $id = (int) $entity; } // If we have an ID, then delete the post. if (is_integer($id)) { // TODO: We assume that we can skip the trash. Is that correct? // FYI, Deletes postmeta as wells. if (is_object(wp_delete_post($id, true))) { $retval = true; } } return $retval; } /** * Saves an entity to the database * * @param object $entity * @return int Post ID */ public function _save_entity($entity) { $post = $this->object->_convert_entity_to_post($entity); $primary_key = $this->object->get_primary_key_column(); // TODO: unsilence this. WordPress 3.9-beta2 is generating an error that should be corrected before its // final release. if ($post_id = @wp_insert_post($post)) { $new_entity = $this->object->find($post_id, true); if ($new_entity) { foreach ($new_entity->get_entity() as $key => $value) { $entity->{$key} = $value; } } // Save properties as post meta. $this->object->_flush_and_update_postmeta($post_id, $entity instanceof stdClass ? $entity : $entity->get_entity()); $entity->{$primary_key} = $post_id; // Clean cache. $this->object->_cache = []; } $entity->id_field = $primary_key; return $post_id; } /** * Starts a new DELETE statement */ public function delete() { $this->object->select(); $this->object->_query_args['is_select'] = false; $this->object->_query_args['is_delete'] = true; return $this->object; } /** * Returns the title of the post. Used when post_title is not set * * @param stdClass $entity * @return string */ public function get_post_title($entity) { return "Untitled {$this->object->get_object_name()}"; } /** * Returns the excerpt of the post. Used when post_excerpt is not set * * @param stdClass $entity * @return string */ public function get_post_excerpt($entity) { return ''; } } /** * Class C_CustomTable_DataMapper_Driver * * @mixin C_CustomTable_DataMapper_Driver_Mixin */ class C_CustomTable_DataMapper_Driver extends C_DataMapper_Driver_Base { /** * The WordPress Database Connection * * @var wpdb */ public $_where_clauses = array(); public $_order_clauses = array(); public $_group_by_columns = array(); public $_limit_clause = ''; public $_select_clause = ''; public $_delete_clause = ''; public $_use_cache = true; public function define($object_name = false, $context = false) { parent::define($object_name, $context); $this->add_mixin('C_CustomTable_DataMapper_Driver_Mixin'); $this->implement('I_CustomTable_DataMapper'); } public function initialize($object_name = false) { parent::initialize(); if (!isset($this->_primary_key_column)) { $this->_primary_key_column = $this->_lookup_primary_key_column(); } $this->migrate(); } /** * Returns the database connection object for WordPress * * @global wpdb $wpdb * @return wpdb */ public function _wpdb() { global $wpdb; return $wpdb; } /** * Looks up the primary key column for this table */ public function _lookup_primary_key_column() { $key = $this->_wpdb()->get_row("SHOW INDEX FROM {$this->get_table_name()} WHERE Key_name='PRIMARY'", ARRAY_A); if (!$key) { throw new Exception("Please specify the primary key for {$this->get_table_name()}"); } return $key['Column_name']; } /** * Gets the name of the primary key column * * @return string */ public function get_primary_key_column() { return $this->object->_primary_key_column; } /** * Determines whether we're going to execute a SELECT statement * * @return boolean */ public function is_select_statement() { return $this->object->_select_clause ? true : false; } /** * Determines if we're going to be executing a DELETE statement * * @return bool */ public function is_delete_statement() { return $this->object->_delete_clause ? true : false; } /** * Orders the results of the query * This method may be used multiple of times to order by more than column * * @param $order_by * @param $direction * @return object */ public function order_by($order_by, $direction = 'ASC') { // We treat the rand() function as an exception. if (preg_match('/rand\\(\\s*\\)/', $order_by)) { $order = 'rand()'; } else { $order_by = $this->object->_clean_column($order_by); // If the order by clause is a column, then it should be backticked. if ($this->object->has_column($order_by)) { $order_by = "`{$order_by}`"; } $direction = $this->object->_clean_column($direction); $order = "{$order_by} {$direction}"; } $this->object->_order_clauses[] = $order; return $this->object; } /** * Specifies a limit and optional offset * * @param integer $max * @param integer $offset * @return object */ public function limit($max, $offset = 0) { if ($offset) { $limit = $this->_wpdb()->prepare('LIMIT %d, %d', max(0, $offset), $max); } else { $limit = $this->_wpdb()->prepare('LIMIT %d', max(0, $max)); } if ($limit) { $this->object->_limit_clause = $limit; } return $this->object; } /** * Specifics a group by clause for one or more columns * * @param array|string $columns * @return object */ public function group_by($columns = array()) { if (!is_array($columns)) { $columns = [$columns]; } $this->object->_group_by_columns = array_merge($this->object->_group_by_columns, $columns); return $this->object; } /** * Adds a where clause to the driver * * @param array $where_clauses * @param string $join */ public function _add_where_clause($where_clauses, $join) { $clauses = []; foreach ($where_clauses as $clause) { extract($clause); if ($this->object->has_column($column)) { $column = "`{$column}`"; } if (!is_array($value)) { $value = [$value]; } foreach ($value as $index => $v) { $v = $clause['type'] == 'numeric' ? $v : "'{$v}'"; $value[$index] = $v; } if ($compare == 'BETWEEN') { $value = "{$value[0]} AND {$value[1]}"; } else { $value = implode(', ', $value); if (strpos($compare, 'IN') !== false) { $value = "({$value})"; } } $clauses[] = "{$column} {$compare} {$value}"; } $this->object->_where_clauses[] = implode(" {$join} ", $clauses); } /** * Returns the total number of entities known * * @return int */ public function count() { $retval = 0; $key = $this->object->get_primary_key_column(); $results = $this->object->run_query("SELECT COUNT(`{$key}`) AS `{$key}` FROM `{$this->object->get_table_name()}`"); if ($results && isset($results[0]->{$key})) { $retval = (int) $results[0]->{$key}; } return $retval; } /** * Run the query * * @param string|bool $sql (optional) run the specified SQL * @param object|bool $model (optional) * @param bool $no_entities (optional) * @return array */ public function run_query($sql = false, $model = false, $no_entities = false) { $results = false; $retval = []; // Or generate SQL query. if (!$sql) { $sql = $this->object->get_generated_query($no_entities); } // If we have a SQL statement to execute, then heck, execute it! if ($sql) { if ($this->object->debug) { var_dump($sql); } // Try getting the result from cache first. if ($this->is_select_statement() && $this->object->_use_cache) { $results = $this->object->get_from_cache($sql); } } if (!$results) { $this->_wpdb()->query($sql); $results = $this->_wpdb()->last_result; if ($this->is_select_statement()) { $this->object->cache($sql, $results); } } if ($results) { $retval = []; // For each row, create an entity, update it's properties, and add it to the result set. if ($no_entities) { $retval = $results; } else { $id_field = $this->get_primary_key_column(); foreach ($results as $row) { if ($row) { if (isset($row->{$id_field})) { if ($model) { $retval[] = $this->object->convert_to_model($row); } else { $retval[] = $this->object->_convert_to_entity($row); } } } } } } elseif ($this->object->debug) { var_dump('No entities returned from query'); } // Just a safety check. if (!$retval) { $retval = []; } return $retval; } /** * Converts an entity to something suitable for inserting into a database column * * @param object $entity * @return array */ public function _convert_to_table_data($entity) { $data = (array) $entity; foreach ($data as $key => $value) { if (is_array($value)) { $data[$key] = $this->object->serialize($value); } } return $data; } /** * Fetches the last row * * @param array $conditions * @return object */ public function find_last($conditions = array(), $model = false) { $retval = null; // Get row number for the last row. $this->select()->limit(1)->order_by('date', 'DESC'); if ($conditions) { $this->where_and($conditions); } $results = $this->run_query(); if ($results) { $retval = $model ? $this->object->convert_to_model($results[0]) : $results[0]; } return $retval; } public function get_column_names() { return array_keys($this->object->_columns); } /** * Migrates the schema of the database */ public function migrate() { if (!$this->object->_columns) { throw new E_ColumnsNotDefinedException("Columns not defined for {$this->get_table_name()}"); } $added = false; $removed = false; // Add any missing columns. foreach ($this->object->_columns as $key => $properties) { if (!in_array($key, $this->object->_table_columns)) { if ($this->object->_add_column($key, $properties['type'], $properties['default_value'])) { $added = true; } } } if ($added or $removed) { $this->object->lookup_columns(); } } public function _init() { $this->object->_where_clauses = []; $this->object->_order_clauses = []; $this->object->_group_by_columns = []; $this->object->_limit_clause = ''; $this->object->_select_clause = ''; } } /** * Provides instance methods for C_CustomTable_DataMapper_Driver * * @mixin C_CustomTable_DataMapper_Driver */ class C_CustomTable_DataMapper_Driver_Mixin extends Mixin { /** * Selects which fields to collect from the table. * NOTE: Not protected from SQL injection - DO NOT let your users specify DB columns * * @param string $fields * @return object */ public function select($fields = null) { // Create a fresh slate. $this->object->_init(); if (!$fields or $fields == '*') { $fields = $this->get_table_name() . '.*'; } $this->object->_select_clause = "SELECT {$fields}"; return $this->object; } /** * Start a delete statement */ public function delete() { // Create a fresh slate. $this->object->_init(); $this->object->_delete_clause = 'DELETE'; return $this->object; } /** * Stores the entity * * @param object $entity * @return bool|object */ public function _save_entity($entity) { $retval = false; unset($entity->id_field); $primary_key = $this->object->get_primary_key_column(); if (isset($entity->{$primary_key}) && $entity->{$primary_key} > 0) { if ($this->object->_update($entity)) { $retval = intval($entity->{$primary_key}); } } else { $retval = $this->object->_create($entity); if ($retval) { $new_entity = $this->object->find($retval); foreach ($new_entity as $key => $value) { $entity->{$key} = $value; } } } $entity->id_field = $primary_key; // Clean cache. if ($retval) { $this->object->_cache = []; } return $retval; } /** * Destroys/deletes an entity * * @param object|C_DataMapper_Model|int $entity * @return boolean */ public function destroy($entity) { $retval = false; $key = $this->object->get_primary_key_column(); // Find the id of the entity. if (is_object($entity) && isset($entity->{$key})) { $id = (int) $entity->{$key}; } else { $id = (int) $entity; } // If we have an ID, then delete the post. if (is_numeric($id)) { $sql = $this->object->_wpdb()->prepare("DELETE FROM `{$this->object->get_table_name()}` WHERE {$key} = %s", $id); $retval = $this->object->_wpdb()->query($sql); } return $retval; } /** * Creates a new record in the database * * @param object $entity * @return boolean */ public function _create($entity) { $retval = false; $id = $this->object->_wpdb()->insert($this->object->get_table_name(), $this->object->_convert_to_table_data($entity)); if ($id) { $key = $this->object->get_primary_key_column(); $retval = $entity->{$key} = intval($this->object->_wpdb()->insert_id); } return $retval; } /** * Updates a record in the database * * @param object $entity * @return int|bool */ public function _update($entity) { $key = $this->object->get_primary_key_column(); return $this->object->_wpdb()->update($this->object->get_table_name(), $this->object->_convert_to_table_data($entity), [$key => $entity->{$key}]); } public function _add_column($column_name, $datatype, $default_value = null) { $sql = "ALTER TABLE `{$this->get_table_name()}` ADD COLUMN `{$column_name}` {$datatype}"; if ($default_value) { if (is_string($default_value)) { $default_value = str_replace("'", "\\'", $default_value); } $sql .= ' NOT NULL DEFAULT ' . (is_string($default_value) ? "'{$default_value}" : "{$default_value}"); } $return = $this->object->_wpdb()->query($sql) ? true : false; $this->object->update_columns_cache(); return $return; } public function _remove_column($column_name) { $sql = "ALTER TABLE `{$this->get_table_name()}` DROP COLUMN `{$column_name}`"; $return = $this->object->_wpdb()->query($sql) ? true : false; $this->object->update_columns_cache(); return $return; } /** * Returns the generated SQL query to be executed * * @param bool $no_entities Default = false * @return string */ public function get_generated_query($no_entities = false) { $sql = []; if ($this->object->is_select_statement()) { $sql[] = $this->object->_select_clause; } elseif ($this->object->is_delete_statement()) { $sql[] = $this->object->_delete_clause; } $sql[] = 'FROM `' . $this->object->get_table_name() . '`'; $where_clauses = []; foreach ($this->object->_where_clauses as $where) { $where_clauses[] = '(' . $where . ')'; } if ($where_clauses) { $sql[] = 'WHERE ' . implode(' AND ', $where_clauses); } if ($this->object->is_select_statement()) { if ($this->object->_group_by_columns) { $sql[] = 'GROUP BY ' . implode(', ', $this->object->_group_by_columns); } if ($this->object->_order_clauses) { $sql[] = 'ORDER BY ' . implode(', ', $this->object->_order_clauses); } if ($this->object->_limit_clause) { $sql[] = $this->object->_limit_clause; } } return implode(' ', $sql); } } /** * Class C_CustomPost_DataMapper_Driver * * @mixin Mixin_CustomPost_DataMapper_Driver * @implements I_CustomPost_DataMapper */ class C_CustomPost_DataMapper_Driver extends C_DataMapper_Driver_Base { public $_query_args = array(); public $_primary_key_column = 'ID'; public $_use_cache = true; public $_cache; public static $_post_table_columns = array(); public function define($object_name = false, $context = false) { if (strlen($object_name) > 20) { throw new Exception('The custom post name can be no longer than 20 characters long'); } parent::define($object_name, $context); $this->add_mixin('Mixin_CustomPost_DataMapper_Driver'); $this->implement('I_CustomPost_DataMapper'); } public function lookup_columns() { if (empty(self::$_post_table_columns)) { $columns = parent::lookup_columns(); foreach ($columns as $column) { self::$_post_table_columns[] = $column; } } else { foreach (self::$_post_table_columns as $column) { $this->_table_columns[] = $column; } } } /** * Gets the name of the table * * @global string $table_prefix * @return string */ public function get_table_name() { global $table_prefix; return $table_prefix . 'posts'; } /** * Returns a list of querable table columns for posts * * @return array */ public function _get_querable_table_columns() { return ['name', 'author', 'date', 'title', 'modified', 'menu_order', 'parent', 'ID', 'rand', 'comment_count']; } /** * Specifies an order clause * * @param string $order_by * @param string $direction * @return C_DataMapper_Driver_Base */ public function order_by($order_by, $direction = 'ASC') { // Make an exception for the rand() method. $order_by = preg_replace('/rand\\(\\s*\\)/', 'rand', $order_by); if (in_array($order_by, $this->object->_get_querable_table_columns())) { $this->object->_query_args['orderby'] = $order_by; } else { // ordering by a meta value. $this->object->_query_args['orderby'] = 'meta_value'; $this->object->_query_args['meta_key'] = $order_by; } $this->object->_query_args['order'] = $direction; return $this->object; } /** * Specifies a limit and optional offset * * @param int $max * @param int|bool $offset (optional) * @return object */ public function limit($max, $offset = false) { if ($max) { $this->object->_query_args['paged'] = true; if ($offset) { $this->object->_query_args['offset'] = $offset; } else { unset($this->object->_query_args['offset']); } $this->object->_query_args['posts_per_page'] = $max; } return $this->object; } /** * Specifies a list of columns to group by * * @param array|string $columns * @return object */ public function group_by($columns = array()) { if (!isset($this->object->_query_args['group_by_columns'])) { $this->object->_query_args['group_by_columns'] = $columns; } else { $this->object->_query_args['group_by_columns'] = array_merge($this->object->_query_args['group_by_columns'], $columns); } return $this->object; } /** * Adds a WP_Query where clause * * @param array $where_clauses * @param string $join */ public function _add_where_clause($where_clauses, $join) { foreach ($where_clauses as $clause) { // Determine where what the where clause is comparing. switch ($clause['column']) { case 'author': case 'author_id': $this->object->_query_args['author'] = $clause['value']; break; case 'author_name': $this->object->_query_args['author_name'] = $clause['value']; break; case 'cat': case 'cat_id': case 'category_id': switch ($clause['compare']) { case '=': case 'BETWEEN': case 'IN': if (!isset($this->object->_query_args['category__in'])) { $this->object->_query_args['category__in'] = []; } $this->object->_query_args['category__in'][] = $clause['value']; break; case '!=': case 'NOT BETWEEN': case 'NOT IN': if (!isset($this->object->_query_args['category__not_in'])) { $this->object->_query_args['category__not_in'] = []; } $this->object->_query_args['category__not_in'][] = $clause['value']; break; } break; case 'category_name': $this->object->_query_args['category_name'] = $clause['value']; break; case 'post_id': case $this->object->get_primary_key_column(): switch ($clause['compare']) { case '=': case 'IN': case 'BETWEEN': if (!isset($this->object->_query_args['post__in'])) { $this->object->_query_args['post__in'] = []; } $this->object->_query_args['post__in'][] = $clause['value']; break; default: if (!isset($this->object->_query_args['post__not_in'])) { $this->object->_query_args['post__not_in'] = []; } $this->object->_query_args['post__not_in'][] = $clause['value']; break; } break; case 'pagename': case 'postname': case 'page_name': case 'post_name': if ($clause['compare'] == 'LIKE') { $this->object->_query_args['page_name__like'] = $clause['value']; } elseif ($clause['compare'] == '=') { $this->object->_query_args['pagename'] = $clause['value']; } elseif ($clause['compare'] == 'IN') { $this->object->_query_args['page_name__in'] = $clause['value']; } break; case 'post_title': // Post title uses custom WHERE clause. if ($clause['compare'] == 'LIKE') { $this->object->_query_args['post_title__like'] = $clause['value']; } else { $this->object->_query_args['post_title'] = $clause['value']; } break; default: // Must be metadata. $clause['key'] = $clause['column']; unset($clause['column']); // Convert values to array, when required. if (in_array($clause['compare'], ['IN', 'BETWEEN'])) { $clause['value'] = explode(',', $clause['value']); foreach ($clause['value'] as &$val) { if (!is_numeric($val)) { // In the _parse_where_clause() method, we // quote the strings and add slashes. $val = stripslashes($val); $val = substr($val, 1, strlen($val) - 2); } } } if (!isset($this->object->_query_args['meta_query'])) { $this->object->_query_args['meta_query'] = []; } $this->object->_query_args['meta_query'][] = $clause; break; } } // If any where clauses have been added, specify how the conditions // will be conbined/joined. if (isset($this->object->_query_args['meta_query'])) { $this->object->_query_args['meta_query']['relation'] = $join; } } /** * Converts a post to an entity * * @param \stdClass $post * @param boolean $model * @return \stdClass */ public function convert_post_to_entity($post, $model = false) { $entity = new stdClass(); // Unserialize the post_content_filtered field. if (is_string($post->post_content_filtered)) { if ($post_content = $this->object->unserialize($post->post_content_filtered)) { foreach ($post_content as $key => $value) { $post->{$key} = $value; } } } // Unserialize the post content field. if (is_string($post->post_content)) { if ($post_content = $this->object->unserialize($post->post_content)) { foreach ($post_content as $key => $value) { $post->{$key} = $value; } } } // Copy post fields to entity. unset($post->post_content); unset($post->post_content_filtered); foreach ($post as $key => $value) { $entity->{$key} = $value; } $this->object->_convert_to_entity($entity); return $model ? $this->object->convert_to_model($entity) : $entity; } /** * Converts an entity to a post * * @param object $entity * @return object */ public function _convert_entity_to_post($entity) { // Was a model passed instead of an entity? $post = $entity; if (!$entity instanceof stdClass) { $post = $entity->get_entity(); } // Create the post content. $post_content = clone $post; foreach ($this->object->_table_columns as $column) { unset($post_content->{$column}); } unset($post->id_field); unset($post->post_content_filtered); unset($post->post_content); $post->post_content = $this->object->serialize($post_content); $post->post_content_filtered = $post->post_content; $post->post_type = $this->object->get_object_name(); // Sometimes an entity can contain a data stored in an array or object // Those will be removed from the post, and serialized in the // post_content field. foreach ($post as $key => $value) { if (in_array(strtolower(gettype($value)), ['object', 'array'])) { unset($post->{$key}); } } // A post required a title. if (!property_exists($post, 'post_title')) { $post->post_title = $this->object->get_post_title($post); } // A post also requires an excerpt. if (!property_exists($post, 'post_excerpt')) { $post->post_excerpt = $this->object->get_post_excerpt($post); } return $post; } /** * Returns the WordPress database class * * @global wpdb $wpdb * @return wpdb */ public function _wpdb() { global $wpdb; return $wpdb; } /** * Flush and update all postmeta for a particular post * * @param int $post_id */ public function _flush_and_update_postmeta($post_id, $entity, $omit = array()) { // We need to insert post meta data for each property // Unfortunately, that means flushing all existing postmeta // and then inserting new values. Depending on the number of // properties, this could be slow. So, we directly access the database. /* @var $wpdb wpdb */ global $wpdb; if (!is_array($omit)) { $omit = [$omit]; } // By default, we omit creating meta values for columns in the posts table. $omit = array_merge($omit, $this->object->_table_columns); // Delete the existing meta values. $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->postmeta} WHERE post_id = %s", $post_id)); // Create query for new meta values. $sql_parts = []; foreach ($entity as $key => $value) { if (in_array($key, $omit)) { continue; } if (is_array($value) or is_object($value)) { $value = $this->object->serialize($value); } $sql_parts[] = $wpdb->prepare('(%s, %s, %s)', $post_id, $key, $value); } // The following $sql_parts is already sent through $wpdb->prepare() -- look directly above this line // // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $wpdb->query("INSERT INTO {$wpdb->postmeta} (post_id, meta_key, meta_value) VALUES " . implode(',', $sql_parts)); } /** * Determines whether the current statement is SELECT * * @return boolean */ public function is_select_statement() { return isset($this->object->_query_args['is_select']) && $this->object->_query_args['is_select']; } /** * Determines whether the current statement is DELETE * * @return bool */ public function is_delete_statement() { return isset($this->object->_query_args['is_delete']) && $this->object->_query_args['is_delete']; } /** * Runs the query * * @param string|bool $sql (optional) Run the specified query * @param object|bool $model (optional) * @param bool $convert_to_entities (optional) Default = true * @return array */ public function run_query($sql = false, $model = false, $convert_to_entities = true) { $retval = []; $results = []; // All of our custom fields are stored as post meta, but is also stored as a serialized // value in the post_content field. Because of this, we don't need to look up and cache the // post meta values. $this->object->_query_args['update_post_meta_cache'] = false; $this->object->_query_args['update_post_meta_cache'] = false; $this->object->_query_args['no_found_posts'] = false; // Don't cache any manual SQL query. if ($sql) { $this->object->_query_args['cache_results'] = false; $this->object->_query_args['custom_sql'] = $sql; } // If this is a select query, then try fetching the results from cache. $cache_key = md5(json_encode($this->object->_query_args)); if ($this->is_select_statement() && $this->object->_use_cache) { $results = $this->object->get_from_cache($cache_key); } // Execute the query. if (!$results) { $query = new WP_Query(['datamapper' => true]); if (isset($this->object->debug)) { $this->object->_query_args['debug'] = true; } $query->query_vars = $this->object->_query_args; add_action('pre_get_posts', [&$this, 'set_query_args'], PHP_INT_MAX - 1, 1); $results = $query->get_posts(); // Cache the result. if ($this->is_select_statement()) { $this->object->cache($cache_key, $results); } remove_action('pre_get_posts', [&$this, 'set_query_args'], PHP_INT_MAX - 1); } // Convert the result. if ($convert_to_entities) { foreach ($results as $row) { $retval[] = $this->object->convert_post_to_entity($row, $model); } } else { $retval = $results; } // Ensure that we return an empty array when there are no results. if (!$retval) { $retval = []; } return $retval; } /** * Ensure that the query args are set. We need to do this in case a third-party * plugin overrides our query * * @param $query */ public function set_query_args($query) { if ($query->get('datamapper')) { $query->query_vars = $this->object->_query_args; } $filter = isset($query->query_vars['suppress_filters']) ? $query->query_vars['suppress_filters'] : false; $query->query_vars['suppress_filters'] = apply_filters('wpml_suppress_filters', $filter); } /** * Fetches the last row * * @param array $conditions (optional) * @param object|bool $model (optional) * @return object */ public function find_last($conditions = array(), $model = false) { $retval = null; // Get row number for the last row. $table_name = $this->object->_clean_column($this->object->get_table_name()); $object_name = $this->object->_clean_column($this->object->get_object_name()); $sql = $this->_wpdb()->prepare("SELECT COUNT(*) FROM {$table_name} WHERE post_type = %s", $object_name); $count = $this->_wpdb()->get_var($sql); $offset = $count - 1; $this->select(); if ($conditions) { $this->where_and($conditions); } if ($offset) { $this->limit(1, $offset); } $results = $this->run_query(); if ($results) { $retval = $model ? $this->object->convert_to_model($results[0]) : $results[0]; } return $retval; } /** * Returns the number of total records/entities that exist * * @return int */ public function count() { $this->object->select($this->object->get_primary_key_column()); $retval = $this->object->run_query(false, false, false); return count($retval); } } /** * Provides instance methods for C_DataMapper_Driver_Base * * @mixin C_DataMapper_Driver_Base */ class Mixin_DataMapper_Driver_Base extends Mixin { /** * Serializes the data * * @param mixed $value * @return string */ public function serialize($value) { return \Imagely\NGG\Util\Serializable::serialize($value); } /** * Unserializes data using our proprietary format * * @param string $value * @return mixed */ public function unserialize($value) { return \Imagely\NGG\Util\Serializable::unserialize($value); } /** * Finds a partiular entry by id * * @param int|stdClass|C_DataMapper_Model $entity * @param object|bool $model (optional) * @return null|object */ public function find($entity, $model = false) { $retval = null; // Get primary key of the entity. $pkey = $this->object->get_primary_key_column(); if (!is_numeric($entity)) { $entity = isset($entity->{$pkey}) ? intval($entity->{$pkey}) : false; } // If we have an entity ID, then get the record. if ($entity) { $results = $this->object->select()->where_and(["{$pkey} = %d", $entity])->limit(1, 0)->run_query(); if ($results) { $retval = $model ? $this->object->convert_to_model($results[0]) : $results[0]; } } return $retval; } /** * Converts a stdObject to an Entity * * @param object $stdObject * @return object */ public function _convert_to_entity($stdObject) { // Add name of the id_field to the entity, and convert // the ID to an integer. $stdObject->id_field = $key = $this->object->get_primary_key_column(); // Cast columns to their appropriate data type. $this->cast_columns($stdObject); // Strip slashes. $this->strip_slashes($stdObject); // Unserialize columns. $this->unserialize_columns($stdObject); // Set defaults for this entity. if (!$this->has_default_values($stdObject)) { $this->object->set_defaults($stdObject); $stdObject->__defaults_set = true; } return $stdObject; } /** * Creates a new model * * @param object|array $properties (optional) * @param string|bool $context (optional) * @return C_DataMapper_Model */ public function create($properties = array(), $context = false) { $entity = $properties; $factory = C_Component_Factory::get_instance(); if (!is_object($properties)) { $entity = new stdClass(); foreach ($properties as $k => $v) { $entity->{$k} = $v; } } return $factory->create($this->object->get_model_factory_method(), $entity, $this->object, $context); } /** * Saves an entity * * @param stdClass|C_DataMapper_Model $entity * @return bool|int Resulting ID or false upon failure */ public function save($entity) { $retval = false; $model = $entity; $this->flush_query_cache(); // Attempt to use something else, most likely an associative array // TODO: Support assocative arrays. The trick is to support references // with dynamic calls using __call() and call_user_func_array(). if (is_array($entity)) { throw new E_InvalidEntityException(); } elseif (!$this->object->is_model($entity)) { unset($entity->__defaults_set); $model = $this->object->convert_to_model($entity); } // Validate the model. $model->validate(); if ($model->is_valid()) { $saved_entity = $model->get_entity(); unset($saved_entity->_errors); $retval = $this->object->_save_entity($saved_entity); } $this->flush_query_cache(); // We always return the same type of entity that we given. if (get_class($entity) == 'stdClass') { $model->get_entity(); } return $retval; } /** * Gets validation errors for the entity * * @param stdClass|C_DataMapper_Model $entity * @return array */ public function get_errors($entity) { $model = $entity; if (!$this->object->is_model($entity)) { $model = $this->object->convert_to_model($entity); } $model->validate(); return $model->get_errors(); } /** * Called to set defaults for the record/model/entity. * Subclasses and adapters should extend this method to provide their * implementation. The implementation should make use of the * _set_default_value() method * * @param object $stdObject */ public function set_defaults($stdObject) { } public function has_default_values($entity) { return isset($entity->__defaults_set) && $entity->__defaults_set == true; } public function define_column($name, $type, $default_value = null) { $this->object->_columns[$name] = ['type' => $type, 'default_value' => $default_value]; } } /** * Class C_DataMapper_Model * * @mixin Mixin_Validation * @mixin Mixin_DataMapper_Model_Instance_Methods * @mixin Mixin_DataMapper_Model_Validation */ class C_DataMapper_Model extends C_Component { var $_mapper; var $_stdObject; /** * Define the model */ public function define($mapper = null, $properties = array(), $context = false) { parent::define($context); $this->add_mixin('Mixin_Validation'); $this->add_mixin('Mixin_DataMapper_Model_Instance_Methods'); $this->add_mixin('Mixin_DataMapper_Model_Validation'); $this->implement('I_DataMapper_Model'); } /** * Creates a new entity for the specified mapper * * @param C_DataMapper_Driver_Base $mapper (optional) * @param array|object|bool $properties (optional) */ public function initialize($mapper = null, $properties = false) { $this->_mapper = $mapper; $this->_stdObject = $properties ? (object) $properties : new stdClass(); parent::initialize(); if (!$this->has_default_values()) { $this->set_defaults(); $this->_stdObject->__defaults_set = true; } } public function jsonSerialize() { return $this->get_entity(); } public function has_default_values() { return isset($this->_stdObject->__defaults_set) && $this->_stdObject->__defaults_set == true; } /** * Gets the data mapper for the entity * * @return C_DataMapper_Driver_Base */ public function get_mapper() { return $this->_mapper; } /** * Gets a property of the model * * @param string $property * @return mixed */ public function &__get($property) { if (isset($this->_stdObject->{$property})) { $retval =& $this->_stdObject->{$property}; return $retval; } else { // We need to assign NULL to a variable first, since only // variables can be returned by reference. $retval = null; return $retval; } } /** * Sets a property for the model * * @param mixed $property * @param mixed $value * @return mixed $value */ public function &__set($property, $value) { $retval = $this->_stdObject->{$property} = $value; return $retval; } public function __isset($property_name) { return isset($this->_stdObject->{$property_name}); } /** * Saves the entity * * @param array $updated_attributes * @return int|bool Object ID or false upon failure */ public function save($updated_attributes = array()) { $this->update_attributes($updated_attributes); return $this->get_mapper()->save($this->get_entity()); } /** * Updates the attributes for an object * * @param array $array (optional) */ public function update_attributes($array = array()) { foreach ($array as $key => $value) { $this->_stdObject->{$key} = $value; } } /** * Sets the default values for this model */ public function set_defaults() { $mapper = $this->get_mapper(); if ($mapper->has_method('set_defaults')) { $mapper->set_defaults($this); } } /** * Destroys or deletes the entity */ public function destroy() { return $this->get_mapper()->destroy($this->_stdObject); } /** * Determines whether the object is new or existing * * @return bool */ public function is_new() { return $this->id() ? false : true; } /** * Gets/sets the primary key * * @param null|int|string $value (optional) * @return mixed */ public function id($value = null) { $key = $this->get_mapper()->get_primary_key_column(); if ($value) { $this->__set($key, $value); } return $this->__get($key); } } /** * This mixin should be overwritten by other modules */ class Mixin_DataMapper_Model_Validation extends Mixin { public function validation() { return $this->object->is_valid(); } } class Mixin_DataMapper_Model_Instance_Methods extends Mixin { /** * Returns the associated entity */ public function &get_entity() { return $this->object->_stdObject; } }photocrati_nextgen/modules/nextgen_addgallery_page/module.nextgen_addgallery_page.php000064400000012703150212224050025601 0ustar00add_form( NGG_ADD_GALLERY_SLUG, 'upload_images' ); if ( ! is_multisite() || ( is_multisite() && $settings->get( 'wpmuImportFolder' ) ) ) { $forms->add_form( NGG_ADD_GALLERY_SLUG, 'import_media_library' ); $forms->add_form( NGG_ADD_GALLERY_SLUG, 'import_folder' ); } } public function check_upload_dir_permissions_requirement() { return wp_is_writable( \Imagely\NGG\DataStorage\Manager::get_instance()->get_upload_abspath() ); } public function check_domdocument_requirement() { return class_exists( 'DOMDocument' ); } function get_type_list() { return [ 'A_Import_Media_Library_Form' => 'adapter.import_media_library_form.php', 'A_Import_Folder_Form' => 'adapter.import_folder_form.php', 'A_Nextgen_Addgallery_Ajax' => 'adapter.nextgen_addgallery_ajax.php', 'A_Nextgen_Addgallery_Controller' => 'adapter.nextgen_addgallery_controller.php', 'A_Nextgen_Addgallery_Pages' => 'adapter.nextgen_addgallery_pages.php', 'A_Upload_Images_Form' => 'adapter.upload_images_form.php', ]; } function _register_adapters() { // AJAX operations aren't admin requests. $this->get_registry()->add_adapter( 'I_Ajax_Controller', 'A_NextGen_AddGallery_Ajax' ); if ( is_admin() ) { $this->get_registry()->add_adapter( 'I_Page_Manager', 'A_NextGen_AddGallery_Pages' ); $this->get_registry()->add_adapter( 'I_NextGen_Admin_Page', 'A_NextGen_AddGallery_Controller', NGG_ADD_GALLERY_SLUG ); $this->get_registry()->add_adapter( 'I_Form', 'A_Upload_Images_Form', 'upload_images' ); if ( ! is_multisite() || ( is_multisite() && \Imagely\NGG\Settings\Settings::get_instance()->get( 'wpmuImportFolder' ) ) ) { $this->get_registry()->add_adapter( 'I_Form', 'A_Import_Folder_Form', 'import_folder' ); $this->get_registry()->add_adapter( 'I_Form', 'A_Import_Media_Library_Form', 'import_media_library' ); } } } function _register_hooks() { add_action( 'admin_init', [ $this, 'register_requirements' ] ); add_action( 'admin_init', [ $this, 'register_scripts' ] ); } public function register_requirements() { \Imagely\NGG\Admin\RequirementsManager::get_instance()->add( 'nextgen_addgallery_xmlcheck', 'phpext', [ $this, 'check_domdocument_requirement' ], [ 'message' => __( 'XML is strongly encouraged for safely uploading images', 'nggallery' ) ] ); $directory = \Imagely\NGG\DataStorage\Manager::get_instance()->get_upload_abspath(); \Imagely\NGG\Admin\RequirementsManager::get_instance()->add( 'add_gallery_upload_dir_permission', 'dirperms', [ $this, 'check_upload_dir_permissions_requirement' ], [ 'message' => sprintf( __( 'Cannot write to %s: new galleries cannot be created', 'nggallery' ), $directory ) ] ); } function register_scripts() { if ( is_admin() ) { $router = \Imagely\NGG\Util\Router::get_instance(); $add_gallery_page_id = 'photocrati-nextgen_addgallery_page'; wp_register_style( 'nextgen_addgallery_page', $router->get_static_url( $add_gallery_page_id . '#styles.css' ), [], NGG_SCRIPT_VERSION ); wp_register_script( 'uppy', $router->get_static_url( $add_gallery_page_id . '#uppy/uppy.min.js' ), [], '1.27.0' ); wp_register_style( 'uppy', $router->get_static_url( $add_gallery_page_id . '#uppy/uppy.min.css' ), [], '1.21.1' ); wp_register_script( 'uppy_i18n', $router->get_static_url( $add_gallery_page_id . '#uppy/i18n.min.js' ), [ 'uppy' ], '1.21.1' ); wp_register_script( 'toastify', $router->get_static_url( $add_gallery_page_id . '#toastify.js' ), [], '1.9.2' ); wp_register_style( 'toastify', $router->get_static_url( $add_gallery_page_id . '#toastify.min.css' ), [], '1.9.2' ); wp_register_script( 'jquery.filetree', $router->get_static_url( $add_gallery_page_id . '#jquery.filetree/jquery.filetree.js' ), [ 'jquery' ], NGG_SCRIPT_VERSION ); wp_register_style( 'jquery.filetree', $router->get_static_url( $add_gallery_page_id . '#jquery.filetree/jquery.filetree.css' ), [], NGG_SCRIPT_VERSION ); wp_register_script( 'nextgen_media_library_import-js', $router->get_static_url( $add_gallery_page_id . '#media-library-import.js' ), [ 'jquery', 'ngg_progressbar' ], NGG_SCRIPT_VERSION ); wp_register_style( 'nextgen_media_library_import-css', $router->get_static_url( $add_gallery_page_id . '#media-library-import.css' ), [], NGG_SCRIPT_VERSION ); } } } new M_NextGen_AddGallery_Page(); photocrati_nextgen/modules/nextgen_addgallery_page/package.module.nextgen_addgallery_page.php000064400000060331150212224050027173 0ustar00call_parent('enqueue_static_resources'); } public function render() { return $this->object->render_partial('photocrati-nextgen_addgallery_page#import_folder', ['browse_nonce' => \Imagely\NGG\Util\Security::create_nonce('nextgen_upload_image'), 'import_nonce' => \Imagely\NGG\Util\Security::create_nonce('nextgen_upload_image')], true); } } /** * Class A_Import_Media_Library_Form * * @mixin C_Form * @adapts I_Form for import_media_library context */ class A_Import_Media_Library_Form extends Mixin { public function get_title() { return __('Import from Media Library', 'nggallery'); } public function enqueue_static_resources() { wp_enqueue_media(); wp_enqueue_script('nextgen_media_library_import-js'); wp_enqueue_style('nextgen_media_library_import-css'); $url = admin_url() . 'admin.php?page=nggallery-manage-gallery&mode=edit&gid={gid}'; $i18n_array = ['admin_url' => admin_url(), 'title' => __('Import Images into NextGen Gallery', 'nggallery'), 'import_multiple' => __('Import %s images', 'nggallery'), 'import_singular' => __('Import 1 image', 'nggallery'), 'imported_multiple' => sprintf(__('{count} images were uploaded successfully. Manage gallery', 'nggallery'), $url), 'imported_singular' => sprintf(__('1 image was uploaded successfully. Manage gallery', 'nggallery'), $url), 'imported_none' => __('0 images were uploaded', 'nggallery'), 'progress_title' => __('Importing gallery', 'nggallery'), 'in_progress' => __('In Progress...', 'nggallery'), 'gritter_title' => __('Upload complete. Great job!', 'nggallery'), 'gritter_error' => __('Oops! Sorry, but an error occured. This may be due to a server misconfiguration. Check your PHP error log or ask your hosting provider for assistance.', 'nggallery'), 'nonce' => \Imagely\NGG\Util\Security::create_nonce('nextgen_upload_image')]; wp_localize_script('nextgen_media_library_import-js', 'ngg_importml_i18n', $i18n_array); } public function render() { $i18n = ['select-images-to-continue' => __('Please make a selection to continue', 'nggallery'), 'select-opener' => __('Select images', 'nggallery'), 'selected-image-import' => __('Import %d image(s)', 'nggallery')]; return $this->object->render_partial('photocrati-nextgen_addgallery_page#import_media_library', ['i18n' => $i18n, 'galleries' => $this->object->get_galleries()], true); } public function get_galleries() { $galleries = []; if (\Imagely\NGG\Util\Security::is_allowed('nextgen_edit_gallery')) { $galleries = \Imagely\NGG\DataMappers\Gallery::get_instance()->find_all(); if (!\Imagely\NGG\Util\Security::is_allowed('nextgen_edit_gallery_unowned')) { $galleries_all = $galleries; $galleries = []; foreach ($galleries_all as $gallery) { if (wp_get_current_user()->ID == (int) $gallery->author) { $galleries[] = $gallery; } } } } return $galleries; } } /** * Class A_NextGen_AddGallery_Ajax * * @mixin C_Ajax_Controller * @adapts I_Ajax_Controller */ class A_NextGen_AddGallery_Ajax extends Mixin { public function cookie_dump_action() { foreach ($_COOKIE as $key => &$value) { if (is_string($value)) { $value = stripslashes($value); } } return ['success' => 1, 'cookies' => $_COOKIE]; } public function create_new_gallery_action() { $gallery_name = urldecode($this->param('gallery_name')); $gallery_mapper = \Imagely\NGG\DataMappers\Gallery::get_instance(); $retval = ['gallery_name' => esc_html($gallery_name), 'gallery_id' => null]; if (!$this->validate_ajax_request('nextgen_upload_image', true)) { $action = 'nextgen_upload_image'; $retval['allowed'] = \Imagely\NGG\Util\Security::is_allowed($action); $retval['verified_token'] = !isset($_REQUEST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_REQUEST['nonce'])), $action); $retval['error'] = __('No permissions to upload images. Try refreshing the page or ensuring that your user account has sufficient roles/privileges.', 'nggallery'); return $retval; } if (strlen($gallery_name) > 0) { $gallery = $gallery_mapper->create(['title' => $gallery_name]); if (!$gallery->save()) { $retval['error'] = $gallery->validate(); } else { $retval['gallery_id'] = $gallery->id(); } } else { $retval['error'] = __('No gallery name specified', 'nggallery'); } return $retval; } public function upload_image_action() { $created_gallery = false; $gallery_id = intval($this->param('gallery_id')); $gallery_name = urldecode($this->param('gallery_name')); $gallery_mapper = \Imagely\NGG\DataMappers\Gallery::get_instance(); $retval = ['gallery_name' => esc_html($gallery_name)]; if ($this->validate_ajax_request('nextgen_upload_image', true)) { if (!class_exists('DOMDocument')) { $retval['error'] = __('Please ask your hosting provider or system administrator to enable the PHP XML module which is required for image uploads', 'nggallery'); } else { // We need to create a gallery. if ($gallery_id == 0) { if (strlen($gallery_name) > 0) { $gallery = $gallery_mapper->create(['title' => $gallery_name]); if (!$gallery->save()) { $retval['error'] = $gallery->validate(); } else { $created_gallery = true; $gallery_id = $gallery->id(); } } else { $retval['error'] = __('No gallery name specified', 'nggallery'); } } // Upload the image to the gallery. if (empty($retval['error'])) { $retval['gallery_id'] = $gallery_id; $settings = \Imagely\NGG\Settings\Settings::get_instance(); $storage = \Imagely\NGG\DataStorage\Manager::get_instance(); try { if ($storage->is_zip()) { if ($results = $storage->upload_zip($gallery_id)) { $retval = $results; } else { $retval['error'] = __('Failed to extract images from ZIP', 'nggallery'); } } elseif ($image_id = $storage->upload_image($gallery_id)) { $retval['image_ids'] = [$image_id]; // check if image was resized correctly. if ($settings->get('imgAutoResize')) { $image_path = $storage->get_full_abspath($image_id); $image_thumb = new \Imagely\NGG\DataTypes\LegacyThumbnail($image_path, true); if ($image_thumb->error) { $retval['error'] = sprintf(__('Automatic image resizing failed [%1$s].', 'nggallery'), $image_thumb->errmsg); } } // check if thumb was generated correctly. $thumb_path = $storage->get_image_abspath($image_id, 'thumb'); if (!file_exists($thumb_path)) { $retval['error'] = __('Thumbnail generation failed.', 'nggallery'); } } else { $retval['error'] = __('Image generation failed', 'nggallery'); } } catch (E_NggErrorException $ex) { $retval['error'] = $ex->getMessage(); if ($created_gallery) { $gallery_mapper->destroy($gallery_id); } } catch (Exception $ex) { $retval['error'] = sprintf(__('An unexpected error occurred: %s', 'nggallery'), $ex->getMessage()); } } } } else { $action = 'nextgen_upload_image'; $retval['allowed'] = \Imagely\NGG\Util\Security::is_allowed($action); $retval['verified_token'] = !isset($_REQUEST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_REQUEST['nonce'])), $action); $retval['error'] = __('No permissions to upload images. Try refreshing the page or ensuring that your user account has sufficient roles/privileges.', 'nggallery'); } // Sending a 500 header is used for uppy.js to determine upload failures. if (!empty($retval['error'])) { header('HTTP/1.1 500 Internal Server Error'); } return $retval; } public function get_import_root_abspath() { if (is_multisite()) { $root = \Imagely\NGG\DataStorage\Manager::get_instance()->get_upload_abspath(); } else { $root = NGG_IMPORT_ROOT; } $root = str_replace('/', DIRECTORY_SEPARATOR, $root); return untrailingslashit($root); } public function browse_folder_action() { $retval = []; $html = []; if ($this->validate_ajax_request('nextgen_upload_image', true)) { if ($dir = urldecode($this->param('dir'))) { $fs = \Imagely\NGG\Util\Filesystem::get_instance(); $root = $this->get_import_root_abspath(); $browse_path = $fs->join_paths($root, $dir); if (strpos(realpath($browse_path), realpath($root)) !== false) { if (@file_exists($browse_path)) { $files = scandir($browse_path); natcasesort($files); if (count($files) > 2) { /* The 2 accounts for . and .. */ $html[] = ''; } $retval['html'] = implode("\n", $html); } else { $retval['error'] = __('Directory does not exist.', 'nggallery'); } } else { $retval['error'] = __('No permissions to browse folders. Try refreshing the page or ensuring that your user account has sufficient roles/privileges.', 'nggallery'); } } else { $retval['error'] = __('No directory specified.', 'nggallery'); } } else { $retval['error'] = __('No permissions to browse folders. Try refreshing the page or ensuring that your user account has sufficient roles/privileges.', 'nggallery'); } return $retval; } public function import_folder_action() { $retval = []; if ($this->validate_ajax_request('nextgen_upload_image', true)) { if ($folder = $this->param('folder')) { $storage = \Imagely\NGG\DataStorage\Manager::get_instance(); $fs = \Imagely\NGG\Util\Filesystem::get_instance(); try { $keep_files = $this->param('keep_location') == 'on'; $gallery_title = $this->param('gallery_title', null); if (empty($gallery_title)) { $gallery_title = null; } $root = $this->get_import_root_abspath(); $import_path = $fs->join_paths($root, $folder); if (strpos(realpath($import_path), realpath($root)) !== false) { $retval = $storage->import_gallery_from_fs($import_path, false, !$keep_files, $gallery_title); if (!$retval) { $retval = ['error' => 'Could not import folder. No images found.']; } } else { $retval['error'] = __('No permissions to import folders. Try refreshing the page or ensuring that your user account has sufficient roles/privileges.', 'nggallery'); } } catch (E_NggErrorException $ex) { $retval['error'] = $ex->getMessage(); } catch (Exception $ex) { $retval['error'] = __('An unexpected error occured.', 'nggallery'); $retval['error_details'] = $ex->getMessage(); } } else { $retval['error'] = __('No folder specified', 'nggallery'); } } else { $retval['error'] = __('No permissions to import folders. Try refreshing the page or ensuring that your user account has sufficient roles/privileges.', 'nggallery'); } return $retval; } public function import_media_library_action() { $retval = []; $created_gallery = false; $gallery_id = intval($this->param('gallery_id')); $gallery_name = urldecode($this->param('gallery_name')); $gallery_mapper = \Imagely\NGG\DataMappers\Gallery::get_instance(); $image_mapper = \Imagely\NGG\DataMappers\Image::get_instance(); $attachment_ids = $this->param('attachment_ids'); if ($this->validate_ajax_request('nextgen_upload_image', true)) { if (empty($attachment_ids) || !is_array($attachment_ids)) { $retval['error'] = __('An unexpected error occured.', 'nggallery'); } if (empty($retval['error']) && $gallery_id == 0) { if (strlen($gallery_name) > 0) { $gallery = $gallery_mapper->create(['title' => $gallery_name]); if (!$gallery->save()) { $retval['error'] = $gallery->validate(); } else { $created_gallery = true; $gallery_id = $gallery->id(); } } else { $retval['error'] = __('No gallery name specified', 'nggallery'); } } if (empty($retval['error'])) { $retval['gallery_id'] = $gallery_id; $storage = \Imagely\NGG\DataStorage\Manager::get_instance(); foreach ($attachment_ids as $id) { try { $abspath = get_attached_file($id); $file_data = @file_get_contents($abspath); $file_name = \Imagely\NGG\Display\I18N::mb_basename($abspath); $attachment = get_post($id); if (empty($file_data)) { $retval['error'] = __('Image generation failed', 'nggallery'); break; } $image = $storage->upload_image($gallery_id, $file_name, $file_data); if ($image) { // Potentially import metadata from WordPress. $image = $image_mapper->find($image); if (!empty($attachment->post_excerpt)) { $image->alttext = $attachment->post_excerpt; } if (!empty($attachment->post_content)) { $image->description = $attachment->post_content; } $image = apply_filters('ngg_medialibrary_imported_image', $image, $attachment); $image_mapper->save($image); $retval['image_ids'][] = $image->{$image->id_field}; } else { $retval['error'] = __('Image generation failed', 'nggallery'); break; } } catch (E_NggErrorException $ex) { $retval['error'] = $ex->getMessage(); if ($created_gallery) { $gallery_mapper->destroy($gallery_id); } } catch (Exception $ex) { $retval['error'] = __('An unexpected error occured.', 'nggallery'); $retval['error_details'] = $ex->getMessage(); } } } } else { $retval['error'] = __('No permissions to upload images. Try refreshing the page or ensuring that your user account has sufficient roles/privileges.', 'nggallery'); } if (!empty($retval['error'])) { return $retval; } else { $retval['gallery_name'] = esc_html($gallery_name); } return $retval; } } /** * Class A_NextGen_AddGallery_Controller * * @mixin C_NextGen_Admin_Page_Controller * @adapts I_NextGen_Admin_Page */ class A_NextGen_AddGallery_Controller extends Mixin { public function get_page_title() { return __('Add Gallery / Images', 'nggallery'); } public function get_required_permission() { return 'NextGEN Upload images'; } public function enqueue_backend_resources() { $this->call_parent('enqueue_backend_resources'); wp_enqueue_style('nextgen_addgallery_page'); wp_enqueue_script('nextgen_addgallery_page'); wp_enqueue_script('frame_event_publisher'); } public function show_save_button() { return false; } } /** * Class A_NextGen_AddGallery_Pages * * @mixin C_NextGen_Admin_Page_Manager * @adapts I_Page_Manager */ class A_NextGen_AddGallery_Pages extends Mixin { public function setup() { $this->object->add(NGG_ADD_GALLERY_SLUG, ['adapter' => 'A_NextGen_AddGallery_Controller', 'parent' => NGGFOLDER, 'add_menu' => true, 'before' => 'nggallery-manage-gallery']); return $this->call_parent('setup'); } } /** * Class A_Upload_Images_Form * * @mixin C_Form * @property C_MVC_Controller|A_Upload_Images_Form $object * @adapts I_Form for "upload_images" context */ class A_Upload_Images_Form extends Mixin { public function get_title() { return __('Upload Images', 'nggallery'); } public function enqueue_static_resources() { wp_enqueue_script('uppy'); wp_enqueue_script('uppy_i18n'); wp_enqueue_style('uppy'); wp_enqueue_script('toastify'); wp_enqueue_style('toastify'); wp_localize_script('uppy', 'NggUploadImages_i18n', $this->object->get_i18n_strings()); M_Ajax::pass_data_to_js('uppy', 'NggUppyCoreSettings', $this->object->get_uppy_core_settings()); M_Ajax::pass_data_to_js('uppy', 'NggUppyDashboardSettings', $this->object->get_uppy_dashboard_settings()); M_Ajax::pass_data_to_js('uppy', 'NggXHRSettings', $this->object->get_uppy_xhr_settings()); } public function get_uppy_note() { $core_settings = $this->object->get_uppy_core_settings(); $max_size = $core_settings['restrictions']['maxfileSize']; $max_size_megabytes = round((int) $max_size / (1024 * 1024)); return sprintf(__('You may select files up to %dMB', 'nggallery'), $max_size_megabytes); } public function get_uppy_xhr_settings() { return apply_filters('ngg_uppy_xhr_settings', ['timeout' => intval(NGG_UPLOAD_TIMEOUT) * 1000, 'limit' => intval(NGG_UPLOAD_LIMIT), 'fieldName' => 'file']); } public function get_uppy_core_settings() { $mime = apply_filters('ngg_allowed_mime_types', NGG_DEFAULT_ALLOWED_MIME_TYPES); return apply_filters('ngg_uppy_core_settings', ['locale' => $this->object->get_uppy_locale(), 'restrictions' => ['maxfileSize' => wp_max_upload_size(), 'allowedFileTypes' => $this->can_upload_zips() ? array_merge($mime, ['.zip']) : get_allowed_mime_types()]]); } public function get_uppy_dashboard_settings() { return apply_filters('ngg_uppy_dashboard_settings', ['inline' => true, 'target' => '#uploader', 'width' => '100%', 'proudlyDisplayPoweredByUppy' => false, 'hideRetryButton' => true, 'note' => $this->object->get_uppy_note(), 'locale' => ['strings' => ['dropPaste' => $this->can_upload_zips() ? __('Drag image and ZIP files here or %{browse}', 'nggallery') : __('Drag image files here or %{browse}', 'nggallery')]]]); } public function get_uppy_locale() { $locale = get_locale(); $mapping = ['ar' => 'ar_SA', 'bg' => 'bg_BG', 'zh-cn' => 'zh_CN', 'zh-tw' => 'zh_TW', 'hr' => 'hr_HR', 'cs' => 'cs_CZ', 'da' => 'da_DK', 'nl' => 'nl_NL', 'en' => 'en_US', 'fi' => 'fi_FI', 'fr' => 'fr_FR', 'gl' => 'gl_ES', 'de' => 'de_DE', 'el' => 'el_GR', 'he' => 'he_IL', 'hu' => 'hu_HU', 'is' => 'is_IS', 'id' => 'id_ID', 'it' => 'it_IT', 'ja' => 'ja_JP', 'ko' => 'ko_KR', 'fa' => 'fa_IR', 'pl' => 'pl_PL', 'pt-br' => 'pt_BR', 'pt' => 'pt_PT', 'ro' => 'ro_RO', 'ru' => 'ru_RU', 'sr' => 'sr_RS', 'sk' => 'sk_SK', 'es' => 'es_ES', 'sv' => 'sv_SE', 'th' => 'th_TH', 'tr' => 'tr_TR', 'vi' => 'vi_VN']; if (!empty($mapping[$locale])) { $locale = $mapping[$locale]; } return $locale; } public function can_upload_zips() { $global_settings = \Imagely\NGG\Settings\GlobalSettings::get_instance(); return !is_multisite() || is_multisite() && $global_settings->get('wpmuZipUpload'); } public function get_i18n_strings() { return ['locale' => $this->object->get_uppy_locale(), 'no_image_uploaded' => __('No images were uploaded successfully.', 'nggallery'), 'one_image_uploaded' => __('1 image was uploaded successfully.', 'nggallery'), 'x_images_uploaded' => __('{count} images were uploaded successfully.', 'nggallery'), 'manage_gallery' => __('Manage gallery > {name}', 'nggallery'), 'image_failed' => __('Image {filename} failed to upload: {error}', 'nggallery'), 'drag_files_here' => $this->can_upload_zips() ? __('Drag image and ZIP files here or %{browse}', 'nggallery') : __('Drag image files here or %{browse}', 'nggallery')]; } public function render() { return $this->object->render_partial('photocrati-nextgen_addgallery_page#upload_images', ['galleries' => $this->object->get_galleries(), 'nonce' => \Imagely\NGG\Util\Security::create_nonce('nextgen_upload_image')], true); } public function get_galleries() { $galleries = []; if (\Imagely\NGG\Util\Security::is_allowed('nextgen_edit_gallery')) { $gallery_mapper = \Imagely\NGG\DataMappers\Gallery::get_instance(); $galleries = $gallery_mapper->find_all(); if (!\Imagely\NGG\Util\Security::is_allowed('nextgen_edit_gallery_unowned')) { $galleries_all = $galleries; $galleries = []; foreach ($galleries_all as $gallery) { if (wp_get_current_user()->ID == (int) $gallery->author) { $galleries[] = $gallery; } } } } return $galleries; } }photocrati_nextgen/modules/nextgen_addgallery_page/templates/upload_images.php000064400000025640150212224050024274 0ustar00
photocrati_nextgen/modules/nextgen_addgallery_page/templates/import_folder.php000064400000006127150212224050024327 0ustar00



photocrati_nextgen/modules/nextgen_addgallery_page/templates/import_media_library.php000064400000001436150212224050025655 0ustar00 photocrati_nextgen/modules/nextgen_addgallery_page/static/media-library-import.min.css000064400000000771150212224050025566 0ustar00#ngg-importML-selected-image-import.hidden{display:none}#ngg-importML-select-opener.hidden{display:none}#ngg-importML-gallery-selection{display:inline-block}#ngg-importML-selected-image-import{vertical-align:middle}#ngg-importML-select-opener{vertical-align:middle}#ngg-importML-gallery-name{vertical-align:middle}#ngg-importML-gallery-select{vertical-align:middle}.ngg_settings_page .jqueryFileTree LI.directory{background-size:contain}.ngg_settings_page .jqueryFileTree LI.expanded{background-size:21px}photocrati_nextgen/modules/nextgen_addgallery_page/static/styles.css000064400000013705150212224050022277 0ustar00@font-face { font-family: 'Lato'; src: url('../../nextgen_admin/static/Lato-Regular.ttf') format('truetype') } #ngg_page_content .ngg_page_content_main { min-height: 0; } #gallery_selection { display: flex; align-items: center; justify-content: left; padding: 20px 20px 25px !important; background: #f7f7f7; flex-wrap: wrap; } #gallery_selection label { font-weight: 600; position: relative; top: -1px; } #gallery_name { width: auto; min-width: 200px; } #gallery_name.error { border: solid 1px red; } #upload_images_content { padding: 0px; } /* Gritter customizations */ #gritter-notice-wrapper { background: rgba(56, 70, 82, .9); border: 1px solid #2a343d; margin: 10px 5px 0 0; border-radius: 3px; bottom: 20px; top: auto; } .gritter-top, .gritter-item, .gritter-bottom { background: none; } .gritter-item { padding: 2px 11px 0 11px; } .gritter-title { text-shadow: none; } #gritter-notice-wrapper a { color: #b8d433; text-decoration: none; padding-top: 5px; display: block; } .gritter-close { width: auto; height: auto; background: none; display: block !important; right: 10px; } .gritter-close:after { content: 'X'; font-weight: bold; font-size: 13px; } /* For Redesign */ .gallery_page_ngg_addgallery #ngg_page_content .ngg_page_content_menu { width: 25%; } .gallery_page_ngg_addgallery #ngg_page_content .ngg_page_content_main { width: 75%; } #ngg_page_content #gallery_id, #ngg_page_content #gallery_name { min-width: 200px !important; font-size: 13px !important; font-family: "Lato", sans-serif; font-weight: 400; color: black !important; vertical-align: middle; } #ngg_page_content input#import_gallery_title { width: 250px; font-size: 13px; color: #aaa; } #ngg_page_content #gallery_create { background: black; margin-left: 2px; } .toast-close { opacity: 1 !important; color: white; margin-left: 10px; } /* This button will appear at lower resolutions despite the hidden class */ #ngg_page_content #gallery_create.hidden { display: none !important; } #ngg_page_content #gallery_create:hover { cursor: pointer; } /* Uppy specific styling and tweaks */ #ngg_page_content button.uppy-StatusBar-actionBtn, #ngg_page_content button.uppy-DashboardContent-back, #ngg_page_content button.uppy-DashboardContent-addMore, #ngg_page_content button.uppy-Dashboard-browse { background: black; } #ngg_page_content button.uppy-DashboardContent-addMore svg { height: 22px; width: 18px; margin-top: 7px; margin-right: 0; } #ngg_page_content .uppy-size--md span.uppy-DashboardContent-addMoreCaption { margin-left: 8px; } #ngg_page_content span.uppy-DashboardContent-addMoreCaption { float: right; } #ngg_page_content .uppy-Dashboard-Item-progressIndicator:hover { background: none !important; } #ngg_page_content .uppy-StatusBar-actions button { padding-right: 0; } #ngg_page_content button.uppy-StatusBar-actionBtn--retry { margin-right: 6px; padding-left: 27px !important; } #ngg_page_content .uppy-StatusBar-actionBtn--retry svg { top: 12px; } #ngg_page_content button.uppy-StatusBar-actionCircleBtn:hover { background: none !important; } #ngg_page_content button.uppy-StatusBar-actionCircleBtn { padding: 0 !important; } #ngg_page_content button.uppy-StatusBar-actionCircleBtn svg { vertical-align: middle; } #ngg_page_content button.uppy-DashboardContent-addMore svg, #ngg_page_content button.uppy-StatusBar-actions svg { line-height: initial; } #ngg_page_content button.uppy-Dashboard-Item-action--remove { background: none !important; padding: 0 !important; width: auto !important; margin: 0; } #ngg_page_content button.uppy-Dashboard-Item-action--remove svg { color: #1f1f1f !important; } #ngg_page_content div.uppy-Dashboard-AddFiles-title { max-width: 600px; } #ngg-create-gallery-default-text { } #ngg-create-gallery-waiting-text { } @media screen and (max-width: 1200px) { #gallery_selection { justify-content: center; } #ngg_page_content #gallery_name { flex-grow: 1; } #gallery_create { margin-top: 5px; } } @media screen and (max-width: 782px) { #ngg_page_content div.uppy-DashboardContent-title { } #ngg_page_content button.uppy-DashboardContent-addMore, #ngg_page_content button.uppy-DashboardContent-back { width: auto !important; margin: 0; } } /* Media Queries */ @media (max-width: 1380px) { .gallery_page_ngg_addgallery #ngg_page_content .ngg_page_content_menu, .gallery_page_ngg_addgallery #ngg_page_content .ngg_page_content_main { width: 100%; } } @media (max-width: 1140px) { .gallery_page_ngg_addgallery #ngg_page_content button, .gallery_page_ngg_addgallery #ngg_page_content .button-primary, .gallery_page_ngg_addgallery #ngg_page_content .button-secondary { width: 201px !important; } } @media (max-width: 800px) { .gallery_page_ngg_addgallery #ngg_page_content .ngg_page_content_menu, .gallery_page_ngg_addgallery #ngg_page_content .ngg_page_content_main { width: 100%; } .gallery_page_ngg_addgallery #ngg_page_content .ngg_page_content_main input, .gallery_page_ngg_addgallery #ngg_page_content .ngg_page_content_main select { width: 100% !important; max-width: 100%; margin: 5px 0; box-sizing: border-box; } .gallery_page_ngg_addgallery #ngg_page_content input[type=checkbox] { width: 16px !important; } .gallery_page_ngg_addgallery #ngg_page_content button, .gallery_page_ngg_addgallery #ngg_page_content .button-primary, .gallery_page_ngg_addgallery #ngg_page_content .button-secondary { width: 100% !important; margin: 4px 0; display: block; text-align: center; } #ngg-importML-gallery-selection { display: block !important; } }photocrati_nextgen/modules/nextgen_addgallery_page/static/toastify.min.js000064400000012135150212224050023220 0ustar00"use strict";function _typeof(t){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}!function(t){"object"===("undefined"==typeof module?"undefined":_typeof(module))&&module.exports?module.exports=t():(void 0).Toastify=t()}(function(t){function o(t){return new o.lib.init(t)}function s(t,o){return o.offset[t]?isNaN(o.offset[t])?o.offset[t]:o.offset[t]+"px":"0px"}function p(t,o){return!(!t||"string"!=typeof o)&&!!(t.className&&-1",i.className="toast-close",i.addEventListener("click",function(t){t.stopPropagation(),this.removeElement(this.toastElement),window.clearTimeout(this.toastElement.timeOutValue)}.bind(this)),o=0>>ooo$2u {4= aă |ʠ̀X(1 M$n8 ؀pTۂVJ0S<|_   H l o5]Z jN b ]#NQ! ,???sss$2u {4= aă v2.FX(Eax,Ii L @o=:D(N D?A* t H.: CYa ^ ]-WOa#f#u ^! ,...ooo$2uz4= ă @5F X( H &qb 3I$&ش !((A,    H._  W( \$!  1!#_# \;photocrati_nextgen/modules/nextgen_addgallery_page/static/jquery.filetree/images/folder_open.png000064400000036445150212224050027634 0ustar00PNG  IHDRL@UP pHYs  9iTXtXML:com.adobe.xmp Adobe Photoshop CC 2015 (Macintosh) 2017-12-15T19:53:06-07:00 2017-12-15T19:57:42-07:00 2017-12-15T19:57:42-07:00 image/png 3 xmp.iid:e0d5da98-107c-4584-b509-2f1175cddae2 adobe:docid:photoshop:4f52f02e-229b-117b-9d9c-ddc7040f2fad xmp.did:43b600e4-dd2e-46ed-be88-7709361bb749 created xmp.iid:43b600e4-dd2e-46ed-be88-7709361bb749 2017-12-15T19:53:06-07:00 Adobe Photoshop CC 2015 (Macintosh) saved xmp.iid:e0d5da98-107c-4584-b509-2f1175cddae2 2017-12-15T19:57:42-07:00 Adobe Photoshop CC 2015 (Macintosh) / 1 720000/10000 720000/10000 2 65535 76 64 f cHRMz%u0`:o_FIDATxMkQ EAiY[n KqB.Auޭ MI[b\)HI&wVMr !sɐ{{ι7ɴmLf 3`&fr;߸vC2^%ph gOr-` n  ρCaS:d} ` ҧ慥0fLJ}"({v;-w,>%3XT *5pF w@XU~B 2X@TQoDԍբ`@V',|R ,rU%%EJ݊pܐ95w`KRt"<X|RwXQo|D C g.%5u(B`e)$>`'w(i%V|5o ,Böas5r)-MeEWߝLlg bǕw-$+D'J\v:|Tdk. k k jJ ! ܔ"j[PP `UtEI" qVK6J?^I鬌N2/A +\;`IENDB`photocrati_nextgen/modules/nextgen_addgallery_page/static/jquery.filetree/images/directory.png000064400000036557150212224050027350 0ustar00PNG  IHDRD@Ѥ pHYs  ;iTXtXML:com.adobe.xmp Adobe Photoshop CC 2015 (Macintosh) 2017-12-15T19:23:44-07:00 2017-12-15T19:52:15-07:00 2017-12-15T19:52:15-07:00 image/png 3 xmp.iid:6e3738de-4d57-463d-bb52-e823fb9c9001 adobe:docid:photoshop:87e7a78a-229a-117b-9d9c-ddc7040f2fad xmp.did:86d06f98-682e-4329-a687-291ca9679e82 created xmp.iid:86d06f98-682e-4329-a687-291ca9679e82 2017-12-15T19:23:44-07:00 Adobe Photoshop CC 2015 (Macintosh) saved xmp.iid:e21ee8dd-b7c4-491f-825c-2a635af5ce52 2017-12-15T19:38-07:00 Adobe Photoshop CC 2015 (Macintosh) / saved xmp.iid:6e3738de-4d57-463d-bb52-e823fb9c9001 2017-12-15T19:52:15-07:00 Adobe Photoshop CC 2015 (Macintosh) / 1 720000/10000 720000/10000 2 65535 68 64 zf cHRMz%u0`:o_F>IDATx?OPO` &jpbfr \50!\q!2@6M>xۜ_zOpqY$ " vwxfL3`LSY}b?>Pq10 X \yn8( 9rATr$̆8$ 4W}HhRY@=dg9DADADADA1" " " " Q@GI@jԺ m ]#ܯRbIENDB`photocrati_nextgen/modules/nextgen_addgallery_page/static/jquery.filetree/jquery.filetree.css000064400000013347150212224050027210 0ustar00UL.jqueryFileTree { font-family: Verdana, sans-serif; font-size: 11px; line-height: 18px; padding: 0px; margin: 0px; } UL.jqueryFileTree LI { list-style: none; padding: 0px; padding-left: 20px; margin: 0px; white-space: nowrap; } UL.jqueryFileTree A { color: #333; text-decoration: none; display: block; padding: 0px 2px; } UL.jqueryFileTree A:hover { background: #BDF; } UL.jqueryFileTree A.selected_folder { background-color: #EEEEEE; } /* Core Styles */ .jqueryFileTree LI.directory { background: url(images/directory.png) left top no-repeat; } .jqueryFileTree LI.expanded { background: url(images/folder_open.png) left top no-repeat; } .jqueryFileTree LI.file { background: url(images/file.png) left top no-repeat; } .jqueryFileTree LI.wait { background: url(images/spinner.gif) left top no-repeat; } /* File Extensions*/ .jqueryFileTree LI.ext_3gp { background: url(images/film.png) left top no-repeat; } .jqueryFileTree LI.ext_afp { background: url(images/code.png) left top no-repeat; } .jqueryFileTree LI.ext_afpa { background: url(images/code.png) left top no-repeat; } .jqueryFileTree LI.ext_asp { background: url(images/code.png) left top no-repeat; } .jqueryFileTree LI.ext_aspx { background: url(images/code.png) left top no-repeat; } .jqueryFileTree LI.ext_avi { background: url(images/film.png) left top no-repeat; } .jqueryFileTree LI.ext_bat { background: url(images/application.png) left top no-repeat; } .jqueryFileTree LI.ext_bmp { background: url(images/picture.png) left top no-repeat; } .jqueryFileTree LI.ext_c { background: url(images/code.png) left top no-repeat; } .jqueryFileTree LI.ext_cfm { background: url(images/code.png) left top no-repeat; } .jqueryFileTree LI.ext_cgi { background: url(images/code.png) left top no-repeat; } .jqueryFileTree LI.ext_com { background: url(images/application.png) left top no-repeat; } .jqueryFileTree LI.ext_cpp { background: url(images/code.png) left top no-repeat; } .jqueryFileTree LI.ext_css { background: url(images/css.png) left top no-repeat; } .jqueryFileTree LI.ext_doc { background: url(images/doc.png) left top no-repeat; } .jqueryFileTree LI.ext_exe { background: url(images/application.png) left top no-repeat; } .jqueryFileTree LI.ext_gif { background: url(images/picture.png) left top no-repeat; } .jqueryFileTree LI.ext_fla { background: url(images/flash.png) left top no-repeat; } .jqueryFileTree LI.ext_h { background: url(images/code.png) left top no-repeat; } .jqueryFileTree LI.ext_htm { background: url(images/html.png) left top no-repeat; } .jqueryFileTree LI.ext_html { background: url(images/html.png) left top no-repeat; } .jqueryFileTree LI.ext_jar { background: url(images/java.png) left top no-repeat; } .jqueryFileTree LI.ext_jpg { background: url(images/picture.png) left top no-repeat; } .jqueryFileTree LI.ext_jpeg { background: url(images/picture.png) left top no-repeat; } .jqueryFileTree LI.ext_js { background: url(images/script.png) left top no-repeat; } .jqueryFileTree LI.ext_lasso { background: url(images/code.png) left top no-repeat; } .jqueryFileTree LI.ext_log { background: url(images/txt.png) left top no-repeat; } .jqueryFileTree LI.ext_m4p { background: url(images/music.png) left top no-repeat; } .jqueryFileTree LI.ext_mov { background: url(images/film.png) left top no-repeat; } .jqueryFileTree LI.ext_mp3 { background: url(images/music.png) left top no-repeat; } .jqueryFileTree LI.ext_mp4 { background: url(images/film.png) left top no-repeat; } .jqueryFileTree LI.ext_mpg { background: url(images/film.png) left top no-repeat; } .jqueryFileTree LI.ext_mpeg { background: url(images/film.png) left top no-repeat; } .jqueryFileTree LI.ext_ogg { background: url(images/music.png) left top no-repeat; } .jqueryFileTree LI.ext_pcx { background: url(images/picture.png) left top no-repeat; } .jqueryFileTree LI.ext_pdf { background: url(images/pdf.png) left top no-repeat; } .jqueryFileTree LI.ext_php { background: url(images/php.png) left top no-repeat; } .jqueryFileTree LI.ext_png { background: url(images/picture.png) left top no-repeat; } .jqueryFileTree LI.ext_ppt { background: url(images/ppt.png) left top no-repeat; } .jqueryFileTree LI.ext_psd { background: url(images/psd.png) left top no-repeat; } .jqueryFileTree LI.ext_pl { background: url(images/script.png) left top no-repeat; } .jqueryFileTree LI.ext_py { background: url(images/script.png) left top no-repeat; } .jqueryFileTree LI.ext_rb { background: url(images/ruby.png) left top no-repeat; } .jqueryFileTree LI.ext_rbx { background: url(images/ruby.png) left top no-repeat; } .jqueryFileTree LI.ext_rhtml { background: url(images/ruby.png) left top no-repeat; } .jqueryFileTree LI.ext_rpm { background: url(images/linux.png) left top no-repeat; } .jqueryFileTree LI.ext_ruby { background: url(images/ruby.png) left top no-repeat; } .jqueryFileTree LI.ext_sql { background: url(images/db.png) left top no-repeat; } .jqueryFileTree LI.ext_swf { background: url(images/flash.png) left top no-repeat; } .jqueryFileTree LI.ext_tif { background: url(images/picture.png) left top no-repeat; } .jqueryFileTree LI.ext_tiff { background: url(images/picture.png) left top no-repeat; } .jqueryFileTree LI.ext_txt { background: url(images/txt.png) left top no-repeat; } .jqueryFileTree LI.ext_vb { background: url(images/code.png) left top no-repeat; } .jqueryFileTree LI.ext_wav { background: url(images/music.png) left top no-repeat; } .jqueryFileTree LI.ext_wmv { background: url(images/film.png) left top no-repeat; } .jqueryFileTree LI.ext_xls { background: url(images/xls.png) left top no-repeat; } .jqueryFileTree LI.ext_xml { background: url(images/code.png) left top no-repeat; } .jqueryFileTree LI.ext_zip { background: url(images/zip.png) left top no-repeat; }photocrati_nextgen/modules/nextgen_addgallery_page/static/jquery.filetree/jquery.filetree.min.js000064400000004055150212224050027612 0ustar00"use strict";function _typeof(e){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}jQuery&&!function(o){o.extend(o.fn,{fileTree:function(n,s){null==(n=n||{}).root&&(n.root="/"),null==n.script&&(n.script="jqueryFileTree.php"),null==n.folderEvent&&(n.folderEvent="click"),null==n.expandSpeed&&(n.expandSpeed=500),null==n.collapseSpeed&&(n.collapseSpeed=500),null==n.expandEasing&&(n.expandEasing=null),null==n.collapseEasing&&(n.collapseEasing=null),null==n.multiFolder&&(n.multiFolder=!0),null==n.loadMessage&&(n.loadMessage="Loading..."),null==n.post_params&&(n.post_params={}),o(this).each(function(){function a(t,l){o(t).addClass("wait"),o(".jqueryFileTree.start").remove();var e=o.extend(n.post_params,{dir:l});o.post(n.script,e,function(e){"object"!=_typeof(e)&&(e=JSON.parse(e)),data=e.html,o(t).find(".start").html(""),o(t).removeClass("wait").append(data),n.root==l?o(t).find("UL:hidden").show():o(t).find("UL:hidden").slideDown({duration:n.expandSpeed,easing:n.expandEasing}),o(e=t).find("LI A").on(n.folderEvent,function(){return o(this).parent().hasClass("directory")?(o(this).parent().hasClass("collapsed")?(n.multiFolder||(o(this).parent().parent().find("UL").slideUp({duration:n.collapseSpeed,easing:n.collapseEasing}),o(this).parent().parent().find("LI.directory").removeClass("expanded").addClass("collapsed")),o(this).parent().find("UL").remove(),a(o(this).parent(),escape(o(this).attr("rel").match(/.*\//))),o(this).parent().removeClass("collapsed").addClass("expanded")):(o(this).parent().find("UL").slideUp({duration:n.collapseSpeed,easing:n.collapseEasing}),o(this).parent().removeClass("expanded").addClass("collapsed")),s(o(this).attr("rel"),!0)):s(o(this).attr("rel"),!1),!1}),"click"!=n.folderEvent.toLowerCase&&o(e).find("LI A").on("click",function(){return!1})})}o(this).html('"),a(o(this),escape(n.root))})}})}(jQuery);photocrati_nextgen/modules/nextgen_addgallery_page/static/jquery.filetree/jquery.filetree.js000064400000010062150212224050027023 0ustar00// jQuery File Tree Plugin // // Version 1.01 // // Cory S.N. LaViska // A Beautiful Site (http://abeautifulsite.net/) // 24 March 2008 // // Visit http://abeautifulsite.net/notebook.php?article=58 for more information // // Usage: $('.fileTreeDemo').fileTree( options, callback ) // // Options: root - root folder to display; default = / // script - location of the serverside AJAX file to use; default = jqueryFileTree.php // folderEvent - event to trigger expand/collapse; default = click // expandSpeed - default = 500 (ms); use -1 for no animation // collapseSpeed - default = 500 (ms); use -1 for no animation // expandEasing - easing function to use on expand (optional) // collapseEasing - easing function to use on collapse (optional) // multiFolder - whether or not to limit the browser to one subfolder at a time // loadMessage - Message to display while initial tree loads (can be HTML) // // History: // // 1.01 - updated to work with foreign characters in directory/file names (12 April 2008) // 1.00 - released (24 March 2008) // // TERMS OF USE // // This plugin is dual-licensed under the GNU General Public License and the MIT License and // is copyright 2008 A Beautiful Site, LLC. // if(jQuery) (function($){ $.extend($.fn, { fileTree: function(o, h) { // Defaults if( !o ) var o = {}; if( o.root == undefined ) o.root = '/'; if( o.script == undefined ) o.script = 'jqueryFileTree.php'; if( o.folderEvent == undefined ) o.folderEvent = 'click'; if( o.expandSpeed == undefined ) o.expandSpeed= 500; if( o.collapseSpeed == undefined ) o.collapseSpeed= 500; if( o.expandEasing == undefined ) o.expandEasing = null; if( o.collapseEasing == undefined ) o.collapseEasing = null; if( o.multiFolder == undefined ) o.multiFolder = true; if( o.loadMessage == undefined ) o.loadMessage = 'Loading...'; if (o.post_params == undefined ) o.post_params = {}; $(this).each( function() { function showTree(c, t) { $(c).addClass('wait'); $(".jqueryFileTree.start").remove(); var post_params = $.extend(o.post_params, {dir: t}); $.post(o.script, post_params, function(response) { if (typeof(response) != 'object') response = JSON.parse(response); data = response.html; $(c).find('.start').html(''); $(c).removeClass('wait').append(data); if( o.root == t ) $(c).find('UL:hidden').show(); else $(c).find('UL:hidden').slideDown({ duration: o.expandSpeed, easing: o.expandEasing }); bindTree(c); }); } function bindTree(t) { $(t).find('LI A').on(o.folderEvent, function() { if( $(this).parent().hasClass('directory') ) { if( $(this).parent().hasClass('collapsed') ) { // Expand if( !o.multiFolder ) { $(this).parent().parent().find('UL').slideUp({ duration: o.collapseSpeed, easing: o.collapseEasing }); $(this).parent().parent().find('LI.directory').removeClass('expanded').addClass('collapsed'); } $(this).parent().find('UL').remove(); // cleanup showTree( $(this).parent(), escape($(this).attr('rel').match( /.*\// )) ); $(this).parent().removeClass('collapsed').addClass('expanded'); } else { // Collapse $(this).parent().find('UL').slideUp({ duration: o.collapseSpeed, easing: o.collapseEasing }); $(this).parent().removeClass('expanded').addClass('collapsed'); } h($(this).attr('rel'), true); } else { h($(this).attr('rel'), false); } return false; }); // Prevent A from triggering the # on non-click events if( o.folderEvent.toLowerCase != 'click' ) $(t).find('LI A').on('click', function() { return false; }); } // Loading message $(this).html(''); // Get the initial file list showTree( $(this), escape(o.root) ); }); } }); })(jQuery);photocrati_nextgen/modules/nextgen_addgallery_page/static/jquery.filetree/jquery.filetree.min.css000064400000012225150212224050027764 0ustar00UL.jqueryFileTree{font-family:Verdana,sans-serif;font-size:11px;line-height:18px;padding:0;margin:0}UL.jqueryFileTree LI{list-style:none;padding:0;padding-left:20px;margin:0;white-space:nowrap}UL.jqueryFileTree A{color:#333;text-decoration:none;display:block;padding:0 2px}UL.jqueryFileTree A:hover{background:#bdf}UL.jqueryFileTree A.selected_folder{background-color:#eee}.jqueryFileTree LI.directory{background:url(images/directory.png) left top no-repeat}.jqueryFileTree LI.expanded{background:url(images/folder_open.png) left top no-repeat}.jqueryFileTree LI.file{background:url(images/file.png) left top no-repeat}.jqueryFileTree LI.wait{background:url(images/spinner.gif) left top no-repeat}.jqueryFileTree LI.ext_3gp{background:url(images/film.png) left top no-repeat}.jqueryFileTree LI.ext_afp{background:url(images/code.png) left top no-repeat}.jqueryFileTree LI.ext_afpa{background:url(images/code.png) left top no-repeat}.jqueryFileTree LI.ext_asp{background:url(images/code.png) left top no-repeat}.jqueryFileTree LI.ext_aspx{background:url(images/code.png) left top no-repeat}.jqueryFileTree LI.ext_avi{background:url(images/film.png) left top no-repeat}.jqueryFileTree LI.ext_bat{background:url(images/application.png) left top no-repeat}.jqueryFileTree LI.ext_bmp{background:url(images/picture.png) left top no-repeat}.jqueryFileTree LI.ext_c{background:url(images/code.png) left top no-repeat}.jqueryFileTree LI.ext_cfm{background:url(images/code.png) left top no-repeat}.jqueryFileTree LI.ext_cgi{background:url(images/code.png) left top no-repeat}.jqueryFileTree LI.ext_com{background:url(images/application.png) left top no-repeat}.jqueryFileTree LI.ext_cpp{background:url(images/code.png) left top no-repeat}.jqueryFileTree LI.ext_css{background:url(images/css.png) left top no-repeat}.jqueryFileTree LI.ext_doc{background:url(images/doc.png) left top no-repeat}.jqueryFileTree LI.ext_exe{background:url(images/application.png) left top no-repeat}.jqueryFileTree LI.ext_gif{background:url(images/picture.png) left top no-repeat}.jqueryFileTree LI.ext_fla{background:url(images/flash.png) left top no-repeat}.jqueryFileTree LI.ext_h{background:url(images/code.png) left top no-repeat}.jqueryFileTree LI.ext_htm{background:url(images/html.png) left top no-repeat}.jqueryFileTree LI.ext_html{background:url(images/html.png) left top no-repeat}.jqueryFileTree LI.ext_jar{background:url(images/java.png) left top no-repeat}.jqueryFileTree LI.ext_jpg{background:url(images/picture.png) left top no-repeat}.jqueryFileTree LI.ext_jpeg{background:url(images/picture.png) left top no-repeat}.jqueryFileTree LI.ext_js{background:url(images/script.png) left top no-repeat}.jqueryFileTree LI.ext_lasso{background:url(images/code.png) left top no-repeat}.jqueryFileTree LI.ext_log{background:url(images/txt.png) left top no-repeat}.jqueryFileTree LI.ext_m4p{background:url(images/music.png) left top no-repeat}.jqueryFileTree LI.ext_mov{background:url(images/film.png) left top no-repeat}.jqueryFileTree LI.ext_mp3{background:url(images/music.png) left top no-repeat}.jqueryFileTree LI.ext_mp4{background:url(images/film.png) left top no-repeat}.jqueryFileTree LI.ext_mpg{background:url(images/film.png) left top no-repeat}.jqueryFileTree LI.ext_mpeg{background:url(images/film.png) left top no-repeat}.jqueryFileTree LI.ext_ogg{background:url(images/music.png) left top no-repeat}.jqueryFileTree LI.ext_pcx{background:url(images/picture.png) left top no-repeat}.jqueryFileTree LI.ext_pdf{background:url(images/pdf.png) left top no-repeat}.jqueryFileTree LI.ext_php{background:url(images/php.png) left top no-repeat}.jqueryFileTree LI.ext_png{background:url(images/picture.png) left top no-repeat}.jqueryFileTree LI.ext_ppt{background:url(images/ppt.png) left top no-repeat}.jqueryFileTree LI.ext_psd{background:url(images/psd.png) left top no-repeat}.jqueryFileTree LI.ext_pl{background:url(images/script.png) left top no-repeat}.jqueryFileTree LI.ext_py{background:url(images/script.png) left top no-repeat}.jqueryFileTree LI.ext_rb{background:url(images/ruby.png) left top no-repeat}.jqueryFileTree LI.ext_rbx{background:url(images/ruby.png) left top no-repeat}.jqueryFileTree LI.ext_rhtml{background:url(images/ruby.png) left top no-repeat}.jqueryFileTree LI.ext_rpm{background:url(images/linux.png) left top no-repeat}.jqueryFileTree LI.ext_ruby{background:url(images/ruby.png) left top no-repeat}.jqueryFileTree LI.ext_sql{background:url(images/db.png) left top no-repeat}.jqueryFileTree LI.ext_swf{background:url(images/flash.png) left top no-repeat}.jqueryFileTree LI.ext_tif{background:url(images/picture.png) left top no-repeat}.jqueryFileTree LI.ext_tiff{background:url(images/picture.png) left top no-repeat}.jqueryFileTree LI.ext_txt{background:url(images/txt.png) left top no-repeat}.jqueryFileTree LI.ext_vb{background:url(images/code.png) left top no-repeat}.jqueryFileTree LI.ext_wav{background:url(images/music.png) left top no-repeat}.jqueryFileTree LI.ext_wmv{background:url(images/film.png) left top no-repeat}.jqueryFileTree LI.ext_xls{background:url(images/xls.png) left top no-repeat}.jqueryFileTree LI.ext_xml{background:url(images/code.png) left top no-repeat}.jqueryFileTree LI.ext_zip{background:url(images/zip.png) left top no-repeat}photocrati_nextgen/modules/nextgen_addgallery_page/static/media-library-import.css000064400000001127150212224050025000 0ustar00#ngg-importML-selected-image-import.hidden { display: none; } #ngg-importML-select-opener.hidden { display: none; } #ngg-importML-gallery-selection { display: inline-block; } #ngg-importML-selected-image-import { vertical-align: middle; } #ngg-importML-select-opener { vertical-align: middle; } #ngg-importML-gallery-name { vertical-align: middle; } #ngg-importML-gallery-select { vertical-align: middle; } .ngg_settings_page .jqueryFileTree LI.directory { background-size: contain; } .ngg_settings_page .jqueryFileTree LI.expanded { background-size: 21px; }photocrati_nextgen/modules/nextgen_addgallery_page/static/media-library-import.js000064400000022135150212224050024626 0ustar00(function($) { var ngg_importml = { ml_data: null, import_ids: [], selectors: { ml_btn_import: $('#ngg-importML-selected-image-import'), ml_btn_select: $('#ngg-importML-select-opener'), gallery_select: $('#ngg-importML-gallery-id'), gallery_name: $('#ngg-importML-gallery-name') }, initialize: function() { this.methods.initialize(); this.methods.set_events(); }, methods: { initialize: function() { ngg_importml.ml_dialog = top.wp.media.frames.ngg_importml = top.wp.media({ multiple: true, title: ngg_importml_i18n.title, button: { text: ngg_importml_i18n.button_text } }); }, urlencode: function(str) { str = (str + '').toString(); return encodeURIComponent(str) .replace(/!/g, '%21') .replace(/'/g, '%27') .replace(/\(/g, '%28') .replace(/\)/g, '%29') .replace(/\*/g, '%2A') .replace(/%20/g, '+'); }, import: { import_count: 0, params: { action: 'import_media_library' }, start: function() { // prevent the impatient from causing simultaneous ongoing posts ngg_importml.selectors.ml_btn_import.attr('disabled', true); ngg_importml.selectors.ml_btn_select.attr('disabled', true); ngg_importml.methods.import.params.gallery_id = ngg_importml.methods.urlencode(ngg_importml.selectors.gallery_select.val()); ngg_importml.methods.import.params.gallery_name = ngg_importml.methods.urlencode(ngg_importml.selectors.gallery_name.val()); ngg_importml.progress_bar = $.nggProgressBar({ title: ngg_importml_i18n.progress_title, infinite: true, starting_value: ngg_importml_i18n.in_progress }); $(ngg_importml).trigger('send_ajax'); }, done: function() { ngg_importml.progress_bar.close(100); ngg_importml.selectors.ml_btn_import.attr('disabled', false); ngg_importml.selectors.ml_btn_select.attr('disabled', false); var msg = ngg_importml_i18n.imported_multiple; if (ngg_importml.methods.import.import_count == 1) { msg = ngg_importml_i18n.imported_singular; } msg = msg.replace('{gid}', ngg_importml.methods.import.params.gallery_id); msg = msg.replace('{count}', ngg_importml.methods.import.import_count); delete ngg_importml.methods.import.params.gallery_id; delete ngg_importml.methods.import.params.gallery_name; $.gritter.add({ title: ngg_importml_i18n.gritter_title, text: msg, sticky: true }); ngg_importml.methods.import.import_count = 0; // Empty the current selection & revert to the default state ngg_importml.ml_dialog.trigger('reset'); ngg_importml.import_ids = []; ngg_importml.selectors.ml_btn_import.fadeOut(); }, send_ajax: function() { var params = ngg_importml.methods.import.params; params.nonce = ngg_importml_i18n.nonce; params.attachment_ids = [ngg_importml.import_ids.pop()]; $.post(photocrati_ajax.url, params, function(data) { if (typeof data.error == 'undefined') { ngg_importml.methods.import.import_count++; // If we created a new gallery, ensure it's now in the drop-down list, and select it if (ngg_importml.selectors.gallery_select.find('option[value="' + data.gallery_id + '"]').length == 0) { ngg_importml.methods.import.params.gallery_id = data.gallery_id; var option = $('