PHPackages                             pup/placeholderapi - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. pup/placeholderapi

ActiveLibrary[API Development](/categories/api)

pup/placeholderapi
==================

A simple and efficient placeholder system for PocketMine-MP. Originally created for the Kyro core.

3.0.0(3w ago)019GPL-3.0-or-laterPHP

Since Oct 2Pushed 3w agoCompare

[ Source](https://github.com/Pupggerss/PlaceholderApi)[ Packagist](https://packagist.org/packages/pup/placeholderapi)[ RSS](/packages/pup-placeholderapi/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (2)Versions (5)Used By (0)

PlaceholderAPI v2.0
===================

[](#placeholderapi-v20)

A powerful, type-safe placeholder system for PocketMine-MP plugins. Create reusable, parameterized placeholders with a clean, extensible API.

What's New in v2.0
------------------

[](#whats-new-in-v20)

- **Type-safe interface system** - Implement `Placeholder` interface for full control
- **Parameterized placeholders** - Use `{placeholder:parameter}` syntax
- **Better organization** - Separate `PlayerPlaceholder` and `ServerPlaceholder` base classes
- **Validation &amp; safety** - Automatic player requirement checks, recursion protection
- **Backward compatible** - All v1.x code still works!

Features
--------

[](#features)

- Built-in color formatting with named placeholders
- Extensive player data placeholders
- Server information placeholders
- Easy custom placeholder registration (closure or class-based)
- Parameterized placeholders for dynamic content
- Gradient text effects
- Recursive placeholder parsing
- Type-safe architecture

Installation
------------

[](#installation)

### As a Virion (Recommended)

[](#as-a-virion-recommended)

```
composer require pup/placeholderapi
```

### Direct Include

[](#direct-include)

Drop the `src/pup/placeholderapi` folder into your plugin's source directory.

Quick Start
-----------

[](#quick-start)

### Initialization

[](#initialization)

**IMPORTANT:** Always initialize PlaceholderAPI before registering custom placeholders to ensure all placeholders are registered to the same manager instance.

```
use pup\placeholderapi\PlaceholderApi;

// In your plugin's onEnable()
public function onEnable(): void
{
    // Initialize PlaceholderAPI first
    PlaceholderApi::initialize();

    // Now register your custom placeholders
    PlaceholderApi::registerPlaceholder(...);
}
```

### Basic Usage

[](#basic-usage)

```
use pup\placeholderapi\PlaceholderApi;

// Parse message without player context (colors + server placeholders)
$message = "{gold}Server: {server_online}/{server_max} players online";
$formatted = PlaceholderApi::parse($message);

// Parse with player context (includes player-specific placeholders)
$message = "{green}Welcome {player_name}! Health: {player_health}";
$formatted = PlaceholderApi::parse($message, $player);
$player->sendMessage($formatted);

// Parse multiple messages at once
$messages = [
    "{gold}Welcome to the server!",
    "{aqua}You have {player_health} health",
    "{yellow}TPS: {server_tps}"
];
$parsed = PlaceholderApi::parseMultiple($messages, $player);
```

### Register Custom Placeholders

[](#register-custom-placeholders)

#### Method 1: Quick Closure Registration

[](#method-1-quick-closure-registration)

```
use pup\placeholderapi\PlaceholderApi;

// Simple server-wide placeholder
PlaceholderApi::registerPlaceholder(
    "server_name",
    fn(?Player $player, ?string $params): string => "My Server",
    requiresPlayer: false,
    supportsParameters: false
);

// Player-specific placeholder
PlaceholderApi::registerPlaceholder(
    "player_coins",
    function(?Player $player, ?string $params): string {
        if ($player === null) return "0";
        return (string)MyEconomy::getCoins($player);
    },
    requiresPlayer: true,
    supportsParameters: false
);

// Placeholder with parameters: {top_player:1}, {top_player:5}
PlaceholderApi::registerPlaceholder(
    "top_player",
    fn(?Player $player, ?string $params): string =>
        MyPlugin::getTopPlayer($params !== null ? (int)$params : 1),
    requiresPlayer: false,
    supportsParameters: true
);
```

#### Method 2: Class-Based Registration (Recommended)

[](#method-2-class-based-registration-recommended)

```
use pocketmine\player\Player;
use pup\placeholderapi\PlaceholderApi;
use pup\placeholderapi\placeholder\PlayerPlaceholder;
use pup\placeholderapi\placeholder\ServerPlaceholder;

// Player-specific placeholder
class PlayerBalancePlaceholder extends PlayerPlaceholder
{
    public function __construct()
    {
        parent::__construct("player_balance");
    }

    protected function processPlayer(Player $player, ?string $params): string
    {
        $balance = MyEconomy::getBalance($player);
        return "$" . number_format($balance, 2);
    }
}

// Server-wide placeholder
class TotalMoneyPlaceholder extends ServerPlaceholder
{
    public function __construct()
    {
        parent::__construct("total_money");
    }

    protected function processServer(?string $params): string
    {
        return "$" . number_format(MyEconomy::getTotalMoney(), 2);
    }
}

// Register them
PlaceholderApi::registerCustomPlaceholder(new PlayerBalancePlaceholder());
PlaceholderApi::registerCustomPlaceholder(new TotalMoneyPlaceholder());
```

Built-in Placeholders
---------------------

[](#built-in-placeholders)

### Player Placeholders (require player context)

[](#player-placeholders-require-player-context)

PlaceholderDescriptionExample Output`{player}` or `{player_name}`Player's name`Steve``{player_display}`Display name`§aSteve``{player_health}`Current health`20.0``{player_max_health}`Max health`20.0``{player_food}`Food level`20``{player_level}`XP level`5``{player_xp}`Total XP`250``{player_gamemode}`Game mode`Survival``{player_ping}`Network ping`42``{player_x}`X coordinate`123.45``{player_y}`Y coordinate`64.00``{player_z}`Z coordinate`-789.12``{player_world}`World name`world`### Server Placeholders (work without player)

[](#server-placeholders-work-without-player)

PlaceholderDescriptionExample Output`{server_motd}`Server MOTD`My Server``{server_online}`Online players`15``{server_max}`Max players`20``{server_tps}`Server TPS`19.95`### Color Placeholders

[](#color-placeholders)

**Colors:** `{black}` `{dark_blue}` `{dark_green}` `{dark_aqua}` `{dark_red}` `{dark_purple}` `{gold}` `{gray}` `{dark_gray}` `{blue}` `{green}` `{aqua}` `{red}` `{light_purple}` `{yellow}` `{white}`

**Formatting:** `{bold}` `{italic}` `{underline}` `{strikethrough}` `{obfuscated}` `{reset}`

Advanced Features
-----------------

[](#advanced-features)

### Parameterized Placeholders

[](#parameterized-placeholders)

```
// Register a placeholder that accepts parameters
PlaceholderApi::registerPlaceholder(
    "player_stat",
    function(?Player $player, ?string $params): string {
        if ($player === null || $params === null) return "N/A";

        return match($params) {
            "kills" => (string)Stats::getKills($player),
            "deaths" => (string)Stats::getDeaths($player),
            "wins" => (string)Stats::getWins($player),
            default => "Unknown"
        };
    },
    requiresPlayer: true,
    supportsParameters: true
);

// Use in messages: {player_stat:kills}, {player_stat:deaths}, {player_stat:wins}
$msg = "{player_name} has {player_stat:kills} kills!";
```

### Recursive Placeholders

[](#recursive-placeholders)

Placeholders can return other placeholders, which will be automatically parsed:

```
PlaceholderApi::registerPlaceholder(
    "welcome_msg",
    fn(?Player $p, ?string $params): string =>
        "{gold}Welcome {player_name}! You have {player_coins} coins.",
    requiresPlayer: true
);

// The nested {player_name} and {player_coins} will be automatically parsed
$result = PlaceholderApi::parse("{welcome_msg}", $player);
```

### Gradient Text Effects

[](#gradient-text-effects)

```
// Character-by-character gradient
$text = "Rainbow Text!";
$colors = ['red', 'gold', 'yellow', 'green', 'aqua', 'blue', 'light_purple'];
$gradient = PlaceholderApi::createCharacterGradient($text, $colors);
$player->sendMessage($gradient);

// Word-by-word gradient
$text = "Each word different color";
$colors = ['red', 'yellow', 'green', 'aqua'];
$gradient = PlaceholderApi::createWordGradient($text, $colors);
$player->sendMessage($gradient);
```

Complete Plugin Example
-----------------------

[](#complete-plugin-example)

```
namespace MyPlugin;

use pocketmine\plugin\PluginBase;
use pocketmine\player\Player;
use pup\placeholderapi\PlaceholderApi;
use pup\placeholderapi\placeholder\PlayerPlaceholder;

class Main extends PluginBase
{
    public function onEnable(): void
    {
        // IMPORTANT: Initialize PlaceholderAPI first
        PlaceholderApi::initialize();

        // Now register custom placeholders
        PlaceholderApi::registerPlaceholder(
            "server_name",
            fn(?Player $p, ?string $params): string => $this->getConfig()->get("name", "My Server"),
            requiresPlayer: false
        );

        PlaceholderApi::registerCustomPlaceholder(new PlayerKillsPlaceholder($this));
    }

    public function onDisable(): void
    {
        // Clean up
        PlaceholderApi::unregisterPlaceholder("server_name");
        PlaceholderApi::unregisterPlaceholder("player_kills");
    }

    public function sendWelcome(Player $player): void
    {
        $messages = [
            "{gold}{bold}========================",
            "{aqua}Welcome {player_name}!",
            "{gray}Health: {red}{player_health}§r{gray}/{player_max_health}",
            "{gray}World: {yellow}{player_world}",
            "{gray}Your kills: {green}{player_kills}",
            "{gray}Online: {white}{server_online}/{server_max}",
            "{gold}{bold}========================"
        ];

        $parsed = PlaceholderApi::parseMultiple($messages, $player);
        foreach ($parsed as $msg) {
            $player->sendMessage($msg);
        }
    }
}

class PlayerKillsPlaceholder extends PlayerPlaceholder
{
    public function __construct(private Main $plugin)
    {
        parent::__construct("player_kills");
    }

    protected function processPlayer(Player $player, ?string $params): string
    {
        // Get kills from your stats system
        return (string)$this->plugin->getKills($player);
    }
}
```

Migration from v1.x
-------------------

[](#migration-from-v1x)

All v1.x code continues to work! The old API is fully supported:

```
// Old way (still works)
PlaceholderApi::registerPlaceholder('my_placeholder', function($player) {
    return "value";
});

// New way (recommended)
PlaceholderApi::registerPlaceholder(
    'my_placeholder',
    fn(?Player $player, ?string $params): string => "value",
    requiresPlayer: false,
    supportsParameters: false
);
```

Best Practices
--------------

[](#best-practices)

1. **Initialize first** - Always call `PlaceholderApi::initialize()` in `onEnable()` before registering placeholders
2. **Use class-based placeholders** for complex logic (easier to test &amp; maintain)
3. **Always validate player null** in player-specific placeholders
4. **Clean up on disable** - unregister your placeholders in `onDisable()`
5. **Use parameters** for flexibility - one placeholder can handle multiple cases
6. **Handle errors gracefully** - wrap risky operations in try-catch

Credits
-------

[](#credits)

Originally created for the Kyro core by Pupggers. Refactored to v2.0 with improved architecture and type safety.

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance95

Actively maintained with recent releases

Popularity7

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity39

Early-stage or recently created project

 Bus Factor1

Top contributor holds 50% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~98 days

Total

4

Last Release

24d ago

Major Versions

1.1.0 → 2.0.02025-10-11

2.0.0 → 3.0.02026-07-25

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/164761956?v=4)[Pup](/maintainers/Pupggerss)[@Pupggerss](https://github.com/Pupggerss)

---

Top Contributors

[![pupggers](https://avatars.githubusercontent.com/u/164761956?v=4)](https://github.com/pupggers "pupggers (12 commits)")[![Pupggerss](https://avatars.githubusercontent.com/u/164761956?v=4)](https://github.com/Pupggerss "Pupggerss (10 commits)")[![poggit-bot](https://avatars.githubusercontent.com/u/22427965?v=4)](https://github.com/poggit-bot "poggit-bot (2 commits)")

---

Tags

pluginapiplaceholderpocketminevirionaltaypmmp

### Embed Badge

![Health badge](/badges/pup-placeholderapi/health.svg)

```
[![Health](https://phpackages.com/badges/pup-placeholderapi/health.svg)](https://phpackages.com/packages/pup-placeholderapi)
```

###  Alternatives

[tinify/magento2

Make your web shop faster by compressing your JPEG and PNG images. This plugin automatically optimizes your images by integrating with the popular image compression services TinyJPG and TinyPNG.

4346.4k](/packages/tinify-magento2)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
