PHP SDK

Publino-Blog in PHP — sauber & SEO-stark

Ob pures PHP, WordPress oder Laravel: Mit composer require binden Sie Publino-Inhalte in jedes Projekt ein. Zero runtime dependencies, PHP 8.2+.

config/publino.php
<?php
// config/publino.php
require_once __DIR__ . '/vendor/autoload.php';

use Publino\Sdk\PublinoClient;

// Named Arguments (PHP 8.2) machen die Konfiguration selbsterklärend.
$publino = new PublinoClient(
    baseUrl: 'https://api.publino.de',
    siteId:  getenv('PUBLINO_SITE_ID'),
    apiKey:  getenv('PUBLINO_API_KEY'),
);
Schritt 1 · Installation

Per Composer installieren

Den API-Key erzeugen Sie im Dashboard unter API & MCP → Delivery Keys. Nutzen Sie den Secret Key (pub_live_…) ausschließlich serverseitig — in PHP ist das automatisch der Fall.

Voraussetzung: PHP 8.2 oder höher mit ext-curl und ext-json. Ein eigener Transport lässt sich über das Transport-Interface einsetzen.
Terminal
# Composer (PHP 8.2+)
composer require publino/sdk

# Zero-Runtime-Dependencies. Benötigt nur ext-curl und ext-json
# (beide in jeder Standard-PHP-Installation enthalten).
.env
# .env  —  Secret Key nur serverseitig verwenden
PUBLINO_API_KEY=pub_live_xxxxxxxxxxxxxxxx
PUBLINO_SITE_ID=mein-blog
Schritt 2 · Client

Client zentral konfigurieren

Legen Sie den Client einmal an und binden Sie ihn überall ein. Die Keys kommen aus Umgebungsvariablen — niemals hartcodiert ins Repository. baseUrl ist standardmäßig https://api.publino.de.

config/publino.php
<?php
// config/publino.php
require_once __DIR__ . '/vendor/autoload.php';

use Publino\Sdk\PublinoClient;

// Named Arguments (PHP 8.2) machen die Konfiguration selbsterklärend.
$publino = new PublinoClient(
    baseUrl: 'https://api.publino.de',
    siteId:  getenv('PUBLINO_SITE_ID'),
    apiKey:  getenv('PUBLINO_API_KEY'),
);
Schritt 3 · Übersicht

Die Blog-Übersicht bauen

$publino->articles('de') gibt ein Array typisierter ArticleSummary-Objekte zurück. Zugriff über Eigenschaften ($a->title); beim Ausgeben immer htmlspecialchars() nutzen.

blog.php
<?php
// blog.php  —  Übersicht aller Artikel
require __DIR__ . '/config/publino.php';

// articles() gibt ein Array von ArticleSummary-Objekten zurück (neueste zuerst).
$articles = $publino->articles('de');
?>
<!doctype html>
<html lang="de">
<head><meta charset="utf-8"><title>Blog</title></head>
<body>
  <h1>Blog</h1>
  <div class="grid">
    <?php foreach ($articles as $a): ?>
      <a href="/blog/<?= $a->slug ?>-<?= $a->id ?>" class="card">
        <h2><?= htmlspecialchars($a->title) ?></h2>
        <?php if ($a->excerpt): ?>
          <p><?= htmlspecialchars($a->excerpt) ?></p>
        <?php endif; ?>
        <small><?= $a->readingMinutes ?> Min. Lesezeit</small>
      </a>
    <?php endforeach; ?>
  </div>
</body>
</html>
Schritt 4 · SEO

Einzelartikel mit perfektem SEO

$publino->article($ref, 'de') liefert ein Article-Objekt (oder null bei 404) — inklusive metaDescription, canonicalUrl, fertigem jsonLd und sauberem html. Den Body geben Sie bewusst ungefiltert aus.

artikel.php
<?php
// artikel.php  —  Einzelartikel mit perfektem SEO
require __DIR__ . '/config/publino.php';

// Referenz aus der URL: "{slug}-{publicId}" oder die bloße Public-ID.
$ref     = $_GET['ref'] ?? '';
$article = $publino->article($ref, 'de'); // ?Article  (null = nicht gefunden)

if ($article === null) {
    http_response_code(404);
    exit('Artikel nicht gefunden');
}

$desc      = $article->metaDescription ?? $article->excerpt ?? '';
$canonical = $article->canonicalUrl ?? "https://example.com/blog/$ref";
?>
<!doctype html>
<html lang="de">
<head>
  <meta charset="utf-8">
  <title><?= htmlspecialchars($article->title) ?></title>

  <!-- 1. Meta-Description & Canonical -->
  <meta name="description" content="<?= htmlspecialchars($desc) ?>">
  <link rel="canonical" href="<?= htmlspecialchars($canonical) ?>">

  <!-- 2. Open Graph -->
  <meta property="og:type" content="article">
  <meta property="og:title" content="<?= htmlspecialchars($article->title) ?>">
  <meta property="og:description" content="<?= htmlspecialchars($desc) ?>">

  <!-- 3. Schema.org JSON-LD fertig von Publino mitgeliefert -->
  <?php if ($article->jsonLd !== null): ?>
    <script type="application/ld+json">
      <?= json_encode($article->jsonLd, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?>
    </script>
  <?php endif; ?>
</head>
<body>
  <article>
    <h1><?= htmlspecialchars($article->title) ?></h1>
    <p><small><?= $article->readingMinutes ?> Min. Lesezeit</small></p>

    <!-- 4. Body: server-gerendertes, bereinigtes HTML aus Publino -->
    <?= $article->html ?>
  </article>
</body>
</html>
Integration · WordPress

Als WordPress-Shortcode

Publino-Inhalte direkt in WordPress — ohne den Editor zu wechseln. Der Shortcode [publino_blog] rendert die Liste, ein WordPress-Transient cached die Antwort.

functions.php
<?php
/**
 * Publino-Blog als Shortcode  ->  [publino_blog]
 * functions.php oder eigenes Plugin
 */
require_once get_stylesheet_directory() . '/vendor/autoload.php';

use Publino\Sdk\PublinoClient;

function publino_client(): PublinoClient {
    return new PublinoClient(
        baseUrl: 'https://api.publino.de',
        siteId:  'mein-blog',
        apiKey:  getenv('PUBLINO_API_KEY'),
    );
}

add_shortcode('publino_blog', function () {
    // WordPress-Transient als Cache (15 Minuten) — spart API-Calls.
    $articles = get_transient('publino_articles');
    if ($articles === false) {
        $articles = publino_client()->articles('de');
        set_transient('publino_articles', $articles, 15 * MINUTE_IN_SECONDS);
    }

    ob_start();
    foreach ($articles as $a) {
        printf(
            '<article><a href="/blog/%s-%s"><h2>%s</h2></a><p>%s</p></article>',
            esc_attr($a->slug),
            esc_attr($a->id),
            esc_html($a->title),
            esc_html($a->excerpt ?? '')
        );
    }
    return ob_get_clean();
});
Integration · Laravel

Controller & Blade-View

Sauber getrennt nach MVC: Der Controller lädt die Daten (mit Laravel-Cache), die Blade-View kümmert sich um Markup und SEO-Head.

BlogController.php
<?php
// app/Http/Controllers/BlogController.php
namespace App\Http\Controllers;

use Illuminate\Support\Facades\Cache;
use Publino\Sdk\PublinoClient;

class BlogController extends Controller
{
    private function publino(): PublinoClient
    {
        return new PublinoClient(
            baseUrl: 'https://api.publino.de',
            siteId:  config('services.publino.site'),
            apiKey:  config('services.publino.key'),
        );
    }

    public function index()
    {
        // 10 Minuten cachen über Laravels Cache-Layer.
        $articles = Cache::remember('publino.articles', 600, fn () =>
            $this->publino()->articles('de')
        );

        return view('blog.index', compact('articles'));
    }

    public function show(string $ref)
    {
        $article = $this->publino()->article($ref, 'de');
        abort_if($article === null, 404);

        return view('blog.show', compact('article'));
    }
}
blog/show.blade.php
{{-- resources/views/blog/show.blade.php --}}
@section('head')
  <title>{{ $article->title }}</title>
  <meta name="description" content="{{ $article->metaDescription ?? '' }}">
  <link rel="canonical" href="{{ $article->canonicalUrl }}">
  @if ($article->jsonLd !== null)
    <script type="application/ld+json">
      {!! json_encode($article->jsonLd, JSON_UNESCAPED_SLASHES) !!}
    </script>
  @endif
@endsection

<article class="prose">
  <h1>{{ $article->title }}</h1>
  {{-- HTML aus Publino bewusst ungefiltert ausgeben --}}
  {!! $article->html !!}
</article>
Schritt 5 · Performance

Cachen & per Webhook invalidieren

Cachen Sie Antworten (Transient/Cache) und löschen Sie den Cache gezielt, sobald Publino einen Webhook sendet — so bleibt der Blog schnell und aktuell.

webhook.php
<?php
// Cache invalidieren per Publino-Webhook (article.published / .updated)
// webhook.php
$payload = json_decode(file_get_contents('php://input'), true);

if (in_array($payload['event'] ?? '', ['article.published', 'article.updated'], true)) {
    // WordPress:
    delete_transient('publino_articles');
    // Laravel:
    // Cache::forget('publino.articles');
}

http_response_code(200);

Lieber JavaScript oder ganz ohne Backend?

Für Next.js, Astro & Nuxt gibt es das JS-SDK — und für reine HTML-Seiten den embed.js-Weg.