4 Module: photocrati-attach_to_post,
5 Depends: { photocrati-nextgen_gallery_display }
9 define('NGG_ATTACH_TO_POST_SLUG', 'nextgen-attach_to_post');
11 class M_Attach_To_Post extends C_Base_Module
13 var $attach_to_post_tinymce_plugin = 'NextGEN_AttachToPost';
14 var $_event_publisher = NULL;
18 * @param string|bool $context
20 function define($context=FALSE)
23 'photocrati-attach_to_post',
25 'Provides the "Attach to Post" interface for displaying galleries and albums',
27 'http://www.nextgen-gallery.com',
29 'http://www.photocrati.com',
33 include_once('class.attach_to_post_option_handler.php');
34 C_NextGen_Settings::get_instance()->add_option_handler('C_Attach_To_Post_Option_Handler', array(
36 'gallery_preview_url',
37 'attach_to_post_display_tab_js_url'
39 if (is_multisite()) C_NextGen_Global_Settings::get_instance()->add_option_handler('C_Attach_To_Post_Option_Handler', array(
41 'gallery_preview_url',
42 'attach_to_post_display_tab_js_url'
45 include_once('class.attach_to_post_installer.php');
46 C_Photocrati_Installer::add_handler($this->module_id, 'C_Attach_To_Post_Installer');
48 // Set WP_ADMIN=true for better compatibility with certain themes & plugins.
49 // Unfortunately as of 3.9 in a multisite environment this causes problems.
50 if (self::is_atp_url() && (!defined('MULTISITE') || (defined('MULTISITE') && !MULTISITE)))
51 define('WP_ADMIN', true);
54 // We only register our display-type settings forms when IS_ADMIN, but Wordpress 3.9 introduced a problem
55 // with doing this on multisite sub-sites. Now we register our forms when is_atp_url() is true OR is_admin()
56 static function is_atp_url()
58 return (strpos(strtolower($_SERVER['REQUEST_URI']), '/nextgen-attach_to_post') !== false) ? TRUE : FALSE;
62 * Gets the Frame Event Publisher
65 function _get_frame_event_publisher()
67 if (is_null($this->_event_publisher)) {
68 $this->_event_publisher = $this->get_registry()->get_utility('I_Frame_Event_Publisher', 'attach_to_post');
71 return $this->_event_publisher;
76 * Registers requires the utilites that this module provides
78 function _register_utilities()
80 // This utility provides a controller that renders the
81 // Attach to Post interface, used to manage Displayed Galleries
82 $this->get_registry()->add_utility(
83 'I_Attach_To_Post_Controller',
85 // 'C_Attach_To_Post_Proxy_Controller'
90 * Registers the adapters that this module provides
92 function _register_adapters()
94 // Installs the Attach to Post module
95 $this->get_registry()->add_adapter(
96 'I_Installer', 'A_Attach_To_Post_Installer'
99 // Provides routing for the Attach To Post interface
100 $this->get_registry()->add_adapter(
101 'I_Router', 'A_Attach_To_Post_Routes'
104 // Provides AJAX actions for the Attach To Post interface
105 $this->get_registry()->add_adapter(
106 'I_Ajax_Controller', 'A_Attach_To_Post_Ajax'
109 // Applies a post hook to the generate_thumbnail method of the
110 // gallery storage component
111 $this->get_registry()->add_adapter(
112 'I_Gallery_Storage', 'A_Gallery_Storage_Frame_Event'
117 function _register_hooks()
121 'admin_enqueue_scripts',
122 array(&$this, 'enqueue_static_resources'),
127 // Add hook to delete displayed galleries when removed from a post
128 add_action('pre_post_update', array(&$this, 'locate_stale_displayed_galleries'));
129 add_action('before_delete_post', array(&$this, 'locate_stale_displayed_galleries'));
130 add_action('post_updated', array(&$this, 'cleanup_displayed_galleries'));
131 add_action('after_delete_post', array(&$this, 'cleanup_displayed_galleries'));
133 // Add hook to subsitute displayed gallery placeholders
134 add_filter('the_content', array(&$this, 'substitute_placeholder_imgs'), PHP_INT_MAX, 1);
136 // Emit frame communication events
137 add_action('ngg_created_new_gallery', array(&$this, 'new_gallery_event'));
138 add_action('ngg_after_new_images_added',array(&$this, 'images_added_event'));
139 add_action('ngg_page_event', array(&$this, 'nextgen_page_event'));
140 add_action('ngg_manage_tags', array(&$this, 'manage_tags_event'));
142 // We use two hooks here because we need it to execute for both the post-new.php
143 // page and ATP interface
144 add_action('plugins_loaded', array(&$this, 'fix_ie11'), 1);
145 add_action('admin_init', array(&$this, 'fix_ie11'), PHP_INT_MAX-1);
146 add_action('admin_enqueue_scripts', array(&$this, 'fix_ie11'), 1);
147 add_action('admin_enqueue_scripts', array(&$this, 'fix_ie11'), PHP_INT_MAX-1);
151 * WordPress sets the X-UA-Compatible header to IE=edge. Unfortunately, this causes problems with Plupload,
152 * so we have the send this header
156 if ((array_search('attach_to_post', array_keys($_REQUEST)) !== FALSE OR strpos($_SERVER['REQUEST_URI'], NGG_ATTACH_TO_POST_SLUG) !== FALSE OR strpos($_SERVER['REQUEST_URI'], 'wp-admin/post.php') !== FALSE OR strpos($_SERVER['REQUEST_URI'], 'wp-admin/post-new.php') !== FALSE)) {
157 if (!headers_sent()) {
158 header('X-UA-Compatible: IE=EmulateIE10');
164 * Substitutes the gallery placeholder content with the gallery type frontend
165 * view, returns a list of static resources that need to be loaded
166 * @param string $content
168 function substitute_placeholder_imgs($content)
170 // Get some utilities
171 $mapper = $this->get_registry()->get_utility('I_Displayed_Gallery_Mapper');
172 $router = $this->get_registry()->get_utility('I_Router');
174 // To match ATP entries we compare the stored url against a generic path
175 // We must check HTTP and HTTPS as well as permalink and non-permalink forms
176 $preview_url = parse_url($router->join_paths(
177 $router->remove_url_segment('index.php', $router->get_base_url('root')),
178 '/nextgen-attach_to_post/preview'
180 $router->debug = TRUE;
181 $preview_url = preg_quote($preview_url['host'] . $preview_url['path'], '#');
183 $alt_preview_url = parse_url($router->join_paths(
184 $router->remove_url_segment('index.php', $router->get_base_url('root')),
185 'index.php/nextgen-attach_to_post/preview'
187 $alt_preview_url = preg_quote($alt_preview_url['host'] . $alt_preview_url['path'], '#');
189 // The placeholder MUST have a gallery instance id
190 if (preg_match_all("#<img.*http(s)?://({$preview_url}|{$alt_preview_url})/id--(\\d+).*\\/>#mi", $content, $matches, PREG_SET_ORDER)) {
191 foreach ($matches as $match) {
192 // Find the displayed gallery
193 $displayed_gallery_id = $match[3];
194 $displayed_gallery = $mapper->find($displayed_gallery_id, TRUE);
196 // Get the content for the displayed gallery
197 $retval = '<p>'._('Invalid Displayed Gallery').'</p>';
198 if ($displayed_gallery) {
199 $renderer = $this->get_registry()->get_utility('I_Displayed_Gallery_Renderer');
200 $retval = $renderer->render($displayed_gallery, TRUE);
202 $content = str_replace($match[0], $retval, $content);
210 * Enqueues static resources required by the Attach to Post interface
212 function enqueue_static_resources()
214 $router = $this->get_registry()->get_utility('I_Router');
216 // Enqueue resources needed at post/page level
217 if (preg_match("/\/wp-admin\/(post|post-new)\.php$/", $_SERVER['SCRIPT_NAME'])) {
218 $this->_enqueue_tinymce_resources();
220 'ngg_attach_to_post_dialog', $router->get_static_url('photocrati-attach_to_post#attach_to_post_dialog.css')
224 elseif (isset($_REQUEST['attach_to_post']) OR
225 (isset($_REQUEST['page']) && strpos($_REQUEST['page'], 'nggallery') !== FALSE)) {
226 wp_enqueue_script('iframely', $router->get_static_url('photocrati-attach_to_post#iframely.js'));
227 wp_enqueue_style('iframely', $router->get_static_url('photocrati-attach_to_post#iframely.css'));
233 * Enqueues resources needed by the TinyMCE editor
235 function _enqueue_tinymce_resources()
239 'nextgen_gallery_attach_to_post_url',
240 C_NextGen_Settings::get_instance()->attach_to_post_url
243 // Registers our tinymce button and plugin for attaching galleries
244 $security = $this->get_registry()->get_utility('I_Security_Manager');
245 $sec_actor = $security->get_current_actor();
247 $sec_actor->is_allowed('NextGEN Attach Interface'),
248 $sec_actor->is_allowed('NextGEN Use TinyMCE')
250 if (!in_array(FALSE, $checks)) {
251 if (get_user_option('rich_editing') == 'true') {
252 add_filter('mce_buttons', array(&$this, 'add_attach_to_post_button'));
253 add_filter('mce_external_plugins', array(&$this, 'add_attach_to_post_tinymce_plugin'));
254 add_filter('wp_mce_translation', array($this, 'add_attach_to_post_tinymce_i18n'));
261 * Adds a TinyMCE button for the Attach To Post plugin
262 * @param array $buttons
265 function add_attach_to_post_button($buttons)
270 $this->attach_to_post_tinymce_plugin
277 * Adds the Attach To Post TinyMCE plugin
278 * @param array $plugins
280 * @uses mce_external_plugins filter
282 function add_attach_to_post_tinymce_plugin($plugins)
285 $router = $this->get_registry()->get_utility('I_Router');
287 if ($wp_version >= 3.9)
288 $file = $router->get_static_url('photocrati-attach_to_post#ngg_attach_to_post_tinymce_plugin.js');
290 $file = $router->get_static_url('photocrati-attach_to_post#ngg_attach_to_post_tinymce_plugin_wp38_compat.js');
292 $plugins[$this->attach_to_post_tinymce_plugin] = $file;
298 * Adds the Attach To Post TinyMCE i18n strings
299 * @param $mce_translation
302 function add_attach_to_post_tinymce_i18n($mce_translation)
304 $mce_translation['ngg_attach_to_post.title'] = __('Attach NextGEN Gallery to Post', 'nggallery');
305 return $mce_translation;
310 * Locates the ids of displayed galleries that have been
311 * removed from the post, and flags then for cleanup (deletion)
312 * @global array $displayed_galleries_to_cleanup
313 * @param int $post_id
315 function locate_stale_displayed_galleries($post_id)
317 global $displayed_galleries_to_cleanup;
318 $displayed_galleries_to_cleanup = array();
319 $post = get_post($post_id);
320 $gallery_preview_url = C_NextGen_Settings::get_instance()->get('gallery_preview_url');
321 $preview_url = preg_quote($gallery_preview_url, '#');
322 if (preg_match_all("#{$preview_url}/id--(\d+)#", html_entity_decode($post->post_content), $matches, PREG_SET_ORDER)) {
323 foreach ($matches as $match) {
324 $preview_url = preg_quote($match[0], '/');
325 // The post was edited, and the displayed gallery placeholder was removed
326 if (isset($_REQUEST['post_content']) && (!preg_match("/{$preview_url}/", $_POST['post_content']))) {
327 $displayed_galleries_to_cleanup[] = intval($match[1]);
329 // The post was deleted
330 elseif (!isset($_REQUEST['action'])) {
331 $displayed_galleries_to_cleanup[] = intval($match[1]);
338 * Deletes any displayed galleries that are no longer associated with
340 * @global array $displayed_galleries_to_cleanup
341 * @param int $post_id
343 function cleanup_displayed_galleries($post_id)
345 global $displayed_galleries_to_cleanup;
346 $mapper = $this->get_registry()->get_utility('I_Displayed_Gallery_Mapper');
347 foreach ($displayed_galleries_to_cleanup as $id) $mapper->destroy($id);
352 * Notify frames that a new gallery has been created
353 * @param int $gallery_id
355 function new_gallery_event($gallery_id)
357 $gallery = $this->get_registry()->get_utility('I_Gallery_Mapper')->find($gallery_id);
359 $this->_get_frame_event_publisher()->add_event(array(
360 'event' => 'new_gallery',
361 'gallery_id'=> intval($gallery_id),
362 'gallery_title' => $gallery->title
368 * Notifies a frame that images have been added to a gallery
369 * @param int $gallery_id
370 * @param array $image_ids
372 function images_added_event($gallery_id, $image_ids=array())
374 $this->_get_frame_event_publisher()->add_event(array(
375 'event' => 'images_added',
376 'gallery_id' => intval($gallery_id)
381 * Notifies a frame that the tags have changed
385 function manage_tags_event($tags = array())
387 $this->_get_frame_event_publisher()->add_event(array(
388 'event' => 'manage_tags',
394 * Notifies a frame that an action has been performed on a particular
396 * @param array $event
398 function nextgen_page_event($event)
400 $this->_get_frame_event_publisher()->add_event($event);
403 function get_type_list()
406 'A_Attach_To_Post_Ajax' => 'adapter.attach_to_post_ajax.php',
407 'C_Attach_To_Post_Installer' => 'class.attach_to_post_installer.php',
408 'A_Attach_To_Post_Routes' => 'adapter.attach_to_post_routes.php',
409 'A_Gallery_Storage_Frame_Event' => 'adapter.gallery_storage_frame_event.php',
410 'C_Attach_Controller' => 'class.attach_controller.php',
411 'C_Attach_To_Post_Proxy_Controller' => 'class.attach_to_post_proxy_controller.php',
412 'I_Attach_To_Post_Controller' => 'interface.attach_to_post_controller.php',
413 'Mixin_Attach_To_Post_Display_Tab' => 'mixin.attach_to_post_display_tab.php'
418 new M_Attach_To_Post();