PHPackages                             mvrk/icenberg - 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. mvrk/icenberg

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

mvrk/icenberg
=============

Abstraction Library for Advanced Custom Fields

v1.0.1(3w ago)7610[1 issues](https://github.com/maverick-international/Icenberg/issues)MITPHPPHP &gt;=8.1

Since Jun 1Pushed 3w ago2 watchersCompare

[ Source](https://github.com/maverick-international/Icenberg)[ Packagist](https://packagist.org/packages/mvrk/icenberg)[ RSS](/packages/mvrk-icenberg/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (1)Dependencies (6)Versions (49)Used By (0)

Icenberg
========

[](#icenberg)

[![Static Badge](https://camo.githubusercontent.com/7a5566288f0208d0af542c75320d64a09aac35c6a4c3798b0f3cd8cff2f18a4a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f666f726365645f746f2d776f726470726573732d626c75653f7374796c653d666c6174266c6f676f3d776f72647072657373266c6f676f436f6c6f723d7768697465)](https://camo.githubusercontent.com/7a5566288f0208d0af542c75320d64a09aac35c6a4c3798b0f3cd8cff2f18a4a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f666f726365645f746f2d776f726470726573732d626c75653f7374796c653d666c6174266c6f676f3d776f72647072657373266c6f676f436f6c6f723d7768697465)[![Packagist Version](https://camo.githubusercontent.com/f6b2f361eb2fcaef0e5b734c486ba6126f002fef2508d746d3f2ea18d295ec46/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d76726b2f6963656e62657267)](https://camo.githubusercontent.com/f6b2f361eb2fcaef0e5b734c486ba6126f002fef2508d746d3f2ea18d295ec46/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d76726b2f6963656e62657267)

Icenberg is an opinionated abstraction library for writing websites with Advanced Custom Fields in WordPress. It cleans up and simplifies ACF Flexible content and ACF Gutenberg block templates which often involve a lot of repetition and logic tangled up in presentation (in true WordPress style) by handling the rendering of blocks and fields for you.

Using Icenberg's element methods you can render acf fields and blocks inside a block, or anywhere you choose, fully scaffolded with BEM classes and settings which makes writing structured and re-usable CSS much more manageable. Icenberg takes care of checking a fields existence and skips over non-rendering fields. It can even apply settings as modifier classes.

```
$icenberg->the_element('client_logos');
```

Using the CLI you can generate full-featured ACF Gutenberg blocks (or flexible content row templates) with all the necessary files and with the boilerplate abstracted and settings applied in one command.

```
wp icenberg block testimonial
```

Who is it for?
--------------

[](#who-is-it-for)

Icenberg is written by professional (human) web developers who use it every day. It is intended for use by other professional or hobbyist web developers who build WordPress themes, by choice or otherwise. If you don't understand the problem it solves, don't like writing (non boilerplate) code or prefer Tailwind to BEM then this probably isn't for you. This is not a WordPress plugin.

Requirements
------------

[](#requirements)

- PHP 8+
- ACF Pro 6+
- WordPress 7+
- Composer
- WP CLI

Getting Started
---------------

[](#getting-started)

Install via composer:

```
composer require mvrk/icenberg
```

Make sure autoloading is set up in functions.php - something like:

```
$composer_path = $_SERVER['DOCUMENT_ROOT'] . '/../vendor/';

if (file_exists($composer_path)) {
    require_once $composer_path . 'autoload.php';
}
```

Initialise in functions.php

```
\MVRK\Icenberg\Hooks::init();
```

Optionally add the CLI commands

```
$is_wp_cli = defined('WP_CLI') && WP_CLI;

if ($is_wp_cli) {
    \MVRK\Icenberg\Commands\Bootstrap::setup();
}
```

Use in a template

```
use MVRK\Icenberg\Icenberg;

$ice = new Icenberg($layout = 'block_name');
```

Configuration
-------------

[](#configuration)

---

To configure for your own preferences and environment, place an 'icenberg.yaml' file in your project's root directory. If this file doesn't exist or can't be parsed, icenberg will just go ahead and use its defaults.

Supported config options below with their default values:

```
#icenberg.yaml

block_directory_name: 'blocks' #change the default block directory name
block_editor_prefix: "block" #wordpress will use this as the prefix for blocks in the block editor
sass_path: 'src/sass/blocks' #specify a location for sass partials
google_maps_api_key: '' #if you want to use the maps field
```

Basic Usage
-----------

[](#basic-usage)

---

Gutenberg Block
---------------

[](#gutenberg-block)

You can use Icenberg in an ACF Gutenberg block render template, whether generated using the CLI or hand made (you should try the CLI). You can use the wrap method in a Gutenberg block to wrap the block frontend in a similar way to how it is wrapped automatically by wp in the backend.

```
use MVRK\Icenberg\Icenberg;

$ice = new Icenberg(strtolower($block['title']));
$wrapped = true;

$ic->wrap(
    [
        $ice->get_element('quote'),
        $ice->get_element('attribution'),
        $ice->get_element('portrait_image'),
    ],
    $block,
    $wrapped
);
```

### Flexible Content

[](#flexible-content)

The following example takes place inside ACF's the\_row() - ie:

```
if (have_rows('content_blocks', $id)) :

    while (have_rows('content_blocks', $id)) : the_row();

        get_template_part('inc/blocks/block_template');

    endwhile;

endif;
```

Initialise with ACFs `get_row_layout()` in your block template:

```
use MVRK\Icenberg\Icenberg;

$ice = new Icenberg(get_row_layout());

$ice->the_element('quote');
$ice->the_element('attribution');
$ice->the_element('portrait');
```

API
---

[](#api)

### Icenberg()

[](#icenberg-1)

instantiate an Icenberg object at block or template level.

```
$ice = new Icenberg($layout = "testimonial", $prefix = "block", $post_id = false)
```

ArgumentTypeRequiredDescription`$layout`stringYesACF layout or block name`$prefix`stringNoPrefix used for classnames etc. Defaults to `'block'``$post_id`mixedNoOverride the default post ID. Defaults to `false`### get\_element()

[](#get_element)

Returns an ACF field as a formatted string, wrapped up in all the divs you need and with any special considerations applied. Takes the field name as an argument and optionally a tag for the uppermost element. If no tag is set it will use 'div'

```
$field_name = $ice->get_element('field_name');

echo $field_name;
```

ArgumentTypeRequiredDescription`$field_name`stringYesThe ACF field name to render`$tag`stringNoThe HTML tag to wrap the element in. Defaults to `'div'``$modifiers`arrayNoAn array of modifiers to use as BEM classes### the\_element()

[](#the_element)

As above, but echoes it out immediately.

```
$ice->the_element('field_name');
```

ArgumentTypeRequiredDescription`$field_name`stringYesThe ACF field name to echo`$tag`stringNoThe HTML tag to wrap the element in. Defaults to `'div'``$modifiers`arrayNoAn array of modifiers to use as BEM classesIcenberg is smart enough to know what a field's type is, so you don't need to differentiate, you just pass the field name in. You can pass ANY field. If the field is supported, Icenberg will process the field and its sub-fields

To retrieve a global option simply pass a comma-delimited string to `the_element()` or `get_element()` - it must be all as one string as opposed to separate args, and it must be comma-delimited, where the first part is the field name and the second part is the options name.

```
$ice->the_element('field_name, options');
```

### enclose() / get\_enclose()

[](#enclose--get_enclose)

Enclose is a utility for wrapping multiple icenberg fields in a container div without having to use a ?&gt; anywhere. You just need to pass it a classname (without prefixes as these will be applied by icenberg). So clean!

ArgumentTypeRequiredDescription`$class`stringYesClassname to apply to wrapper div (BEM modifiers will be appended automatically)`$elements`arrayYesArray of rendered HTML elements (e.g. `get_element()` results or strings)`$tag`stringNoThe HTML tag to wrap the element in. Defaults to `'div'``$attrs`arrayNoAn array of additional attributes to apply to the wrapper element`$modifiers`arrayNoAn array of modifiers to use as BEM classesSo for example, in a 'Cta' block, where cta\_heading is a text field and cta\_content is a WYSIWYG field:

```
$ice->enclose('text', [
    $ice->get_element('cta_heading')
    $ice->get_element('cta_content'),
]);
```

will generate:

```

        I'm a heading, look at me!

            sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
            nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

```

You could also pass any thing else you like to enclose as part of the array, as long as its storable as a variable (for example inserting a `get_template_part()` won't work here because it effectively prints the content).

```
$random_text = "I am some random text, isn't it wonderful?";

$ice->enclose('text', [
    $ice->get_element('cta_heading'),
    $random_text
]);
```

Of course life is never simple, so you will most likely need more complex layouts, but icenberg doesn't mind. You can insert it in html if you want to.

```

    the_element('motif_blurple');
    endif; ?>

```

### Value()

[](#value)

```
$lady_in_red = $ice->value('dancing_with_me');
```

You can us the `value()` method to return the 'raw', value of a given field without checking for existence or specifying if it is a sub-field. As this just returns the value there are no special considerations for individual field types.

ArgumentTypeRequiredDescription`$field_name`stringYesName of the field### field()

[](#field)

```
$ice->field($field_name)
```

you can use icenberg to evaluate fields and do some more complex field manipulation too, using the `field()` method in conjunction with the below methods. `field()` takes the field name as an argument and returns the icenberg instance for method chaining.

ArgumentTypeRequiredDescription`$field_name`stringYesName of the field to work with### get()

[](#get)

```
$ice->field('saxophone')->get()
```

Returns the icenbergified field HTML (in the same way as get\_element). Optionally pass a tag for the wrapper.

ArgumentTypeRequiredDescription`$tag`stringNoTag to use for the wrapper. Defaults to `'div'``$modifiers`arrayNoAn array of modifiers to use as BEM classes### prune()

[](#prune)

```
$group = $ice->field('bad_singers')->prune(['chris_de_burgh', 'cliff_richard'])->get();
```

Pass an array of field names to the prune method to remove them from a group or from a repeater row.

ArgumentTypeRequiredDescription`$exclusions`arrayYesField names to exclude from the group/repeater output### only()

[](#only)

```
$group = $ice->field('great_singers')->only(['chris_de_burgh'])->get('marquee');
```

Whitelist fields in a group

ArgumentTypeRequiredDescription`$inclusions`arrayYesField names to include in the group/repeater output### is()

[](#is)

returns true if the value of the field equals the argument passed to `is()`. You don't need to check for a fields existence before using these methods as they will do it for you and return `false` if they don't.

```
if ($ice->field('font_colour')->is('red')) :
    $ice->the_element('font_colour');
else :
    echo 'oh no';
endif;
```

ArgumentTypeRequiredDescription`$value`mixedYesValue to compare against the field value### has()

[](#has)

Returns true if the field value (an array/iterable like a select multiple or checkbox field) contains the given value. Returns false if the field doesn't exist or isn't iterable.

```
if ($ice->field('mall')->has('cop')) :
    echo 'blart';
endif;
```

ArgumentTypeRequiredDescription`$value`mixedYesValue to compare against the field value### lessThan() / greaterThan()

[](#lessthan--greaterthan)

Self-explanatory, both take an integer as an argument. Warning: If you use it on a non-numeric field it will return false.

```
if ($ice->field('range_test')->lessThan(51)) :
    $class = 'text_' . $ice->field('range_test')->field;
    $ice->enclose($class, [
        $ice->get_element('cta_content'),
        $ice->get_element('cta_image'),
    ]);
endif;
```

ArgumentTypeRequiredDescription`$value`intYesInteger to compare against field value### settings()

[](#settings)

Pass in a field group of settings and optionally an array of manually set classes, and it will attach them as CSS modifier classes. if you include a text field called 'unique\_id' in your group icenberg will attach it as an ID too.

ArgumentTypeRequiredDescription`$block_settings`arrayYesArray of field group names`$classes`arrayYesArbitrary classnames to append as modifiersIf using the `wrap()` method, you don't need to manually specify settings. `wrap()` looks for a field group called ' block\_settings' and one called 'settings' on the block and uses this method to parse them into modifiers on the intermediate wrapper.

Example using settings in `enclose()`:

```
$classes = ['banana', 'orange'];

$block_settings = get_sub_field($block_settings);

$settings = $ice->settings($block_settings, $classes);

$ice->enclose ($settings, [
    $ice->get_element('cheese_board'),
    $ice->get_element('flame_thrower')
])
```

or in regular php/html

```

...whatever you want

```

which will print out something like

```
"class='component--orange component--banana component--padding-top-300 component--skin-purple' id='some_id'"
```

Depending on the settings in your group.

### wrap()

[](#wrap)

Wraps an array of rendered elements in the standard Icenberg block wrapper, mirroring the wrapping that WordPress applies in the backend so the frontend matches. Optionally accepts a background element which can be rendered behind the wrapped content.

```
$ice->wrap(
    [
        $ice->get_element('quote'),
        $ice->get_element('attribution'),
    ],
    $block,
    $wrap_inner = true,
    $background = $ice->get_element('background_image')
);
```

ArgumentTypeRequiredDescription`$content`arrayYesHTML elements to wrap`$block`arrayNoThe acf block, automatically available in the render template`$wrap_inner`boolNoWhether to wrap the contents in an inner wrapper`$background`mixedNoA rendered element (e.g. an image) to place behind the wrapped content.### InnerBlocks

[](#innerblocks)

Helper for rendering Gutenberg's `` tag inside an ACF block render template, with the appropriate BEM class applied automatically so it slots in with the rest of your block markup. Pass an array of allowed block names and the current Icenberg instance.

```
use MVRK\Icenberg\Icenberg;
use MVRK\Icenberg\Blocks\InnerBlocks;

$icenberg = new Icenberg('my_block');
$allowed_blocks = ['core/heading', 'core/paragraph'];

$content = $icenberg->get_enclose('content', [
    $icenberg->get_element('intro'),
    InnerBlocks::make($allowed_blocks, $icenberg),
]);

$icenberg->wrap([$content], $block);
```

ArgumentTypeRequiredDescription`$allowed_blocks`arrayYesArray of block names permitted inside the InnerBlocks`$icenberg`IcenbergYesThe current Icenberg instance### member()

[](#member)

Pulls a single sub-field value directly out of a group field without having to render the whole group. Useful when you only need one value from a settings or config group.

```
$accent = $ice->member('accent_colour', 'block_settings');
```

ArgumentTypeRequiredDescription`$target`stringYesThe sub-field name to retrieve (needle)`$group`stringYesThe name of the group field to look inside (haystack)Special Fields
--------------

[](#special-fields)

#### Google Maps Field

[](#google-maps-field)

For the Google Maps field to work properly on front and backends you will need an API key. Once you have the key, add it to icenberg.yml in your project and the frontend will work. To make it work in the backend, add the following to your functions.php (in this example the key is defined in wp-config.php)

```
function acf_google_map_field($api)
{
    $api['key'] = GOOGLE_MAPS_API_KEY;

    return $api;
}
add_filter('acf/fields/google_map/api', 'acf_google_map_field');
```

CLI
---

[](#cli)

you can use the Icenberg CLI to rapidly bootstrap Icenberg blocks. This extends wp-cli so you need to have that installed and working first.

### Available commands

[](#available-commands)

```
wp icenberg block --block_name
```

This bootstraps an ACF Gutenberg block with all relevant files ready to go.

This assumes that your blocks are in a folder called 'blocks' in your template root directory but this is configurable via icenberg.yaml

Icenberg generates a folder per block within the 'blocks' folder. This folder contains

- block.json
- &lt;block\_name&gt;.php
- &lt;block\_name&gt;.css

It will also register an empty field group ready for access via the ACF GUI and send a scss file to the sass directory. The block.json is opinionated so modify as required once its generated. Pay attention to the fact that the stylesheet is set to display in-editor only because we're assuming a workflow where you're compiling sass to the CSS file and enqueuing it globally on the frontend.

```
wp icenberg block --block_name --flexible
```

this is similar to the above but creates just the php and scss files for flexible content blocks.

### Supported Add Ons

[](#supported-add-ons)

The library directly supports the following ACF plugins:

- [ACF Gravity forms](https://wordpress.org/plugins/acf-gravityforms-add-on/)
- [Table Field Add-on for ACF and SCF](https://wordpress.org/plugins/advanced-custom-fields-table-field/)

Other plugins may be compatible if they use the built-in field names or aren't directly involved in the render.

Supported fields
----------------

[](#supported-fields)

#### Full Support

[](#full-support)

The following fields can be used with get\_element() / the\_element() and all other Icenberg methods:

- DatePicker
- DateTimePicker
- Gallery
- Google Maps
- Group
- IconPicker
- Image
- Link
- Number
- OEmbed
- Page Link
- Post Object
- Range
- Relationship
- Repeater
- Select
- Text
- Textarea
- TimePicker
- WYSIWYG

Element methods will quietly skip over any other default fields if they are included in a group or repeater.

#### Limited Support

[](#limited-support)

The values of the following fields are available in the settings method or any of the field methods:

- ButtonGroup
- Checkbox
- Taxonomy
- User
- TrueFalse

Submit a GitHub issue if you have a use case for directly rendering any of these and we'll consider it.

#### Third party fields:

[](#third-party-fields)

- Forms
- Table

### VS Code Extension

[](#vs-code-extension)

An extension with useful snippets is available for Virtual Studio Code.

[Icenberg Snippets](https://marketplace.visualstudio.com/items?itemName=coderjerk.icenberg-snippets&ssr=false#overview)

###  Health Score

52

—

FairBetter than 96% of packages

Maintenance92

Actively maintained with recent releases

Popularity20

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity70

Established project with proven stability

 Bus Factor1

Top contributor holds 82.1% 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 ~33 days

Recently: every ~96 days

Total

45

Last Release

23d ago

Major Versions

v0.9.2 → v1.02026-05-27

PHP version history (2 changes)v0.1PHP &gt;=7.4

v1.0PHP &gt;=8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/42ca0d6cedc29ed4cc557e116aa1cdea8f1d55cd6374b3241068acc8c582cbb7?d=identicon)[Mvrk](/maintainers/Mvrk)

---

Top Contributors

[![danieldevine](https://avatars.githubusercontent.com/u/5939939?v=4)](https://github.com/danieldevine "danieldevine (96 commits)")[![cathal-maverick](https://avatars.githubusercontent.com/u/32732059?v=4)](https://github.com/cathal-maverick "cathal-maverick (21 commits)")

---

Tags

acfadvanced-custom-fieldsbemwordpresswordpressacfadvanced custom fields

### Embed Badge

![Health badge](/badges/mvrk-icenberg/health.svg)

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

###  Alternatives

[friendsoftypo3/content-blocks

TYPO3 CMS Content Blocks - Content Types API | Define reusable components via YAML

101466.4k45](/packages/friendsoftypo3-content-blocks)[hellonico/acf-country

A country field for ACF.

12195.6k](/packages/hellonico-acf-country)[folbert/fewbricks

Write code to create fields and more for Advanced Custom Fields

1196.0k](/packages/folbert-fewbricks)[rcsofttech/audit-trail-bundle

Enterprise-grade, high-performance Symfony audit trail bundle. Automatically track Doctrine entity changes with split-phase architecture, multiple transports (HTTP, Queue, Doctrine), and sensitive data masking.

1155.2k](/packages/rcsofttech-audit-trail-bundle)[bostondv/acf-ninja-forms

Adds an Advanced Custom Fields field to select one or many Ninja Forms.

1525.1k](/packages/bostondv-acf-ninja-forms)[mmirus/acf-flexible-content-title

Display the content of a field in the title bar of your Advanced Custom Fields flexible content sections.

362.8k](/packages/mmirus-acf-flexible-content-title)

PHPackages © 2026

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