Classified Ads

A full-featured classified ads marketplace for your Larapen site. Users can create, browse, search, and manage listings with custom fields, location filtering, image galleries, and built-in messaging: all with admin moderation and granular permissions.

Custom Fields

Define unlimited custom fields per category or globally. Support for 10 field types including text, select, checkbox, date, and price range.

Moderation System

Optional admin approval workflow. Approve, reject (with reason), or auto-publish listings. Configurable per-site.

Search & Filtering

Full-text search across titles, descriptions, and locations. Filter by category, price range, condition, city, and custom fields.

Buyer-Seller Messaging

Built-in contact form with email notifications. Messages tracked per listing with read/unread status.

Favorites & Saved

Authenticated users can bookmark listings for later. Toggle save/unsave with a single click.

Multi-Language

All listing content, categories, and custom fields are translatable via spatie/laravel-translatable. Full i18n support.

Auto-Expiration

Listings expire after a configurable number of days. Expired listings are automatically hidden from public view.

Community Reporting

Users can report inappropriate listings. Admins review, dismiss, or act on reports from a dedicated panel.

Use Cases

General Marketplace

Run a Craigslist-style classified ads board where users post items for sale, services, or rentals. Categories and custom fields let you structure any type of listing.

  • Enable user registration and listing creation.
  • Define categories (Vehicles, Electronics, Real Estate, Jobs, etc.) with category-specific custom fields.
  • Enable moderation to review submissions before they go live.
  • Buyers message sellers directly through the built-in contact form.

Business Directory

Create a directory of local businesses with custom fields for opening hours, services offered, and contact details.

  • Disable the price field or make it optional.
  • Add custom fields like “Opening Hours”, “Website URL”, and “Services Offered”.
  • Use location fields (city, region, address) for geographic filtering.

Internal Asset Board

A private board for an organization to list and exchange internal assets, equipment, or resources.

  • Disable guest browsing: require login to view listings.
  • Disable public publishing: only admins create listings.
  • Use the “condition” field (new, used, refurbished) for asset tracking.

Requirements

Requirement Details
Larapen Core ≥ 1.0.0
PHP ≥ 8.2
MySQL ≥ 8.0
User Accounts Required: the add-on depends on the core users table for listing ownership, messaging, favorites, and reporting.
Dependencies None: no other add-ons required.

Installation

Step 1: Upload Add-on

Place the classified folder inside the addons/ directory of your Larapen installation:

Step 2: Activate

Go to Admin → Add-ons → Installed Add-ons and activate Classified Ads.

Step 3: Run Migrations

This creates six tables: classified_listings, classified_custom_fields, classified_custom_field_values, classified_messages, classified_reports, and classified_saved_listings.

Step 4: Clear Caches

Step 5: Configure

Navigate to Admin → Classified Ads → Settings to configure moderation, publishing rules, image limits, listing duration, and notification preferences.

Tip: After activation, a “Classified Ads” menu group appears in the admin sidebar with links to Listings, Categories, Custom Fields, Messages, Reports, and Settings.

Configuration

Configuration defaults are defined in config/classified.php and can be overridden via admin settings (stored in the database with the classified_ prefix).

Setting Key Type Default Description
per_page int 12 Listings per page on the front-end
admin_per_page int 15 Listings per page in the admin panel
max_images int 5 Maximum images per listing (featured + gallery)
listing_duration_days int 30 Days until a listing expires (0 = never expires)
allow_publishing bool true Allow users to create listings on the front-end
guest_browse bool true Allow non-authenticated visitors to browse listings
guest_contact bool false Allow guests to send messages to sellers
moderation_enabled bool true Require admin approval before listings go live
require_phone bool false Make phone number mandatory on listings
enable_reports bool true Allow users to report listings
enable_favorites bool true Allow users to save/bookmark listings
allow_author_translations bool true Allow listing authors to provide translations

Notification Settings

Each notification can be individually enabled or disabled from the admin settings panel:

Setting Key Default Description
notify_admin_on_new_listing true Notify admins when a new listing is submitted
notify_author_on_new_listing true Send confirmation email to listing author
notify_author_on_approval true Notify author when their listing is approved
notify_author_on_rejection true Notify author when their listing is rejected
notify_owner_on_new_message true Notify listing owner when a new message is received
notify_admin_on_report true Notify admins when a listing is reported
notify_owner_on_expiration true Notify listing owner when their listing expires

Admin: Settings

Access via Admin → Classified Ads → Settings. The settings page is organized into logical sections:

  • Publishing: Toggle user listing creation, guest browsing, and guest contact.
  • Moderation: Enable/disable admin approval for new listings.
  • Listing Duration: Set how many days listings remain active (0 for unlimited).
  • Images: Maximum number of images per listing.
  • Contact Info: Whether phone number is required.
  • Features: Enable/disable reporting and favorites.
  • Translations: Allow authors to provide multi-language content.
  • Notifications: Toggle each of the 7 notification types.
GET /admin/classified/settings

Displays the settings form with current values.

PUT /admin/classified/settings

Saves all settings. Validated via UpdateClassifiedSettingsRequest.

Admin: Listings

The listings management page provides a paginated table of all listings with filtering by status and category. Each row shows the listing title, author, category, status badge, price, view count, message count, report count, and creation date.

GET /admin/classified/listings
Query Parameters
statusFilter by status (draft, pending_review, published, expired, rejected, sold)
category_idFilter by category ID

Create & Edit

The listing form includes fields for:

  • Content: Title (translatable), content/description (translatable), meta title, meta description
  • Classification: Category selection, item condition (new, used, refurbished)
  • Pricing: Price, currency, negotiable flag
  • Location: City, region, country, address, latitude/longitude
  • Contact: Contact name, email, phone
  • Media: Featured image + gallery images (up to max configured)
  • Custom Fields: Dynamic fields loaded based on the selected category (via AJAX)
  • Status: Draft, pending review, published (admin can bypass moderation)
  • Options: Featured toggle, expiration date, position
GET /admin/classified/listings/create

Listing creation form.

POST /admin/classified/listings

Store a new listing. Validated via Admin\StoreListingRequest. Handles image uploads and custom field values.

GET /admin/classified/listings/{listing}/edit

Edit form for an existing listing.

PUT /admin/classified/listings/{listing}

Update an existing listing. Supports replacing the featured image, adding/removing gallery images, and updating custom field values.

DELETE /admin/classified/listings/{listing}

Delete a listing and all associated media, custom field values, messages, reports, and saved entries (via cascade).

Moderation

When moderation is enabled, new listings are set to pending_review status. Admins can approve or reject them:

POST /admin/classified/listings/{listing}/approve

Sets the listing status to published, records the publication date, and clears any rejection reason. Sends an approval notification to the author (if enabled).

POST /admin/classified/listings/{listing}/reject
Request Body
reasonRequired: the rejection reason (sent to the author via email)

Admin: Categories

Classified categories use the core unified categories table with categorizable_type = 'listing'. Categories support nesting (parent/child hierarchy via nested set) and are translatable.

GET /admin/classified/categories

Paginated nested tree view of all listing categories.

POST /admin/classified/categories

Create a new category. Validated via StoreCategoryRequest. Fields: name (translatable), slug (translatable), description (translatable), meta title, meta description, parent category, position, active status.

PUT /admin/classified/categories/{category}

Update a category and rebuild the nested set tree.

DELETE /admin/classified/categories/{category}

Delete a category. Listings in the deleted category will have their category_id set to null.

Admin: Custom Fields

Custom fields allow you to extend listings with category-specific or global attributes. Fields can be marked as filterable (shown in search filters) and searchable (included in full-text search).

GET /admin/classified/custom-fields

Paginated list of all custom fields with category filter.

POST /admin/classified/custom-fields
Fields
nameTranslatable: field label
slugUnique identifier
typeOne of the 10 supported field types
category_idNullable: null means the field applies to all categories
placeholderTranslatable: placeholder text
help_textTranslatable: help text shown below the field
optionsJSON array: for select, checkbox, and radio types
is_requiredWhether the field is mandatory
is_filterableShow in search/filter sidebar
is_searchableInclude in full-text search
min_value / max_valueValidation bounds for numeric fields
positionDisplay order

Supported Field Types

Type Value Has Options? HTML Input
TexttextNo<input type="text">
TextareatextareaNo<textarea>
NumbernumberNo<input type="number">
SelectselectYes<select>
CheckboxcheckboxYes<input type="checkbox">
RadioradioYes<input type="radio">
DatedateNo<input type="date">
Price Rangeprice_rangeNo<input type="number">
URLurlNo<input type="url">
EmailemailNo<input type="email">
Dynamic Loading: Custom fields are loaded dynamically via AJAX when the user selects a category on the listing form. The endpoint GET /api/classified/custom-fields/{categoryId?} returns the relevant fields for that category (plus any global fields).

Admin: Messages

View all messages sent through listing contact forms. Messages can be filtered by read/unread status.

GET /admin/classified/messages

Paginated list of messages with sender, listing, date, and read status. Supports filtering by unread messages.

GET /admin/classified/messages/{message}

View message details. Automatically marks the message as read.

DELETE /admin/classified/messages/{message}

Delete a message permanently.

Admin: Reports

View and manage listing reports submitted by users. Reports include a reason (spam, inappropriate, fraud, wrong category, duplicate, or other) and an optional description.

GET /admin/classified/reports

Paginated list of reports with status filter (pending, reviewed, dismissed).

PUT /admin/classified/reports/{report}

Review a report: set status to reviewed or dismissed. Records the reviewer and review timestamp.

DELETE /admin/classified/reports/{report}

Delete a report permanently.

Report Reasons

Value Description
spamListing is spam or unsolicited advertising
inappropriateContent violates community guidelines
fraudSuspected fraudulent listing
wrong_categoryListing is in the wrong category
duplicateDuplicate of another listing
otherOther reason (user provides description)

Front-End: Browsing & Search

The public classifieds page shows published, non-expired listings ordered by featured status, publication date, and position. Visitors can filter and search listings using multiple criteria.

Search & Filter Options

Filter Parameter Description
Keyword SearchsearchFull-text search in title, content, city, and region
Categorycategory_idFilter by category
CitycityLocation-based filtering (LIKE match)
Price Minprice_minMinimum price threshold
Price Maxprice_maxMaximum price threshold
ConditionconditionItem condition (new, used, refurbished)
Guest Access: Browsing can be restricted to authenticated users only by setting guest_browse to false in the admin settings. When disabled, the ClassifiedGuestAccess middleware redirects unauthenticated visitors to the login page.

Category Browsing

Access via /classifieds/category/{slug}. Shows listings filtered by the specified category, with full search and filtering available within that category.

Front-End: Listing Detail

Access via /classifieds/{slug}. The listing detail page includes:

  • Full title, description, and custom field values
  • Image gallery (featured image + additional gallery images)
  • Price with currency formatting and negotiable indicator
  • Item condition badge
  • Location information (city, region, country, address)
  • Seller contact information
  • Contact form (for sending a message to the seller)
  • Save/unsave button (for authenticated users)
  • Report button (for authenticated users)
  • Related listings (same category or same city)
  • View count (incremented on each visit)

Front-End: Create & Edit Listings

Authenticated users can create and edit their own listings from the front-end. This feature can be disabled site-wide by setting allow_publishing to false.

GET /classifieds/create/new

Listing creation form. Requires authentication. Protected by CheckPublishingEnabled middleware.

POST /classifieds/create/new

Submit a new listing. Validated via Front\StoreListingRequest. When moderation is enabled, the listing is set to pending_review and requires admin approval.

GET /classifieds/{listing}/edit

Edit form for a listing. Only the listing owner can access this page.

PUT /classifieds/{listing}/edit

Update a listing. Validated via Front\UpdateListingRequest.

Moderation: When moderation is enabled, newly created listings are automatically set to pending_review status (even if the user selects “published”). Only admin-created listings or admin-approved listings bypass moderation.

Front-End: My Listings

Access via /classifieds/my/listings. Authenticated users can view all their listings with status-based tabs: all, active, pending, expired, sold, and draft.

From this page, users can:

  • View listing status and message count
  • Edit their listings
  • Delete their listings
DELETE /classifieds/{listing}

Delete a listing. Only the listing owner can perform this action.

Front-End: Saved Listings

Access via /classifieds/my/saved. Users can bookmark listings and view them later from a dedicated saved listings page.

POST /classifieds/{listing}/save

Toggle save/unsave for a listing. Returns whether the listing is now saved (true) or unsaved (false). Works as an AJAX toggle.

Feature Toggle: The favorites feature can be disabled entirely by setting enable_favorites to false in admin settings.

Front-End: Contact Seller

Each listing detail page includes a contact form that sends a message to the listing owner.

POST /classifieds/{listing}/contact
Request Body
sender_nameRequired: sender’s name
sender_emailRequired: sender’s email
sender_phoneOptional: sender’s phone
messageRequired: the message body

Guest contact can be controlled via the guest_contact setting. When disabled, only authenticated users can send messages.

Front-End: Reporting

Authenticated users can report listings that violate community guidelines.

POST /classifieds/{listing}/report
Request Body
reasonRequired: one of: spam, inappropriate, fraud, wrong_category, duplicate, other
descriptionOptional: additional details about the report

Notifications

The add-on includes 7 email notification classes, all extending BaseNotification and using the mail channel. Each notification can be individually toggled via admin settings.

Notification Recipient Trigger Setting
NewListingAdminNotification Admin users New listing submitted notify_admin_on_new_listing
ListingConfirmationNotification Listing author Listing submitted notify_author_on_new_listing
ListingApprovedNotification Listing author Listing approved by admin notify_author_on_approval
ListingRejectedNotification Listing author Listing rejected by admin notify_author_on_rejection
NewMessageNotification Listing owner New contact message received notify_owner_on_new_message
ListingReportedNotification Admin users Listing reported by a user notify_admin_on_report
ListingExpiredNotification Listing owner Listing expires notify_owner_on_expiration
Fallback: If a listing has no associated user (e.g., deleted user), notifications are sent to the contact_email address on the listing using on-demand notification routing.

Updating

Step 1: Replace Files

Replace the add-on directory with the new version.

Step 2: Run Migrations

Step 3: Clear Caches

Step 4: Verify

Visit Admin → Classified Ads → Settings and confirm all settings are intact. Browse the classifieds page to verify listings display correctly.

Backup first: Always back up your database before running migrations on a production system.

Troubleshooting

Listings not visible on the front-end

Check that:

  • The listing status is published (not draft, pending, expired, rejected, or sold).
  • The published_at date is in the past.
  • The expires_at date is either null or in the future.
  • Guest browsing is enabled if you are not logged in (check guest_browse setting).

Users cannot create listings

  • Ensure allow_publishing is set to true in admin settings.
  • Verify the user is authenticated (listing creation requires login).
  • Check the CheckPublishingEnabled middleware is not blocking access.

Custom fields not appearing on the listing form

  • Ensure the custom field is active (is_active = true).
  • Verify the field is either global (category_id = null) or assigned to the selected category.
  • Check the browser console for AJAX errors on the /api/classified/custom-fields/ endpoint.
  • Ensure JavaScript is enabled and the category select element triggers the AJAX call.

Listings stuck in “Pending Review”

  • Moderation is enabled by default. Go to Admin → Classified Ads → Listings and approve pending listings.
  • To disable moderation, set moderation_enabled to false in admin settings. New listings will be published immediately.

Notifications not being sent

  • Verify the corresponding notification setting is enabled (e.g., notify_admin_on_new_listing).
  • Ensure your mail configuration is correct in .env (SMTP, Mailgun, etc.).
  • Check the Laravel log (storage/logs/laravel.log) for mail errors.
  • If the listing has no associated user, ensure the contact_email is set on the listing for fallback delivery.

Expired listings still showing

  • The expireOldListings() method in ClassifiedService must be called to update status. This should be scheduled as a cron job or artisan command.
  • Listings with expires_at in the past are automatically excluded from the active() scope, but their status field is only updated when the expiration process runs.

Images not uploading

  • Check PHP’s upload_max_filesize and post_max_size settings.
  • Verify the storage directory is writable.
  • Ensure you have not exceeded the max_images limit configured in admin settings.

Category listing counts incorrect

  • Listing counts are computed dynamically via withCount. If counts seem stale, clear the application cache: php artisan cache:clear.

Save/favorite toggle not working

  • Ensure the user is authenticated (saving requires login).
  • Verify enable_favorites is set to true in admin settings.
  • Check the browser console for AJAX errors on the toggle endpoint.
  • Ensure the CSRF token is included in the request headers.

Was this article helpful?

Thank you for your feedback!

Still need help? Create a support ticket

Create a Ticket