Template API
ultivo_field() and ultivo_rows() are how you read values in a template. They are short, a default value is an argument rather than an ?:, and a repeater is a plain foreach with no global loop state to keep track of.
Coming from ACF, the classic functions (ultivo_get_field(), ultivo_have_rows(), and so on) exist as well and stay fully supported: see Classic functions. They are the fastest way to get an existing project running, because the names map one to one. This page is where that project ends up.
ultivo_field(): get one field#
$title = ultivo_field( 'hero_title' ); // field on the current post $title = ultivo_field( 'hero_title', 12 ); // field on post 12 $color = ultivo_field( 'color', false, '#fff' ); // with a default when empty $address = ultivo_field( 'company_address', 'options' ); // from an options page $bio = ultivo_field( 'bio', 'user_5' ); // from a user ("term_9" works too)
Signature: ultivo_field( $selector, $post_id = false, $default = null ). An image field still returns an array: ultivo_field( 'logo' )['url'].
ultivo_rows(): loop over a repeater#
No more ultivo_have_rows() / ultivo_the_row(): just a foreach. An empty repeater simply iterates zero times, so no surrounding if is needed.
foreach ( ultivo_rows( 'slides' ) as $slide ) { echo $slide['title']; // sub-field via array access echo $slide->get( 'button', 'Read more' ); // or with a default }
Row count: count( ultivo_rows( 'slides' ) ).
Flexible content: layout per row#
Each row knows its own layout via ->layout():
foreach ( ultivo_rows( 'content_blocks' ) as $block ) { switch ( $block->layout() ) { case 'text': echo $block['content']; break; case 'gallery': foreach ( $block['photos'] as $photo ) { // nested repeater in the layout echo $photo['photo']['url']; } break; } }
Nested flexible content (flexible inside flexible) works the same way: $block->rows( 'sub_blocks' ).
render(): one line per page template#
Loads a theme file per row automatically, and skips layouts with no matching file:
ultivo_rows( 'content_blocks' )->render( 'template-parts/blocks' );
- Flexible content: loads
template-parts/blocks/{layout}.phpper row (e.g.text.php,gallery.php). - Repeater: loads
template-parts/blocks/row.phpfor every row. - Inside that file, the row is available as
$row:
<?php // template-parts/blocks/text.php ?> <section class="text-block"> <?php echo wp_kses_post( $row['content'] ); ?> </section>
Classic vs. recommended#
| ACF-style | Recommended |
|---|---|
ultivo_get_field( 'x' ) |
ultivo_field( 'x' ) |
ultivo_get_field( 'x', 12 ) |
ultivo_field( 'x', 12 ) |
$v = ultivo_get_field('x') ?: 'default'; |
ultivo_field( 'x', false, 'default' ) |
have_rows + while + the_row |
foreach ( ultivo_rows( 'x' ) as $row ) |
ultivo_get_sub_field( 'y' ) |
$row['y'] |
ultivo_get_row_layout() |
$row->layout() |
layout switch + get_template_part() per block |
ultivo_rows( 'x' )->render( 'path/blocks' ) |
Writing values still goes through the existing functions: ultivo_update_field() and ultivo_add_row().