{"id":33997562,"url":"https://github.com/maverick-international/icenberg","last_synced_at":"2025-12-13T08:59:01.211Z","repository":{"id":38835379,"uuid":"498673360","full_name":"maverick-international/Icenberg","owner":"maverick-international","description":"Abstracts away Advanced Custom Fields flexible content markup","archived":false,"fork":false,"pushed_at":"2025-11-19T08:43:56.000Z","size":246,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-11-19T10:20:22.981Z","etag":null,"topics":["acf","advanced-custom-fields","bem"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maverick-international.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-06-01T09:33:28.000Z","updated_at":"2025-11-19T08:43:21.000Z","dependencies_parsed_at":"2025-05-12T09:53:02.192Z","dependency_job_id":null,"html_url":"https://github.com/maverick-international/Icenberg","commit_stats":{"total_commits":22,"total_committers":3,"mean_commits":7.333333333333333,"dds":0.2272727272727273,"last_synced_commit":"9323fe1ebd35b1d6e76a7c593875d838d41e0a40"},"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"purl":"pkg:github/maverick-international/Icenberg","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maverick-international%2FIcenberg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maverick-international%2FIcenberg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maverick-international%2FIcenberg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maverick-international%2FIcenberg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maverick-international","download_url":"https://codeload.github.com/maverick-international/Icenberg/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maverick-international%2FIcenberg/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27702869,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-13T02:00:09.769Z","response_time":147,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["acf","advanced-custom-fields","bem"],"created_at":"2025-12-13T08:59:00.255Z","updated_at":"2025-12-13T08:59:01.203Z","avatar_url":"https://github.com/maverick-international.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Icenberg 🥶\n\n\n\n- [Icenberg 🥶](#icenberg-)\n    - [What is it?](#what-is-it)\n    - [Getting Started](#getting-started)\n      - [Initialise](#initialise)\n      - [`Icenberg::__construct($layout, $prefix = 'block', $post_id = false)`](#icenberg__constructlayout-prefix--block-post_id--false)\n    - [Using with ACF Flexible Content blocks](#using-with-acf-flexible-content-blocks)\n  - [Using in an ACF Gutenberg Block](#using-in-an-acf-gutenberg-block)\n    - [Icenberg Methods](#icenberg-methods)\n      - [`get_element($field_name, $tag = 'div', $modifiers = [])`](#get_elementfield_name-tag--div-modifiers--)\n      - [`the_element($field_name, $tag = 'div', $modifiers = [])`](#the_elementfield_name-tag--div-modifiers--)\n      - [Global Options](#global-options)\n      - [`enclose($class, array $elements, $tag = 'div', $attrs = [], $modifiers = [])`](#encloseclass-array-elements-tag--div-attrs---modifiers--)\n  - [Values](#values)\n  - [Conditionals and manipulations](#conditionals-and-manipulations)\n      - [`field($field_name)`](#fieldfield_name)\n      - [`get($tag = 'div', $modifiers = [])`](#gettag--div-modifiers--)\n      - [`prune(array $exclusions)`](#prunearray-exclusions)\n      - [`only(array $inclusions)`](#onlyarray-inclusions)\n      - [`is($value)`](#isvalue)\n      - [`lessThan($value)` / `greaterThan($value)`](#lessthanvalue--greaterthanvalue)\n  - [Special Fields](#special-fields)\n      - [Google Maps Field](#google-maps-field)\n      - [`settings($field_name, $additional_classes = [])`](#settingsfield_name-additional_classes--)\n      - [`get_buttons($field_name, $modifiers = [])` / `the_buttons($field_name, $modifiers = [])`](#get_buttonsfield_name-modifiers----the_buttonsfield_name-modifiers--)\n  - [CLI](#cli)\n    - [Available commands](#available-commands)\n    - [Configuration](#configuration)\n  - [Supported fields](#supported-fields)\n      - [Full Support](#full-support)\n      - [Third party fields:](#third-party-fields)\n      - [Special Fields](#special-fields-1)\n    - [VS Code Extension](#vs-code-extension)\n\n\n\n### What is it?\n\nIcenberg is an opinionated abstraction for ACF 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). \n\nUsing Icenberg's methods we can render acf fields complete with BEM classes and settings in a clean(er) object oriented fashion, while still allowing us to do things the old fashioned way if necessary. \n\n![icenberg logo](images/comparison.png)\n\n\nIcenberg requires ACF Pro and is primarily for internal use at Maverick, although it is easy to implement on any WordPress template using ACF fields. It also includes a convenient CLI for generating ACF Gutenberg blocks.\n\nIt is designed to be used primarily with flexible content fields and ACF Gutenberg blocks but works with any field including option fields. It could also work within other scenarios, in theory.\n\n\n### Getting Started\n\nInstall via composer:\n\n```bash\ncomposer require mvrk/icenberg\n```\n\nmake sure autoloading is set up in functions.php - something like:\n\n```php\n\n$composer_path = $_SERVER['DOCUMENT_ROOT'] . '/../vendor/';\n\nif (file_exists($composer_path)) {\n\n    require_once $composer_path . 'autoload.php';\n}\n\n```\nMake sure you have ACF Pro installed. The library also supports [ACF Gravity forms](https://wordpress.org/plugins/acf-gravityforms-add-on/) plugin.\n\n#### Initialise\n\n```php\n\nuse MVRK\\Icenberg\\Icenberg;\n\n$ice = new Icenberg($layout = 'block_name', $prefix = 'block', $post_id = false);\n\n```\n\n#### `Icenberg::__construct($layout, $prefix = 'block', $post_id = false)`\n\n| Argument     | Type    | Required | Description                       |\n|--------------|---------|----------|-----------------------------------|\n| `$layout`    | string  | Yes      | ACF layout or block name          |\n| `$prefix`    | string  | No       | Prefix used for classnames etc. Defaults to `'block'` |\n| `$post_id`   | mixed   | No       | Override the default post ID. Defaults to `false` |\n\n---\n\n### Using with ACF Flexible Content blocks\nThe following example takes place inside ACF's the_row() - ie:\n\n```php\n\nif (have_rows('content_blocks', $id)) :\n\n    while (have_rows('content_blocks', $id)) : the_row();\n\n        get_template_part('inc/blocks/block_template');\n\n    endwhile;\n\nendif;\n```\nInitialise with ACFs `get_row_layout()` in your block template:\n\n```php\n\nuse MVRK\\Icenberg\\Icenberg;\n\n$ice = new Icenberg(get_row_layout());\n\n$ice-\u003ethe_element('quote');\n$ice-\u003ethe_element('attribution');\n$ice-\u003ethe_element('portrait');\n\n```\n\n## Using in an ACF Gutenberg Block\n\nSince v0.5.0 you can use Icenberg in an ACF gutenberg block, just pass the block title instead of the row layout. 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:\n\n```php\nuse MVRK\\Icenberg\\Icenberg;\n\n$icenberg = new Icenberg(strtolower($block['title']));\n\n$icenberg::wrap(\n    [\n        $icenberg-\u003eget_element('quote'),\n        $icenberg-\u003eget_element('attribution'),\n        $icenberg-\u003eget_element('portrait'),\n    ],\n    $block,\n    true\n);\n\n```\n\n### Icenberg Methods\n\n#### `get_element($field_name, $tag = 'div', $modifiers = [])`\n\n| Argument     | Type   | Required | Description                      |\n|--------------|--------|----------|----------------------------------|\n| `$field_name`| string | Yes      | The ACF field name to render     |\n| `$tag`       | string | No       | The HTML tag to wrap the element in. Defaults to `'div'` |\n| `$modifiers` | array  | No       | An array of modifiers to use as BEM classes |\n\nReturns 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'\n\n```php\n\n$field_name = $ice-\u003eget_element('field_name');\n\necho $field_name;\n\n```\n\n#### `the_element($field_name, $tag = 'div', $modifiers = [])`\n\n| Argument     | Type   | Required | Description                      |\n|--------------|--------|----------|----------------------------------|\n| `$field_name`| string | Yes      | The ACF field name to echo       |\n| `$tag`       | string | No       | The HTML tag to wrap the element in. Defaults to `'div'` |\n| `$modifiers` | array  | No       | An array of modifiers to use as BEM classes |\n\nAs above, but echoes it out immediately.\n\n```php\n\n$ice-\u003ethe_element('field_name');\n\n```\nIcenberg 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.\n\n#### Global Options\n\nTo retrieve a global option simply pass a comma delimeted string to `the_element()` or `get_element()` - it must be all as one string as opposed to seperate args and it must be comma delimited, where the first part is the field name and the second part is the options name, eg\n\n```php\n\n$ice-\u003ethe_element('field_name, options');\n\n```\n\n\n#### `enclose($class, array $elements, $tag = 'div', $attrs = [], $modifiers = [])`\n\n| Argument     | Type    | Required | Description                       |\n|--------------|---------|----------|-----------------------------------|\n| `$class`     | string  | Yes      | Classname to apply to wrapper div (BEM modifiers will be appended automatically) |\n| `$elements`  | array   | Yes      | Array of rendered HTML elements (e.g. `get_element()` results or strings) |\n| `$tag`       | string  | No       | The HTML tag to wrap the element in. Defaults to `'div'` |\n| `$attrs`     | array   | No       | An array of additional attributes to apply to the wrapper element |\n| `$modifiers` | array   | No       | An array of modifiers to use as BEM classes |\n\nEnclose is a utility for wrapping multiple icenberg fields in a container div without having to use a ?\u003e anywhere. You just need to pass it a classname (without prefixes as these will be applied by icenberg). So clean!\n\nSo for example, in a 'Cta' block,  where cta_heading is a text field and cta_content is a wysiwyg field:\n\n```php\n\n$ice-\u003eenclose('text', [\n    $ice-\u003eget_element('cta_heading')\n    $ice-\u003eget_element('cta_content'),\n]);\n\n```\nwill generate:\n\n```html\n\n\u003cdiv class=\"block block--cta\"\u003e\n    \u003cdiv class=\"section__inner\"\u003e\n        \u003cdiv class=\"wrapper block--cta__wrapper\"\u003e\n            \u003cdiv class=\"block--cta__text\"\u003e\n                \u003cdiv class=\"block--cta__cta-heading\"\u003e\n                    I'm a heading, look at me!\n                \u003c/div\u003e\n                \u003cdiv class=\"block--cta__cta-content\"\u003e\n                    \u003cp\u003e\n                        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.\n                    \u003c/p\u003e\n                \u003c/div\u003e\n            \u003c/div\u003e\n        \u003c/div\u003e\n    \u003c/div\u003e\n\u003c/div\u003e\n\n\n```\n\nYou 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).\n\n```php\n\n$random_text = \"\u003cspan\u003eI am some random text, isn't it wonderful?\u003c/span\u003e\";\n\n$ice-\u003eenclose('text', [\n    $ice-\u003eget_element('cta_heading'),\n    $random_text\n]);\n\n```\n\nOf 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.\n\n```html\n\n\u003cdiv class=\"testimonial__corner-illustration_green_reversed\"\u003e\n    \u003c?php if($motif_variation_5_purple === 'orange') :\n    $ice-\u003ethe_element('motif_blurple');\n    endif; ?\u003e\n\u003c/div\u003e\n\n```\n## Values\nYou can us the `value()` method to return the 'raw', value of a given field without checking for existence or specifiying if it is a sub field.\n\n```php\n$lady_in_red = $ice-\u003evalue('dancing_with_me');\n```\nas this just returns the value there are no special considerations for individual field types.\n\n## Conditionals and manipulations\n\n#### `field($field_name)`\n\n| Argument     | Type   | Required | Description                       |\n|--------------|--------|----------|-----------------------------------|\n| `$field_name`| string | Yes      | Name of the field to work with    |\n\nyou can use icenberg to evaluate fields and do some more comlplex field manipualtion too, using the `field()` method in conjucntion with the below methods. `field()` takes the field name as an argument and returns the icenberg instance for method chaining.\n\n ```php\n $ice-\u003efield($field_name)\n ```\n#### `get($tag = 'div', $modifiers = [])`\n\n| Argument     | Type   | Required | Description                       |\n|--------------|--------|----------|-----------------------------------|\n| `$tag`       | string | No       | Tag to use for the wrapper. Defaults to `'div'` |\n| `$modifiers` | array  | No       | An array of modifiers to use as BEM classes |\n\nReturns the icenbergified field html (in the same way as get_element). Optionally pass a tag for the wrapper.\n\n```php\n$ice-\u003efield('saxaphone')-\u003eget()\n```\n\n#### `prune(array $exclusions)`\n\n| Argument     | Type   | Required | Description                       |\n|--------------|--------|----------|-----------------------------------|\n| `$exclusions`| array  | Yes      | Field names to exclude from the group/repeater output |\n\npass an array of field names to the prune method to remove them from a group or from a repeater row.\n\n```php\n$group = $ice-\u003efield('bad_singers')-\u003eprune(['chris_de_burgh', 'cliff_richard'])-\u003eget();\n\n```\n\n#### `only(array $inclusions)`\n\n| Argument     | Type   | Required | Description                       |\n|--------------|--------|----------|-----------------------------------|\n| `$inclusions`| array  | Yes      | Field names to include in the group/repeater output |\n\n```php\n$group = $ice-\u003efield('great_singers')-\u003eonly(['chris_de_burgh'])-\u003eget('marquee');\n\n```\n\n#### `is($value)`\n\n| Argument     | Type   | Required | Description                       |\n|--------------|--------|----------|-----------------------------------|\n| `$value`     | mixed  | Yes      | Value to compare against the field value |\n\nreturns true if the value of the field equals the argument passed to `is()`. You don't need to check for a fields existance before using these methods as they will do it for you and return `false` if they don't.\n\n```php\n if ($ice-\u003efield('font_colour')-\u003eis('red')) :\n    $ice-\u003ethe_element('font_colour');\nelse :\n    echo 'oh no';\nendif;\n```\n\n#### `lessThan($value)` / `greaterThan($value)`\n\n| Argument     | Type   | Required | Description                       |\n|--------------|--------|----------|-----------------------------------|\n| `$value`     | int    | Yes      | Integer to compare field value against |\n\n\nSelf explanatory, both take an integer as an argument. Warning: If you use it on a non numeric field it will return false.\n\n```php\nif ($ice-\u003efield('range_test')-\u003elessThan(51)) :\n    $class = 'text_' . $ice-\u003efield('range_test')-\u003efield;\n    $ice-\u003eenclose($class, [\n        $ice-\u003eget_element('cta_content'),\n        $ice-\u003eget_element('cta_image'),\n    ]);\nendif;\n\n```\n\n## Special Fields\n\n#### Google Maps Field\n\nFor 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)\n\n```php\nfunction acf_google_map_field($api)\n{\n    $api['key'] = GOOGLE_MAPS_API_KEY;\n\n    return $api;\n}\nadd_filter('acf/fields/google_map/api', 'acf_google_map_field');\n```\n\n#### `settings($field_name, $additional_classes = [])`\n\n| Argument            | Type          | Required | Description                                |\n|---------------------|---------------|----------|--------------------------------------------|\n| `$field_name`       | string|array | Yes      | Field group name or settings array         |\n| `$additional_classes` | array      | No       | Additional classnames to append as modifiers |\n\nPass 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 a id too.\n\nExample using settings in  `enclose()`:\n\n```php\n$classes = ['banana', 'orange'];\n\n$block_settings = get_sub_field($block_settings);\n\n$settings = $ice-\u003esettings($block_settings, $classes);\n\n$ice-\u003eenclose ($settings, [\n    $ice-\u003eget_element('cheese_board'),\n    $ice-\u003eget_element('flame_thrower')\n])\n```\n\nor in regular php/html\n\n```html\n\n\u003cdiv \u003c?php echo $settings; ?\u003e\u003e\n    ...whatever you want\n\u003c/div\u003e\n```\n\nwhich will print out something like\n```html\n\"class='orange orange_padding_top_300 orange_skin_purple' id='cheese_board'\"\n```\n\nDepending on the settings in your group.\n\n\n#### `get_buttons($field_name, $modifiers = [])` / `the_buttons($field_name, $modifiers = [])`\n\n| Argument     | Type   | Required | Description                       |\n|--------------|--------|----------|-----------------------------------|\n| `$field_name`| string | Yes      | Field group name for buttons      |\n| `$modifiers` | array  | No       | An array of modifiers to use as BEM classes |\n\nReturn a formatted group of buttons with a huge range of styles catered for - very Maverick specific.Expects our usual group of buttons format.\n\n## CLI\n\nyou can now use the Icenberg CLI to rapidly bootstrap Icenberg blocks (since v0.5.0). This extends wp-cli so you need to have that installed and working first.\n\nAdd the below to your functions.php, after the autoload.\n\n```php\n$is_wp_cli = defined('WP_CLI') \u0026\u0026 WP_CLI;\n\nif ($is_wp_cli) {\n    \\MVRK\\Icenberg\\Commands\\Bootstrap::setup();\n}\n``` \n\n### Available commands\n\n`wp icenberg block --block_name`\n\nthis bootstraps an ACF gutenberg block with all relevant files ready to go.\n\nThis assumes that your blocks are in a folder called 'blocks' in your template root directory but this is configurable via icenberg.yaml\n\nIcenberg generates a folder per block within the blocks folder. This folder contains\n- block.json\n- \u003cblock_name\u003e.php\n- \u003cblock_name\u003e.css\n\nIt will also register an empty field group ready for access via the ACF GUI.\n\n`wp icenberg block --block_name --flexible`\n\nthis is similar to the above but creates just the php and scss files for flexible content blocks. \n\n\n### Configuration\nConfig options are now available by placing 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.\n\nSupported config options below with their default values:\n\n```yaml\nblock_directory_name: 'blocks' #change the default block directory name\nsass_path: 'src/sass/blocks' #specify a location for sass partials\ngoogle_maps_api_key: '\u003cyour key here\u003e'\n\n```\n\n## Supported fields\n\n#### Full Support\n- Gallery\n- Group\n- Image\n- Link\n- Number\n- OEmbed\n- Range\n- Repeater\n- Select\n- Text\n- Textarea\n- Wysiwyg\n- Relationship\n- Post Object\n- Page Link\n- Google Maps\n\n#### Third party fields:\n- Forms\n- Swatch\n\n#### Special Fields\n- Buttons\n- Settings\n\n### VS Code Extension\nAn extension with useful snippets is available for Virtual Studio Code.\n\n[Icenberg Snippets](https://marketplace.visualstudio.com/items?itemName=coderjerk.icenberg-snippets\u0026ssr=false#overview)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaverick-international%2Ficenberg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaverick-international%2Ficenberg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaverick-international%2Ficenberg/lists"}