# WP Ingame Shop Pro

Ein leistungsstarker, vollständig eigenständiger Ingame-Shop für WordPress, entwickelt für Minecraft-Server (Spigot/Paper).  
Er bietet ein komfortables Warenkorb-System, Gutscheine, Daily Deals, eine benutzerdefinierte Währung und ein **Item-Ankauf-System** – komplett ohne RCON.

Dieses Plugin nutzt eine eigene Datenbankstruktur für maximale Performance und vollständige Unabhängigkeit von WordPress-Beiträgen.

---

## ✨ Highlights

- 🛒 **Warenkorb-System**  
  Mehrere Items pro Bestellung.  
  Eine Bestellung = eine saubere Datenbankzeile mit JSON-Details.

- ⚡ **Mehrfachbearbeitung (Bulk Edit)**  
  Hunderte Items gleichzeitig bearbeiten (Preis, Server, Kategorie, Status, **Ankauf**).

- 💰 **Eigene Währung**  
  „Coins", „Tokens" oder beliebige virtuelle Währungen.

- 🖼️ **Automatische Bildzuweisung**  
  `minecraft:diamond` → `minecraft_diamond.png`  
  Ideal für große Bildsammlungen (1500+ Dateien).

- 🔥 **Daily Deal & Sale-System**

- 🎫 **Smart Coupons**  
  Prozent- oder Festbetrag, optional nicht kombinierbar mit Angeboten.

- 🔄 **Item-Ankauf-System**  
  Spieler können Items direkt ingame an den Shop verkaufen.  
  Ankaufspreis pro Item konfigurierbar (% vom VK, Festpreis oder VK minus Betrag).

- ✈️ **Fly-Abo-System**  
  Monatlich abgebuchtes Abonnement mit tägl. Stunden-Limit (Standard: 6h).  
  Kauf im Shop, Verwaltung & Kündigung vollständig ingame.

- 📦 **Plot-Slot-System**  
  Zusätzliche PlotSquared-Slots einmalig kaufen oder monatlich abonnieren.  
  Integration über LuckPerms (`plots.plot.<n>` Permission), vollautomatisch.

- 🌐 **REST API ohne RCON**

- 📊 **Top-Spender & Umsatzstatistik**

---

## 🚀 Installation

### WordPress Plugin

1. Ordner `wp-ingame-shop-pro` nach:

```
wp-content/plugins/
```

2. Plugin im WordPress Backend aktivieren.  
3. Fertig.

Bei Aktivierung werden automatisch erstellt:

- Datenbanktabellen (`wp_wis_*`)
- Cron-Jobs für Daily Deals

### Spigot/Paper Plugin

1. `IngameShopSpigot.jar` in den `plugins/`-Ordner des Servers legen.
2. Server starten – `config.yml` wird automatisch erstellt.
3. `config.yml` ausfüllen (WordPress-URL, API-Key, Server-Name).
4. `/wpis reload` oder Server neu starten.

**Voraussetzungen:** Vault + ein Economy-Plugin (z.B. EssentialsX)

---

# ⚙️ Spigot Plugin Konfiguration

```yaml
# WordPress-URL (kein abschließendes /)
wordpress-url: "https://deine-domain.de"

# API-Key aus den WordPress-Einstellungen
api-key: "HIER_DEN_KEY_AUS_WORDPRESS_EINTRAGEN"

# Name dieses Servers (muss mit dem Server-Slug in WordPress übereinstimmen)
server-name: "survival"

# Währungsname (muss mit WordPress-Einstellung übereinstimmen)
currency-name: "$"

# Wie oft (in Sekunden) nach ausstehenden Bestellungen gesucht wird
check-interval: 10

# Debug-Modus (ausführliche Logs in der Konsole)
debug-mode: false

# Fly-Code-Einlösung auf diesem Server deaktivieren
fly-redeem-disabled: false

# Spieler der die Einnahmen aus dem Shop erhält (Vault-Konto)
income-receiver: ""

# MySQL-Verbindung (für Fly-Code-System, Rang-Sessions, Fly-Abo und Plot-Slots)
mysql:
  host: "localhost"
  port: "3306"
  database: "minecraft"
  username: "root"
  password: "DEIN_PASSWORT"

# Ankauf-Einstellungen
sell:
  enabled: true
  # Preiskorrektur relativ zum WP-Ankaufspreis (in Prozent)
  # 0.0 = exakt WP-Preis | -10.0 = 10 % weniger | +5.0 = 5 % mehr
  price-offset: 0.0

# Fly-Abo-Einstellungen
fly-abo:
  # Maximale Fly-Zeit pro Tag in Stunden (Standard: 6)
  max-daily-hours: 6

# Plot-Slot Einstellungen (nur Citybuild)
plot-slots:
  # Auf welchem Server greift das Plot-Slot-System?
  server: "citybuild"
  # Standard-Plot-Slots pro LuckPerms-Gruppe
  rank-defaults:
    member: 2
    vip: 3
    scout: 4
    primo: 5
```

---

# 🎮 Ingame-Befehle

## Übersicht

| Befehl | Beschreibung | Berechtigung |
|--------|-------------|--------------|
| `/abo` | Zeigt alle laufenden Abonnements in einer Übersicht | `ingameshop.abo` |

## Shop / Bestellungen

| Befehl | Beschreibung | Berechtigung |
|--------|-------------|--------------|
| `/orders` | Zeigt deine letzten Bestellungen | `ingameshop.orders` |

## Fly-Gutscheine

| Befehl | Beschreibung | Berechtigung |
|--------|-------------|--------------|
| `/flytime` | Zeigt deine aktive verbleibende Fly-Zeit | `ingameshop.flytime` |
| `/flyredeem <Code>` | Löst einen Fly-Gutschein-Code ein | `ingameshop.flyredeem` |
| `/flycodes` | GUI mit deinen ungenutzten Fly-Codes (einlösen / weitergeben) | `ingameshop.flycodes` |
| `/flygive <Spieler> <Sekunden> [Label]` | Gibt einem Spieler einen Fly-Code (Admin) | `ingameshop.flygive` |
| `/flypause` | Pausiert oder setzt die aktive Fly-Zeit fort | `ingameshop.flypause` |

## Fly-Abo

| Befehl | Beschreibung | Berechtigung |
|--------|-------------|--------------|
| `/flyabo` | Zeigt Abo-Status, Ablaufdatum und heutiges Tageslimit | `ingameshop.flyabo` |
| `/flyabocancel confirm` | Kündigt das Abo zum Monatsende (bleibt bis dahin aktiv) | `ingameshop.flyabocancel` |
| `/flyabogive <Spieler> <Monatspreis> [Label]` | Vergibt ein Fly-Abo manuell (Admin) | `ingameshop.flyabogive` (OP) |

## Plot-Slots

| Befehl | Beschreibung | Berechtigung |
|--------|-------------|--------------|
| `/plotslots` | Zeigt eigene Slot-Übersicht (Basis / Einmalig / Abo / Gesamt) | `ingameshop.plotslots` |
| `/plotabo` | Zeigt Plot-Abo-Status, Slots, Preis und Ablaufdatum | `ingameshop.plotabo` |
| `/plotabocancel confirm` | Kündigt das Plot-Abo zum Monatsende | `ingameshop.plotabocancel` |
| `/plotabogive <Spieler> <Slots> <Preis> [Label]` | Vergibt ein Plot-Abo manuell (Admin) | `ingameshop.plotabogive` (OP) |
| `/plotslotsgive <Spieler> <Slots> [Label]` | Vergibt permanente Plot-Slots (Admin) | `ingameshop.plotslotsgive` (OP) |

## Ränge

| Befehl | Beschreibung | Berechtigung |
|--------|-------------|--------------|
| `/rankinfo` | Zeigt deine aktiven zeitbasierten Ränge | `ingameshop.rankinfo` |

## Item-Ankauf

| Befehl | Beschreibung | Berechtigung |
|--------|-------------|--------------|
| `/sell` | Öffnet das Ankauf-GUI mit allen ankaufbaren Items | `ingameshop.sell` |
| `/sell hand` | Verkauft den Stack in der Hand direkt | `ingameshop.sell` |
| `/sell all` | Verkauft alle ankaufbaren Items aus dem Inventar | `ingameshop.sell` |

### Ankauf-GUI
- **Linksklick** auf ein Item → verkauft alle davon im Inventar
- **Rechtsklick** auf ein Item → verkauft genau 1 Stack (max. 64)
- Items werden alle 5 Minuten automatisch aus WordPress aktualisiert

## Admin

| Befehl | Beschreibung | Berechtigung |
|--------|-------------|--------------|
| `/wpis reload` | Lädt config.yml und Ankaufliste live neu | `ingameshop.reload` (OP) |

---

# ✈️ Fly-Abo-System

Das Fly-Abo ermöglicht es Spielern, ein monatlich abgebuchtes Abonnement im Shop zu kaufen, das ihnen täglich eine konfigurierbare Menge an Fly-Zeit gewährt.

## Funktionsweise

- Spieler kaufen das Abo einmalig im Shop – der **Artikelpreis** ist gleichzeitig der monatliche Beitrag
- Das Abo ist sofort aktiv und gilt bis zum letzten Tag des laufenden Monats
- Täglich stehen bis zu `max-daily-hours` Stunden Fly zur Verfügung (Standard: 6h)
- Der Tagesverbrauch wird täglich zurückgesetzt
- Am **1. jedes Monats** wird der Monatsbeitrag automatisch per Vault abgebucht und das Abo verlängert
- Kann der Spieler nicht zahlen, wird das Abo **automatisch zum Monatsende gekündigt**
- Kündigung jederzeit ingame möglich – das Abo läuft bis **Ende des laufenden Monats** weiter
- Verwaltung und Kündigung erfolgen ausschließlich ingame

## BossBar

Beim aktiven Fly-Abo wird eine **grüne BossBar** angezeigt:

```
✈ Fly-Abo: 5h 30min / 6h
```

Warnungen bei: 1h, 30min, 10min, 5min, 1min, 30s, 10s verbleibend.

## Shop-Artikel anlegen (WordPress)

1. **Ingame Shop → Items → Neu**
2. Typ: **„✈ Fly-Abo (tägl. Limit)"** auswählen
3. **Preis setzen** – dieser Betrag wird monatlich per Vault abgebucht
4. Name vergeben → Speichern

Die Item-ID wird automatisch als `fly_abo` gespeichert.  
> **Hinweis:** Es gibt nur einen Fly-Abo-Artikel. Der Preis im Shop = monatlicher Beitrag.

## Billing-Übersicht

| Zeitpunkt | Was passiert |
|-----------|-------------|
| Kauf im Shop | Vault-Abzug, Abo sofort aktiv bis Monatsende |
| 1. des Monats | Automatische Vault-Abbuchung, Abo verlängert sich |
| Zahlung fehlgeschlagen | Abo läuft bis Monatsende, danach automatisch beendet |
| `/flyabocancel confirm` | Kündigung vorgemerkt, Abo läuft bis Monatsende weiter |

---

# 📦 Plot-Slot-System

Spieler können zusätzliche Plot-Slots auf dem Citybuild-Server kaufen – entweder **einmalig permanent** oder als **monatliches Abo**.

## Standard-Limits pro Rang

| Rang | Standard-Slots |
|------|---------------|
| Member | 2 |
| VIP | 3 |
| Scout | 4 |
| Primo | 5 |

## Gesamtlimit-Berechnung

```
Gesamt = Rang-Basis + einmalig gekaufte Slots + Abo-Slots
```

Das Plugin setzt automatisch die LuckPerms-Permission `plots.plot.<n>` – PlotSquared liest diese direkt aus.

## PlotSquared Voraussetzung

In `plugins/PlotSquared/config/worlds.yml` muss für jede Welt gesetzt sein:

```yaml
worlds:
  citybuild:
    plot:
      max_plots_per_player: -1
```

## Shop-Artikel anlegen (WordPress)

**Einmaliger Kauf (permanent):**
1. Typ: **„📦 Plot-Slots (einmalig)"** auswählen
2. Anzahl der zusätzlichen Slots eingeben
3. Preis setzen → Speichern  
Item-ID: `plot_slots_2` (z.B. +2 Slots permanent)

**Monatliches Abo:**
1. Typ: **„📦 Plot-Abo (monatlich)"** auswählen
2. Anzahl der Abo-Slots eingeben
3. Preis setzen (= monatlicher Beitrag) → Speichern  
Item-ID: `plot_abo_2` (z.B. +2 Slots monatlich)

## Billing-Übersicht

| Zeitpunkt | Was passiert |
|-----------|-------------|
| Kauf im Shop | Vault-Abzug, Slots sofort aktiv, LuckPerms Permission gesetzt |
| 1. des Monats | Automatische Vault-Abbuchung, Abo-Slots bleiben aktiv |
| Zahlung fehlgeschlagen | Abo-Slots verfallen, überzählige Plots eingefroren |
| `/plotabocancel confirm` | Kündigung vorgemerkt, läuft bis Monatsende weiter |

## Einfrieren bei Zahlungsausfall

Wenn nach Zahlungsausfall der Spieler mehr Plots besitzt als das neue Limit erlaubt, werden die überzähligen Plots eingefroren (kein Bauen möglich) bis das Abo erneuert wird.

---

# 📋 /abo – Abo-Übersicht

Der Befehl `/abo` zeigt alle laufenden Abonnements eines Spielers in einer kompakten Übersicht:

```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  📋 Meine Abonnements
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ✈ Fly-Abo
  ┌ Paket:             Fly-Abo Monat
  ├ Preis:             50 $ / Monat
  ├ Status:            ✔ Aktiv
  ├ Aktiv bis:         30.04.2026
  ├ Nächste Abbuchung: 01.05.2026
  ├ Heute:             1h 30min / 6h  (noch: 4h 30min)
  └ Kündigen:          /flyabocancel confirm

  📦 Plot-Abo
  ┌ Paket:             Plot-Abo +2 Slots
  ├ Slots:             +2 Plot-Slots
  ├ Preis:             30 $ / Monat
  ├ Status:            ✔ Aktiv
  ├ Aktiv bis:         30.04.2026
  ├ Nächste Abbuchung: 01.05.2026
  └ Kündigen:          /plotabocancel confirm

  📦 Plot-Slots
  ┌ Rang-Basis:        2
  ├ Einmalig:          +1
  ├ Abo:               +2
  └ Gesamt:            5 Slots
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```

Die Plot-Slots-Übersicht wird immer angezeigt. Hat der Spieler kein Abo, erscheint ein Hinweis mit dem Shop-Link.

---

# 🖼️ Bilder-Konfiguration (Gitea Raw)

## 📂 Basis-URL für alle Item-Bilder

```
https://git.viper.ipv64.net/M_Viper/WP-Ingame-Shop-Pro/raw/branch/main/images/
```

### 🔧 Eintragen im Plugin

**Ingame Shop → Einstellungen → Bilder Basis-URL**

Eintragen:

```
https://git.viper.ipv64.net/M_Viper/WP-Ingame-Shop-Pro/raw/branch/main/images/
```

---

## 📌 Automatische Bildlogik

Item-ID im Shop:

```
minecraft:diamond
```

Automatisch geladen wird:

```
https://git.viper.ipv64.net/M_Viper/WP-Ingame-Shop-Pro/raw/branch/main/images/minecraft_diamond.png
```

Regeln:

- `:` wird zu `_`
- Dateiendung = `.png`
- Keine manuelle Bildzuweisung notwendig

---

# 📥 Quick JSON Import (Direkt von Gitea)

## 🔗 Import-URL

```
https://git.viper.ipv64.net/M_Viper/WP-Ingame-Shop-Pro/raw/branch/main/items.json
```

---

## 🛠️ Import durchführen

1. **Ingame Shop → JSON Tools**
2. **Import**
3. URL einfügen
4. Import starten

Ideal für:

- Kompletten Shop-Aufbau in Sekunden
- Regelmäßige Synchronisation
- Kombination mit Bulk Edit

---

# 🛠️ Admin-Bereich

## 1️⃣ Einstellungen

- Shop Header Text
- Währungsname (z.B. Coins)
- Bilder Basis-URL
- Daily Deal (% Rabatt)
- Gutscheine auf Sale-Items erlauben / verbieten

---

## 2️⃣ Items Verwaltung

### Einzelbearbeitung

- Item ID (`minecraft:diamond`)
- Typ: Minecraft Item | ✈ Fly-Gutschein | 👑 Rang (LuckPerms) | ✈ Fly-Abo | 📦 Plot-Slots (einmalig) | 📦 Plot-Abo (monatlich)
- Preis
- Angebotspreis
- Server-Zuweisung
- Kategorie
- Status (`publish` / `draft`)
- **Ankauf aktivieren** (mit Preismodus und Live-Vorschau)

### Ankauf-Preismodi (pro Item)

| Modus | Beispiel | Ergebnis bei VK 100 |
|-------|---------|---------------------|
| `% vom VK` | 80 | 80 Coins |
| `VK minus` | 10 | 90 Coins |
| `Fixpreis` | 15 | immer 15 Coins |

---

## 🔄 Bulk Edit (Mehrfachbearbeitung)

Beispiel: 100 Items auf Ankauf konfigurieren.

1. Items anhaken  
2. „Massenaktionen" wählen:
   - Server zuweisen
   - Preis ändern
   - Angebot ändern
   - Kategorie setzen
   - Status ändern
   - **Ankauf konfigurieren**
3. Anwenden  
4. Änderungen speichern  

Bei **Ankauf konfigurieren** siehst du pro Item:
- Checkbox zum Aktivieren/Deaktivieren
- Modus-Auswahl (%, minus, fix)
- Wert-Eingabe
- Live-Vorschau des Ankaufspreises

---

## 3️⃣ Weitere Bereiche

### 📦 Bestellungen

- Bestellungen anzeigen
- Manuell abschließen
- Stornieren

Status:

```
pending
processing
completed
cancelled
```

---

### 🌐 Server

Beispiel:

```
lobby
survival
skyblock
```

Frontend-Filter werden automatisch generiert.

---

### 📂 Kategorien

Beispiel:

```
Blöcke
Waffen
R�stung
Ranks
```

---

### 🎫 Gutscheine

- `fixed` (Festbetrag)
- `percent` (Prozent)
- Ablaufdatum
- Nutzungslimit
- Ausschluss bei Angeboten

---

### 📊 Top Spender

Automatische Auswertung der Bestellungen.

---

# 🎮 Frontend Nutzung

Shortcode:

```
[ingame_shop_form]
```

---

## Spieler-Funktionen

- Suche
- Server-Filter
- Kategorie-Tabs
- Warenkorb
- Gutschein-Eingabe
- Server-Validierung beim Checkout

---

# 📡 REST API

Basis:

```
/wp-json/wis/v1/
```

---

## Bestellung erstellen

```
POST /wis/v1/order
```

```json
{
  "player": "Name",
  "server": "survival",
  "cart": [
    { "id": "item_id", "quantity": 1 }
  ],
  "coupon_code": "CODE"
}
```

---

## Offene Bestellungen abrufen

```
GET /wis/v1/pending_orders?player=Name
```

---

## Status ändern

```
POST /wis/v1/execute_order
POST /wis/v1/complete_order
POST /wis/v1/cancel_order
```

---

## Gutschein validieren

```
POST /wis/v1/validate_coupon
```

---

## Ankauf – Items abrufen

```
GET /wis/v1/sell_items?server=survival
```

Antwort:
```json
{
  "items": [
    {
      "item_id": "minecraft:diamond",
      "name": "Diamant",
      "buy_price": 100,
      "sell_price": 80
    }
  ],
  "currency": "Coins"
}
```

---

## Ankauf – Item verkaufen

```
POST /wis/v1/sell_item
```

```json
{
  "player": "Steve",
  "server": "survival",
  "item_id": "minecraft:diamond",
  "quantity": 5
}
```

Antwort:
```json
{
  "success": true,
  "item_name": "Diamant",
  "quantity": 5,
  "price_per_item": 80.00,
  "total": 400.00
}
```

---

# 💾 Datenbank-Struktur

## `wp_wis_items`

| Feld | Beschreibung |
|------|-------------|
| item_id | minecraft:diamond |
| name | Anzeigename |
| price | Standardpreis |
| offer_price | Angebotspreis |
| is_offer | 0 / 1 |
| servers | JSON Array |
| categories | JSON Array |
| status | publish / draft |
| sell_enabled | 0 / 1 – Ankauf aktiv? |
| sell_price_mode | percent / fixed / minus |
| sell_price_value | Wert passend zum Modus |

---

## `wp_wis_orders`

| Feld | Beschreibung |
|------|-------------|
| player_name | Minecraft Name |
| server | Zielserver |
| item_title | Zusammenfassung |
| price | Gesamtpreis |
| response | JSON |
| status | pending / processing / completed / cancelled |

---

## `wp_wis_coupons`

| Feld | Beschreibung |
|------|-------------|
| code | Gutschein |
| type | fixed / percent |
| value | Rabattwert |
| usage_limit | Limit |
| used_count | Nutzung |

---

## `wp_wis_sell_log`

| Feld | Beschreibung |
|------|-------------|
| player_name | Minecraft Name |
| server | Server-Slug |
| item_id | minecraft:diamond |
| item_name | Anzeigename |
| quantity | Verkaufte Menge |
| price_per_item | Ankaufspreis pro Stück |
| total_paid | Ausgezahlter Gesamtbetrag |
| sold_at | Zeitstempel |

---

## `wis_fly_abos` *(Spigot MySQL)*

| Feld | Beschreibung |
|------|-------------|
| player_name | Minecraft Name |
| label | Anzeigename des Pakets |
| monthly_price | Monatlicher Beitrag (Vault) |
| cancelled | 0 / 1 – Kündigung vorgemerkt? |
| cancellation_reason | `user` oder `payment_failed` |
| next_billing_date | Datum der nächsten Abbuchung (immer 1. des Monats) |
| period_end | Letzter Tag der aktuellen Abo-Periode (Monatsende) |
| granted_at | Aktivierungszeitpunkt |

---

## `wis_fly_abo_usage` *(Spigot MySQL)*

| Feld | Beschreibung |
|------|-------------|
| player_name | Minecraft Name |
| usage_date | Datum (täglich) |
| used_sec | Verbrauchte Sekunden an diesem Tag |

---

## `wis_plot_extra_slots` *(Spigot MySQL)*

| Feld | Beschreibung |
|------|-------------|
| player_name | Minecraft Name |
| extra_slots | Dauerhaft gekaufte Zusatz-Slots |
| last_perm | Zuletzt gesetzter `plots.plot.<n>` Wert (für sauberes LP-Update) |
| granted_at | Zeitstempel der letzten Vergabe |

---

## `wis_plot_abos` *(Spigot MySQL)*

| Feld | Beschreibung |
|------|-------------|
| player_name | Minecraft Name |
| label | Anzeigename des Pakets |
| abo_slots | Anzahl der Abo-Slots |
| monthly_price | Monatlicher Beitrag (Vault) |
| cancelled | 0 / 1 – Kündigung vorgemerkt? |
| cancellation_reason | `user` oder `payment_failed` |
| next_billing_date | Datum der nächsten Abbuchung (immer 1. des Monats) |
| period_end | Letzter Tag der aktuellen Abo-Periode (Monatsende) |
| granted_at | Aktivierungszeitpunkt |

---

## `wp_wis_servers`

Serverdefinitionen

---

## `wp_wis_categories`

Kategoriedefinitionen

---

# ⚡ Performance Empfehlung

Bei 1500+ PNG-Dateien:

- CDN empfohlen
- PNG verlustfrei komprimieren
- Gitea Caching aktivieren
- Optional WebP-Versionen erstellen

---

# 🔐 Sicherheitshinweis

Aktuell sind API-Endpunkte öffentlich (`__return_true`).

Für Produktion empfohlen:

- API-Key Header
- Bearer Token
- IP Whitelisting
- Nonce/Signature System

---

**Copyright © 2026 - M_Viper - Alle Rechte vorbehalten**

Die unbefugte Vervielfältigung, Verbreitung oder Weitergabe dieses Plugins ist strafbar und wird rechtlich verfolgt.