/** * Sends a notification email. * * @param string $type The type of notification to send * @param stdObj $post WP Post object * @param stdObj $comment WP Comment object * @param array $recipients Array of email addresses to send the notification to. This will merge with predetermined values. * @param mixed $single_user (id or WP User Object) User in which the notification directly refers to such as the User which was added as a reviewer. * @param $data array of supporting data for notifications * @return bool true if mail sent successfully, false otherwise. */ function annowf_send_notification($type, $post = null, $comment = null, $recipients = null, $single_user = null, $data = false) { // Ensure that workflow notifications are enabled. This is also enforced prior to calls to annowf_send_notification if (!anno_workflow_enabled('notifications')) { return false; } else { if (empty($type)) { return false; } } $notification = annowf_notification_message($type, $post, $comment, $single_user, $data); if (is_null($recipients) || !is_array($recipients)) { $recipients = annowf_notification_recipients($type, $post); } else { if (is_array($recipients)) { $recipients = array_merge($recipients, annowf_notification_recipients($type, $post)); } } $recipients = apply_filters('annowf_notification_recipients', array_unique($recipients), $type, $post); // Sitewide admin should never recieve any workflow notifications. $admin_email = get_option('admin_email'); if ($key = array_search($admin_email, $recipients)) { unset($recipients[$key]); } $headers = array('BCC: ' . implode(', ', array_unique($recipients))); return @wp_mail(null, $notification['subject'], $notification['body'], $headers); }
/** * Register article post type */ function anno_register_post_types() { if (anno_workflow_enabled()) { $capability_type = array('article', 'articles'); } else { $capability_type = 'post'; } $labels = array('name' => _x('Articles', 'post type name', 'anno'), 'singular_name' => _x('Article', 'post type singular name', 'anno'), 'add_new_item' => _x('Add New Article', 'post type plural name', 'anno'), 'edit_item' => _x('Edit Article', 'post type label', 'anno'), 'new_item' => _x('New Article', 'post type label', 'anno'), 'view_item' => _x('View Article', 'post type label', 'anno'), 'search_items' => _x('Search Articles', 'post type label', 'anno'), 'not_found' => _x('No Articles found', 'post type label', 'anno'), 'not_found_in_trash' => _x('No Articles found in Trash', 'post type label', 'anno'), 'menu_name' => _x('Articles', 'post type label, noun', 'anno')); $args = array('labels' => $labels, 'public' => true, 'show_ui' => true, 'has_archive' => true, 'hierarchical' => false, 'rewrite' => true, 'query_var' => 'articles', 'supports' => array('title', 'thumbnail', 'comments', 'revisions', 'author'), 'taxonomies' => array(), 'menu_position' => 5, 'capability_type' => $capability_type, 'menu_icon' => 'dashicons-welcome-write-blog'); register_post_type('article', $args); }
function annowf_setup() { if (anno_workflow_enabled()) { // Used in generating save buttons and proccess state changes global $anno_post_save; $anno_post_save = array('approve' => _x('Approve', 'Publishing box action button text', 'anno'), 'publish' => _x('Publish', 'Publishing box action button text', 'anno'), 'reject' => _x('Reject', 'Publishing box action button text', 'anno'), 'review' => _x('Submit For Review', 'Publishing box action button text', 'anno'), 'revisions' => _x('Request Revisions', 'Publishing box action button text', 'anno'), 'clone' => _x('Clone', 'Publishing box action button text', 'anno'), 'revert' => _x('Revert To Draft', 'Publishing box action button text', 'anno')); include_once ANNO_PLUGIN_PATH . '/workflow/users.php'; include_once ANNO_PLUGIN_PATH . '/workflow/workflow.php'; include_once ANNO_PLUGIN_PATH . '/workflow/audit.php'; include_once ANNO_PLUGIN_PATH . '/workflow/internal-comments/internal-comments.php'; include_once ANNO_PLUGIN_PATH . '/workflow/publishing-meta-box.php'; include_once ANNO_PLUGIN_PATH . '/workflow/notification.php'; } }
/** * Handles AJAX request for adding a co-author to a post. */ function annowf_add_co_author() { $response = annowf_add_user('co_author'); if ($response['message'] == 'success') { // Used for quick access when filtering posts on a post-author page $post_id = absint($_POST['post_id']); // Send email if (anno_workflow_enabled('notifications')) { $post = get_post($post_id); annowf_send_notification('co_author_added', $post, '', array($response['user']->user_email), $response['user']); } // Add author to JSON for appending to author dropdown $response['author'] = '<option value="' . $response['user']->ID . '">' . $response['user']->user_login . '</option>'; //Add to the audit log $current_user = wp_get_current_user(); annowf_save_audit_item($post_id, $current_user->ID, 6, array($response['user']->ID)); } unset($response['user']); echo json_encode($response); die; }
/** * Determines whether or not a user has the given abilities for a given post * * @param string $cap The capability to check * @param int $user_id The user id to check for a capability. Defaults to current user (global) * @param int $post_id The ID of the post to check Defaults to current post (global) * @param int $comment_id the ID of the comment to check * @return bool True if user has the given capability for the given post */ function anno_user_can($cap, $user_id = null, $post_id = null, $comment_id = null) { if (is_null($user_id)) { $current_user = wp_get_current_user(); $user_id = $current_user->ID; } if (is_null($post_id)) { $post_id = anno_get_post_id(); } if (!empty($_GET['revision'])) { $revision = get_post($_GET['revision']); $post_id = $revision->post_parent; } $post_state = annowf_get_post_state($post_id); $user_role = anno_role($user_id, $post_id); // Number of times this item has gone back to draft state. $post_round = get_post_meta($post_id, '_round', true); // WP role names $admin = 'administrator'; $editor = 'editor'; switch ($cap) { case 'administrator': case 'admin': if ($user_role == $admin) { return true; } break; case 'editor': case 'view_audit': if (in_array($user_role, array($admin, $editor))) { return true; } break; case 'trash_post': // Draft state, author or editor+ if (in_array($user_role, array($admin, $editor))) { return true; } else { if ($post_round < 1 && $post_state == 'draft' && $user_role == 'author') { return true; } } break; case 'view_post': // Published post state, or user is associated with the post if ($post_state == 'published' || $user_role) { return true; } break; case 'edit_slug': if ($user_role == $admin) { return true; } if ($user_role == $editor && $post_state == 'draft') { return true; } break; case 'edit_post': global $pagenow; // Allow edits for things such as typos (in any state) if ($user_role == $admin) { return true; } else { if ($user_role == $editor && $post_state && !in_array($post_state, array('published', 'rejected'))) { return true; } else { if (($user_role == 'author' || $user_role == 'co-author') && $post_state == 'draft') { return true; } else { if ($pagenow == 'post-new.php') { return true; } } } } break; case 'leave_review': // Only reviewers, and in_review state $reviewers = anno_get_reviewers($post_id); if (in_array($user_id, $reviewers) && $post_state == 'in_review') { return true; } break; case 'edit_comment': $comment = get_comment($comment_id); if ($user_role && in_array($user_role, array($editor, $admin)) || $user_id == $comment->user_id) { return true; } break; case 'add_general_comment': // Anyone who isn't a reviewer, attached to the post and not in published state if ($user_role && $user_role != 'reviewer') { return true; } break; case 'view_general_comment': case 'view_general_comments': if ($user_role) { return true; } break; case 'add_review_comment': // if user is reviewer or editor+ and state is in review if ($user_role && !in_array($user_role, array('author', 'co-author')) && $post_state == 'in_review') { return true; } break; case 'manage_co_authors': if ($user_role == $admin) { return true; } else { if ($user_role == $editor && $post_state && !in_array($post_state, array('published', 'rejected'))) { return true; } else { if ($user_role == 'author' && $post_state == 'draft') { return true; } } } break; case 'manage_public_comments': if (in_array($user_role, array($admin, $editor))) { return true; } break; case 'view_review_comment': // if user is or editor+ if (in_array($user_role, array($admin, $editor))) { return true; } // if user is reviewer and comment author = reviewer $comment = anno_internal_comments_get_comment_root($comment_id); if ($user_role == 'reviewer' && $comment && $comment->user_id == $user_id) { return true; } break; case 'view_reviewers': case 'view_review_comments': //Reviewer or editor+ if ($user_role && !in_array($user_role, array('author', 'co-author'))) { return true; } else { if ($user_role == 'author' && anno_workflow_enabled('author_reviewer')) { return true; } } break; case 'manage_reviewers': // if in review state and user is editor+ if (in_array($user_role, array($admin, $editor)) && in_array($post_state, array('submitted', 'in_review'))) { return true; } break; case 'alter_post_state': switch ($post_state) { case 'draft': // If not reviewer, and in draft state if ($user_role && !in_array($user_role, array('reviewer', 'co-author')) && $post_state == 'draft') { return true; } break; case 'submitted': case 'in_review': // Revert to draft // Revert to draft case 'rejected': // Must be an editor+ if (in_array($user_role, array($admin, $editor))) { return true; } break; // Must be a part of the publishing staff // Must be a part of the publishing staff case 'approved': if ($user_role == $admin) { return true; } break; case 'published': // No one can change a published article's status return false; break; default: break; } break; case 'clone_post': // Anyone can clone the post when its published if ($post_state == 'published' || $post_state == 'rejected') { return true; } break; case 'select_author': if ($user_role == $admin) { return true; } else { if ($user_role == $editor && !in_array($post_state, array('published', 'rejected'))) { return true; } else { if ($user_role == 'author' && $post_state == 'draft') { return true; } } } default: break; } // if we haven't returned, assume false return false; }
/** * Determines whether or not a user can edit, based on the workflow being active or not */ function anno_current_user_can_edit() { // User must have the WP permissions if (current_user_can('edit_article')) { $post_id = null; if (isset($_POST['attachment_id'])) { $post = get_post($_POST['attachment_id']); $post_id = $post->post_parent; } // Do an additional check if the workflow is enabled if (anno_workflow_enabled()) { if (anno_user_can('edit_post', null, $post_id)) { return true; } else { return false; } } return true; } return false; }
/** * Generate the Front portion of an article XML * * @param postObject $article Article to generate the XML for. * @return string XML generated */ private function xml_front($article) { // Journal Title $journal_title = cfct_get_option('journal_name'); if (!empty($journal_title)) { $journal_title_xml = '<journal-title-group> <journal-title>' . esc_html($journal_title) . '</journal-title> </journal-title-group>'; } else { $journal_title_xml = ''; } // Journal ID $journal_id = cfct_get_option('journal_id'); if (!empty($journal_id)) { $journal_id_type = cfct_get_option('journal_id_type'); if (!empty($journal_id_type)) { $journal_id_type_xml = ' journal-id-type="' . esc_attr($journal_id_type) . '"'; } else { $journal_id_type_xml = ''; } $journal_id_xml = '<journal-id' . $journal_id_type_xml . '>' . esc_html($journal_id) . '</journal-id>'; } else { $journal_id_xml = ''; } // Publisher ISSN $pub_issn = cfct_get_option('publisher_issn'); if (!empty($pub_issn)) { $pub_issn_xml = '<issn pub-type="epub">' . esc_html($pub_issn) . '</issn>'; } else { $pub_issn_xml = ''; } // Abstract $abstract = $article->post_excerpt; if (!empty($abstract)) { $abstract_xml = ' <abstract>' . $abstract . '</abstract>'; } else { $abstract_xml = ''; } // Funding Statement $funding = get_post_meta($article->ID, '_anno_funding', true); if (!empty($funding)) { $funding_xml = '<funding-group> <funding-statement>' . esc_html($funding) . '</funding-statement> </funding-group>'; } else { $funding_xml = ''; } // DOI $doi = get_post_meta($article->ID, '_anno_doi', true); if (!empty($doi)) { $doi_xml = '<article-id pub-id-type="doi">' . esc_html($doi) . '</article-id>'; } else { $doi_xml = ''; } // Article category. Theoretically, there can only be one! $cats = wp_get_object_terms($article->ID, 'article_category'); if (!empty($cats) && is_array($cats)) { $category = get_category($cats[0]); if (!empty($category)) { $category_xml = '<article-categories> <subj-group> <subject>' . esc_html($category->name) . '</subject> </subj-group> </article-categories>'; } else { $category_xml = ''; } } else { $category_xml = ''; } // Article Tags $tags = wp_get_object_terms($article->ID, 'article_tag'); if (!empty($tags) && is_array($tags)) { $tag_xml = '<kwd-group kwd-group-type="simple">'; foreach ($tags as $tag) { $tag = get_term($tag, 'article_tag'); $tag_xml .= '<kwd>' . esc_html($tag->name) . '</kwd>'; } $tag_xml .= ' </kwd-group>'; } else { $tag_xml = ''; } // Article title/subtitle $subtitle = get_post_meta($article->ID, '_anno_subtitle', true); $title_xml = '<title-group>'; if (!empty($article->post_title) || !empty($subtitle)) { $title_xml = '<title-group>'; if (!empty($article->post_title)) { $title_xml .= ' <article-title>' . esc_html($article->post_title) . '</article-title>'; } else { $title_xml .= ' <article-title />'; } if (!empty($subtitle)) { $title_xml .= ' <subtitle>' . esc_html($subtitle) . '</subtitle>'; } } $title_xml .= ' </title-group>'; // Publisher info $pub_name = cfct_get_option('publisher_name'); $pub_loc = cfct_get_option('publisher_location'); if (!empty($pub_name) || !empty($pub_loc)) { $publisher_xml = '<publisher>'; if (!empty($pub_name)) { $publisher_xml .= ' <publisher-name>' . esc_html($pub_name) . '</publisher-name>'; } if (!empty($pub_loc)) { $publisher_xml .= ' <publisher-loc>' . esc_html($pub_loc) . '</publisher-loc>'; } $publisher_xml .= ' </publisher>'; } else { $publisher_xml = ''; } $pub_date_xml = $this->xml_pubdate($article->post_date); // Authors $authors = get_post_meta($article->ID, '_anno_author_snapshot', true); if (!empty($authors) && is_array($authors)) { $author_xml = '<contrib-group>'; foreach ($authors as $author) { $author_xml .= ' <contrib>'; if (isset($author['surname']) && !empty($author['surname']) || isset($author['given_names']) && !empty($author['given_names']) || isset($author['prefix']) && !empty($author['prefix']) || isset($author['suffix']) && !empty($author['suffix'])) { $author_xml .= ' <name>'; if (isset($author['surname']) && !empty($author['surname'])) { $author_xml .= ' <surname>' . esc_html($author['surname']) . '</surname>'; } if (isset($author['given_names']) && !empty($author['given_names'])) { $author_xml .= ' <given-names>' . esc_html($author['given_names']) . '</given-names>'; } if (isset($author['prefix']) && !empty($author['prefix'])) { $author_xml .= ' <prefix>' . esc_html($author['prefix']) . '</prefix>'; } if (isset($author['suffix']) && !empty($author['suffix'])) { $author_xml .= ' <suffix>' . esc_html($author['suffix']) . '</suffix>'; } $author_xml .= ' </name>'; } // Affiliation legacy support if (!empty($author['affiliation']) || !empty($author['institution'])) { $author_xml .= ' <aff>'; if (!empty($author['affiliation'])) { $author_xml .= esc_html($author['affiliation']); } if (!empty($author['institution'])) { $author_xml .= '<institution>' . esc_html($author['institution']) . '</institution>'; } $author_xml .= '</aff>'; } if (isset($author['bio']) && !empty($author['bio'])) { $author_xml .= ' <bio><p>' . esc_html($author['bio']) . '</p></bio>'; } if (isset($author['link']) && !empty($author['link'])) { $author_xml .= ' <ext-link ext-link-type="uri" xlink:href="' . esc_url($author['link']) . '">' . esc_html($author['link']) . '</ext-link>'; } $author_xml .= ' </contrib>'; } $author_xml .= ' </contrib-group>'; } // Related Articles $related_xml = ''; if (anno_workflow_enabled()) { $related_articles = annowf_clone_get_ancestors($article->ID); } if (!empty($related_articles) && is_array($related_articles)) { foreach ($related_articles as $related_article_id) { $related_article = get_post($related_article_id); if (!empty($related_article) && $related_article->post_status == 'publish') { $related_xml .= '<related-article id="' . esc_attr('a' . $related_article->ID) . '" related-article-type="companion" ext-link-type="uri" xlink:href="' . esc_attr(get_permalink($related_article_id)) . '" '; $related_doi = get_post_meta($related_article_id, '_anno_doi', true); if (!empty($related_doi)) { $related_xml .= 'elocation-id="' . esc_attr($related_doi) . '" '; } // Queried for above if (!empty($journal_id)) { $related_xml .= 'journal_id="' . esc_attr($journal_id) . '" '; } // Queried for above if (!empty($journal_id_type)) { $related_xml .= 'journal_id_type="' . esc_attr($journal_id_type) . '" '; } $related_xml .= ' />'; } } } return '<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE article PUBLIC "-//NLM//DTD Journal Publishing DTD v3.0 20080202//EN" "journalpublishing3.dtd"> <article article-type="research-article" xml:lang="en" xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <?origin annotum?> <front> <journal-meta> ' . $journal_id_xml . ' ' . $journal_title_xml . ' ' . $pub_issn_xml . ' ' . $publisher_xml . ' </journal-meta> <article-meta> ' . $doi_xml . ' ' . $category_xml . ' ' . $title_xml . ' ' . $author_xml . ' ' . $pub_date_xml . ' ' . $abstract_xml . ' ' . $tag_xml . ' ' . $funding_xml . ' ' . $related_xml . ' </article-meta> </front>'; }
/** * Enforce general comment capabilities */ function anno_internal_comments_capabilities($allcaps, $caps, $args) { // $args are an array => 'capability_name' , 'user_id', 'additional args (obj id)' if ($args[0] == 'edit_comment') { $comment = get_comment($args[2]); if (!empty($comment) && ($comment->comment_type == 'article_general' || $comment->comment_type == 'article_review')) { if (anno_workflow_enabled()) { if (!anno_user_can('edit_comment', $args[1], '', $args[2])) { $allcaps = array(); } } else { $allcaps = array(); } } } return $allcaps; }
function anno_validate_on_save($post_id, $post) { remove_action('save_post_article', 'anno_validate_on_save', 999, 2); $error = false; $schema = trailingslashit(get_template_directory()) . 'functions/schema/kipling-jp3-partial.rng'; $body_content = anno_validation_prep_body($post->post_content_filtered, $post_id); $body_validation = anno_validate($body_content, $schema); $abstract_content = anno_validation_prep_abstract($post->post_excerpt); $abstract_validation = anno_validate($abstract_content, $schema); if (isset($body_validation['status']) && $body_validation['status'] == 'error') { $error = true; } if (isset($abstract_validation['status']) && $abstract_validation['status'] == 'error') { $error = true; } if ($error && $post->post_status == 'publish') { $post->post_status = 'draft'; if (anno_workflow_enabled()) { $status = 'pending'; update_post_meta($post_id, '_post_state', 'approved'); } else { $status = 'draft'; } add_filter('redirect_post_location', 'anno_validation_redirect_post_location_message'); remove_action('post_updated', 'annowf_transistion_state', 10, 3); remove_action('add_post_meta', 'anno_save_appendices_xml_as_html', 10, 3); remove_filter('wp_insert_post_data', 'anno_insert_post_data', null, 2); remove_filter('wp_insert_post_data', 'annowf_insert_post_data', 10, 2); wp_update_post(array('ID' => $post_id, 'post_status' => 'draft')); } }