Threshold Plugins

Threshold Filterable Portfolio

Tag each photo with the groups you define, drop one shortcode on a page, and visitors narrow the grid with filters that live in the address bar. Six filter-bar layouts, a lightbox, and an Appearance tab. No page builder required.

  • Version 1.0.0
  • Updated November 6, 2026
  • WordPress 6.0+
  • PHP 7.4+
  • GPL-2.0-or-later
A website showing a grid of photos with a row of filter chips above it

Why I built Filterable Portfolio

A client wanted a photo gallery filtered by the kind of work, the room, and the town, with a slice of it on every town page. The gallery plugins I tried either needed a page builder, charged for filters, or loaded a framework to hide a few pictures. The job is small: tag photos, draw a grid, hide what does not match. So I wrote the small one, and made the groups configurable so it works for any portfolio.

Your own filter groups

Treatment, Room, Town, Brand out of the box; rename them, nest them, or add your own. Every group is a checkbox box on the photo, never free typing.

Six filter-bar layouts

Stacked groups, a scrolling row, dropdowns, a primary row with Refine, a sidebar, or a drawer. Put them all on one test page and let the client pick.

Filters you can link to

The chosen filters live in the page address, so a button on a town page can open the portfolio already narrowed to that town, and the back button works.

Styled from the admin

Colors, chip shape, thumbnail shape, and spacing on an Appearance tab, written as CSS variables so your theme is never touched.

Filterable Portfolio is free software, licensed under GPL-2.0-or-later, like WordPress itself.

User guide

Everything lives under Portfolio in the WordPress admin menu. Each Settings tab has its own Save button; saving one tab never changes another.

Getting started

  1. Upload the plugin ZIP on Plugins → Add New → Upload Plugin and activate it. A Portfolio menu appears.
  2. Open Portfolio → Settings → Filter Groups. Four groups come ready: Treatment, Room, Town, and Brand. Rename them, remove them, or add your own.
  3. Add a few photos under Portfolio → Add New.
  4. Put [tfp_portfolio] on a page. That is the whole portfolio with its filter bar.

Decide your groups first

A group’s key becomes part of the database name for its terms. Labels can change at any time, but changing a key after photos are tagged disconnects them from their terms. Settle the keys before you tag a hundred photos.

Adding photos

Every entry is one photo with a title. On Portfolio → Add New:

  • Title shows under the thumbnail and in the lightbox.
  • Photo (the Featured Image box) is the image itself. Upload at least 1600 pixels wide; the grid shows a 640 × 480 crop and the lightbox shows the large size.
  • Excerpt is the optional caption shown in the lightbox after the title.
  • Each filter group is a box of checkboxes. Tick every term that applies; a photo can carry several.
  • Order (in the attributes box) sorts the grid under the default sort; lower numbers come first, ties fall back to the newest date.

Photos without a featured image never appear in the grid, so a draft entry can be finished later.

Filter groups

Portfolio → Settings → Filter Groups defines the groups. Rows run top to bottom in the same order as the filter bar; use the arrows to reorder.

Group settings
ColumnWhat it does
KeyShort and lowercase: letters, digits, dashes, or underscores, up to 20. It is the shortcode attribute (town="avalon") and the address parameter (?town=avalon). Words WordPress itself reads from the address (page, name, s, order, and so on) are refused with a notice.
Label (singular / plural)What visitors and editors see: the filter heading, the checkbox box title, and the admin submenu.
NestedLets terms have parents, for example Jersey Shore → Avalon. A photo tagged Avalon also matches Jersey Shore.
In filter barUntick to tag photos with a group without offering it as a filter; handy for a group you only use in shortcodes.
In captionPrints the photo’s terms from this group under the thumbnail, separated by dots.
Bar showsFor nested groups: list only the parents in the filter bar (short and tidy) or every term.

Terms are managed like categories, under the group’s own submenu (for example Portfolio → Towns) or by ticking new ones on a photo. The filter bar only lists terms that have at least one visible photo, so a filter never leads to an empty grid.

Removing a group hides it everywhere but leaves its terms in the database; adding a group with the same key brings them back. At least one group must remain.

Placing the portfolio

Paste the shortcode wherever your editor runs shortcodes: a Shortcode block, a Divi Code module, an Elementor Shortcode widget, or a Kadence Advanced Text block.

[tfp_portfolio]

The Usage tab in Settings lists the same attributes with copy buttons and fills the examples with your own term slugs.

Shortcode attributes
AttributeValuesDefaultWhat it does
<group key>term slugs, comma-separated—Show only photos tagged with these terms, for example town="avalon,stone-harbor". A parent term includes its children. One attribute per group.
limita number, or -1-1 (all)How many photos to show.
filtersyes | noyesShow the filter bar.
layoutstack | row | dropdowns | primary | sidebar | drawer | allfrom SettingsWhich filter bar to draw. all adds a preview switcher.
columns1–6from SettingsDesktop columns. The grid drops to 2 columns in containers under 860 px and to 1 under 520 px on its own.
lightboxyes | nofrom SettingsOpen photos in the lightbox, or show plain thumbnails.
orderbymenu_order date | menu_order | date | title | modified | randmenu_order dateSort order. menu_order is the Order field on the photo.
orderASC | DESCDESCAscending or descending.

Several shortcodes on one page work; they share one set of filters, because the filters live in the page address.

Filter-bar layouts

All six layouts use the same filters; only the arrangement differs. Pick a site-wide default on the General tab and override it per shortcode with layout="…".

Layouts
LayoutBest for
A — Stacked groups stackA few groups with a handful of options each; everything visible. Collapses behind a Filter button on phones.
B — Single row rowOne scrolling line of options with arrows; compact, but shows little on a phone.
C — Dropdowns dropdownsA menu per group with a count badge; chosen filters appear as removable tags. The default. A group with a single term shows as one toggle chip.
D — First group + Refine primaryThe first group’s options in a row, the rest behind a Refine button. Good when one group matters most.
E — Sidebar sidebarFilters in a sticky left column beside the photos on wide screens; collapses on phones.
F — Drawer drawerOne button opens a panel that slides in from the right. Keeps the page clean.

Letting a client choose

Put [tfp_portfolio layout="all"] on a private test page. A “Filter style” switcher appears above the grid, the current choice is written to the address (?layout=drawer), and the chosen filters survive switching, so you can send a link that opens on a specific option. Set a real layout before the page goes live.

Slices and filtered links

A slice on another page

A town page, a service page, or a brand page can show just its own photos, with no filter bar:

[tfp_portfolio town="avalon" limit="6" filters="no"]
[tfp_portfolio treatment="shutters" brand="hunter-douglas" limit="9" filters="no" columns="3"]

Links that open a filtered view

Filters live in the page address, so any link or button can land on a pre-filtered portfolio. Commas mean “either”; separate groups mean “and”.

/portfolio/?treatment=shutters,blinds&town=south-jersey

shows photos tagged Shutters or Blinds, and tagged South Jersey (or any town inside it).

Appearance

Portfolio → Settings → Appearance styles the portfolio without touching your theme. The values become CSS variables on the portfolio, and the site’s font is inherited.

  • Colors: accent (selected chips, badges), text, secondary text, borders, chip background.
  • Chip corner radius: 999 for pills, 0 for square, 4–8 for softly rounded.
  • Photo corner radius and grid gap.
  • Thumbnail shape: 4:3, 3:2, 16:9, square, 3:4, or natural (no crop; rows will not line up).
  • Hover zoom on or off.
  • Custom CSS, printed after the plugin’s styles on any page that shows a portfolio. Scope rules to .tfp-portfolio. Useful hooks: .tfp-chip, .tfp-chip[aria-pressed="true"], .tfp-dd summary, .tfp-item figcaption, .tfp-title, .tfp-tags, .tfp-lb.

The General tab holds the wording: the Filter button label, the Refine button, the reset link, the “no results” message, and the word used in the live count (“6 of 22 photos shown”).

Importing many photos

With WP-CLI on the server, a spreadsheet saved as CSV can create the entries, attach the photos, and tag them in one run.

wp tfp import photos.csv --dry-run
wp tfp import photos.csv
  • Columns: image, title, caption, then one column per group key (treatment, room, town, brand with the defaults).
  • image is a web address, a Media Library attachment ID, or a path inside wp-content/uploads (for example 2026/11/avalon-living-room.jpg after uploading the folder by SFTP).
  • Several terms in one cell are separated with |. Nested terms are written Parent > Child; missing terms are created.
  • Entries are matched by title. A row whose title already exists updates that entry’s terms and caption and keeps its photo, so titles should be unique.
  • --dry-run prints what would happen without writing anything.

wp tfp export photos.csv writes every entry back out in the same format, the quickest way to see what the import expects. wp tfp settings prints the current settings.

Updates and uninstalling

The plugin checks my update server and shows new releases on the normal WordPress Updates screen like any other plugin. It also enrolls itself in WordPress auto-updates when activated, so fixes arrive without anyone logging in; switch that off on the Plugins screen if you prefer to update by hand. Check for updates now at the bottom of any Settings tab forces a check.

Deactivating leaves everything in place. Deleting the plugin removes its settings and caches. Your photos and terms are kept unless Delete data is ticked on the General tab before deleting, in which case every portfolio entry and every filter term is removed too. Images stay in the Media Library either way.

Troubleshooting

The shortcode shows nothing

The grid is empty when no published entry has a photo, or when the shortcode’s group attributes match nothing. Check that the entries are published, each has a Photo, and the slugs in the shortcode match the terms (the Usage tab lists them).

A filter is missing from the bar

The bar only lists terms with at least one visible photo, and only groups with In filter bar ticked. For nested groups set to “Parents only”, child towns are reachable through their parent.

The filters do not change the grid

Another plugin or the theme is probably stopping the plugin’s script. Look for JavaScript errors in the browser console, and check that the page is not served from a cache that strips scripts. Caching the page itself is fine; the filters run in the browser.

Styling looks wrong in my theme

Use the Appearance tab first; most differences are a color or radius. For anything else, add a rule in Custom CSS scoped to .tfp-portfolio.

I renamed a key and my photos lost their tags

Set the key back to what it was and the tags return. Keys are the one thing to settle before tagging.

Nothing happens on “Check for updates now”

The result box reports the reason. “Could not reach the update server” usually means the host blocks outbound requests; ask your host to allow updates.webdevsandbox.com.

What’s new

1.0.0 — November 2026

First release: the Portfolio post type with configurable filter groups, the [tfp_portfolio] shortcode with six filter-bar layouts and the preview switcher, filtering mirrored to the page address, the lightbox, the Appearance and Usage tabs, WP-CLI import and export, self-hosted updates, and an uninstaller that keeps your data unless you say otherwise.

License, support, and requirements

License and availability

Threshold Filterable Portfolio is free software, released under GPL-2.0-or-later. Sites that run it get updates through the normal WordPress Updates screen, from my own update server.

Download latest version

Support and contact

Filterable Portfolio is developed and supported by Spencer Taylor, Threshold Solutions, South Jersey, USA. For questions about the plugin, use the contact page.

Requirements

WordPress 6.0 or newer and PHP 7.4 or newer. Any theme; no page builder or other plugins needed. WP-CLI only for the optional CSV import.

Have an idea for a feature you'd like to see in Filterable Portfolio? Drop me a note.

More Threshold Plugins

Questions about Filterable Portfolio?

Ask me about the plugin, Google sign-in, or the security of your own site.