Codync
免费开源的 1:1 Grok Bot 与 Muse 替代方案。可在 iPhone、Mac 或 Linux 桌面上将 Claude 代码、Codex、Cursor 以及 40 多个编码代理作为持久机器人使用。支持群组聊天、线程、应用。
AI 翻译
尚未收集仓库信息。
尚未检测到更新。GitHub 发布版本后会显示在这里。
Franken CMS is a CMS alternative powered by Laravel and FilamentPHP
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗A WordPress alternative for Laravel. Powered by FilamentPHP and the TALL stack.
Franken CMS gives you content management — posts, pages, taxonomies, menus, SEO, and a template field system — as a Laravel package. Build your app your way without being locked into a rigid structure.
Beta — Franken CMS is in active development. APIs may change before the stable release.
Full documentation is available at frankencms.com.
composer require frankencms/franken-cms
Then run the installer:
php artisan franken-cms:install
The installer will guide you through publishing config, running migrations, registering the Filament plugin, and setting up your theme.
Franken CMS ships with optional AI-assisted content generation (SEO titles, meta descriptions, teasers, alt text, blog post drafts) built on the laravel/ai SDK. It's entirely opt-in — the package is not required to run Franken CMS.
composer require laravel/ai:^1.0
Using Amazon Bedrock? laravel/ai 1.x no longer installs the AWS SDK, so add it yourself:
composer require aws/aws-sdk-php
Add your API key(s) to .env. Franken CMS reads provider credentials straight from config/ai.php, so no key is stored in the database:
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
GEMINI_API_KEY=
See vendor/laravel/ai/config/ai.php for the full list of supported providers (Azure, Bedrock, Cohere, DeepSeek, ElevenLabs, Groq, Jina, Mistral, OpenAI-compatible, OpenRouter, VoyageAI, xAI, and more). Optionally publish the config to customize it further:
php artisan vendor:publish --tag=ai-config
Ollama requires no API key. It's disabled by default to avoid advertising a "local" provider that may not actually be running; opt in explicitly in .env:
CMS_AI_ENABLE_OLLAMA=true
With the SDK installed and at least one provider configured, go to CMS Settings → Igor in the Filament admin panel and toggle Igor on. AI features activate only when all three are true: the SDK is installed, a provider has credentials, and the toggle is enabled.
Note: API keys are no longer stored in the database. If you're upgrading from an older Franken CMS version, remove any stale
cms_ai.api_keyrow from your settings table (or runphp artisan migrate:fresh) and set the key in.envinstead.
Text generation and image generation are configured independently in CMS Settings → Igor → Provider:
Text Generation — powers SEO titles, meta descriptions, teasers, alt text, and blog post drafts.
Image Generation — powers featured image generation (and any future image features).
default_for_images when that provider has credentials, falling back to your first configured image-capable provider otherwise — so a single OPENAI_API_KEY works with no selection at all.Both engines have a Test Model button that fires a minimal probe with the currently selected provider/model and reports either success or the provider's exact error. Use it whenever a model misbehaves — providers (notably OpenAI) list models in their API that your project may not have permission to invoke, and the only reliable way to know is a real call. The image test generates one small low-quality image, so it asks for confirmation first (your provider bills for it, typically a cent or two).
Igor can generate a post's featured image using the image engine above. Configure the feature itself in CMS Settings → Igor → Prompts → Featured Image Generation:
{title} and {excerpt} placeholders ({excerpt} is filled from the post's teaser field)Once enabled, a Generate with AI button appears next to the featured image upload when editing an existing post or page (it's hidden while creating a new one, since there's no record yet to attach the image to). The button opens a modal with the prompt pre-filled from your template, editable before generating. The generated image's aspect ratio follows the featured image aspect ratio configured in Media settings (21:9 and custom ratios fall back to 16:9), and it replaces the current featured image on success.
Franken CMS can generate og:image and twitter:image previews automatically for posts and pages, built on spatie/laravel-og-image. It's entirely opt-in — without the package, manual per-post uploads and the site default image keep working exactly as before.
composer require spatie/laravel-og-image
The franken-cms:install command will also offer to install and wire it up for you.
Templates are mapped by post type in config/franken-cms.php. Publish the config if you haven't (php artisan vendor:publish --tag=franken-cms-config) — the mappings ship commented out, so generation stays off until you enable them:
'og_image' => [
'templates' => [
'post' => 'theme.og-templates.post',
'page' => 'theme.og-templates.page',
],
],
Each template is a plain Blade view rendered on a 1200×630 canvas and receives $post — do not wrap it in <x-og-image> yourself, Franken CMS's component handles that.
The example theme ships two ready-made designs in theme/og-templates/:
post.blade.php — the "specimen card": category + specimen-number chip, gradient display title, author ⌁ date ⌁ read-time metadata, and the featured image seamed in with a lightning-bolt edge and suture stitches.page.blade.php — the "dossier card": the calmer sibling — page-path chip, site tagline, and a gradient bolt watermark when the page has no featured image.Both are fully self-contained (fonts and CSS live inside the template, no asset rebuild needed), scale the title to its length, honor each image's focal point, and degrade gracefully when data is missing — edit them freely, or use them as a reference for your own. Preview any page's card by appending ?ogimage to its URL; the image URL contains a content hash, so design changes bust caches automatically.
Drop <x-franken-og-image /> into your theme layout before </body> (the example theme ships with it already in place).
For each page, an image is resolved in this order: per-post uploaded image → mapped template → site default image → site-wide fallback template. The fallback template is opt-in — point og_image.default_template in config/franken-cms.php at a Blade view (the example theme ships one at theme.og-templates.default) and it generates an image for any page that would otherwise have none. Posts that opt into Twitter summary cards (instead of large-image cards) keep the classic manual og:image/twitter:image tag path.
Image generation needs Chrome and Node available on the server:
npm install puppeteer
npx puppeteer browsers install chrome
If that's not an option, set the following in .env to render via Cloudflare's Browser Rendering API instead:
CLOUDFLARE_API_TOKEN=
CLOUDFLARE_ACCOUNT_ID=
Cloudflare needs a publicly reachable URL. Its browser runs in Cloudflare's cloud and fetches your page to screenshot it, so it cannot see local domains like
https://myapp.test— screenshots fail with a network error. Use the local Chrome driver for local development (leave theCLOUDFLARE_*vars unset there) and enable Cloudflare in deployed environments.
For routes outside the CMS (hand-coded, non-post/page views), use <x-og-image> directly per Spatie's documentation.
FrankenCMS's OG image generation is scoped to CMS-managed pages, so on these non-CMS routes it keeps emitting its own classic tags (including a site default og:image, if one is configured). That means a page using <x-og-image> directly will end up with Spatie's generated tag alongside FrankenCMS's classic tag. Crawlers generally take the first og:image they encounter, so if that matters, either remove the site default or skip the <x-og-image> component on that page.
Append ?ogimage to any page URL to preview the generated image directly in the browser.
FrankenCMS automatically generates sitemaps for CMS content (sitemap-pages.xml, sitemap-posts.xml). It can also generate sitemap-routes.xml covering your application's own routes — the static pages you define in routes/web.php outside the CMS.
Enabled by default; toggle it under Settings → Sitemap → App Routes Sitemap.
A route is included automatically when it is a static GET route (no URI parameters), uses the web middleware, has no domain restriction, and is not:
auth, guest, verified, signed, or password.confirm middlewareRoute::redirect() (the target belongs in the sitemap, not the redirect)// Force-include a route the heuristics would skip, optionally with metadata
Route::middleware(['web', 'auth'])
->get('/members/welcome', WelcomeController::class)
->sitemap(priority: 0.9, changeFrequency: 'monthly');
// Exclude a route the heuristics would include
Route::view('/internal-demo', 'demo')->skipSitemap();
Allowed changeFrequency values: always, hourly, daily, weekly, monthly, yearly, never. Priority is 0.0–1.0.
Routes without overrides use the sitemap settings' default priority and change frequency. The Excluded Paths setting always wins — a URL matching an excluded pattern never appears, even with a ->sitemap() force-include. Routes with URI parameters can't be enumerated; point Custom Sitemaps at a hand-built sitemap for those.
Gate detection is alias- and known-middleware-based, not exhaustive — routes gated by policies, custom middleware classes, or custom middleware groups won't be recognized as gated automatically, so use ->skipSitemap() explicitly for those.
CMS content is routed by Laravel as usual (a Route::fallback() plus named page routes). Livewire can sit on top of that in two optional ways. Your theme layout needs @livewireStyles and @livewireScripts; the example theme already has both.
Your own Route::livewire() routes in routes/web.php keep working alongside the CMS, because the CMS fallback route is registered last.
wire:navigate)CMS_LIVEWIRE_NAVIGATE=true
# Optional: prefetch on hover (wire:navigate.hover)
CMS_LIVEWIRE_NAVIGATE_PREFETCH=true
Menu items, breadcrumbs, and the example theme's post, category, and tag links then fetch the next page and swap the body without a full reload. Links get wire:navigate only when they are internal and open in the same tab. External URLs, #anchors, mailto:/tel: links, file URLs (sitemap.xml, *.pdf) and the paths in franken-cms.livewire.navigate_except (by default admin, feed) always do a full page load.
Use the same rule on your own theme links:
<a href="{{ $url }}" @frankenNavigate($url)>…</a>
{{-- or --}}
<a href="{{ $url }}" {{ franken_navigate($url, $target) }}>…</a>
Things to know:
DOMContentLoaded runs only once. Listen for livewire:navigated instead.@persist('name') … @endpersist. Don't persist the header if it shows the active menu state.<head> tags are rendered server-side on every request and merged by Livewire, and crawlers always do full loads, so SEO output is unchanged.Any theme template can be a Livewire single-file component. Write it in the theme folder with the usual name (page-…, post-…), without a ⚡ prefix, and pick it per page in the admin like any other template:
{{-- resources/views/theme/page-newsletter.blade.php --}}
<?php
use FrankenCms\Livewire\Concerns\InteractsWithFrankenPage;
use Livewire\Component;
new class extends Component {
use InteractsWithFrankenPage; // provides $page / $post and $frankenFields
public string $email = '';
public function subscribe(): void
{
$this->validate(['email' => 'required|email']);
// ...
}
};
?>
<div>
<h1>@frankenText('hero.title', ['label' => 'Title', 'default' => 'Join the list'])</h1>
<form wire:submit="subscribe">
<input type="email" wire:model="email">
<button>Subscribe</button>
</form>
</div>
@franken* fields work as they do in plain templates: they show up in the editor, and their values are available on every render, including Livewire update requests.franken-cms.livewire.layout. If that isn't set, the example theme's theme.components.layouts.main.index is used when it exists, then Livewire's component_layout. A #[Layout] attribute on the component overrides all of these.WithPagination). The CMS passes only $page/$post, never the posts paginator.CMS_LIVEWIRE_PAGE_COMPONENTS=false.composer test
See CHANGELOG for version history.
See CONTRIBUTING for details.
Please review our security policy on how to report security vulnerabilities.
The MIT License (MIT). See License File for more information.