How Can We Help?

Search for answers or browse our knowledge base.

< All Topics
Print

How-to: Build a Display Type for NextGEN Gallery

This tutorial is currently outdated and is in the process of being updated

-

This tutorial will demonstrate how to create display types for NextGEN Gallery 2.0. As an example, we'll port the JJ NextGEN JQuery slider (developed by JJ Coder) from the 1.9.x codebase to 2.0. I've committed each step to a repository on Bitbucket.

Introduction

NextGEN Gallery 2.0 is the start of something new. It's the product of Photocrati's vision for creating the most popular gallery management solution for photographers; built on top of the Pope Framework to provide an extensible base for years to come.

NextGEN Gallery 2.0 is modular, composed of over 30 modules to deliver it's rich feature-set. We're very proud of this milestone and what we've accomplished, but it's only the beginning - we have much more work to do and lots in store for this codebase.

This introduction is to acquaint developers that would like to develop NextGEN Gallery extensions, with the constructs and modules that are currently available in NextGEN Gallery 2.0. We encourage you to review our source code at Bitbucket for a more in-depth look. We also recommend that you read our Introduction to Pope article to ensure that you get the most from the content below.

The Architecture

NextGEN Gallery 2.0 Architecture

The above diagram is an attempt to summarize the architecture of the plugin, as well provide an indication of what modules are used. Each grouping of modules depends on the grouping/level below it. This is vastly difference architecture than the 1.9.x codebase of NextGEN Gallery had before, which was developed primarily by Alex Rabe. That original codebase has been encapsulated as a module, called "ngglegacy", within the 2.0 paradigm, and mainly provides the central gallery management interface. Overtime, this module will be segmented into smaller modules, to keep the codebase lean, easy to maintain, and extensible.

Initialization

The plugin initializes by performing the following steps:

  1. Include Pope Autoloader (pope/lib/autoload.php)
  2. Register the component factory utility, used to hatch (or produce) components
  3. Load the "photocrati-nextgen" product, which in turn, load's all of the modules defined for that product. When we say load in this context, we're referring to how each module should a) register it's adapters; b) register it's utilities; c) add hooks to the WordPress framework
  4. Initialize the state of the modules
  5. Set the plugin's document root for the I_Fs utility
  6. Hook into the WordPress init action, and start the Pope Router

Front-end Requests

NextGEN Gallery 2.0 implements the MVC pattern, provided by the MVC module. When an HTTP request is sent to the front-end of the WordPress site, the Pope router intercepts to examine if it should process the request or pass the request through to the underlying framework. This can be found in nggallery.php's route() method:

function route()
	{
		$router = $this->_registry->get_utility('I_Router');
		if (!$router->serve_request() && $router->has_parameter_segments()) {
			return $router->passthru();
		}
	}

The router is configured by modules to route specific requests to a particular controller and action. Here's an example provided by the AJAX module, used to route AJAX requests:

function add_ajax_routes()
	{
		$app	= $this->object->create_app('/photocrati_ajax');
		$app->route('/js',	'I_Ajax_Controller#js');
		$app->route('/',	'I_Ajax_Controller#index');
	}

Controllers are subclasses of the C_MVC_Controller component, provided by the MVC module. Controllers can have one or more actions (methods that are invokable by the router). Action methods must have the postfix, _action, for security reasons:

function index_action()
	{
		$retval = FALSE;

		// Inform the MVC framework what type of content we're returning
		$this->set_content_type('json');

		// 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);
			}
		}

		// If no retval has been set, then return an error
		if (!$retval)
			$retval = array('error' => 'Not a valid AJAX action');

		// Return the JSON to the browser
		echo json_encode($retval);
	}

The above code provides the index_action by the C_Ajax_Controller component, used to serve an AJAX request.

Display Types

A display type is a type of module which provides the logic for rendering a gallery or album on a post or page. NextGEN Gallery ships with many display types, out-of-the-box, such as NextGEN Basic ImageBrowser and NextGEN Basic Compact Album. A display type module is made up of the following:

  • An installer, which installs the display type in the database
  • A form, which provides the display settings in the Attach to Post interface and Display Settings page in WP-Admin
  • A controller, used to render the front-end HTTP request to a page/post that has an embedded displayed gallery object
  • A modal, used to provide validation of the display settings for the display type
  • A datamapper, used to set default values for the display type
  • Routes, which configure the router to parse parameters provided in the URI
  • A module file, which ties all of the above together

Porting JJ NextGEN JQuery Slider

Please download JJ NextGEN JQuery Slider and we'll modify the source code to achieve the above. Specifically, we'll do the following steps:

  • Create a Pope product, to represent JJ NextGEN JQuery Slider
  • Create a Pope module, to represent Nivo Slider
  • Adjust the plugin header to load our product
  • Re-arrange the static assets
  • Register Nivo Slider as a display type
  • Add settings form
  • Add front-end controller
Create a Pope Product

Any third-party plugin wanting to extend NextGEN Gallery 2.0 must provide a Pope product definition file. This is used to distinguish what modules your product provides versus another. Create a file called product.jj_nextgen_jquery_slider.php:

<?php
/*
{
    Product: jj-nextgen_jquery_slider
}
*/
class P_JJ_NextGen_JQuery_Slider extends C_Base_Product
{
    function define()
    {
        parent::define(
            'jj-nextgen_jquery_slider',
            'JJ NextGEN JQuery Slider',
            'Provides the JJ NextGEN JQuery Slider display type',
            '0.1'
        );

        $this->get_registry()->set_product_module_path($this->module_id, __DIR__);
        $this->get_registry()->load_module('jj-nivo_slider');
    }
}

new P_JJ_NextGen_JQuery_Slider;

The block comment is what we call the <em, which provides some necessary metadata to Pope. The rest of the code is used mainly to tell Pope where to find this product's modules.

Create a Pope module

The JJ NextGEN JQuery slider plugin uses Nivo Slider to provide it's functionality. We'll therefore expose Nivo Slider as Pope module to the rest of the framework. Create a file called module.nivo_slider.php:

<?php
/*
{
    Module: jj-nivo_slider
}
*/

define('JJ_NIVO_SLIDER', 'jj-nivo_slider');

class M_JJ_Nivo_Slider extends C_Base_Module
{
    function define()
    {
        parent::define(
            JJ_NIVO_SLIDER,
            'Nivo Slider',
            'Nivo Slider for NextGEN Gallery 2.0',
            '0.1',
            'http://wordpress.org/extend/plugins/jj-nextgen-jquery-slider/',
            'Michael Weichert',
            'http://mweichert.com'
        );
    }

    function _register_hooks()
    {
        add_shortcode('jj-ngg-jquery-slider', array(&$this, 'render_shortcode'));
        add_shortcode('jj-nivo-slider',       array(&$this, 'render_shortcode'));
        add_shortcode('nivo-slider',          array(&$this, 'render_shortcode'));
        add_action('wp_enqueue_scripts',      array(&$this, 'register_static_resources'));
    }

    function render_shortcode($attrs=array())
    {
		return "<div><strong>NIVO SLIDER</strong></div>";
    }

    function register_static_resources()
    {

    }
}

new M_JJ_Nivo_Slider();

The above module definition file is more or less a placeholder at this time that we'll be extending throughout this tutorial to provide the Nivo Slider implementation. As you can see, for now, we've added a shortcode for jj-ngg-jquery-slider which will simply output NIVO SLIDER when rendered.

Load our product

Now that we have the necessary pieces for loading our Pope application, we'll modify the plugin header file, jj-ngg-jquery-slider.php:

<?php
/*
Plugin Name: JJ NextGen JQuery Slider
Description: Allows you to pick a gallery from the 'NextGen Gallery' plugin to use as a 'JQuery Nivo Slider'.
Author: JJ Coder (ported by Michael Weichert)
Version: 1.3.9
*/

class JJ_NextGen_JQuery_Slider
{
    /**
     * Initializes the plugin
     */
    function __construct()
    {
        add_action('load_nextgen_gallery_modules', array(&$this, 'load_product'));

        if (is_admin()) {
            add_filter('plugin_row_meta', array(&$this, 'add_plugin_links'), 10, 2);
        }

    }

    /**
     * Loads the Pope jj_nextgen_jquery_slider providing the JJ NextGEN JQuery slider
     * @param C_Component_Registry $registry
     */
    function load_product(C_Component_Registry $registry)
    {
        // Tell the registry where it can find our products/modules
        $registry->add_module_path(__DIR__, TRUE, TRUE);
    }

    /**
     * Add some links to the plugin page that relate to this plugin
     * @param array $links
     * @param string $file
     * @return array
     */
    function add_plugin_links($links, $file)
    {
        if (strpos($file, basename(__FILE__)) !== FALSE) {
            $links[] = '<a href="http://wordpress.org/extend/plugins/jj-nextgen-jquery-slider/">' . 'Visit plugin site' . '</a>';
            $links[] = '<a href="http://www.redcross.org.nz/donate">' . 'Donate to Christchurch Quake' . '</a>';
        }

        return $links;
    }
}

new JJ_NextGen_JQuery_Slider();

We can now delete the includes folder as it will no longer be required from here on. Unfortunately, NextGEN Gallery 2.0 doesn't expose the Attach to Post interface as a widget yet, and therefore we won't be providing a widget for this longer, as the original did. Users can instead use the shortcode, jj-ngg-jquery-slider.

JJ NextGEN JQuery Slider is now a working Pope application, although it doesn't do much yet. If you activate the plugin and put the shortcode, jj-ngg-jquery-slider in the body of a post or page, save it, and view the page on the front-end, you should see NIVO SLIDER in-place of the shortcode.

Re-arrange static assets

The MVC module for Pope, by default, expects all static assets to live in a directory called static. Let's create that now and move the images, scripts, and stylesheets directories.

Your directory tree should now look like the following:

  • jj-nextgen-jquery-slider
    • static
      • images
      • script
      • stylesheets
    • jj-ngg-jquery-slider.php
    • module.nivo_slider.php
    • product.jj_nextgen_jquery_slider.php
    • readme.txt
    • screenshot-1.png
    • screenshot-2.png
    • screenshot-3.png

We'll then register the stylesheet and script for Nivo Slider with WordPress:

<?php
/*
{
    Module: jj-nivo_slider
}
*/

define('JJ_NIVO_SLIDER', 'jj-nivo_slider');

class M_JJ_Nivo_Slider extends C_Base_Module
{
    function define()
    {
        parent::define(
            JJ_NIVO_SLIDER,
            'Nivo Slider',
            'Nivo Slider for NextGEN Gallery 2.0',
            '0.1',
            'http://wordpress.org/extend/plugins/jj-nextgen-jquery-slider/',
            'Michael Weichert',
            'http://mweichert.com'
        );
    }

    function _register_hooks()
    {
        add_shortcode('jj-ngg-jquery-slider', array(&$this, 'render_shortcode'));
        add_shortcode('jj-nivo-slider',       array(&$this, 'render_shortcode'));
        add_shortcode('nivo-slider',          array(&$this, 'render_shortcode'));
        add_action('wp_enqueue_scripts',      array(&$this, 'register_static_resources'));
    }

    function render_shortcode($attrs=array())
    {
        return "<div><strong>NIVO SLIDER</strong></div>";
    }

    function register_static_resources()
    {
        $router = $this->get_registry()->get_utility('I_Router');
        $css    = $router->get_static_url('jj-nivo-slider#stylesheets/nivo-slider.css');
        $js     = $router->get_static_url('jj-nivo-slider#script/jquery.nivo.slider.pack.js');
        wp_register_style('nivo-slider', $css);
        wp_register_script('nivo-slider', $js, array('jquery'));
    }
}

new M_JJ_Nivo_Slider();

Finally, while we're at it, we'll update nivo-slider by using the latest script and stylesheet from GitHub. The Github repository contains several themes for Nivo Slider as well that we'll download and store in the static/stylesheets directory. We'll then register these themes with WordPress as available stylesheets:

<?php
/*
{
    Module: jj-nivo_slider
}
*/

define('JJ_NIVO_SLIDER', 'jj-nivo_slider');

class M_JJ_Nivo_Slider extends C_Base_Module
{
    function define()
    {
        parent::define(
            JJ_NIVO_SLIDER,
            'Nivo Slider',
            'Nivo Slider for NextGEN Gallery 2.0',
            '0.1',
            'http://wordpress.org/extend/plugins/jj-nextgen-jquery-slider/',
            'Michael Weichert',
            'http://mweichert.com'
        );
    }

    function _register_hooks()
    {
        add_shortcode('jj-ngg-jquery-slider', array(&$this, 'render_shortcode'));
        add_shortcode('jj-nivo-slider',       array(&$this, 'render_shortcode'));
        add_shortcode('nivo-slider',          array(&$this, 'render_shortcode'));
        add_action('wp_enqueue_scripts',      array(&$this, 'register_static_resources'));
    }

    function render_shortcode($attrs=array())
    {
        return "<div><strong>NIVO SLIDER</strong></div>";
    }

    function register_static_resources()
    {
        $router = $this->get_registry()->get_utility('I_Router');
        $css    = $router->get_static_url('jj-nivo-slider#stylesheets/nivo-slider.css');
        $js     = $router->get_static_url('jj-nivo-slider#script/jquery.nivo.slider.pack.js');
        wp_register_style('nivo-slider', $css);
        wp_register_script('nivo-slider', $js, array('jquery'));

        // Register themes
        foreach (array('bar', 'dark', 'default', 'light') as $theme) {
            $css = $router->get_static_url("jj-nivo-slider#stylesheets/{$theme}/{$theme}.css");
            wp_register_style('nivo-slider-'.$theme, $css);
        }
    }
}

new M_JJ_Nivo_Slider();
Register Nivo Slider as a Display Type

NextGEN Gallery 2.0 introduces the concept of a Display Type (see above). Display Types are automatically added to the Attach to Post and Display Settings pages, and therefore are the recommended mechanism used to render the presentation of a displayed gallery. We can register a new display type by adding an adapter for the I_Installer interface. Create a file called adapter.nivo_slider_installer.php:

<?php

class A_Nivo_Slider_Installer extends Mixin
{
    function initialize()
    {
        $this->object->add_post_hook(
            'install',
            'Nivo Slider Installer',
            get_class(),
            'install_nivo_slider'
        );
    }

    function install_nivo_slider()
    {
        $this->object->install_display_type(
            JJ_NIVO_SLIDER, array(
            'title'                 =>  'Nivo Slider',
            'entity_types'          =>  array('image'),
            'preview_image_relpath' =>  'jj-nivo_slider#preview.jpg',
            'default_source'        =>  'galleries'
        ));
    }
}

The key to installing a new display type is to call the install_display_type method provided by the A_Gallery_Display_Installer adapter for the I_Installer interface, which accepts the following parameters:

  • the name of the display type
  • An associative array with the following key value pairs
      • title, the human-friendly name of the display type
      • entity_types, the type of entities this display type can be used to display. Valid entities are image, gallery, and album.
      • preview_image_relpath, the path to the preview image used in the Attach to Post interface. This image should be 110x80 pixels. For our example, we'll just copy the image from the NextGEN Basic Slideshow module.
      • default_source, the default source for finding entities. Valid values are galleries and albums

    We now need to inform Pope that we have an adapter for the I_Installer interface:

    <?php
    /*
    {
        Module: jj-nivo_slider
    }
    */
    
    define('JJ_NIVO_SLIDER', 'jj-nivo_slider');
    
    class M_JJ_Nivo_Slider extends C_Base_Module
    {
        function define()
        {
            parent::define(
                JJ_NIVO_SLIDER,
                'Nivo Slider',
                'Nivo Slider for NextGEN Gallery 2.0',
                '0.1',
                'http://wordpress.org/extend/plugins/jj-nextgen-jquery-slider/',
                'Michael Weichert',
                'http://mweichert.com'
            );
        }
    
        function _register_hooks()
        {
            add_shortcode('jj-ngg-jquery-slider', array(&$this, 'render_shortcode'));
            add_shortcode('jj-nivo-slider',       array(&$this, 'render_shortcode'));
            add_shortcode('nivo-slider',          array(&$this, 'render_shortcode'));
            add_action('wp_enqueue_scripts',      array(&$this, 'register_static_resources'));
        }
    
        function _register_adapters()
        {
            $this->get_registry()->add_adapter('I_Installer', 'A_Nivo_Slider_Installer');
        }
    
        function render_shortcode($attrs=array())
        {
            return "<div><strong>NIVO SLIDER</strong></div>";
        }
    
        function register_static_resources()
        {
            $router = $this->get_registry()->get_utility('I_Router');
            $css    = $router->get_static_url('jj-nivo-slider#stylesheets/nivo-slider.css');
            $js     = $router->get_static_url('jj-nivo-slider#script/jquery.nivo.slider.pack.js');
            wp_register_style('nivo-slider', $css);
            wp_register_script('nivo-slider', $js, array('jquery'));
    
            // Register themes
            foreach (array('bar', 'dark', 'default', 'light') as $theme) {
                $css = $router->get_static_url("jj-nivo-slider#stylesheets/{$theme}/{$theme}.css");
                wp_register_style('nivo-slider-'.$theme, $css);
            }
        }
    }
    
    new M_JJ_Nivo_Slider();

    If you deactivate NextGEN Gallery, and then reactivate, Nivo Slider should appear in both the Attach to Post and Display Settings pages. The display type is now installed as a custom post type in your database.

    NOTE:The installer module implementation is still in development, and most likely to change before the final release.

    Add settings form

    A display type usually have user-configurable settings that can either can be specified in the Attach to Post interface, or as parameters for a shortcode. We'll be adding some default setting values and a form used to customize and override those values.

    NextGEN Gallery introduces a module called datamapper, which provides a utility implementing the datamapper pattern used to interact with entities stored in the database. There is a utility that implements the I_Display_Type_Mapper interface that is used to retrieve display type entities. This is also the utility used to set default values for entities.

    We'll create an adapter for this utility to set the default values for our display type. Create a file called adapter.nivo_slider_mapper.php:

    <?php
    
    class A_Nivo_Slider_Mapper extends Mixin
    {
        function initialize()
        {
            $this->object->add_post_hook(
                'set_defaults',
                'Nivo Slider Defaults',
                'Hook_Nivo_Slider_Defaults'
            );
        }
    }
    
    class Hook_Nivo_Slider_Defaults extends Hook
    {
        function set_defaults($entity)
        {
            if ($entity->name == JJ_NIVO_SLIDER) {
                $this->object->_set_default_value($entity, 'settings', 'max_width',     0);
                $this->object->_set_default_value($entity, 'settings', 'aspect_ratio',  0);
                $this->object->_set_default_value($entity, 'settings', 'center',        FALSE);
                $this->object->_set_default_value($entity, 'settings', 'theme',         'default');
    
                // Looked up default values from http://github.com/gilbitron/Nivo-Slider/blob/master/jquery.nivo.slider.js
                $this->object->_set_default_value($entity, 'settings', 'customize_nivo_slider', FALSE);
                $this->object->_set_default_value($entity, 'settings', 'effect',        'random');
                $this->object->_set_default_value($entity, 'settings', 'slices',        15);
                $this->object->_set_default_value($entity, 'settings', 'boxCols',       8);
                $this->object->_set_default_value($entity, 'settings', 'boxRows',       4);
                $this->object->_set_default_value($entity, 'settings', 'animSpeed',     500);
                $this->object->_set_default_value($entity, 'settings', 'pauseTime',     3000);
                $this->object->_set_default_value($entity, 'settings', 'startSlide',    0);
                $this->object->_set_default_value($entity, 'settings', 'directionNav',  TRUE);
                $this->object->_set_default_value($entity, 'settings', 'controlNav',    TRUE);
                $this->object->_set_default_value($entity, 'settings', 'controlNavThumbs', FALSE);
                $this->object->_set_default_value($entity, 'settings', 'pauseOnHover',  TRUE);
                $this->object->_set_default_value($entity, 'settings', 'manualAdvance', FALSE);
                $this->object->_set_default_value($entity, 'settings', 'autostart',     TRUE);
                $this->object->_set_default_value($entity, 'settings', 'prevText',      'Prev');
                $this->object->_set_default_value($entity, 'settings', 'nextText',      'Next');
                $this->object->_set_default_value($entity, 'settings', 'randomStart',   FALSE);
            }
        }
    }

    We'll then need to register the adapter in our module definition file:

    <?php
    /*
    {
        Module: jj-nivo_slider
    }
    */
    
    define('JJ_NIVO_SLIDER', 'jj-nivo_slider');
    
    class M_JJ_Nivo_Slider extends C_Base_Module
    {
        function define()
        {
            parent::define(
                JJ_NIVO_SLIDER,
                'Nivo Slider',
                'Nivo Slider for NextGEN Gallery 2.0',
                '0.1',
                'http://wordpress.org/extend/plugins/jj-nextgen-jquery-slider/',
                'Michael Weichert',
                'http://mweichert.com'
            );
        }
    
        function _register_hooks()
        {
            add_shortcode('jj-ngg-jquery-slider', array(&$this, 'render_shortcode'));
            add_shortcode('jj-nivo-slider',       array(&$this, 'render_shortcode'));
            add_shortcode('nivo-slider',          array(&$this, 'render_shortcode'));
            add_action('wp_enqueue_scripts',      array(&$this, 'register_static_resources'));
        }
    
        function _register_adapters()
        {
            $this->get_registry()->add_adapter('I_Installer', 'A_Nivo_Slider_Installer');
            $this->get_registry()->add_adapter('I_Display_Type_Mapper', 'A_Nivo_Slider_Mapper');
        }
    
        function render_shortcode($attrs=array())
        {
            return "<div><strong>NIVO SLIDER</strong></div>";
        }
    
        function register_static_resources()
        {
            $router = $this->get_registry()->get_utility('I_Router');
            $css    = $router->get_static_url('jj-nivo-slider#stylesheets/nivo-slider.css');
            $js     = $router->get_static_url('jj-nivo-slider#script/jquery.nivo.slider.pack.js');
            wp_register_style('nivo-slider', $css);
            wp_register_script('nivo-slider', $js, array('jquery'));
    
            // Register themes
            foreach (array('bar', 'dark', 'default', 'light') as $theme) {
                $css = $router->get_static_url("jj-nivo-slider#stylesheets/{$theme}/{$theme}.css");
                wp_register_style('nivo-slider-'.$theme, $css);
            }
        }
    }
    
    new M_JJ_Nivo_Slider();

    Forms implement the I_Form interface, and are registered with the I_Form_Manager manager. The I_Form_Manager is responsible for knowing what forms are to be rendered on what pages. We'll register a new form for the Display Settings page:

    <?php
    /*
    {
        Module: jj-nivo_slider
    }
    */
    
    define('JJ_NIVO_SLIDER', 'jj-nivo_slider');
    
    class M_JJ_Nivo_Slider extends C_Base_Module
    {
        function define()
        {
            parent::define(
                JJ_NIVO_SLIDER,
                'Nivo Slider',
                'Nivo Slider for NextGEN Gallery 2.0',
                '0.1',
                'http://wordpress.org/extend/plugins/jj-nextgen-jquery-slider/',
                'Michael Weichert',
                'http://mweichert.com'
            );
        }
    
        function initialize()
        {
            parent::initialize();
            $form_manager = $this->get_registry()->get_utility('I_Form_Manager');
            $form_manager->add_form(NEXTGEN_DISPLAY_SETTINGS_SLUG, JJ_NIVO_SLIDER);
        }
    
        function _register_hooks()
        {
            add_shortcode('jj-ngg-jquery-slider', array(&$this, 'render_shortcode'));
            add_shortcode('jj-nivo-slider',       array(&$this, 'render_shortcode'));
            add_shortcode('nivo-slider',          array(&$this, 'render_shortcode'));
            add_action('wp_enqueue_scripts',      array(&$this, 'register_static_resources'));
        }
    
        function _register_adapters()
        {
            $this->get_registry()->add_adapter('I_Installer', 'A_Nivo_Slider_Installer');
            $this->get_registry()->add_adapter('I_Display_Type_Mapper', 'A_Nivo_Slider_Mapper');
        }
    
        function render_shortcode($attrs=array())
        {
            return "<div><strong>NIVO SLIDER</strong></div>";
        }
    
        function register_static_resources()
        {
            $router = $this->get_registry()->get_utility('I_Router');
            $css    = $router->get_static_url('jj-nivo-slider#stylesheets/nivo-slider.css');
            $js     = $router->get_static_url('jj-nivo-slider#script/jquery.nivo.slider.pack.js');
            wp_register_style('nivo-slider', $css);
            wp_register_script('nivo-slider', $js, array('jquery'));
    
            // Register themes
            foreach (array('bar', 'dark', 'default', 'light') as $theme) {
                $css = $router->get_static_url("jj-nivo-slider#stylesheets/{$theme}/{$theme}.css");
                wp_register_style('nivo-slider-'.$theme, $css);
            }
        }
    }
    
    new M_JJ_Nivo_Slider();

    The above addition to our module file will cause a new I_Form instance to be instantiated with jj-nivo_slider as the context when the Display Settings page is being viewed. We'll now create an adapter for the form that we'll later register for that context. Create a file called adapter.nivo_slider_form.php:

    <?php
    
    class A_Nivo_Slider_Form extends Mixin_Display_Type_Form
    {
        function get_display_type_name()
        {
            return JJ_NIVO_SLIDER;
        }
    
        function enqueue_static_resources()
        {
            wp_enqueue_script(
                'nivo_slider_settings',
                $this->object->get_static_url('jj-nivo_slider#nivo_slider_settings.js'),
                array('jquery')
            );
        }
    
        function _get_field_names()
        {
            return array(
                'nivo_slider_max_width',
                'nivo_slider_aspect_ratio',
                'nivo_slider_center',
                'nivo_slider_theme',
                'nivo_slider_autostart_slideshow',
                'nivo_slider_direction_nav',
                'nivo_slider_prev_text',
                'nivo_slider_next_text',
                'nivo_slider_control_nav',
                'nivo_slider_control_nav_thumbs',
                'nivo_slider_random_start',
                'nivo_slider_starting_slide',
                'nivo_slider_effect',
                'nivo_slider_override_settings',
                'nivo_slider_slices',
                'nivo_slider_box_columns',
                'nivo_slider_box_rows',
                'nivo_slider_animation_speed',
                'nivo_slider_pause_speed',
                'nivo_slider_pause_on_hover'
            );
        }
    
        function _render_nivo_slider_max_width_field($display_type)
        {
            return $this->object->_render_number_field(
                $display_type,
                'max_width',
                'Max width',
                $display_type->settings['max_width'],
                "Enter 0 to fill the size of the container",
                FALSE,
                0,
                0
            );
        }
    
        function _render_nivo_slider_aspect_ratio_field($display_type)
        {
            return $this->object->_render_select_field(
                $display_type,
                'aspect_ratio',
                'Aspect ratio',
                $this->object->_get_aspect_ratio_options(),
                $display_type->settings['aspect_ratio']
            );
        }
    
        function _render_nivo_slider_center_field($display_type)
        {
            return $this->object->_render_radio_field(
                $display_type,
                'center',
                'Center?',
                $display_type->settings['center']
            );
        }
    
        function _render_nivo_slider_theme_field($display_type)
        {
            return $this->object->_render_select_field(
                $display_type,
                'theme',
                'Skin',
                array(
                    'default'   => 'Default',
                    'bar'       => 'Bar',
                    'dark'      => 'Dark',
                    'light'     => 'Light'
                ),
                $display_type->settings['theme']
            );
        }
    
        function _render_nivo_slider_override_settings_field($display_type)
        {
            return $this->object->_render_radio_field(
                $display_type,
                'customize_nivo_slider',
                'Customize effects?',
                $display_type->settings['customize_nivo_slider']
    
            );
        }
    
        function _render_nivo_slider_effect_field($display_type)
        {
            return $this->object->_render_select_field(
                $display_type,
                'effect',
                'Transition effect',
                array(
                    'random'            =>  'Random',
                    'fade'              =>  'Fade',
                    'fold'              =>  'Fold',
                    'boxRandom'         =>  'Random boxes',
                    'sliceDown'         =>  'Slice down',
                    'sliceDown'         =>  'Slice down & left',
                    'sliceUp'           =>  'Slice up',
                    'sliceUpLeft'       =>  'Slice up & left',
                    'sliceUpDown'       =>  'Slice up & down',
                    'sliceUpDownLeft'   =>  'Slice up & down & left',
                    'slideInRight'      =>  'Slide from right',
                    'slideInLeft'       =>  'Slide from left',
                    'boxRain'           =>  'Rain',
                    'boxRainReverse'    =>  'Reverse Rain',
                    'boxRainGrow'       =>  'Rain Grow',
                    'boxRainGrowReverse'=>  'Reverse Rain Grow'
                ),
                $display_type->settings['effect']
            );
        }
    
        function _render_nivo_slider_slices_field($display_type)
        {
            return $this->object->_render_number_field(
                $display_type,
                'slices',
                '# of slices',
                $display_type->settings['slices'],
                'When a slice effect is selected, how many slices should be displayed?',
                !$display_type->settings['customize_nivo_slider'],
                0,
                2
            );
        }
    
        function _render_nivo_slider_box_columns_field($display_type)
        {
            return $this->object->_render_number_field(
                $display_type,
                'boxCols',
                '# of box columns',
                $display_type->settings['boxCols'],
                "When a box effect is selected, how many columns should be displayed?",
                !$display_type->settings['customize_nivo_slider'],
                0,
                1
            );
        }
    
        function _render_nivo_slider_box_rows_field($display_type)
        {
            return $this->object->_render_number_field(
                $display_type,
                'boxRows',
                '# of box rows',
                $display_type->settings['boxRows'],
                "When a box effect is selected, how many rows should be displayed?",
                !$display_type->settings['customize_nivo_slider'],
                0,
                1
            );
        }
    
        function _render_nivo_slider_animation_speed_field($display_type)
        {
            return $this->object->_render_number_field(
                $display_type,
                'animSpeed',
                'Animation speed',
                $display_type->settings['animSpeed'],
                "How fast, in millseconds, a transition moves from one to another",
                !$display_type->settings['customize_nivo_slider'],
                0,
                1
            );
        }
    
        function _render_nivo_slider_pause_speed_field($display_type)
        {
            return $this->object->_render_number_field(
                $display_type,
                'pauseTime',
                'Pause speed',
                $display_type->settings['pauseTime'],
                "The delay, in milliseconds, from when one transition finishes and another is to start",
                !$display_type->settings['customize_nivo_slider'],
                0,
                1
            );
        }
    
        function _render_nivo_slider_random_start_field($display_type)
        {
            return $this->object->_render_radio_field(
                $display_type,
                'randomStart',
                'Start on a random slide?',
                $display_type->settings['randomStart']
    
            );
        }
    
        function _render_nivo_slider_starting_slide_field($display_type)
        {
            return $this->object->_render_number_field(
                $display_type,
                'startSlide',
                "Starting slide",
                $display_type->settings['startSlide'],
                "The first slide to show, 0 being the first available.",
                !$display_type->settings['randomStart']
            );
        }
    
        function _render_nivo_slider_direction_nav_field($display_type)
        {
            return $this->object->_render_radio_field(
                $display_type,
                'directionNav',
                'Display navigation buttons?',
                $display_type->settings['directionNav']
            );
        }
    
        function _render_nivo_slider_control_nav_field($display_type)
        {
            return $this->object->_render_radio_field(
                $display_type,
                'controlNav',
                "Display pagination buttons?",
                $display_type->settings['controlNav']
            );
        }
    
        function _render_nivo_slider_control_nav_thumbs($display_type)
        {
            return $this->object->_render_radio_field(
                $display_type,
                'controlNavThumbs',
                "Use thumbnails for pagination buttons?",
                $display_type->settings['controlNavThumbs'],
                '',
                !$display_type->settings['controlNav']
            );
        }
    
        function _render_nivo_slider_pause_on_hover_field($display_type)
        {
            return $this->object->_render_radio_field(
                $display_type,
                'pauseOnHover',
                "Pause on hover",
                $display_type->settings['pauseOnHover']
            );
        }
    
        function _render_nivo_slider_autostart_slideshow_field($display_type)
        {
            return $this->object->_render_radio_field(
                $display_type,
                'autostart',
                'Autostart slideshow?',
                $display_type->settings['autostart']
            );
        }
    
        function _render_nivo_slider_prev_text_field($display_type)
        {
            return $this->object->_render_text_field(
                $display_type,
                'nextText',
                'Next button label',
                $display_type->settings['nextText'],
                '',
                !$display_type->settings['directionNav']
            );
        }
    
        function _render_nivo_slider_next_text_field($display_type)
        {
            return $this->object->_render_text_field(
                $display_type,
                'prevText',
                'Previous button label',
                $display_type->settings['prevText'],
                '',
                !$display_type->settings['directionNav']
            );
        }
    }

    You specify in the _get_field_names() which fields are to be rendered. The I_Form instance will then try rendering the field by calling a _render_[field_name]_field instance method. The default implementation of the The I_Form interface is the C_Form component, which provides many helper methods for rendering form forms. See the Mixin_Form_Field_Generators for a list of all helper methods available, located in the nextgen_admin module. We'll now register the adapter, afterwhich, you should see the form rendered in the Attach to Post and Display Settings pages:

    <?php
    /*
    {
        Module: jj-nivo_slider
    }
    */
    
    define('JJ_NIVO_SLIDER', 'jj-nivo_slider');
    
    class M_JJ_Nivo_Slider extends C_Base_Module
    {
        function define()
        {
            parent::define(
                JJ_NIVO_SLIDER,
                'Nivo Slider',
                'Nivo Slider for NextGEN Gallery 2.0',
                '0.1',
                'http://wordpress.org/extend/plugins/jj-nextgen-jquery-slider/',
                'Michael Weichert',
                'http://mweichert.com'
            );
        }
    
        function initialize()
        {
            parent::initialize();
            $form_manager = $this->get_registry()->get_utility('I_Form_Manager');
            $form_manager->add_form(NEXTGEN_DISPLAY_SETTINGS_SLUG, JJ_NIVO_SLIDER);
        }
    
        function _register_hooks()
        {
            add_shortcode('jj-ngg-jquery-slider', array(&$this, 'render_shortcode'));
            add_shortcode('jj-nivo-slider',       array(&$this, 'render_shortcode'));
            add_shortcode('nivo-slider',          array(&$this, 'render_shortcode'));
            add_action('wp_enqueue_scripts',      array(&$this, 'register_static_resources'));
        }
    
        function _register_adapters()
        {
            $this->get_registry()->add_adapter('I_Installer', 'A_Nivo_Slider_Installer');
            $this->get_registry()->add_adapter('I_Display_Type_Mapper', 'A_Nivo_Slider_Mapper');
            $this->get_registry()->add_adapter('I_Form', 'A_Nivo_Slider_Form', JJ_NIVO_SLIDER);
        }
    
        function render_shortcode($attrs=array())
        {
            return "<div><strong>NIVO SLIDER</strong></div>";
        }
    
        function register_static_resources()
        {
            $router = $this->get_registry()->get_utility('I_Router');
            $css    = $router->get_static_url('jj-nivo-slider#stylesheets/nivo-slider.css');
            $js     = $router->get_static_url('jj-nivo-slider#script/jquery.nivo.slider.pack.js');
            wp_register_style('nivo-slider', $css);
            wp_register_script('nivo-slider', $js, array('jquery'));
    
            // Register themes
            foreach (array('bar', 'dark', 'default', 'light') as $theme) {
                $css = $router->get_static_url("jj-nivo-slider#stylesheets/{$theme}/{$theme}.css");
                wp_register_style('nivo-slider-'.$theme, $css);
            }
        }
    }
    
    new M_JJ_Nivo_Slider();
    Add a front-end controller

    We're now in the final stages of creating our display type. We can select it from the Attach to Post interface, and configure it's settings, but now we need to implement how the display type will render a C_Displayed_Gallery object on the front-end. The I_Display_Type_Controller utility is used to render displayed galleries. One is fetched using the display type as it's context, and it's expected that adapters for that context will be registered to provide the rendering logic. We'll create that adapter now. Create a file called adapter.nivo_slider_controller.php:

    <?php
    
    class A_Nivo_Slider_Controller extends Mixin
    {
        function index_action($displayed_gallery, $return=FALSE)
        {
            $params                 = array();
            $params['id']           = $displayed_gallery->id();
            $params['images']       = $displayed_gallery->get_included_entities();
            $params['effect_code']  = $this->object->get_effect_code($displayed_gallery);
            $params['storage']      = $this->get_registry()->get_utility('I_Gallery_Storage');
    
            // Use the manualAdvance parameter instead of autostart
            $options = $displayed_gallery->display_settings;
            $options['manualAdvance'] = !$options['autostart'];
            $params['options']      = json_encode($options);
    
            return $this->object->render_view(
                'jj-nivo_slider#index',
                $params,
                $return
            );
        }
    
        function enqueue_frontend_resources($displayed_gallery)
        {
            $this->call_parent('enqueue_frontend_resources', $displayed_gallery);
            wp_enqueue_script('nivo-slider');
            wp_enqueue_style('nivo-slider');
            wp_enqueue_style('nivo-slider-'.$displayed_gallery->display_settings['theme']);
        }
    }

    The index_action() method renders the markup of the display type, and the enqueue_frontend_resources() method is used to enqueue static resources with WordPress.

    The index_action() method makes use is assembling some parameters to pass to the render_view() method, which will render our PHP template to generate the markup. The MVC module expects all modules to store their templates in a directory called, you guessed it - templates. Lets create templates/index.php and write our mark-up:

    <?php $this->start_element('nextgen_gallery.gallery_container', 'container', $displayed_gallery) ?>
    <div id="<?php echo_h($id)?>_container" class="nivo_slider_container">
    
        <?php $this->start_element('nextgen_gallery.image_list_container', 'container', $images) ?>
        <div id="<?php echo_h($id) ?>" class="nivoSlider">
            <?php foreach ($images as $image): ?>
    
                <?php $this->start_element('nextgen_gallery.image', 'item', $image); ?>
                <img
                    title="<?php echo esc_attr($image->alttext)?>"
                    alt="<?php echo esc_attr($image->alttext)?>"
                    src="<?php echo esc_attr($storage->get_image_url($image))?>"
                    style="max-width:none;"
                />
                <?php $this->end_element() ?>
    
            <?php endforeach ?>
        </div>
        <?php $this->end_element(); ?>
    
        <?php $this->start_element('jj-nivo_slider.initscript', 'initscript', $displayed_gallery); ?>
        <script type="text/javascript">
            jQuery(function($){
                var options = <?php echo $options?>;
                var slider = $('#<?php echo_h($id) ?>');
                var container = $('#<?php echo_h($id) ?>_container');
    
                // Apply theme
                container.addClass('theme-'+options.theme);
    
                // Calculate container dimensions
                if (parseInt(options.max_width) > 0)
                    container.css('width', options.max_width);
                else
                    container.css('width', '100%');
    
                // Centered?
                if (parseInt(options.center) > 0) container.css('margin', 'auto');
    
                slider.nivoSlider(options);
            });
        </script>
        <?php $this->end_element(); ?>
    
    </div>
    <?php $this->end_element(); ?>

    In the template, we iterate over each image and output an IMG tag as well as a script tag used to initialize Nivo Slider. We use $this->start_element() and $this->end_element() calls to indicate some important key HTML elements that can be extended and modified by other third-party plugins, but that is outside the scope of this tutorial.

    The template makes use of an important utility, I_Gallery_Storage, which provides an abstraction for retrieving image paths and urls. In the future, we plan on implementing all NextGEN Data as custom post types, and store images using the Media Library. By utilizing the I_Gallery_Storage component, your code will be ready for that change without requiring any additional work from you.

    Now that we have a controller and a template to render, we need to register the adapter in our module definition file:

    <?php
    /*
    {
        Module: jj-nivo_slider
    }
    */
    
    define('JJ_NIVO_SLIDER', 'jj-nivo_slider');
    
    class M_JJ_Nivo_Slider extends C_Base_Module
    {
        function define()
        {
            parent::define(
                JJ_NIVO_SLIDER,
                'Nivo Slider',
                'Nivo Slider for NextGEN Gallery 2.0',
                '0.1',
                'http://wordpress.org/extend/plugins/jj-nextgen-jquery-slider/',
                'Michael Weichert',
                'http://mweichert.com'
            );
        }
    
        function initialize()
        {
            parent::initialize();
            $form_manager = $this->get_registry()->get_utility('I_Form_Manager');
            $form_manager->add_form(NEXTGEN_DISPLAY_SETTINGS_SLUG, JJ_NIVO_SLIDER);
        }
    
        function _register_hooks()
        {
            add_shortcode('jj-ngg-jquery-slider', array(&$this, 'render_shortcode'));
            add_shortcode('jj-nivo-slider',       array(&$this, 'render_shortcode'));
            add_shortcode('nivo-slider',          array(&$this, 'render_shortcode'));
            add_action('wp_enqueue_scripts',      array(&$this, 'register_static_resources'));
        }
    
        function _register_adapters()
        {
            $this->get_registry()->add_adapter('I_Installer', 'A_Nivo_Slider_Installer');
            $this->get_registry()->add_adapter('I_Display_Type_Mapper', 'A_Nivo_Slider_Mapper');
            $this->get_registry()->add_adapter('I_Form', 'A_Nivo_Slider_Form', JJ_NIVO_SLIDER);
            $this->get_registry()->add_adapter('I_Display_Type_Controller', 'A_Nivo_Slider_Controller', JJ_NIVO_SLIDER);
        }
    
        function render_shortcode($attrs=array())
        {
            return "<div><strong>NIVO SLIDER</strong></div>";
        }
    
        function register_static_resources()
        {
            $router = $this->get_registry()->get_utility('I_Router');
            $css    = $router->get_static_url('jj-nivo-slider#stylesheets/nivo-slider.css');
            $js     = $router->get_static_url('jj-nivo-slider#script/jquery.nivo.slider.pack.js');
            wp_register_style('nivo-slider', $css);
            wp_register_script('nivo-slider', $js, array('jquery'));
    
            // Register themes
            foreach (array('bar', 'dark', 'default', 'light') as $theme) {
                $css = $router->get_static_url("jj-nivo-slider#stylesheets/{$theme}/{$theme}.css");
                wp_register_style('nivo-slider-'.$theme, $css);
            }
        }
    }
    
    new M_JJ_Nivo_Slider();

    At this point, our display type is complete and we should be able to render a Nivo Slider gallery by using the Attach to Post interface. We can also use the NextGEN Gallery 2.0 shortcode mechanism:

    We cannot display this gallery

    For example of how to use the ngg_images shortcode, please review class.displayed_gallery_renderer.php of the nextgen_gallery_display module.

    The JJ NextGEN JQuery slider plugin provides it's own shortcode, [jj-ngg-jquery-slider], that we temporarily configured to output NIVO SLIDER instead of the actual displayed gallery. Let's fix that now:

    <?php
    /*
    {
        Module: jj-nivo_slider
    }
    */
    
    define('JJ_NIVO_SLIDER', 'jj-nivo_slider');
    
    class M_JJ_Nivo_Slider extends C_Base_Module
    {
        function define()
        {
            parent::define(
                JJ_NIVO_SLIDER,
                'Nivo Slider',
                'Nivo Slider for NextGEN Gallery 2.0',
                '0.1',
                'http://wordpress.org/extend/plugins/jj-nextgen-jquery-slider/',
                'Michael Weichert',
                'http://mweichert.com'
            );
        }
    
        function initialize()
        {
            parent::initialize();
            $form_manager = $this->get_registry()->get_utility('I_Form_Manager');
            $form_manager->add_form(NEXTGEN_DISPLAY_SETTINGS_SLUG, JJ_NIVO_SLIDER);
        }
    
        function _register_hooks()
        {
            add_shortcode('jj-ngg-jquery-slider', array(&$this, 'render_shortcode'));
            add_shortcode('jj-nivo-slider',       array(&$this, 'render_shortcode'));
            add_shortcode('nivo-slider',          array(&$this, 'render_shortcode'));
            add_action('wp_enqueue_scripts',      array(&$this, 'register_static_resources'));
        }
    
        function _register_adapters()
        {
            $this->get_registry()->add_adapter('I_Installer', 'A_Nivo_Slider_Installer');
            $this->get_registry()->add_adapter('I_Display_Type_Mapper', 'A_Nivo_Slider_Mapper');
            $this->get_registry()->add_adapter('I_Form', 'A_Nivo_Slider_Form', JJ_NIVO_SLIDER);
            $this->get_registry()->add_adapter('I_Display_Type_Controller', 'A_Nivo_Slider_Controller', JJ_NIVO_SLIDER);
        }
    
        function render_shortcode($attrs=array())
        {
            if (!$attrs)                            $attrs = array();
            if (!isset($attrs['source']))           $attrs['source'] = 'galleries';
            if (!isset($attrs['display_type']))     $attrs['display_type'] = $this->module_id;
            if (isset($attrs['galleryid']))         $attrs['gallery_ids'] = $attrs['galleryid'];
            unset ($attrs['galleryid']);
    
            $renderer = $this->_get_registry()->get_utility('I_Displayed_Gallery_Renderer');
    
            // Render the displayed gallery
            return $renderer->display_images($attrs);
        }
    
        function register_static_resources()
        {
            $router = $this->get_registry()->get_utility('I_Router');
            $css    = $router->get_static_url('jj-nivo-slider#stylesheets/nivo-slider.css');
            $js     = $router->get_static_url('jj-nivo-slider#script/jquery.nivo.slider.pack.js');
            wp_register_style('nivo-slider', $css);
            wp_register_script('nivo-slider', $js, array('jquery'));
    
            // Register themes
            foreach (array('bar', 'dark', 'default', 'light') as $theme) {
                $css = $router->get_static_url("jj-nivo-slider#stylesheets/{$theme}/{$theme}.css");
                wp_register_style('nivo-slider-'.$theme, $css);
            }
        }
    }
    
    new M_JJ_Nivo_Slider();

    Our plugin is functionally complete, but we'll add some code to optimize Pope's autoloader:

    <?php
    /*
    {
        Module: jj-nivo_slider
    }
    */
    
    define('JJ_NIVO_SLIDER', 'jj-nivo_slider');
    
    class M_JJ_Nivo_Slider extends C_Base_Module
    {
        function define()
        {
            parent::define(
                JJ_NIVO_SLIDER,
                'Nivo Slider',
                'Nivo Slider for NextGEN Gallery 2.0',
                '0.1',
                'http://wordpress.org/extend/plugins/jj-nextgen-jquery-slider/',
                'Michael Weichert',
                'http://mweichert.com'
            );
        }
    
        function initialize()
        {
            parent::initialize();
            $form_manager = $this->get_registry()->get_utility('I_Form_Manager');
            $form_manager->add_form(NEXTGEN_DISPLAY_SETTINGS_SLUG, JJ_NIVO_SLIDER);
        }
    
        function _register_hooks()
        {
            add_shortcode('jj-ngg-jquery-slider', array(&$this, 'render_shortcode'));
            add_shortcode('jj-nivo-slider',       array(&$this, 'render_shortcode'));
            add_shortcode('nivo-slider',          array(&$this, 'render_shortcode'));
            add_action('wp_enqueue_scripts',      array(&$this, 'register_static_resources'));
        }
    
        function _register_adapters()
        {
            $this->get_registry()->add_adapter('I_Installer', 'A_Nivo_Slider_Installer');
            $this->get_registry()->add_adapter('I_Display_Type_Mapper', 'A_Nivo_Slider_Mapper');
            $this->get_registry()->add_adapter('I_Form', 'A_Nivo_Slider_Form', JJ_NIVO_SLIDER);
            $this->get_registry()->add_adapter('I_Display_Type_Controller', 'A_Nivo_Slider_Controller', JJ_NIVO_SLIDER);
        }
    
        function render_shortcode($attrs=array())
        {
            if (!$attrs)                            $attrs = array();
            if (!isset($attrs['source']))           $attrs['source'] = 'galleries';
            if (!isset($attrs['display_type']))     $attrs['display_type'] = $this->module_id;
            if (isset($attrs['galleryid']))         $attrs['gallery_ids'] = $attrs['galleryid'];
            unset ($attrs['galleryid']);
    
            $renderer = $this->_get_registry()->get_utility('I_Displayed_Gallery_Renderer');
    
            // Render the displayed gallery
            return $renderer->display_images($attrs);
        }
    
        function register_static_resources()
        {
            $router = $this->get_registry()->get_utility('I_Router');
            $css    = $router->get_static_url('jj-nivo-slider#stylesheets/nivo-slider.css');
            $js     = $router->get_static_url('jj-nivo-slider#script/jquery.nivo.slider.pack.js');
            wp_register_style('nivo-slider', $css);
            wp_register_script('nivo-slider', $js, array('jquery'));
    
            // Register themes
            foreach (array('bar', 'dark', 'default', 'light') as $theme) {
                $css = $router->get_static_url("jj-nivo-slider#stylesheets/{$theme}/{$theme}.css");
                wp_register_style('nivo-slider-'.$theme, $css);
            }
        }
    
    	function get_type_list()
    	{
    		return array(
    			'A_Nivo_Slider_Controller'	=>	'adapter.nivo_slider_controller.php',
    			'A_Nivo_Slider_Form'		=>	'adapter.nivo_slider_form.php',
    			'A_Nivo_Slider_Installer'	=>	'adapter.nivo_slider_installer.php',
    			'A_Nivo_Slider_Mapper'		=>	'adapter.nivo_slider_mapper.php',
    		);
    	}
    }
    
    new M_JJ_Nivo_Slider();

    The addition of the get_type_list() has a significant performance impact, and although not strictly required, should always be added to your module definition file. It's simply a map of class names and the files that your module provides.

    That completes our task of porting the JJ NextGEN JQuery Slider plugin to NextGEN Gallery 2.0, and wraps up our tutorial. I'd suggest all third-party developers sign-up to receive our Developer News to keep yourself informed. Should you have any questions about NGG 2.0 development, please send them here and someone will get back in touch.

    Thanks for reading!

This Post Has 11 Comments

  1. Woah, as a pretty newbie web programmer, this is intense! Back with NextGEN Gallery v1.x, I made a template file called singlepic-caption.php to add the caption and a border around the image, calling it from posts with the singlepic shortcode addition template=caption. Trying to work out how to get this working again since the upgrade to v2.0!

    1. Hi Geoffrey,

      We are working on more documentation and will have it posted once it’s complete.

      1. Hay,
        i made a update to 2.0.7 and now my design is destroyed 😛
        please hurry up with documentation of 2.x Themes – 2.x has so good changes. It’s really disturbing that i have to downgrade again 😉 ( a unfinished documentation is better, then no documentation =) )

        1. templates* not themes

  2. Hi! First of all, I would like to thank you for this great tutorial.
    Even if I’m not pretty sure if this pope framework give us a real improvement, I know I have to work with it to create the new Powertags version.
    I’ve tried to replicate this code, but it shows only:

    array (size=1)
    ‘display_type’ =>
    array (size=1)
    0 => string ‘Invalid display type’ (length=20)

    “Invalid Displayed Gallery”

    Can you post the zip file with the working code so I can compare mine version with yours?

  3. I struggled to follow the tutorial as it was not clear where each new file should be saved. Stating such information clearly would help enormously especially with a screen shot of the file structure for more visual learners.

    I have got as far as entering [jj-ngg-jquery-slider] into a page but fail to get NIVO SLIDER to display.

    The code I have used has been cut and paste from the samples provided on this page and all file names double checked. The files have all been saved in plugins>jj-nextgen-jquery-slider.

    If this is incorrect please update your tutorial as I am sure other will make the same assumptions, follow the same actions which will result in broken galleries.

    I look forward to when these teething problems are resolved. The potential of your plugin is amazing.

  4. Hi, first, thanks for your great work!

    Getting into all this is really interesting, but needs a lot of time!

    What I did in the past with ngg was to customize gallery.php and create a album-mytemplate.php (called via short code template=mytemplate). In that way I’ve been able (long time ago!) to have responsive galleries, masonry organized, with ngg-cutom-field I’ve added custom thumbs widths, modals in the gallery, enabling video and still custom css classes, and showing it with fancybox (customizing buttons, functions, etc…). Well, it was a lot of work. And it did the job pretty well.
    I’d like to know the best way to move all this work into 2.0 without having to restart working on that from scratch.

    If can help I can provide in pm a link to a dev web site with the gallery.

    Thanks!

  5. Hello guy,
    I got a question for Geoffrey. I was looking to display a caption below a singlepic with NextGEN gallery, but was not able to do it with the new version. Did you find a way to do it ?
    Marc

    1. Hi Marc,

      We hope to add this as a feature in a future update. Please add your vote for it here.

  6. Hi,
    Tried the above tutorial “as-is”, but it simply does not work. It took me the best part of 4 days to get it working somehow. The problems were varied:

    – The shortcode initially did not work, but that had to do with the Netbeans IDE removing the “.php” extension from the file name when you specify filenames that include a “.” (dot). So, module.nivo_slider.php becomes module.nivo_slider, and Nextgen does not find the file because it is looking for a file ending with “.php” (regex);
    – The installer bit is incomplete/inaccurate. It may work with an adapter, but most of the modules in NextGen use a “class.” type of component instead like C_Nivo_Slider_Installer. But to make it work, apparently the only way is to “include” the installer file in the “define” method of the module, and register it as a handler with the C_Photocrati_Installer component:

    include_once(‘class.nivo_slider_installer.php’);
    C_Photocrati_Installer::add_handler($this->module_id, ‘C_Nivo_Slider_Installer’);
    – The settings form adapter (A_Nivo_Slider_Form) apparently needs a Form Manager adapter (A_Nivo_Slider_Forms, with an initialize method that adds the Nivo Slider form), that needs to be registered. At least this the only way I managed to get it working;
    – There is a typo in the calls to get_static_url in the register_static_resources method of the module: the first part of the file should be “jj-nivo_slider” (with an underscore between “nivo” and “slider”) and not “jj-nivo-slider”. Result: the jquery nivo scripts and stylesheets were not found, and not loaded;
    – I suspect a bug in the “update” method of class C_Photocrati_Installer, whereby an update never re-triggers a generation of the Display Type posts (custom post type display_type). It does not matter how many times I deactivated and reactivated the NextGen plugin and the “jj-nivo_slider” display type plugin (as documented above), the new Display Type never showed up until I “forced” an update “reset” in debugging.

    I would suggest an update of the tutorial to a state where it does actually work. Additional tutorials and documentation on the Pope Framework would also prove tremendously useful (it would certainly have saved me a lot of debugging time to understand just the basics of it): architecture model, class diagram, verbose tutorials,… Anything would be helpful.

    Or if there is already in-depth documentation (other than bitbucket raw code…) and other detailed tutorials, could you please direct me/us to it?

    It all looks like great work that has been done, but unfortunately, without being able to understand it, not many people will be able to actually make good use of it all.

    Anyhow, these are just suggestions.

    Philippe

    1. Thanks, your comment was very useful

Comments are closed.

Table of Contents
Close Menu