Manage a Pledge: Enable adding/removing contributors from wp-admin. (#99)

This updates the display of contributors into a table view, and adds the ability to add and remove contributors to existing pledges.

The display has been refactored to use JS templates & JSON contributor data– the data is output onto the page when loaded from the server, and rendered when the page finishes loading. Adding & removing contributors now submits to an admin-ajax.php endpoint, which, if successful, return the new list of contributors. This ensures the display is always up to date.

Fixes #3
This commit is contained in:
Kelly Dwan 2019-11-20 11:01:00 -05:00 committed by GitHub
parent f32d26ef47
commit 82192eea4c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 437 additions and 73 deletions

View file

@ -135,7 +135,7 @@ function populate_list_table_columns( $column, $post_id ) {
* @param int $pledge_id The post ID of the pledge.
* @param array $contributors Array of contributor wporg usernames.
*
* @return void
* @return array List of the new contributor post IDs, mapped from username => ID.
*/
function add_pledge_contributors( $pledge_id, $contributors ) {
$results = array();
@ -162,6 +162,8 @@ function add_pledge_contributors( $pledge_id, $contributors ) {
* or an error code on failure.
*/
do_action( FiveForTheFuture\PREFIX . '_add_pledge_contributors', $pledge_id, $contributors, $results );
return $results;
}
/**
@ -238,6 +240,43 @@ function get_pledge_contributors( $pledge_id, $status = 'publish', $contributor_
return $posts;
}
/**
* Get the contributor posts in the format used for the JS templates.
*
* @param int $pledge_id The post ID of the pledge.
*
* @return array An array of contributor data, ready to be used in the JS templates.
*/
function get_pledge_contributors_data( $pledge_id ) {
$contrib_data = array();
$contributors = get_pledge_contributors( $pledge_id, 'all' );
foreach ( $contributors as $contributor_status => $group ) {
$contrib_data[ $contributor_status ] = array_map(
function( $contributor_post ) use ( $contributor_status, $pledge_id ) {
$name = $contributor_post->post_title;
$contributor = get_user_by( 'login', $name );
return [
'pledgeId' => $pledge_id,
'contributorId' => $contributor_post->ID,
'status' => $contributor_status,
'avatar' => get_avatar( $contributor, 32 ),
// @todo Add full name, from `$contributor`?
'name' => $name,
'displayName' => $contributor->display_name,
'publishDate' => get_the_date( '', $contributor_post ),
'resendLabel' => __( 'Resend Confirmation', 'wporg' ),
'removeConfirm' => sprintf( __( 'Remove %s from this pledge?', 'wporg-5ftf' ), $name ),
'removeLabel' => sprintf( __( 'Remove %s', 'wporg' ), $name ),
];
},
$group
);
}
return $contrib_data;
}
/**
* Get the user objects that correspond with pledge contributor posts.
*

View file

@ -0,0 +1,79 @@
<?php
/**
* Handle submissions to admin-ajax.php.
*/
namespace WordPressDotOrg\FiveForTheFuture\Endpoints;
use WordPressDotOrg\FiveForTheFuture\{ Auth, Contributor, Email, PledgeForm };
add_action( 'wp_ajax_manage-contributors', __NAMESPACE__ . '\manage_contributors_handler' );
/**
* Handle the AJAX request for managing contributors on a pledge.
* This responds to adding, removing, and resending emails to contributors.
*/
function manage_contributors_handler() {
check_ajax_referer( 'manage-contributors', '_ajax_nonce' );
$action = filter_input( INPUT_POST, 'manage_action' );
$pledge_id = filter_input( INPUT_POST, 'pledge_id', FILTER_VALIDATE_INT );
$contributor_id = filter_input( INPUT_POST, 'contributor_id', FILTER_VALIDATE_INT );
$token = filter_input( INPUT_POST, '_token' );
$authenticated = Auth\can_manage_pledge( $pledge_id, $token );
if ( is_wp_error( $authenticated ) ) {
wp_die( wp_json_encode( [
'success' => false,
'message' => $authenticated->get_error_message(),
] ) );
}
switch ( $action ) {
case 'resend-contributor-confirmation':
$contribution = get_post( $contributor_id );
Email\send_contributor_confirmation_emails( $pledge_id, $contributor_id );
wp_die( wp_json_encode( [
'success' => true,
'message' => sprintf( __( 'Confirmation email sent to %s.', 'wporg-5ftf' ), $contribution->post_title ),
] ) );
break;
case 'remove-contributor':
// Trash contributor.
Contributor\remove_contributor( $contributor_id );
wp_die( wp_json_encode( [
'success' => true,
'contributors' => Contributor\get_pledge_contributors_data( $pledge_id ),
] ) );
break;
case 'add-contributor':
$pledge = get_post( $pledge_id );
$new_contributors = PledgeForm\parse_contributors( $_POST['contributors'] );
if ( is_wp_error( $new_contributors ) ) {
wp_die( wp_json_encode( [
'success' => false,
'message' => $new_contributors->get_error_message(),
] ) );
}
$contributor_ids = Contributor\add_pledge_contributors( $pledge_id, $new_contributors );
if ( 'publish' === $pledge->post_status ) {
foreach ( $contributor_ids as $contributor_id ) {
Email\send_contributor_confirmation_emails( $pledge_id, $contributor_id );
}
}
// Fetch all contributors, now that the new ones have been added.
$contributors = Contributor\get_pledge_contributors_data( $pledge_id );
wp_die( wp_json_encode( [
'success' => true,
'contributors' => $contributors,
] ) );
break;
}
// No matching action, we can just exit.
wp_die();
}

View file

@ -155,7 +155,8 @@ function render_form_manage() {
$updated = false;
// @todo Get pledge ID from somewhere.
$data = PledgeMeta\get_pledge_meta();
$data = PledgeMeta\get_pledge_meta();
$is_manage = true;
if ( 'Update Pledge' === $action ) {
$processed = process_form_manage();

View file

@ -202,14 +202,15 @@ function add_meta_boxes() {
* @param array $box
*/
function render_meta_boxes( $pledge, $box ) {
$readonly = ! current_user_can( 'edit_page', $pledge->ID );
$readonly = ! current_user_can( 'edit_page', $pledge->ID );
$is_manage = true;
$data = array();
foreach ( get_pledge_meta_config() as $key => $config ) {
$data[ $key ] = get_post_meta( $pledge->ID, META_PREFIX . $key, $config['single'] );
}
$contributors = Contributor\get_pledge_contributors( $pledge->ID, 'all' );
$contributors = Contributor\get_pledge_contributors_data( $pledge->ID );
echo '<div class="pledge-form">';
@ -279,13 +280,6 @@ function save_pledge( $pledge_id, $pledge ) {
get_page_by_path( 'for-organizations' )->ID
);
}
if ( filter_input( INPUT_POST, 'resend-contributor-confirmation' ) ) {
Email\send_contributor_confirmation_emails(
$pledge_id,
filter_input( INPUT_GET, 'resend-contributor-id', FILTER_VALIDATE_INT )
);
}
}
/**
@ -485,8 +479,25 @@ function enqueue_assets() {
$ver = filemtime( FiveForTheFuture\PATH . '/assets/css/admin.css' );
wp_register_style( '5ftf-admin', plugins_url( 'assets/css/admin.css', __DIR__ ), [], $ver );
$ver = filemtime( FiveForTheFuture\PATH . '/assets/js/admin.js' );
wp_register_script( '5ftf-admin', plugins_url( 'assets/js/admin.js', __DIR__ ), [ 'jquery', 'wp-util' ], $ver );
$script_data = [
'pledgeId' => get_the_ID(),
'manageNonce' => wp_create_nonce( 'manage-contributors' ),
];
wp_add_inline_script(
'5ftf-admin',
sprintf(
'var FiveForTheFuture = JSON.parse( decodeURIComponent( \'%s\' ) );',
rawurlencode( wp_json_encode( $script_data ) )
),
'before'
);
$current_page = get_current_screen();
if ( Pledge\CPT_ID === $current_page->id ) {
wp_enqueue_style( '5ftf-admin' );
wp_enqueue_script( '5ftf-admin' );
}
}