Rendering in PHP Templates
TableCrafter has no dedicated public PHP API — the supported way to render a table from a theme file is to pass its [tablecrafter] shortcode through WordPress core's do_shortcode(). This page documents that path end to end, using only the real shortcode tag, attributes, and markup the plugin emits.
When to render from PHP
Most users embed tables with the editor: the [tablecrafter] shortcode, the TableCrafter → Data Table Gutenberg block (registered as tablecrafter/data-table), or the Elementor widget. Render from PHP instead when the table lives in template logic the editor can't reach:
- A theme template part such as
single.php,page-pricing.php, a custom page template, or a block theme pattern's PHP fallback. - Inside a loop where the data
sourceURL is computed per-post (for example from a custom field). - Headers, footers, or sidebars rendered outside
the_content(), where shortcodes are not auto-expanded.
The Gutenberg block callback (render_block_callback()) and the Elementor widget both build a [tablecrafter ...] string and call do_shortcode() internally. Calling it yourself in PHP is the exact same code path — there is no separate or "lower-level" render function to call.
The core pattern
The shortcode callback render_table() is not part of a documented public class API, so do not call it directly. Always go through do_shortcode() so WordPress resolves the registered tablecrafter tag and the plugin's normalization, caching, and asset-enqueue logic all run:
echo do_shortcode( '[tablecrafter source="https://example.com/api/products.json"]' );
That single call:
- Validates
sourcewithesc_url_raw()and renders an empty-source placeholder if it is blank. - Checks the Stale-While-Revalidate transient (
tc_html_…) and, on a cold cache, fetches and renders the table server-side so the HTML is crawlable. - Enqueues the
tablecrafter-frontendscript andtablecrafter-stylestylesheet. - Returns a
<div class="tablecrafter-container" data-ssr="true">wrapper that the bundled JS hydrates into an interactive table.
Shortcode attribute reference
These are the only attributes the shortcode recognizes (from the shortcode_atts() defaults in render_table()). The data source attribute is source — there is no url attribute. Boolean attributes accept true, 1, or yes as true; anything else is false.
| Attribute | Type | Default | Description |
|---|---|---|---|
| source | Required | '' | URL to the JSON/CSV data source. Passed through esc_url_raw(). If empty, an admin placeholder is returned instead of a table. |
| id | Optional | tc-{uniqid} | DOM id for the container. Set a stable value if you need to target it from custom JS or CSS. |
| include | Optional | '' | Comma-separated list of columns to keep (allowlist). Omit to show all columns. |
| exclude | Optional | '' | Comma-separated list of columns to drop (denylist). |
| root | Optional | '' | Path to the array inside a nested JSON response (for example data.results) that holds the rows. |
| search | Optional | false | Enable the global search box. |
| filters | Optional | true | Enable per-column filters. This one defaults to on. |
| export | Optional | false | Show export controls (CSV, XLSX, PDF). |
| per_page | Optional | 0 | Rows per page. 0 disables pagination; any value > 0 enables it. |
| sort | Optional | '' | Initial sort as column:direction, e.g. price:desc. |
| auto_refresh | Optional | false | Periodically re-fetch the source in the browser. |
| refresh_interval | Optional | 300000 | Auto-refresh interval in milliseconds (default 5 minutes). |
| refresh_indicator | Optional | true | Show the live refresh indicator. |
| refresh_countdown | Optional | false | Show a countdown to the next refresh. |
| refresh_last_updated | Optional | true | Show the "last updated" timestamp. |
A complete template example
This renders a paginated, searchable, exportable product table from a per-post source URL. Because attribute values come from PHP, sanitize them and build the shortcode string with sprintf() rather than hand-concatenating untrusted input:
// In a custom page template or template part.
$source = esc_url_raw( get_post_meta( get_the_ID(), 'data_feed_url', true ) );
if ( $source ) {
$shortcode = sprintf(
'[tablecrafter source="%s" search="true" export="true" per_page="%d" sort="%s"]',
esc_attr( $source ),
25,
'name:asc'
);
// do_shortcode() output is already sanitized server-side; safe to echo.
echo do_shortcode( $shortcode );
}
Build the attribute string yourself — do not interpolate raw user input straight into the shortcode. The plugin escapes its own output, but a malformed source or unescaped quote in an attribute can break shortcode parsing. Pass URLs through esc_url_raw() and other values through esc_attr() first, as shown above.
What the markup looks like
The shortcode returns a single wrapper whose data-* attributes mirror the attributes you passed. On a warm cache it already contains the server-rendered .tc-table; on a cold first hit it ships a .tc-loading placeholder plus an inline JSON island the JS hydrates from:
<div id="tc-..." class="tablecrafter-container"
data-source="..." data-search="true" data-export="true"
data-per-page="25" data-sort="name:asc" data-ssr="true">
<!-- server-rendered .tc-table, or .tc-loading on cold cache -->
<script type="application/json" class="tc-initial-data">[...]</script>
</div>
Useful container and child classes you can target from your theme's CSS: .tablecrafter-container, .tc-table, .tc-table-container, .tc-global-search, .tc-filters, .tc-pagination, .tc-export-controls, .tc-loading, and .tc-error-state.
Asset loading in templates
You do not need to enqueue anything yourself. The shortcode calls register_assets() and enqueues the tablecrafter-frontend script (which depends on the tablecrafter-lib core library) and the tablecrafter-style stylesheet, then localizes the tablecrafterData JS object (with ajaxUrl, proxy nonce, and export nonces) for the proxy and export endpoints.
One caveat: WordPress enqueues happen during page rendering, so call do_shortcode() while the template is being output (inside the loop, header, footer, or a template part) — not from an early hook that fires before wp_enqueue_scripts. The bundled frontend.js auto-discovers every .tablecrafter-container on DOMContentLoaded and hydrates it, so multiple tables on one page each initialize independently.
Caching behavior to expect
The first PHP render of a given source fetches synchronously and stores both the HTML and parsed data in a transient (tc_html_…) keyed by source plus the display attributes, for one hour. Subsequent renders serve that cached HTML instantly; if the cached copy is older than five minutes, a background tc_refresh_single_source event is scheduled so the next visitor sees fresh data without a blocking fetch. Changing any of source, include, exclude, search, filters, export, per_page, or sort produces a different cache key, so variants never collide.
Equivalence with the block and Elementor widget
Whichever surface you choose resolves to the same shortcode. The Gutenberg block's render callback maps its attributes onto render_table(), and the Elementor widget assembles a [tablecrafter source="..."] string from its controls and runs it through do_shortcode(). That means the attribute names and behavior documented here are authoritative across all three integration methods — what you learn in PHP transfers directly to the editor surfaces.
Next, see shortcode-reference.html for the full attribute catalog with examples, and gutenberg-block.html for the no-code editor equivalent of these same options.