'publish_'.self::$post_type_name_cap, 'edit_posts' => 'edit_'.self::$post_type_name_cap, 'edit_others_posts' => 'edit_others_'.self::$post_type_name_cap, 'delete_posts' => 'delete_'.self::$post_type_name_cap, 'delete_others_posts' => 'delete_others_'.self::$post_type_name_cap, 'read_private_posts' => 'read_private_'.self::$post_type_name_cap, 'edit_post' => 'edit_'.self::$post_type_name, 'delete_post' => 'delete_'.self::$post_type_name, 'read_post' => 'read_'.self::$post_type_name, ); // cache our options before doing anything, since everything else depends on them self::$options = self::get_all_options(); // fill all of our variables self::$instruction_nav_title = self::$options['manual_nav']; self::$instruction_page_title = self::$options['manual_title']; self::$admin_page_title = __("Site Notes Configuration", DSNMANAGER_TEXTDOMAIN); self::$admin_nav_title = __("Site Notes", DSNMANAGER_TEXTDOMAIN); self::$base = plugin_basename(__FILE__); // create the site note content type if(!defined('DSN_DISABLE_CHANGES')) { self::add_content_type(); } // add hooks add_filter('plugin_row_meta',array($this,'extra_plugin_links'),10,2); add_action('all_admin_notices',array($this,'all_admin_notices')); add_action('admin_init',array($this,'admin_init')); // add styles/scripts add_action('admin_enqueue_scripts',array($this,'enqueue_includes')); // add dashboard notes if there are any if(self::has_dashboard_notes()) { add_action('wp_dashboard_setup', array($this,'setup_dashboard')); } // add instruction manual page if entries exist if(self::has_instruction_notes()) { add_action( 'admin_menu', array($this,'admin_menu') ); } // add the options page if this user can manage the options if(self::user_has_admin()) { if(!defined('DSN_DISABLE_CHANGES')) { add_action('admin_menu', array($this,'add_config_menu')); add_action('admin_init', array($this,'register_settings')); } } } public static function enqueue_includes() { wp_register_style(self::$plugin_stylesheet_id, plugins_url('admin-dashboard-site-notes/admin-styles.css')); wp_enqueue_style(self::$plugin_stylesheet_id); wp_register_script(self::$plugin_script_id, plugins_url('admin-dashboard-site-notes/admin-scripts.js'),'jquery' ); wp_enqueue_script(self::$plugin_script_id); } // check if user is allowed to configure the plugin // only super admins are allowed, unless DSN_ADMIN_CONFIG is true, in which case any admin is allowed public static function user_has_admin() { return is_super_admin() || (defined('DSN_ADMIN_CONFIG') && current_user_can('manage_options')); } // get all wordpress roles, allowing them to be filtered by other plugins public static function get_roles() { global $wp_roles; if(!$wp_roles) { return array(); } $all_roles = $wp_roles->roles; $editable_roles = apply_filters('editable_roles', $all_roles); return $editable_roles; } // add the content type to the admin navigation public function admin_menu() { add_dashboard_page(self::$instruction_page_title, self::$instruction_nav_title, 'read', self::$plugin_id, array($this,'admin_page')); } // echo the instruction manual public static function admin_page() { echo "
"; echo "

" . self::$instruction_page_title . "

"; $posts = self::get_notes_by_parent(0); // generate table of contents $output = ''; foreach($posts as $post) { $output .= self::index_with_children($post); } echo "
"; echo "

" . __('Table of Contents', DSNMANAGER_TEXTDOMAIN) . "

"; echo $output; echo "
"; // generate instructions $output = ''; foreach($posts as $post) { $output .= self::note_with_children($post, 0, true); } echo "
"; echo $output; echo "
"; echo "
"; } public static function has_instruction_notes() { $args = array('action'=>'instruction','post_parent'=>0); $posts = self::get_notes($args); if(count($posts)) { return true; } return false; } public static function has_dashboard_notes() { $posts = self::get_notes_by_parent(0); if(count($posts)) { return true; } return false; } public function setup_dashboard() { wp_add_dashboard_widget('dsn_dashboard' , self::$options['dashboard_title'], array($this,'dsn_dashboard')); } public static function dsn_dashboard() { $posts = self::get_notes_by_parent(0); $output = ''; foreach($posts as $post) { $output .= self::note_with_children($post); } echo $output; } // recursively get the linked post title and it's children public static function index_with_children($post,$depth=0) { if($depth > 64) { // sanity check return __("Error: note output aborted, hierarchy too deep (>64)", DSNMANAGER_TEXTDOMAIN); } $output = "'; return $output; } // recursively get the post and it's children public static function note_with_children($post,$depth=0,$full_post=false) { if($depth > 64) { // sanity check return __("Error: note output aborted, hierarchy too deep (>64)", DSNMANAGER_TEXTDOMAIN); } $output = "'; return $output; } // returns the current custom post type if applicable, or false if not public static function current_post_type() { if(isset($_GET['post_type'])) { return $_GET['post_type']; } else if(isset($_GET['post'])) { global $post; if(isset($post->ID)) { return get_post_type($post->ID); } } return ''; } // returns the current action public static function current_action() { global $pagenow; switch($pagenow) { case 'index.php': if(isset($_GET['page'])) { if($_GET['page']==self::$plugin_id) { return 'instructions'; } break; } return 'dashboard'; case 'edit.php': return 'search'; case 'post-new.php': return 'new'; case 'post.php': return 'edit'; } return ''; } public static function get_current_loc($action=null) { $on_content_type = self::current_post_type(); if($action) { $on_action = 'instructions'; } else { $on_action = self::current_action(); } $loc = "loc_"; $loc .= $on_action; if($on_content_type) { $loc .= "_" . $on_content_type; } return $loc; } public static function get_everywhere_metakey() { return self::$custom_field_prefix . 'loc_all_' . self::current_post_type(); } public static function get_notes_by_parent($which_parent=0) { $args = array('post_parent'=>(int)$which_parent); return self::get_notes($args); } // return all notes public static function get_notes($args=array()) { global $wpdb, $current_user; if(!isset($current_user->caps)) { return; } $post_type_name = self::$post_type_name; if(isset($args['action'])) { $which_location = self::get_current_loc($args['action']); } else { $which_location = self::get_current_loc(); } // set up the subquery for role checking $wheres_arr = array(); $pre = self::$custom_field_prefix; $roles = $current_user->caps; foreach($roles as $role_name=>$role_arr) { $role = $wpdb->escape($role_name); $wheres_arr[] = " (meta_key = '{$pre}role_{$role}' AND meta_value = '1') "; } $where_str = implode(" OR ", $wheres_arr); if(!strlen($where_str)) { return; } $role_query = " SELECT post_id FROM {$wpdb->postmeta} WHERE {$where_str}"; $post_parent = ''; if(isset($args['post_parent'])) { if(is_array($args['post_parent'])) { $p = implode(',',$args['post_parent']); $post_parent = " AND {$wpdb->posts}.post_parent IN '{$p}' "; } else { $post_parent = " AND {$wpdb->posts}.post_parent = '{$args['post_parent']}' "; } } // build the full query if($which_location=='loc_instructions') { $sql = $wpdb->prepare(" SELECT * FROM {$wpdb->postmeta} LEFT JOIN {$wpdb->posts} ON {$wpdb->posts}.id = {$wpdb->postmeta}.post_id WHERE {$wpdb->posts}.post_status = 'publish' AND {$wpdb->posts}.post_type = '%s' AND ({$wpdb->postmeta}.meta_key = '%s' AND {$wpdb->postmeta}.meta_value = '0') AND {$wpdb->posts}.id IN ( {$role_query} ) {$post_parent} GROUP BY {$wpdb->posts}.id ORDER BY {$wpdb->posts}.menu_order ASC, {$wpdb->posts}.post_title ASC ", $post_type_name, self::$custom_field_prefix . 'instructions_exclude'); } else { $sql = $wpdb->prepare(" SELECT * FROM {$wpdb->postmeta} LEFT JOIN {$wpdb->posts} ON {$wpdb->posts}.id = {$wpdb->postmeta}.post_id WHERE {$wpdb->posts}.post_status = 'publish' AND {$wpdb->posts}.post_type = '%s' AND ( ({$wpdb->postmeta}.meta_key = '%s' AND {$wpdb->postmeta}.meta_value = '1') OR ({$wpdb->postmeta}.meta_key = '%s' AND {$wpdb->postmeta}.meta_value = '1') OR ({$wpdb->postmeta}.meta_key = '{$pre}loc_everywhere' AND {$wpdb->postmeta}.meta_value = '1') ) AND {$wpdb->posts}.id IN ( {$role_query} ) {$post_parent} GROUP BY {$wpdb->posts}.id ORDER BY {$wpdb->posts}.menu_order ASC, {$wpdb->posts}.post_title ASC ", $post_type_name, self::$custom_field_prefix . $which_location, self::get_everywhere_metakey() ); } $res = $wpdb->get_results($sql); return $res; } // apply our internal options to content and return what we actually want public static function get_content($post,$full_post=false) { $c = ''; if(self::$options['support_excerpt']) { $c = $post->post_excerpt; if(self::$options['use_excerpt_filter']) { $c = apply_filters('the_content', $c); } } if(!strlen(trim($c)) || $full_post) { $c = $post->post_content; if(self::$options['use_content_filter']) { $c = apply_filters('the_content', $c); } } return $c; } public static function get_note_meta($post_id, $key, $single=false) { return get_post_meta($post_id,self::$custom_field_prefix . $key,$single); } // Called on hook 'all_admin_notices' public function all_admin_notices() { // on the dashboard we print a pretty widget, not a notice if(self::current_action() == 'dashboard' || self::current_action() == 'instructions' || self::current_action() == '') { return; } $posts = self::get_notes(); $output = ''; if(count($posts)) { $g = self::$options['use_grouping']; if($g) $output .= "
"; foreach($posts as $post) { $hide_t = self::get_note_meta($post->ID, 'hide_title', true); if($hide_t) $t = ''; else $t = "
{$post->post_title}
"; $c = self::get_content($post); if($g) $output .= "
{$t}
{$c}
"; else $output .= "
{$t}
{$c}
"; } if($g) $output .= "
"; } echo $output; } // Called on wordpress hook 'admin_init' public function admin_init() { add_meta_box('display-location-div', __('When and where to display this message', DSNMANAGER_TEXTDOMAIN), array($this,'display_info_metabox'), 'dsn_note', 'normal', 'low'); add_action('save_post', array($this,'save_meta')); $types = get_post_types(); foreach($types as $type=>$type_obj) { if(!in_array($type,self::$exclude_types)) { self::$post_types[$type] = get_post_type_object($type); } } } // save all of our meta fields public static function save_meta($post_id) { // prevent wp from killing our custom fields during autosave if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) { return $post_id; } // only save these fields on dsn_notes if( (isset($_POST['post_type']) && $_POST['post_type'] != self::$post_type_name ) || (isset($_GET['post_type']) && $_GET['post_type'] != self::$post_type_name )) { return $post_id; } if(is_array($_POST) && count($_POST)) { self::check_and_save_checkbox('loc_dashboard',$post_id); self::check_and_save_checkbox('instructions_exclude',$post_id); self::check_and_save_checkbox('hide_title',$post_id); self::check_and_save_checkbox('loc_everywhere',$post_id); foreach(self::$post_types as $type=>$type_obj) { self::check_and_save_checkbox("loc_edit_".$type,$post_id); self::check_and_save_checkbox("loc_new_".$type,$post_id); self::check_and_save_checkbox("loc_search_".$type,$post_id); self::check_and_save_checkbox("loc_all_".$type,$post_id); } global $wp_roles; $roles = $wp_roles->roles; foreach($roles as $role_name=>$role_arr) { self::check_and_save_checkbox("role_".$role_name,$post_id); } } } // saves post data from checkboxes public static function check_and_save_checkbox($key,$post_id = null) { if(!$post_id) { global $post; $post_id = $post->ID; } $key = self::$custom_field_prefix . $key; if(isset($_POST[$key])) { update_post_meta($post_id, $key, 1); } else { update_post_meta($post_id, $key, 0); } } public static function get_checkbox($key, $msg, $class='', $is_checked=false) { $checked = ''; $key = self::$custom_field_prefix . $key; if(isset(self::$custom[$key][0]) && self::$custom[$key][0] == 1) { $checked = " checked='checked' "; } $ret = ""; $ret .= ""; $ret .= ""; $ret .= ""; return $ret; } public static function display_info_metabox() { global $post; self::$custom = get_post_custom($post->ID); $output = ''; $output .= "
"; $output .= "
"; $output .= "

" . __("Miscellaneous Options:", DSNMANAGER_TEXTDOMAIN) . "

"; $output .= "
"; $output .= self::get_checkbox("loc_dashboard",__("Include in the dashboard widget", DSNMANAGER_TEXTDOMAIN)); $output .= "
"; /* TODO: manual action settings $output .= "
"; $output .= "
"; $output .= self::get_checkbox("dsn_loc_manual",__("Include this note on the following pages (eg, options-general.php to appear on the Settings->General page).")); $output .= "
"; */ $output .= "
"; $output .= self::get_checkbox("instructions_exclude",__("Exclude from site instruction manual.", DSNMANAGER_TEXTDOMAIN)); $output .= "
"; $output .= "
"; $output .= self::get_checkbox("hide_title",__("Hide the title of this post for inline notes.", DSNMANAGER_TEXTDOMAIN)); $output .= "
"; $output .= "
"; // close #dsn_meta_other $roles = self::get_roles(); $output .= "
"; $output .= "

" . __("Show for the following roles:", DSNMANAGER_TEXTDOMAIN) . "

"; foreach($roles as $role_name=>$role_arr) { $output .= "
"; $output .= self::get_checkbox("role_".$role_name,translate_user_role($role_arr['name'])); $output .= "
"; } $output .= "
"; $output .= "
"; $output .= "

" . __("Display in the following locations:", DSNMANAGER_TEXTDOMAIN) . "

"; $output .= ""; $output .= ""; $ct = 0; foreach(self::$post_types as $type=>$type_obj) { if($ct++ % 2 == 0) $class = ' odd '; else $class = ' even '; $output .= ""; $output .= ""; $output .= ""; $output .= ""; $output .= ""; $output .= ""; $output .= ""; } $output .= "
        " . self::get_checkbox("loc_everywhere",__("Everywhere", DSNMANAGER_TEXTDOMAIN),'master_check') . "
{$type_obj->name}:" . self::get_checkbox("loc_edit_".$type,__("Edit", DSNMANAGER_TEXTDOMAIN),'child_check') . "" . self::get_checkbox("loc_new_".$type,__("New", DSNMANAGER_TEXTDOMAIN),'child_check') . "" . self::get_checkbox("loc_search_".$type,__("Search", DSNMANAGER_TEXTDOMAIN),'child_check') . "" . self::get_checkbox("loc_all_".$type,__("All", DSNMANAGER_TEXTDOMAIN),'parent_check',true) . "
"; $output .= "
"; // close #dsn_meta_locations $output .= "
"; // close #dsn_meta_box echo $output; } // Create the site note content type public function add_content_type() { $labels = array( 'name' => __( 'Site Notes' , DSNMANAGER_TEXTDOMAIN), 'singular_name' => __( 'Site Note' , DSNMANAGER_TEXTDOMAIN), 'add_new_item' => __( 'Add Site Note' , DSNMANAGER_TEXTDOMAIN), 'edit_item' => __( 'Edit Site Note' , DSNMANAGER_TEXTDOMAIN), 'new_item' => __( 'New Site Note' , DSNMANAGER_TEXTDOMAIN), 'view_item' => __( 'View Site Note' , DSNMANAGER_TEXTDOMAIN) ); $supports = array( 'editor'=>true, 'title'=>true, 'page-attributes'=>true, 'hierarchy'=>true ); $supports = array('title','editor','page-attributes'); if(self::$options['support_excerpt']) { $supports[] = 'excerpt'; } if(self::$options['support_customfields']) { $supports[] = 'custom-fields'; } if(self::$options['support_revisions']) { $supports[] = 'revisions'; } $args = array( 'labels' => $labels, 'public' => false, 'publicly_queryable' => false, 'show_ui' => true, 'show_in_menu' => true, 'hierarchical' => true, 'page-attributes' => true, 'revisions' => true, 'supports' => $supports, 'capability_type'=>self::$post_type_name_cap, 'capabilities'=>self::$capabilities, 'description' => __('Add helpful notes for site admins', DSNMANAGER_TEXTDOMAIN), ); register_post_type( self::$post_type_name,$args); } ///////// // // OPTIONS PAGE SECTION // ///////// // return all options, but also, if there were any defaults that weren't // already found in the db, update the options to include those new entries. // That ensures that we don't have to constantly use isset when working with // options, and also allows brand new options added in new versions to have // defaults set. public static function get_all_options() { $name = self::$plugin_id; $options = get_option($name); // set defaults $defaults = array( //'support_thumbnail' => true, //'support_author' => true, 'support_customfields' => false, 'support_revisions' => false, 'support_excerpt' => true, 'use_excerpt_filter' => false, 'use_content_filter' => true, 'use_grouping' => false, 'dashboard_title' => __('Admin Guide', DSNMANAGER_TEXTDOMAIN), 'manual_title' => __("Site Instruction Manual", DSNMANAGER_TEXTDOMAIN), 'manual_nav' => __("Site Instructions", DSNMANAGER_TEXTDOMAIN), ); $roles = self::get_roles(); foreach($roles as $role=>$role_obj) { $defaults['role_'.$role] = false; if($role=='administrator') { $defaults['role_administrator'] = true; // if role_administrator has never been set before, add capabilities // for using the post type. if(!isset($options['role_administrator'])) { global $wp_roles; $wp_roles->add_cap($role, self::$post_type_name_cap,true); foreach(self::$capabilities as $c=>$val) { $wp_roles->add_cap($role, $val, true); } } } } $changed = false; foreach($defaults as $name=>$value) { if( !isset($options[$name]) ) { $options[$name] = $value; $changed = true; } } if($changed) { update_option($name,$options); } return $options; } // register settings for options page function register_settings(){ register_setting( self::$plugin_id, self::$plugin_id, array($this,'plugin_options_validate') ); $section = 'plugin_main'; add_settings_section($section, __('General Settings', DSNMANAGER_TEXTDOMAIN), array($this,'settings_section_description'), self::$plugin_id); $section_roles = 'plugin_roles'; add_settings_section($section_roles, __('Permissions', DSNMANAGER_TEXTDOMAIN), array($this,'settings_section_roles_description'), self::$plugin_id); // TODO: add_settings_field('support_author',__('Add author name support'), array($this,'input_checkbox'), self::$plugin_id, 'plugin_main', array('id'=>'support_author')); // TODO: add_settings_field('support_thumbnail',__('Add thumbnail support'), array($this,'input_checkbox'), self::$plugin_id, 'plugin_main', array('id'=>'support_thumbnail')); $cb_check = array($this,'input_checkbox'); $cb_text = array($this,'input_textfield'); $roles = self::get_roles(); foreach($roles as $role=>$role_arr) { add_settings_field('role_' . $role, translate_user_role($role_arr['name']), $cb_check, self::$plugin_id, $section_roles, array('id'=>'role_'.$role)); } add_settings_field('support_customfields',__('Add custom field support', DSNMANAGER_TEXTDOMAIN), $cb_check, self::$plugin_id, $section, array('id'=>'support_customfields')); add_settings_field('support_revisions',__('Add revision support', DSNMANAGER_TEXTDOMAIN), $cb_check, self::$plugin_id, $section, array('id'=>'support_revisions')); add_settings_field('support_excerpt',__('Add excerpt support', DSNMANAGER_TEXTDOMAIN), $cb_check, self::$plugin_id, $section, array('id'=>'support_excerpt')); add_settings_field('use_excerpt_filter',__('Use content filter on excerpts', DSNMANAGER_TEXTDOMAIN), $cb_check, self::$plugin_id, $section, array('id'=>'use_excerpt_filter')); add_settings_field('use_content_filter',__('Use content filter on full notes', DSNMANAGER_TEXTDOMAIN), $cb_check, self::$plugin_id, $section, array('id'=>'use_content_filter')); add_settings_field('use_grouping',__('Group notes into one box', DSNMANAGER_TEXTDOMAIN), $cb_check, self::$plugin_id, $section, array('id'=>'use_grouping')); add_settings_field('dashboard_title', __('Dashboard widget title', DSNMANAGER_TEXTDOMAIN), $cb_text, self::$plugin_id, $section, array('id'=>'dashboard_title')); add_settings_field('manual_title', __('Instruction manual page title', DSNMANAGER_TEXTDOMAIN), $cb_text, self::$plugin_id, $section, array('id'=>'manual_title')); add_settings_field('manual_nav', __('Instruction manual nav title', DSNMANAGER_TEXTDOMAIN), $cb_text, self::$plugin_id, $section, array('id'=>'manual_nav')); } function input_checkbox($args) { $id = $args['id']; $name = self::$plugin_id; $checked = (self::$options[$id] ? " checked='checked' " : ' '); echo ""; echo ""; } function input_textfield($args) { $id = $args['id']; $name = self::$plugin_id; $value = esc_html(self::$options[$id]); echo ""; } function settings_section_description() { echo ''; } function settings_section_roles_description() { echo __('Assign the roles that can create and edit notes. Super-admins can always create and edit notes.', DSNMANAGER_TEXTDOMAIN); } function plugin_options_validate($input) { $options = get_option(self::$plugin_id); if(is_array($input)) { foreach($input as $key=>$val) { $options[$key] = $val; } // for each role, give/remove the edit capability // TODO: this should really go in a 'save options' hook, but it works fine here for now global $wp_roles; $roles = self::get_roles(); foreach($roles as $role=>$role_obj) { if(isset($input['role_'.$role]) && $input['role_'.$role]) { $wp_roles->add_cap($role, self::$post_type_name_cap,true); foreach(self::$capabilities as $c=>$val) { $wp_roles->add_cap($role, $val, true); } } else { $wp_roles->add_cap($role, self::$post_type_name_cap,false); foreach(self::$capabilities as $c=>$val) { $wp_roles->add_cap($role, $val, false); } } } } return $options; } // add the config page to the admin navigation under 'settings' function add_config_menu() { add_options_page(esc_html(self::$admin_page_title), esc_html(self::$admin_nav_title), 'manage_options', self::$plugin_id, array($this,'options_page')); } // admin options page function options_page() { if(!self::user_has_admin()) { wp_die(__("You don't have permission to access this page.", DSNMANAGER_TEXTDOMAIN)); } ?>

' . translate('Settings saved.') . '

'; } ?>
%s',$flattr_url, esc_html__('Flattr', DSNMANAGER_TEXTDOMAIN)), sprintf('%s',$paypal_url, esc_html__('Donate', DSNMANAGER_TEXTDOMAIN)) )); } return $data; } } $dsnmanager = null; function dsn_init_manager() { if(is_admin()) { global $dsnmanager; $dsnmanager = new DSNManager(); } } add_action('init','dsn_init_manager', 1);