=== Ultimate Classified Listings – Classifieds, Directory & Marketplace ===
Contributors: webcodingplace
Tags: classifieds, directory, listings, classified ads, marketplace
Requires at least: 6.0
Tested up to: 7.0
Requires PHP: 7.4
Stable tag: 2.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Free classifieds & directory plugin with maps, frontend submission, AJAX search, packages-ready architecture and a hardened security model.

== Description ==

Ultimate Classified Listings is a responsive classifieds and directory plugin for WordPress. It ships nice, clean templates and built-in features like unlimited custom fields, gallery sliders + grids, advanced AJAX search and Google Maps or OpenStreetMap support out of the box.

It's also a full listing management system: register sellers, approve submissions, manage seller profiles, and run your own classifieds, jobs, real-estate, services or community marketplace.

= Why Ultimate Classified Listings =

* **Free where the leaders paywall** — maps, AJAX search, frontend submission and custom fields are all free.
* **Stable and secure** — A comprehensive security hardening pass: CSRF nonces on every AJAX endpoint, plaintext passwords no longer stored in options, email header injection closed, and rate limiting on auth flows.
* **Theme-friendly** — full template override system, works with any WordPress theme.
* **Multilingual ready** — WPML and Polylang aware.
* **Developer friendly** — 40+ hooks and filters, REST API support on the listing CPT.

= Core Features =

* Frontend listing submission with custom field sections
* Unlimited custom fields and field sections (drag-and-drop builder)
* Categories and tags with custom icons / images
* Gallery sliders and image grids
* AJAX-powered search with filters, price range and sort
* Google Maps **or** OpenStreetMap (Leaflet) with location markers
* Seller dashboard: add / edit / delete listings, profile management
* Two seller-registration modes: auto-approve or manual approval
* Two submission modes: publish immediately or pending review
* Listing comparison
* Contact-seller form with reCAPTCHA + email-injection protection
* Compare and share listings
* Full theme template overrides under `/your-theme/ucl/...`

= Quick Links =

- **[Live Demo](https://www.wpclassifiedlistings.com/demo/)**
- **[Documentation](https://www.wpclassifiedlistings.com/documentation/)**
- **[AJAX Search](https://www.wpclassifiedlistings.com/demo/search-listings-ajax/)**

== Installation ==

1. Navigate to the WordPress Dashboard -> Plugins -> Add New
2. Search for the Ultimate Classified Listings
3. Install and Activate
4. Now configure the settings from the Ultimate Classified Listings -> Settings

== Frequently Asked Questions ==

= Is this plugin free? =

Yes. The core plugin is free, including maps, AJAX search, frontend submission, and custom fields.

= Does it work with Elementor, Gutenberg or Divi? =

The plugin uses shortcodes that work in any builder. Native Gutenberg blocks are on the v3.0 roadmap.

= Do I need a Google Maps API key? =

No. The plugin ships OpenStreetMap via Leaflet by default. If you prefer Google Maps, you can add your API key in Settings.

= Can I let users pay to post listings? =

Built-in payment gateways are on the v3.0 roadmap. In v2.x you can use Settings → Submission Mode to require admin approval before listings are published.

= How are seller passwords stored? =

As of 2.0, passwords are no longer stored in plain text in `wp_options`. Newly registered users that require manual approval have their password hashed before storage. Legacy entries from prior versions will receive a one-time password reset email when approved.

= How does the plugin protect against CSRF? =

Every AJAX endpoint requires a nonce verified by `check_ajax_referer()`. Public requests use a dedicated public nonce and admin requests use a separate admin nonce, both rotated by WordPress.

= I'm migrating from another plugin. Is there a migration tool? =

Migration tools from Directorist, WP Adverts and Classified Listing are on the v3.x roadmap. For now you can use WP All Import/Export/

== Screenshots ==

1. Listings archive
2. Sections Manager
3. Fields Builder
4. Frontend Management

== Changelog ==

= 2.0 - 14 June 2026 =

- Bug fix: When the archive/search-results top bar was rendered (via `[uclwp_search_results top_bar="enable"]` or anywhere the `uclwp_archive_topbar` action fires) and a visitor changed the sort dropdown, the resulting URL kept only `sort_by` and `layout` and dropped every other active query arg — keywords, price range, custom-field filters, etc. The top bar now re-emits every other `$_GET` value as a hidden input inside the form (using PHP bracket notation for nested sub-arrays like `regular_price[min]`), so the sort round-trip preserves the active filter set. The grid/list switcher anchors already used `add_query_arg()` and were unaffected.
- Added: New helper `uclwp_flatten_query_args()` that flattens nested arrays into `name[sub][sub]` / value pairs suitable for hidden form inputs. Reusable from any template that needs to pass current GET state through a `<form method="GET">`.

= 1.16.0 =

- Feature: Two new single-listing styles. Pick one in Settings → Templates Settings → Single Listing Style. Style 1 (Classic, default) is the existing look. Style 2 (Card Stack) renders each section as a raised card with a coloured left rail and a chip-style heading — e-commerce / property-listing feel. Style 3 (Minimal) drops the card chrome entirely and separates sections with thin top dividers. Implemented as a body class (`ucl-listing-style-1/2/3`) added on single-listing pages; templates are unchanged so all theme overrides keep working.
- Feature: Price quick-pick chips are now editable from the admin. New "Price Quick-Pick Presets" textarea in Settings → Search Settings (right after Total Listings) — one numeric preset per line; each becomes a "Up to {price}" chip under the price range control in search styles 2 and 3. Leave blank to hide the chips entirely. Still filterable in code via `uclwp_search_price_chips`.
- Feature: `[uclwp_search_results]` now supports a `top_bar="enable"` attribute (default `disable`) that adds the same sort + grid/list switcher the `[uclwp_listings]` shortcode renders.
- Feature: Per-listing map zoom level is now saved. The admin metabox map writes the user-chosen zoom into a hidden `ucl_listing_zoom` input (Leaflet `zoomend` and Google `zoom_changed` events both wired up); both the admin metabox save path and the frontend create/edit handler persist it; the single-listing template reads it back and the map opens at exactly that zoom on the frontend.
- Improvement: Search style 2 polish — reduced cell min-height from 46px to 38px, button is now a properly sized pill (not a tall circle), inputs no longer have huge top/bottom padding. New `columns` shortcode attribute (1–6, default 4) controls how many secondary-field cells appear per row via CSS grid. Mobile collapses to 2 columns at ≤768px and 1 column at ≤480px.
- Bug fix: Card image aspect ratio (Settings → Listings → Card Image Aspect Ratio) was not being applied. The CSS selector keyed off `[style*="--ucl-card-image-ratio"]`, which never matched because the variable is emitted via an inline `<style>` tag, not the element's `style` attribute. The aspect-ratio rule now applies directly to `.uclwp-grid-box-wrap .uclwp-image` and `.uclwp-list-box-wrap .uclwp-image`, so all four card styles honour the chosen ratio.

= 1.15.0 =

- Feature: Two new search-form styles, selectable via `[uclwp_search_form style="2"]` and `[uclwp_search_form style="3"]`.
  - **Style 2 — Bar**: Compact horizontal pill bar with rounded inputs, designed to sit above an archive grid. Trulia/Zillow feel.
  - **Style 3 — Hero**: Tall hero panel with a prominent keyword box, neat secondary-field grid below, and a final CTA row with a "Clear filters" link. Designed to anchor landing or category-archive pages. Configurable heading + sub-heading via the new `search_form_heading` / `search_form_subheading` settings.
- Feature: New `uclwp_render_price_range_search()` helper renders a modern two-input price control with the currency symbol affixed inside each input, plus optional quick-pick chips ("Up to $100", "Up to $500", etc.). Used by styles 2 and 3. Preset chip values are filterable via `uclwp_search_price_chips`.
- Improvement: Equal-height listing cards. Cards within the same row now stretch to match the tallest neighbour and push price/CTA footer rows to the bottom, so grids look tidy even when titles/excerpts vary in length. Scoped to `.ucl-display-listings` so single-listing sidebars and the compare box are unaffected.
- Bug fix: `[uclwp_categories]` (and the underlying `render_category_image()`) no longer renders the saved Bootstrap-icon class. The previous wrapper produced `class="bi bi-{bi bi-house}"`, an invalid class that resolved to nothing. Output is now `class="bi bi-house"` (or the admin-set value). Categories with a saved icon will start rendering it immediately on update.
- Bug fix: Long seller email addresses were overflowing the contact box in the single-listing sidebar. The `<li>` rows now apply `overflow: hidden; text-overflow: ellipsis; white-space: nowrap;` and pick up the missing right padding so the email truncates inside the bordered chip.

= 1.14.2 =

- Bug fix: When creating a new listing in wp-admin, Leaflet threw `Invalid LatLng object: (undefined, undefined)` and the map widget failed to render. Root cause was the v1.14.1 admin-enqueue fix, which preloaded the frontend single-listing map script (`assets/js/location.js`) on the post-edit screen. That script expects a different localize payload (`ucl_location_settings.latitude/longitude`) than the metabox renderer provides (`ucl_map_settings.def_lat/def_long`), so its values came up undefined. The redundant enqueue has been removed — the location field renderer enqueues the correct script (`assets/fields/location.js`) on its own when the section actually renders.
- Bug fix: Belt-and-braces hardening of the location renderer so that even if a stored listing has empty latitude/longitude meta the JS still receives a numeric default (US geographic centre, 37.0902 / -95.7129). The previous longitude default lost its negative sign so the placeholder pin showed up in central Asia instead of Kansas.
- Bug fix: `Control.Geocoder.js` now declares `ucl-leaflet-js` as a dependency so the geocoder loads after Leaflet on the post-edit screen.

= 1.14.1 =

- Bug fix: The Listing Information metabox on the wp-admin post-edit screen (`post.php` / `post-new.php` for the `uclwp_listing` CPT) was rendering without Bootstrap CSS, the icon font, the iconpicker JS, the media uploader, or the map widget. The `load_admin_scripts()` enqueue gate previously matched only the plugin's own subpages (slug contained "uclwp"); it now also enqueues all required assets when the current admin screen's `post_type` is `uclwp_listing`. Bootstrap stays scoped to `.uclwp-bs-wrapper` so it does not affect the surrounding wp-admin UI.

= 1.14.0 =

Final WordPress.org Plugin Check pass — clears all reported errors for plugin-directory submission.

- Plugin name: Renamed to "Ultimate Classified Listings – Classifieds, Directory & Marketplace" so the readme title matches the plugin header and the word "Plugin" (a restricted term) is no longer part of the displayed name.
- Tested up to: bumped to 7.0 to match the current WordPress release as required by .org.
- Escaping: Wrapped the dynamic CSS variable block emitted by `assets/css/styles.php` through `wp_strip_all_tags()` after each value is individually escaped via `esc_attr()`, with phpcs:ignore annotations explaining why the final concatenation is safe.
- Escaping: `paginate_links()` output in `render_pagination()` now passes through `wp_kses_post()` before echoing.
- i18n: Added `/* translators: %s ... */` comments above two `printf( esc_html__( ... ), ... )` calls in the setup-wizard "next steps" panel that were missing them.
- Sanitization: Added `sanitize_text_field( wp_unslash( ... ) )` wrappers around `$_REQUEST['listing_id']` reads in `class-shortcodes.php delete_listing`, `class-email.php contact_seller`, `class-favorites.php ajax_toggle`, and `shortcodes/dashboard/edit.php`. The values are still validated through `uclwp_validate_listing_id()`.
- Sanitization: `$_SERVER['REQUEST_URI']` used to build the favorites login-redirect URL now passes through `esc_url_raw( wp_unslash( ... ) )` before `home_url()`.
- Sanitization: Recursive array inputs (`$_POST['uclwp_data']`, `$_REQUEST['sections']`, `$_REQUEST['fields']`) now have phpcs:ignore annotations documenting that each leaf is sanitized further down. The actual per-leaf sanitization was already in place.
- Sanitization: Login/register password reads carry phpcs:ignore annotations explaining why passwords must not be passed through `sanitize_text_field()` (would strip control characters needed for hash comparison).
- File uploads in seller registration carry phpcs:ignore annotations pointing to the nonce check at the top of the handler.

= 1.13.0 =

Second WordPress.org Plugin Check pass — addresses the warnings flagged by the official PCP tool that the manual sanitization audit missed.

- Plugin Check: Added `defined( 'ABSPATH' ) || exit;` guard to 32 files that didn't have one, including all template files, shortcode partials, admin subviews, the inc/arrays/ data files and assets/css/styles.php.
- Plugin Check: Replaced all `json_encode( $resp )` AJAX response calls with `wp_send_json( $resp )` so character encoding follows WP's UTF-8 conventions and the response is properly closed via `wp_die()`.
- Plugin Check: Replaced remaining non-AJAX `json_encode()` calls (Slick / image-grid data-attributes) with `wp_json_encode()`.
- Plugin Check: Added explicit `timeout` argument (10 s) to every `wp_remote_post()` call.
- Plugin Check: Added `rel="noopener noreferrer"` to every `target="_blank"` link in the admin settings help text, the post-update messages, and the setup-wizard "next steps" panel.
- Plugin Check: Removed `load_plugin_textdomain()` — WordPress 4.6+ loads translations automatically for plugins hosted on .org and the call is now flagged as discouraged.
- Plugin Check: Replaced bare `die();` / `die(0);` with `wp_die();` in AJAX handlers.
- Plugin Check: Added missing version arguments to every `wp_enqueue_style` / `wp_enqueue_script` call (used `UCLWP_VERSION` for bundled assets and `null` for third-party CDN scripts whose URL already carries a version key).
- Plugin Check: Renamed three filters that were missing the plugin prefix: `no_results_message` → `uclwp_no_results_message`, `seller_contact_email_message` → `uclwp_seller_contact_email_message`, `raw_uclwp_price` → `uclwp_raw_price`, `formatted_uclwp_price` → `uclwp_formatted_price`.
- Plugin Check: Removed nested `esc_attr( sanitize_text_field( … ) )` double-escape pattern in the search-form field renderer; the value is now sanitized once on input and the existing `esc_attr()` at output point handles HTML-attribute escaping.
- Plugin Check: Google-Maps script URL now built via `add_query_arg()` instead of string concatenation, and routed through HTTPS unconditionally.
- Plugin Check: Direct `$wpdb->update()` call in seller-approve flow now has type-specifier arrays for $where and $data and a justification comment explaining why the WP user-API helpers can't be used (the password is already hashed).

= 1.12.0 =

This release is a full sanitization + escaping pass for WordPress.org plugin review compliance. No behaviour changes; every output path is now explicitly escaped and every input path is unslash + sanitized.

- Sanitization: All `$_GET` / `$_POST` / `$_REQUEST` access across the plugin now runs through `wp_unslash()` before sanitization, matching WordPress core conventions and `WPCS` requirements.
- Escaping: Replaced `esc_attr_e()` / `esc_attr__()` with the correct `esc_html_e()` / `esc_html__()` everywhere the output is HTML body content (labels, table cells, headings, paragraph text). Attribute-context calls (`placeholder=""`, `title=""`, `value=""`, `data-*=""`) remain `esc_attr_e()`.
- Escaping: Replaced `esc_attr()` with `esc_html()` on user-controlled body text — listing titles, seller names, emails, phone numbers, category names, etc.
- Escaping: Textarea content now uses `esc_textarea()` instead of `esc_attr()`.
- Bugfix: `compare-box.php` printed nothing for compare table column headers due to `esc_attr( $label )` (which returns instead of echoing). Now properly `echo esc_html( $label )`.
- Hardening: Removed the second hardcoded reCAPTCHA fallback key in `templates/sidebar/default.php`. CAPTCHA now fails closed when not configured.
- Hardening: `gdpr_message` setting in the contact-seller form is now output via `wp_kses_post()` so admins can include safe HTML formatting (was `esc_attr()` which broke the HTML).
- Hardening: Search query builder (`uclwp_get_search_query`) sanitizes all dynamic `orderby`, `meta_key`, `tag`, and `range` inputs and validates against an allow-list before passing to `WP_Query`.
- Hardening: HTML emails (contact-seller) now `esc_html()` user-controlled fields (client name, email, phone, message, listing title) before HTML interpolation.
- Hardening: Compare AJAX listing IDs cast through `absint()`; meta_key segments through `sanitize_key()`.
- Hardening: `class-shortcodes::update_profile` casts and unslashes every `$_REQUEST` field.
- Hardening: Term-meta image/icon callbacks (`save_category_image`, `updated_category_image`) now check `current_user_can('manage_categories')` and `wp_unslash()` the inputs (core verifies the nonce upstream on the term-edit screen).
- Hardening: Dashboard "My Listings" search query reads `$_GET['uclwp_status']` through an enum allow-list (`publish`, `pending`, `draft`, `future`, `any`).
- Compatibility: `selected()` and `selected( $a, $b )` used in place of inline `($a == $b) ? 'selected' : ''` ternaries where the markup allowed it.
- Compatibility: `(int) $cat->count` and `(int) count_user_posts(...)` casts in `page-sellers.php` and other admin lists in place of `esc_attr()` on integers.

= 1.11.0 =

- Feature: Modern field rendering. Custom fields on single-listing pages now render as icon + label + value cards by default, using each field's saved icon (from the Fields Builder). Two additional display modes are available — "List" (definition-list rows) and "Inline" (compact icon pills). Choose via Settings → Listings → Field Display on Single Listing Pages.
- Feature: Card meta strip redesigned as inline icon pills with the field's icon, replacing the previous flat title-pipe-value rows. Customize which fields appear via the new Card Meta Fields setting (comma-separated keys).
- Feature: Checkbox / features fields now render as accent-coloured chips with check icons, instead of plain bulleted text.
- Feature: Favorites (save listings). Adds a heart button to every listing card. Saved listings are stored per-user and viewable via the new "Saved Listings" item in the seller dashboard or the `[uclwp_favorites]` shortcode. Toggle the feature in Settings → Listings → Favorites.
- Feature: Dark mode. Five options — Off, Auto (follow OS), Toggle (manual button in top-bar), Auto + Toggle, and Force. Six dark-mode colour overrides for surface, card background, card border, heading, body and muted text.
- Improvement: Field-display helpers now resolve safely when a value is empty so cards never render orphan labels.
- Improvement: `uclwp_listing_action_buttons` filter added so add-ons can inject extra card buttons without forking templates.
- Improvement: `uclwp_dashboard_allowed_pages` filter added.

= 1.10.0 =

- Feature: Three new listing card styles. Style 2 — Minimal (flat, bordered, generous whitespace), Style 3 — Bold Overlay (full-bleed image with gradient and meta overlaid), Style 4 — Compact / Magazine (dense layout with prominent CTA). Each ships with both a grid and a list variant. Switch globally from Listings → Listing Card Style, or per-shortcode via `[uclwp_listings style="3"]`.
- Feature: 14 new colour controls under Colors and CSS — Primary, Primary Hover, Secondary, Accent, Heading, Body Text, Muted Text, Card Background, Card Border, Surface, Price, Badge Background, Badge Text, Button Background/Text/Hover. Each is emitted as a CSS custom property on `.uclwp-bs-wrapper` so themes and custom CSS can override them too.
- Feature: Card Corner Radius setting (0–64px).
- Feature: Card Image Aspect Ratio setting (Original / 4:3 / 16:9 / 1:1 / 3:4) — useful when seller-uploaded images vary in dimensions.
- Compat: Existing installs see no visual change. The legacy two-colour palette (Primary / Secondary Color) is preserved and used as the fallback when the new individual settings are blank.

= 1.9.0 =

- Feature: Setup wizard. A short, dismissible welcome screen guides new installs through site type, page creation (Listings, Search, Categories, Seller Dashboard), currency, map provider and submission workflow. Triggered on activation and surfaced via a one-line admin notice until completed.
- Feature: Auto-create essential pages with the correct shortcodes pre-inserted.
- Feature: Polite, non-blocking "leave a review" prompt. Appears only after 7 days + 3 published listings, with Remind Later (14 days) and Permanent Dismiss options.
- Improvement: Admin classes now load only in `is_admin()` context to reduce frontend overhead.

= 1.8.0 =

This is a **major security hardening release**. All sites should update.

- Security: Added CSRF nonce verification to every public AJAX endpoint (`uclwp_search_listing`, `uclwp_seller_login`, `uclwp_seller_register`, `uclwp_create_listing_frontend`, `uclwp_delete_listing`, `uclwp_contact_seller`, `uclwp_compare_listings`).
- Security: Added CSRF nonce verification to admin AJAX endpoints (`uclwp_save_field_sections`, `uclwp_save_custom_fields`, `uclwp_reset_custom_fields`, `wcp_uclwp_save_settings`, `ucl_deny_seller`, `ucl_approve_seller`).
- Security: Pending-seller passwords are no longer stored in plaintext in `wp_options`. New registrations store only a salted hash; legacy entries are routed through the standard password-reset flow on approval.
- Security: Fixed email header injection in the contact-seller form. From: header now sanitized via a dedicated helper, newlines stripped from name, Reply-To added, Cc recipients individually validated.
- Security: Removed the hardcoded reCAPTCHA secret-key fallback. CAPTCHA verification now fails closed when not configured.
- Security: Replaced unvalidated `$_SERVER['REMOTE_ADDR']` use with `filter_var(... FILTER_VALIDATE_IP)`.
- Security: Listing IDs in delete and edit flows are now validated against the `uclwp_listing` post type and authorized via `current_user_can('edit_post'|'delete_post', $id)` instead of manual ownership checks.
- Security: Pending-seller `userindex` is cast to integer and validated against existing keys before use.
- Security: Permalink-settings save path now requires the core `update-permalink` nonce.
- Security: Added transient-based rate limiting on login, registration and contact-seller endpoints.
- Security: Asset URLs now include `UCLWP_VERSION` for cache busting after security updates.
- Bumped minimum WordPress to 6.0 and minimum PHP to 7.4.
- License header reconciled to GPLv2-or-later.

= 1.7 =

- Bug Fixed: Security related issues

= 1.6 =

- Bug Fixed: Security related issues

= 1.5 =

- Bug Fixed: Security issues fixes, notified by Wordfence

= 1.4 =

- Feature Added: Ability to choose category from the frontend
- Feature Added: Ability to assign tags from the frontend
- Bug Fixed: Empty categories are not displaying
- Bug Fixed: Security issues fixes, notified by WPScan Team

= 1.3 =

- Bug Fixed: Security issues fixes, notified by WPScan Team

= 1.2 =

- Bug Fixed: Iframes not saving from frontend

= 1.1 =

- Feature Added: Iframes support in the shortcode field

= 1.0.0 =

- Initial Release

== Upgrade Notice ==

= 2.0 =
Fixes the archive top bar wiping active search filters when the sort dropdown changes. Strongly recommended for anyone using [uclwp_search_results top_bar="enable"].

= 1.16.0 =
Adds two new single-listing styles, admin-editable price chips, a top bar option on [uclwp_search_results], per-listing map zoom persistence, a columns attribute on search style 2, and a fix for the card image aspect-ratio setting that wasn't applying.

= 1.15.0 =
Adds two new search-form styles (Bar + Hero) with a modern price-range control. Fixes equal-height grid cards, the empty category icon, and overflowing seller emails in the sidebar.

= 1.14.2 =
Fixes the "Invalid LatLng object" Leaflet error when creating a new listing in wp-admin, introduced by the 1.14.1 metabox-assets fix. Strongly recommended for anyone on 1.14.1.

= 1.14.1 =
Bug fix: restores Bootstrap CSS, icons, media uploader and map on the wp-admin Listing Information metabox. No behaviour change anywhere else.

= 1.14.0 =
Release-candidate compliance pass — clears all Plugin Check errors for WordPress.org submission (escape on dynamic CSS, paginate_links output, translator comments, Tested up to 7.0, plugin name rules). No behaviour change.

= 1.13.0 =
Second WordPress.org Plugin Check compliance pass. Adds ABSPATH guards everywhere, wp_send_json/wp_json_encode adoption, wp_remote timeout, rel="noopener noreferrer" on target=_blank links, removes deprecated load_plugin_textdomain, prefixes orphan filters. No behaviour change.

= 1.12.0 =
Full sanitization and escaping audit for WordPress.org plugin review compliance. Fixes one display bug in the compare-listings table; removes a second hardcoded reCAPTCHA fallback key; no breaking changes.

= 1.11.0 =
Field display redesigned on single pages and cards (icon + label + value cards, definition lists, or inline pills). Adds Favorites and Dark Mode. Visually backward-compatible — the new "cards" display becomes the default on single-listing pages.

= 1.10.0 =
Adds three new listing card styles (Minimal, Bold Overlay, Compact), a 14-colour palette wired through CSS variables, card radius and image aspect-ratio settings. Visually backward-compatible.

= 1.9.0 =
Adds a setup wizard, auto-page creation, and a polite review prompt. Builds on the 1.8.0 security hardening.

= 1.8.0 =
Major security hardening release. Adds CSRF protection to every AJAX endpoint, removes plaintext password storage, fixes email header injection, and rate-limits authentication. All sites should update.
