From 4fcecb647d1bf494e7091c4a1c44fd31130ea5b7 Mon Sep 17 00:00:00 2001 From: Ren <18050944+renintw@users.noreply.github.com> Date: Tue, 21 May 2024 03:51:42 +0800 Subject: [PATCH] Fix always show "the link you followed has expired" error page (#1321) * Fix always shows "the link you followed has expired" error page. In the last commit, the "extend the notes field for vendor payments" causes the "The link you followed has expired" message to always appear when saving a post. Therefore here only retains the part related to adding a new "Needs follow-up" status for payments and removes else. * PHPCS * Only shows the Needs Follow-up post under the Needs Follow-up tab. --- .../includes/payment-requests-dashboard.php | 1 - .../includes/payment-requests-list-table.php | 2 + .../includes/reimbursement-request.php | 122 ++++++ .../includes/wordcamp-budgets.php | 368 +++++------------- .../metabox-notes.php} | 12 +- .../views/wordcamp-budgets/metabox-notes.php | 42 -- 6 files changed, 236 insertions(+), 311 deletions(-) rename public_html/wp-content/plugins/wordcamp-payments/views/{wordcamp-budgets/metabox-notes-private.php => reimbursement-request/metabox-notes.php} (64%) delete mode 100644 public_html/wp-content/plugins/wordcamp-payments/views/wordcamp-budgets/metabox-notes.php diff --git a/public_html/wp-content/plugins/wordcamp-payments-network/includes/payment-requests-dashboard.php b/public_html/wp-content/plugins/wordcamp-payments-network/includes/payment-requests-dashboard.php index f51c2aeeab..fcc149ccd7 100644 --- a/public_html/wp-content/plugins/wordcamp-payments-network/includes/payment-requests-dashboard.php +++ b/public_html/wp-content/plugins/wordcamp-payments-network/includes/payment-requests-dashboard.php @@ -333,7 +333,6 @@ public static function get_current_tab() { $tabs = array( 'drafts', 'overdue', - 'pending-approval', 'approved', 'pending-payment', diff --git a/public_html/wp-content/plugins/wordcamp-payments-network/includes/payment-requests-list-table.php b/public_html/wp-content/plugins/wordcamp-payments-network/includes/payment-requests-list-table.php index 561bbdfb2c..b56fca8326 100644 --- a/public_html/wp-content/plugins/wordcamp-payments-network/includes/payment-requests-list-table.php +++ b/public_html/wp-content/plugins/wordcamp-payments-network/includes/payment-requests-list-table.php @@ -71,6 +71,8 @@ public function prepare_items() { $where .= " AND `status` IN ( 'wcb-failed', 'wcb-cancelled' ) "; } elseif ( 'drafts' == $view ) { $where .= " AND `status` = 'draft' "; + } elseif ( 'needs-followup' == $view ) { + $where .= " AND `status` = 'wcb-needs-followup' "; } if ( ! empty( $_REQUEST['s'] ) ) { diff --git a/public_html/wp-content/plugins/wordcamp-payments/includes/reimbursement-request.php b/public_html/wp-content/plugins/wordcamp-payments/includes/reimbursement-request.php index 65eb9644f1..0097455f46 100644 --- a/public_html/wp-content/plugins/wordcamp-payments/includes/reimbursement-request.php +++ b/public_html/wp-content/plugins/wordcamp-payments/includes/reimbursement-request.php @@ -163,6 +163,15 @@ function init_meta_boxes() { 'high' ); + add_meta_box( + 'wcbrr_notes', + esc_html__( 'Notes', 'wordcamporg' ), + __NAMESPACE__ . '\render_notes_metabox', + POST_TYPE, + 'side', + 'high' + ); + add_meta_box( 'wcbrr_general_information', esc_html__( 'General Information', 'wordcamporg' ), @@ -308,6 +317,19 @@ function render_status_metabox( $post ) { require_once dirname( __DIR__ ) . '/views/reimbursement-request/metabox-status.php'; } +/** + * Render the Notes metabox + * + * @param WP_Post $post + */ +function render_notes_metabox( $post ) { + wp_nonce_field( 'notes', 'notes_nonce' ); + + $existing_notes = get_post_meta( $post->ID, '_wcbrr_notes', true ); + + require_once dirname( __DIR__ ) . '/views/reimbursement-request/metabox-notes.php'; +} + /** * Render General Information Metabox * @@ -500,6 +522,10 @@ function save_request( $post_id, $post ) { verify_metabox_nonces(); + // phpcs:ignore is added because verify_metabox_nonces(); already checks that. + // phpcs:ignore WordPress.Security.NonceVerification.Missing + validate_and_save_notes( $post, $_POST['wcbrr_new_note'] ); + /* * We need to determine if the user is allowed to modify the request -- in terms of this plugin's post_status * restrictions, not in terms of current_user_can( 'edit_post', N ) -- but at this point in the execution @@ -651,6 +677,7 @@ function render_log_metabox( $post ) { function verify_metabox_nonces() { $nonces = array( 'status_nonce', + 'notes_nonce', 'general_information_nonce', 'payment_details_nonce', 'expenses_nonce', @@ -720,6 +747,101 @@ function validate_and_save_expenses( $post_id, $expenses ) { update_post_meta( $post_id, '_wcbrr_expenses', $expenses ); } +/** + * Validate and save expense data + * + * @param WP_Post $post + * @param string $new_note_message + */ +function validate_and_save_notes( $post, $new_note_message ) { + + // Save incomplete message. + // phpcs:ignore is used because verify_metabox_nonces(); already checks that. + if ( isset( $_POST['wcp_mark_incomplete_notes'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $safe_value = ''; + if ( 'wcb-incomplete' == $post->post_status ) { + $safe_value = wp_kses( $_POST['wcp_mark_incomplete_notes'], wp_kses_allowed_html( 'strip' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing + } + + update_post_meta( $post->ID, '_wcp_incomplete_notes', $safe_value ); + } + + $new_note_message = sanitize_text_field( wp_unslash( $new_note_message ) ); + + if ( empty( $new_note_message ) ) { + return; + } + + $notes = get_post_meta( $post->ID, '_wcbrr_notes', true ); + if ( ! is_array( $notes ) ) { + $notes = array(); + } + + $new_note = array( + 'timestamp' => time(), + 'author_id' => get_current_user_id(), + 'message' => $new_note_message, + ); + + $notes[] = $new_note; + + update_post_meta( $post->ID, '_wcbrr_notes', $notes ); + notify_parties_of_new_note( $post, $new_note ); + + \WordCamp_Budgets::log( + $post->ID, + get_current_user_id(), + sprintf( 'Note: %s', $new_note_message ), + array( + 'action' => 'note-added', + ) + ); +} + +/** + * Notify WordCamp Central or the request author when new notes are added + * + * @param WP_Post $request + * @param array $note + */ +function notify_parties_of_new_note( $request, $note ) { + $note_author = get_user_by( 'id', $note['author_id'] ); + + if ( $note_author->has_cap( 'manage_network' ) ) { + $to = \WordCamp_Budgets::get_requester_formatted_email( $request->post_author ); + $subject_prefix = sprintf( '[%s] ', get_wordcamp_name() ); + } else { + $to = 'support@wordcamp.org'; + $subject_prefix = ''; + } + + if ( ! $to ) { + return; + } + + $subject = sprintf( '%sNew note on `%s`', $subject_prefix, sanitize_text_field( $request->post_title ) ); + $note_author_name = \WordCamp_Budgets::get_requester_name( $note['author_id'] ); + $request_url = admin_url( sprintf( 'post.php?post=%s&action=edit', $request->ID ) ); + $headers = array( 'Reply-To: support@wordcamp.org' ); + + $message = sprintf( ' + %s has added the following note on the reimbursement request for %s: + + %s + + You can view the request and respond to their note at: + + %s', + sanitize_text_field( $note_author_name ), + sanitize_text_field( $request->post_title ), + sanitize_text_field( $note['message'] ), + esc_url_raw( $request_url ) + ); + $message = str_replace( "\t", '', $message ); + + wp_mail( $to, $subject, $message, $headers ); +} + /** * Notify the organizer when the status of their reimbursement changes or when notes are added * diff --git a/public_html/wp-content/plugins/wordcamp-payments/includes/wordcamp-budgets.php b/public_html/wp-content/plugins/wordcamp-payments/includes/wordcamp-budgets.php index 56c9a3a772..f803e2eebc 100644 --- a/public_html/wp-content/plugins/wordcamp-payments/includes/wordcamp-budgets.php +++ b/public_html/wp-content/plugins/wordcamp-payments/includes/wordcamp-budgets.php @@ -19,8 +19,6 @@ public function __construct() { add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_common_assets' ), 11 ); add_filter( 'user_has_cap', array( __CLASS__, 'user_can_view_payment_details' ), 10, 4 ); add_filter( 'default_title', array( $this, 'set_default_payments_title' ), 10, 2 ); - add_action( 'add_meta_boxes', array( $this, 'init_meta_boxes' ) ); - add_action( 'save_post', array( $this, 'save_request' ), 10, 2 ); } /** @@ -29,93 +27,117 @@ public function __construct() { public static function register_post_statuses() { // Uses core's draft status too. - register_post_status( 'wcb-incomplete', array( // phpcs:ignore PEAR.Functions.FunctionCallSignature.MultipleArguments - 'label' => esc_html_x( 'Incomplete', 'payment request', 'wordcamporg' ), - 'public' => false, - 'protected' => true, - 'label_count' => _nx_noop( - 'Incomplete (%s)', - 'Incomplete (%s)', - 'wordcamporg' - ), - ) ); + register_post_status( + 'wcb-incomplete', + array( + 'label' => esc_html_x( 'Incomplete', 'payment request', 'wordcamporg' ), + 'public' => false, + 'protected' => true, + 'label_count' => _nx_noop( + 'Incomplete (%s)', + 'Incomplete (%s)', + 'wordcamporg' + ), + ) + ); - register_post_status( 'wcb-pending-approval', array( // phpcs:ignore PEAR.Functions.FunctionCallSignature.MultipleArguments - 'label' => esc_html_x( 'Pending Approval', 'payment request', 'wordcamporg' ), - 'public' => false, - 'protected' => true, - 'label_count' => _nx_noop( - 'Pending Approval (%s)', - 'Pending Approval (%s)', - 'wordcamporg' - ), - ) ); + register_post_status( + 'wcb-pending-approval', + array( + 'label' => esc_html_x( 'Pending Approval', 'payment request', 'wordcamporg' ), + 'public' => false, + 'protected' => true, + 'label_count' => _nx_noop( + 'Pending Approval (%s)', + 'Pending Approval (%s)', + 'wordcamporg' + ), + ) + ); - register_post_status( 'wcb-needs-followup', array( // phpcs:ignore PEAR.Functions.FunctionCallSignature.MultipleArguments - 'label' => esc_html_x( 'Needs Follow-up', 'payment request', 'wordcamporg' ), - 'public' => false, - 'protected' => true, - 'label_count' => _nx_noop( - 'Needs Follow-up (%s)', - 'Needs Follow-up (%s)', - 'wordcamporg' - ), - ) ); + register_post_status( + 'wcb-needs-followup', + array( + 'label' => esc_html_x( 'Needs Follow-up', 'payment request', 'wordcamporg' ), + 'public' => false, + 'protected' => true, + 'label_count' => _nx_noop( + 'Needs Follow-up (%s)', + 'Needs Follow-up (%s)', + 'wordcamporg' + ), + ) + ); - register_post_status( 'wcb-approved', array( // phpcs:ignore PEAR.Functions.FunctionCallSignature.MultipleArguments - 'label' => esc_html_x( 'Approved', 'payment request', 'wordcamporg' ), - 'public' => false, - 'protected' => true, - 'label_count' => _nx_noop( - 'Approved (%s)', - 'Approved (%s)', - 'wordcamporg' - ), - ) ); + register_post_status( + 'wcb-approved', + array( + 'label' => esc_html_x( 'Approved', 'payment request', 'wordcamporg' ), + 'public' => false, + 'protected' => true, + 'label_count' => _nx_noop( + 'Approved (%s)', + 'Approved (%s)', + 'wordcamporg' + ), + ) + ); - register_post_status( 'wcb-pending-payment', array( // phpcs:ignore PEAR.Functions.FunctionCallSignature.MultipleArguments - 'label' => esc_html_x( 'Payment Sent', 'payment request', 'wordcamporg' ), - 'public' => false, - 'protected' => true, - 'label_count' => _nx_noop( - 'Payment Sent (%s)', - 'Payment Sent (%s)', - 'wordcamporg' - ), - ) ); + register_post_status( + 'wcb-pending-payment', + array( + 'label' => esc_html_x( 'Payment Sent', 'payment request', 'wordcamporg' ), + 'public' => false, + 'protected' => true, + 'label_count' => _nx_noop( + 'Payment Sent (%s)', + 'Payment Sent (%s)', + 'wordcamporg' + ), + ) + ); - register_post_status( 'wcb-paid', array( // phpcs:ignore PEAR.Functions.FunctionCallSignature.MultipleArguments - 'label' => esc_html_x( 'Paid', 'payment request', 'wordcamporg' ), - 'public' => false, - 'protected' => true, - 'label_count' => _nx_noop( - 'Paid (%s)', - 'Paid (%s)', - 'wordcamporg' - ), - ) ); + register_post_status( + 'wcb-paid', + array( + 'label' => esc_html_x( 'Paid', 'payment request', 'wordcamporg' ), + 'public' => false, + 'protected' => true, + 'label_count' => _nx_noop( + 'Paid (%s)', + 'Paid (%s)', + 'wordcamporg' + ), + ) + ); - register_post_status( 'wcb-failed', array( // phpcs:ignore PEAR.Functions.FunctionCallSignature.MultipleArguments - 'label' => esc_html_x( 'Failed', 'payment request', 'wordcamporg' ), - 'public' => false, - 'protected' => true, - 'label_count' => _nx_noop( - 'Failed (%s)', - 'Failed (%s)', - 'wordcamporg' - ), - ) ); + register_post_status( + 'wcb-failed', + array( + 'label' => esc_html_x( 'Failed', 'payment request', 'wordcamporg' ), + 'public' => false, + 'protected' => true, + 'label_count' => _nx_noop( + 'Failed (%s)', + 'Failed (%s)', + 'wordcamporg' + ), + ) + ); - register_post_status( 'wcb-cancelled', array( // phpcs:ignore PEAR.Functions.FunctionCallSignature.MultipleArguments - 'label' => esc_html_x( 'Cancelled', 'payment request', 'wordcamporg' ), - 'public' => false, - 'protected' => true, - 'label_count' => _nx_noop( - 'Cancelled (%s)', - 'Cancelled (%s)', - 'wordcamporg' - ), - ) ); + register_post_status( + 'wcb-cancelled', + array( + 'label' => esc_html_x( 'Cancelled', 'payment request', 'wordcamporg' ), + 'public' => false, + 'protected' => true, + 'label_count' => _nx_noop( + 'Cancelled (%s)', + 'Cancelled (%s)', + 'wordcamporg' + ), + ) + ); } /** @@ -868,186 +890,4 @@ public static function log( $post_id, $user_id, $message, $data = array() ) { update_post_meta( $post_id, '_wcp_log', wp_slash( $log ) ); } - - /** - * Register meta boxes - */ - public function init_meta_boxes() { - add_meta_box( - 'wcbrr_notes', - esc_html__( 'Notes', 'wordcamporg' ), - array( $this, 'render_notes_metabox' ), - array( 'wcb_reimbursement', 'wcp_payment_request' ), - 'side', - 'default' - ); - - if ( current_user_can( 'manage_network' ) ) { - add_meta_box( - 'wcbrr_notes_private', - esc_html__( 'Private notes', 'wordcamporg' ), - array( $this, 'render_notes_private_metabox' ), - array( 'wcb_reimbursement', 'wcp_payment_request' ), - 'side', - 'default' - ); - } - } - - /** - * Render the Notes metabox - * - * @param WP_Post $post - */ - public function render_notes_metabox( $post ) { - wp_nonce_field( 'notes', 'notes_nonce' ); - - $existing_notes = get_post_meta( $post->ID, '_wcbrr_notes', true ); - - require_once dirname( __DIR__ ) . '/views/wordcamp-budgets/metabox-notes.php'; - } - - /** - * Render the Private notes metabox - * - * @param WP_Post $post - */ - public function render_notes_private_metabox( $post ) { - wp_nonce_field( 'notes_private', 'notes_private_nonce' ); - - $existing_notes = get_post_meta( $post->ID, '_wcbrr_notes_private', true ); - - require_once dirname( __DIR__ ) . '/views/wordcamp-budgets/metabox-notes-private.php'; - } - - /** - * Save the post's data - * - * @param int $post_id - * @param WP_Post $post - */ - public function save_request( $post_id, $post ) { - if ( empty( $_POST ) || ! empty( $_POST['wcpn-request-import'] ) ) { - return; - } - - check_admin_referer( str_replace( '_nonce', '', 'notes_nonce' ), 'notes_nonce' ); - $this::validate_and_save_notes( $post, $_POST['wcbrr_new_note'] ); - - if ( current_user_can( 'manage_network' ) ) { - check_admin_referer( str_replace( '_nonce', '', 'notes_private_nonce' ), 'notes_private_nonce' ); - $this::validate_and_save_notes_private( $post, $_POST['wcbrr_new_note_private'] ); - } - } - - /** - * Validate and save notes. - * - * @param WP_Post $post - * @param string $new_note_message - */ - public function validate_and_save_notes( $post, $new_note_message ) { - $new_note_message = sanitize_text_field( wp_unslash( $new_note_message ) ); - - if ( empty( $new_note_message ) ) { - return; - } - - $notes = get_post_meta( $post->ID, '_wcbrr_notes', true ); - if ( ! is_array( $notes ) ) { - $notes = array(); - } - - $new_note = array( - 'timestamp' => time(), - 'author_id' => get_current_user_id(), - 'message' => $new_note_message, - ); - - $notes[] = $new_note; - - update_post_meta( $post->ID, '_wcbrr_notes', $notes ); - $this::notify_parties_of_new_note( $post, $new_note ); - - $this::log( $post->ID, get_current_user_id(), sprintf( 'Note: %s', $new_note_message ), array( // phpcs:ignore PEAR.Functions.FunctionCallSignature.MultipleArguments - 'action' => 'note-added', - ) ); - } - - /** - * Validate and save private notes. - * - * @param WP_Post $post - * @param string $new_note_message - */ - public function validate_and_save_notes_private( $post, $new_note_message ) { - $new_note_message = sanitize_text_field( wp_unslash( $new_note_message ) ); - - if ( empty( $new_note_message ) ) { - return; - } - - $notes = get_post_meta( $post->ID, '_wcbrr_notes_private', true ); - if ( ! is_array( $notes ) ) { - $notes = array(); - } - - $new_note = array( - 'timestamp' => time(), - 'author_id' => get_current_user_id(), - 'message' => $new_note_message, - ); - - $notes[] = $new_note; - - update_post_meta( $post->ID, '_wcbrr_notes_private', $notes ); - - $this::log( $post->ID, get_current_user_id(), __( 'Private note', 'wordcamporg' ), array( // phpcs:ignore PEAR.Functions.FunctionCallSignature.MultipleArguments - 'action' => 'note-added', - ) ); - } - - /** - * Notify WordCamp Central or the request author when new notes are added - * - * @param WP_Post $request - * @param array $note - */ - public function notify_parties_of_new_note( $request, $note ) { - $note_author = get_user_by( 'id', $note['author_id'] ); - - if ( $note_author->has_cap( 'manage_network' ) ) { - $to = $this::get_requester_formatted_email( $request->post_author ); - $subject_prefix = sprintf( '[%s] ', get_wordcamp_name() ); - } else { - $to = 'support@wordcamp.org'; - $subject_prefix = ''; - } - - if ( ! $to ) { - return; - } - - $subject = sprintf( '%sNew note on `%s`', $subject_prefix, sanitize_text_field( $request->post_title ) ); - $note_author_name = $this::get_requester_name( $note['author_id'] ); - $request_url = admin_url( sprintf( 'post.php?post=%s&action=edit', $request->ID ) ); - $headers = array( 'Reply-To: support@wordcamp.org' ); - - $message = sprintf( ' - %s has added the following note on the reimbursement request for %s: - - %s - - You can view the request and respond to their note at: - - %s', - sanitize_text_field( $note_author_name ), - sanitize_text_field( $request->post_title ), - sanitize_text_field( $note['message'] ), - esc_url_raw( $request_url ) - ); - $message = str_replace( "\t", '', $message ); - - wp_mail( $to, $subject, $message, $headers ); - } } diff --git a/public_html/wp-content/plugins/wordcamp-payments/views/wordcamp-budgets/metabox-notes-private.php b/public_html/wp-content/plugins/wordcamp-payments/views/reimbursement-request/metabox-notes.php similarity index 64% rename from public_html/wp-content/plugins/wordcamp-payments/views/wordcamp-budgets/metabox-notes-private.php rename to public_html/wp-content/plugins/wordcamp-payments/views/reimbursement-request/metabox-notes.php index d68aedd665..e014c65649 100644 --- a/public_html/wp-content/plugins/wordcamp-payments/views/wordcamp-budgets/metabox-notes-private.php +++ b/public_html/wp-content/plugins/wordcamp-payments/views/reimbursement-request/metabox-notes.php @@ -21,15 +21,19 @@
(visible to organizers)
- - - - - - -