Created
January 26, 2019 15:19
-
-
Save ibes/bae8b98e9c5a37e0da1797aff9308adb to your computer and use it in GitHub Desktop.
Building Content Teams with WP User Groups and Custom User Roles - https://webdevstudios.com/2016/03/22/building-content-teams-wp-user-groups/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Plugin Name: Content Teams | |
* Plugin URI: https://webdevstudios.com/2016/03/22/building-content-teams-wp-user-groups/ | |
* Description: Putting together the pieces of Chris Reynolds tutorial to create Content Teams | |
* Version: 0.1.0 | |
* Author: Sebastian Gärtner original by Chris Reynolds | |
* Author URI: https://webdevstudios.com/2016/03/22/building-content-teams-wp-user-groups/ | |
* Text Domain: wds | |
* License: GPL-2.0+ | |
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt | |
* | |
* Thanks to: https://webdevstudios.com/2016/03/22/building-content-teams-wp-user-groups/ | |
*/ | |
// plugin needs to be installed | |
// https://wordpress.org/plugins/wp-user-groups/ | |
// needs to be added to the project: https://github.com/johnbillion/extended-cpts | |
require_once 'extended-cpts/extended-cpts.php'; | |
/* Registers the taxonomies to be used by WP User Groups as User Taxonomies. | |
* | |
* In order to create teams that can work with certain types of content, | |
* we need to be able to group users into teams. Uses WP User Groups. | |
* | |
* @link https://github.com/stuttter/wp-user-groups | |
*/ | |
add_action( 'init', 'wds_register_user_taxonomy' ); | |
function wds_register_user_taxonomy() { | |
// Make sure that WP_User_Taxonomy class exists | |
if ( ! class_exists( 'WP_User_Taxonomy' ) ) { | |
return; | |
} | |
// Create the new user taxonomy. | |
new WP_User_Taxonomy( 'content_team', 'users/content-team', array( | |
'singular' => __( 'Team', 'wds' ), | |
'plural' => __( 'Teams', 'wds' ), | |
) ); | |
} | |
/** | |
* Register a new taxonomy for content teams to be used as a User Taxonomy. | |
* We're using John Billion's Extended Taxonomies library to simplify the taxonomy | |
* creation. | |
* | |
* @link https://github.com/johnbillion/extended-cpts | |
*/ | |
add_action( 'init', 'wds_register_taxonomies', 90 ); | |
function wds_register_taxonomies() { | |
/* | |
* The Content Area taxonomy. | |
* | |
* This is a content taxonomy that is used to create "teams" of users based on | |
* the area(s) they specialize in. Members of a Content Team can only see | |
* documents within their own team. | |
*/ | |
register_extended_taxonomy( 'content_area', array( 'post') , array( | |
), array( | |
'singular' => __( 'Area', 'wds' ), | |
'plural' => __( 'Areas', 'wds' ), | |
'slug' => 'content-area', | |
) ); | |
} | |
add_action( 'init', 'wds_remove_default_user_groups', 9 ); | |
function wds_remove_default_user_groups () { | |
remove_action( 'init', 'wp_register_default_user_group_taxonomy' ); | |
remove_action( 'init', 'wp_register_default_user_type_taxonomy' ); | |
} | |
function add_roles_on_plugin_activation() { | |
add_role( 'content_creator', __( 'Content Creator', 'wds' ), array( | |
'read' => true, | |
'delete_posts' => true, | |
'edit_posts' => true, | |
'upload_files' => true, // Let them upload files, they'll need it. | |
'edit_pages' => true, // Able to edit WordPress pages. | |
) ); | |
// Content Approvers are set up like Editors with fewer caps. | |
add_role( 'content_approver', __( 'Content Approver', 'wds' ), array( | |
'delete_posts' => true, | |
'delete_published_posts' => true, | |
'edit_others_posts' => true, | |
'edit_posts' => true, | |
'edit_published_posts' => true, | |
'publish_posts' => true, | |
'read' => true, | |
'unfiltered_html' => true, | |
'upload_files' => true, | |
) ); | |
add_caps(); | |
} | |
register_activation_hook( __FILE__, 'add_roles_on_plugin_activation' ); | |
function delete_roles_on_plugin_deactivation() { | |
remove_role( 'content_creator' ); | |
remove_role( 'content_approver' ); | |
remove_caps(); | |
} | |
register_deactivation_hook( __FILE__, 'delete_roles_on_plugin_deactivation' ); | |
/* | |
* Take a role and return the new capabilities that should be added to that role. | |
* @param string $role Any role used by the Content Teams plugin. | |
* @return array Array of new capabilities added to that role. | |
*/ | |
function role_to_caps_map( $role = '' ) { | |
// Bail if no role was passed. | |
if ( '' == $role ) { | |
return false; | |
} | |
// Check if the role passed is one we're using. | |
if ( ! $this->using_role( $role ) ) { | |
return false; | |
} | |
// Map the new capabilities to user roles. | |
$caps_map = array( | |
'administrator' => array( | |
'edit_team_content', // Able to view content from teams. | |
'edit_global_content', // Able to view all content, regardless of team. | |
), | |
'editor' => array( | |
'edit_team_content', | |
'edit_global_content', | |
), | |
'contributor' => array( | |
'edit_team_content', | |
'edit_global_content', | |
), | |
'site_approver' => array( | |
'edit_team_content', | |
'team_publish_posts', | |
), | |
'site_creator' => array( | |
'edit_team_content', | |
), | |
); | |
// Return the new capabilities for the given role. | |
return $caps_map[ $role ]; | |
} | |
/* | |
* Adds or removes the new capabilities required for Content Teams. | |
* | |
* @param string $action The desired action. Either 'add' or 'remove'. | |
*/ | |
function adjust_caps( $action = '' ) { | |
if ( ! in_array( $action, array( 'add', 'remove' ) ) ) { | |
return; | |
} | |
$adjust_cap = $action . '_cap'; | |
// Loop through all the content team roles. | |
foreach ( $this->content_team_roles() as $this_role ) { | |
// Check if the role exists and save the role to a variable. | |
if ( $role = get_role( $this_role ) ) { | |
// Loop through each cap for that role. | |
foreach ( $this->role_to_caps_map( $this_role ) as $cap ) { | |
// Add the cap to the role. | |
$role->$adjust_cap( $cap ); | |
} // Ends caps loop. | |
} // Ends role check. | |
} // Ends role loop. | |
} | |
/** | |
* Triggered on activation, adds the new capabilities for Content Teams. | |
*/ | |
function add_caps() { | |
adjust_caps( 'add' ); | |
} | |
/** | |
* Triggered on deactivation, removes the new capabilities for Content Teams. | |
*/ | |
function remove_caps() { | |
adjust_caps( 'remove' ); | |
} | |
add_action( 'init', function() { | |
register_extended_post_type( 'content_area_cpt' ); | |
} ); | |
// on create content area term, content team term is created | |
function wds_create_content_team( $term_id, $tt_id ) { | |
$term = get_term_by( 'id', $term_id, 'content_area' ); | |
if ( ! $term ) { | |
return; | |
} | |
wp_insert_term( $term->name, 'content_team', array( | |
'description' => $term->description, | |
'slug' => $term->slug, | |
) ); | |
} | |
add_action( 'create_content_area', 'wds_create_content_team', 10, 2 ); | |
/* | |
* Runs on the save_post hook to handle adding terms for Content Areas. | |
* | |
* @param int $post_id The ID of the Content Area post | |
* @param object $post The post object. | |
*/ | |
function wds_save_taxes( $post_id, $post ) { | |
// If this isn't the Content Area CPT, then bail. | |
if ( 'content_area_cpt' !== $post->post_type ) { | |
return; | |
} | |
// Add term for the Content Area. | |
if ( 'publish' == $post->post_status ) { | |
wds_add_content_area_term( $post->ID, $post->post_title ); | |
} | |
} | |
add_action( 'save_post', 'wds_save_taxes', 10, 2 ); | |
/** | |
* Inserts or updates a Content Area term. | |
* | |
* @param string $slug The post slug. | |
* @param string $title The post title. | |
*/ | |
function wds_add_content_area_term( $slug, $title ) { | |
$term = get_term_by( 'slug', $slug, 'content_area', OBJECT ); | |
if ( ! $term ) { | |
wp_insert_term( | |
esc_html( $title ), | |
'content_area', | |
array( 'slug' => $slug ) | |
); | |
} else { | |
wp_update_term( | |
$term->term_id, | |
'content_area', | |
array( | |
'name' => esc_html( $title ), | |
'slug' => esc_attr( $slug ), | |
) | |
); | |
} | |
} | |
/* | |
* Handles the magic filtering of Program Areas by Content Team. | |
* | |
* @param class $query WP_Query that we're modifying. | |
*/ | |
function wds_filter_content_areas( $query ) { | |
if ( ! is_admin() ) { | |
return; | |
} | |
// Get the post type. | |
$current_post_type = $query->get( 'post_type' ); | |
// Make sure we're on the right post type edit page. | |
if ( in_array( $current_post_type, wds_content_area_post_types() ) ) { | |
if ( wds_is_site_content_editor() ) { | |
$teams = ( wp_get_terms_for_user( get_current_user_id(), 'content_team' ) ) ? wp_get_terms_for_user( get_current_user_id(), 'content_team' ) : array(); | |
$areas = array(); | |
foreach ( $teams as $team ) { | |
$areas[] = wds_get_term_id_by_team( $team, 'content_team' ); | |
$content_area_cpt_ids[] = absint( $team->slug ); | |
} | |
$content_area_cpt_ids = ! empty( $content_area_cpt_ids ) ? $content_area_cpt_ids : array( 0 ); | |
if ( 'clp_program_area_cpt' == $query->get( 'post_type' ) ) : | |
$query->set( 'post__in', $program_area_cpt_ids ); | |
else : | |
$query->set( 'tax_query', array( | |
array( | |
'taxonomy' => 'content_area', | |
'field' => 'term_id', | |
'terms' => $areas, | |
'operator' => 'IN', | |
), | |
) ); | |
endif; | |
} | |
} | |
} | |
add_action( 'pre_get_posts', 'wds_filter_content_areas', 10 ); | |
/** | |
* Return a term ID for a content term based on that term's content team term. | |
* @param object $term The original term object. | |
* @return int The taxonomy term id. | |
*/ | |
function wds_get_term_id_by_team( $term ) { | |
if ( is_array( $term ) && isset( $term['invalid_taxonomy'] ) || empty( $term ) ) { | |
return; | |
} | |
$new_term = get_term_by( 'slug', $term->slug, 'content_area' ); | |
return $new_term->term_id; | |
} | |
/** | |
* Break down the checks to user capabilities. If they can edit global content, show them things that they need to do their job. | |
* | |
* @return bool If a user is a member of a specific team, hide things. | |
*/ | |
function wds_is_site_content_editor() { | |
// If the current user can edit global content, we don't need to filter. | |
if ( current_user_can( 'edit_global_content' ) ) { | |
return false; | |
} | |
// If the current user can only edit team content, we do need to filter. | |
if ( current_user_can( 'edit_team_content' ) ) { | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Return an array of applicable post types. | |
* | |
* @param array $args The args to lookup post types with. | |
* @return array | |
*/ | |
function wds_content_area_post_types( $args = array() ) { | |
$post_type_args = wp_parse_args( $args, array( | |
'public' => true, | |
) ); | |
/** | |
* Filter the post types from WordPress before we return them. | |
* | |
* @param array $post_types Array of WP post types return from get_post_types(). | |
* @return array | |
*/ | |
return apply_filters( 'wds_content_area_post_types_filter', get_post_types( $post_type_args ) ); | |
} | |
/** | |
* Adds Content Areas automagically to the post when it's saved. | |
* | |
* If a user creates any other post type, we want to find out what content | |
* area they are in and add that content area to the post. This automatically | |
* adds a the content area the user is associated with to the post. | |
* | |
* @param int $post_id The post ID you're editing. | |
*/ | |
function wds_add_user_team_terms_to_post( $post_id ) { | |
if ( wp_is_post_revision( $post_id ) ) | |
return; | |
// Set Post taxonomy terms to sync with the users taxonomy terms. | |
$user_terms = wp_get_terms_for_user( get_current_user_id(), 'content_team' ); | |
// Get the normal taxonomy terms that are the same as the user taxonomy terms. | |
foreach ( $user_terms as $term ) { | |
$post_terms[] = $term->slug; // Add the slug to the array, when we add the normal taxon term below it will use the same slug. | |
} | |
// Actually associate the matched terms with the post. | |
if ( isset( $post_terms ) ) { | |
$__terms = wp_set_object_terms( $post_id, $post_terms, 'content_area' ); | |
} | |
} | |
add_action( 'save_post', 'wds_add_user_team_terms_to_post', 99 ); // User Content Team > Post Content Area. | |
/** | |
* Add custom post statuses. | |
* Currently there's just one custom post status -- Team Published. | |
* | |
* @link https://codex.wordpress.org/Function_Reference/register_post_status | |
* @since 0.2.0 | |
*/ | |
function wds_add_post_statuses() { | |
register_post_status( 'team-publish', array( | |
'label' => __( 'Team Published', 'wds' ), | |
'public' => true, | |
'exclude_from_search' => true, | |
'show_in_admin_all_list' => true, | |
'show_in_admin_status_list' => true, | |
'label_count' => _n_noop( __( 'Team Published <span class="count">(%s)</span>', 'wds' ), __( 'Team Published <span class="count">(%s)</span>', 'wds' ) ), | |
) ); | |
} | |
add_action( 'init', 'wds_add_post_statuses' ); | |
/** | |
* Alter the post status dropdown and publish button. | |
* | |
* @link http://jamescollings.co.uk/blog/wordpress-create-custom-post-status/ | |
* @since 0.2.0 | |
* @return null | |
*/ | |
function wds_append_post_status_list() { | |
global $post; | |
if ( ! $post ) { | |
return; // We need a post. | |
} | |
// Set up some variables. | |
$published = __( 'Published' ); | |
$option = __( 'Team Published', 'wds' ); | |
$complete = ( 'team-publish' == $post->post_status ) ? ' selected="selected"' : ''; | |
$label = ( 'team-publish' == $post->post_status ) ? '<span id=\"post-status-display\"> ' . esc_attr( $option ) . '</span>' : ''; | |
// Use javascript to append the Team Published option to the list of post statuses. | |
echo ' | |
<script> | |
jQuery(document).ready(function($){ | |
$("select#post_status").append("<option value=\"team-publish\" ' . esc_attr( $complete ) . '>' . esc_attr( $option ) . '</option>"); | |
$(".misc-pub-section label").append("' . $label . '"); | |
}); | |
</script> | |
'; | |
// If the current user can Team Publish posts, change the Publish button to say "Team Publish" instead. | |
if ( current_user_can( 'team_publish_posts' ) ) { | |
echo ' | |
<script> | |
jQuery(document).ready(function($){ | |
var publishInput = $("input#publish"); | |
if ( "Publish" == publishInput.val() ) { | |
publishInput.val("' . esc_attr__( 'Team Publish', 'wds' ) . '"); | |
} | |
$("select#post_status").change(function(){ | |
$("a.save-post-status").click(function(){ | |
publishInput.val("' . esc_attr__( 'Team Publish', 'wds' ) . '"); | |
}) | |
}); | |
}); | |
</script> | |
'; | |
} | |
// If the current user can actually publish, add a Published status to the dropdown of post statuses, too. | |
if ( current_user_can( 'publish_team_posts' ) ) { | |
// Only add Published to the dropdown if the post isn't already published. Prevents a duplicate Published from displaying in the list. | |
if ( $post->post_status !== 'publish' ) { | |
echo ' | |
<script> | |
jQuery(document).ready(function($){ | |
$("select#post_status").append("<option value=\"publish\">' . esc_attr( $published ) . '</option>"); | |
}); | |
</script> | |
'; | |
} | |
} | |
} | |
add_filter( 'admin_footer', 'wds_append_post_status_list', 999 ); | |
/** | |
* Prevent the post from saving as Published if submitted by a user who shouldn't be able to publish. | |
* | |
* @since 0.2.0 | |
* @param array $data The submitted data. | |
* @param array $postarr Array of post data. | |
* @link http://wordpress.stackexchange.com/a/113545 | |
* @return array Updated post data. | |
*/ | |
function wds_prevent_post_change( $data, $postarr ) { | |
if ( ! isset( $postarr['ID'] ) || ! $postarr['ID'] ) { | |
return $data; | |
} | |
// If a user isn't able to team publish posts (only Content Approvers), do the normal stuff. | |
if ( ! current_user_can( 'team_publish_posts' ) ) { | |
return $data; | |
} | |
$old = get_post( $postarr['ID'] ); // The post before update. | |
if ( | |
$old->post_status == 'auto-draft' || | |
$old->post_status !== 'trash' && // Without this post restoring from trash fail. | |
'publish' === $data['post_status'] | |
) { | |
// Force the post to be set as team-publish. | |
$data['post_status'] = 'team-publish'; | |
} | |
return $data; | |
} | |
add_filter( 'wp_insert_post_data', 'wds_prevent_post_change', 20, 2 ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment