WP Smith

Creating WordPress & Genesis Websites Since 2010

  • Home
  • About
  • Services
  • Blog
  • Contact

Sep 23 2015

Extending Any Plugin Properly

Extending Outline
  • Potential Problems & Requirements
  • Demonstration
  • Example Usage
  • WPS_Plugin_Extend Class

For many one-off development projects and almost all full website development projects, I often extend plugins. Most people place these extensions inside their functions.php file cluttering the file with all sorts of code. I prefer to separate my code base into parts that make sense. For example, if I am hooking into a Gravity Forms, even for only one hook, I create an extension plugin (e.g., Gravity Forms - Customizing Notifications).

For clarification purposes, let me define a couple of terms: extension plugin and dependency plugin.

Extension Plugin
A plugin that extends or increases the scope or application of another plugin (e.g., Gravity Forms - Date Range Field).

Dependency Plugin
A plugin that is dependent upon another plugin or needs another plugin for support or operation (e.g., Gravity Forms).

Potential Problems & Requirements

Creating an extension plugin that is dependent on a dependency plugin creates some potential problems. Some of these problems could be:

  • White Screen of Death: Site breaks because of a missing function and/or class and the developer forgot to check whether the function or class exists (e.g., class_exists( 'My_Dependent_Class' ) or function_exists( 'my_dependent_function' )).
  • The extension plugin doesn't deactivate when dependency plugin deactivates resulting in additional overhead or code bloating.
  • The extension plugin is activated before the dependency plugin is activated, but WordPress says the plugin was activated.

To prevent these issues, we would like to:

  • Prevent the activation of the extension plugin if the dependency plugin is not activated.
  • .

  • Auto-deactivate the extension plugin if the dependency plugin is deactivated.
  • Notify the user that the plugin has been deactivated and the reason why it has been deactivated to improve the user experience.,

So, I have a class that is part of my development framework called WPS_Extend_Plugin that makes this a piece of cake.

Demonstration

For demonstration purposes, I am going to extend Gravity Forms to create a new field called Date Range (plugin named: Gravity Forms - Date Range). My requirements are simple:

  • I do not want to have this plugin activated without Gravity Forms activated.
  • I want the plugin to auto-deactivate if Gravity Forms is deactivated.
  • I want the user to know what happened

The Plugin Setup

As you can see from the screen capture are both of my plugins are not activated.
Extending Any Plugin Example Both Plugins Deactivated

Activating the Extension Plugin without the Dependency Plugin Activated

In the example below, I activate the extension plugin without the dependency being activated. This will create two error notifications: one in the admin notices area and the other on the plugin row. However, as you can see WordPress does not "check" to see if the plugin actually activated. Instead, WordPress assumes the plugin was activated and outputs the activation message.
Extending Any Plugin Example Activating the Extension Plugin Alone

Activating the Dependency Plugin and Extension Plugin Properly

In this example, I activate both plugins "normally" and "properly" where I activate the dependency first and then the extension plugin second. Everything works as expected.
Extending Any Plugin Example Activating the Dependency Plugin First
Extending Any Plugin Example Activating the Extension Plugin Second

Activating the Extension Plugin without the Correct Dependency Plugin Version

In the example below, I activate the extension plugin without the proper dependency plugin version being activated. As you can see the dependency plugin exists and is activated; however, I have marked the extension plugin to depend on a version greater than the version that is activated. This too will create two error notifications: one in the admin notices area and the other on the plugin row. However, as you can see WordPress does not "check" to see if the plugin actually activated. Instead, WordPress assumes the plugin was activated and outputs the activation message.
Extending Any Plugin Example Activating the Extension Plugin with Wrong Version of Dependency Plugin

Usage

Using this class is quite simple. Just add it to your plugin in whatever directory and require the file.

// Require WPS_Extend_Plugin class
require_once( 'classes/WPS_Extend_Plugin.php' );

Then if you want to require a plugin, just instantiate the class. Here are two examples of extending Gravity Forms and AddThis.

// Extend Gravity Forms
new WPS_Extend_Plugin( 'gravityforms/gravityforms.php', __FILE__, '1.9', 'my-plugin-text-domain' );
// Extend AddThis
new WPS_Extend_Plugin( 'addthis/addthis_social_widget.php', __FILE__, '1.9.13', 'my-plugin-text-domain' );

If you would like to require more than one plugin at a time, you can use my function wps_extend_plugins:

if ( !function_exists( 'wps_extend_plugins' ) ) {
/**
* Determines whether the plugins are active and available taking appropriate action if not.
*
* @since Version 1.0.0
* @author Travis Smith <[email protected]>
*
* @see WPS_Extend_Plugin
*
* @param array $plugins
* @param string $root_file Plugin basename, File reference path to root including filename.
* @param string|null $text_domain Text domain.
*/
function wps_extend_plugins( $plugins, $root_file, $text_domain = null ) {
$plugin_extensions = array();
foreach ( $plugins as $plugin => $min_version ) {
$plugin_extensions[ $plugin ] = new WPS_Extend_Plugin( $plugin, $root_file, $min_version, $text_domain );
}
}
}

This function can be used like this:

// Extend Jetpack, Gravity Forms, Display Posts Shortcode, Soliloquy
wps_extend_plugins( array(
'gravityforms/gravityforms.php' => '1.9',
'display-posts-shortcode/display-posts-shortcode.php' => '2.5',
'jetpack/jetpack.php' => '3.7',
'soliloquy/soliloquy.php' => '2.4.3',
), __FILE__, 'my-plugin-text-domain' )

The Class

<?php
/**
* Contains WPS_Extend_Plugin class. and wps_extend_plugins function.
*
* @package WPS_Core
* @author Travis Smith <[email protected]>
* @copyright 2015 WP Smith, Travis Smith
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
* @version 1.0.0
* @since File available since Release 1.0.0
*/
if ( !class_exists( 'WPS_Extend_Plugin' ) ) {
/**
* Class WPS_Extend_Plugin
*
* Extends an existing plugin.
*
* @since Version 1.0.0
* @author Travis Smith <[email protected]>
*
*/
class WPS_Extend_Plugin {
/**
* Dependent plugin name, plugin relative path (e.g., 'addthis/addthis_social_widget.php' )
*
* @var string|array
*/
private $plugin = '';
/**
* Action being performed on plugins page.
*
* @var string
*/
private $action = '';
/**
* Minimum version of dependent plugin required.
* @var string
*/
private $min_version;
/**
* Reference to the current plugin's root.
* The full path and filename of the file with symlinks resolved.
*
* @var string
*/
private $root_file = __FILE__;
/**
* Text domain.
*
* @var string
*/
public $text_domain = 'wps';
/**
* Message to be displayed.
*
* @var string
*/
public $message = '';
/**
* Plugin data.
*
* @var array
*/
public $plugin_data = array();
/**
* Transient name.
*
* @var string
*/
private $transient = '';
/**
* Constructor
*
* @param string $plugin Plugin activation "slug"
* @param string $root_file Plugin basename, File reference path to root including filename.
* @param string|null $min_version Minimum version allowed.
* @param string|null $text_domain Text domain.
*/
public function __construct( $plugin, $root_file, $min_version = null, $text_domain = null ) {
// Setup
$this->plugin = $plugin;
$this->root_file = $root_file;
$this->min_version = $min_version ? $min_version : $this->min_version;
$this->text_domain = $text_domain ? $text_domain : $this->text_domain;
$this->transient = substr( 'wpsep-' . plugin_basename( $root_file ), 0, 40 );
/*
* Cannot add a notice since plugin has been deactivated
* Add notice since WP always seems to assume that the plugin was updated.
* Cannot use 'deactivate_' . $plugin hook as it does not fire if plugin is silently deactivated (such as during an update)
*/
if ( 'plugins.php' === basename( $_SERVER['PHP_SELF'] ) && ! ( defined( 'WP_CLI' ) && WP_CLI ) ) {
$this->set_action_type();
// Add admin notice
add_action( 'admin_notices', array( $this, 'admin_notice' ) );
// Late Deactivation so we can output the notifications
add_filter( 'plugin_action_links_' . $plugin, array( $this, 'plugin_action_links_maybe_deactivate' ) );
add_filter( 'network_admin_plugin_action_links_' . $plugin, array( $this, 'plugin_action_links_maybe_deactivate' ) );
// Fix Current Plugin Action Links
add_filter( 'plugin_action_links_' . plugin_basename( $root_file ), array( $this, 'plugin_action_links' ), 10, 4 );
add_filter( 'network_admin_plugin_action_links_' . plugin_basename( $root_file ), array( $this, 'plugin_action_links' ), 10, 4 );
// Add notice on Plugin Row
add_action( 'after_plugin_row_' . plugin_basename( $root_file ), array( $this, 'plugin_row' ) );
} else {
// Maybe deactivate on update of active_plugins and active_sitewide_plugins options
// deactivated_plugin action and deactivate_ . $plugin do not fire if plugin is being deactivated silently
add_action( 'update_option_active_sitewide_plugins', array( $this, 'maybe_deactivate' ), 10, 2 );
add_action( 'update_option_active_plugins', array( $this, 'maybe_deactivate' ), 10, 2 );
}
}
/**
* Conditional helper function to determine which generic action is being taken.
*
* @param string $action Action ('activate' or 'deactivate').
*
* @return bool Whether performing an activation action or deactivation action.
*/
private function is_action( $action ) {
if ( 'activate' === $action ) {
return ( 'activate' === $this->action || 'activate-multi' === $this->action );
}
if ( 'deactivate' === $action ) {
return ( 'deactivate' === $this->action || 'deactivate-multi' === $this->action );
}
return false;
}
/**
* Sets the action being taken by the plugins.php page.
*/
private function set_action_type() {
if ( isset( $_REQUEST['deactivate-multi'] ) && $_REQUEST['deactivate-multi'] ) {
$this->action = 'deactivate-multi';
} elseif ( isset( $_REQUEST['activate-multi'] ) && $_REQUEST['activate-multi'] ) {
$this->action = 'activate-multi';
} elseif ( isset( $_REQUEST['deactivate'] ) && $_REQUEST['deactivate'] ) {
$this->action = 'deactivate';
} elseif ( isset( $_REQUEST['activate'] ) && $_REQUEST['activate'] ) {
$this->action = 'activate';
}
}
/**
* Maybe fix the action links as WordPress believes the plugin is active when it may have been deactivated.
*
* @param array $actions An array of plugin action links.
* @param string $plugin_file Path to the plugin file.
* @param array $plugin_data An array of plugin data.
* @param string $context The plugin context. Defaults are 'All', 'Active',
* 'Inactive', 'Recently Activated', 'Upgrade',
* 'Must-Use', 'Drop-ins', 'Search'.
*
* @return array $actions Maybe an array of modified plugin action links.
*/
public function plugin_action_links_maybe_deactivate( $actions ) {
if ( ! $this->is_active() ) {
self::deactivate_self( $this->root_file );
}
return $actions;
}
/**
* Maybe fix the action links as WordPress believes the plugin is active when it may have been deactivated.
*
* @param array $actions An array of plugin action links.
* @param string $plugin_file Path to the plugin file.
* @param array $plugin_data An array of plugin data.
* @param string $context The plugin context. Defaults are 'All', 'Active',
* 'Inactive', 'Recently Activated', 'Upgrade',
* 'Must-Use', 'Drop-ins', 'Search'.
*
* @return array $actions Maybe an array of modified plugin action links.
*/
public function plugin_action_links( $actions, $plugin_file, $plugin_data, $context ) {
if ( ! $this->is_active() ) {
if ( isset( $actions['deactivate'] ) ) {
$params = self::get_url_params( $actions['deactivate'] );
$params = wp_parse_args( $params, array( 's' => '', ) );
unset( $actions['deactivate'] );
// Change action link deactivate to activate
$screen = get_current_screen();
if ( $screen->in_admin( 'network' ) ) {
if ( current_user_can( 'manage_network_plugins' ) ) {
/* translators: %s: plugin name */
$actions['activate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $params['paged'] . '&amp;s=' . $params['s'], 'activate-plugin_' . $plugin_file ) . '" class="edit" aria-label="' . esc_attr( sprintf( __( 'Network Activate %s' ), $plugin_data['Name'] ) ) . '">' . __( 'Network Activate' ) . '</a>';
}
if ( current_user_can( 'delete_plugins' ) ) {
/* translators: %s: plugin name */
$actions['delete'] = '<a href="' . wp_nonce_url( 'plugins.php?action=delete-selected&amp;checked[]=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $params['paged'] . '&amp;s=' . $params['s'], 'bulk-plugins' ) . '" class="delete" aria-label="' . esc_attr( sprintf( __( 'Delete %s' ), $plugin_data['Name'] ) ) . '">' . __( 'Delete' ) . '</a>';
}
} else {
/* translators: %s: plugin name */
$actions['activate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $params['paged'] . '&amp;s=' . $params['s'], 'activate-plugin_' . $plugin_file ) . '" class="edit" aria-label="' . esc_attr( sprintf( __( 'Activate %s', $this->text_domain ), $plugin_data['Name'] ) ) . '">' . __( 'Activate', $this->text_domain ) . '</a>';
if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) {
/* translators: %s: plugin name */
$actions['delete'] = '<a href="' . wp_nonce_url( 'plugins.php?action=delete-selected&amp;checked[]=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $params['paged'] . '&amp;s=' . $params['s'], 'bulk-plugins' ) . '" class="delete" aria-label="' . esc_attr( sprintf( __( 'Delete %s', $this->text_domain ), $plugin_data['Name'] ) ) . '">' . __( 'Delete', $this->text_domain ) . '</a>';
}
}
}
}
return $actions;
}
/**
* Outputs an admin notice if plugin is trying to be activated when dependent plugin is not activated.
*/
public function admin_notice() {
if ( ! $this->is_active() ) {
printf( '<div class="error notice is-dismissible"><p class="extension-message">%s</p></div>', $this->get_message() );
}
}
/**
* Deactivate ourself if dependent plugin is deactivated.
*
* @param mixed $old_value The old option value.
* @param mixed $value The new option value.
*/
public function maybe_deactivate( $old_value, $value ) {
if ( ! $this->is_active() ) {
self::deactivate_self( $this->root_file );
if ( defined( 'WP_CLI' ) && WP_CLI ) {
WP_CLI::error( $this->get_message( 'deactivate' ) );
}
}
}
public function recently_activated( $value, $old_value ) {
//$this->pr( $old_value, '$old_value' );
//$this->pr( $value, '$value' );
$current = array_diff_key( $value, $old_value );
//$this->pr( $current, '$current' );
//wp_die();
// Check if our plugin was just now deactivated
if ( isset( $current[ $this->plugin ] ) ) {
$this->set_transient( 'was_active', 1 );
}
return $value;
}
/**
* Returns the message to be displayed.
*
* @return string Message
*/
private function get_message() {
return $this->message;
}
/**
* Sets the message based on the needed notification type.
*
* @param string $type Notification type (deactivate, activate, update).
*/
private function set_message( $type ) {
$dependency = $this->get_plugin_data( 'Name' ) ? $this->get_plugin_data( 'Name' ) : $this->plugin;
switch ( $type ) {
case 'deactivate':
$current = $this->get_plugin_data( 'Name', 'current' ) ? $this->get_plugin_data( 'Name', 'current' ) : plugin_basename( $this->root_file );
$this->message = sprintf(
__( '%1$s (v%2$s) is required for %3$s. Deactivating %3$s.', $this->text_domain ),
$dependency,
$this->min_version,
$current
);
break;
case 'upgrade':
case 'update':
case 'activate':
default:
if ( 'update' === $type || 'upgrade' === $type || !$this->is_plugin_at_min_version() ) {
$action = 'update';
} else {
$action = 'activate';
}
$this->message = sprintf(
__( '%s (v%s) is required. Please %s it before activating this plugin.', $this->text_domain ),
$dependency,
$this->min_version,
$action
);
break;
}
}
/**
* Returns the plugin data.
*
* @param null|string $attr Specific data to return.
* @param null|string $plugin Specific plugin to return plugin_data.
*
* @return string|array Specific attribute value or all values.
*/
private function get_plugin_data( $attr = null, $plugin = null ) {
// Default to dependency plugin
if ( ! $plugin || 'dependency' === $plugin ) {
$plugin = $this->plugin;
$plugin_path = trailingslashit( plugin_dir_path( dirname( $this->root_file ) ) ) . $this->plugin;
// Allow current plugin_data to be returned
} elseif ( 'current' === $plugin ) {
$plugin = plugin_basename( $this->root_file );
$plugin_path = plugin_dir_path( dirname( $this->root_file ) ) . plugin_basename( $this->root_file );
// Un-supported plugin request, do nothing
} else {
return array();
}
// Maybe get fresh plugin_data
if ( ! isset( $this->plugin_data[ $plugin ] ) || ( isset( $this->plugin_data[ $plugin ] ) && ! $this->plugin_data[ $plugin ] ) ) {
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
$this->plugin_data = get_plugin_data( $plugin_path, false, false );
}
// Maybe return specific attribute
if ( $attr && isset( $this->plugin_data[ $attr ] ) ) {
return $this->plugin_data[ $attr ];
}
// Return everything
return $this->plugin_data;
}
/**
* Returns an array of parameters from HTML markup containing a link.
*
* @param string $text HTML to be parsed.
*
* @return array Associative array of parameters and values.
*/
private static function get_url_params( $text ) {
// Capture parameters
preg_match( "/<a\s[^>]*href=\"([^\"]*)\"[^>]*>(.*)<\/a>/", $text, $output );
if ( $output ) {
preg_match_all( '/([^?&=#]+)=([^&#]*)/', html_entity_decode( urldecode( $output[1] ) ), $m );
//combine the keys and values onto an assoc array
return array_combine( $m[1], $m[2] );
}
return array();
}
/**
* Deactivates the plugin.
*
* Function attempts to determine whether to deactivate extension plugin based on whether the depdendent
* plugin is active or not.
*
* @uses deactivate_plugins Deactivate a single plugin or multiple plugins.
*
* @param string $file Single plugin or list of plugins to deactivate.
* @param mixed $network_wide Whether to deactivate the plugin for all sites in the network.
* A value of null (the default) will deactivate plugins for both the site and the
* network.
*/
public static function deactivate_self( $file, $network_wide = false ) {
if ( is_multisite() && false !== $network_wide ) {
$network_wide = is_plugin_active_for_network( $file );
}
deactivate_plugins( plugin_basename( $file ), true, $network_wide );
}
/**
* Checks whether the dependent plugin(s) is/are active by checking the active_plugins list.
*
* @return bool Whether the dependent plugin is active.
*/
public function is_active() {
$active = true;
// Check Plugin Active
if ( ! is_plugin_active( $this->plugin ) ) {
if ( $this->is_action( 'activate' ) ) {
$this->set_message( 'activate' );
} elseif ( $this->is_action( 'deactivate' ) ) {
$this->set_message( 'deactivate' );
}
return false;
}
// Plugin Active, Check Version
if ( ! $this->is_plugin_at_min_version() ) {
$this->set_message( 'update' );
return false;
}
// Maybe remove was_active transient
// if ( $active ) {
// $this->delete_transient( 'was_active' );
// }
// All Good!
return $active;
}
/**
* Determins whether the given plugin is at the minimum version.
*
* @return bool Whether the plugin is at the minimum version.
*/
private function is_plugin_at_min_version() {
if ( ! $this->min_version ) {
return true;
}
return ( floatval( $this->get_plugin_data( 'Version' ) ) >= floatval( $this->min_version ) );
}
/**
* Adds a notice to the plugin row to inform the user of the dependency.
*/
public function plugin_row() {
if ( ! $this->is_active() ) {
printf( '</tr><tr class="plugin-update-tr"><td colspan="5" class="plugin-update"><div class="update-message" style="background-color: #ffebe8;">%s</div></td>', $this->get_message() );
}
}
}
}
view raw WPS_Extend_Plugin.php hosted with ❤ by GitHub

Known Issues/To Do Item

WordPress outputs a message "Plugin reactivated successfully." regardless of whether the plugin was activated or not, since activate_plugin() does not return a Boolean response based on whether the plugin was actually activated (activate_plugin() always returns null or a WP_Error). I hope to fix this in a future revision (most likely via inline JavaScript as I want to keep everything contained within the class).

Written by Travis Smith · Categorized: Plugins

Feb 13 2014

SQL WordPress Plugins: Accessing the Database from within WordPress

In some sites more than others, I will find myself spending more time in the database or SQL side of the site as this makes for an incredibly efficient method to updating, restoring, or fixing data as opposed to using the WordPress admin interface. Sometimes you, too, may be forced to access the database directly, if you accidentally changed something like Home or Site URL (phpMyAdmin is awesome for this).

However, what if you have a client and they did not give you SQL access? What if your client does not have cPanel or phpMyAdmin? There are a variety of tools (i.e., WordPress plugins) available for you to do database stuff from WordPress (though not as fast per se).

Check out these plugins:

  1. MyWebSql: Allows editing/managing the WordPress database directly from within the admin panel, just like phpMyAdmin. Note, this needs the bcmath PHP extension as well as gmp & openssl extensions. If you don't have these extensions, try changing SECURE_LOGIN to false as directed here.
    WordPress SQL Plugin: MyWebSQL
  2. Adminer ([plugin_info slug="adminer" data="downloaded"]): [plugin_info slug="adminer" data="short_description"] (Thanks Jason!)
    WordPress SQL Plugins: Adminer
  3. Search and Replace ([plugin_info slug="search-and-replace" data="downloaded"]): [plugin_info slug="search-and-replace" data="short_description"]
    WordPress SQL Plugin: Search and  Replace
  4. Search Regex ([plugin_info slug="search-regex" data="downloaded"]): [plugin_info slug="search-regex" data="short_description"]ort.
    WordPress SQL Plugin: Search Regex
  5. SQL Executioner ([plugin_info slug="sql-executioner" data="downloaded"]): [plugin_info slug="sql-executioner" data="short_description"]
    WordPress SQL Plugin: SQL Executioner
  6. Edit Any Table ([plugin_info slug="edit-any-table" data="downloaded"]): [plugin_info slug="edit-any-table" data="short_description"]
    WordPress SQL Plugin: Edit Any Table
  7. WP Clean Up ([plugin_info slug="wp-clean-up" data="downloaded"]): [plugin_info slug="wp-clean-up" data="short_description"]
    WordPress SQL Plugin: WP Clean Up
  8. ELI's SQL Admin Reports Shortcode and DB Backup ([plugin_info slug="elisqlreports" data="downloaded"]): [plugin_info slug="elisqlreports" data="short_description"]
    WordPress SQL Plugin: Eli's SQL Report
  9. Safe Search and Replace ([plugin_info slug="safe-search-replace" data="downloaded"]): [plugin_info slug="safe-search-replace" data="short_description"]
    WordPress SQL Plugin: Safe Search and Replace
  10. Find replace ([plugin_info slug="find-replace" data="downloaded"]): [plugin_info slug="find-replace" data="short_description"]
    WordPress SQL Plugin: Find and replace

Other Plugins include:

  • dbview ([plugin_info slug="dbview" data="downloaded"]): [plugin_info slug="dbview" data="short_description"]
    WordPress SQL Plugin: DBView
  • WP MySQL Console (hasn't been updated in over 2 years) ([plugin_info slug="wp=mysql-console" data="downloaded"]): [plugin_info slug="wp-mysql-console" data="short_description"]
    WordPress SQL Plugin: WP MySQL Console Plugin

Written by Travis Smith · Categorized: Plugins

Aug 23 2013

Limit Users to Soliloquy: How to Add a Custom Capability to Soliloquy?

By default, anyone who can edit and edit others' posts can edit soliloquy. So what can you do to limit access to Soliloquy? It is simple as two steps:

  1. Filter Soliloquy Post Type Registration Parameters
  2. Add Capabilities to Specific Role

Filter Soliloquy Post Type Registration Parameters

We want to over-ride soliloquy's default `capability_type` of `post` and give it a custom capability type.

add_filter( 'tgmsp_post_type_args', 'gs_tgmsp_post_type_args' );
/**
* Filters Soliloquy post type registration parameters.
*
* @param array $args Soliloquy post type registration args.
* @return array $args Modified soliloquy post type registration args.
*/
function gs_tgmsp_post_type_args( $args ) {
$args['capability_type'] = 'soliloquy';
return $args;
}
view raw soliloquy-capabilities.php hosted with ❤ by GitHub

Doing this will give create the following caps:

[cap] => stdClass Object
(
    [edit_post]              => edit_soliloquy
    [read_post]              => read_soliloquy
    [delete_post]            => delete_soliloquy
    [edit_posts]             => edit_soliloquys
    [edit_others_posts]      => edit_others_soliloquys
    [publish_posts]          => publish_soliloquys
    [read_private_posts]     => read_private_soliloquys
    [delete_posts]           => delete_soliloquys
    [delete_private_posts]   => delete_private_soliloquys
    [delete_published_posts] => delete_published_soliloquys
    [delete_others_posts]    => delete_others_soliloquys
    [edit_private_posts]     => edit_private_soliloquys
    [edit_published_posts]   => edit_published_soliloquys
)

If that was all you were to do, then no one would have access to Soliloquy. Now you need to add these capabilities to the designated role (e.g., administrator).

Add Capabilities to Specific Role

This step is slightly more complicated than just modifying an argument. In short, we need to grab the post type object to get the newly created capabilities and add them to the role we want.

So, I want to hook immediately after soliloquy is registered. To do this, we hook into registered_post_type, a little known hook introduced in WordPress 3.3.

add_action( 'registered_post_type', 'gs_tgmsp_add_caps_to_admin', 10, 2 );
/**
* Add capabilities to soliloquy custom post type
*
* @param string $post_type Post type.
* @param array $args Original post type registration args.
*/
function gs_tgmsp_add_caps_to_admin( $post_type, $args ) {
view raw soliloquy-capabilities.php hosted with ❤ by GitHub

Next, I want to make sure that I have the soliloquy post type.

/** Make sure we have the correct post type */
if ( 'soliloquy' !== $post_type ) return;
view raw soliloquy-capabilities.php hosted with ❤ by GitHub

Once I have the soliloquy post type, I get the capabilities via get_post_type_object().

/** Get post type object to get capabilities */
$pt = get_post_type_object( $post_type );
view raw soliloquy-capabilities.php hosted with ❤ by GitHub

I then call my function (gs_add_caps_to_role()) to add the custom capabilities created by WordPress to the designated role.

/** Add capabilities to administrator */
gs_add_caps_to_role( 'administrator', $pt->cap );
}
view raw soliloquy-capabilities.php hosted with ❤ by GitHub

Alternatively, you can use the $wp_post_types global variable, which could be very dangerous.

/** Get global post type object */
global $wp_post_types;
/** Add capabilities to administrator */
gs_add_caps_to_role( 'administrator', $wp_post_types[ $post_type ]->cap );
}
view raw soliloquy-capabilitiesalt.php hosted with ❤ by GitHub

So here's the entire function:

<?php
add_filter( 'tgmsp_post_type_args', 'gs_tgmsp_post_type_args' );
/**
* Filters Soliloquy post type registration parameters.
*
* @param array $args Soliloquy post type registration args.
* @return array $args Modified soliloquy post type registration args.
*/
function gs_tgmsp_post_type_args( $args ) {
$args['capability_type'] = 'soliloquy';
return $args;
}
add_action( 'registered_post_type', 'gs_tgmsp_add_caps_to_admin', 10, 2 );
/**
* Add capabilities to soliloquy custom post type
*
* @param string $post_type Post type.
* @param array $args Original post type registration args.
*/
function gs_tgmsp_add_caps_to_admin( $post_type, $args ) {
/** Make sure we have the correct post type */
if ( 'soliloquy' !== $post_type ) return;
/** Get post type object to get capabilities */
$pt = get_post_type_object( $post_type );
/** Add capabilities to administrator */
gs_add_caps_to_role( 'administrator', $pt->cap );
}
view raw soliloquy-capabilities.php hosted with ❤ by GitHub

The function I called to add the capabilities to a specific role (gs_add_caps_to_role()) is split out so I can use it in other places. If you want you can certainly place all this in one function. In this function, I simply ensure that I have an array and cycle through the capabilities adding them one-by-one to the designated role.

<?php
/**
* Add custom capabilities to role
*
* @param string $role Role to add capabilities.
* @param array $caps Custom capabilities.
*/
function gs_add_caps_to_role( $role, $caps ) {
/** Convert object to an array */
if ( is_object( $caps ) )
$caps = json_decode( json_encode( $caps ), true );
/** Make sure we have an array, bail otherwise */
if ( !is_array( $caps ) ) return;
/** Get specified role object */
$role = get_role( $role );
/** Cycle through caps & add to role */
foreach( array_values( $caps ) as $cap )
$role->add_cap( $cap );
}
view raw add-capabilities-to-role.php hosted with ❤ by GitHub

So, if I wanted to add these capabilities to the administrator and editor, I would do this:

/** Add capabilities to roles */
foreach( array( 'administrator', 'editor', ) as $role )
gs_add_caps_to_role( $role, $pt->cap );
view raw soliloquy-capabilitiesmultiple.php hosted with ❤ by GitHub

Written by Travis Smith · Categorized: Plugins, WordPress

Nov 18 2012

Dequeue Soliloquy Style

Since Soliloquy does not "properly" enqueue the flexslider stylesheet (only meaning, it doesn't hook into wp_enqueue_scripts, and frankly, it does it with the best approach IMHO). Here is the proper hook to remove the default Soliloquy style sheet.

Written by Travis Smith · Categorized: Plugins

May 29 2012

How to Pre-Populate A Radio/Select Field in Gravity Forms Based on Previous Inputs

So recently someone asked me, "Can Gravity Forms pre-populate a dropdown [radio or select] with information based on a previous input in a multipage form?" While the options are plenty to make this happen with the very many Gravity Form hooks. Some include the following (but not limited to):

  • Set a cookie & retrieve the cookie for use later using setcookie() & $_COOKIE.
  • Use jQuery (and/or AJAX) to populate fields

While both of these are extremely viable options, what this person wanted was to search a custom post type for someone's name. So on page 1 of the form was an input for the person's name.

While logically, one would think that the gform_field_value_$parameter_name filter would work, I couldn't for the life of me determine how to do this for select and/or radio fields. So, I switched back to gform_pre_render hook. As you may or may not know gform_pre_render hook gives you the $form object to manipulate prior to rendering the form and executed before the form is displayed, which is what I needed.

Setup

In order to set this up, you will need two things:

  1. A custom post type called 'Persons' (wps_person), which served as the body of data that would pre-populate the radios.
  2. A simple Multipaged form

Gravity Forms Multi-paged Form

So create a new gravity form. Add a name (Field ID:1), then add a radio field. In the name field select either Normal (this is what the example uses) or Simple (example has a commented out replacement for this). Have the name on page 1 and the radio options on page 2. In the radio field, do the following under the Advanced Tab:

  • Add a CSS class name 'person'
  • Check "Allow field to be populated dynamically" but no need to choose a parameter name

Now you are ready...

Gravity Forms Customization

First, we have to cycle through the form fields. Gravity Forms does not prepped the Form Object (here $form) where the key is the Field ID (though that would be nice).

Next, in this snippet, you will notice a check at the beginning to see if we are on the correct field. You may think I go overboard, but I don't want to edit the wrong field. So I am checking for the following:

  • Field Type
  • CSS class
  • Allows pre-population

[php]
if ( 'radio' != $field['type'] || false === strpos( $field['cssClass'], 'candle-person' ) || ! rgar( $field, 'allowsPrepopulate' ) )
[/php]

While you don't necessarily need all three per se, I find that I don't run into errors when I do all three.

Third, we do a new WP_Query() (see codex for more information & see Mark Luetke's (Github, Site) WP_Query Args Gist) searching for those items that match the name. Here I access the $_POST var with the appropriate input_*_* name. I then also tell it to query my post type ('wps_person'). For future possibilities, I add another query var 'gform_search', just in case I want to do something with pre_get_posts later, but that's for more advanced usage.

Then, I just cycle through the available posts to create my choices, and return the form.

Here's an example:

Written by Travis Smith · Categorized: Plugins

  • 1
  • 2
  • 3
  • 4
  • Next Page »
  • Twitter
  • Facebook
  • LinkedIn
  • Google+
  • RSS

Copyright © 2025 � WP Smith on Genesis on Genesis Framework � WordPress � Log in