Kuroco's Smarty template plugin reference and Webhook/batch processing patterns.
Documentation Reference: /kuroco-docs You can search and reference the official Kuroco documentation using skills.
Table of Contents
Part 1: Smarty Plugin Reference
- Frequently Used Plugins
- Plugin types (functions, modifiers, blocks) → references/syntax.md
- Reference by Category
- Usage examples (list display, Slack notification, permission display, error handling, paging) → references/examples.md
- Smarty Syntax Reference - Basic syntax, control structures, built-in variables
Part 2: Webhook/Batch Processing Patterns
- Batch Processing
- Internal API Calls
- External System Integration Architecture Design → For more details, see references/integration-design.md
- External API Calls
- Trigger Processing
- Webhook (receiving endpoint, URL format) → references/integrations.md
- External Service Integration → For details, see references/integrations.md
Part 1: Smarty Plugin Reference
Complete reference of all plugins available in Kuroco's Smarty templates.
Frequently Used Plugins
Variable/Data Operations
| Plugin | Description | Example |
|---|---|---|
assign |
Variable assignment.var can be written with dot notation for nested arrays |
{assign var="request.status" value="pending"} |
append |
Array append. Use this when the key is a variable | {append var="arr" index=$key value="値"} |
json_decode |
JSON Parse | {$json|json_decode:true} |
rcms_json_encode |
JSON Encode | {$arr|@rcms_json_encode} |
API/Data Retrieval
| Plugin | Description | Example |
|---|---|---|
api_internal |
Internal API call | {api_internal endpoint='/rcms-api/1/news' var='result'} |
api_method |
Directly execute model operations without creating an endpoint (GET only) | {api_method var='result' model='Topics' method='list' ...} |
assign_tag_list |
Retrieve tag list | {assign_tag_list var='tags'} |
→ Details: references/api-plugins.md
String Processing
| Plugin | Description | Example |
|---|---|---|
escape |
Escape | {$html|escape} |
truncate |
String truncation | {$text|truncate:100:"..."} |
mb_truncate |
Multibyte support | {$text|mb_truncate:50} |
date_format |
Date format | {$date|date_format:"%Y-%m-%d"} |
translate |
Translation | {$key|translate} |
nl2br |
Convert newlines to BR | {$text|nl2br} |
replace |
String replacement | {$text|replace:"a":"b"} |
→ Details: references/string-plugins.md
Form/UI
| Plugin | Description | Example |
|---|---|---|
fileupload |
File Upload | {fileupload id="photo" hidden_nm="photo_url" url=$upload_url}{/fileupload} |
inquiry_input |
Form input | {inquiry_input col="name" ...} |
pager |
Pagination | {pager info=$pageInfo} |
→ Details: references/form-plugins.md
Authentication/Permissions
| Plugin | Description | Example |
|---|---|---|
rcms_auth |
Permission control block | {rcms_auth target="read:/topics/"}...{/rcms_auth} |
login |
Login processing | {login ...} |
logout |
Logout processing | {logout ...} |
→ Details: references/auth-plugins.md
External Service Integration
| Plugin | Description | Example |
|---|---|---|
sendmail |
Email sending | {sendmail to=$email subject="件名" contents="本文"} |
slack_post_message |
Slack notification | {slack_post_message channel="#general" text="..."} |
ai_completion |
AI call | {ai_completion var='result' message=$prompt model='gpt-4'} |
github_deploy |
GitHub Deploy | {github_deploy ...} |
→ Details: references/integration-plugins.md
File Operations
| Plugin | Description | Example |
|---|---|---|
write_file |
File writing | {write_file var="path" value="内容"} |
put_file |
Storage Upload | {put_file path="/files/..." tmp_path=$tmp} |
read_file |
Read file line by line (blocking) | {read_file name="log" path="/files/user/..." row="line"}{$line}{/read_file} |
read_dir |
Directory reading | {read_dir name="files" path="/files/user/..." file_var='file'}...{/read_dir} |
→ Details: references/file-plugins.md
Vue.js integration
| Plugin | Description | Example |
|---|---|---|
rcms_vue_component |
Vue Component | {rcms_vue_component config="rcms-mng" name="..."} |
head_include |
Add to head | {head_include file="..."} |
→ Details: references/vue-plugins.md
Reference by category
| Category | File | Main plugins |
|---|---|---|
| Syntax reference | syntax.md | Basic syntax, control structures, built-in variables, best practices |
| API・Data retrieval | api-plugins.md | api_internal, api_method, assign_tag_list |
| String processing | string-plugins.md | escape, truncate, date_format, translate |
| Array operations | array-plugins.md | count, in_array, implode, explode, sort family |
| Form/UI | form-plugins.md | fileupload, inquiry_input, pager, html_* |
| Authentication・Permissions | auth-plugins.md | rcms_auth, login, logout |
| External integration | integration-plugins.md | sendmail, slack_*, ai_completion |
| File operations | file-plugins.md | write_file, put_file, read_file, read_dir |
| Vue.js integration | vue-plugins.md | rcms_vue_component, head_include |
| All plugins | all-plugins.md | List of all 151 plugins |
Best practices for Webhooks, batch processing, and external integration in Kuroco HeadlessCMS.
About Smarty syntax: Batch processing and triggers are written in Smarty templates. For details on syntax and plugins, refer to Part 1 above.
Batch processing
Overview
Batch processing is processing that is automatically executed at fixed intervals.
Execution frequency options:
| Frequency | Use case |
|---|---|
| Every 15 minutes | When frequent synchronization is required |
| Every 30 minutes | Near real-time processing |
| Every hour | Regular aggregation and updates |
| Daily (specified time) | Daily reports, backups |
Execution limits for free-use users: For sites that have selected card payment and have no card registered,batch launches (registrations) are limited to 100 times per hour. The count is the number of batch launches, not the number of requests issued within the batch (external
{api}sending is counted separately at 1,000 times/hour). If a card is registered or payment is by invoice, there is no limit.The maximum execution time for one batch is 4 hours by default, and 6 hours for Smarty batches—exceeding this results in a timeout failure. Rather than trying to fit large amounts of data within this limit, split it into pages as described in "Timeout countermeasures" below to keep each run short.
Use Cases
- CSV generation and integration with external systems
- Data import from external systems
- Log aggregation and statistical data calculation
- Regular email delivery
- GitHub Actions integration (deploy trigger)
Creating batch processing
Admin panel: [Operations] → [Batch processing] → [Add]
| Item | Description | Example |
|---|---|---|
| Title | Batch name | CSV output batch |
| Identifier | Unique identifier (alphanumeric) | csv_export |
| Execution frequency | Execution interval | Daily 03:00 |
| Execution content | Written in Smarty syntax | See below |
Internal API calls
Basic syntax
{api_internal
endpoint='/rcms-api/1/news'
method='GET'
member_id=1
queries=$queries
var='response'
}
Retrieve content list
{assign var="queries" value=$dataSet.emptyArray}
{append var="queries" index="cnt" value=0}
{append var="queries" index="filter" value="topics_flg = 1"}
{api_internal
endpoint='/rcms-api/1/news'
method='GET'
member_id=1
queries=$queries
var='news_list'
}
{foreach from=$news_list.list item="news"}
ID: {$news.topics_id}, タイトル: {$news.subject}
{/foreach}
Create content
The POST request body is also queries Passed viabody There is no such parameter).
{assign var="body" value=$dataSet.emptyArray}
{append var="body" index="subject" value="タイトル"}
{append var="body" index="contents" value="本文"}
{append var="body" index="open_flg" value=1}
{api_internal
endpoint='/rcms-api/1/news/insert'
method='POST'
member_id=1
queries=$body
var='result'
}
Update (/update/{topics_id}) has the same form; put only the keys to change in queries . For extended fields, use the ext_slug name (if not set, the ext_1 / ext_col_01 format) as the key—check the key name and see bulk_upsert は /kuroco-api-content .
Designing integration methods for external systems
Before connecting to an external system, decide which of the 3 patterns to use (the selection criteria are the same as 0-4 in /kuroco-app-builder ).
| Pattern | Configuration | Suitable cases |
|---|---|---|
| Direct call | The frontend calls the external API directly. Kuroco is not involved | The external API allows CORS, the key can be placed in the frontend, real-time performance is the top priority |
| Proxy (via Kuroco) | From the Smarty template of the custom endpoint, {api} Call the external API with the plugin and return the result |
You want to hide the key, unify authentication/CORS/rate limiting on the Kuroco side, or process the response |
| Ingestion | Import external data into Topics/CSV tables in advance and provide it via the standard Topics API | The update frequency is low, and you want external data to also use Kuroco's standard features (search, cache, multilingual) |
Judgment criteria:
- Is it necessary to keep the key secret? → If yes, use a proxy or ingestion. Direct calls allow the key to be read from the frontend JS, so they cannot be used for private keys
- Is real-time performance required? → If required, use a proxy; if acceptable, use ingestion
- Do you want external data to also use Kuroco's standard features (search, categories, cache, multilingual)? → If yes, use ingestion
- Spider is not suitable for polling structured APIs(It is for crawling and ingesting web pages and files, and the crawl itself counts as billable requests). If you want to periodically fetch structured APIs, ingestion can also use batch processing +
{api}. - Sending notifications to external destinations (Slack / LINE / SMS / email) is outside the 3 patterns. You can either call an integration plugin from trigger processing or simply send to a trigger email address (→ External service integration)
If the other party has a REST API, {api} will rarely get stuck on "whether it can connect." The focus of the design is (1) where to place secrets ({secret}) と (2) token lifecycle management Place it in. Things to confirm after choosing—{api} restrictions (1 file per call, default timeout 30 seconds / maximum 3600 seconds. Custom endpoints themselves are cut off at 30 seconds), the suitability/unsuitability of batch / spider / Webhook, whether to obtain OAuth tokens each time (JIT) or store them in protected Topics records, practical pitfalls such as Instagram long-lived tokens expiring in 60 days, and design deliverable templates—are references/integration-design.md summarized in. Once you choose proxy / ingestion, read this before implementation (if you only need the syntax, you may proceed to the next section). For how to write returning results to the frontend via proxy, see Returning from a proxy endpoint。
External API calls
For external API calls, use the {api} plugin ({api_internal}is a different plugin that calls Kuroco's own API, so do not confuse them.api_requestThere is no plugin with that name).
Basic syntax
{api
endpoint='https://api.example.com/endpoint'
method='GET'
headers=$headers
var='response'
status_var='status'
}
POST request example (JSON)
headersは'Key: value'format strings in an array. Pass the JSON body tojson_body.
{secret var='api_key' key='EXAMPLE_API_KEY'}
{assign_array var=headers values=""}
{append var=headers value='Content-Type: application/json'}
{append var=headers value="Authorization: Bearer `$api_key`"}
{assign_array var=body values=""}
{append var=body index='message' value='Hello'}
{api
endpoint='https://api.example.com/post'
method='POST'
headers=$headers
json_body=$body|@json_encode
json_var='response'
status_var='status'
}
When sending non-JSON (e.g. CSV)
bodyattribute. Even for non-JSON content, in order to escape multibyte characters, you need to pass it through|@json_encode. Specify the Content-Type header explicitly in thetext/***format.
{assign_array var=headers values=""}
{append var=headers value='Content-Type: text/csv'}
{assign var=csv value="ID,NAME,PRICE\n1,apple,150\n2,orange,200"}
{api
endpoint='https://api.example.com/upload'
method='PUT'
headers=$headers
body=$csv|@json_encode
var='response'
status_var='status'
}
Main parameters
| Parameters | Description |
|---|---|
endpoint |
Destination URL (required) |
query / queries |
Query string / query parameter array (may also be written directly in the URL) |
method |
GET/POST/PUT/PATCH/DELETE/PURGE/HEAD |
headers |
'Key: value'format string array |
json_body / body |
JSON / non-JSON request body |
files |
File to send.Only 1 file can be sent per call(the second and subsequent items in the array are ignored) |
var / json_var |
Response storage variable.For APIs that return JSON, use json_var (you can receive it as a decoded array.(var is the raw string) |
status_var |
Success/failure (0/1) |
http_code_var / resp_header_var |
Storage variables for HTTP status code / response headers |
timeout |
Timeout in seconds.Default 30, specifiable from 1 to 3600(out of range is an error). For slow external APIs, either extend it explicitly or switch to ingestion (batch). |
cache_time |
Cache time (minutes). Reduces round trips to the counterpart API. This has a different purpose from caching on the Kuroco side endpoint (which reduces Kuroco API request billing), and they can be used together. |
sslcert / sslkey / cainfo |
Certificate, key, and CA information for mTLS. The value isthe secret key name, not the certificate itself |
Values that should be kept secret, such as external API keys, should be read via the **{secret}plugin** (registered in advance from [Environment Settings] → [Secrets]).$smarty.const.*(site constants) are for non-secret configuration values, and should not be used for confidential information such as API keys.
{secret var='api_key' key='EXAMPLE_API_KEY'}
{assign_array var=headers values=""}
{append var=headers value="Authorization: Bearer `$api_key`"}
{api
endpoint='https://api.example.com/endpoint'
headers=$headers
var='response'
}
Proxy endpoint response (custom processing)
request_api / request_api_post By default, the custom endpoint forThe data returns the variable {"data": …} in the form。PHP execution time for 1 request is 30 secondsassigned in the template (the API entry's set_time_limit(30)), so in the proxy {api} When calling timeout set it to less than 30 (e.g. 10)—if left at the default 30 seconds, the endpoint side will be cut off first while waiting externally. To return JSON in any form as-is, enable show_contents in the endpoint settings, and the template outputs a JSON string (if the output is empty, [], and if the JSON is invalid, Contents JSON error). The request parameters are $smarty.request.*(common to GET/POST) or $smarty.post.* and validate before embedding it in an external URL.
{assign var=city value=$smarty.request.city|default:"tokyo"}
{secret var='weather_key' key='WEATHER_API_KEY'}
{assign_array var=headers values=""}
{append var=headers value="X-Api-Key: `$weather_key`"}
{api
endpoint="https://api.weather.example/today?city=`$city`"
method='GET'
headers=$headers
json_var='forecast'
status_var='ok'
timeout=10
cache_time=30
}
{if $ok == 1}
{assign var='data' value=$forecast}
{else}
{logger msg1="weather-proxy-error" msg2="city=`$city`"}
{assign_array var=err values=""}
{append var=err index='error' value='weather_unavailable'}
{assign var='data' value=$err}
{/if}
{* 既定はこれで {"data": …} が返る。show_contents を有効にした場合は代わりに {$data|@rcms_json_encode} を出力する *}
Trigger processing
Trigger on content update
Admin screen: [Content definition] → [Trigger settings]
Available events:
| Event | Timing |
|---|---|
| On create | After content creation |
| On update | After content update |
| On delete | After content deletion |
| On publish | When publication status changes |
| After preview site submission | After the submission process to the preview site (stage site) is complete |
Available variables:
{$topics.topics_id} {* コンテンツID *}
{$topics.subject} {* タイトル *}
{$topics.contents} {* 本文 *}
{$topics.ymd} {* 公開日 *}
{$topics.ext_col_01} {* 拡張項目 *}
Trigger on form submission
Admin screen: [Form] → [Trigger settings]
{$inquiry.inquiry_id} {* 回答ID *}
{$inquiry.name} {* 名前 *}
{$inquiry.email} {* メールアドレス *}
{$inquiry.message} {* メッセージ *}
External service integration
Detailed integration patterns: references/integrations.md(GitHub Actions / Slack / Chatwork / Email / SendGrid / Webhook / custom processing). LINE, SMS, and X only have trigger email addresses, and there is no additional information in references
Trigger email address (integration triggered by email sending)
By specifying a dedicated address as the email recipient, you can trigger sending to external services, batch processing, or starting AI agents upon email sending. The triggering email may be the {sendmail}of trigger processing, the recipient of a form's auto-reply or admin notification email, or a newsletter—first consider recipient settings that avoid writing code。
Prerequisites: Each recipient requires the integration settings for the target channel to be enabled (For LINE, the trigger email address is displayed in [Channel]→[Messaging]→[LINE]. For Slack, Slack integration in site settings). The local part (before @) is Slack=channel ID or #channel name, LINE=the destination LINE user ID (obtained via the official account's friend-add Webhook or LINE Login (OAuth SSO) and saved to the member—kuroco-docs LINE integration tutorial), SMS=phone number. Only the text of the email body can be sent (For LINE, [emoji:…] notation emoji are also allowed).
| Destination address | Action |
|---|---|
{channel}@slack.r-cms.jp |
Slack send |
{twitter_id}@tweets.twitter.r-cms.jp |
X (Twitter) post |
{batch_id}@batch.r-cms.jp |
Batch processing startup |
{ai_agent_id}@agent.r-cms.jp |
AI agent startup |
{LINE ID}@text.line.r-cms.jp |
LINE sending |
{tel}@twilio.r-cms.jp |
Text message (SMS) sending (Twilio) |
Slack notification
The plugin name is slack_post_message(slack_send plugin does not exist). Instead of a webhook URL, use the site settings' Slack integration (slack_bot_token).
{slack_post_message
channel="#general"
text="通知メッセージ"
}
Email notification
The parameter name in the body is contents(body ).
{sendmail
to="recipient@example.com"
subject="件名"
contents="本文"
}
GitHub Actions integration
{secret var='github_token' key='GITHUB_TOKEN'}
{assign_array var=headers values=""}
{append var=headers value="Authorization: token `$github_token`"}
{append var=headers value='Accept: application/vnd.github.v3+json'}
{assign_array var=body values=""}
{append var=body index='event_type' value='kuroco-update'}
{api
endpoint='https://api.github.com/repos/owner/repo/dispatches'
method='POST'
headers=$headers
json_body=$body|@json_encode
var='response'
status_var='status'
}
Best Practices
- Execution time: Set it to a time slot with low system load (late night/early morning), and process large amounts of data once a day with paging (
{while}Example of looping through pages: references/examples.md) - Error Handling:
errorsTo avoid|@count > 0even when empty, check with{logger}(msg1〜msg4, each within 1KB) andslack_post_messageto notify (example: references/examples.md) - There is no tag for early termination. To "do not execute the rest" on failure, express it by enclosing the write part in
{if $status == 1}…{/if}(orerrors|@count == 0) - Dynamic endpoint pathis interpolated with backticks.
{id}If you write curly braces like the following as-is, they will be interpreted as Smarty tags - Shortened assignment
{$var = ...}does not exist. Arguments following a variable tag are not read by the compiler and are discarded, so the save and execution succeed but only the assignment disappears. Use{assign}か{append}to write values (references/syntax.md)
{api_internal endpoint="/rcms-api/3/product/update/`$row.topics_id`" method='POST' member_id=1 queries=$body var='res' status_var='ok'}
Related skills
/kuroco-api-content- API design, authentication patterns, content CRUD operations/kuroco-admin-mcp- Management operations via Admin MCP
Related documents
../kuroco-docs/docs/tutorials-api-custom-1.md(how-to-use-batch) - How to use batch processing../kuroco-docs/docs/tutorials-content-1.md(auto-run-github-with-contents-update) - GitHub Actions integration../kuroco-docs/docs/tutorials-form-mail-1.md(send-slack-notification-after-a-form-has-been-submitted) - Slack notification../kuroco-docs/docs/reference-smarty-trigger-3.md(trigger-variables) - Trigger variables