Title: MontraFolio
Author: LG-Systems
Published: <strong>September 23, 2026</strong>
Last modified: September 23, 2026

---

Search plugins

![](https://ps.w.org/montrafolio/assets/banner-772x250.png?rev=3708312)

![](https://ps.w.org/montrafolio/assets/icon-256x256.png?rev=3708312)

# MontraFolio

 By [LG-Systems](https://profiles.wordpress.org/luismiggarcia/)

[Download](https://downloads.wordpress.org/plugin/montrafolio.1.1.3.zip)

 * [Details](https://wordpress.org/plugins/montrafolio/#description)
 * [Reviews](https://wordpress.org/plugins/montrafolio/#reviews)
 *  [Installation](https://wordpress.org/plugins/montrafolio/#installation)
 * [Development](https://wordpress.org/plugins/montrafolio/#developers)

 [Support](https://wordpress.org/support/plugin/montrafolio/)

## Description

MontraFolio gives every user of the site an image portfolio of their own, and lets
staff run shared portfolios — events, trips, campaigns — with designated contributors.

 * **Portfolio, collection, image.** A portfolio has one owner and any number of
   collections; each collection holds images and can be visible or hidden.
 * **Private by construction.** Nothing goes to the Media Library. Files live in
   a folder the web server does not serve; the plugin checks who may see each image
   before delivering it.
 * **Mobile first.** Camera and gallery uploads from a mobile device, images resized
   on the device, reorder by touch, carousel by swipe. Folder drag-and-drop on a
   desktop feeds the same pipeline.
 * **A page for the portfolio, a gallery for each collection.** The portfolio page
   presents the cover, the owner and a full description, then its collections as
   cards. Each collection shows its images as tiles or a carousel: visitors switch
   between the two, the collection decides which modes are available and which opens
   first.
 * **Chronological order.** Images can be ordered by their original capture time,
   across contributors.
 * **Owners and contributors.** One owner administers a portfolio; contributors 
   publish in the collections they were given, or in all of them.
 * **Limits at four levels.** The site sets what a new portfolio and a new collection
   are born with; from there the portfolio carries its own storage and image ceilings,
   a collection may narrow them, and each contributor may be narrowed further. No
   level ever grants more than the level above it, and lowering one deletes nothing—
   it only narrows the next upload.
 * **Videos in a collection.** Paste the address of a video on YouTube, Vimeo, Dailymotion
   or TikTok and it takes its place among the images, in the same order, with the
   same caption and observation. Only its thumbnail is stored here; by default the
   public page contacts nobody until a visitor presses play.
 * **Videos on networks that answer nobody.** Instagram, Facebook and LinkedIn answer
   no plugin about an address, so nothing is asked of them: you paste the address,
   choose the picture the card will show, and the card opens the video in a new 
   tab. Those networks are never contacted by this site — not when you add the video,
   not when a visitor looks at the collection.
 * **No telemetry, ever.** Sign-in with WordPress accounts; optional single sign-
   on through any plugin that hooks the WordPress login. The only requests that 
   ever leave the site are the ones videos need, listed under External services.
 * **Interface in English, Portuguese and Spanish**, independently of the WordPress
   language.
 * **In any page of the theme.** Three blocks, each with a shortcode: a collection
   with its lightbox, the collections of a portfolio, and the descriptions of either.
 * **Personal data under control.** Images are stored without camera metadata; the
   personal data export of WordPress includes the plugin’s data; a retention rule
   can remove unused personal portfolios, warning their owners a long time before
   and letting them keep them with one button; the privacy policy paragraphs are
   suggested under Settings  Privacy.
 * **Accessible.** Keyboard, screen readers, reduced motion and AA contrast on the
   public pages and in the portfolio area.

Everything described above is in this version and covered by tests: the portfolio
area (sign-in, content terms, portfolios, collections, contributors, uploads, limits),
the private storage and the image delivery, the public pages and the three blocks
with their shortcodes, the wp-admin management screens (the portfolios list with
its filters, creation of assigned portfolios, editing, owner change, rename with
redirect, contributors, limits, suspension, deletion, storage report, regeneration
of the derived sizes), the permissions by role, the personal data exporter and eraser,
the retention rule with its notice, and the accessibility and performance passes.

### External services

This plugin connects to four video services, and only when somebody uses the video
feature. Nothing else on the site ever contacts them, and with every service switched
off in **Settings  Videos** no request is made at all.

**When an owner or a contributor adds a video** by pasting its address, the site
asks that service’s public oEmbed endpoint about the address, to learn the title
and the address of the thumbnail. What is sent is the address that was pasted and
the site’s own address, in the request; the thumbnail is then downloaded once and
stored on this site. Nothing about the visitor is involved: this happens while somebody
is administering a collection.

**When a visitor presses play** on a video, that visitor’s browser loads the player
from the service, which receives their IP address and whatever their browser sends,
and may set cookies. Until play is pressed nothing is requested, unless the site
turns _Load the video only when the visitor presses play_ off.

**Linked videos contact nobody.** The networks the _Link a video_ feature points
at — Instagram, Facebook, LinkedIn, and whichever else a site adds to the list —
are **not** external services of this plugin: no request is ever made to them, at
any moment, by the site or by the pages it serves. The address is stored as text
and the picture is one the site uploaded itself. A visitor who presses the link 
goes there under their own steam, exactly as they would follow any link written 
in any post.

The services, with their terms and their privacy policies:

 * YouTube (`https://www.youtube.com/oembed`, player on `youtube-nocookie.com` or`
   youtube.com`) — terms https://www.youtube.com/t/terms · privacy https://policies.
   google.com/privacy
 * Vimeo (`https://vimeo.com/api/oembed.json`, player on `player.vimeo.com`) — terms
   https://vimeo.com/terms · privacy https://vimeo.com/privacy
 * Dailymotion (`https://www.dailymotion.com/services/oembed`, player on `geo.dailymotion.
   com`) — terms https://legal.dailymotion.com/en/terms-of-use/ · privacy https://
   legal.dailymotion.com/en/privacy-policy/
 * TikTok (`https://www.tiktok.com/oembed`, player on `tiktok.com`) — terms https://
   www.tiktok.com/legal/terms-of-service · privacy https://www.tiktok.com/legal/
   privacy-policy

### Source code

Everything this plugin ships is its source. The JavaScript and the CSS under `assets/`
are written
 by hand and served exactly as they are written: there is no build step,
no bundler and no minifier, so what runs in a browser is the file you can open in
the plugin’s folder. Nothing here is generated from something kept elsewhere. The
only compiled files are the two third-party libraries below, and each is named with
the address of its own source.

The translations are not carried in the package: WordPress.org delivers them as 
language packs, and
 a site that wants a language nobody has published yet drops
the catalog into wp-content/languages/plugins.

### Third-party code

 * The QR code component uses _qrcode-generator_ by Kazuhiko Arase (MIT license).
   The plugin ships the minified build; the unminified source is available at https://
   github.com/kazuhikoarase/qrcode-generator
 * HEIC photos are decoded on the device by _libheif_ (LGPL-3.0), in the WebAssembly
   build published as _libheif-js_ version 1.23.2. The plugin ships `assets/vendor/
   libheif/libheif.js` (Emscripten glue, minified) and `assets/vendor/libheif/libheif.
   wasm` (the compiled library); the sources are at https://github.com/strukturag/
   libheif and the build that produces these files at https://github.com/catdad-
   experiments/libheif-js

## Screenshots

[⌊The portfolio area on a desktop: what the portfolio is on the left, everything
done to it on the right.⌉⌊The portfolio area on a desktop: what the portfolio is
on the left, everything done to it on the right.⌉[

The portfolio area on a desktop: what the portfolio is on the left, everything done
to it on the right.

[⌊The portfolio area on a phone: the cover, and the collections shown, hidden and
ordered by touch.⌉⌊The portfolio area on a phone: the cover, and the collections
shown, hidden and ordered by touch.⌉[

The portfolio area on a phone: the cover, and the collections shown, hidden and 
ordered by touch.

[⌊The portfolios list in wp-admin, with its filters and the storage report.⌉⌊The
portfolios list in wp-admin, with its filters and the storage report.⌉[

The portfolios list in wp-admin, with its filters and the storage report.

[⌊Permissions by role: what each role of the site may do with portfolios.⌉⌊Permissions
by role: what each role of the site may do with portfolios.⌉[

Permissions by role: what each role of the site may do with portfolios.

[⌊The page of a portfolio: the cover, the owner, the description, and the collections
as cards.⌉⌊The page of a portfolio: the cover, the owner, the description, and the
collections as cards.⌉[

The page of a portfolio: the cover, the owner, the description, and the collections
as cards.

[⌊A collection as tiles.⌉⌊A collection as tiles.⌉[

A collection as tiles.

[⌊The same collection as a carousel; the visitor switches between the two.⌉⌊The 
same collection as a carousel; the visitor switches between the two.⌉[

The same collection as a carousel; the visitor switches between the two.

[⌊An image opened large, with its caption and its observation.⌉⌊An image opened 
large, with its caption and its observation.⌉[

An image opened large, with its caption and its observation.

## Blocks

This plugin provides 3 blocks.

 *   MontraFolio – Collection One collection, as tiles or a carousel, from MontraFolio.
 *   MontraFolio – Details The description of a portfolio and/or of a collection,
   from MontraFolio.
 *   MontraFolio – Portfolio The collections of a portfolio, as cards or as a list,
   from MontraFolio.

## Installation

 1. Upload the plugin folder to `/wp-content/plugins/` or install it from the Plugins
    screen.
 2. Activate it. The private image folder and the database tables are created on activation.
 3. Open **MontraFolio  Settings** to choose the address words and the upload limits,
    and **Permissions by Role** to decide who manages portfolios.

## FAQ

### Does the plugin send any data anywhere?

No usage data, no domain, no versions: the plugin never reports anything about your
site to anybody, and updates come from WordPress.org through the normal WordPress
mechanism. The single exception is videos, and only where somebody uses them: adding
a video asks its service for the title and the thumbnail, and playing one loads 
it from that service. Both are listed under External services below.

### Can I put a YouTube video in a collection?

Yes — YouTube, Vimeo, Dailymotion or TikTok, by pasting the address of the video.
It becomes an item of the collection like an image: same order, same caption, same
observation, and it can even be the cover. Nothing of the video is stored on your
site except its thumbnail, which counts as one image against the collection’s limits.
Each service can be switched off in **Settings  Videos**, and switching them all
off removes the feature from the portfolio area.

### What about a video on Instagram, Facebook or LinkedIn?

Those cannot be played inside your pages, and this plugin does not pretend otherwise.
Since 2020 Meta answers the Facebook and Instagram oEmbed only to an application
registered with Meta, which a plugin installed on sites it knows nothing about cannot
be; LinkedIn never published an endpoint at all. So there is no title and no thumbnail
to fetch — and nothing is fetched.

Instead there is **Link a video**: you paste the address and choose a picture of
your own for the card. It takes its place in the collection like any other item,
and the card opens the address in a new tab. Those networks are never contacted 
by your site, at any moment, so no script of theirs runs on your pages and no visitor’s
address reaches them until that visitor chooses to go. The accepted networks are
a list you can edit in **Settings  Videos**.

### Do my visitors get tracked by the video services?

Not until they choose to be. With _Load the video only when the visitor presses 
play_ on — which is how it is installed — a public page showing a video makes no
request at all to the video service: the visitor sees the thumbnail stored on your
own server, and a notice saying what pressing play will load. Only then is the player
loaded — and it starts playing right away, because pressing play is the gesture 
browsers ask for before a video may start, so one press is all it takes. YouTube
is played from youtube-nocookie.com unless you say otherwise, Vimeo is asked not
to keep a session about the viewer, and the text of the notice is yours to write.

### Do I need another plugin to sign in?

No. Users sign in with their WordPress accounts on the plugin’s own page. A single
sign-on plugin (Microsoft Entra ID, LDAP and others) is optional and plugs into 
the WordPress login pipeline.

### Where are the images stored?

In `wp-content/uploads/montrafolio/`, a folder protected against direct access on
Apache and IIS. On nginx, add the `location` rule described in the manual; the unguessable
file names and the delivery through the plugin remain the real defence.

### Do users need wp-admin?

No. Owners and contributors work in p-admin, a page of the plugin at the address
chosen in Settings (`/p-admin/` by default). Users with nothing beyond a reading
role land there after signing in and never see wp-admin.

### Can I show a portfolio inside a page of my theme?

Yes, with three blocks — **MontraFolio – Collection** (the gallery), **MontraFolio–
Details** (the descriptions) and **MontraFolio – Portfolio** (the list of collections)—
or their shortcodes, `[mtfl_collection portfolio="ana" collection="trip"]`, `[mtfl_details]`
and `[mtfl_portfolio]`. The portfolio is picked on the block itself. The Collection
block presents it as tiles, as a carousel or as both, inheriting what the owner 
proposed when it is not told otherwise; a list of collections can point each line
at the same page, so that one page holds the list and the gallery of whichever collection
the visitor picks.

### What personal data does the plugin store, and can users export it?

The owner name shown on a portfolio and the owner e-mail kept with it, which is 
never published (copied from the profile, editable by the site staff without changing
the account), which account made each contributor designation and each upload, the
file name an image had on the device, the content terms accepted (version and date)
and the date of the last activity in the portfolio area. Images are stored without
camera metadata. **Tools  Export Personal Data** includes all of it. **Tools  Erase
Personal Data** deletes the personal portfolio with its images, releases assigned
portfolios without touching their content, removes the account’s designations, anonymises
the uploader and the device file name of images in other portfolios, and keeps only
the acceptance of the content terms, as the proof that what is still published was
uploaded under them. Nothing is sent to another server.

### What happens to a portfolio when its user is deleted?

If the person deleting the account attributes its content to another user, that 
user receives every portfolio of the deleted one. Otherwise **Settings  Privacy**
decides for the personal portfolio (delete it with its images, or hand it to a chosen
account), and assigned portfolios wait for a new owner. Optionally, a retention 
period removes the personal portfolios of users with no activity for that long: 
the portfolio is marked, its owner is written to, the portfolio area offers a button
that keeps it, any use of it takes the mark off, and only after the notice period(
a year by default) is it deleted.

### Can I limit how much each person uploads?

Yes, at four levels. **Settings** decides what a new portfolio and a new collection
start with. A manager holding _set the limits of a portfolio_ then gives each portfolio
its own storage and image ceilings in wp-admin; the owner sees that ceiling and,
in the portfolio area, may narrow any collection and any contributor within it. 
A level set to 0 has no limit of its own and follows the level above. Changing a
limit never deletes anything: it decides what the next upload may add, and the meter
each person sees is whichever level runs out first for them.

### Can I put a portfolio inside a page of my theme?

Yes — see the blocks above. Beyond that, the pages the plugin serves itself (the
sign-in, the content terms, the portfolio area, the public gallery) are documents
it writes whole, without the theme’s header and footer: that is what lets a public
image be answered before the theme even loads. A site adds what it needs to them
through three actions of the plugin — `mtfl_page_head`, `mtfl_page_body_start` and`
mtfl_page_footer` — each given the context of the page, so a consent banner or an
analytics script can be placed where the site means it and kept off the sign-in 
page. The public pages carry their own Open Graph and Twitter tags, built from the
title, the description and the cover.

### My host only allows 2 MB uploads. Do I have to change that?

No. A photo bigger than one request can carry is sent in parts and put back together
on the
 server, exactly as a backup file is. The only limit that can make a photo
smaller is the one in **Settings  Uploads**, which is yours to choose. Nothing in
the plugin asks you to change a PHP setting, and it never lowers quality to fit 
your host’s.

### What about HEIC photos from an iPhone?

They are accepted everywhere, and nothing has to be configured for it. Safari converts
them itself; every other browser converts them with libheif, which the plugin loads
on the device only when such a photo appears. A server whose Imagick was built with
HEIC support converts them too, which is only faster; _Tools  Site Health  Info  
Media Handling_ says whether yours was.

## Reviews

There are no reviews for this plugin.

## Contributors & Developers

“MontraFolio” is open source software. The following people have contributed to 
this plugin.

Contributors

 *   [ LG-Systems ](https://profiles.wordpress.org/luismiggarcia/)

[Translate “MontraFolio” into your language.](https://translate.wordpress.org/projects/wp-plugins/montrafolio)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/montrafolio/), check
out the [SVN repository](https://plugins.svn.wordpress.org/montrafolio/), or subscribe
to the [development log](https://plugins.trac.wordpress.org/log/montrafolio/) by
[RSS](https://plugins.trac.wordpress.org/log/montrafolio/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

#### 1.1.3

 * **The blocks are found by words in the site’s language.** The search words of
   the three blocks — the ones the editor’s inserter matches — live in `block.json`,
   and the translation catalog did not carry them, so they stayed in English whatever
   the language of the site. The catalog now holds them, with the title and description
   written there too, and a language pack translates them along with everything 
   else.
 * **The help under the address parameter reads as a pattern.** The two lines that
   explain it — `?name={portfolio}` and `?name={collection}` — used angle brackets,
   which translators and their tools took for HTML and asked to keep untouched. 
   Braces say what they mean: put the name of the parameter here and the address
   there, in any language.

#### 1.1.2

 * **A changed icon is fetched again.** The icon in the wp-admin menu, the one in
   the browser tab and the one beside the blocks in the editor were served from 
   an address that never changed, so a browser that had already seen an older one
   went on showing it — sometimes long after the update, with nothing to explain
   why. They now carry the version of the file, as everything else the plugin serves
   already did.
 * **The three blocks now describe themselves on WordPress.org.** Each block’s name,
   title, description and icon move into its own `block.json`, the file the directory
   reads — so the _Blocks_ section of the plugin page tells what _MontraFolio – 
   Details_, _– Portfolio_ and _– Collection_ each do, instead of listing only their
   names. Nothing changes in the editor: the same titles, the same descriptions 
   and the same mark as before.

#### 1.1.1

**The name is written MontraFolio**, with a capital F. It reads that way wherever
the plugin names itself: the header WordPress shows, the titles of the three blocks
in the editor, the menu of wp-admin, the settings screens, the export and the erasure
of personal data, and the line above the title of the pages the plugin serves, for
sites that did not put a name of their own there.

 * **Nothing that addresses anything changed.** The folder of the plugin, the shortcodes,
   the blocks, the REST addresses and the private folder of the images are written
   exactly as in 1.1.0. A page built with 1.1.0 needs nothing done to it, and an
   update is only an update of the text.
 * **The translations were rebuilt with it**, so the Portuguese and the Spanish 
   name the plugin the same way.

#### 1.1.0

**MontraFolio.** The plugin carries its name through everything it names: the blocks,
the REST addresses, the folder the images live in and the graphics.

 * **It has a mark of its own.** The monogram appears on the menu in wp-admin, in
   the tab of every page the plugin serves, and beside its blocks in the editor.
 * **The blocks and the shortcodes are named for it.** _MontraFolio – Collection_,_–
   Details_ and _– Portfolio_, and `[mtfl_collection]`, `[mtfl_details]`, `[mtfl_portfolio]`.
   A page built with an earlier set shows the blocks as unrecognised, and an earlier
   shortcode prints nothing, until each is written with these names.
 * **What the plugin stores is named for it too**, and moves there on the first 
   request after the update: the tables, the settings, the permissions granted by
   role and what each person’s account remembers. Nothing is copied and nothing 
   is rebuilt — the names change and the rows stay where they are. In the one case
   where a table cannot move because a table of the new name already holds rows,
   every screen says so and neither set is touched.
 * **The private folder is `uploads/montrafolio`**, and an earlier one is renamed
   to it on the first request after the update. Nothing is copied and nothing is
   rebuilt — the folder is renamed with everything in it, and the images go on being
   served from the same addresses. A site that named its own folder is left alone.
   In the one case where the rename cannot be done, every screen of the plugin says
   so plainly, names both folders and says that nothing was deleted.
 * **The REST addresses are `montrafolio/v1`.** Only something written against them
   by hand would notice.
 * **Translations now come from WordPress.org instead of travelling inside the plugin.**
   They are delivered as language packs and installed into `wp-content/languages/
   plugins`, the folder WordPress keeps for them — which means a translation now
   survives an update of the plugin instead of being replaced by it, and a site 
   can put a language of its own in that same folder for a language nobody has published
   yet. _Settings  Plugin  Plugin language_, which makes the plugin speak a language
   the rest of the site does not, reads from there too; a language that is not installed
   reads in English. Until the packs for a language exist, the plugin reads in English
   unless its file is placed by hand — the manual says how.
 * Every form and every address the plugin reads is now taken apart field by field,
   each value through the sanitizer that field deserves, instead of the request 
   being read whole. Nothing a person does changes: what a form was allowed to save,
   it still saves, and what it refused, it still refuses. It is the reading itself
   that is narrower — a field the form does not have never reaches the plugin at
   all.
 * The pages the plugin serves on its own — the sign-in, the portfolio area and 
   the public galleries — now hand their stylesheets and scripts to WordPress instead
   of writing the tags themselves. Nothing a visitor sees changes: the same files
   load, in the same order, deferred as before. What it buys is that these pages
   are no longer invisible to everything that works through WordPress’s own asset
   list — a caching or optimisation plugin now sees them like any other page, and
   a site that wants to add a stylesheet of its own, or take one away, has a name
   to call it by.

#### 1.0.1

 * **A portfolio now says it changed when its photographs change.** The date each
   portfolio carries only moved when somebody edited a setting of it — a title, 
   a description, a collection created or renamed. An afternoon of uploading moved
   nothing, so the portfolios that had seen the most work looked exactly like the
   ones nobody had opened in months. Two screens read that date and both were misleading
   because of it: the _Updated_ column of the list in wp-admin, and the portfolio
   picker, which offers the most recently updated first when nothing is typed in
   it. Photographs arriving and leaving, captions written and images reordered now
   all move it, and those two screens say what actually happened.
 * **A collection’s date follows what its images say, and the order they are in.**
   Images arriving and leaving already moved it. Editing a caption, an observation
   or a capture date moved nothing at all — an afternoon spent captioning a collection
   left it looking untouched — and neither did reordering by hand or arranging by
   capture time. All of those are printed on the public page, so all of them are
   changes now. What it buys today is that a Portfolio block set to _Recent_ orders
   collections by when they last actually changed; what it buys later is a date 
   worth trusting for anything that needs to know whether a collection is still 
   what it was.

Nothing a visitor sees was changed by this version, and nothing needs doing on update.

#### 1.0.0

First version published on WordPress.org.

What it is: portfolios of images for an organisation, one for each person who wants
one and as
 many shared ones as the staff need; collections shown as tiles or as
a carousel; images kept in a private folder the plugin serves itself, never in the
Media Library; uploads from a phone’s camera, resized on the device before they 
travel; limits at four levels; videos hosted elsewhere added beside the images without
a visitor being handed to anybody until they press play; a portfolio area built 
for a phone, and management screens in wp-admin for whoever runs the site; the personal
data export and erasure of WordPress, a retention rule for portfolios nobody uses
any more, and no telemetry of any kind.

The development that got here — fifteen versions, from 0.5.0 to 0.9.5 — is in `changelog.
txt`.

## Meta

 *  Version **1.1.3**
 *  Last updated **6 hours ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 6.5 or higher **
 *  Tested up to **7.1.2**
 *  PHP version ** 8.1 or higher **
 * Tags
 * [carousel](https://wordpress.org/plugins/tags/carousel/)[gallery](https://wordpress.org/plugins/tags/gallery/)
   [images](https://wordpress.org/plugins/tags/images/)[portfolio](https://wordpress.org/plugins/tags/portfolio/)
   [video](https://wordpress.org/plugins/tags/video/)
 *  [Advanced View](https://wordpress.org/plugins/montrafolio/advanced/)

## Ratings

No reviews have been submitted yet.

[Your review](https://wordpress.org/support/plugin/montrafolio/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/montrafolio/reviews/)

## Contributors

 *   [ LG-Systems ](https://profiles.wordpress.org/luismiggarcia/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/montrafolio/)