The Feed File
Define activity headlines, icons, and group headlines in routes/feed.php. The installer creates this file.
Basic Definitions
Defining a Headline
A headline describes an activity using a template:
use App\Models\Order;
use Storyfeed\Facades\Story;
Story::for(Order::class)
->verb('place')
->headline(':actor placed :object with :target');The for method specifies the object type, and the verb method specifies the recorded verb. This headline applies to place activities involving an order.
Headline Templates
Role Tokens
| Token | Entity |
|---|---|
:actor | who performed the action |
:object | the entity acted on |
:target | the entity the action was directed at |
:context | the containing entity |
:origin | the source |
:result | the entity produced |
:instrument | the tool or service used |
Each token is replaced with the entity's label and linked when it has a URL.
Optional Segments
Enclose an optional phrase in square brackets to include it only when its referenced roles are filled:
use App\Models\Order;
use Storyfeed\Facades\Story;
Story::for(Order::class)
->verb('place')
->headline(':actor placed :object[ with :target]');Storyfeed resolves optional segments before returning the payload. In this example, it includes with :target only when the activity has a target. Without brackets, an empty role leaves its token in the template.
Dynamic Headlines
To choose a headline for each activity, pass a closure that returns a template:
use App\Models\Order;
use Storyfeed\Facades\Story;
use Storyfeed\ActivityContext;
Story::for(Order::class)
->verb('place')
->headline(
fn (ActivityContext $activity) => $activity->boolean('rush')
? ':actor rushed :object to :target'
: ':actor placed :object with :target',
);The closure receives an ActivityContext, which provides typed helpers for the activity’s data and accessors for its roles. It runs when Storyfeed retrieves the feed. Returned role tokens are rendered as entity labels and links. Text without role tokens is displayed unchanged.
Icons and Intents
use App\Models\Order;
use Storyfeed\Facades\Story;
Story::for(Order::class)
->verb('place')
->headline(':actor placed :object with :target')
->icon('shopping-bag');
Story::for(Order::class)
->verb('complete')
->headline(':actor completed :object')
->icon('receipt');Use the intent method to assign an application-defined value, such as success or danger. Storyfeed returns it in the glyph_intent field:
use App\Models\Order;
use Storyfeed\Facades\Story;
Story::for(Order::class)->verb('complete')->icon('receipt')->intent('success');[
{
"kind": "activity",
"id": "a-complete",
"verb": "complete",
"published_at": "1985-07-02T12:08:00.000000Z",
"headline_template": ":actor completed :object",
"headline": null,
"glyph": "receipt",
"glyph_intent": "success",
"actor": {
"type": "user",
"id": "101",
"label": "Steve Harrington",
"url": "/users/101",
"attributes": {},
"modal": false,
"data": {},
"media": null,
"body": null,
"tombstone": null
},
"object": {
"type": "order",
"id": "1035",
"label": "Order #1035",
"url": "/orders/1035",
"attributes": {},
"modal": false,
"data": {},
"media": null,
"body": null,
"tombstone": null
},
"target": {
"type": "venue",
"id": "101",
"label": "Scoops Ahoy",
"url": "/venues/scoops",
"attributes": {},
"modal": false,
"data": {},
"media": {
"icon": null,
"image": null,
"files": [],
"preview": {
"src": "/media/worlds/stranger-things/parlour.jpg",
"mediaType": "image/jpeg",
"width": 960,
"height": 720,
"alt": "An ice cream counter"
},
"url": null
},
"body": [
{
"$body": "Storyfeed/Body/Image",
"$v": 1,
"caption": "Scoops Ahoy",
"alt": "Scoops Ahoy",
"width": null,
"height": null,
"image": "preview"
}
],
"tombstone": null
},
"context": null,
"origin": null,
"result": null,
"instrument": null,
"data": {},
"tombstoned": [],
"redundant": false,
"missing_headline_template": null,
"missing_headline": null
}
]See Rendering to display the icon and apply its intent.
Definition Groups
use App\Models\Order;
use Storyfeed\Facades\Story;
Story::for(Order::class)->group(function () {
Story::verb('place')->headline(':actor placed :object with :target');
Story::verb('complete')->headline(':actor completed :object');
});All verb definitions inside the closure apply to orders.
Resource Definitions
The resource method on the Story facade defines create, update, delete, and restore for a model:
use App\Models\Order;
use Storyfeed\Facades\Story;
Story::resource(Order::class);| Verb | Headline | Icon |
|---|---|---|
create | :actor created :object | plus |
update | :actor updated :object | pencil |
delete | :actor deleted :object | trash |
restore | :actor restored :object | rotate-ccw |
Use the only or except methods to select resource verbs. Exclude a verb before defining it separately:
use App\Models\Order;
use Storyfeed\Facades\Story;
Story::resource(Order::class)->except('update');
Story::for(Order::class)->verb('update')->headline(':actor changed :object');Defining the same verb in both places causes an error with both source locations.
Definition Precedence
Storyfeed applies definitions in this order, from most to least specific:
| Declaration | Matches |
|---|---|
Story::for(Order::class)->verb('place') | that verb on that object type |
Story::for(Order::class)->fallback() | every verb on that object type |
Story::verb('place') | that verb on any object type |
Story::fallback() | everything with no more specific entry |
This precedence applies to both headlines and intents. Use a fallback to define a headline for order verbs without their own definition:
use App\Models\Order;
use Storyfeed\Facades\Story;
Story::for(Order::class)->fallback()->headline(':actor updated :object');You may also define group headlines and headlines for deleted models.
Listing Definitions
List the definitions loaded by your application:
php artisan storyfeed:listUse --type=order or --verb=place to filter definitions, and --json for JSON output. Each entry includes the headline, icon, and declaration location. See Commands for all options.
Caching Definitions
Cache definitions during deployment:
php artisan storyfeed:cacheStoryfeed loads cached definitions without evaluating routes/feed.php. The optimize Artisan command also caches these definitions. Rebuild the cache after changing them. To clear it:
php artisan storyfeed:clearStoryfeed serializes closure headlines into the cache. If a closure cannot be serialized, the command fails and reports its source location. See Commands.