Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

OOP, extended API, example plugin #6

Merged
merged 4 commits into from

2 participants

@franz-josef-kaiser
Collaborator
  • OOP: I completely moved the plugin to an OOP concept to get rid of all the public functions.
  • Extended API: The API now comes with an array of arguments. This means that I deprecated the $key argument, as it can simply be built from the label, which makes it easier. I then added in the support for a root, so we can use the WP_CONTENT_DIR, WP_PLUGIN_DIR, WPMU_PLUGIN_DIR and the root as containers for additional plugin directories. It now also works (and this was the main reason for this), if you defined an external location for your plugins. I got several local installations, that all together share the local domain plugins.dev for their plugins. This saves me from copy/pasting and updating plugins in several installations and makes development much easier. Moving the arguments to an array will make altering the API arguments much easier later on. I took some time to make shure, that we'll guide people on how to use the new API without breaking existing installations, so everything's backwards compatible. The last thing that was added, is guidance on when to hook the plugin. It's a simply call to _doing_it_wrong() if the current_filter() isn't plugins_loaded. This prevents the usage of the muplugins_loaded hook, but it isn't a loss, as the filter wouldn't help anything, as the plugin runs later.
  • Example Plugin: I added an example plugin to show how stuff works and should be done.
  • Readme: I also added a small changelog to keep people on trac. I got some code somewhere, where we could also extend the plugin info in the list table and move the changelog to a separate file, but that's code for another patch.

Everything's tested in different cases, but you know what: We're all humans and bugs are built in :)

@franz-josef-kaiser franz-josef-kaiser commented on the diff
inc/admin.php
((4 lines not shown))
-class CD_APD_Admin
+
+if ( ! class_exists( 'CD_APD_Admin' ) )
+{
+ add_action( 'plugins_loaded', array( 'CD_APD_Admin', 'instance' ) );
@franz-josef-kaiser Collaborator

Hooking the main class into plugins_loaded on priority 10. This will allow people better control via hooks. It also makes sure, the new static $instance only runs once.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@franz-josef-kaiser franz-josef-kaiser commented on the diff
inc/api.php
((17 lines not shown))
+
+
+/**
+ * Registers a new plugin directory.
+ *
+ * @since 0.1
+ * @uses _get_new_plugin_directory_root()
+ * @param array $args An Array of arguments: 'dir' = Name of the directory, 'label' = What you read above the list table, 'case' = Where the dir resides.
+ * @param string $deprecated_dir (deprecated arg) The new plugin directory. Either a full path or a folder name within wp-content.
+ * @param string $deprecated_label (deprecated arg) The nice name of the plugin directory. Presented in the list table.
+ * @return bool TRUE on success, FALSE in case the $key/$label is already in use.
+ */
+function register_plugin_directory( $args, $deprecated_dir = '', $deprecated_label = '' )
+{
+ // The call was too late (or too early in case of a MU-Plugin)
+ if ( 'plugins_loaded' !== current_filter() )
@franz-josef-kaiser Collaborator

Make sure we run stuff on the right filter. If not, we're adding a note for the user that she/he should fix stuff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@franz-josef-kaiser franz-josef-kaiser commented on the diff
inc/api.php
((27 lines not shown))
+ * @return bool TRUE on success, FALSE in case the $key/$label is already in use.
+ */
+function register_plugin_directory( $args, $deprecated_dir = '', $deprecated_label = '' )
+{
+ // The call was too late (or too early in case of a MU-Plugin)
+ if ( 'plugins_loaded' !== current_filter() )
+ {
+ _doing_it_wrong(
+ __FUNCTION__
+ ,__( 'Registering a new plugin directory should be done during the `plugins_loaded` hook on priority `0`.', 'cd_apd_textdomain' )
+ ,'0.1'
+ );
+ }
+
+ // Deprecating single arguments
+ if ( ! is_array( $args ) )
@franz-josef-kaiser Collaborator

Moving input arguments to an array...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@franz-josef-kaiser franz-josef-kaiser commented on the diff
inc/api.php
((43 lines not shown))
+ {
+ $info = debug_backtrace();
+ // The key now gets built from the label: Converted to lowercase alphanumeric string.
+ _deprecated_argument(
+ __FUNCTION__
+ ,'0.3'
+ ,sprintf(
+ __( "%sYou need to specify the arguments – when registering new plugin directories – as associative array.%s%s", 'cd_apd_textdomain' )
+ ,'<br /><blockquote><strong>'
+ ,'</strong></blockquote>'
+ ,"The call was from within: <code>{$info[ 0 ]['file']}</code> in the function: <code>{$info[ 1 ]['function']}()</code>.<br />"
+ )
+ );
+
+ // Fix for back compat
+ $args = array(
@franz-josef-kaiser Collaborator

...and making sure stuff doesn't break and is backwards compatible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@franz-josef-kaiser franz-josef-kaiser commented on the diff
inc/api.php
((90 lines not shown))
+ );
+
+ return true;
+}
+
+
+/**
+ * Retrieves the root path for the new plugin directory.
+ *
+ * @internal Callback function for register_plugin_directory()
+ *
+ * @since 0.3
+ * @param string $case Valid: 'content', 'plugins', 'muplugins', 'root'.
+ * @return string $root The root path based on the WP filesystem constants.
+ */
+function _get_new_plugin_directory_root( $root )
@franz-josef-kaiser Collaborator

Now we're supporting all different sorts of locations. The switch makes sure, we can easily add in additional cases. Maybe we should also add an filter?

@chrisguitarguy Owner
case 'content':
default:
    $root = apply_filters("adp_root_{$root}", WP_CONTENT_DIR);

Probably a good idea. Makes it more flexible.

@franz-josef-kaiser Collaborator
case 'content' :
    $root = WP_CONTENT_DIR;
    break;

default :
    $root = apply_filters( "adp_root_{$root}", WP_CONTENT_DIR );
    break;

...to move 'content' away from any other behavior. This would allow to add whatever/custom/etc... as arg and then make use of the filter.

@chrisguitarguy Owner

Sounds good to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@chrisguitarguy chrisguitarguy merged commit 1e71dcb into from
@chrisguitarguy

Merged! Will test tonight.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
41 example_plugin/register_addt_plugins_dir.php
@@ -0,0 +1,41 @@
+<?php
+! defined( 'ABSPATH' ) AND exit();
+/*
+Plugin Name: Additional Plugin Directories: Example Plugin
+Plugin URI: http://github.com/chrisguitarguy
+Description: Example Plugin to show how to register additional plugin directories
+Version: 0.1
+Author: Franz Josef Kaiser
+Author URI: http://unserkaiser.com
+License: MIT
+*/
+
+
+/**
+ * Registers a new plugin directory
+ *
+ * @example
+ * $args Array (Valid args for `root`) 'content', 'plugins', 'muplugins', 'root'
+ * The new directories must be subdirectories of the following WP file system constants:
+ * 'content': (default) WP_CONTENT_DIR
+ * 'plugins': WP_PLUGIN_DIR
+ * 'muplugins': WPMU_PLUGIN_DIR
+ * 'root': one level below WP_CONTENT_DIR
+ *
+ * @return void
+ */
+function cd_apd_register_additional_plugin_directories()
+{
+ // Better abort - if we don't do this, we'll create an error on deactivation of the main plugin.
+ if ( ! function_exists( 'register_plugin_directory' ) )
+ return;
+
+ // Call the public API function once for every directory you want to add.
+ register_plugin_directory( array(
+ 'dir' => 'example_plugin_directory'
+ ,'label' => 'Example Label for the list table'
+ ,'root' => 'plugins'
+ ) );
+}
+// Needs to be added on the `plugins_loaded` hook with a priority of `0`.
+add_action( 'plugins_loaded', 'cd_apd_register_additional_plugin_directories', 0 );
View
183 inc/admin.php
@@ -1,57 +1,116 @@
<?php
-! defined( 'ABSPATH' ) && exit();
+! defined( 'ABSPATH' ) AND exit();
-class CD_APD_Admin
+
+if ( ! class_exists( 'CD_APD_Admin' ) )
+{
+ add_action( 'plugins_loaded', array( 'CD_APD_Admin', 'instance' ) );
@franz-josef-kaiser Collaborator

Hooking the main class into plugins_loaded on priority 10. This will allow people better control via hooks. It also makes sure, the new static $instance only runs once.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+/**
+ * Admin/Factory
+ *
+ * @author Christopher Davis, Franz Josef Kaiser
+ * @license GPL
+ * @copyright © Christopher Davis, Franz Josef Kaiser 2011-2012
+ *
+ * @package WordPress
+ * @subpackage Additional Plugin Directories: Admin/Factory
+ */
+class CD_APD_Admin extends CD_APD_Core
{
/**
+ * Instance
+ *
+ * @since 0.3
+ * @access protected
+ * @var object
+ */
+ protected static $instance;
+
+
+ /**
* The container for all of our custom plugins
+ *
+ * @since 0.1
+ * @access protected
+ * @var array
*/
protected $plugins = array();
+
/**
* What custom actions are we allowed to handle here?
+ *
+ * @since 0.1
+ * @access protected
+ * @var array
*/
protected $actions = array();
+
/**
* The original count of the plugins
+ *
+ * @since 0.1
+ * @access protected
+ * @var int
*/
protected $all_count = 0;
+
+ /**
+ * Creates a new static instance
+ *
+ * @since 0.3
+ * @static
+ * @return void
+ */
+ public static function instance()
+ {
+ null === self :: $instance AND self :: $instance = new self;
+ return self :: $instance;
+ }
+
+
/**
* constructor
*
- * @since 0.1
+ * @since 0.1
+ * @return void
*/
public function __construct()
{
- add_action( 'load-plugins.php', array( $this, 'init' ) );
add_action( 'plugins_loaded', array( $this, 'setup_actions' ), 1 );
+ add_action( 'load-plugins.php', array( $this, 'init' ) );
}
/**
* Sets up which actions we can handle with this plugin. We'll use this
- * to catch activations and deactivations as the normal way won't work
+ * to catch activations and deactivations as the normal way won't work.
+ * Has the filter 'custom_plugin_actions' to allow extensions.
*
- * @since 0.1
+ * @since 0.1
+ * @return void
*/
public function setup_actions()
{
- $tmp = array(
- 'custom_activate',
- 'custom_deactivate'
+ $this->actions = apply_filters(
+ 'custom_plugin_actions',
+ array(
+ 'custom_activate',
+ 'custom_deactivate'
+ )
);
- $this->actions = apply_filters( 'custom_plugin_actions', $tmp );
}
/**
- * Makes the magic happen. Loads all the other hooks to modify the
- * plugin list table
+ * Makes the magic happen. Loads all the other hooks to modify the plugin list table
*
- * @since 0.1
+ * @since 0.1
+ * @return void
*/
public function init()
{
@@ -81,7 +140,9 @@ public function init()
/**
* Adds our custom plugin directories to the list of plugin types
*
- * @since 0.1
+ * @since 0.1
+ * @param array $views
+ * @return array $views
*/
public function views( $views )
{
@@ -94,7 +155,9 @@ public function views( $views )
// Add our directories to the action links
foreach ( $wp_plugin_directories as $key => $info )
{
- if ( ! count( $this->plugins[$key] ) )
+ $count = count( $this->plugins[ $key ] );
+
+ if ( ! $count )
continue;
$views[ $key ] = sprintf(
@@ -102,7 +165,7 @@ public function views( $views )
add_query_arg( 'plugin_status', $key, 'plugins.php' ),
$this->get_plugin_status() == $key ? ' class="current" ' : '',
esc_html( $info['label'] ),
- count( $this->plugins[ $key ] )
+ $count
);
}
@@ -112,6 +175,10 @@ public function views( $views )
/**
* Unset inactive plugin link as it doesn't really work for this view
+ *
+ * @since 0.1
+ * @param array $views
+ * @return array $views
*/
public function views_again( $views )
{
@@ -124,10 +191,15 @@ public function views_again( $views )
/**
* Filters the plugins list to include all the plugins in our custom directory
+ *
+ * @since 0.1
+ * @param array $plugins
+ * @return array $plugins
*/
public function filter_plugins( $plugins )
{
- if ( $key = $this->get_plugin_status() )
+ $key = $this->get_plugin_status();
+ if ( $key )
{
$this->all_count = count( $plugins );
$plugins = $this->plugins[ $key] ;
@@ -139,23 +211,32 @@ public function filter_plugins( $plugins )
/**
* Correct some action links so we can actually "activate" plugins
+ *
+ * @since 0.1
+ * @param array $links
+ * @param string $plugin_file
+ * @return array $links
*/
public function action_links( $links, $plugin_file )
{
$context = $this->get_plugin_status();
+ $active = get_option( "active_plugins_{$context}", array() );
+
// let's just start over
$links = array();
- $links['activate'] = sprintf(
- '<a href="%s" title="Activate this plugin">%s</a>',
- wp_nonce_url(
- "plugins.php?action=custom_activate&amp;plugin={$plugin_file}&amp;plugin_status=".esc_attr( $context ),
- "custom_activate-{$plugin_file}"
- ),
- __( 'Activate' )
- );
+ if ( ! in_array( $plugin_file, $active ) )
+ {
+ $links['activate'] = sprintf(
+ '<a href="%s" title="Activate this plugin">%s</a>',
+ wp_nonce_url(
+ "plugins.php?action=custom_activate&amp;plugin={$plugin_file}&amp;plugin_status=".esc_attr( $context ),
+ "custom_activate-{$plugin_file}"
+ ),
+ __( 'Activate' )
+ );
+ }
- $active = get_option( "active_plugins_{$context}", array() );
if ( in_array( $plugin_file, $active ) )
{
$links['deactivate'] = sprintf(
@@ -175,14 +256,18 @@ public function action_links( $links, $plugin_file )
/**
* Enqueues on JS file for fun hacks
*
- * @since 0.1
- * @uses wp_enqueue_script
+ * @since 0.1
+ * @uses wp_enqueue_script()
+ * @return void
*/
- public function scripts()
+ public function scripts( $screen )
{
+ if ( 'plugins.php' !== $screen )
+ return;
+
wp_enqueue_script(
'cd-apd-js',
- CD_APD_URL . 'js/apd.js',
+ CD_APD_URL.'js/apd.js',
array( 'jquery' ),
null
);
@@ -199,8 +284,9 @@ public function scripts()
/**
* Fetch all the custom plugins we have!
*
- * @since 0.1
- * @uses cd_adp_get_plugins To fetch all the custom plugins
+ * @since 0.1
+ * @uses get_plugins_from_cache() To fetch all the custom plugins
+ * @return void
*/
public function get_plugins()
{
@@ -210,7 +296,7 @@ public function get_plugins()
foreach ( array_keys( $wp_plugin_directories ) as $key )
{
- $this->plugins[ $key ] = cd_apd_get_plugins( $key );
+ $this->plugins[ $key ] = $this->get_plugins_from_cache( $key );
}
}
@@ -219,7 +305,8 @@ public function get_plugins()
* Handle activations and deactivations as the standard way will
* fail with "plugin file does not exist
*
- * @since 0.1
+ * @since 0.1
+ * @return void
*/
public function handle_actions()
{
@@ -240,11 +327,11 @@ public function handle_actions()
{
case 'custom_activate':
if ( ! current_user_can('activate_plugins') )
- wp_die( __('You do not have sufficient permissions to manage plugins for this site.') );
+ wp_die( __( 'You do not have sufficient permissions to manage plugins for this site.' ) );
check_admin_referer( "custom_activate-{$plugin}" );
- $result = cd_apd_activate_plugin( $plugin, $context );
+ $result = $this->activate_plugin( $plugin, $context );
if ( is_wp_error( $result ) )
{
if ( 'unexpected_output' == $result->get_error_code() )
@@ -278,15 +365,21 @@ public function handle_actions()
wp_die( __( 'You do not have sufficient permissions to deactivate plugins for this site.' ) );
check_admin_referer( "custom_deactivate-{$plugin}" );
- cd_apd_deactivate_plugins( $plugin, $context );
+
+ $this->deactivate_plugins( $plugin, $context );
+
if ( headers_sent() )
+ {
printf(
"<meta http-equiv='refresh' content='%s' />",
esc_attr( "0;url=plugins.php?deactivate=true&plugin_status={$status}&paged={$page}&s={$s}" )
);
+ }
else
- wp_redirect( self_admin_url("plugins.php?deactivate=true&plugin_status={$context}") );
- exit();
+ {
+ wp_redirect( self_admin_url( "plugins.php?deactivate=true&plugin_status={$context}" ) );
+ exit();
+ }
break;
default:
@@ -297,11 +390,11 @@ public function handle_actions()
/**
- * Utility function to get the current `plugin_status` key returns
- * false if our key isn't in the the custom directories
+ * Utility function to get the current `plugin_status`.
+ * The key returns FALSE if our key isn't in the the custom directories
*
- * @since 0.1
- * @return bool|string False on failure, the `$wp_plugin_directories` key on success
+ * @since 0.1
+ * @return bool|string $rv False on failure, the `$wp_plugin_directories` key on success
*/
public function get_plugin_status()
{
@@ -319,6 +412,6 @@ public function get_plugin_status()
return $rv;
}
-} // end class
+} // END Class CD_APD_Admin
-new CD_APD_Admin();
+} // endif;
View
134 inc/api.php
@@ -0,0 +1,134 @@
+<?php
+! defined( 'ABSPATH' ) AND exit();
+
+
+
+/**
+ * The central API
+ *
+ * @author Christopher Davis, Franz Josef Kaiser
+ * @license GPL
+ * @copyright © Christopher Davis, Franz Josef Kaiser 2011-2012
+ *
+ * @since 0.3
+ * @package Additional Plugin directories
+ * @subpackage The central API
+ */
+
+
+/**
+ * Registers a new plugin directory.
+ *
+ * @since 0.1
+ * @uses _get_new_plugin_directory_root()
+ * @param array $args An Array of arguments: 'dir' = Name of the directory, 'label' = What you read above the list table, 'case' = Where the dir resides.
+ * @param string $deprecated_dir (deprecated arg) The new plugin directory. Either a full path or a folder name within wp-content.
+ * @param string $deprecated_label (deprecated arg) The nice name of the plugin directory. Presented in the list table.
+ * @return bool TRUE on success, FALSE in case the $key/$label is already in use.
+ */
+function register_plugin_directory( $args, $deprecated_dir = '', $deprecated_label = '' )
+{
+ // The call was too late (or too early in case of a MU-Plugin)
+ if ( 'plugins_loaded' !== current_filter() )
@franz-josef-kaiser Collaborator

Make sure we run stuff on the right filter. If not, we're adding a note for the user that she/he should fix stuff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ {
+ _doing_it_wrong(
+ __FUNCTION__
+ ,__( 'Registering a new plugin directory should be done during the `plugins_loaded` hook on priority `0`.', 'cd_apd_textdomain' )
+ ,'0.1'
+ );
+ }
+
+ // Deprecating single arguments
+ if ( ! is_array( $args ) )
@franz-josef-kaiser Collaborator

Moving input arguments to an array...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ {
+ $info = debug_backtrace();
+ // The key now gets built from the label: Converted to lowercase alphanumeric string.
+ _deprecated_argument(
+ __FUNCTION__
+ ,'0.3'
+ ,sprintf(
+ __( "%sYou need to specify the arguments &ndash; when registering new plugin directories &ndash; as associative array.%s%s", 'cd_apd_textdomain' )
+ ,'<br /><blockquote><strong>'
+ ,'</strong></blockquote>'
+ ,"The call was from within: <code>{$info[ 0 ]['file']}</code> in the function: <code>{$info[ 1 ]['function']}()</code>.<br />"
+ )
+ );
+
+ // Fix for back compat
+ $args = array(
@franz-josef-kaiser Collaborator

...and making sure stuff doesn't break and is backwards compatible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ 'dir' => $deprecated_dir
+ ,'label' => $deprecated_label
+ );
+ }
+
+ // Setup defaults
+ $args = wp_parse_args( $args, array( 'root' => 'content' ) );
+
+ global $wp_plugin_directories;
+
+ empty( $wp_plugin_directories ) AND $wp_plugin_directories = array();
+
+ $new_dir = _get_new_plugin_directory_root( $args['root'] ).$args['dir'];
+
+ if ( ! file_exists( $args['dir'] ) AND file_exists( $new_dir ) )
+ {
+ $args['dir'] = $new_dir;
+ }
+
+ // Build $key from $label
+ $key = strtolower( preg_replace( "/[^a-zA-Z0-9\s]/", "", $args['label'] ) );
+
+ // Return FALSE in case we already got the key
+ if ( isset( $wp_plugin_directories[ $key ] ) )
+ return false;
+
+ // Assign the directory
+ $wp_plugin_directories[ $key ] = array(
+ 'dir' => $args['dir']
+ ,'label' => $args['label']
+ ,'root' => $args['root']
+ );
+
+ return true;
+}
+
+
+/**
+ * Retrieves the root path for the new plugin directory.
+ *
+ * @internal Callback function for register_plugin_directory()
+ *
+ * @since 0.3
+ * @param string $case Valid: 'content', 'plugins', 'muplugins', 'root'.
+ * @return string $root The root path based on the WP filesystem constants.
+ */
+function _get_new_plugin_directory_root( $root )
@franz-josef-kaiser Collaborator

Now we're supporting all different sorts of locations. The switch makes sure, we can easily add in additional cases. Maybe we should also add an filter?

@chrisguitarguy Owner
case 'content':
default:
    $root = apply_filters("adp_root_{$root}", WP_CONTENT_DIR);

Probably a good idea. Makes it more flexible.

@franz-josef-kaiser Collaborator
case 'content' :
    $root = WP_CONTENT_DIR;
    break;

default :
    $root = apply_filters( "adp_root_{$root}", WP_CONTENT_DIR );
    break;

...to move 'content' away from any other behavior. This would allow to add whatever/custom/etc... as arg and then make use of the filter.

@chrisguitarguy Owner

Sounds good to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+{
+ switch ( $root )
+ {
+ case 'plugins' :
+ $root = WP_PLUGIN_DIR;
+ break;
+
+ case 'muplugins' :
+ $root = WPMU_PLUGIN_DIR;
+ break;
+
+ // Experimental Edge Case:
+ // Assuming that the WP_CONTENT_DIR is a direct child of the root directory
+ // and directory separators are "/" above that.
+ // Maybe needs enchancements later on. Wait for feedback in Issues.
+ case 'root' :
+ $root = explode( DIRECTORY_SEPARATOR, WP_CONTENT_DIR );
+ $root = explode( '/', array_pop( $root ) );
+ $root = array_pop( $root );
+ break;
+
+ case 'content' :
+ default :
+ $root = WP_CONTENT_DIR;
+ break;
+ }
+
+ return trailingslashit( $root );
+}
View
388 inc/core.php
@@ -2,248 +2,280 @@
! defined( 'ABSPATH' ) AND exit();
+
+if ( ! class_exists( 'CD_APD_Core' ) )
+{
+
/**
- * The central API: registers a new plugin directory
+ * Core
*
- * @since 0.1
- * @param $key The plugin directory key. Used internally in the plugin list table and to save options.
- * @param $dir The new plugin directory. Either a full path or a folder name within wp-content.
- * @param $label The nice name of the plugin directory. Presented in the list table
+ * @author Christopher Davis, Franz Josef Kaiser
+ * @license GPL
+ * @copyright © Christopher Davis, Franz Josef Kaiser 2011-2012
+ *
+ * @package WordPress
+ * @subpackage Additional Plugin Directories: Core
*/
-function register_plugin_directory( $key, $dir, $label )
+class CD_APD_Core
{
- global $wp_plugin_directories;
-
- empty( $wp_plugin_directories ) AND $wp_plugin_directories = array();
-
- if ( ! file_exists( $dir ) AND file_exists( trailingslashit( WP_CONTENT_DIR ) . $dir ) )
+ /**
+ *
+ */
+ public function __construct()
{
- $dir = trailingslashit( WP_CONTENT_DIR ) . $dir;
+ add_action( 'plugins_loaded', array( $this, 'load_plugins' ), 99 );
}
- $wp_plugin_directories[ $key ] = array(
- 'label' => $label,
- 'dir' => $dir
- );
-}
-
-add_action( 'plugins_loaded', 'cd_apd_load_more', 99 );
-/**
- * Loads additional plugins from custom directories. To add a directory,
- * you must do so in a plugin (hooked into `plugins_loaded` with a low
- * priority
- */
-function cd_apd_load_more()
-{
- global $wp_plugin_directories;
-
- empty( $wp_plugin_directories ) AND $wp_plugin_directories = array();
- foreach ( array_keys( $wp_plugin_directories ) as $key )
+ /**
+ * Loads additional plugins from custom directories.
+ * To add a directory, you must do so in a plugin (hooked into `plugins_loaded` with a low priority).
+ *
+ * @since 0.1
+ * @return void
+ */
+ public function load_plugins()
{
- $active = get_option( "active_plugins_{$key}", array() );
- foreach( $active as $a )
+ global $wp_plugin_directories;
+
+ empty( $wp_plugin_directories ) AND $wp_plugin_directories = array();
+
+ foreach ( array_keys( $wp_plugin_directories ) as $key )
{
- if ( file_exists( "{$wp_plugin_directories[ $key ]['dir']}/{$a}" ) )
+ $active = get_option( "active_plugins_{$key}", array() );
+ foreach( $active as $a )
{
- include_once( "{$wp_plugin_directories[ $key ]['dir']}/{$a}" );
+ if ( file_exists( "{$wp_plugin_directories[ $key ]['dir']}/{$a}" ) )
+ {
+ include_once( "{$wp_plugin_directories[ $key ]['dir']}/{$a}" );
+ }
}
}
}
-}
-/**
- * Get the valid plugins from the custom directory
- *
- * @since 0.1
- * @param $dir_key The `key` of our custom plugin directory
- * @return array A list of the plugins
- */
-function cd_apd_get_plugins( $dir_key )
-{
- global $wp_plugin_directories;
+ /**
+ * Get the valid plugins from the custom directory
+ *
+ * @since 0.1
+ * @param $dir_key The `key` of our custom plugin directory
+ * @return array A list of the plugins
+ */
+ public function get_plugins_from_cache( $dir_key )
+ {
+ global $wp_plugin_directories;
- // invalid dir key? bail
- if ( ! isset( $wp_plugin_directories[ $dir_key ] ) )
- return array();
+ // invalid dir key? bail
+ if ( ! isset( $wp_plugin_directories[ $dir_key ] ) )
+ return array();
- $plugin_root = $wp_plugin_directories[ $dir_key ]['dir'];
+ $plugin_root = $wp_plugin_directories[ $dir_key ]['dir'];
- if ( ! $cache_plugins = wp_cache_get( 'plugins', 'plugins') )
- $cache_plugins = array();
+ if ( ! $cache_plugins = wp_cache_get( 'plugins', 'plugins') )
+ $cache_plugins = array();
- if ( isset( $cache_plugins[ $dir_key ] ) )
- return $cache_plugins[ $dir_key ];
+ if ( isset( $cache_plugins[ $dir_key ] ) )
+ return $cache_plugins[ $dir_key ];
- $wp_plugins = array();
+ $wp_plugins = array();
- $plugins_dir = @ opendir( $plugin_root );
- $plugin_files = array();
- if ( $plugins_dir ) {
- while ( ( $file = readdir( $plugins_dir ) ) !== false ) {
- if ( substr($file, 0, 1) == '.' )
- continue;
- if ( is_dir( "{$plugin_root}/{$file}" ) ) {
- $plugins_subdir = @ opendir( "{$plugin_root}/{$file}" );
- if ( $plugins_subdir ) {
- while ( ( $subfile = readdir( $plugins_subdir ) ) !== false ) {
- if ( substr($subfile, 0, 1) == '.' )
- continue;
- if ( substr($subfile, -4) == '.php' )
- $plugin_files[] = "{$file}/{$subfile}";
+ $plugins_dir = @ opendir( $plugin_root );
+ $plugin_files = array();
+ if ( $plugins_dir )
+ {
+ while ( false !== ( $file = readdir( $plugins_dir ) ) )
+ {
+ if ( '.' === substr( $file, 0, 1 ) )
+ continue;
+
+ if ( is_dir( "{$plugin_root}/{$file}" ) )
+ {
+ $plugins_subdir = @ opendir( "{$plugin_root}/{$file}" );
+ if ( $plugins_subdir )
+ {
+ while ( ( $subfile = readdir( $plugins_subdir ) ) !== false )
+ {
+ if ( '.' === substr( $subfile, 0, 1 ) )
+ continue;
+
+ if ( '.php' === substr( $subfile, -4 ) )
+ $plugin_files[] = "{$file}/{$subfile}";
+ }
+ closedir( $plugins_subdir );
}
- closedir( $plugins_subdir );
}
- } else {
- '.php' === substr( $file, -4 ) AND $plugin_files[] = $file;
+ else
+ {
+ '.php' === substr( $file, -4 ) AND $plugin_files[] = $file;
+ }
}
+ closedir( $plugins_dir );
}
- closedir( $plugins_dir );
- }
- if ( empty( $plugin_files ) )
- return $wp_plugins;
+ if ( empty( $plugin_files ) )
+ return $wp_plugins;
- foreach ( $plugin_files as $plugin_file ) {
- if ( ! is_readable( "{$plugin_root}/{$plugin_file}" ) )
- continue;
+ foreach ( $plugin_files as $plugin_file )
+ {
+ if ( ! is_readable( "{$plugin_root}/{$plugin_file}" ) )
+ continue;
- // Do not apply markup/translate as it'll be cached.
- $plugin_data = get_plugin_data( "{$plugin_root}/{$plugin_file}", false, false );
+ // Do not apply markup/translate as it'll be cached.
+ $plugin_data = get_plugin_data( "{$plugin_root}/{$plugin_file}", false, false );
- if ( empty ( $plugin_data['Name'] ) )
- continue;
+ if ( empty ( $plugin_data['Name'] ) )
+ continue;
- $wp_plugins[ trim( $plugin_file ) ] = $plugin_data;
- }
+ $wp_plugins[ trim( $plugin_file ) ] = $plugin_data;
+ }
- uasort( $wp_plugins, '_sort_uname_callback' );
+ uasort( $wp_plugins, '_sort_uname_callback' );
- $cache_plugins[ $dir_key ] = $wp_plugins;
- wp_cache_set( 'plugins', $cache_plugins, 'plugins' );
+ // Setup cache, if we ain't already got one.
+ // If we got one, we already returned the cached plugins.
+ $cache_plugins[ $dir_key ] = $wp_plugins;
+ wp_cache_set( 'plugins', $cache_plugins, 'plugins' );
- return $wp_plugins;
-}
+ return $wp_plugins;
+ }
-/**
- * Custom plugin activation function.
- */
-function cd_apd_activate_plugin( $plugin, $context, $silent = false )
-{
- $plugin = trim( $plugin );
+ /**
+ * Custom plugin activation function.
+ *
+ * @since 0.1
+ * @return void
+ */
+ public function activate_plugin( $plugin, $context, $silent = false )
+ {
+ $plugin = trim( $plugin );
- $redirect = add_query_arg( 'plugin_status', $context, admin_url( 'plugins.php' ) );
- $redirect = apply_filters( 'custom_plugin_redirect', $redirect );
+ $redirect = add_query_arg( 'plugin_status', $context, admin_url( 'plugins.php' ) );
+ $redirect = apply_filters( 'custom_plugin_redirect', $redirect );
- $current = get_option( "active_plugins_{$context}", array() );
+ $current = get_option( "active_plugins_{$context}", array() );
- $valid = cd_apd_validate_plugin( $plugin, $context );
+ $valid = $this->validate_plugin( $plugin, $context );
- if ( is_wp_error( $valid ) )
- return $valid;
+ if ( is_wp_error( $valid ) )
+ return $valid;
- if ( ! in_array( $plugin, $current ) ) {
- if ( ! empty( $redirect ) )
+ if ( ! in_array( $plugin, $current ) )
{
- // we'll override this later if the plugin can be included without fatal error
- wp_redirect( add_query_arg(
- '_error_nonce'
- ,wp_create_nonce( "plugin-activation-error_{$plugin}" )
- ,$redirect
- ) );
- }
+ if ( ! empty( $redirect ) )
+ {
+ // we'll override this later if the plugin can be included without fatal error
+ wp_redirect( add_query_arg(
+ '_error_nonce'
+ ,wp_create_nonce( "plugin-activation-error_{$plugin}" )
+ ,$redirect
+ ) );
+ }
- ob_start();
- include_once( $valid );
+ ob_start();
+ include_once( $valid );
- if ( ! $silent ) {
- do_action( 'custom_activate_plugin', $plugin, $context );
- do_action( "custom_activate_{$plugin}", $context );
- }
+ if ( ! $silent )
+ {
+ do_action( 'custom_activate_plugin', $plugin, $context );
+ do_action( "custom_activate_{$plugin}", $context );
+ }
- $current[] = $plugin;
- sort( $current );
- update_option( "active_plugins_{$context}", $current );
+ $current[] = $plugin;
+ sort( $current );
+ update_option( "active_plugins_{$context}", $current );
- if ( ! $silent ) {
- do_action( 'custom_activated_plugin', $plugin, $context );
- }
+ if ( ! $silent )
+ {
+ do_action( 'custom_activated_plugin', $plugin, $context );
+ }
- if ( ob_get_length() > 0 ) {
- $output = ob_get_clean();
- return new WP_Error( 'unexpected_output', __( 'The plugin generated unexpected output.' ), $output );
+ if ( ob_get_length() > 0 )
+ {
+ $output = ob_get_clean();
+ return new WP_Error( 'unexpected_output', __( 'The plugin generated unexpected output.' ), $output );
+ }
+ ob_end_clean();
}
- ob_end_clean();
+
+ return true;
}
- return true;
-}
+ /**
+ * Deactivate custom plugins
+ *
+ * @since 0.1
+ * @return void
+ */
+ public function deactivate_plugins( $plugins, $context, $silent = false )
+ {
+ $current = get_option( "active_plugins_{$context}", array() );
-/**
- * Deactivate custom plugins
- */
-function cd_apd_deactivate_plugins( $plugins, $context, $silent = false ) {
- $current = get_option( "active_plugins_{$context}", array() );
+ foreach ( (array) $plugins as $plugin )
+ {
+ $plugin = trim( $plugin );
+ if ( ! in_array( $plugin, $current ) ) continue;
- foreach ( (array) $plugins as $plugin )
- {
- $plugin = trim( $plugin );
- if ( ! in_array( $plugin, $current ) ) continue;
+ if ( ! $silent )
+ do_action( 'custom_deactivate_plugin', $plugin, $context );
- if ( ! $silent )
- do_action( 'custom_deactivate_plugin', $plugin, $context );
+ $key = array_search( $plugin, $current );
+ if ( false !== $key )
+ {
+ array_splice( $current, $key, 1 );
+ }
- $key = array_search( $plugin, $current );
- if ( false !== $key ) {
- array_splice( $current, $key, 1 );
+ if ( ! $silent )
+ {
+ do_action( "custom_deactivate_{$plugin}", $context );
+ do_action( 'custom_deactivated_plugin', $plugin, $context );
+ }
}
- if ( ! $silent ) {
- do_action( "custom_deactivate_{$plugin}", $context );
- do_action( 'custom_deactivated_plugin', $plugin, $context );
- }
+ update_option( "active_plugins_{$context}", $current );
}
- update_option( "active_plugins_{$context}", $current );
-}
-
-/**
- * Checks to see whether the plugin and is valid and can be activated.
- *
- * @uses validate_file To make sure the plugin name is okay.
- * @return WP_Error|string WP_Error object on failure, the plugin to include on success.
- */
-function cd_apd_validate_plugin( $plugin, $context )
-{
- $rv = true;
- if ( validate_file( $plugin ) )
+ /**
+ * Checks to see whether the plugin and is valid and can be activated.
+ *
+ * @uses validate_file To make sure the plugin name is okay.
+ * @param string $plugin
+ * @return array $context
+ * @return WP_Error|string WP_Error object on failure, the plugin to include on success.
+ */
+ public function validate_plugin( $plugin, $context )
{
- $rv = new WP_Error( 'plugin_invalid', __( 'Invalid plugin path.' ) );
- }
+ $rv = true;
+ if ( validate_file( $plugin ) )
+ {
+ $rv = new WP_Error( 'plugin_invalid', __( 'Invalid plugin path.' ) );
+ }
- global $wp_plugin_directories;
+ global $wp_plugin_directories;
- if ( ! isset( $wp_plugin_directories[ $context ] ) )
- {
- $rv = new WP_Error( 'invalid_context', __( 'The context for this plugin does not exist' ) );
- }
+ if ( ! isset( $wp_plugin_directories[ $context ] ) )
+ {
+ $rv = new WP_Error( 'invalid_context', __( 'The context for this plugin does not exist' ) );
+ }
- $dir = $wp_plugin_directories[ $context ]['dir'];
- if ( ! file_exists( "{$dir}/{$plugin}" ) )
- {
- $rv = new WP_Error( 'plugin_not_found', __( 'Plugin file does not exist.' ) );
- }
+ $dir = $wp_plugin_directories[ $context ]['dir'];
+ if ( ! file_exists( "{$dir}/{$plugin}" ) )
+ {
+ $rv = new WP_Error( 'plugin_not_found', __( 'Plugin file does not exist.' ) );
+ }
- $installed_plugins = cd_apd_get_plugins( $context );
- if ( ! isset( $installed_plugins[ $plugin ] ) )
- {
- $rv = new WP_Error( 'no_plugin_header', __('The plugin does not have a valid header.') );
+ $installed_plugins = $this->get_plugins_from_cache( $context );
+ if ( ! isset( $installed_plugins[ $plugin ] ) )
+ {
+ $rv = new WP_Error( 'no_plugin_header', __('The plugin does not have a valid header.') );
+ }
+
+ $rv = "{$dir}/{$plugin}";
+
+ return $rv;
}
+} // END Class CD_APD_Core
- $rv = "{$dir}/{$plugin}";
- return $rv;
-}
+} // endif;
View
22 js/apd.js
@@ -1,10 +1,14 @@
-jQuery(document).ready(function($){
- $('li.all a').removeClass('current').find('span.count').html('(' + cd_apd.count + ')');
- $('.wp-list-table.plugins tr').each(function(){
- var is_active = $(this).find('a.cd-apd-deactivate');
- if(is_active.length) {
- $(this).removeClass('inactive').addClass('active');
- $(this).find('div.plugin-version-author-uri').removeClass('inactive').addClass('active');
+jQuery( document ).ready( function($)
+{
+ // Add the count
+ $( 'li.all a' ).removeClass( 'current' ).find( 'span.count' ).html( '(' + cd_apd.count + ')' );
+ $( '.wp-list-table.plugins tr' ).each( function()
+ {
+ var is_active = $( this ).find( 'a.cd-apd-deactivate' );
+ if ( is_active.length )
+ {
+ $( this ).removeClass( 'inactive' ).addClass( 'active' );
+ $( this ).find( 'div.plugin-version-author-uri' ).removeClass( 'inactive' ).addClass( 'active' );
}
- });
-});
+ } );
+} );
View
20 plugin-dirs.php
@@ -1,22 +1,24 @@
<?php
-! defined( 'ABSPATH' ) && exit();
+! defined( 'ABSPATH' ) AND exit();
/*
-Plugin Name: Additional Plugin Directories
-Plugin URI: http://github.com/chrisguitarugy
-Description: A framework for adding additional plugin directories to WordPress
-Version: 0.1
-Author: Christopher Davis
-Author URI: http://christopherdavis.me
-License: GPL2
+Plugin Name: Additional Plugin Directories
+Plugin URI: http://github.com/chrisguitarguy
+Description: A framework to allow adding additional plugin directories to WordPress
+Version: 0.6
+Author: Christopher Davis
+Contributors: Franz Josef Kaiser, Julien Chaumond
+Author URI: http://christopherdavis.me
+License: GPL2
*/
define( 'CD_APD_PATH', plugin_dir_path( __FILE__ ) );
define( 'CD_APD_URL', plugin_dir_url( __FILE__ ) );
+require_once( CD_APD_PATH.'inc/api.php' );
require_once( CD_APD_PATH.'inc/core.php' );
-if( is_admin() )
+if ( is_admin() )
{
require_once( CD_APD_PATH.'inc/admin.php' );
}
View
21 readme.md
@@ -2,3 +2,24 @@ Add Plugin Directories to WordPress
===================================
A work in progress related to a [WordPress stack exchange question](http://wordpress.stackexchange.com/questions/43262/add-multiple-plugin-directories).
+
+
+EXAMPLE
+
+For an example, take a look at the `example_plugin` folder and the `register_addt_plugins_dir.php` file.
+
+You need to copy this folder to your actual plugins folder and then activate it from within your plugins list. It only works if the main plugin is activated.
+
+*) the one you defined with the `WP_PLUGIN_DIR` or `WPMU_PLUGIN_DIR` in your wp-config.php file - or the default `plugins` folder in your install.
+
+
+CHANGELOG
+
+0.1 Initial version
+0.2 Clean Up & code styling alignment
+0.3 Minor styling fixes
+0.4 Moved to OOP concept
+0.5 Improved API - now supports different plugin locations aside from the `WP_CONTENT_DIR`.
+0.5.1 Minor fix for left over debug code
+0.5.2 JS styling for readability
+0.6 Removed "activate" link when plugin is already active, as suggested by Julien Chaumond in Issue #3
Something went wrong with that request. Please try again.