Exemple #1
0
 public static function get_role_title($role_name, $args = array())
 {
     global $wp_roles, $pp_role_defs, $pp_cap_caster;
     $defaults = array('plural' => false, 'slug_fallback' => true, 'include_warnings' => false);
     $args = array_merge($defaults, $args);
     extract($args, EXTR_SKIP);
     pp_init_cap_caster();
     if (strpos($role_name, ':')) {
         $arr_name = explode(':', $role_name);
         if (!empty($arr_name[2])) {
             $caption_prop = $plural ? 'name' : 'singular_name';
             $warning = '';
             if (isset($pp_role_defs->pattern_roles[$arr_name[0]])) {
                 $role_caption = $pp_role_defs->pattern_roles[$arr_name[0]]->labels->{$caption_prop};
                 if ($include_warnings && isset($wp_roles->role_names[$arr_name[0]]) && !$pp_cap_caster->is_valid_pattern_role($arr_name[0])) {
                     $warning = '<span class="pp-red"> ' . sprintf(__('(using default capabilities due to invalid %s definition)', 'pp'), $wp_roles->role_names[$arr_name[0]]) . '</span>';
                 }
             } elseif ($slug_fallback) {
                 $role_caption = $arr_name[0];
             } else {
                 return '';
             }
             $type_caption = '';
             if ($type_obj = pp_get_type_object($arr_name[1], $arr_name[2])) {
                 $type_caption = $type_obj->labels->singular_name;
             } else {
                 return $slug_fallback ? $role_name : '';
             }
             $cond_caption = '';
             if (isset($arr_name[4])) {
                 $cond_caption = apply_filters('pp_condition_caption', ucwords(str_replace('_', ' ', $arr_name[4])), $arr_name[3], $arr_name[4]);
             }
             if ($cond_caption) {
                 return trim(sprintf(__('%1$s&nbsp;%2$s&nbsp;<span class="pp_nolink">-&nbsp;%3$s</span>%4$s', 'pp'), $type_caption, str_replace(' ', '&nbsp;', $role_caption), str_replace(' ', '&nbsp;', $cond_caption), $warning));
             } else {
                 return trim(sprintf(__('%1$s&nbsp;%2$s&nbsp;%3$s', 'pp'), $type_caption, $role_caption, $warning));
             }
         }
     } elseif (isset($wp_roles->role_names[$role_name])) {
         return $wp_roles->role_names[$role_name];
     } else {
         return apply_filters('pp_role_title', $role_name, $args);
     }
 }
function _ppc_count_assigned_exceptions($agent_type, $args = array())
{
    global $wpdb;
    $defaults = array('query_agent_ids' => false, 'join_groups' => true);
    extract(array_merge($defaults, $args), EXTR_SKIP);
    $item_types = array_merge(pp_get_enabled_post_types(), pp_get_enabled_taxonomies(), pp_get_group_types(array('editable' => true)));
    $type_clause = "AND e.for_item_type IN ('','" . implode("','", $item_types) . "')";
    $type_clause .= " AND e.via_item_type IN ('','" . implode("','", $item_types) . "')";
    $ops_clause = "AND operation IN ('" . implode("','", pp_get_operations()) . "')";
    $count = array();
    $agent_type = pp_sanitize_key($agent_type);
    if ('user' == $agent_type && $join_groups) {
        $results = array();
        foreach (pp_get_group_types(array(), 'object') as $group_type => $gtype_obj) {
            global $wpdb;
            if (!empty($gtype_obj->schema['members'])) {
                extract($gtype_obj->schema['members']);
                // members_table, col_group, col_user
            } else {
                $members_table = $wpdb->pp_group_members;
                $col_member_group = 'group_id';
                $col_member_user = '******';
            }
            $agent_clause = $query_agent_ids ? "AND gm.{$col_member_user} IN ('" . implode("','", (array) $query_agent_ids) . "')" : '';
            if ('groups_only' === $join_groups || 'pp_group' != $group_type) {
                $agent_type_clause = "( e.agent_type = '{$group_type}' AND gm.{$col_member_group} = e.agent_id )";
            } else {
                $agent_type_clause = "( e.agent_type = 'user' AND gm.user_id = e.agent_id ) OR ( e.agent_type = 'pp_group' AND gm.group_id = e.agent_id )";
            }
            $_results = $wpdb->get_results("SELECT gm.{$col_member_user} as qry_agent_id, e.exception_id, e.for_item_source, e.for_item_type, e.via_item_type, e.operation, COUNT(DISTINCT i.exception_id, i.item_id) AS exc_count FROM {$wpdb->ppc_exception_items} AS i INNER JOIN {$wpdb->ppc_exceptions} AS e ON i.exception_id = e.exception_id INNER JOIN {$members_table} AS gm ON ( {$agent_type_clause} ) WHERE i.inherited_from = '0' {$ops_clause} {$type_clause} {$agent_clause} GROUP BY qry_agent_id, e.for_item_source, e.for_item_type, e.operation");
            $results = array_merge($results, $_results);
        }
    } else {
        $agent_clause = $query_agent_ids ? "AND e.agent_id IN ('" . implode("','", (array) $query_agent_ids) . "')" : '';
        $results = $wpdb->get_results("SELECT e.agent_id AS qry_agent_id, e.exception_id, e.for_item_source, e.for_item_type, e.operation, e.via_item_type, COUNT(DISTINCT i.exception_id, i.item_id) AS exc_count FROM {$wpdb->ppc_exception_items} AS i INNER JOIN {$wpdb->ppc_exceptions} AS e ON i.exception_id = e.exception_id WHERE i.inherited_from = '0' AND e.agent_type = '{$agent_type}' {$ops_clause} {$type_clause} {$agent_clause} GROUP BY qry_agent_id, e.for_item_source, e.for_item_type, e.operation");
    }
    foreach ($results as $row) {
        if (!$row->for_item_type) {
            $type_label = '';
        } else {
            if (!($type_obj = pp_get_type_object($row->for_item_source, $row->for_item_type))) {
                continue;
            }
            $type_label = $type_obj->labels->singular_name;
        }
        if ($op_obj = pp_get_op_object($row->operation, $row->for_item_type)) {
            if ('assign' == $row->operation) {
                if ($tx_obj = get_taxonomy($row->via_item_type)) {
                    $lbl = str_replace('Term', $tx_obj->labels->singular_name, $op_obj->label);
                } else {
                    $lbl = $op_obj->label;
                }
                //$lbl = sprintf( __('%2$s: %1$s', 'pp'), $op_lbl, $type_label );
            } elseif (isset($op_obj->abbrev)) {
                $lbl = $op_obj->abbrev;
            } else {
                $lbl = sprintf(__('%1$s %2$s', 'pp'), $op_obj->label, $type_label);
            }
        } else {
            $lbl = $type_label;
        }
        if (!isset($count[$row->qry_agent_id]['exceptions'][$lbl])) {
            $count[$row->qry_agent_id]['exceptions'][$lbl] = 0;
        }
        $count[$row->qry_agent_id]['exceptions'][$lbl] += $row->exc_count;
        if (!isset($count[$row->qry_agent_id]['exc_count'])) {
            $count[$row->qry_agent_id]['exc_count'] = 0;
        }
        $count[$row->qry_agent_id]['exc_count'] += $row->exc_count;
    }
    return $count;
}
             $types[$for_src_name] = $group_type_obj->labels->name;
         }
     }
     $types = apply_filters('pp_exception_via_types', $types, $for_src_name, $for_type, $operation, $mod_type);
     foreach ($types as $val => $title) {
         $class = $for_type == $val ? ' class="pp-post-object"' : '';
         $html .= "<option value='{$val}'{$class}>{$title}</option>";
     }
     break;
 case 'get_assign_for_ui':
     if (!is_user_logged_in()) {
         echo '<p>' . __('(login timed out)', 'pp') . '</p><div class="pp-checkbox"><input type="checkbox" name="pp_select_for_item" style="display:none"><input type="checkbox" name="pp_select_for_item" style="display:none"></div>';
         exit;
     }
     if ($via_type) {
         $type_obj = pp_get_type_object($via_src_name, $via_type);
         $html = '<div class="pp-checkbox">' . '<input type="checkbox" id="pp_select_x_item_assign" name="pp_select_x_for_item" checked="checked" value="1" /><label id="pp_x_item_assign_label" for="pp_select_x_item_assign"> ' . sprintf(__('selected %s:', 'pp'), $type_obj->labels->name) . '</label>' . '</div>';
         if ($type_obj && $type_obj->hierarchical && apply_filters('pp_do_assign_for_children_ui', true, $for_type, compact('operation', 'mod_type'))) {
             if (!($caption = apply_filters('pp_assign_for_children_caption', '', $for_type))) {
                 $caption = sprintf(__('sub-%s of:', 'pp'), $type_obj->labels->name);
             }
             $checked = apply_filters('pp_assign_for_children_checked', false, $for_type, compact('operation', 'mod_type')) ? ' checked="checked" ' : '';
             $disabled = apply_filters('pp_assign_for_children_locked', false, $for_type, compact('operation', 'mod_type')) ? ' disabled="disabled" ' : '';
             $html .= '<div class="pp-checkbox">' . '<input type="checkbox" id="pp_select_x_child_assign" name="pp_select_x_for_children" value="1"' . $checked . $disabled . ' /><label id="pp_x_child_assign_label" for="pp_select_x_child_assign"> ' . $caption . '</label>' . '</div>';
         }
         $html = apply_filters('pp_assign_for_ui', $html, $for_src_name, $for_type, $operation, $mod_type);
     }
     break;
 case 'get_status_ui':
     if (!is_user_logged_in()) {
         echo '<p>' . __('(login timed out)', 'pp') . '</p><div class="pp-checkbox"><input type="checkbox" name="pp_select_for_item" style="display:none"><input type="checkbox" name="pp_select_for_item" style="display:none"></div>';
 function get_typecast_caps($role_name)
 {
     $arr_name = explode(':', $role_name);
     if (empty($arr_name[2])) {
         return array();
     }
     // this role typecast is not db-defined, so generate it
     $base_role_name = $arr_name[0];
     $src_name = $arr_name[1];
     $object_type = $arr_name[2];
     // typecast role assignment stored, but undefined source name or object_type
     if (!($type_obj = pp_get_type_object($src_name, $object_type))) {
         return array();
     }
     // disregard stored Supplemental Roles for Media when Media is no longer enabled for PP filtering (otherwise Post editing caps are granted)
     if ('attachment' == $object_type) {
         static $media_filtering_enabled;
         if (!isset($media_filtering_enabled)) {
             $media_filtering_enabled = pp_get_enabled_post_types(array('name' => 'attachment'));
         }
         if (!$media_filtering_enabled) {
             return array();
         }
     }
     if (empty($this->pattern_role_type_caps)) {
         $this->define_pattern_caps();
     }
     $pattern_role_caps = 'term' == $src_name ? $this->pattern_role_taxonomy_caps : $this->pattern_role_type_caps;
     if (empty($pattern_role_caps[$base_role_name])) {
         // if the role definition is not currently configured for Pattern Role usage, disregard the assignment
         return array();
     }
     if (!defined('PPS_VERSION') && strpos($role_name, 'post_status:private') && isset($pattern_role_caps[$base_role_name]['read'])) {
         $pattern_role_caps[$base_role_name]['read_private_posts'] = true;
     }
     if (!empty($arr_name[3])) {
         if (empty($arr_name[4])) {
             // disregard stored roles with invalid status
             return array();
         } elseif ('post_status' == $arr_name[3]) {
             // ignore supplemental roles for statuses which are no longer active for this post type
             if (!pp_get_post_stati(array('name' => $arr_name[4], 'post_type' => $object_type))) {
                 return array();
             }
         }
     }
     // add all type-specific caps whose base property cap is included in this pattern role
     // i.e. If 'edit_posts' is in the pattern role, grant $type_obj->cap->edit_posts
     //
     if ($caps = array_intersect_key((array) get_object_vars($type_obj->cap), $pattern_role_caps[$base_role_name])) {
         // At least one type-defined cap is being cast from this pattern role for specified object_type
         $status_caps = apply_filters('pp_get_typecast_caps', $caps, $arr_name, $type_obj);
         if (!empty($arr_name[3]) && false === strpos($role_name, 'post_status:private') && $caps == $status_caps) {
             // if stored status value is invalid, don't credit user for "default statuses" type caps (but allow for subscriber-private if PPS inactive
             return array();
         } else {
             return apply_filters('pp_apply_arbitrary_caps', $status_caps, $arr_name, $type_obj);
         }
     }
     return $caps;
 }
Exemple #5
0
function _pp_get_type_roles($for_item_source, $for_item_type, $require_caps = false)
{
    global $pp_role_defs;
    $type_roles = array();
    if (empty($pp_role_defs->disabled_pattern_role_types[$for_item_type]) && post_type_exists($for_item_type)) {
        if ($require_caps) {
            $pp_cap_caster = pp_init_cap_caster();
            if (empty($pp_cap_caster->pattern_role_type_caps)) {
                $pp_cap_caster->define_pattern_caps();
            }
            $check_prop = taxonomy_exists($for_item_type) ? $pp_cap_caster->pattern_role_taxonomy_caps : $pp_cap_caster->pattern_role_type_caps;
        } else {
            $check_prop = array();
        }
        foreach ($pp_role_defs->pattern_roles as $role_name => $pattern_role) {
            if (!$check_prop || !empty($check_prop[$role_name])) {
                $type_roles["{$role_name}:{$for_item_source}:{$for_item_type}"] = $pattern_role->labels->singular_name;
            }
        }
    }
    // Consider WP roles which are enabled for direct supplemental assignment,
    // but only if they have at least one type-defined capability and are not disabled for the object type
    static $wp_type_roles = array();
    if (!isset($wp_type_roles[$for_item_source]) || !isset($wp_type_roles[$for_item_source][$for_item_type])) {
        $wp_type_roles[$for_item_source][$for_item_type] = array();
        if ($pp_role_defs->direct_roles) {
            global $wp_roles;
            if ('-1' === $for_item_type) {
                foreach (array_keys($pp_role_defs->direct_roles) as $role_name) {
                    $wp_type_roles[$for_item_source][$for_item_type][$role_name] = $pp_role_defs->direct_roles[$role_name]->labels->singular_name;
                }
            } elseif ($type_obj = pp_get_type_object($for_item_source, $for_item_type)) {
                $type_caps = (array) $type_obj->cap;
                $check_type_caps = array_diff_key(array_fill_keys($type_caps, true), array('read' => true));
                $cap_caster = pp_init_cap_caster();
                $cap_caster->define_pattern_caps();
                foreach (array_keys($pp_role_defs->direct_roles) as $role_name) {
                    if (array_intersect_key($check_type_caps, $wp_roles->role_objects[$role_name]->capabilities) || !empty($cap_caster->pattern_role_arbitrary_caps[$role_name])) {
                        $wp_type_roles[$for_item_source][$for_item_type][$role_name] = $pp_role_defs->direct_roles[$role_name]->labels->singular_name;
                    }
                }
            }
        }
    }
    $type_roles = array_merge($type_roles, $wp_type_roles[$for_item_source][$for_item_type]);
    return apply_filters('pp_get_type_roles', $type_roles, $for_item_source, $for_item_type);
}
    public static function _current_exceptions_ui($exc_results, $args = array())
    {
        global $pp_admin, $pp_role_defs, $pp_data_sources;
        $defaults = array('read_only' => false, 'class' => 'pp-group-roles', 'item_links' => false, 'caption' => '', 'link' => '', 'agent_type' => '');
        $args = array_merge($defaults, $args);
        extract($args);
        if (!$exc_results) {
            return;
        }
        if (!$caption) {
            $caption = 'user' == $agent_type ? sprintf(__('Exceptions %1$s(for user)%2$s', 'pp'), '<small>', '</small>') : __('Exceptions', 'pp');
        }
        require_once PPC_ABSPATH . '/lib/ancestry_lib_pp.php';
        $can_assign = current_user_can('pp_assign_roles') && pp_bulk_roles_enabled();
        $exceptions = array_fill_keys(array_merge(array('term', 'post'), pp_get_group_types()), array());
        $item_paths = array_fill_keys(array_keys($exceptions), array(__('(none)', 'pp')));
        // support imported include exception with no items included
        $post_types = pp_get_enabled_post_types(array(), 'names');
        $taxonomies = pp_get_enabled_taxonomies(array('object_type' => false), 'names');
        foreach ($exc_results as $row) {
            // object_type not strictly necessary here, included for consistency with term role array
            switch ($row->via_item_source) {
                case 'term':
                    if ($row->item_id) {
                        $taxonomy = '';
                        $term_id = (int) pp_ttid_to_termid($row->item_id, $taxonomy);
                        if ($row->item_id) {
                            $item_paths['term'][$row->item_id] = PP_Ancestry::get_term_path($term_id, $taxonomy);
                        }
                        $via_type = $taxonomy;
                    } else {
                        $via_type = $row->via_item_type;
                    }
                    break;
                case 'post':
                    if ($row->item_id) {
                        $item_paths['post'][$row->item_id] = PP_Ancestry::get_post_path($row->item_id);
                    }
                    // no break
                // no break
                default:
                    if (pp_group_type_exists($row->via_item_source)) {
                        static $groups_by_id;
                        if (!isset($groups_by_id)) {
                            $groups_by_id = array();
                        }
                        if (!isset($groups_by_id[$row->via_item_source])) {
                            $groups_by_id[$row->via_item_source] = array();
                            foreach (pp_get_groups($row->via_item_source, array('skip_meta_types' => 'wp_role')) as $group) {
                                $groups_by_id[$row->via_item_source][$group->ID] = $group->name;
                            }
                        }
                        if (isset($groups_by_id[$row->via_item_source][$row->item_id])) {
                            $item_paths[$row->via_item_source][$row->item_id] = $groups_by_id[$row->via_item_source][$row->item_id];
                        }
                        $via_type = $row->via_item_source;
                    } else {
                        $via_type = $row->via_item_type ? $row->via_item_type : $row->for_item_type;
                    }
            }
            if (!isset($exceptions[$row->via_item_source][$via_type])) {
                $exceptions[$row->via_item_source][$via_type] = array();
            }
            if (!isset($exceptions[$row->via_item_source][$via_type][$row->for_item_type])) {
                $exceptions[$row->via_item_source][$via_type][$row->for_item_type] = array();
            }
            if (!isset($exceptions[$row->via_item_source][$via_type][$row->for_item_type][$row->operation])) {
                $exceptions[$row->via_item_source][$via_type][$row->for_item_type][$row->operation] = array();
            }
            if (!isset($exceptions[$row->via_item_source][$via_type][$row->for_item_type][$row->operation][$row->mod_type])) {
                $exceptions[$row->via_item_source][$via_type][$row->for_item_type][$row->operation][$row->mod_type] = array();
            }
            if (!isset($exceptions[$row->via_item_source][$via_type][$row->for_item_type][$row->operation][$row->mod_type][$row->for_item_status])) {
                $exceptions[$row->via_item_source][$via_type][$row->for_item_type][$row->operation][$row->mod_type][$row->for_item_status] = array();
            }
            if (!isset($exceptions[$row->via_item_source][$via_type][$row->for_item_type][$row->operation][$row->mod_type][$row->for_item_status][$row->item_id])) {
                $exceptions[$row->via_item_source][$via_type][$row->for_item_type][$row->operation][$row->mod_type][$row->for_item_status][$row->item_id] = array();
            }
            $exceptions[$row->via_item_source][$via_type][$row->for_item_type][$row->operation][$row->mod_type][$row->for_item_status][$row->item_id][$row->assign_for] = $row->eitem_id;
            if (!empty($row->inherited_from)) {
                $exceptions[$row->via_item_source][$via_type][$row->for_item_type][$row->operation][$row->mod_type][$row->for_item_status][$row->item_id]['inherited_from'] = $row->inherited_from;
            }
        }
        echo '<div style="clear:both;"></div>' . "<div id='pp_current_exceptions' class='pp-group-box {$class}'>" . '<h3>';
        if ($link) {
            echo "<a href='{$link}'>{$caption}</a>";
        } else {
            echo $caption;
        }
        echo '</h3>';
        echo '<div>';
        echo '<div id="pp_current_exceptions_inner">';
        //ksort( $type_roles );
        if (empty($_REQUEST['all_types']) && !empty($exceptions['post'])) {
            $all_types = array_fill_keys(array_merge($post_types, $taxonomies, array('')), true);
            $all_types = array_diff_key($all_types, array('topic' => true, 'reply' => true));
            // hide topic, reply assignments even if they are somehow saved/imported without inherited_from value
            $exceptions['post'] = array_intersect_key($exceptions['post'], $all_types);
            foreach (array_keys($exceptions['post']) as $key) {
                $exceptions['post'][$key] = array_intersect_key($exceptions['post'][$key], $all_types);
            }
        }
        foreach (array_keys($exceptions) as $via_src) {
            ksort($exceptions[$via_src]);
            foreach (array_keys($exceptions[$via_src]) as $via_type) {
                if ($via_type_obj = pp_get_type_object($via_src, $via_type)) {
                    $via_type_caption = $via_type_obj->labels->singular_name;
                } else {
                    continue;
                }
                $any_redundant = false;
                echo "<div id='pp_current_{$via_src}_{$via_type}_roles' class='pp-current-exceptions'>";
                /*
                if ( 'term' == $via_src )
                	echo '<h4>' . __( 'Per-Term:', 'pp' ) . '</h4>';
                else {
                	if ( $object_type )
                		echo '<h4>' . sprintf( __( 'Per-%s:', 'pp' ), $type_caption ) . '</h4>';
                	else
                		echo '<h4>' . sprintf( __( 'Per-object:', 'pp' ), $type_caption ) . '</h4>';
                }
                
                echo '<h4>' . sprintf( __( '%s Exceptions', 'pp' ), $via_type_caption ) . '</h4>';
                */
                ksort($exceptions[$via_src][$via_type]);
                foreach (array_keys($exceptions[$via_src][$via_type]) as $for_type) {
                    if (pp_group_type_exists($for_type)) {
                        $for_src = $for_type;
                    } else {
                        $for_src = taxonomy_exists($for_type) || !$for_type ? 'term' : 'post';
                    }
                    if (!$for_type) {
                        $for_type_obj = (object) array('labels' => (object) array('singular_name' => __('(all post types)', 'pp')));
                    } elseif (!($for_type_obj = pp_get_type_object($for_src, $for_type))) {
                        continue;
                    }
                    foreach (array_keys($exceptions[$via_src][$via_type][$for_type]) as $operation) {
                        if (!($operation_obj = pp_get_op_object($operation, $for_type))) {
                            continue;
                        }
                        if ('assign' == $operation) {
                            $op_caption = $for_type ? sprintf(__('%1$s (%2$s: %3$s)', 'pp'), $operation_obj->label, $for_type_obj->labels->singular_name, $via_type_caption) : sprintf(__('%1$s %2$s %3$s', 'pp'), $operation_obj->label, $via_type_caption, $for_type_obj->labels->singular_name);
                        } elseif (in_array($operation, array('manage', 'associate'))) {
                            $op_caption = sprintf(__('%1$s %2$s', 'pp'), $operation_obj->label, $via_type_caption);
                        } else {
                            $op_caption = sprintf(__('%1$s %2$s', 'pp'), $operation_obj->label, $for_type_obj->labels->singular_name);
                        }
                        echo "<div class='type-roles-wrapper'>";
                        echo '<h4>' . $op_caption . '</h4>';
                        echo "<div class='pp-current-type-roles'>";
                        echo '<div class="pp-current-roles-tbl-wrapper"><table>';
                        // fill table body (item assignments for each role)
                        echo '<tbody>';
                        foreach (array_keys($exceptions[$via_src][$via_type][$for_type][$operation]) as $mod_type) {
                            if (!($mod_type_obj = pp_get_mod_object($mod_type))) {
                                continue;
                            }
                            foreach (array_keys($exceptions[$via_src][$via_type][$for_type][$operation][$mod_type]) as $status) {
                                if ($status) {
                                    $_status = explode(':', $status);
                                    if (count($_status) > 1) {
                                        $attrib = $_status[0];
                                        $_status = $_status[1];
                                    } else {
                                        $attrib = 'post_status';
                                        $_status = $status;
                                    }
                                    if ('post_status' == $attrib) {
                                        if ($status_obj = get_post_status_object($_status)) {
                                            $status_label = $status_obj->label;
                                        } elseif ('{unpublished}' == $_status) {
                                            // @todo: API
                                            $status_label = __('unpublished', 'pp');
                                        } else {
                                            $status_label = $status;
                                        }
                                    } else {
                                        $status_label = $status;
                                    }
                                    $mod_caption = sprintf(__('%1$s (%2$s)', 'pp'), $mod_type_obj->label, $status_label);
                                } else {
                                    $mod_caption = $mod_type_obj->label;
                                }
                                if ('exclude' == $mod_type && !empty($exceptions[$via_src][$via_type][$for_type][$operation]['include'])) {
                                    $tr_class = ' class="pp_faded"';
                                    $mod_caption = sprintf(__('* %s', 'pp'), $mod_caption);
                                    $any_faded = true;
                                } else {
                                    $tr_class = '';
                                }
                                echo "<tr{$tr_class}><td class='pp_item_role_caption'>{$mod_caption}</td>";
                                echo '<td>';
                                //if ( $item_links ) {
                                //	if ( 'term' != $scope )
                                //		$edit_url_base = $pp_data_sources->member_property( $item_source, '_edit_link' );
                                //}
                                echo "<div class='pp-role-terms-wrapper pp-role-terms-{$via_type}'>";
                                if ('term' == $via_src && !in_array($operation, array('manage', 'associate'))) {
                                    if (taxonomy_exists($via_type)) {
                                        // "Categories:"
                                        $tx_obj = get_taxonomy($via_type);
                                        $tx_caption = $tx_obj->labels->name;
                                    } else {
                                        $tx_caption = '';
                                    }
                                    echo '<div class="pp-taxonomy-caption">' . sprintf(__('%s:', 'pp'), $tx_caption) . '</div>';
                                    //$edit_url_base = ( isset($tx_obj->_edit_link) ) ? $tx_obj->_edit_link : '';
                                }
                                echo '<div class="pp-role-terms">';
                                $tx_item_paths = array_intersect_key($item_paths[$via_src], $exceptions[$via_src][$via_type][$for_type][$operation][$mod_type][$status]);
                                uasort($tx_item_paths, 'strnatcasecmp');
                                // sort by array values, but maintain keys );
                                foreach ($tx_item_paths as $item_id => $item_path) {
                                    //$assignment = $roles[$scope][$role_name][$item_source][$item_type][$item_id];
                                    $assignment = $exceptions[$via_src][$via_type][$for_type][$operation][$mod_type][$status][$item_id];
                                    $classes = array();
                                    if (isset($assignment['children'])) {
                                        if (isset($assignment['item'])) {
                                            $ass_id = $assignment['item'] . ',' . $assignment['children'];
                                            $classes[] = 'role_both';
                                            $any_both = true;
                                        } else {
                                            $ass_id = '0,' . $assignment['children'];
                                            $classes[] = 'role_ch';
                                            $any_child_only = true;
                                        }
                                    } else {
                                        $ass_id = $assignment['item'];
                                    }
                                    $class = $classes ? "class='" . implode(' ', $classes) . "'" : '';
                                    if ($read_only) {
                                        if ($item_links) {
                                            //$item_edit_url = sprintf($edit_url_base, $item_id);
                                            $item_edit_url = '';
                                            echo "<div><a href='{$item_edit_url}' {$class}>{$item_path}</a></div>";
                                        } else {
                                            echo "<div><span {$class}>{$item_path}</span></div>";
                                        }
                                    } else {
                                        $cb_id = 'pp_edit_exception_' . str_replace(',', '_', $ass_id);
                                        if (!empty($assignment['inherited_from'])) {
                                            $classes[] = 'inherited';
                                            $classes[] = "from_{$assignment['inherited_from']}";
                                        }
                                        if ($tr_class) {
                                            // apply fading for redundantly stored exclusions
                                            $classes[] = $tr_class;
                                        }
                                        $lbl_class = $classes ? "class='" . implode(' ', $classes) . "'" : '';
                                        if ('term' == $via_src) {
                                            $edit_url = admin_url("edit-tags.php?taxonomy={$via_type}&action=edit&tag_ID=" . pp_ttid_to_termid($item_id, $via_type) . "&post_type={$for_type}");
                                        } else {
                                            $edit_url = admin_url("post.php?post={$item_id}&action=edit");
                                        }
                                        echo "<div><label for='{$cb_id}' {$lbl_class}><input id='{$cb_id}' type='checkbox' name='pp_edit_exception[]' value='{$ass_id}' {$class}> " . $item_path . '</label><a href="' . $edit_url . '">' . __('edit') . '</a></div>';
                                    }
                                }
                                // end foreach item
                                if (count($tx_item_paths) > 3 && !$read_only) {
                                    $cb_id = "pp_check_all_{$via_src}_{$via_type}_{$for_type}_{$operation}_{$status}";
                                    echo "<div><label for='{$cb_id}'><input type='checkbox' id='{$cb_id}' class='pp_check_all'> " . __('(all)', 'pp') . '</label></div>';
                                }
                                echo '</div></div>';
                                // pp-role-terms, pp-role-terms-wrapper
                                echo '</td></tr>';
                            }
                            // end foreach status
                        }
                        // end foreach mod_type
                        echo '</tbody>';
                        echo '</table></div>';
                        // pp-current-roles-tbl-wrapper
                        echo '<div class="pp-exception-bulk-edit" style="display:none">';
                        echo "<select><option value=''>" . __ppw('Bulk Actions', 'pp') . "</option><option value='remove'>" . __ppw('Remove', 'pp') . '</option>';
                        if ('post' == $via_src && (!$via_type || $via_type_obj->hierarchical)) {
                            echo "<option value='propagate'>" . sprintf(__('Assign for selected and sub-%s', 'pp'), $via_type_obj->labels->name) . '</option>';
                            echo "<option value='unpropagate'>" . sprintf(__('Assign for selected %s only', 'pp'), $via_type_obj->labels->singular_name) . '</option>';
                            echo "<option value='children_only'>" . sprintf(__('Assign for sub-%s only', 'pp'), $via_type_obj->labels->name) . '</option>';
                        } elseif ('term' == $via_src && $via_type_obj->hierarchical) {
                            echo "<option value='propagate'>" . __('Assign for selected and sub-terms', 'pp') . '</option>';
                            echo "<option value='unpropagate'>" . __('Assign for selected term only', 'pp') . '</option>';
                            echo "<option value='children_only'>" . __('Assign for sub-terms only', 'pp') . '</option>';
                        }
                        echo '</select>';
                        //submit_button( __ppw('Apply'), 'button-secondary submit-edit-item-exception', '', false );
                        ?>
						<input type="submit" name="" class="button submit-edit-item-exception" value="<?php 
                        _e('Apply', 'pp');
                        ?>
" />
						<?php 
                        echo '<img class="waiting" style="display:none;" src="' . esc_url(admin_url('images/wpspin_light.gif')) . '" alt="" />';
                        echo '</div>';
                        // pp-exception-bulk-edit
                        echo '</div></div>';
                        // type-roles-wrapper, pp-current-type-roles
                    }
                    // end foreach operation
                }
                // end foreach for_type
                if ($any_redundant) {
                    echo '<div class="pp-current-roles-note">' . __('* = exceptions redundant due to a corresponding &quot;only these&quot; entry', 'pp') . '</div>';
                }
                if (!empty($via_type_obj->hierarchical)) {
                    $_caption = strtolower($via_type_obj->labels->name);
                    if (!empty($any_both) || !empty($any_child_only)) {
                        ?>
						<div class="pp-current-roles-note">

						<?php 
                        if (!empty($any_both)) {
                            echo '<span class="role_both" style="padding-right:20px">' . sprintf(__('... = assigned for %1$s and sub-%1$s', 'pp'), $_caption) . '</span>';
                        }
                        if (!empty($any_child_only)) {
                            echo '<span>' . sprintf(__('* = assigned for sub-%s only', 'pp'), $_caption) . '</span>';
                        }
                        ?>
						</div>
					<?php 
                    }
                    $show_all_url = esc_url(add_query_arg('show_propagated', '1', $_SERVER['REQUEST_URI']));
                    $show_all_link = "&nbsp;&nbsp;<a href='{$show_all_url}'>";
                    if (empty($_REQUEST['show_propagated'])) {
                        if ('term' == $via_src) {
                            echo '<div class="pp-current-roles-note">' . sprintf(__('note: Exceptions inherited from parent %1$s are not displayed. %2$sshow all%3$s', 'pp'), $_caption, $show_all_link, '</a>') . '</div>';
                        } else {
                            echo '<div class="pp-current-roles-note">' . sprintf(__('note: Exceptions inherited from parent %1$s or terms are not displayed. %2$sshow all%3$s', 'pp'), $_caption, $show_all_link, '</a>') . '</div>';
                        }
                    }
                }
                echo '</div>';
                // pp-current-exceptions
            }
            // end foreach via_type
        }
        // end foreach via_src
        echo '</div>';
        // pp_current_exceptions_inner
        echo '</div>';
        // no class
        echo '</div>';
        // pp_current_exceptions
    }