Add a full-featured blog and news section to your LaraClassifier / JobClass site. Create posts with categories, tags, featured images, and a threaded comment system with moderation: all fully translatable.
Rich Post Editor
Create posts with translatable titles, slugs, content, excerpts, and SEO metadata. Attach featured images via the media library.
Categories & Tags
Organize content with hierarchical categories (using the unified categories table) and a flexible tagging system.
Threaded Comments
Nested comment replies with configurable depth, moderation queue, auto-approval rules, and CAPTCHA support.
Live Posting & Self-Moderation
Comments, replies, edits and deletions are sent without reloading the page. Signed-in authors can edit and delete their own comments.
Multi-Language
All posts, categories, and tags support translations via Spatie Translatable. Localized front-end URLs with locale prefix.
Email Notifications
Admins are notified of new comments. Comment authors are notified when someone replies to their comment.
Reading Time & Views
Automatic reading time calculation (configurable WPM) and view count tracking for each post.
Use Cases
Company Blog
Publish company news, product updates, and industry insights. Organize posts by category (e.g. “Product Updates”, “Industry News”, “Tutorials”) and let visitors engage through comments.
Portfolio Blog
Complement your portfolio with behind-the-scenes articles, case studies, and project write-ups. Tag posts with relevant project names or technologies for easy cross-referencing.
Multi-Language Content Hub
Publish articles in multiple languages (English, French, etc.) with per-locale slugs and content. Each post can have fully independent translations managed through the admin panel.
News Section
Use the blog as a press/news section. Leverage the “published at” date for scheduling and the “draft/published” workflow for editorial control.
Requirements
- LaraClassifier / JobClass v19.0.0 or later
- PHP 8.3+
- MySQL 8.0+ (required for
JSON_SEARCHin translatable slug lookups) - The core categories table must exist (blog categories use the unified
categoriestable withcategorizable_type = 'post')
Installation
Step 1: Upload the Add-on
In the admin panel, go to Admin → Extensions → Add-ons and click the Upload Add-on button. Select the add-on’s ZIP file: the system extracts it automatically and the add-on appears in the installed add-ons list.
Step 2: Activate the Add-on
Find Blog & News in the list and click Activate. Its migrations, seeders (if any) and permissions are set up automatically.
Step 3: Configure
Navigate to Admin → Blog → Settings to configure posts per page, comment moderation, notifications, and reading-time settings. See Configuration.
Purchase Code (License Key)
Blog & News is sold as a separate product, so it has its own purchase code (license key) — distinct from the purchase code of the main application and from the one of every other add-on. You are asked for it when you activate Blog & News in Admin panel → Add-ons.
Our products are sold on three platforms. The way you receive a purchase code depends on where you bought the product.
| Platform / Marketplace | How you get the purchase code | Where to find it again |
|---|---|---|
| bedigit.com Store In-site purchase (Shop) |
Generated automatically when the order is paid, then sent by email — either in its own license email, or inside the order confirmation email. | My Account → My Licenses on bedigit.com |
| Gumroad | Created as soon as Gumroad notifies us of the sale, then sent in a separate email, in addition to the Gumroad receipt. | The license email, your Gumroad Library, and My Account → My Licenses on bedigit.com |
| Envato Market CodeCanyon |
Issued by Envato, not by us, and never sent by email: you download it yourself from your Envato account. | Envato account → Downloads → License certificate & purchase code |
1. bedigit.com Store (in-site purchase)
- As soon as the order’s payment status becomes Paid, a license key is generated automatically for every licensed item in the order (one key per purchased unit — buying 3 units gives 3 distinct keys).
- It is emailed to the address used on the order, either in a dedicated license email or inside the order confirmation email. Check your inbox and your spam / junk folder.
- The key stays available in your account under My Account → My Licenses. Keys are masked in the list; open the license detail page to reveal and copy the full key, see the domains it is activated on, and deactivate a domain to free an activation slot.
- The matching invoice is under My Account → My Orders.
2. Gumroad
- A Gumroad purchase produces two separate emails: the Gumroad receipt (sent by Gumroad, giving access to the files) and a license key email (sent by bedigit.com) that contains your purchase code.
- The license key email is generated as soon as Gumroad notifies us of the sale, so it normally arrives within seconds of the payment. Here too, check your inbox and your spam / junk folder.
- When the Gumroad product uses Gumroad’s own license-key feature, the same key also appears in your Gumroad receipt and under Library → your purchase on gumroad.com.
- Use the same email address on bedigit.com as on Gumroad: your keys are then linked to your account automatically and listed under My Account → My Licenses, even if you register after the purchase. You can also add a Gumroad key manually from My Account → My Gumroad Licenses.
3. Envato Market (CodeCanyon)
- Envato purchase codes are issued and delivered by Envato Market, never emailed by us — so there is nothing to look for in your spam folder: you retrieve the code from your Envato account.
- Log in to your Envato / CodeCanyon account, open the Downloads page, find the item, and choose License certificate & purchase code from the Download dropdown. The code is written in that certificate.
- An Envato purchase code looks like
12345678-90ab-cdef-1234-567890abcdef(8-4-4-4-12 characters). It never changes, and renewing item support does not issue a new one. - Official Envato article: Where Is My Purchase Code?
Configuration
The blog add-on ships with a configuration file at config/blog.php that defines default values.
All settings can be overridden from the admin panel (stored in the settings table, group blog).
| Setting | Description | Default |
|---|---|---|
blog_posts_per_page |
Number of posts displayed per page on the blog listing. | 10 |
blog_related_posts_count |
Number of related posts shown at the bottom of each post detail page. | 3 |
blog_words_per_minute |
Average reading speed used to calculate the “X min read” estimate. | 200 |
blog_home_shows_listing |
Serve the plain post listing at /blog instead of the magazine home. /blog/posts then redirects to /blog. |
false |
blog_home_hero_enabled |
Show the hero banner at the top of the blog home page. The rest of the hero is stored in the other blog_home_hero_* settings (heading, subheading, button, height, alignment, background and text colours). |
false |
blog_home_trending_enabled |
Run the most-read headlines on one line under the header of the blog home page. | true |
blog_home_trending_limit |
How many headlines the trending bar carries (1–12). | 5 |
blog_home_sections |
The home page sections, as JSON: one entry per section with its content type, layout, post count, title / subtitle per language, and the category, tag or post IDs it targets. | Featured (lead) + Latest (grid) + Most read (spotlight) |
blog_comments_enabled |
Enable or disable the comment system globally. | true |
blog_comments_require_approval |
When enabled, guest comments must be approved by an admin before appearing. Authenticated user comments are auto-approved. | true |
blog_allow_guest_comments |
Allow non-logged-in visitors to leave comments (requires name and email). | false |
blog_comments_max_depth |
Maximum nesting level for threaded comment replies (1–5). | 2 |
blog_auto_approve_trusted_commenters |
Auto-approve comments from users who already have a previously approved comment (matched by email). | false |
blog_auto_approve_replies |
Auto-approve replies to an existing comment, so a thread keeps flowing without a moderator approving every answer. First-level comments still follow the normal moderation rules. | false |
blog_notify_admin_on_comment |
Send email notifications to all admin users when a new comment or reply is posted. | true |
blog_notify_author_on_reply |
Send email notifications to comment authors when someone replies to their comment. | true |
blog_page_header_mode |
Header style of the blog front pages: simple (title + breadcrumb) or hero (a band with its own background). The rest of the header is stored in the other blog_page_header_* settings (visibility switches, height, alignment, background and text colours). |
simple |
blog_page_header_show_header |
Render the page header at all. blog_page_header_show_title, _show_subtitle and _show_breadcrumb switch its parts individually. |
true |
blog_page_header_show_subnav |
Show the blog sub-navigation bar (Blog / All Posts) under the page header. | true |
blog_captcha_enabled |
Require CAPTCHA verification when posting comments (requires a CAPTCHA provider to be configured in core settings). | false |
Config File Defaults
The config/blog.php file also includes featured image dimensions used when processing uploads:
| Key | Description | Default |
|---|---|---|
featured_images.width |
Featured image width (px) | 1200 |
featured_images.height |
Featured image height (px) | 630 |
featured_images.thumbnail_width |
Thumbnail width (px) | 400 |
featured_images.thumbnail_height |
Thumbnail height (px) | 250 |
Admin: Posts
The Posts page (Blog → All Posts) is the primary interface for managing blog content.
Posts List
A sortable, paginated table (20 per page) showing:
- Featured image thumbnail
- Title (translatable)
- Category
- Author
- Status (Draft / Published)
- View count
- Comments count
- Published at date
Filters & Search
The posts list supports three filter dimensions:
- Search: searches within post titles (across all translated locales via
JSON_SEARCH) - Status: filter by
draftorpublished - Category: filter by a specific category
Creating & Editing Posts
The post form includes the following fields, each supporting per-locale translations:
Content Fields (per locale)
| Field | Validation | Notes |
|---|---|---|
title |
Required (default locale), max 255 | Translatable. Used to auto-generate slug. |
slug |
Optional, max 255 | Translatable. Auto-generated from title if left empty. |
content |
Optional | Translatable. WYSIWYG editor content. |
excerpt |
Optional, max 500 | Translatable. Short summary for listing pages. |
meta_title |
Optional, max 70 | Translatable. SEO title tag. |
meta_description |
Optional, max 160 | Translatable. SEO meta description. |
Non-Translatable Fields
| Field | Validation | Notes |
|---|---|---|
category_id |
Optional, must exist in categories |
Blog category (from unified categories table) |
featured_image |
Optional, image file | Uploaded via core media service |
status |
Required, draft or published |
Uses the PageStatus enum |
published_at |
Optional, date | Auto-set to current time on first publish if empty |
tags |
Optional, array of tag IDs | Multi-select from existing tags |
Str::slug().
Admin: Categories
Blog categories (Blog → Categories) use the core unified categories table,
scoped by categorizable_type = 'post'. This means they share the same table structure as
portfolio and other add-on categories, but are isolated via a global scope on the PostCategory model.
Category Fields
| Field | Notes |
|---|---|
name |
Translatable. Required for default locale. |
slug |
Translatable. Auto-generated from name if empty. |
description |
Translatable. Optional. |
parent_id |
Nullable. Supports one level of nesting (parent → child). |
position |
Integer for manual ordering. |
is_active |
Boolean. Inactive categories are hidden from front-end. |
Admin: Tags
Tags (Blog → Tags) are lightweight labels that can be attached to any post.
Unlike categories, tags are flat (no hierarchy) and are stored in the blog_post_tags table.
Tag Fields
| Field | Notes |
|---|---|
name |
Translatable. The display name of the tag. |
slug |
Translatable. URL-friendly identifier. |
The tags list shows each tag with its associated post count. Tags are searchable by name and paginated (20 per page).
detach()), but the posts themselves are not affected.
Admin: Comments
The Comments page (Blog → Comments) provides a moderation interface for all blog comments across all posts.
Comments List
A paginated table (20 per page) showing:
- Author: user name (if authenticated) or guest name/email
- Content: comment text preview
- Post: the blog post the comment belongs to
- Status: Approved / Pending badge
- Date
A pending count badge is shown in the header to quickly identify items needing attention.
Moderation
Per-comment actions:
- View: see full comment content, replies, and post context
- Approve (
PATCH): marks the comment as approved - Delete: permanently removes the comment
Filter by Status
Use the status query parameter to filter:
?status=pending: show only pending (unapproved) comments?status=approved: show only approved comments
Bulk Actions
Select multiple comments using checkboxes and apply bulk actions:
- Approve: approve all selected comments at once
- Delete: delete all selected comments
Bulk actions are sent as POST admin/blog/comments/bulk with action and
comma-separated ids.
Admin: Settings
The settings page (Blog → Settings) is organized into six sections:
Posts Display
- Posts Per Page: number of posts on the listing page (1–100)
- Related Posts: number of related posts shown on post detail pages (0–12)
- Words Per Minute: reading speed for reading time calculation (100–500)
Home Page
The tab opens on Home Page Layout, which decides what /blog serves:
- Magazine home (default): the front page built from the cards below. The post
listing stays at
/blog/posts. - Post listing: the plain paginated list of posts.
/blog/poststhen redirects to/blogso the two never compete for the same content, the listing takes the blog's own title and breadcrumb, and the sub-navigation is dropped (only one entry would be left). The cards below are hidden but keep their values, so switching back restores the magazine home as it was.
The remaining three cards build the magazine home page:
- Hero Banner: an optional masthead above the first section. The heading, subheading and button label are per language; the height, text alignment, background (solid colour, gradient or image with an overlay) and the title / subtitle / breadcrumb colours match the controls on the Page Header tab. Leave a colour empty to inherit it from the theme.
- Trending Bar: runs the most-read headlines on one line under the header, with a configurable number of headlines (1–12).
- Home Sections: the section builder. Add, reorder, rename per language,
and disable sections. Each section has a content source and a layout:
- Content: Featured posts (the posts flagged in the post editor, topped up with the most-read ones), Latest posts, Most read, From a category, From a tag, or Hand-picked posts (chosen one by one, shown in the order you pick them).
- Layout: Lead story, Grid, List, Spotlight, Headlines or Carousel.
The whole section list is stored as JSON in the blog_home_sections setting; the hero
and trending bar use the blog_home_hero_* and blog_home_trending_* settings.
Comments
- Enable Comments: global toggle for the comment system
- Require Approval: whether guest comments need admin approval (authenticated users are always auto-approved)
- Guest Comments: allow non-logged-in visitors to comment
- Reply Depth: maximum nesting level for threaded replies (1–5)
- Auto-Approve Trusted: auto-approve comments from emails that already have an approved comment
- Auto-Approve Replies: auto-approve replies to an existing comment, without waiting for moderation. Useful to keep a discussion flowing while still moderating first-level comments
Notifications
- Admin Notification: email admins when a new comment/reply is posted
- Reply Notification: email comment authors when someone replies to their comment
CAPTCHA Protection
- Enable CAPTCHA for Comments: require CAPTCHA verification when posting comments
Requires a CAPTCHA provider to be configured in the core settings. If no provider is configured, a warning is shown with a link to the configuration page.
Page Header
The header band of the blog front pages — the post listing and the category, tag, author and search archives. The home page hero keeps its own settings on the Home Page tab and still wins there; anything it leaves empty falls back to this tab. The article page paints its own masthead from the post’s featured image and is not affected.
- Header style: Simple title + breadcrumb (the default) keeps the theme’s own background and only takes the alignment and the text colours; Hero header paints a full band with its own height and background.
- Visibility: switch the whole header, its title, its subtitle, its breadcrumb and the blog sub-navigation bar on or off.
- Layout: header height (any CSS length) and content alignment (left, center, right, or the theme default).
- Background (hero style only): theme default, solid colour, gradient (two colours and an angle) or an image with an overlay opacity. A solid colour and a gradient can also carry a decorative overlay image.
- Text colours: title, subtitle, breadcrumb text and breadcrumb link. Leave a colour empty to inherit it from the theme.
The values are stored in the blog_page_header_* settings and resolved by
Addons\Blog\Support\PageHeader, which falls back to its own defaults for every key
that was never saved.
Front-end: Blog Home
The blog front page (/{locale}/blog) is a magazine-style home page assembled from the
Blog → Settings → Home Page tab. Top to bottom it renders:
- Hero banner (optional), painted by the addon's own page header
- Sub-navigation: Blog and All Posts (hidden when the listing is the main page, or when Show sub-navigation is off on the Page Header tab)
- Trending bar (optional): the most-read headlines on one scrollable line
- Content sections: in the order set in the admin, each in its chosen layout
- Topic rail: every category that has at least one post, with its post count
Section layouts
- Lead story: one dominant story whose headline block breaks the bottom edge of its image, beside a stack of secondary stories
- Grid: an even card grid, three across on desktop
- List: full-width rows, thumbnail left, story right
- Spotlight: one open story beside a compact panel of the rest
- Headlines: a dense, image-free headline list in up to three columns
- Carousel: a horizontal rail of cards with scroll buttons
Most read sections are numbered in the Spotlight and Headlines layouts, because the position carries real information there. Every other content source drops the numerals.
Featured posts
The Featured content source reads the Featured post toggle in the post
editor’s Publish card (blog_posts.is_featured), newest first. If fewer posts are
flagged than the section asks for, it is topped up with the most-viewed posts.
Styling
Every front-end blog page pulls one shared stylesheet
(blog::front.partials.styles), so the home page, the archives and the article page
read as one publication. It derives all of its colours from the active theme’s Bootstrap
tokens and inherits the theme’s heading font rather than declaring one, so the blog follows
the theme and its dark mode.
Front-end: Blog Listing
The blog listing page (/blog/posts) displays published posts with pagination.
The category, tag, author and search pages share this same layout.
Main Content
- Post cards: each showing: featured image thumbnail, title, excerpt, category badge, author name, published date, reading time, and view count
- Pagination: configurable posts per page
Sidebar
- Categories: list of active categories with post counts
- Recent Posts: the 5 most recently published posts
- Popular Posts: the 5 most viewed posts
- Tags: all tags that have at least one post
Front-end: Post Detail
The post detail page (/{locale}/blog/{slug}) renders the full post content.
Content
- Header: title, category, author, published date, reading time, view count
- Featured image: full-width hero image (via polymorphic media relation)
- Content body: rendered HTML content
- Tags: tag badges linked to tag filter pages
- Post navigation: previous / next post links
- Related posts: posts sharing the same category or tags (configurable count)
- Comments section: threaded comments with reply form (see Comments)
View Count Tracking
Each time the post detail page is loaded, PostService::incrementViewCount()
increments the view_count column. This drives the “Popular Posts” sidebar widget.
Related Posts Algorithm
Related posts are selected by matching:
- Posts in the same category
- Posts sharing any of the same tags
Results are ordered by published date (most recent first) and limited to the configured count.
Front-end: Category & Tag Pages
Category Page
URL: /{locale}/blog/category/{slug}
Displays all published posts in the specified category with the same pagination, sidebar widgets, and post card layout as the main listing. The category is resolved by its translatable slug (current locale first, then English fallback).
Tag Page
URL: /{locale}/blog/tag/{slug}
Displays all published posts tagged with the specified tag. Same layout as the category page. The tag is resolved by its translatable slug.
Front-end: Search
URL: /{locale}/blog/search?q={query}
Full-text search across post titles and content in all locales using MySQL JSON_SEARCH.
Results are paginated and displayed with the standard blog listing layout.
Front-end: Comments
The comment system appears at the bottom of each post detail page (when enabled).
Comment Form
- Authenticated users: only need to enter the comment content. Auto-approved unless moderation overrides apply.
- Guest users (if enabled): must provide name, email, and content. Subject to approval moderation.
- Reply form: appears under a comment when clicking “Reply”, up to the configured max depth. A single reply form is shared by the whole page and moved to the comment being answered.
- Notify on reply: checkbox to opt in/out of reply notifications.
- CAPTCHA: displayed when CAPTCHA is enabled for blog comments, and refreshed after each submission.
Posting Without a Page Reload
Comments, replies, edits and deletions are all sent in the background: the page is never reloaded and the visitor stays where they were in the discussion.
- While a request is being sent, the form is dimmed, its buttons are disabled and the submit button shows a spinner. This prevents double submissions and makes the wait visible.
- On success, an approved comment is inserted straight into the list (a reply lands under its parent), the comment counter is updated and a confirmation message is shown above the form.
- If the comment still needs moderation, the confirmation says so and nothing is added to the list: the comment appears once an admin approves it.
- Validation errors are shown under the field concerned, without losing what was typed.
- If JavaScript is unavailable, the forms fall back to a normal submission and a page reload: nothing is lost.
Editing & Deleting Your Own Comments
Signed-in visitors get Edit and Delete actions on the comments they wrote. Both work in the background, like posting.
- Edit opens the comment text in place. Saving replaces the text immediately and marks the comment as “Edited” next to its date.
- Editing closes once somebody replies. The Edit action disappears as soon as the comment has a reply, so the answers below it can’t lose the context they were written for. It comes back if every reply is removed. Pending replies count too, even though they are not displayed yet.
- Delete asks for confirmation first, then removes the comment along with all of its replies. Deleted comments are kept in the trash rather than destroyed, so an admin can still review them.
- These actions never appear on somebody else’s comment, and are refused by the server as well as hidden in the page. They are not available on guest comments, which carry no reliable identity.
- Turning Enable Comments off also disables editing and deleting.
Comment Display
- Comments are displayed in threaded format (parent → replies).
- Only approved comments are shown to front-end visitors: a reply awaiting moderation stays hidden until it is approved.
- Each comment shows: author display name, date, an “Edited” marker if its author changed it, and the content.
- The comment counter next to the section title counts approved comments and replies.
Validation Rules
| Field | Validation |
|---|---|
content |
Required, 3–2000 characters |
parent_id |
Optional, must exist in blog_comments; depth check enforced |
author_name |
Required for guests, max 255 |
author_email |
Required for guests, valid email, max 255 |
notify_on_reply |
Optional boolean |
Auto-Approval Logic
- If Require Approval is off → all comments are auto-approved.
- If the commenter is authenticated → auto-approved.
- If the comment is a reply and Auto-Approve Replies is on → auto-approved.
- If Auto-Approve Trusted is on and the email has a previously approved comment → auto-approved.
- Otherwise → pending (requires admin approval).
Multi-Language Support
The blog add-on uses spatie/laravel-translatable for all content fields.
Translations are stored as JSON columns in the database.
Translatable Fields by Model
| Model | Translatable Fields |
|---|---|
Post |
slug, title, content, excerpt, meta_title, meta_description |
PostCategory |
slug, name, description |
PostTag |
slug, name |
Slug Resolution
Front-end controllers resolve slugs by searching in the current locale first, then falling back to English:
Featured Images
Posts support a single featured image via a polymorphic MorphOne relationship
to the core Media model (mediable). The HasMedia trait is included on the Post model.
Upload Flow
- Admin uploads an image file via the post create/edit form.
- The
PostServicedelegates toMediaService::uploadFor(). - The image is stored in the
postssubdirectory of the media disk. - Thumbnails are generated based on config dimensions (
featured_images.thumbnail_width/height).
Image Removal
The edit form includes a “Remove featured image” checkbox. When checked,
the existing media record and files are deleted via MediaService::delete().
Uploading a new image automatically replaces the old one.
Email Notifications
The blog add-on sends two types of email notifications:
New Comment Notification
Sent to all admin users (is_admin = true) when a new comment or reply is posted.
- Subject: “New comment on {post title}” or “New reply on {post title}”
- Body: Author name, post title, content preview (200 chars)
- Action: “Moderate Comments” link (if pending) or “View Comment” link (if approved)
Controlled by: blog_notify_admin_on_comment setting.
Comment Reply Notification
Sent to the parent comment’s author when someone replies to their comment.
- Subject: “New reply to your comment on {post title}”
- Body: Reply author name, post title, content preview
- Action: “View Reply” link
Controlled by: blog_notify_author_on_reply setting.
Reply notifications respect the commenter’s notify_on_reply preference
and are not sent when someone replies to their own comment.
CAPTCHA Protection
When blog_captcha_enabled is set to true, the comment form includes
a CAPTCHA challenge. The blog add-on integrates with the core CaptchaService:
- The service checks if CAPTCHA is enabled for the
blogcontext. - The appropriate CAPTCHA field name is resolved via
CaptchaService::getResponseFieldName(). - Validation uses the
CaptchaRuleclass from the core.
A CAPTCHA provider (e.g., reCAPTCHA, hCaptcha) must be configured in the core settings for this feature to work.
Updating
There are two ways to update this add-on: via the admin panel (recommended) or manually replacing files.
Method 1: Admin Panel Upload (Recommended)
- Download the latest
.zipfile of this add-on. - Go to Admin panel → Add-ons and click the Upload button.
- Select or drag the
.zipfile into the upload area. - A confirmation prompt will show the current and new version numbers. Click Replace to proceed.
- Go to Admin panel → System Update (
/admin/update) to apply any pending database migrations.
Method 2: Manual File Replacement
Step 1: Replace Files
Replace the add-on directory with the new version.
Step 2: Run Migrations
php artisan migrate
Pending migrations run once, so the command is safe to repeat.
Step 3: Clear Caches
php artisan config:clear
php artisan route:clear
php artisan view:clear
Step 4: Rebuild Assets
Only needed if the update includes new or modified SCSS/JS theme files.
Step 5: Verify
Visit Blog → Settings to confirm the settings page loads correctly, then check the front-end blog listing page.
Uninstallation
Switching an add-on off without losing anything is a deactivation: go to Admin panel → Add-ons, find Blog & News and click Deactivate.
- Its routes, views, admin menu entries and permissions stop being registered, and its front-end pages stop answering.
- Its database tables and all the data they hold are kept, and its files stay under
extensions/addons/blog/. Nothing is deleted. - The purchase code recorded at activation is kept too, so activating the add-on again does not ask for it.
- Deactivation is refused while another active add-on depends on this one: deactivate that add-on first.
Click Activate on the same card to switch it back on. Pending migrations are re-run, assets are republished, and the add-on picks up exactly where it left off.
Removing
Removing is permanent and destroys the add-on's data. The Remove button only appears on a deactivated add-on, so removal is always two steps:
- Deactivate Blog & News (see Uninstallation).
- Click Remove on its card and confirm the prompt.
The admin panel then, in one pass:
- runs the add-on's uninstall hook, if it ships one, while its code is still on disk;
- revokes the permissions declared in its
addon.json; - rolls back its migrations — this drops its database tables and every row they hold — and purges its entries from the
migrationstable, so a later reinstall migrates from scratch; - deletes its published assets:
public/addons/blog/,public/vendor/blog/andstorage/app/public/addons/blog/; - deletes the add-on directory
extensions/addons/blog/; - deletes its row in the
addonstable (the recorded purchase code goes with it) and clears the application cache.
Removal is refused, with an explanatory message and before anything is destroyed, when the add-on is still active, when another active add-on depends on it, or when the web server (PHP) user cannot delete extensions/addons/blog/. In that last case, give that user write permission on the directory and on its parent, then try again.
Deleting the folder over FTP or SSH is not equivalent: the add-on's tables, its entries in the migrations table and its addons row are all left behind, and its card stays in the list. Use Remove in the admin panel instead.
Troubleshooting
Blog pages return 404
- Ensure the Blog add-on is activated in Admin → Add-ons.
- Run
php artisan route:clearto clear the route cache. - Verify the
BlogServiceProvideris being registered (checkAddonServiceProviderautoloader).
Post shows “Not Found” despite being published
- Check that the post status is
published(notdraft). - Ensure
published_atis set and is in the past (future-dated posts are not visible). - Verify the slug matches the URL: slugs are locale-specific. The system tries the current locale first, then English.
Category page returns 404
- Ensure the category is active (
is_active = true). - Check that the category’s
categorizable_typeispost. - Verify the slug in the URL matches the category’s translatable slug for the current locale.
Comments not appearing on posts
- Check that
blog_comments_enabledis set totruein settings. - If using moderation, comments must be approved first. Check the admin comments page for pending items.
- Guest comments require
blog_allow_guest_commentsto be enabled.
The “Edit” action is missing on my own comment
- A comment can no longer be edited once somebody has replied to it. Delete the replies (or ask an admin to) and the Edit action comes back.
- A reply awaiting moderation also locks editing, even though it is not displayed yet. Check
Blog → Comments filtered on
?status=pending. - Editing and deleting are only offered to signed-in authors. Comments posted as a guest cannot be edited, because there is no reliable way to prove who wrote them.
- Both actions are hidden when Enable Comments is off.
A reply was posted but does not show up
- If Require Approval is on and the reply came from a guest, it is pending: only approved replies are displayed. Approve it from Blog → Comments.
- To let replies through without moderating each one, enable Auto-Approve Replies in Blog → Settings.
Posting a comment reloads the whole page
- That is the fallback used when the page’s JavaScript did not run. The comment is still saved correctly: only the no-reload behaviour is lost.
- Check the browser console for a script error on the post page, and make sure the theme assets are built and loaded.
Comment form not showing for guests
- Enable
blog_allow_guest_commentsin Blog → Settings. - The
StoreCommentRequestchecks authorization: if guest comments are disabled, the form submission returns 403.
CAPTCHA not appearing on comment form
- Ensure
blog_captcha_enabledis set totruein blog settings. - A CAPTCHA provider must be configured in Admin → Settings → CAPTCHA.
- The
CaptchaService::isEnabledFor('blog')check must returntrue.
Email notifications not being sent
- Check that mail is configured correctly in Admin → Settings → Mail.
- Verify the notification toggles are enabled:
blog_notify_admin_on_commentand/orblog_notify_author_on_reply. - Reply notifications require the parent comment author to have
notify_on_reply = true. - Self-replies do not trigger notifications (by design).
Cannot delete a category: “Cannot delete category with existing posts”
The add-on prevents deleting categories that have posts assigned to them. Either reassign the posts to a different category or delete them first.
Featured image not displaying
- Check that the media file was uploaded successfully (look in the
mediatable for amediable_typematching the post). - Verify the storage symlink exists:
php artisan storage:link. - Check file permissions on the storage directory.
Search returns no results despite matching posts
- The search uses MySQL
JSON_SEARCHwhich requires MySQL 8.0+. - Search is pattern-matched (contains), so partial matches should work.
- Only published posts (with
published_atin the past) are included in search results.
Reading time shows “1 min” for all posts
- Ensure the post has content (the reading time is calculated from
strip_tags(content)). - Check the
blog_words_per_minutesetting: the default is 200 WPM. - Very short posts will always show 1 minute (the minimum).
Blog & News v1.0.1: A LaraClassifier / JobClass add-on.
© BeDigit. All rights reserved.