Shortcodes and Block Attributes
Every shortcode Logo Carousel registers, the PHP template function, and the attribute shape behind each block, for theme work, migrations and generating blocks in code.
This page has two audiences. If you're placing logos in a PHP template, a widget area or a page builder, you want Shortcodes and PHP function. If you're generating blocks in code (a migration script, an importer, a starter-content routine), skip to Block attributes.
Shortcodes
A shortcode is a tag in square brackets that WordPress swaps for real output when the page loads. Logo Carousel has two families: one for classic views, and one for Saved Templates built with blocks.
[logocarousel]: a classic view
Renders a view built under Logo Carousel → Manage Views (the Classic version). A view is a saved set of display options for the classic logo list.
[logocarousel id="123"]| Attribute | Required | Notes |
|---|---|---|
id | yes | The view's post ID (post type sp_lc_shortcodes). Copy it from the Shortcode column on the Manage Views screen. |
[logo_carousel_pro id="123"] is an alias that does exactly the same thing. Older content may use it, and it keeps working.
The shortcode prints nothing when id is missing, points at something that isn't a view, or points at a view in the trash. A deleted view therefore leaves no broken markup behind.
A red license notice instead of logos?
When the license isn't active, the shortcode shows an "activate the license" notice in place of the logos, and only to administrators. Everyone else sees nothing, which is why it's often reported as "the logos vanished for visitors." Sites first installed on version 3.3.15 or earlier are exempt. See Installation → Activate your license.
[lc_template]: a Saved Template
Renders a Saved Template: a layout built with the blocks and saved once so you can reuse it anywhere, including places blocks can't go.
[lc_template id="456"]| Attribute | Required | Notes |
|---|---|---|
id | yes | The template's post ID (post type sp_lc_template). The Saved Templates screen shows the ready-made shortcode for each template. |
It prints nothing when:
- the template doesn't exist or isn't a Saved Template,
- the Saved Templates module is switched off on Logo Carousel → Getting Started → Modules, or
- the template isn't published and the visitor can't edit it. Drafts only render for people who can edit them, so you can preview while you work.
A template that contains its own shortcode is ignored rather than looping forever.
This is the shortcode to use for block-built layouts inside a theme template, a widget or a builder without block support.
Page-builder shortcodes
Two more shortcodes exist for page-builder integrations: [vc_sp_logo_carousel] (WPBakery, attribute template_id) and [et_pb_sp_logo_carousel] (the Divi 4 module). The builders insert these for you when you add their element. Both point at Saved Templates, so if you're writing a shortcode by hand, use [lc_template] instead. See Integrations.
PHP function: logocarousel()
For theme files there's a small helper that prints a classic view:
<?php
if ( function_exists( 'logocarousel' ) ) {
logocarousel( 123 ); // The view's ID.
}
?>It echoes [logocarousel id="123"], so the same rules apply. The function_exists() check keeps your theme from crashing if the plugin is ever deactivated.
There's no matching helper for Saved Templates. Use do_shortcode():
<?php echo do_shortcode( '[lc_template id="456"]' ); ?>Block attributes
Each block stores its whole configuration as block attributes: the JSON inside the HTML comment that opens the block in the post content. Switch the block editor to Code editor (the ⋮ menu, or Ctrl+Shift+Alt+M / ⌥⇧⌘M) to see it.
Block names
| Block | Name |
|---|---|
sp-logo-carousel/carousel | |
sp-logo-carousel/grid | |
sp-logo-carousel/list | |
sp-logo-carousel/marquee | |
sp-logo-carousel/table |
All five are dynamic blocks: the post stores only the comment with its attributes, and the HTML is built on the server every time the page loads. That's why changing a setting never triggers "This block contains unexpected or invalid content."
The older Classic Shortcode block (sp-logo-carousel-pro/shortcode) simply wraps a [logocarousel] view. Its attributes are shortcode (the view ID) plus a few editor flags.
How the schema works
The attribute schema lives in PHP only, under src/Blocks/Schema/ in the plugin. The block.json files have no attributes key; the editor receives the schema from the server when it loads. Two practical consequences:
- Reading
block.jsonwon't tell you the attributes. - To see the real defaults, ask WordPress (see Reading the real defaults).
Grouped attributes
Settings are grouped: each inspector panel has one object, and its options live inside it. You'll find navigation.presetIcon, never a flat navPresetIcon.
Shared by all five blocks
| Attribute | Type | Holds |
|---|---|---|
uniqueId | string | Per-block ID that scopes the block's CSS. Must be unique on the page. |
logoSource | object | mode, patternId and items: the logos themselves (see below) |
imagesSettings | object | Logo Images settings: aspectRatio, resolution, lazyLoad, randomOrder, clickAction, allowSvgUploads, custom width and height |
logoImagesStyle | object | Logo Images style: hoverAnimation, margin, and normal / hover states (custom colour, image filter, opacity, overlay) |
displayElements | object | Display Elements: which of title, description and Read More show, their order, and styling |
tooltips | object | Tooltips |
ajaxFilter | object | Ajax Live Filter styling |
ajaxSearch | object | Ajax Search styling |
scheduling | object | Scheduling: enabled, startDate, endDate |
motionEffects | object | Motion Effects: entrance, scroll, sticky |
section | object | Block background, padding and margin |
visibility | object | hideOnDesktop, hideOnTablet, hideOnMobilePortrait, hideOnMobileLandscape |
advanced | object | cssClass, cssId |
patternDemo | boolean | True while the block still shows demo logos from a pattern or the AI builder |
isPreview | boolean | Used only for the inserter's preview image |
Per block
| Attribute | Blocks | Holds |
|---|---|---|
layout | all | Layouts. Its shape differs per block (see below) |
navigation | Carousel | Navigation Arrows |
pagination | Carousel | Pagination Dots |
gridPagination | Grid, List, Table | Pagination: paginationType (loadMore or number), logoShowPerClick, alignment, plus loadMore and number styling |
marqueeDisplayElements | Marquee | Separate Display Elements settings for the standard and ribbon styles |
tableTitles | Table | The header row: enabled, the three column labels, alignment, height and styling |
The layout object
layout holds a style key, a shared object for settings every style uses, and one object per style for settings each style remembers on its own. That's why switching a Carousel from Standard to Center and back restores your Standard columns.
| Block | Style key and values | Per-style objects |
|---|---|---|
| Carousel | carouselStyle: standard, center, staggered-carousel, multirow | standard, center, staggered, multirow |
| Grid | gridStyle: standard, strip, staggered, zigzag | standard, strip, staggered, zigzag |
| List | listStyle: left, center, right | left, center, right |
| Marquee | marqueeStyle: standard, wave, ribbon | standard, wave, ribbon |
| Table | (one style) | style holds the table lines and background |
Where a setting lives varies by block. On a Carousel, columns is per style (layout.standard.columns) while autoplay is shared (layout.shared.autoplay). On a Grid, columns sits in layout.shared. When in doubt, read what the editor saved.
Responsive values use one shape everywhere: a device map, plus a unit map when the value has units.
"gapBetweenLogos": {
"device": { "Desktop": 15, "Tablet": 15, "Mobile": 15 },
"unit": { "Desktop": "px", "Tablet": "px", "Mobile": "px" }
}Logos live in logoSource.items
Block logos are stored in the block, not in a post type. Each block has its own list in logoSource.items, and the images themselves are ordinary Media Library attachments. (The classic version's logo post type is separate; blocks don't read it.)
Each item looks like this:
| Key | Notes |
|---|---|
id | Any string unique within the block |
mediaId | The attachment ID. This is the main source of the image. |
imageUrl | Fallback image URL, used when there's no mediaId |
title | Up to 120 characters. Shown by Display Elements and tooltips. |
altText | Up to 125 characters |
url | The logo's link. Must start with http:// or https:// |
description | Up to 500 characters |
caption | Up to 200 characters. Comes from the attachment. |
categories | Array of plain category names (up to 20, 80 characters each). Used by the Ajax Live Filter. |
order | Position in the list, starting at 0 |
additionalInfo | File name, MIME type, size and dimensions, shown in the popup |
createdAt, updatedAt | ISO dates |
Categories are just names stored on each logo. There's no separate category list for blocks: a block's categories are whatever its logos carry.
Example block markup
A Carousel with three logos, five columns on desktop and autoplay off:
<!-- wp:sp-logo-carousel/carousel {"uniqueId":"lcpro-carousel-k3x9q2m7a","align":"wide","logoSource":{"mode":"","patternId":"","items":[{"id":"logo-1","mediaId":"101","title":"Northwind","altText":"Northwind logo","url":"https://northwind.example","categories":["Partners"],"order":0},{"id":"logo-2","mediaId":"102","title":"Contoso","altText":"Contoso logo","url":"","categories":["Clients"],"order":1},{"id":"logo-3","mediaId":"103","title":"Fabrikam","altText":"Fabrikam logo","url":"","categories":["Clients"],"order":2}]},"layout":{"carouselStyle":"standard","shared":{"autoplay":false},"standard":{"columns":{"device":{"Desktop":5,"Tablet":3,"Mobile":2}}}}} /-->A Grid with Load More pagination after eight logos:
<!-- wp:sp-logo-carousel/grid {"uniqueId":"lcpro-grid-p8d2w4n1c","logoSource":{"mode":"","patternId":"","items":[ … ]},"layout":{"gridStyle":"standard","shared":{"pagination":true}},"gridPagination":{"paginationType":"loadMore","logoShowPerClick":8}} /-->Generating blocks in PHP
$items = array();
foreach ( array( 101, 102, 103 ) as $index => $attachment_id ) {
$items[] = array(
'id' => 'logo-' . $attachment_id,
'mediaId' => (string) $attachment_id,
'title' => get_the_title( $attachment_id ),
'altText' => (string) get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ),
'order' => $index,
);
}
$attrs = array(
'uniqueId' => 'lcpro-carousel-' . strtolower( wp_generate_password( 9, false ) ),
'logoSource' => array(
'mode' => '',
'patternId' => '',
'items' => $items,
),
);
wp_insert_post( array(
'post_title' => 'Our clients',
'post_status' => 'draft',
'post_type' => 'page',
'post_content' => serialize_block( array(
'blockName' => 'sp-logo-carousel/carousel',
'attrs' => $attrs,
'innerBlocks' => array(),
'innerHTML' => '',
'innerContent' => array(),
) ),
) );Rules that save debugging time:
- Give every block its own
uniqueId. The block's CSS is scoped to it. Two blocks with the same ID on one page share styles. (The editor repairs duplicates when you open the page; generated content that's never opened won't be repaired.) - Leave out what you don't need. Attributes you don't send use their defaults.
- Copy a whole group rather than guessing keys. The surest way is to configure one block by hand, open the Code editor, and copy the group you need. Unknown keys are ignored, so a misspelt key fails silently.
- Use
mediaIdfor images. Images resolve from the attachment at render time, so a logo picks up the right size and survives a domain change.imageUrlalone works, but loses those benefits.
Reading the real defaults
Defaults shift between releases, so read them from your own install with WP-CLI:
wp eval '
$type = WP_Block_Type_Registry::get_instance()->get_registered( "sp-logo-carousel/grid" );
echo wp_json_encode( $type->attributes["layout"]["default"], JSON_PRETTY_PRINT );
'Swap the block name and the attribute key (imagesSettings, gridPagination, …) to explore.
Saved Templates are usually the better tool
If the goal is "the same logos in many places," build it once as a Saved Template and place [lc_template id="…"] wherever you need it. One place to update, and no attribute JSON to maintain.
Next steps
- Hooks: Actions and Filters: change behaviour with PHP.
- Template Overrides: change classic shortcode HTML.
- REST API and AJAX: the endpoints behind the editor.
- Saved Templates: the maintainable way to reuse a layout.