PHPackages                             muqsit/invmenu - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. muqsit/invmenu

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

muqsit/invmenu
==============

A PocketMine-MP virion to create and manage virtual inventories!

4.7.4(4mo ago)2225.4k↑35.3%87[16 issues](https://github.com/Muqsit/InvMenu/issues)1GPL-3.0PHP

Since Jun 1Pushed 4mo ago16 watchersCompare

[ Source](https://github.com/Muqsit/InvMenu)[ Packagist](https://packagist.org/packages/muqsit/invmenu)[ RSS](/packages/muqsit-invmenu/feed)WikiDiscussions pm5 Synced today

READMEChangelog (8)Dependencies (1)Versions (11)Used By (1)

InvMenu
=======

[](#invmenu)

Create and manage virtual inventories in PocketMine-MP.

Installation and setup
----------------------

[](#installation-and-setup)

Download the compiled .phar file from [Poggit CI](https://poggit.pmmp.io/ci/Muqsit/InvMenu/~) and place it in your `virions/` folder. Read [installation](https://github.com/Muqsit/InvMenu/wiki/Installation) and [using in a plugin](https://github.com/Muqsit/InvMenu/wiki/Using-InvMenu-in-a-plugin)for a more elaborate guide on how to setup InvMenu library.

Note

You must register `InvMenuHandler` before you can use InvMenu.

```
// in class MyPlugin extends PluginBase:
protected function onEnable() : void{
	if(!InvMenuHandler::isRegistered()){
		InvMenuHandler::register($this);
	}
}
```

Create a virtual inventory
--------------------------

[](#create-a-virtual-inventory)

Quick start, use `InvMenu::create(InvMenu::TYPE_CHEST)->send($player);` to display a virtual chest inventory to a player.

`InvMenu::create($identifier)` creates an InvMenu instance. `$identifier` may be an identifier of a registered `InvMenuType` object. InvMenu comes with 3 pre-registered inventory types of different sizes:

- `InvMenu::TYPE_CHEST` - a 27-slot normal chest inventory
- `InvMenu::TYPE_DOUBLE_CHEST` - a 54-slot double chest inventory
- `InvMenu::TYPE_HOPPER` - a 5-slot hopper inventory

```
$menu = InvMenu::create(InvMenu::TYPE_CHEST);
$inventory = $menu->getInventory();
```

As `$inventory` implements [PocketMine's Inventory interface](https://github.com/pmmp/PocketMine-MP/blob/stable/src/inventory/Inventory.php), you get to access all the fancy PocketMine inventory methods.

```
$menu->getInventory()->setContents([
	VanillaItems::DIAMOND_SWORD(),
	VanillaItems::DIAMOND_PICKAXE()
]);
$menu->getInventory()->addItem(VanillaItems::DIAMOND_AXE());
$menu->getInventory()->setItem(3, VanillaItems::GOLD_INGOT());
```

To send a menu to a player, use:

```
/** @var Player $player */
$menu->send($player);
```

Tip

One `InvMenu` can be sent to multiple players—even 2 players in different worlds, so everyone views and edits the same inventory as if it were one chest.

Set a custom name
-----------------

[](#set-a-custom-name)

There are two ways to name an InvMenu. You can either specify a global name (see method A), or you can set a name at the time you send the menu (see method B).

```
$menu->setName("Custom Name"); // method A
$menu->send($player, "Greetings, " . $player->getName()); // method B
```

Verify whether a menu is sent successfully
------------------------------------------

[](#verify-whether-a-menu-is-sent-successfully)

`InvMenu::send()` is not guaranteed to succeed. A failure may arise from plugins cancelling InventoryOpenEvent, a disconnected player, or the player refusing the request (e.g., because they are in pause menu). Use the `$callback` parameter to verify whether a menu has been opened.

```
$menu->send($player, callback: function(bool $success) : void{
	if($success){
		// player is viewing the menu
	}
});
```

Monitor movement of items
-------------------------

[](#monitor-movement-of-items)

InvMenu comes with a listener whereby developers can write logic to monitor movement of items in and out of inventory, and thereby take action. A listener is a callback with the following signature:

```
/**
 * @param InvMenuTransaction $transaction
 *
 * Return $transaction->continue() to continue the transaction.
 * Return $transaction->discard() to cancel the transaction.
 * @return InvMenuTransactionResult
 */
Closure(InvMenuTransaction $transaction) : InvMenuTransactionResult;
```

- `InvMenuTransaction::getPlayer()` returns the `Player` that triggered the transaction.
- `InvMenuTransaction::getItemClicked()` returns the `Item` the player clicked in the menu. You may also use `InvMenuTransaction::getOut()`.
- `InvMenuTransaction::getItemClickedWith()` returns the `Item` the player had in their hand when clicking an item. You may also use `InvMenuTransaction::getIn()`.
- `InvMenuTransaction::getAction()` returns `SlotChangeAction` - you can get the slot that the player clicked in the menu.
- `InvMenuTransaction::getTransaction()` returns the complete `InventoryTransaction` holding all the above information.

```
$menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{
	$player = $transaction->getPlayer();
	$itemClicked = $transaction->getItemClicked();
	$itemClickedWith = $transaction->getItemClickedWith();
	$action = $transaction->getAction();
	$txn = $transaction->getTransaction();
	return $transaction->continue();
});
```

The listener below does not allow players to take out apples from the menu:

```
$menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{
	if($transaction->getItemClicked()->getTypeId() === ItemTypeIds::APPLE){
		$player->sendMessage("You cannot take apples out of that inventory.");
		return $transaction->discard();
	}
	return $transaction->continue();
});
```

There are two methods you can use to prevent players from editing the menu. Either create a listener that `discard()`s the transaction, or use `InvMenu::readonly()`.

```
$menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{
	return $transaction->discard();
});

$menu->setListener(InvMenu::readonly()); // equivalent shorthand of the above

// you can also pass a callback in InvMenu::readonly()
$menu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) : void{
	// do something
}));
```

Alternatively, you may choose to write your own `InventoryTransactionEvent` listener that works on transactions on `$menu->getInventory()`. However, an InvMenu listener is enough to fulfil most tasks.

Execute a task post-transaction
-------------------------------

[](#execute-a-task-post-transaction)

Few actions are not possible to invoke at the time a player is viewing an inventory, such as sending a form—a player cannot view a form while viewing an inventory. Close the menu and utilize `InvMenuTransactionResult::then()` callback to achieve this.

```
$menu->setListener(function(InvMenuTransaction $transaction) : InvMenuTransactionResult{
	$transaction->getPlayer()->removeCurrentWindow();
	return $transaction->discard()->then(function(Player $player) : void{
		$player->sendForm(new Form());
	});
});

// or if you are using InvMenu::readonly():
$menu->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) : void{
	$transaction->getPlayer()->removeCurrentWindow();
	$transaction->then(function(Player $player) : void{
		$player->sendForm(new Form());
	});
}));
```

Monitor menu close events
-------------------------

[](#monitor-menu-close-events)

Register an inventory close callback to run whenever a player closes the menu. An inventory close callback takes the following signature:

```
/**
 * @param Player $player the player that closed the menu
 * @param Inventory $inventory the inventory of the menu
 */
Closure(Player $player, Inventory $inventory) : void;
```

```
$menu->setInventoryCloseListener(function(Player $player, Inventory $inventory) : void{
	$player->sendMessage("You are no longer viewing the menu.");
});
```

Inventory close listener is fired during both—server-initiated requests (i.e., `$player->removeCurrentWindow()`) and when the player closes the inventory on their end.

Advanced usage: Register a custom InvMenuType
---------------------------------------------

[](#advanced-usage-register-a-custom-invmenutype)

Important

PocketMine does not register a dispenser block. As of PocketMine v5, the task of registering missing vanilla blocks is excessively laborious and hence beyond the scope of this guide. [pmmp/RegisterBlocksDemoPM5](https://github.com/pmmp/RegisterBlocksDemoPM5)has a nice guide on how to achieve this. **Still overwhelmed?** I wrote a [drag-n-drop example plugin](https://gist.github.com/Muqsit/8884e0f75b317c332a56e01740bbfe98)that does all of it and registers a `/dispenser` command. With DevTools plugin installed, simply copy the code and paste it in a new "DispenserInvMenuPlugin.php" file in your server's plugin folder.

InvMenu does not provide a 9-slot dispenser inventory. But you can still achieve this by registering a dispenser InvMenuType. You'll need to specify inventory size, block actor identifier (tile identifier), and the window type (network property) for the creation of the graphic (block) and inventory parts.

```
public const TYPE_DISPENSER = "myplugin:dispenser";

protected function onEnable() : void{
	InvMenuHandler::getTypeRegistry()->register(self::TYPE_DISPENSER, InvMenuTypeBuilders::BLOCK_ACTOR_FIXED()
		->setBlock(ExtraVanillaBlocks::DISPENSER())
		->setSize(9)
		->setBlockActorId("Dispenser")
		->setNetworkWindowType(WindowTypes::DISPENSER)
	->build());
}
```

Sweet! Now you can create a dispenser menu using:

```
$menu = InvMenu::create(self::TYPE_DISPENSER);
```

InvMenu Wiki
------------

[](#invmenu-wiki)

Applications, examples, tutorials and featured projects using InvMenu can be found on the [InvMenu Wiki](https://github.com/Muqsit/InvMenu/wiki/InvMenu-v4.0).

###  Health Score

51

—

FairBetter than 95% of packages

Maintenance74

Regular maintenance activity

Popularity43

Moderate usage in the ecosystem

Community30

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 93.9% 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 ~142 days

Recently: every ~230 days

Total

8

Last Release

135d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/247134f60bf8c5c7c8a2f06b0ecea431a052614283aac5093b57bde51039e34a?d=identicon)[muqsit](/maintainers/muqsit)

---

Top Contributors

[![Muqsit](https://avatars.githubusercontent.com/u/15074389?v=4)](https://github.com/Muqsit "Muqsit (216 commits)")[![dries-c](https://avatars.githubusercontent.com/u/15795262?v=4)](https://github.com/dries-c "dries-c (2 commits)")[![darknessplx](https://avatars.githubusercontent.com/u/170175746?v=4)](https://github.com/darknessplx "darknessplx (1 commits)")[![fernanACM](https://avatars.githubusercontent.com/u/83558341?v=4)](https://github.com/fernanACM "fernanACM (1 commits)")[![inxomnyaa](https://avatars.githubusercontent.com/u/8733998?v=4)](https://github.com/inxomnyaa "inxomnyaa (1 commits)")[![ipad54](https://avatars.githubusercontent.com/u/63200545?v=4)](https://github.com/ipad54 "ipad54 (1 commits)")[![KanekiOnMC](https://avatars.githubusercontent.com/u/52374013?v=4)](https://github.com/KanekiOnMC "KanekiOnMC (1 commits)")[![poggit-bot](https://avatars.githubusercontent.com/u/22427965?v=4)](https://github.com/poggit-bot "poggit-bot (1 commits)")[![RajadorDev](https://avatars.githubusercontent.com/u/125204182?v=4)](https://github.com/RajadorDev "RajadorDev (1 commits)")[![remminiscent](https://avatars.githubusercontent.com/u/237890659?v=4)](https://github.com/remminiscent "remminiscent (1 commits)")[![SOF3](https://avatars.githubusercontent.com/u/19623715?v=4)](https://github.com/SOF3 "SOF3 (1 commits)")[![BrandPVP](https://avatars.githubusercontent.com/u/114182697?v=4)](https://github.com/BrandPVP "BrandPVP (1 commits)")[![xerenahmed](https://avatars.githubusercontent.com/u/35738714?v=4)](https://github.com/xerenahmed "xerenahmed (1 commits)")[![dadodasyra](https://avatars.githubusercontent.com/u/44753923?v=4)](https://github.com/dadodasyra "dadodasyra (1 commits)")

---

Tags

guiinventorypmmppocketminevirion

### Embed Badge

![Health badge](/badges/muqsit-invmenu/health.svg)

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

###  Alternatives

[muqsit/simple-packet-handler

Handle specific data packets (virion for PMMP API 4.0.0)

417.8k4](/packages/muqsit-simple-packet-handler)[dktapps/pmforms

Form API library for PocketMine-MP plugins

532.6k1](/packages/dktapps-pmforms)[muqsit/asynciterator

A virion that simplifies writing tasks that traverse iterators

183.1k](/packages/muqsit-asynciterator)

PHPackages © 2026

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