It took me quite a while to understand that in order to add action to statamic field, you have to read extending the control panel first. Yes read docs. Did you manage to add your first field action ? for myself I will document here the hards steps that took me to a great feature that allows duplicating an existing replicator block content to a new entry, in the context of using a page builder based on replicator fieldset. The page builder itself -and its frontend templates - initially comes from the blogo starter kit, which is quickly extended with my own sets.
Some issues left
I tested this duplicator action guy with a few content types and it works fine, I have identified a few possible evolution paths
- duplicator bugs on images, saves an extra string in the asset field, for the moment I remove them manually in the md file
- would like to duplicate the set to any possible entry type, including to a global set
- might have issues with duplicates unique id ??
the principle : field action for replicator sets, linked to php controller
Field action javascript : wave-field-actions.js
Statamic.$fieldActions.add('replicator-fieldtype-set', {
title: 'WAVE Generate Content',
confirm: {
fields: {
name: {
type: "text",
display: 'Name',
instructions: 'Enter your new page title',
validate: ['required', 'min:2']
}
}
},
// visible: ({ config }) => config.handle === 'text_block',
run: async ({ values, confirmation}) => {
console.log(values)
try {
const response = Statamic.$request.post('/wave-api/entries', {
collection: 'pages',
title: confirmation.values.name,
content: values
});
Statamic.$toast.success('Entry created successfully');
} catch (error) {
console.error('Error creating entry:', error);
Statamic.$toast.error('Failed to create entry');
}
}
});
as you can see in the code above, the result of the action is to post the data to a controller I've created, accessible by the web route :
Route::post('/wave-api/entries', [WaveController::class, 'store'])->middleware(['web']);
The controller that creates the new entry
use Illuminate\Http\Request;
use Statamic\Facades\Entry;
class WaveController extends Controller
{
public function store(Request $request)
{
$mappedContent = $request->content;
// $mappedContent["_id"] = Str::uuid()->toString();;
$entry = Entry::make()
->collection($request->collection)
->blueprint('page')
->data([
'title' => $request->title,
"blocks"=>[$mappedContent]
]);
print_r($mappedContent);
$entry->save();
return response()->json(['success' => true]);
}
}
Going further with duplicate to existing entry
here is a new version of the field action with a new confirmation field : select an entry and the block will be duplicated to that entry
Statamic.$fieldActions.add('replicator-fieldtype-set', {
title: 'WAVE Duplicate Content',
confirm: {
text: 'Duplicate this content to new page or existing page',
fields: {
name: {
type: "text",
display: 'Name',
instructions: 'Enter your new page title',
validate: [ 'min:2']
},
target_page: {
type: "entries",
display: 'OR Select Target Page',
instructions: 'Choose an existing page to update',
max_items: 1,
collections: ['pages']
}
}
},
// visible: ({ config }) => config.handle === 'text_block',
run: async ({ values, confirmation}) => {
// console.log(values)
try {
// alert (confirmation.values.target_page)
const response = Statamic.$request.post('/wave-api/entries', {
collection: 'pages',
title: confirmation.values.name,
target_page:confirmation.values.target_page,
content: values
});
if (confirmation.values.target_page.length==1)
Statamic.$toast.success('Entry updated successfully');
else
Statamic.$toast.success('Entry created successfully');
} catch (error) {
console.error('Error creating entry:', error);
Statamic.$toast.error('Failed to create entry');
}
}
});
//https://jacksleight.dev/posts/adding-actions-to-specific-statamic-fields
//https://maciekpalmowski.dev/blog/field-actions-in-statamic-are-amazing/
the controller side :
<?php
// app/Http/Controllers/EntryController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Statamic\Facades\Entry;
class WaveController extends Controller
{
public function store(Request $request)
{
$mappedContent = $request->content;
// $mappedContent["_id"] = Str::uuid()->toString();;
if ($request->target_page)
{
$selectedPageId = $request->target_page[0];
$entry = Entry::find($selectedPageId);
if (!$entry) {
return response()->json(['success' => false, 'message' => 'Entry not found'], 404);
}
$currentBlocks = $entry->get('blocks') ?? [];
// Add new block to existing blocks
$newBlocks = array_merge($currentBlocks, [$mappedContent]);
// Update the entry
$entry->set('blocks' , $newBlocks);
$entry->save();
}
else {
$entry = Entry::make()
->collection($request->collection)
->blueprint('page')
->data([
'title' => $request->title,
"blocks" => [$mappedContent]
]);
$entry->save();
}
return response()->json(['success' => true]);
}
}