Adventurebook Dashboard';
},
'dashicons-book',
6
);
} );
/**
* Register Adventurebook meta boxes reliably for all screens
*/
add_action( 'add_meta_boxes', 'adventurebook_register_metaboxes', 99 );
function adventurebook_register_metaboxes( $post_type ) {
if ( $post_type !== 'adventurebook_page' ) {
return;
}
/**
* add a meta box to the adventurebook_page post type to add additional resources "wood:100;stone:50;gold:20"
* resources can be harvested with the appropriate skill ("woodcutting" for wood, "mining" for stone or gold)
* the number after the colon indicates how many resources can be harvested on this page within 1 hour.
* it is capped by the character's skill (10 * level max per harvest action).
*/
// Resource Harvesting Box
add_meta_box(
'adventurebook_page_resources',
__( 'Resource Harvesting', 'adventurebook' ),
'adventurebook_page_resources_html',
'adventurebook_page',
'normal',
'high'
);
// Falls sie aus einem fehlerhaften Benutzerlayout "verschwunden" ist:
global $wp_meta_boxes;
if ( isset( $wp_meta_boxes['adventurebook_page']['side']['default']['adventurebook_page_resources'] ) ) {
$box = $wp_meta_boxes['adventurebook_page']['side']['default']['adventurebook_page_resources'];
unset( $wp_meta_boxes['adventurebook_page']['side']['default']['adventurebook_page_resources'] );
$wp_meta_boxes['adventurebook_page']['normal']['high']['adventurebook_page_resources'] = $box;
}
}
function adventurebook_admin_enqueue_select2( $hook ): void
{
// check if a CPT adventurebook_page is edited
if ( $hook !== 'post.php' && $hook !== 'post-new.php' ) {
return;
}
$base_url = plugin_dir_url( __FILE__ );
// Select2 lokal laden
wp_enqueue_style(
'adventurebook-select2',
$base_url . '../../css/select2.min.css',
[],
'4.1.0'
);
wp_enqueue_script(
'adventurebook-select2',
$base_url . '../../js/select2.min.js',
[ 'jquery' ],
'4.1.0',
true
);
// Eigenes Init-Skript
wp_enqueue_script(
'adventurebook-select2-init',
$base_url . '../../js/admin-select2-init.js',
[ 'adventurebook-select2' ],
'1.0.0',
true
);
// Übersetzbare Platzhaltertexte bereitstellen
wp_localize_script( 'adventurebook-select2-init', 'adventurebook_select2', [
'placeholder' => __( 'Select items...', 'adventurebook' ),
] );
}
add_action( 'admin_enqueue_scripts', 'adventurebook_admin_enqueue_select2' );
// Media Uploader Scripts nur auf den Adventurebook Items und Enemies Seiten laden
add_action( 'admin_enqueue_scripts', 'adventurebook_enqueue_media_scripts' );
function adventurebook_enqueue_media_scripts( $hook_suffix ): void
{
// check if this the adventurebook items or enemies page
if ( $hook_suffix !== 'adventurebook_page_adventurebook_items' &&
$hook_suffix !== 'adventurebook_page_adventurebook-enemies'
) {
return;
}
// Media Uploader Scripts laden
wp_enqueue_media();
}
// ----------------- PAGES -----------------
function adventurebook_set_parent_on_new_page( $post_id ): void
{
// prevent autosave effects
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
// check if the post type is 'adventurebook_page'
if ( get_post_type( $post_id ) != 'adventurebook_page' ) {
return;
}
if ( ! isset( $_GET['_adventurebook_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_adventurebook_nonce'] ) ), 'adventurebook_set_parent_action' ) ) {
return;
}
// check for editing rights
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
// check if the parent_adventurebook parameter is set in the URL
if ( isset( $_GET['parent_adventurebook'] ) &&
isset( $_GET['post_type'] ) &&
$_GET['post_type'] === 'adventurebook_page' ) {
$parent_id = intval( $_GET['parent_adventurebook'] );
// temporarily remove the hook to prevent infinite loops
remove_action( 'save_post', 'adventurebook_set_parent_on_new_page', 10, 3 );
// set the parent value
wp_update_post( array(
'ID' => $post_id,
'post_parent' => $parent_id,
) );
// add the hook back
add_action( 'save_post', 'adventurebook_set_parent_on_new_page', 10, 3 );
}
}
function adventurebook_page_resources_html(): void {
global $post;
wp_nonce_field('adventurebook_save_page_resources', 'adventurebook_nonce_page_resources');
// Combat System laden
$parent_id = wp_get_post_parent_id($post->ID);
// get the current combat system of the parent adventurebook
$combat_system = adventurebook_get_combat_system_for_adventurebook($parent_id);
$resources = $combat_system ? $combat_system->get_available_resources() : [];
// gespeicherte Werte
$stored = get_post_meta($post->ID, '_adventurebook_page_resources', true);
$parsed = [];
if ($stored) {
foreach (explode(';', $stored) as $pair) {
if (strpos($pair, ':') !== false) {
[$k, $v] = explode(':', $pair);
$parsed[$k] = intval($v);
}
}
}
$preselected_keys = array_keys($parsed);
?>
$amount): ?>
0) {
$result[] = sanitize_key($key) . ':' . $amount;
}
}
update_post_meta($post_id, '_adventurebook_page_resources', implode(';', $result));
}
/** * add a meta box to the adventurebook_page post type to select a script
*/
function adventurebook_add_page_script_meta_box(): void
{
add_meta_box(
'adventurebook_page_script', // Unique ID
__( 'Select Script', 'adventurebook' ), // Box title
'adventurebook_page_script_html', // Content callback
'adventurebook_page', // Post type
'side', // Context
'default' // Priority
);
}
function adventurebook_page_script_html( $post ): void
{
// retrieve the currently selected script
$script_code = get_post_meta( $post->ID, '_adventurebook_page_script', true );
// Nonce for security
wp_nonce_field( 'adventurebook_save_page_script', 'adventurebook_nonce_page_script' );
echo '';
echo '';
}
function adventurebook_save_page_script_meta_box_data( $post_id ): void
{
// Check if the user has permission to edit the post
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
// Verify the nonce
if ( ! isset( $_POST['adventurebook_nonce_page_script'] ) ||
! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['adventurebook_nonce_page_script'] ) ), 'adventurebook_save_page_script' ) ) {
return;
}
// check for editing rights
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
// Check if the script dropdown is set
if ( isset( $_POST['adventurebook_page_script'] ) ) {
$script_code = sanitize_text_field( wp_unslash( $_POST['adventurebook_page_script'] ) );
update_post_meta( $post_id, '_adventurebook_page_script', $script_code );
}
}
add_action( 'save_post', 'adventurebook_save_page_script_meta_box_data' );
add_action( 'add_meta_boxes', 'adventurebook_add_page_script_meta_box' );
/**
* add a meta box to the adventurebook post type with information about the adventurebook
* e.g. which enemy_definitions are used in this adventurebook
*/
add_action( 'add_meta_boxes', 'adventurebook_add_book_info_meta_box' );
function adventurebook_add_book_info_meta_box(): void
{
add_meta_box(
'adventurebook_book_info', // Unique ID
__( 'Adventurebook Info', 'adventurebook' ), // Box title
'adventurebook_book_info_html', // Content callback
'adventurebook', // Post type
'normal', // Context
'default' // Priority
);
}
function adventurebook_book_info_html( $post ): void
{
// Enemies
echo '
' . esc_html( __( 'Used Enemies in this Adventurebook', 'adventurebook' ) ) . '
';
} else {
// sort by name
usort( $enemy_definitions, function ( $a, $b ) {
return strcmp( $a->name, $b->name );
} );
echo '
';
foreach ( $enemy_definitions as $enemy_definition ) {
// show an edit link to the enemy definition edit page
$edit_url = admin_url( 'admin.php?page=adventurebook-enemies&action=edit&id=' . $enemy_definition->id );
echo '
';
} else {
// sort by name
usort( $item_definitions, function ( $a, $b ) {
return strcmp( $a->name, $b->name );
} );
echo '
';
foreach ( $item_definitions as $item_definition ) {
// show an edit link to the item definition edit page
$edit_url = admin_url( 'admin.php?page=adventurebook_items&action=edit&id=' . $item_definition->id );
echo '
';
foreach ( $scripts as $script ) {
// show an edit link to the script edit page
$edit_url = admin_url( 'admin.php?page=adventurebook_scripts&action=edit&id=' . $script->id );
echo '
post_parent;
// Abrufen aller Adventurebooks
$books = get_posts( array(
'post_type' => 'adventurebook',
'numberposts' => - 1,
'post_status' => 'publish',
'orderby' => 'title',
'order' => 'ASC',
) );
echo '';
// show a button to edit the selected parent adventurebook
if ( $current_parent_id ) {
$edit_link = get_edit_post_link( $current_parent_id );
echo '' . esc_html__( 'Edit Parent Book', 'adventurebook' ) . '';
}
}
/**
* Filtert die Post-Daten vor dem Speichern und setzt den Parent,
* falls das Dropdown-Feld übergeben wurde.
*/
add_filter( 'wp_insert_post_data', 'adventurebook_handle_parent_dropdown', 10, 2 );
function adventurebook_handle_parent_dropdown( $data, $postarr ) {
// Nur für unseren CPT
if ( $data['post_type'] !== 'adventurebook_page' ) {
return $data;
}
// Wenn kein POST-Kontext existiert (z. B. WP-CLI), abbrechen
if ( empty( $_POST ) ) {
return $data;
}
// Nonce prüfen
if (
! isset( $_POST['adventurebook_nonce_parent'] ) ||
! wp_verify_nonce(
sanitize_text_field( wp_unslash( $_POST['adventurebook_nonce_parent'] ) ),
'adventurebook_save_parent'
)
) {
return $data;
}
// Rechte prüfen
if ( ! current_user_can( 'edit_post', $postarr['ID'] ) ) {
return $data;
}
// Wenn das Dropdown-Feld vorhanden ist, Parent übernehmen
if ( isset( $_POST['adventurebook_parent_dropdown'] ) ) {
$data['post_parent'] = intval( $_POST['adventurebook_parent_dropdown'] );
}
return $data;
}
// Callback-Funktion, um das Metabox-HTML anzuzeigen
function adventurebook_type_meta_box_callback( $post ) {
// Hole den gespeicherten Wert aus der Post-Meta
$adventurebook_type = get_post_meta( $post->ID, '_adventurebook_type', true );
// Sicherheit: Nonce-Feld für die Verifizierung beim Speichern
wp_nonce_field( 'adventurebook_save_type', 'adventurebook_nonce_type' );
?>
ID, '_additional_image', true );
$image_url = wp_get_attachment_url( $image_id );
?>
'text/html' ) );
wp_enqueue_script( 'code-editor' );
wp_enqueue_style( 'code-editor' );
// vis.js for map visualization
wp_enqueue_script(
'vis-network',
$plugin_url .'../vis-4.21.0/dist/vis-network.min.js',
[],
'9.1.6', // oder deine Version
true
);
// include the custom script
$version = filemtime( $plugin_path . '../../js/adventurebook_admin.js' );
wp_enqueue_script( 'adventurebook-custom-script', $plugin_url . '../../js/adventurebook_admin.js', array( 'jquery' ), $version, true );
// AJAX URL und Nonce an das JavaScript übergeben
wp_localize_script( 'adventurebook-custom-script', 'adventurebook_ajax', array(
'ajax_url' => admin_url( 'admin-ajax.php' ), // WordPress AJAX-URL
'nonce' => wp_create_nonce( 'adventurebook_ajax_nonce' ) // Nonce zur Sicherheit
) );
// PHP-Daten vorbereiten
global $post;
// get the parent page id of this post
$book_id = wp_get_post_parent_id( $post );
// get the game type of the parent book
$book_type = get_post_meta( $book_id, '_adventurebook_type', true );
// get all pages of the same book
$pages = get_posts( array(
'post_type' => 'adventurebook_page',
'post_parent' => $book_id,
'post_status' => 'publish',
'numberposts' => - 1,
'orderby' => 'title',
'order' => 'ASC',
) );
$pages_data = array_map( function ( $page ) {
return [
'ID' => $page->ID,
'title' => $page->post_title,
];
}, $pages );
// include the decision options script
// the script needs the $adventurebook_decision_dirs variable from admin_decisions.php
wp_enqueue_script( 'adventurebook-decision-options',
$plugin_url .
'../../js/adventurebook_admin_decision_options.js',
array( 'jquery' ),
$version,
true );
wp_localize_script( 'adventurebook-decision-options', 'adventurebook_decision_dirs', $adventurebook_decision_dirs );
// Übersetzungen und Seiten als JS-Variablen verfügbar machen
wp_localize_script( 'adventurebook-decision-options', 'adventurebook_pages', $pages_data );
// JS also needs the available restriction types
global $adventurebook_restriction_types;
wp_localize_script( 'adventurebook-decision-options', 'adventurebook_restriction_types', $adventurebook_restriction_types );
wp_localize_script( 'adventurebook-decision-options', 'adventurebook_book_type', [$book_type] );
wp_localize_script( 'adventurebook-decision-options', 'adventurebook_i18n', [
'label' => __( 'Label', 'adventurebook' ),
'target' => __( 'Target Page', 'adventurebook' ),
'select_page' => __( 'Select a page', 'adventurebook' ),
'generate_new_page' => __( 'Generate new page', 'adventurebook' ),
'remove' => __( 'Remove', 'adventurebook' ),
'new_page_title' => __( 'New Page Title', 'adventurebook' ),
'new_page_backlink' => __( 'Backlink Label', 'adventurebook' ),
'restriction_type' => __( 'Restriction Type', 'adventurebook' ),
'restriction_value' => __( 'Restriction Value', 'adventurebook' ),
'add_decision' => __( 'Add Decision', 'adventurebook' ),
'decision_dir' => __( 'Direction', 'adventurebook' ),
] );
// translate strings for JS
$selected = isset($_GET['book_id']) ? intval(ab_get('book_id')) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$graph = $selected ? adventurebook_generate_map_graph_for_book($selected) : ['nodes'=>[], 'edges'=>[]];
wp_localize_script('adventurebook-custom-script', 'adventurebookMapData', [
'graph' => $graph,
'ajax_url' => admin_url('admin-ajax.php'),
'selected' => $selected,
'edit_url' => admin_url('post.php?action=edit&post='),
]);
}
// --- Dropdown for Game-type Adventurebook Combat Systems ---
add_action( 'add_meta_boxes', function () {
add_meta_box(
'adventurebook_combat_system',
__( 'Combat System', 'adventurebook' ),
'adventurebook_render_adventurebook_combat_system_meta_box',
'adventurebook',
'side',
'default'
);
} );
function adventurebook_render_adventurebook_combat_system_meta_box($post ) {
wp_nonce_field( 'adventurebook_combat_system_save', 'adventurebook_combat_system_nonce' );
// Aktueller Typ
$adventurebook_type = get_post_meta( $post->ID, '_adventurebook_type', true );
// Nur anzeigen, wenn Typ == "Game"
if ( $adventurebook_type !== 'game' ) {
echo '
' . esc_html( __( 'No Combat System, Adventurebook-Type is not "Game".', 'adventurebook' ) ) . '
';
return;
}
// Gespeicherter Wert
$selected_system = get_post_meta( $post->ID, '_adventurebook_combat_system', true );
$systems = adventurebook_get_all_combat_systems();
// Dropdown
?>
get_name();
}
}
}
return $systems;
}
/**
* returns an instance of the combat system for the given adventurebook
* or null if no combat system is set or the class does not exist
*
* @param $adventurebook_id
*
* @return Adventurebook\Combat_System|null
*/
function adventurebook_get_combat_system_for_adventurebook($adventurebook_id ): ?Adventurebook\Combat_System {
$adventurebook_combat_system_class = "Adventurebook\\" . get_post_meta( $adventurebook_id, '_adventurebook_combat_system', true );
if ( $adventurebook_combat_system_class && class_exists( $adventurebook_combat_system_class ) ) {
return new $adventurebook_combat_system_class();
}
return null;
}
function adventurebook_get_combat_system_for_character_id($character_id ): ?Adventurebook\Combat_System {
$character = Character::get_character_by_id( $character_id );
if ( $character ) {
return adventurebook_get_combat_system_for_adventurebook( $character->adventurebook_id );
}
return null;
}
#region --- CUSTOM POST TYPE "adventurebook" ---
// 1. Add a new column to the CPT admin table
add_filter( 'manage_adventurebook_posts_columns', function ( $columns ) {
// Insert new column after the Title column
$new = [];
foreach ( $columns as $key => $value ) {
$new[ $key ] = $value;
if ( 'title' === $key ) {
$new['page_id'] = __( 'ID', 'adventurebook' );
}
}
return $new;
} );
// 2. Render the column content
add_action( 'manage_adventurebook_posts_custom_column', function ( $column_name, $post_id ) {
if ( 'page_id' === $column_name ) {
echo intval( $post_id );
}
}, 10, 2 );
// 3. (Optional) Make it sortable
add_filter( 'manage_edit-adventurebook_sortable_columns', function ( $columns ) {
$columns['page_id'] = 'ID';
return $columns;
} );
/**
* Register the 'adventurebook' custom post type
* An Adventure Book is a custom post type that represents a book that can be read online.
* It has pages that can be navigated through.
*/
function adventurebook_register_book_post_type(): void {
$labels = array(
'name' => __( 'Adventurebooks', 'adventurebook' ),
'singular_name' => __( 'Adventurebook', 'adventurebook' ),
'menu_name' => __( 'Adventurebooks', 'adventurebook' ),
'name_admin_bar' => __( 'Adventurebooks', 'adventurebook' ),
'add_new' => __( 'Add New Book', 'adventurebook' ),
'add_new_item' => __( 'Add New Adventurebook', 'adventurebook' ),
'new_item' => __( 'New Adventurebook', 'adventurebook' ),
'edit_item' => __( 'Edit Adventurebook', 'adventurebook' ),
'view_item' => __( 'View Adventurebook', 'adventurebook' ),
'all_items' => __( 'Adventurebooks', 'adventurebook' ),
'search_items' => __( 'Search Adventurebooks', 'adventurebook' ),
'not_found' => __( 'No Adventurebooks found.', 'adventurebook' ),
'not_found_in_trash' => __( 'No Adventurebooks found in Trash.', 'adventurebook' )
);
$args = array(
'labels' => $labels,
'public' => false,
'publicly_queryable' => false,
'exclude_from_search' => true,
'show_ui' => true,
'show_in_menu' => 'adventurebook_main',
'query_var' => true,
'rewrite' => false,
'capability_type' => 'post',
'has_archive' => true,
'hierarchical' => true,
'menu_position' => 5,
'menu_icon' => 'dashicons-book-alt',
'supports' => array( 'title' ),
);
register_post_type( 'adventurebook', $args );
}
// add custom columns to the adventurebook post type
function adventurebook_add_custom_columns( $columns ) {
$columns['game_type'] = __( 'Type / System', 'adventurebook' );
$columns['page_count'] = __( 'Page Count', 'adventurebook' );
$columns['start_page'] = __( 'Start Page', 'adventurebook' );
return $columns;
}
function adventurebook_custom_column_content( $column, $post_id ) {
if ( $column === 'game_type' ) {
$type = get_post_meta( $post_id, '_adventurebook_type', true );
$combat_system = get_post_meta( $post_id, '_adventurebook_combat_system', true );
echo esc_html( ucfirst( $type ) ) . ' ' . esc_html( ucfirst( str_replace( '_', ' ', $combat_system ) ) );
}
if ( $column === 'page_count' ) {
// show the number of pages that belong to this adventurebook
// but first remove the "adventurebook_page_filter_by_parent" pre_get_post filter to avoid interference
remove_action( 'pre_get_posts', 'adventurebook_page_filter_by_parent' );
$pages = get_posts( array(
'post_type' => 'adventurebook_page',
'post_parent' => $post_id,
'numberposts' => - 1,
'post_status' => 'publish',
) );
add_action( 'pre_get_posts', 'adventurebook_page_filter_by_parent' );
$page_count = count( $pages );
echo esc_html( $page_count );
}
if ( $column === 'start_page' ) {
// Abrufen der ID der Startseite für das Adventurebook
$start_page_id = get_post_meta( $post_id, '_adventurebook_start_page', true );
if ( $start_page_id ) {
// Abrufen des Titels der Startseite
$start_page = get_post( $start_page_id );
if ( $start_page ) {
// show an edit link to the start page (CTP adventurebook_page)
$edit_link = get_edit_post_link( $start_page_id );
echo '' . esc_html( $start_page->post_title ) . ' (' . esc_html( $start_page_id ) . ')';
} else {
esc_html_e( 'No Start Page', 'adventurebook' );
}
} else {
esc_html_e( 'No Start Page', 'adventurebook' );
}
}
}
function adventurebook_add_new_page_link_meta_box() {
add_meta_box(
'adventurebook_new_page_link', // Unique ID
__( 'Add New Book Page', 'adventurebook' ), // Box title
'adventurebook_new_page_link_html', // Content callback
'adventurebook', // Post type
'side', // Context
'high' // Priority
);
}
function adventurebook_new_page_link_html( $post ) {
$link = add_query_arg( array(
'post_type' => 'adventurebook_page',
'parent_adventurebook' => $post->ID,
'_adventurebook_nonce' => wp_create_nonce( 'adventurebook_set_parent_action' )
), admin_url( 'post-new.php' ) );
echo '';
esc_html_e( 'Add New Book Page', 'adventurebook' );
echo '';
}
// Füge eine Metabox hinzu, um die Startseite auszuwählen
function adventurebook_add_start_page_meta_box() {
add_meta_box(
'adventurebook_start_page', // ID der Metabox
esc_html( __( 'Select Target Page', 'adventurebook' ) ), // Titel der Metabox
'adventurebook_start_page_meta_box_html', // Callback zur Ausgabe des Inhalts
'adventurebook', // Post-Typ
'side', // Kontext
'default' // Priorität
);
}
// HTML für das Dropdown-Menü in der Metabox
function adventurebook_start_page_meta_box_html( $post ) {
wp_nonce_field( 'adventurebook_save_startpage', 'adventurebook_nonce_startpage' );
// retrieve the currently selected start page
$selected_page_id = get_post_meta( $post->ID, '_adventurebook_start_page', true );
// get all pages, sorted by title, and with parent as the current book
$pages = get_posts( array(
'post_type' => 'adventurebook_page',
'post_parent' => $post->ID,
'numberposts' => - 1,
'post_status' => 'publish',
'orderby' => 'title',
'order' => 'ASC',
) );
if ( empty( $pages ) ) {
echo esc_html( __( 'No pages found. Please create pages first.', 'adventurebook' ) );
return;
}
echo '';
}
function adventurebook_save_start_page_meta_box( $post_id ) {
// Verhindere Autosave-Effekte
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
// Sicherstellen, dass es sich um den richtigen Post-Typ handelt
if ( get_post_type( $post_id ) != 'adventurebook' ) {
return;
}
// Check Nonce
if ( ! isset( $_POST['adventurebook_nonce_startpage'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['adventurebook_nonce_startpage'] ) ), 'adventurebook_save_startpage' ) ) {
return;
}
// check for editing rights
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
remove_action( 'save_post', 'adventurebook_save_start_page_meta_box' );
// Überprüfen, ob eine Startseite ausgewählt wurde
if ( isset( $_POST['adventurebook_start_page'] ) ) {
$start_page_id = intval( $_POST['adventurebook_start_page'] );
update_post_meta( $post_id, '_adventurebook_start_page', $start_page_id );
}
add_action( 'save_post', 'adventurebook_save_start_page_meta_box' );
}
#endregion
add_action( 'deleted_post', 'adventurebook_deleted_post' );
function adventurebook_deleted_post( $post_id ) {
$post_type = get_post_type( $post_id );
// delete a whole adventurebook
if ( $post_type === 'adventurebook' ) {
// delete all adventurebook_page posts that belong to this adventurebook
$pages = get_posts( array(
'post_type' => 'adventurebook_page',
'posts_per_page' => - 1,
'post_status' => 'any',
'post_parent' => $post_id,
) );
foreach ( $pages as $page ) {
$item_spwan = Item_Spawn::get_item_spawns_by_page_id( $page->ID, true );
foreach ( $item_spwan as $spawn ) {
/* @var $spawn Item_Spawn */
Item_Spawn::delete_item_spawn_point( $spawn->id );
}
$enemy_spwan = Enemy_Spawn::get_enemy_spawns_by_page_id( $page->ID, 0 );
foreach ( $enemy_spwan as $spawn ) {
/* @var $spawn Enemy_Spawn */
Enemy_Spawn::delete_enemy_spawn_point( $spawn->id );
}
wp_delete_post( $page->ID, true );
}
// now delete the adventurebook itself (already done by WP)
// finally, delete all characters that belong to this adventurebook
Character::delete_orphaned_characters();
}
// delete an adventurebook_page
if ( $post_type === 'adventurebook_page' ) {
// remove any links that point to this page
$all_pages = get_posts( array(
'post_type' => 'adventurebook_page',
'posts_per_page' => - 1,
'post_status' => 'any',
) );
global $wpdb;
// fetch all adventurebook_page posts with the meta key _adventurebook_decision_options from the database
$meta_key = '_adventurebook_decision_options';
$results = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$wpdb->prepare(
"SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s",
$meta_key
),
ARRAY_A
);
if ( empty( $results ) ) {
return;
}
foreach ( $results as $row ) {
$meta_value = maybe_unserialize( $row['meta_value'] );
$post_id_with_meta = (int) $row['post_id'];
$modified = false;
if ( is_array( $meta_value ) ) {
foreach ( $meta_value as $index => $option ) {
if ( isset( $option['target'] ) && (int) $option['target'] === $post_id ) {
unset( $meta_value[ $index ] );
$modified = true;
}
}
}
if ( $modified ) {
// Neu speichern oder löschen, wenn leer
if ( empty( $meta_value ) ) {
delete_post_meta( $post_id_with_meta, $meta_key );
} else {
update_post_meta( $post_id_with_meta, $meta_key, array_values( $meta_value ) );
}
}
}
}
}
/**
* Adventurebook – custom plugin deactivation confirmation flow
*/
function adventurebook_enqueue_deactivation_script( $hook ) {
// Load only on the Plugins list page
if ( 'plugins.php' !== $hook ) {
return;
}
wp_enqueue_script(
'adventurebook-deactivate',
plugin_dir_url( __FILE__ ) . '../../js/adventurebook_deactivate.js',
array( 'jquery' ),
'1.0',
true
);
// Pass the custom confirmation URL to JS
wp_localize_script( 'adventurebook-deactivate', 'adventurebookDeactivate', array(
'confirm_url' => admin_url( 'admin.php?page=adventurebook-deactivate-confirm' ),
'confirm_text' => __( 'Are you sure you want to deactivate Adventurebook?', 'adventurebook' ),
) );
}
function adventurebook_add_deactivate_confirm_page() {
add_submenu_page(
'admin.php',
__( 'Confirm Adventurebook Deactivation', 'adventurebook' ),
__( 'Confirm Adventurebook Deactivation', 'adventurebook' ),
'manage_options',
'adventurebook-deactivate-confirm',
'adventurebook_render_deactivate_confirm_page'
);
}
// 3. Render the confirmation page
function adventurebook_render_deactivate_confirm_page() {
if ( ! current_user_can( 'activate_plugins' ) ) {
wp_die( esc_html__( 'You do not have permission to perform this action.', 'adventurebook' ) );
}
$plugin_file = 'adventurebook/adventurebook.php';
$deactivate_url = wp_nonce_url(
admin_url( 'plugins.php?action=deactivate&plugin=' . urlencode( $plugin_file ) ),
'deactivate-plugin_' . $plugin_file
);
$cancel_url = admin_url( 'plugins.php' );
?>
'adventurebook_page',
'posts_per_page' => - 1,
'post_status' => 'any',
) );
foreach ( $pages as $page ) {
$additional_image_id = get_post_meta( $page->ID, '_additional_image', true );
if ( $additional_image_id ) {
wp_delete_attachment( $additional_image_id, true );
}
wp_delete_post( $page->ID, true );
}
// now delete all adventurebooks
$adventurebooks = get_posts( array(
'post_type' => 'adventurebook',
'posts_per_page' => - 1,
'post_status' => 'any',
) );
foreach ( $adventurebooks as $book ) {
wp_delete_post( $book->ID, true );
}
}
if ( $delete_data ) {
// before we drop all tables, delete all images that are used by item_definition or enemy_definition
adventurebook_delete_all_used_images();
adventurebook_drop_all_tables();
delete_option( 'adventurebook_settings' );
delete_option( 'adventurebook_version' );
}
}
/** Delete all images that are used by item_definition or enemy_definition
* This function is called before dropping all tables when the plugin is deactivated with data deletion
*
* the image is referenced by the image_url field in the item_definition and enemy_definition tables
* we need to find the attachment ID from the URL and then delete the attachment from the media library
*/
function adventurebook_delete_all_used_images() {
global $wpdb;
// get all image URLs from item_definition
$item_image_urls = $wpdb->get_col( "SELECT image_url FROM {$wpdb->prefix}adventurebook_item_definitions WHERE image_url IS NOT NULL AND image_url != ''" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
// get all image URLs from enemy_definition
$enemy_image_urls = $wpdb->get_col( "SELECT image_url FROM {$wpdb->prefix}adventurebook_enemy_definitions WHERE image_url IS NOT NULL AND image_url != ''" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$all_image_urls = array_unique( array_merge( $item_image_urls, $enemy_image_urls ) );
foreach ( $all_image_urls as $image_url ) {
$attachment_id = adventurebook_ensure_attachment_from_url( $image_url );
if ( $attachment_id ) {
wp_delete_attachment( $attachment_id, true );
}
}
}
function adventurebook_settings_page(): void {
add_submenu_page(
'adventurebook_main',
__( 'Adventurebook Settings', 'adventurebook' ),
__( 'Settings', 'adventurebook' ),
'manage_options',
'adventurebook-settings',
'adventurebook_settings_page_callback',
);
}
add_action( 'admin_menu', 'adventurebook_settings_page' );
add_action( 'add_meta_boxes', function() {
add_meta_box(
'adventurebook_play_box',
'Quick Access',
function( $post ) {
// PLAY BUTTON
// get the active character for this user and adventurebook
// get the adventurebook id - this is the page id of the parent post
$adventurebook_id = wp_get_post_parent_id( $post->ID );
$user_id = get_current_user_id();
$current_character_id = intval(get_user_meta( $user_id, 'adventurebook_current_character_id_' . $adventurebook_id, true ));
// get the current character
$character = Character::get_character_by_id( $current_character_id );
if ( $character ) {
// move the character to the current page ($character->location_id = $post->ID)
$character->move_to_zone( $post->ID );
}
// now just call the play url for this book
// find the page where the shortcode [adventurebook id="$post->ID"] is used
$startpage = adventurebook_get_first_page_using_shortcode( $adventurebook_id );
// get the url for this page
if( ! $startpage ) {
echo '
'.esc_html__('No page with [adventurebook id="..."] shortcode found for this book. Please create a page with this shortcode first.', 'adventurebook').'