{"id":49,"date":"2026-04-30T23:15:55","date_gmt":"2026-04-30T23:15:55","guid":{"rendered":"https:\/\/docs.fasterthemes.com\/best-classifieds-wordpress-theme\/2026\/04\/30\/frontend-submission\/"},"modified":"2026-04-30T23:15:55","modified_gmt":"2026-04-30T23:15:55","slug":"frontend-submission","status":"publish","type":"post","link":"https:\/\/docs.fasterthemes.com\/best-classifieds-wordpress-theme\/2026\/04\/30\/frontend-submission\/","title":{"rendered":"Frontend Submission"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\">Frontend Submission <em>[Pro]<\/em><\/h1>\n\n\n<p>The frontend submission form lets logged-in members post listings without entering the WordPress admin. This is the heart of a self-service marketplace.<\/p>\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p><strong>Pro feature.<\/strong> The free theme has no frontend submission \u2014 listings are admin-only.<\/p><\/blockquote>\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n<h2 class=\"wp-block-heading\">The shortcode<\/h2>\n\n\n<pre class=\"wp-block-code\"><code>[bc_submit_listing]<\/code><\/pre>\n\n\n<p>Drop this into any page. The WOW Feeder creates <code>\/post-a-listing\/<\/code> with this shortcode pre-filled.<\/p>\n\n\n<p>The shortcode renders a multi-step form:<\/p>\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Category<\/strong> \u2014 pick a sub-category. Custom fields adjust to the choice.<\/li>\n<li><strong>Details<\/strong> \u2014 title, description, price, location, condition.<\/li>\n<li><strong>Photos<\/strong> \u2014 drag-drop up to 8 images (configurable).<\/li>\n<li><strong>Custom fields<\/strong> \u2014 category-specific (cars: make\/model\/year; property: bedrooms\/sqft).<\/li>\n<li><strong>Contact<\/strong> \u2014 email, phone (defaults to the user&#8217;s profile).<\/li>\n<li><strong>Package<\/strong> \u2014 free or paid (if packages are configured).<\/li>\n<li><strong>Review &#038; submit<\/strong> \u2014 preview before publishing.<\/li>\n<\/ol>\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n<h2 class=\"wp-block-heading\">Configuration<\/h2>\n\n\n<p><strong>Classifieds Pro \u2192 Settings \u2192 Submission<\/strong>:<\/p>\n\n\n<figure class=\"wp-block-table\"><table>\n<thead><tr>\n<th>Setting<\/th>\n<th>Default<\/th>\n<th>Notes<\/th>\n<\/tr><\/thead><tbody>\n<tr>\n<td><strong>Submit page<\/strong><\/td>\n<td><code>\/post-a-listing\/<\/code><\/td>\n<td>The page with the shortcode. Auto-populates from the WOW Feeder.<\/td>\n<\/tr>\n<tr>\n<td><strong>Require login<\/strong><\/td>\n<td>On<\/td>\n<td>If off, anonymous users get a &#8220;log in to post&#8221; prompt. We don&#8217;t recommend turning this off \u2014 anonymous listings are a spam magnet.<\/td>\n<\/tr>\n<tr>\n<td><strong>Require approval<\/strong><\/td>\n<td>Off<\/td>\n<td>If on, all submissions go to <strong>Pending<\/strong> status. Review at <strong>Classifieds Pro \u2192 Pending Listings<\/strong>.<\/td>\n<\/tr>\n<tr>\n<td><strong>Max images per listing<\/strong><\/td>\n<td>8<\/td>\n<td>1\u201312 supported. More than 8 makes the form heavy.<\/td>\n<\/tr>\n<tr>\n<td><strong>Max image size (MB)<\/strong><\/td>\n<td>5<\/td>\n<td>Server upload limit overrides this if lower.<\/td>\n<\/tr>\n<tr>\n<td><strong>Allowed image formats<\/strong><\/td>\n<td>JPG, PNG, WebP<\/td>\n<td>HEIC support coming soon.<\/td>\n<\/tr>\n<tr>\n<td><strong>Max title length<\/strong><\/td>\n<td>80<\/td>\n<td>Spam preventer.<\/td>\n<\/tr>\n<tr>\n<td><strong>Min description length<\/strong><\/td>\n<td>50<\/td>\n<td>Quality preventer.<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n<h2 class=\"wp-block-heading\">What sellers see<\/h2>\n\n\n<svg viewBox=\"0 0 720 320\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"max-width:100%;height:auto;display:block;margin:1rem auto;font-family:system-ui,sans-serif;\">\n  <rect x=\"20\" y=\"20\" width=\"680\" height=\"40\" rx=\"6\" fill=\"#fff\" stroke=\"#cbd5e1\"\/>\n  <circle cx=\"50\" cy=\"40\" r=\"14\" fill=\"#0F4C3A\"\/>\n  <text x=\"50\" y=\"44\" text-anchor=\"middle\" font-size=\"11\" fill=\"#fff\" font-weight=\"700\">1<\/text>\n  <text x=\"78\" y=\"44\" font-size=\"11\" fill=\"#1a1a1a\" font-weight=\"600\">Category<\/text>\n\n  <line x1=\"160\" y1=\"40\" x2=\"200\" y2=\"40\" stroke=\"#94a3b8\" stroke-width=\"1\" stroke-dasharray=\"3,3\"\/>\n\n  <circle cx=\"220\" cy=\"40\" r=\"14\" fill=\"#0F4C3A\"\/>\n  <text x=\"220\" y=\"44\" text-anchor=\"middle\" font-size=\"11\" fill=\"#fff\" font-weight=\"700\">2<\/text>\n  <text x=\"248\" y=\"44\" font-size=\"11\" fill=\"#1a1a1a\" font-weight=\"600\">Details<\/text>\n\n  <line x1=\"320\" y1=\"40\" x2=\"360\" y2=\"40\" stroke=\"#94a3b8\" stroke-width=\"1\" stroke-dasharray=\"3,3\"\/>\n\n  <circle cx=\"380\" cy=\"40\" r=\"14\" fill=\"#0F4C3A\" opacity=\"0.5\"\/>\n  <text x=\"380\" y=\"44\" text-anchor=\"middle\" font-size=\"11\" fill=\"#fff\" font-weight=\"700\">3<\/text>\n  <text x=\"408\" y=\"44\" font-size=\"11\" fill=\"#5a6f84\">Photos<\/text>\n\n  <line x1=\"460\" y1=\"40\" x2=\"500\" y2=\"40\" stroke=\"#94a3b8\" stroke-width=\"1\" stroke-dasharray=\"3,3\"\/>\n\n  <circle cx=\"520\" cy=\"40\" r=\"14\" fill=\"#cbd5e1\"\/>\n  <text x=\"520\" y=\"44\" text-anchor=\"middle\" font-size=\"11\" fill=\"#fff\" font-weight=\"700\">4<\/text>\n  <text x=\"548\" y=\"44\" font-size=\"11\" fill=\"#5a6f84\">Fields<\/text>\n\n  <line x1=\"600\" y1=\"40\" x2=\"640\" y2=\"40\" stroke=\"#94a3b8\" stroke-width=\"1\" stroke-dasharray=\"3,3\"\/>\n\n  <circle cx=\"660\" cy=\"40\" r=\"14\" fill=\"#cbd5e1\"\/>\n  <text x=\"660\" y=\"44\" text-anchor=\"middle\" font-size=\"11\" fill=\"#fff\" font-weight=\"700\">5<\/text>\n\n  <rect x=\"20\" y=\"80\" width=\"680\" height=\"220\" rx=\"6\" fill=\"#FAFAF7\" stroke=\"#cbd5e1\"\/>\n  <text x=\"40\" y=\"108\" font-size=\"13\" font-weight=\"700\" fill=\"#1a1a1a\">Step 2: Details<\/text>\n\n  <text x=\"40\" y=\"140\" font-size=\"11\" fill=\"#5a6f84\">Title<\/text>\n  <rect x=\"40\" y=\"148\" width=\"640\" height=\"32\" rx=\"4\" fill=\"#fff\" stroke=\"#cbd5e1\"\/>\n\n  <text x=\"40\" y=\"200\" font-size=\"11\" fill=\"#5a6f84\">Description<\/text>\n  <rect x=\"40\" y=\"208\" width=\"640\" height=\"60\" rx=\"4\" fill=\"#fff\" stroke=\"#cbd5e1\"\/>\n\n  <rect x=\"540\" y=\"278\" width=\"140\" height=\"14\" rx=\"0\" fill=\"none\"\/>\n  <text x=\"40\" y=\"290\" font-size=\"10\" fill=\"#5a6f84\">50 \/ 1000 characters<\/text>\n<\/svg>\n\n\n<p>The form is mobile-friendly with touch-sized inputs and a clear progress indicator.<\/p>\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n<h2 class=\"wp-block-heading\">Categories drive the form<\/h2>\n\n\n<p>Picking a category in step 1 changes:<\/p>\n\n\n<ul class=\"wp-block-list\">\n<li>Which custom fields appear in step 4 (cars get make\/model\/year\/mileage; jobs get salary\/employment\/remote)<\/li>\n<li>Whether photos are required (services and jobs are usually fine without)<\/li>\n<li>Which package options are shown (some categories may have category-only packages)<\/li>\n<\/ul>\n\n\n<p>Categories are configured at <strong>Classifieds Pro \u2192 Settings \u2192 Categories<\/strong>. Each row controls:<\/p>\n\n\n<figure class=\"wp-block-table\"><table>\n<thead><tr>\n<th>Column<\/th>\n<th>Purpose<\/th>\n<\/tr><\/thead><tbody>\n<tr>\n<td><strong>Slug<\/strong><\/td>\n<td>Matches the WP category slug<\/td>\n<\/tr>\n<tr>\n<td><strong>Custom fields<\/strong><\/td>\n<td>Which fields show in the form for this category<\/td>\n<\/tr>\n<tr>\n<td><strong>Photo required<\/strong><\/td>\n<td>If on, listings without photos can&#8217;t be submitted<\/td>\n<\/tr>\n<tr>\n<td><strong>Default package<\/strong><\/td>\n<td>Pre-selected on submission<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n<h2 class=\"wp-block-heading\">Submission flow<\/h2>\n\n\n<svg viewBox=\"0 0 720 200\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"max-width:100%;height:auto;display:block;margin:1rem auto;font-family:system-ui,sans-serif;\">\n  <rect x=\"20\" y=\"40\" width=\"120\" height=\"40\" rx=\"5\" fill=\"#FAFAF7\" stroke=\"#1E40AF\"\/>\n  <text x=\"80\" y=\"64\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\">Form submit<\/text>\n\n  <line x1=\"140\" y1=\"60\" x2=\"170\" y2=\"60\" stroke=\"#94a3b8\" stroke-width=\"1.5\"\/>\n  <polygon points=\"166,56 176,60 166,64\" fill=\"#94a3b8\"\/>\n\n  <rect x=\"170\" y=\"40\" width=\"130\" height=\"40\" rx=\"5\" fill=\"#FAFAF7\" stroke=\"#1E40AF\"\/>\n  <text x=\"235\" y=\"58\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\">Server validates<\/text>\n  <text x=\"235\" y=\"72\" text-anchor=\"middle\" font-size=\"9\" fill=\"#5a6f84\">required fields, length, files<\/text>\n\n  <line x1=\"300\" y1=\"60\" x2=\"330\" y2=\"60\" stroke=\"#94a3b8\" stroke-width=\"1.5\"\/>\n  <polygon points=\"326,56 336,60 326,64\" fill=\"#94a3b8\"\/>\n\n  <rect x=\"330\" y=\"40\" width=\"130\" height=\"40\" rx=\"5\" fill=\"#FAFAF7\" stroke=\"#1E40AF\"\/>\n  <text x=\"395\" y=\"58\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\">Package picked?<\/text>\n  <text x=\"395\" y=\"72\" text-anchor=\"middle\" font-size=\"9\" fill=\"#5a6f84\">Free vs Paid<\/text>\n\n  <line x1=\"460\" y1=\"60\" x2=\"490\" y2=\"60\" stroke=\"#94a3b8\" stroke-width=\"1.5\"\/>\n  <polygon points=\"486,56 496,60 486,64\" fill=\"#94a3b8\"\/>\n\n  <rect x=\"490\" y=\"20\" width=\"130\" height=\"40\" rx=\"5\" fill=\"#FAFAF7\" stroke=\"#10b981\"\/>\n  <text x=\"555\" y=\"38\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\">Free \u2192 Publish<\/text>\n  <text x=\"555\" y=\"52\" text-anchor=\"middle\" font-size=\"9\" fill=\"#5a6f84\">or pending<\/text>\n\n  <rect x=\"490\" y=\"70\" width=\"130\" height=\"40\" rx=\"5\" fill=\"#FAFAF7\" stroke=\"#D4582C\"\/>\n  <text x=\"555\" y=\"88\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\">Paid \u2192 Stripe<\/text>\n  <text x=\"555\" y=\"102\" text-anchor=\"middle\" font-size=\"9\" fill=\"#5a6f84\">or Razorpay popup<\/text>\n\n  <line x1=\"620\" y1=\"90\" x2=\"640\" y2=\"90\" stroke=\"#94a3b8\" stroke-width=\"1.5\"\/>\n  <line x1=\"640\" y1=\"90\" x2=\"640\" y2=\"160\" stroke=\"#94a3b8\" stroke-width=\"1.5\"\/>\n  <line x1=\"80\" y1=\"160\" x2=\"640\" y2=\"160\" stroke=\"#94a3b8\" stroke-width=\"1.5\"\/>\n  <polygon points=\"86,156 76,160 86,164\" fill=\"#94a3b8\"\/>\n\n  <text x=\"80\" y=\"180\" font-size=\"10\" fill=\"#5a6f84\" font-style=\"italic\">After payment success \u2192 publish or pending<\/text>\n<\/svg>\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n<h2 class=\"wp-block-heading\">Validation<\/h2>\n\n\n<p>Server-side validation runs even if the JS is bypassed. Required fields, length limits, file types, image dimensions are all checked. Validation errors return as inline messages above each field, plus a summary banner at the top of the form.<\/p>\n\n\n<p>To add custom validation rules:<\/p>\n\n\n<pre class=\"wp-block-code\"><code>add_filter( &#039;best_classifieds_submission_validate&#039;, function( $errors, $data ) {\n    \/\/ Block listings priced under $1\n    if ( ! empty( $data[&#039;_bc_price&#039;] ) &amp;&amp; (float) $data[&#039;_bc_price&#039;] &lt; 1 ) {\n        $errors[&#039;_bc_price&#039;] = &#039;Price must be at least $1.&#039;;\n    }\n    \/\/ Block listings with no contact info\n    if ( empty( $data[&#039;_bc_contact_email&#039;] ) &amp;&amp; empty( $data[&#039;_bc_contact_phone&#039;] ) ) {\n        $errors[&#039;_bc_contact_email&#039;] = &#039;Provide at least one contact method.&#039;;\n    }\n    return $errors;\n}, 10, 2 );<\/code><\/pre>\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n<h2 class=\"wp-block-heading\">Pre-publish hooks<\/h2>\n\n\n<p>Inject your own logic before\/after the listing is created:<\/p>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Modify post args before insert\nadd_filter( &#039;best_classifieds_submission_post_args&#039;, function( $args, $data ) {\n    \/\/ Auto-add a tag based on a custom field\n    $args[&#039;tax_input&#039;][&#039;post_tag&#039;] = array( &#039;frontend-submitted&#039; );\n    return $args;\n}, 10, 2 );\n\n\/\/ React after a successful submission\nadd_action( &#039;best_classifieds_after_submission&#039;, function( $post_id, $data ) {\n    \/\/ Send a Slack notification\n    wp_remote_post( &#039;https:\/\/hooks.slack.com\/...&#039;, array(\n        &#039;body&#039; =&gt; json_encode( array( &#039;text&#039; =&gt; &#039;New listing: &#039; . get_the_title( $post_id ) ) ),\n    ) );\n}, 10, 2 );<\/code><\/pre>\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n<h2 class=\"wp-block-heading\">Spam protection<\/h2>\n\n\n<p>Three layers (all on by default):<\/p>\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Honeypot field<\/strong> \u2014 hidden from real users, bots fill it. Submissions with a non-empty honeypot are silently discarded.<\/li>\n<li><strong>Time-trap<\/strong> \u2014 minimum 3 seconds between page load and submit. Bots fail this.<\/li>\n<li><strong>Rate limiting<\/strong> \u2014 same IP can submit at most 5 listings per hour. Configurable.<\/li>\n<\/ol>\n\n\n<p>For sites under heavy spam pressure, plug in:<\/p>\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Akismet<\/strong> \u2014 set the API key in WP General settings; submissions are automatically checked.<\/li>\n<li><strong>hCaptcha<\/strong> \u2014 install the plugin, the form auto-detects and adds the challenge.<\/li>\n<li><strong>Cloudflare Turnstile<\/strong> \u2014 same.<\/li>\n<\/ul>\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n<h2 class=\"wp-block-heading\">Editing existing listings<\/h2>\n\n\n<p>Members edit from their dashboard (<code>[bc_dashboard]<\/code> \u2192 &#8220;My listings&#8221; \u2192 click &#8220;Edit&#8221;). The submission form re-opens pre-populated with the existing data.<\/p>\n\n\n<p>To prevent edits to certain fields after publish:<\/p>\n\n\n<pre class=\"wp-block-code\"><code>add_filter( &#039;best_classifieds_submission_locked_fields&#039;, function( $locked, $post_id ) {\n    \/\/ Lock category and price after publish\n    return array_merge( $locked, array( &#039;category&#039;, &#039;_bc_price&#039; ) );\n}, 10, 2 );<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>The frontend submission form lets logged-in members post listings without entering the WordPress admin. This is the heart of a self-service marketplace.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-49","post","type-post","status-publish","format-standard","hentry","category-pro-features"],"_links":{"self":[{"href":"https:\/\/docs.fasterthemes.com\/best-classifieds-wordpress-theme\/wp-json\/wp\/v2\/posts\/49","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/docs.fasterthemes.com\/best-classifieds-wordpress-theme\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/docs.fasterthemes.com\/best-classifieds-wordpress-theme\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/docs.fasterthemes.com\/best-classifieds-wordpress-theme\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/docs.fasterthemes.com\/best-classifieds-wordpress-theme\/wp-json\/wp\/v2\/comments?post=49"}],"version-history":[{"count":0,"href":"https:\/\/docs.fasterthemes.com\/best-classifieds-wordpress-theme\/wp-json\/wp\/v2\/posts\/49\/revisions"}],"wp:attachment":[{"href":"https:\/\/docs.fasterthemes.com\/best-classifieds-wordpress-theme\/wp-json\/wp\/v2\/media?parent=49"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/docs.fasterthemes.com\/best-classifieds-wordpress-theme\/wp-json\/wp\/v2\/categories?post=49"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/docs.fasterthemes.com\/best-classifieds-wordpress-theme\/wp-json\/wp\/v2\/tags?post=49"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}