_x( 'Contributors', 'Pledges General Name', 'wporg' ), 'singular_name' => _x( 'Contributor', 'Pledge Singular Name', 'wporg' ), 'menu_name' => __( 'Five for the Future', 'wporg' ), 'archives' => __( 'Contributor Archives', 'wporg' ), 'attributes' => __( 'Contributor Attributes', 'wporg' ), 'parent_item_colon' => __( 'Parent Contributor:', 'wporg' ), 'all_items' => __( 'Contributors', 'wporg' ), 'add_new_item' => __( 'Add New Contributor', 'wporg' ), 'add_new' => __( 'Add New', 'wporg' ), 'new_item' => __( 'New Contributor', 'wporg' ), 'edit_item' => __( 'Edit Contributor', 'wporg' ), 'update_item' => __( 'Update Contributor', 'wporg' ), 'view_item' => __( 'View Contributor', 'wporg' ), 'view_items' => __( 'View Contributors', 'wporg' ), 'search_items' => __( 'Search Contributors', 'wporg' ), 'not_found' => __( 'Not found', 'wporg' ), 'not_found_in_trash' => __( 'Not found in Trash', 'wporg' ), 'insert_into_item' => __( 'Insert into contributor', 'wporg' ), 'uploaded_to_this_item' => __( 'Uploaded to this contributor', 'wporg' ), 'items_list' => __( 'Contributors list', 'wporg' ), 'items_list_navigation' => __( 'Contributors list navigation', 'wporg' ), 'filter_items_list' => __( 'Filter contributors list', 'wporg' ), ); $args = array( 'labels' => $labels, 'supports' => array( 'title' ), 'hierarchical' => false, 'public' => false, 'show_ui' => true, 'show_in_menu' => 'edit.php?post_type=' . Pledge\CPT_ID, 'menu_position' => 25, 'show_in_admin_bar' => false, 'show_in_nav_menus' => false, 'can_export' => false, 'taxonomies' => array(), 'has_archive' => false, 'exclude_from_search' => true, 'publicly_queryable' => false, 'capability_type' => 'page', 'capabilities' => array( 'create_posts' => 'do_not_allow' ), 'map_meta_cap' => true, 'show_in_rest' => false, // todo Maybe turn this on later. ); register_post_type( CPT_ID, $args ); } /** * Add columns to the Contributors list table. * * @param array $columns * * @return array */ function add_list_table_columns( $columns ) { $first = array_slice( $columns, 0, 2, true ); $last = array_slice( $columns, 2, null, true ); $new_columns = array( 'pledge' => __( 'Pledge', 'wporg' ), ); return array_merge( $first, $new_columns, $last ); } /** * Render content in the custom columns added to the Contributors list table. * * @param string $column * @param int $post_id * * @return void */ function populate_list_table_columns( $column, $post_id ) { switch ( $column ) { case 'pledge': $contributor = get_post( $post_id ); $pledge = get_post( $contributor->post_parent ); if ( ! $pledge ) { esc_html_e( 'Unattached', 'wordpressorg' ); break; } $pledge_name = get_the_title( $pledge ); if ( current_user_can( 'edit_post', $pledge->ID ) ) { $pledge_name = sprintf( '%2$s', get_edit_post_link( $pledge ), esc_html( $pledge_name ) ); } echo wp_kses_post( $pledge_name ); break; } } /** * Add one or more contributors to a pledge. * * Note that this does not validate whether a contributor's wporg username exists in the system. * * @param int $pledge_id The post ID of the pledge. * @param array $contributors Array of contributor wporg usernames. * * @return void */ function add_pledge_contributors( $pledge_id, $contributors ) { $results = array(); foreach ( $contributors as $wporg_username ) { $args = array( 'post_type' => CPT_ID, 'post_title' => sanitize_user( $wporg_username ), 'post_parent' => $pledge_id, 'post_status' => 'pending', ); $result = wp_insert_post( $args, true ); $results[ $wporg_username ] = ( is_wp_error( $result ) ) ? $result->get_error_code() : $result; } /** * Action: Fires when one or more contributors are added to a pledge. * * @param int $pledge_id The post ID of the pledge. * @param array $contributors Array of contributor wporg usernames. * @param array $results Associative array, key is wporg username, value is post ID on success, * or an error code on failure. */ do_action( FiveForTheFuture\PREFIX . '_add_pledge_contributors', $pledge_id, $contributors, $results ); } /** * Remove a contributor post from a pledge. * * This wrapper function ensures we have a standardized way of removing a contributor that will still * transition a post status (see PledgeMeta\update_confirmed_contributor_count). * * @param int $contributor_post_id * * @return false|WP_Post|null */ function remove_contributor( $contributor_post_id ) { $pledge_id = get_post( $contributor_post_id )->post_parent; $result = wp_trash_post( $contributor_post_id ); /** * Action: Fires when a contributor is removed from a pledge. * * @param int $pledge_id * @param int $contributor_post_id * @param WP_Post|false|null $result */ do_action( FiveForTheFuture\PREFIX . '_remove_contributor', $pledge_id, $contributor_post_id, $result ); return $result; } /** * Get the contributor posts associated with a particular pledge post. * * @param int $pledge_id The post ID of the pledge. * @param string $status Optional. 'all', 'pending', or 'publish'. * @param int $contributor_id Optional. Retrieve a specific contributor instead of all. * * @return array An array of contributor posts. If $status is set to 'all', will be * a multidimensional array with keys for each status. */ function get_pledge_contributors( $pledge_id, $status = 'publish', $contributor_id = null ) { $args = array( 'page_id' => $contributor_id, 'post_type' => CPT_ID, 'post_parent' => $pledge_id, 'numberposts' => -1, 'orderby' => 'title', 'order' => 'asc', ); if ( 'all' === $status ) { $args['post_status'] = array( 'pending', 'publish' ); } else { $args['post_status'] = sanitize_key( $status ); } $posts = get_posts( $args ); if ( 'all' === $status && ! empty( $posts ) ) { $initial = array( 'publish' => array(), 'pending' => array(), ); $posts = array_reduce( $posts, function( $carry, WP_Post $item ) { $carry[ $item->post_status ][] = $item; return $carry; }, $initial ); } return $posts; } /** * Get the user objects that correspond with pledge contributor posts. * * @param WP_Post[] $contributor_posts * * @return WP_User[] */ function get_contributor_user_objects( array $contributor_posts ) { return array_map( function( WP_Post $post ) { return get_user_by( 'login', $post->post_title ); }, $contributor_posts ); } /** * Only show the My Pledges menu to users who are logged in. * * @param array $menu_items * * @return array */ function hide_my_pledges_when_logged_out( $menu_items ) { if ( get_current_user_id() ) { return $menu_items; } foreach ( $menu_items as $key => $item ) { if ( home_url( 'my-pledges/' ) === $item->url ) { unset( $menu_items[ $key ] ); } } return $menu_items; } /** * Render the My Pledges shortcode. * * @return string */ function render_my_pledges() { $user = wp_get_current_user(); $profile_data = XProfile\get_contributor_user_data( $user->ID ); $pledge_url = get_permalink( get_page_by_path( 'for-organizations' ) ); $success_message = process_my_pledges_form(); $contributor_pending_posts = get_posts( array( 'title' => $user->user_login, 'post_type' => CPT_ID, 'post_status' => array( 'pending' ), 'numberposts' => 100, ) ); $contributor_publish_posts = get_posts( array( 'title' => $user->user_login, 'post_type' => CPT_ID, 'post_status' => array( 'publish' ), 'numberposts' => 100, ) ); $confirmed_pledge_ids = wp_list_pluck( $contributor_publish_posts, 'ID' ); ob_start(); require FiveForTheFuture\get_views_path() . 'list-my-pledges.php'; return ob_get_clean(); } /** * Process the My Pledges form. * * @return string */ function process_my_pledges_form() { $message = ''; $status = false; $contributor_post_id = filter_input( INPUT_POST, 'contributor_post_id', FILTER_VALIDATE_INT ); $pledge = get_post( get_post( $contributor_post_id )->post_parent ); $nonce = filter_input( INPUT_POST, '_wpnonce', FILTER_SANITIZE_STRING ); if ( filter_input( INPUT_POST, 'join_organization' ) ) { wp_verify_nonce( $nonce, 'join_decline_organization' ) || wp_nonce_ays( 'join_decline_organization' ); $status = 'publish'; $message = "You have joined the pledge from {$pledge->post_title}."; } elseif ( filter_input( INPUT_POST, 'decline_invitation' ) ) { wp_verify_nonce( $nonce, 'join_decline_organization' ) || wp_nonce_ays( 'join_decline_organization' ); $status = 'trash'; $message = "You have declined the pledge invitation from {$pledge->post_title}."; } elseif ( filter_input( INPUT_POST, 'leave_organization' ) ) { wp_verify_nonce( $nonce, 'leave_organization' ) || wp_nonce_ays( 'leave_organization' ); $status = 'trash'; $message = "You have left the {$pledge->post_title} pledge."; } if ( 'publish' === $status ) { wp_update_post( array( 'ID' => $contributor_post_id, 'post_status' => $status, ) ); } elseif ( 'trash' === $status ) { remove_contributor( $contributor_post_id ); } return $message; }