---
title: "lzb/get_blocks"
description: "lzb/get_blocks adds or removes whole blocks from the list Lazy Blocks works from, so a plugin can ship blocks without saving them in the database."
url: "https://www.lazyblocks.com/docs/php-filters/lzb-get_blocks/"
lastUpdated: 2026-09-23
source: "php-filters/lzb-get_blocks.mdx"
---
# lzb/get_blocks

Adds or removes whole blocks from the list every other part of the plugin works from, which is how a plugin ships blocks without writing them into the database.

`get_blocks()` fires it at two places. Once on a request-level cache hit, where it returns early with the list it already built, and once at the end after the database blocks, the blocks added through `lazyblocks()->add_block()` and the duplicate slug pass have all been folded together. A handler therefore runs on both paths and has to be safe to run more than once per request.

## Attributes

| Name      | Type      | Description                                                                                      |
| --------- | --------- | ------------------------------------------------------------------------------------------------ |
| `$blocks` | **Array** | list of blocks, each one shaped like [lzb/block_data](https://www.lazyblocks.com/docs/php-filters/lzb-block_data/) returns |

The list is a plain indexed array. Each item has `id`, `title`, `icon`, `keywords`, `slug`, `description`, `category`, `category_label`, `supports`, `controls`, `code`, `style`, `script`, `styles`, `condition` and `edit_url`. `slug` is the full block name including the namespace, so it reads `lazyblock/pricing-table` rather than `pricing-table`. `id` is the post ID and is `null` for a block registered from PHP.

## Usage

```php title="PHP"
function my_lzb_get_blocks( $blocks ) {
  // Hide the blocks tagged "internal" from editors, without deleting them.
  if ( current_user_can( 'manage_options' ) ) {
    return $blocks;
  }

  return array_values(
    array_filter(
      $blocks,
      function ( $block ) {
        return ! in_array( 'internal', (array) $block['keywords'], true );
      }
    )
  );
}

add_filter( 'lzb/get_blocks', 'my_lzb_get_blocks' );
```

Reindex after filtering, as above. Several consumers walk the list with `foreach` and are fine with gaps, but the array is also passed to the editor as JSON, where a gapped array is serialised as an object and the editor registers nothing. A block added here is registered like any other, so it needs a `slug` with a namespace and a `controls` array whose `type` values are real control types.

`get_blocks()` also writes the database blocks into a transient before this filter runs, which means additions made here are never cached. [lzb/cache_expiration](https://www.lazyblocks.com/docs/php-filters/lzb-cache_expiration/) sets the transient lifetime and [lzb/cache_cleared](https://www.lazyblocks.com/docs/php-actions/lzb-cache_cleared/) fires when it is flushed. To register a block rather than post-process the list, call `lazyblocks()->add_block()` on [lzb/init](https://www.lazyblocks.com/docs/php-actions/lzb-init/).

## Documentation Index
> Fetch the complete documentation index at: https://www.lazyblocks.com/llms.txt
> Fetch every page in a single file at: https://www.lazyblocks.com/llms-full.txt
