' .
__( 'Use the Groups box to limit the visibility of posts, pages and other post types.', 'groups' ) .
'
' .
'
' .
__( 'You can select one or more groups to restrict access to its members.', 'groups' ) .
( !current_user_can( GROUPS_ADMINISTER_GROUPS ) ?
' ' .
__( 'Note that you must be a member of a group to use it to restrict access.', 'groups' )
:
''
) .
'
' .
'
' .
'' . __( 'Example:', 'groups' ) . '' .
'
' .
__( 'Let\'s assume that you want to limit the visibility of a post to members of the Premium group.', 'groups' ) .
'
' .
' ' .
'
' .
__( 'Choose or enter Premium in the Read field located in the Groups box and save or update the post (or hit Enter).', 'groups' ) .
'
' .
__( 'In the same field, you can create a new group and restrict access. Group names are case-sensitive. In order to be able to use the new group, your user account will be assigned to it.', 'groups' ) .
'
';
if ( self::user_can_restrict() ) {
$include = self::get_user_can_restrict_group_ids();
$groups = Groups_Group::get_groups( array( 'order_by' => 'name', 'order' => 'ASC', 'include' => $include ) );
$groups_read = get_post_meta( $post_id, Groups_Post_Access::POSTMETA_PREFIX . Groups_Post_Access::READ );
$read_help = sprintf(
__( 'You can restrict the visibility of this %1$s to group members. Choose one or more groups that are allowed to read this %2$s. If no groups are chosen, the %3$s is visible to anyone.', 'groups' ),
$post_singular_name,
$post_singular_name,
$post_singular_name
);
if ( current_user_can( GROUPS_ADMINISTER_GROUPS ) ) {
$read_help .= ' ' . __( 'You can create a new group by indicating the group\'s name.', 'groups' );
}
$output .= sprintf(
'';
$output .= Groups_UIE::render_select(
'.select.groups-read',
true,
true,
current_user_can( GROUPS_ADMINISTER_GROUPS )
);
$output .= '
';
$output .= sprintf(
__( 'Restricts the visibility of this %s to members of the chosen groups.', 'groups' ),
$post_singular_name
);
$output .= '
'; // .select-read-groups-container
$output .= apply_filters( 'groups_access_meta_boxes_groups_after_read_groups', '', $object, $box );
$output = apply_filters( 'groups_access_meta_boxes_groups', $output, $object, $box );
echo $output;
}
/**
* Invokes our save_post() if the post content is considered empty.
* This is required because even on an empty post, we want to allow to
* quick-create group and category as well as assign capabilities.
* At WordPress 3.6.1, this is the only way we can achieve that, because
* the save_post action is not invoked if the post content is considered
* empty.
*
* @param boolean $maybe_empty
* @param array $postarr
* @return boolean
*/
public static function wp_insert_post_empty_content( $maybe_empty, $postarr ) {
// Only consider invoking save_post() here, if the post content is
// considered to be empty at this stage. This is so we don't end up
// having save_post() invoked twice when the post is not empty.
if ( $maybe_empty ) {
$post_id = !empty( $postarr['ID'] ) ? $postarr['ID'] : !empty( $postarr['post_ID'] ) ? $postarr['post_ID'] : null;
if ( $post_id ) {
self::save_post( $post_id );
}
}
return $maybe_empty;
}
/**
* Save the group access restriction.
*
* @param int $post_id
* @param mixed $post post data (not used here)
*/
public static function save_post( $post_id = null, $post = null ) {
// This is called multiple times and if a new post is created and a new group is requested*,
// we can end up without the new group being assigned to the post unless we duely check
// for revision and autosave:
// (* on the second call, the new group exists and it will bail out on "if ( !( $group = Groups_Group::read_by_name( $name ) ) ) { ...")
if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE || wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) ) {
} else {
$post_type = get_post_type( $post_id );
$post_type_object = get_post_type_object( $post_type );
if ( $post_type_object && $post_type != 'attachment' ) {
$post_types_option = Groups_Options::get_option( Groups_Post_Access::POST_TYPES, array() );
if ( !isset( $post_types_option[$post_type]['add_meta_box'] ) || $post_types_option[$post_type]['add_meta_box'] ) {
if ( self::user_can_restrict() ) {
if ( isset( $_POST[self::NONCE] ) && wp_verify_nonce( $_POST[self::NONCE], self::SET_GROUPS ) ) {
$post_type = isset( $_POST['post_type'] ) ? $_POST['post_type'] : null;
if ( $post_type !== null ) {
// See http://codex.wordpress.org/Function_Reference/current_user_can 20130119 WP 3.5
// "... Some capability checks (like 'edit_post' or 'delete_page') require this [the post ID] be provided."
// If the post ID is not provided, it will throw:
// PHP Notice: Undefined offset: 0 in /var/www/groups-forums/wp-includes/capabilities.php on line 1067
$edit_post_type = 'edit_' . $post_type;
if ( $post_type_object = get_post_type_object( $post_type ) ) {
if ( !isset( $post_type_object->capabilities ) ) {
// get_post_type_capabilities() (WP 3.8) will throw a warning
// when trying to merge the missing property otherwise. It's either a
// bug or the function's documentation should make it clear that you
// have to provide that.
$post_type_object->capabilities = array();
}
$caps_object = get_post_type_capabilities( $post_type_object );
if ( isset( $caps_object->edit_post ) ) {
$edit_post_type = $caps_object->edit_post;
}
}
if ( current_user_can( $edit_post_type, $post_id ) ) {
$include = self::get_user_can_restrict_group_ids();
$groups = Groups_Group::get_groups( array( 'order_by' => 'name', 'order' => 'ASC', 'include' => $include ) );
$user_group_ids_deep = array();
foreach( $groups as $group ) {
$user_group_ids_deep[] = $group->group_id;
}
$group_ids = array();
$submitted_group_ids = !empty( $_POST[self::GROUPS_READ] ) && is_array( $_POST[self::GROUPS_READ] ) ? $_POST[self::GROUPS_READ] : array();
// assign requested groups and create and assign new groups if allowed
foreach( $submitted_group_ids as $group_id ) {
if ( is_numeric( $group_id ) ) {
if ( in_array( $group_id, $user_group_ids_deep ) ) {
$group_ids[] = $group_id;
}
} else {
if ( current_user_can( GROUPS_ADMINISTER_GROUPS ) ) {
$creator_id = get_current_user_id();
$datetime = date( 'Y-m-d H:i:s', time() );
$name = ucwords( strtolower( trim( preg_replace( '/\s+/', ' ', $group_id ) ) ) );
if ( strlen( $name ) > 0 ) {
if ( !( $group = Groups_Group::read_by_name( $name ) ) ) {
if ( $group_id = Groups_Group::create( compact( 'creator_id', 'datetime', 'name' ) ) ) {
if ( Groups_User_Group::create( array( 'user_id' => $creator_id, 'group_id' => $group_id ) ) ) {
$group_ids[] = $group_id;
}
}
}
}
}
}
}
do_action( 'groups_access_meta_boxes_before_groups_read_update', $post_id, $group_ids );
$update_result = Groups_Post_Access::update( array( 'post_id' => $post_id, 'groups_read' => $group_ids ) );
do_action( 'groups_access_meta_boxes_after_groups_read_update', $post_id, $group_ids, $update_result );
}
}
}
}
}
}
}
}
/**
* Enqueue scripts and styles.
*/
private static function enqueue() {
global $groups_version;
if ( !wp_script_is( 'selectize' ) ) {
wp_enqueue_script( 'selectize', GROUPS_PLUGIN_URL . 'js/selectize/selectize.min.js', array( 'jquery' ), $groups_version, false );
}
if ( !wp_style_is( 'selectize' ) ) {
wp_enqueue_style( 'selectize', GROUPS_PLUGIN_URL . 'css/selectize/selectize.bootstrap2.css', array(), $groups_version );
}
}
/**
* Render groups box for attachment post type (Media).
*
* @param array $form_fields
* @param object $post
* @return array
*/
public static function attachment_fields_to_edit( $form_fields, $post ) {
Groups_UIE::enqueue( 'select' );
$post_types_option = Groups_Options::get_option( Groups_Post_Access::POST_TYPES, array() );
if ( !isset( $post_types_option['attachment']['add_meta_box'] ) || $post_types_option['attachment']['add_meta_box'] ) {
if ( self::user_can_restrict() ) {
$include = self::get_user_can_restrict_group_ids();
$groups = Groups_Group::get_groups( array( 'order_by' => 'name', 'order' => 'ASC', 'include' => $include ) );
$groups_read = get_post_meta( $post->ID, Groups_Post_Access::POSTMETA_PREFIX . Groups_Post_Access::READ );
$output = '';
$post_singular_name = __( 'Media', 'groups' );
$output .= __( 'Read', 'groups' );
// On attachments edited within the 'Insert Media' popup, the update is triggered too soon and we end up with only the last capability selected.
// This occurs when using normal checkboxes as well as the select below (Chosen and Selectize tested).
// With checkboxes it's even more confusing, it's actually better to have it using a select as below,
// because the visual feedback corresponds with what is assigned.
// See http://wordpress.org/support/topic/multiple-access-restrictions-for-media-items-are-not-saved-in-grid-view
// and https://core.trac.wordpress.org/ticket/28053 - this is an issue with multiple value fields and should
// be fixed within WordPress.
// $output .= '
';
$output .= __( 'Restricts the visibility of this entry to members of the chosen groups.', 'groups' );
$output .= '
';
$output .= '
';
$output .= __( 'The attachment page is restricted to authorized users, but due to technical limitations, the file can still be accessed directly via its URL.', 'groups' );
$output .= ' ';
$output .= sprintf( __( 'Please use Groups File Access for files that require complete protection.', 'groups' ), esc_url( 'http://www.itthinx.com/shop/groups-file-access/' ) );
$output .= '
';
$form_fields['groups_read'] = array(
'label' => __( 'Groups', 'groups' ),
'input' => 'html',
'html' => $output
);
}
}
return $form_fields;
}
/**
* Save groups for attachment post type (Media).
* When multiple attachments are saved, this is called once for each.
*
* @param array $post post data
* @param array $attachment attachment field data
* @return array
*/
public static function attachment_fields_to_save( $post, $attachment ) {
$post_types_option = Groups_Options::get_option( Groups_Post_Access::POST_TYPES, array() );
if ( !isset( $post_types_option['attachment']['add_meta_box'] ) || $post_types_option['attachment']['add_meta_box'] ) {
// if we're here, we assume the user is allowed to edit attachments,
// but we still need to check if the user can restrict access
if ( self::user_can_restrict() ) {
$post_id = null;
if ( isset( $post['ID'] ) ) {
$post_id = $post['ID'];
} else if ( isset( $post['post_ID'] ) ) {
$post_id = $post['post_ID'];
}
if ( $post_id !== null ) {
$include = self::get_user_can_restrict_group_ids();
$groups = Groups_Group::get_groups( array( 'order_by' => 'name', 'order' => 'ASC', 'include' => $include ) );
$group_ids = array();
if ( !empty( $attachment[self::GROUPS_READ] ) && is_array( $attachment[self::GROUPS_READ] ) ) {
foreach( $groups as $group ) {
if ( in_array( $group->group_id, $attachment[self::GROUPS_READ] ) ) {
$group_ids[] = $group->group_id;
}
}
}
do_action( 'groups_access_meta_boxes_before_groups_read_update', $post_id, $group_ids );
$update_result = Groups_Post_Access::update( array( 'post_id' => $post_id, 'groups_read' => $group_ids ) );
do_action( 'groups_access_meta_boxes_after_groups_read_update', $post_id, $group_ids, $update_result );
}
}
}
return $post;
}
/**
* Returns true if the user can restrict access to posts. The current user is
* assumed by default unless a user ID is provided.
*
* @param int $user_id indicates the desired user, otherwise for the current user
* @return boolean
*/
public static function user_can_restrict( $user_id = null ) {
if ( $user_id === null ) {
$user_id = get_current_user_id();
}
$user = new Groups_User( $user_id);
return $user->can( GROUPS_RESTRICT_ACCESS );
}
/**
* Returns the group IDs of the groups that the user can use to restrict access.
*
* If the user can GROUPS_RESTRICT_ACCESS, the following group IDs are returned:
* - If the user can GROUPS_ADMINISTER_GROUPS, this will return the IDs of all groups.
* - Otherwise it will return the IDs of all groups that the user belongs to, directly
* or indirectly by group inheritance.
*
* If the user can not GROUPS_RESTRICT_ACCESS, an empty array is returned.
*
* @param int $user_id if provided, retrieve results for the user indicated by user ID, otherwise for the current user
* @return array of int with the group IDs
*/
public static function get_user_can_restrict_group_ids( $user_id = null ) {
$group_ids = array();
if ( $user_id === null ) {
$user_id = get_current_user_id();
}
if ( self::user_can_restrict( $user_id ) ) {
if ( current_user_can( GROUPS_ADMINISTER_GROUPS ) ) {
$group_ids = Groups_Group::get_group_ids();
} else {
$user = new Groups_User( $user_id );
$group_ids = $user->group_ids_deep;
}
if ( !empty( $group_ids ) && is_array( $group_ids ) ) {
$group_ids = array_map (array( 'Groups_Utility','id'), $group_ids );
}
}
return $group_ids;
}
/**
* @deprecated
* @return array of valid read capabilities for the current or given user
*/
public static function get_valid_read_caps_for_user( $user_id = null ) {
require_once( GROUPS_LEGACY_LIB . '/access/class-groups-access-meta-boxes-legacy.php' );
return Groups_Access_Meta_Boxes_Legacy::get_valid_read_caps_for_user( $user_id );
}
}
Groups_Access_Meta_Boxes::init();