contao/news-bundle
Adds full news management to the Contao CMS: create and organize news archives and items, publish and list news on your site, and integrate news features into a professional, easy-to-maintain Contao installation.
Install Contao Core First:
Since news-bundle is Contao-specific, install Contao as a dependency:
composer require contao/core-bundle
Run Contao’s installation:
php bin/contao-console contao:install
Add the News Bundle:
composer require contao/news-bundle
Enable it in config/bundles.php:
Contao\NewsBundle\ContaoNewsBundle::class => ['all' => true],
Database Setup: Update Contao’s database via:
php bin/contao-console contao:database:update
Or manually run the tl_news migration (if extracted).
First Use Case: Display News in Laravel Blade
Create a Blade template (resources/views/news/list.blade.php):
@foreach(\Contao\NewsBundle\Model\NewsModel::findPublishedByArchive($archiveId) as $news)
<article>
<h2>{{ $news->headline }}</h2>
<p>{{ Str::limit($news->teaser, 200) }}</p>
<a href="{{ route('news.show', $news->id) }}">Read More</a>
</article>
@endforeach
Route News in Laravel:
Define routes in routes/web.php:
Route::get('/news/{id}', [\App\Http\Controllers\NewsController::class, 'show'])
->name('news.show');
Editorial Workflow:
/contao/backend/modules/News).start/stop dates in tl_news.tl_news_archive).softDeletes.Laravel-Centric Integration:
// app/Services/NewsService.php
class NewsService {
public function getFeaturedNews(int $limit = 3) {
return \Contao\NewsBundle\Model\NewsModel::findPublishedByArchive(1)
->limit($limit)
->orderBy('date desc');
}
}
// app/Http/Resources/NewsResource.php
public function toArray($request, News $news) {
return [
'title' => $news->headline,
'slug' => $news->alias,
'excerpt' => $news->teaser,
];
}
Frontend Patterns:
@newsList($archiveId, ['limit' => 5, 'showTeaser' => true])
$news = \Contao\NewsBundle\Model\NewsModel::findByPk($id);
if (auth()->check() && auth()->user()->can('view_premium_news')) {
$news = NewsModel::findPublishedByArchive(2); // Premium archive
}
meta package with Contao’s SEO fields:
use Spatie\Meta\Tags;
Tags::title($news->headline)
->description($news->metaDescription ?? $news->teaser);
spatie/laravel-medialibrary alongside Contao’s file uploads:
$news->addMedia(storage_path('app/public/uploads/' . $news->singleSRC))
->usingCollection('news_images');
Doctrine 1.x vs. Eloquent:
NewsModel uses Doctrine 1.x, which lacks Laravel’s Eloquent features (e.g., relationships, accessors).class LaravelNews extends Model {
public static function findPublished() {
return NewsModel::findPublished()->getArray();
}
}
Routing Conflicts:
/news/[id]) may clash with Laravel’s.Route::prefix('contao')->group(function () {
// Contao routes
});
Templating Quirks:
$this->News).@php
$news = \Contao\NewsBundle\Model\NewsModel::findByPk($id);
@endphp
<h1>{{ $news->headline }}</h1>
Database Locking:
tl_news uses serialized fields (e.g., jumpTo), which break in Laravel.json columns or normalize data:
Schema::table('tl_news', function (Blueprint $table) {
$table->json('jumpTo')->default('[]');
});
TL_DEBUG in config/autoload.php:
'debug' => true,
'tl_debug' => true,
\Doctrine\DBAL\Logging\EchoSQLLogger::enable();
dca/tl_news.php. Override them in config/dca.php:
$GLOBALS['TL_DCA']['tl_news']['fields']['customField'] = [
'label' => ['tl_news_customField', 'label'],
'inputType' => 'text',
];
Custom Fields: Add fields via DCA:
$GLOBALS['TL_DCA']['tl_news']['fields']['author'] = [
'label' => ['tl_news_author', 'label'],
'inputType' => 'text',
];
Then access in Laravel:
$news->author;
Hooks: Use Contao’s hooks to extend functionality:
// app/Providers/ContaoServiceProvider.php
public function boot() {
\Contao\CoreBundle\ContaoCoreBundle::getContainer()
->get('hook')->attach('getNewsItem', function ($item) {
$item->customField = 'value';
return $item;
});
}
Event Listeners:
Listen to Contao events (e.g., insert, delete) via Laravel’s events:
// app/Providers/EventServiceProvider.php
protected $listen = [
'contao.news.insert' => [NewsListener::class, 'handleInsert'],
];
API Layer: Expose news via Laravel’s API:
Route::get('/api/news', function () {
return \Contao\NewsBundle\Model\NewsModel::findPublished()->toArray();
});
NewsModel may load related data (e.g., tl_news_archive) inefficiently.
Fix: Use Laravel’s with():
$news = NewsModel::findPublished()->with('archive')->get();
$news = Cache::remember("news_{$archiveId}", now()->addHours(1), function () use ($archiveId) {
return NewsModel::findPublishedByArchive($archiveId);
});
How can I help you explore Laravel packages today?