'Character', 'plural' => 'Characters', 'ajax' => false ] ); } function get_columns() { return [ 'cb' => '', 'name' => __('Name', 'adventurebook'), 'id' => 'ID', 'lvl' => __('Might', 'adventurebook'), 'user' => __('User', 'adventurebook'), 'created_at'=> __('Created At', 'adventurebook'), 'adventurebook' => __('Adventurebook', 'adventurebook'), 'location' => __('Location', 'adventurebook'), ]; } function get_sortable_columns() { return [ 'id' => [ 'id', false ], 'name' => [ 'name', false ], 'lvl' => [ 'lvl', false ], 'created_at' => [ 'created_at', false], 'user' => [ 'user', false], ]; } function column_cb( $item ) { /** @var Character $item */ return sprintf( '', intval( $item->id) ); } function column_lvl( $item ): int { /** @var Character $item */ return $item->get_combat_strength(); } function column_default( $item, $column_name ) { global $wpdb; /** @var Character $item */ switch ( $column_name ) { case 'id': return $item->id; case 'name': return $this->column_name( $item ); case 'lvl': return $this->column_lvl( $item ); case 'user': // show username and link it to the user edit page $user_info = get_userdata( intval( $item->user_id ) ); if ( $user_info ) { return sprintf( '%s', esc_url( get_edit_user_link( $user_info->ID ) ), esc_html( $user_info->user_login ) ); } else { return __('Unknown User', 'adventurebook'); } case 'created_at': $timestamp = strtotime( $item->created_at ); if ( $timestamp ) { return date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $timestamp ); } else { return ''; } case 'adventurebook': // get the adventurebook title by id / it's the name of the CPT adventurebook $adventurebook_id = intval( $item->adventurebook_id ); $adventurebook_post = get_post( $adventurebook_id ); $adventurebook_title = $adventurebook_post ? $adventurebook_post->post_title : ''; if ( $adventurebook_title ) { return esc_html( $adventurebook_title ); } else { return __('Unknown Adventurebook', 'adventurebook'); } case 'location': // get the location name by id - it's the id of the CPT adventurebook_page $location_id = intval( $item->location_id ); $location_post = get_post( $location_id ); if ( $location_post ) { // return link to edit the adventurebook_page return sprintf( '%s', esc_url( get_edit_post_link( $location_post->ID ) ), esc_html( $location_post->post_title ) ); } else { return __('Unknown Location', 'adventurebook'); } default: return ''; } } function column_name( $character ) : string { /** @var Character $character */ $actions = [ 'edit' => sprintf( ''.__('Edit', 'adventurebook').'', $character->id ), 'delete' => sprintf( ''.__('Delete', 'adventurebook').'', $character->id, wp_create_nonce( 'adventurebook_delete_character_' . $character->id ) ), ]; return sprintf( '%s %s', esc_html( $character->get_name() ), $this->row_actions( $actions ) ); } function get_bulk_actions() { return [ 'bulk-delete' => __('Delete', 'adventurebook') ]; } function process_bulk_action() { global $wpdb; $action = $this->current_action(); if ( $action === 'bulk-delete' ) { if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ), 'bulk-characters' ) ) { $this->message = __('Nonce invalid.', 'adventurebook'); return; } $character_ids = isset( $_POST['character_ids'] ) ? array_map( 'intval', wp_unslash( $_POST['character_ids'] ) ) : []; if ( $character_ids ) { foreach ( $character_ids as $id ) { $wpdb->delete( "{$wpdb->prefix}adventurebook_characters", [ 'id' => $id ] );// phpcs:ignore WordPress.DB.DirectDatabaseQuery } $this->message = sprintf( '%d Characters deleted.', count( $character_ids ) ); } } } function prepare_characters() { if ( isset ($_REQUEST['s']) ) { // did we get ANY search request? If yes, check the nonce check_admin_referer( 'adventurebook_search_character' ); } global $wpdb; $this->process_bulk_action(); $per_page = 10; $current_page = $this->get_pagenum(); $offset = ( $current_page - 1 ) * $per_page; $allowed_orderby = [ 'id', 'name' ]; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $orderby = isset( $_GET['orderby'] ) ? sanitize_text_field( wp_unslash( $_GET['orderby'] ) ) : 'id'; if ( ! in_array( $orderby, $allowed_orderby, true ) ) { $orderby = 'id'; } $allowed_order = [ 'ASC', 'DESC' ]; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $order = isset( $_GET['order'] ) ? strtoupper( sanitize_text_field( wp_unslash( $_GET['order'] ) ) ) : 'DESC'; if ( ! in_array( $order, $allowed_order, true ) ) { $order = 'DESC'; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended $search = isset( $_REQUEST['s'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ) : ''; if ( $search !== '' ) { $like = '%' . $wpdb->esc_like( $search ) . '%'; $total_items = (int) $wpdb->get_var( $wpdb->prepare(// phpcs:ignore WordPress.DB.DirectDatabaseQuery "SELECT COUNT(*) FROM {$wpdb->prefix}adventurebook_characters WHERE name LIKE %s", $like ) ); $this->items_data = $wpdb->get_results( $wpdb->prepare(// phpcs:ignore WordPress.DB.DirectDatabaseQuery "SELECT * FROM " . $wpdb->prefix . "adventurebook_characters WHERE name LIKE %s ORDER BY $orderby $order LIMIT %d OFFSET %d",// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $like, $per_page, $offset ), ARRAY_A ); } else { $total_items = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}adventurebook_characters" );// phpcs:ignore WordPress.DB.DirectDatabaseQuery $this->items_data = $wpdb->get_results( $wpdb->prepare(// phpcs:ignore WordPress.DB.DirectDatabaseQuery "SELECT * FROM {$wpdb->prefix}adventurebook_characters ORDER BY $orderby $order LIMIT %d OFFSET %d",// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $per_page, $offset ), ARRAY_A ); } // now convert each item to a Character object foreach ( $this->items_data as $key => $item ) { $this->items_data[ $key ] = Character::get_character_by_id( $item['id'] ); } if ( ab_get('orderby') === 'lvl' ) { usort( $this->items_data, function( $a, $b ) use ( $order ) { $a_lvl = $a->get_combat_strength(); $b_lvl = $b->get_combat_strength(); if ( ab_get('order') === 'asc' ) { return $a_lvl <=> $b_lvl; } else { return $b_lvl <=> $a_lvl; } }); } $this->set_pagination_args( [ 'total_items' => $total_items, 'per_page' => $per_page, 'total_pages' => ceil( $total_items / $per_page ), ] ); $this->_column_headers = [ $this->get_columns(), [], $this->get_sortable_columns() ]; $this->items = $this->items_data; } public function get_message() { return $this->message; } } function adventurebook_characters_page() { // check for admin permissions if ( ! current_user_can( 'manage_options' ) ) { return; } global $wpdb; $message = ''; $is_list_view = ! isset( $_GET['action'] ) || ! in_array( $_GET['action'], [ 'new', 'edit' ], true ); // Speichern if ( isset( $_POST['adventurebook_save_character'] ) ) { $nonce = isset( $_POST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ) : ''; if ( $nonce && wp_verify_nonce( $nonce, 'adventurebook_save_character' ) ) { $id = isset( $_POST['id'] ) ? intval( $_POST['id'] ) : 0; $name = isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : ''; // stats is a JSON string, so we just unslash it $stats = isset( $_POST['stats'] ) ? sanitize_text_field(wp_unslash( $_POST['stats'] )) : '{}'; if ( $id > 0 ) { $wpdb->update( "{$wpdb->prefix}adventurebook_characters",// phpcs:ignore WordPress.DB.DirectDatabaseQuery compact( 'name', 'stats' ), [ 'id' => $id ] ); $message = __('Character updated.', 'adventurebook' ); } else { $wpdb->insert( "{$wpdb->prefix}adventurebook_characters",// phpcs:ignore WordPress.DB.DirectDatabaseQuery compact( 'name', 'stats' ) ); $message = __('Character created.', 'adventurebook' ); } $is_list_view = false; } else { $message = __('Invalid nonce.', 'adventurebook'); } } // Einzel-Löschen if ( isset( $_GET['action'], $_GET['id'] ) && $_GET['action'] === 'delete' ) { // check nonce $id = intval( sanitize_text_field(wp_unslash($_GET['id'] ))); $nonce = isset( $_GET['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) : ''; if ( $nonce && wp_verify_nonce( $nonce, 'adventurebook_delete_character_' . $id ) ) { $wpdb->delete( "{$wpdb->prefix}adventurebook_characters", [ 'id' => $id ] );// phpcs:ignore WordPress.DB.DirectDatabaseQuery $message = __('Character deleted.', 'adventurebook' ); } } echo '
' . esc_html( $message ) . '
'; if ( ! $is_list_view ) { echo ''; } echo '' . esc_html( $list_table->get_message() ) . '