💡 RESOURCES
Performance optimization, organization patterns, and common pitfalls
Use consistent, descriptive names for your GUI files and IDs:
| Pattern | Example | Use Case |
|---|---|---|
| Feature name | shop.yml, bank.yml |
Simple, single-purpose GUIs |
| Category prefix | admin-ban.yml, admin-kick.yml |
Related GUIs grouped by category |
| Lowercase with dashes | server-selector.yml |
Multi-word names |
Avoid spaces, special characters, and uppercase in file names and GUI IDs. The ID is case-sensitive when used in commands.
Keep your CustomGuis/ folder organized. While GUIPlus reads all .yml files from this folder, a clean structure helps you manage large GUI collections:
plugins/GUIPlus/CustomGuis/
├── shop.yml # Main shop
├── bank.yml # Banking system
├── warps.yml # Warp menu
├── profile.yml # Player profile
├── adminpanel.yml # Admin tools
├── rules.yml # Server rules
└── daily.yml # Daily rewards
Tip: GUIPlus does not support subfolders inside
CustomGuis/. All GUI files must be in the root of the folder.
PlaceholderAPI placeholders in item lore are re-evaluated every second (20 ticks). Having many placeholders across many items can increase server load:
Avoid:
# 10 items each with 5 placeholder lore lines = 50 placeholder evaluations per second
item-lore:
- §7Stat 1: %statistic_mine_block_diamond_ore%
- §7Stat 2: %statistic_mine_block_iron_ore%
- §7Stat 3: %statistic_mine_block_gold_ore%
- §7Stat 4: %statistic_mine_block_coal_ore%
- §7Stat 5: %statistic_mine_block_emerald_ore%Better: Consolidate data into fewer items or use static text where values don't change frequently:
item-lore:
- §7Total Mined: %statistic_mine_block%Rather than building one massive GUI with many scenes, create separate GUIs for different purposes and link them with commands:
# In your main menu, link to sub-menus
click-events:
command:
commands:
- gui open shopThis keeps each GUI file manageable and reduces the number of items loaded at once.
Conditions are evaluated when the GUI opens and when items refresh. Simpler conditions are faster:
has-permission— Very fast (permission lookup)has-money— Fast (single Vault call)conditional-placeholder— Speed depends on the placeholder being evaluatedcooldown— Fast (timestamp comparison)
Always quote strings that start with special YAML characters (%, &, *, !, {, [, etc.):
# These need quotes because % is a special character indicator in some parsers
conditionFailMessage: '§cYou need at least $500!'
conditional_condition: '%player_level%>=10'Single quotes (') are safest for Minecraft formatting codes since § and & don't need escaping.
Use '' (empty single-quoted string) for blank lines in lore:
item-lore:
- ''
- §7This has spacing above and below
- ''Some fields accept both numbers and placeholder strings. When using a placeholder, quote it:
# Static number — no quotes needed
money-remove:
amount: 500
# Dynamic placeholder — quotes needed
money-remove:
amount: '%input%'YAML uses spaces, not tabs. Use 2-space indentation consistently:
scenes:
'0':
delay: 0
items:
'1':
slot: 0
item: DIAMONDTip: Use a YAML validator (search "YAML lint" online) to catch indentation and syntax errors before reloading.
Fill empty slots with glass panes to create clean borders:
# Repeat for each border slot
'100':
slot: 0
item: BLACK_STAINED_GLASS_PANE
amount: 1
item-name: ' '
'101':
slot: 1
item: BLACK_STAINED_GLASS_PANE
amount: 1
item-name: ' '
# ... continue for all border slotsTip: Use the in-game editor to place border items quickly rather than writing YAML by hand.
Add a consistent "back" button that returns to the previous GUI:
'99':
slot: 45
item: ARROW
amount: 1
item-name: §7← Back
click-events:
back: {}
sound-click-event:
sound: UI_BUTTON_CLICK'100':
slot: 49
item: BARRIER
amount: 1
item-name: §c§lClose
click-events:
close-inventory: {}Always add sound feedback to click events. It gives players clear confirmation that their action worked:
click-events:
sound-click-event:
sound: UI_BUTTON_CLICK # Neutral click
# or
sound-click-event:
sound: ENTITY_PLAYER_LEVELUP # Success/purchase
# or
sound-click-event:
sound: ENTITY_VILLAGER_NO # Denied/errorUse clickType to give items dual functionality:
click-events:
buy-action:
message: §aPurchased!
clickType: LEFT
info-action:
message: §7This item costs $500
clickType: RIGHTAdd instructions in the lore so players know:
item-lore:
- ''
- §eLeft-click to buy
- §7Right-click for infoYAML maps cannot have duplicate keys. If you need two click events of the same type, use unique keys:
Wrong:
click-events:
message:
message: §aFirst message
message: # This overwrites the first one!
message: §bSecond messageCorrect:
click-events:
first-message:
message: §aFirst message
second-message:
message: §bSecond messagePlaceholder values in conditions must be quoted:
Wrong:
conditional_condition: %player_level%>=10Correct:
conditional_condition: '%player_level%>=10'The = operator in conditional-placeholder does string comparison, not numeric. 10 does not string-equal 10.0:
Wrong (for numeric equality):
conditional_condition: '%vault_eco_balance%=1000'Correct:
# Use >= and <= together for numeric equality
conditional_condition: '%vault_eco_balance%>=1000'Cooldown durations are in milliseconds, not seconds:
| Duration | Milliseconds |
|---|---|
| 1 second | 1000 |
| 30 seconds | 30000 |
| 5 minutes | 300000 |
| 1 hour | 3600000 |
| 24 hours | 86400000 |
Use the Bukkit material name, not the Minecraft display name:
| Display Name | Correct Material |
|---|---|
| Crafting Table | CRAFTING_TABLE |
| Ender Chest | ENDER_CHEST |
| Enchanting Table | ENCHANTING_TABLE |
| Jack o'Lantern | JACK_O_LANTERN |
Check the Bukkit Material list for exact names.
The command click event has a setOp: true option that temporarily gives the player OP to execute a command. Avoid using this. Instead, use console_command to run privileged commands from the console:
Avoid:
click-events:
command:
commands:
- give %player% diamond 1
setOp: truePrefer:
click-events:
console_command:
commands:
- give %player% diamond 1When using chat fetcher for player input, always validate:
- Type check — Use
is-integeroris-doubleto ensure the input is a number - Range check — Use
conditional-placeholderto check bounds (e.g.,%input%>0) - Economy check — Use
has-moneyto verify funds before deducting
conditions:
is-integer:
value: '%input%'
conditional-placeholder:
conditional_condition: '%input%>0'
has-money:
required-balance: '%input%'| ← Previous | Next → |
|---|---|
| Premade Configurations | FAQ & Troubleshooting |