$columns * @return array */ public function columns( array $columns ): array { $columns['senti_release_version'] = __( 'Version', 'senti-feedback' ); $columns['senti_release_date'] = __( 'Publication date', 'senti-feedback' ); return $columns; } /** * @internal */ public function render_column( string $column, int $post_id ): void { if ( $column === 'senti_release_version' ) { echo esc_html( (string) get_post_meta( $post_id, Identifiers::META_RELEASE_VERSION_LABEL, true ) ); } if ( $column === 'senti_release_date' ) { echo esc_html( (string) get_post_meta( $post_id, Identifiers::META_RELEASE_PUBLICATION_DATE, true ) ); } } /** * @internal * @param array $columns * @return array */ public function sortable_columns( array $columns ): array { $columns['senti_release_date'] = 'senti_release_date'; return $columns; } /** * @internal */ public function sort_collection( WP_Query $query ): void { if ( ! is_admin() || ! $query->is_main_query() || $query->get( 'post_type' ) !== Identifiers::POST_TYPE_RELEASE || $query->get( 'orderby' ) !== 'senti_release_date' ) { return; } $query->set( 'meta_key', Identifiers::META_RELEASE_PUBLICATION_DATE ); $query->set( 'orderby', 'meta_value' ); } /** * @internal */ public function render( WP_Post $post ): void { $version_label = (string) get_post_meta( $post->ID, Identifiers::META_RELEASE_VERSION_LABEL, true ); $publication_date = (string) get_post_meta( $post->ID, Identifiers::META_RELEASE_PUBLICATION_DATE, true ); $feedback_selected = $this->releases->feedback_ids( $post->ID ); $feedback_items = $this->load_relationship_items( Identifiers::POST_TYPE_FEEDBACK, $feedback_selected ); $roadmap_selected = $this->releases->roadmap_ids( $post->ID ); $roadmap_items = $this->load_relationship_items( Identifiers::POST_TYPE_ROADMAP, $roadmap_selected ); include dirname( __DIR__, 2 ) . '/templates/admin/metaboxes/release-details.php'; } /** * @internal * @param array $actions * @return array */ public function row_actions( array $actions, WP_Post $post ): array { if ( $post->post_type !== Identifiers::POST_TYPE_RELEASE || $post->post_status !== 'publish' || ! current_user_can( Capabilities::PUBLISH_RELEASES, $post->ID ) ) { return $actions; } $url = wp_nonce_url( add_query_arg( [ 'action' => 'senti_enqueue_release_notifications', 'release_id' => $post->ID, ], admin_url( 'admin-post.php' ) ), 'senti_enqueue_release_notifications_' . $post->ID ); $actions['senti_notify'] = '' . esc_html__( 'Notify subscribers', 'senti-feedback' ) . ''; return $actions; } /** * @internal */ public function save( int $post_id, WP_Post $post ): void { $nonce = isset( $_POST['senti_release_nonce'] ) && is_string( $_POST['senti_release_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['senti_release_nonce'] ) ) : ''; if ( $post->post_type !== Identifiers::POST_TYPE_RELEASE || ! wp_verify_nonce( $nonce, 'senti_release_save' ) || ! current_user_can( 'edit_post', $post_id ) || wp_is_post_revision( $post->ID ) || wp_is_post_autosave( $post->ID ) ) { return; } $version = isset( $_POST['senti_release_version'] ) && is_string( $_POST['senti_release_version'] ) ? sanitize_text_field( wp_unslash( $_POST['senti_release_version'] ) ) : ''; $date = isset( $_POST['senti_release_date'] ) && is_string( $_POST['senti_release_date'] ) ? sanitize_text_field( wp_unslash( $_POST['senti_release_date'] ) ) : ''; update_post_meta( $post_id, Identifiers::META_RELEASE_VERSION_LABEL, $version ); update_post_meta( $post_id, Identifiers::META_RELEASE_PUBLICATION_DATE, $date ); $feedback = isset( $_POST['senti_release_feedback'] ) && is_array( $_POST['senti_release_feedback'] ) ? array_map( 'absint', wp_unslash( $_POST['senti_release_feedback'] ) ) : []; $roadmap = isset( $_POST['senti_release_roadmap'] ) && is_array( $_POST['senti_release_roadmap'] ) ? array_map( 'absint', wp_unslash( $_POST['senti_release_roadmap'] ) ) : []; try { $this->releases->replace_feedback( $post_id, $feedback ); $this->releases->replace_roadmap( $post_id, $roadmap ); } catch ( ReleaseException ) { return; } } /** * @internal */ public function notifications_queued_notice(): void { $queued = isset( $_GET['senti_notifications_queued'] ) && is_string( $_GET['senti_notifications_queued'] ) && sanitize_text_field( wp_unslash( $_GET['senti_notifications_queued'] ) ) === '1'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This query value only displays a non-mutating notice after a nonce-verified action. if ( ! $queued ) { return; } include dirname( __DIR__, 2 ) . '/templates/admin/metaboxes/release-notice.php'; } /** * @param int[] $selected * @return WP_Post[] */ private function load_relationship_items( string $type, array $selected ): array { $items = get_posts( [ 'post_type' => $type, 'post_status' => [ 'publish', 'pending', 'draft' ], 'numberposts' => 100, 'orderby' => 'title', 'order' => 'ASC', ] ); $shown = wp_list_pluck( $items, 'ID' ); foreach ( array_diff( $selected, array_map( 'intval', $shown ) ) as $missing_id ) { $missing = get_post( $missing_id ); if ( $missing instanceof WP_Post ) { $items[] = $missing; } } return $items; } }