This replaces most of the manual “download attachment, log into WordPress, import,
select all, apply category, save” routine with: run a script, check a spreadsheet,
click one import button on the site.
It’s two separate pieces:
- A small file on the WordPress site (one-time install, an admin/developer job).
- A Google Sheet with a script attached, which anyone can copy into their own
Google account so more than one person can run it.
Part 1 – WordPress: install the REST snippet
This lets the script check for and create document categories (e.g. “Board Meeting
2026 > July 2026″) on the site. It does not expose documents themselves, and it
doesn’t change anything about how Document Library Pro behaves for normal use.
- Using your hosting file manager or FTP/SFTP, go to
wp-content/mu-plugins/
(create that folder if it isn’t there already). - Upload
wdco-dlp-rest-api.phpinto that folder. - That’s it – “mu-plugins” load automatically, nothing to activate.
To remove it later, just delete the file.
Part 2 – The Google Sheet and script
Anyone who wants to be able to run this (you, or someone else at WDCO) does this
once, in their own Google account:
- Go to sheets.google.com and create a new blank spreadsheet. Name it
something like “WDCO Document Import”. - Go to Extensions > Apps Script. Delete the placeholder code, and paste in
the contents ofCode.gs. - In the Apps Script editor, go to Project Settings (the gear icon) and
tick “Show appsscript.json manifest file in editor”. - A file called
appsscript.jsonwill appear in the file list on the left.
Open it, delete its contents, and paste in the contents of theappsscript.jsonfile provided. This limits what permissions Google asks you
to grant (see “About the permissions” below), and also switches on the Drive
conversion feature used to turn Word documents into PDFs automatically (see
“Word documents are converted to PDF automatically” below) – nothing further
needs enabling separately in the editor’s Services list. - Save the project (the disk icon, or Ctrl/Cmd+S), giving it a name.
- Close the Apps Script tab and reload the Google Sheet. A new menu should
appear: WDCO Document Import. - From that menu, choose 1. Setup / configure… and follow the prompts:
- Your WordPress site URL
- Your WordPress username
- A WordPress Application Password – not your login password. Create one
under your WordPress profile: Users > Profile > Application Passwords,
give it a name like “WDCO import script”, and paste the generated password
when asked. This is what lets the script talk to your site. - The Gmail label your filter applies to relevant emails, exactly as it
appears in Gmail’s own search box (e.g.wdco-meeting-papers– just the
part afterlabel:, no need to type “label:” itself). Setting up that
filter is a one-time job in Gmail’s own settings (Settings > Filters and
Blocked Addresses > Create a new filter), matching on subject words
(executive, liaison, board, agm) plus “Has attachment,” applying your
chosen label. If you leave this blank, the script falls back to doing
that same keyword search itself, but only within a recent time window
(see the next prompt) rather than your whole mailbox. - How many days back to search if no label is set (leave blank for the
default, 45 days) – or, even with a label set, an extra safety limit in
case the label ever ends up wider than intended. - The first time you run any menu item, Google will ask you to authorize the
script – review and accept. A note on backlogs: if a label already has a lot of messages under it
(e.g. you applied the filter retroactively to your whole inbox), the first
“Find new documents now” click won’t necessarily get through all of them
in one go – it stops itself cleanly if it’s taking too long, and tells you
to click it again to keep going. Nothing is missed or double-counted;
it just picks up from where it left off.
That’s the whole setup. Each person who wants to run this makes their own copy
of the Sheet (File > Make a copy) and repeats step 7 with their own
Application Password – the script code comes along automatically when you copy
the Sheet, but the configuration (site, username, password) does not, so each
copy needs its own.
Using it day to day
- Find new documents now – searches Gmail for anything with an attachment
whose subject mentions Executive, Liaison, Board, or AGM, sent from an @publicvoice.london or @publicvoice.uk address, and whose subject does not
mention London Heathside, MHDT, the Partnership Board or the Estate
Management Board. It works out a category for each, and adds a row per
document to the “Documents” tab. Rows it isn’t confident about are
highlighted yellow, with a reason in the “Review reason” column – usually
because the subject didn’t include a full date, or because an attachment’s
file name mentions one of the excluded bodies. Edit the “Category” cell
directly to correct it, or leave it if the guess looks right. Processed
emails are labelledWDCO/Importedin Gmail so they won’t be fetched again. - Turn on monthly automatic check (third Friday) – runs the same search
on the third Friday of each month, in the morning, and emails you a short
summary if anything new turns up (nothing is emailed if there’s nothing
new). Apps Script cannot schedule “the third Friday” directly, so the
trigger fires every Friday and the script does nothing unless the date is
the 15th to the 21st. Turning this on also switches off the old weekly
check. You can still run “Find new documents now” manually at any time. The
script only ever adds rows to the sheet; nothing is uploaded to WordPress
until you export the CSV and import it yourself. - Duplicate attachments – every row carries an “Attachment fingerprint”
(file name plus a checksum of the file’s contents). When a later email
carries an attachment already in the sheet, the earlier row is deleted and
the later one kept. Rows already marked “Exported” are never deleted: the
later copy is added and flagged for review instead. A run that removes rows
lists them in its on-screen message or summary email, and the Drive files
themselves are left alone. Rows that pre-date this feature are
fingerprinted automatically at the start of the next run, or on demand with
Fingerprint existing rows. - Check for duplicates on the site – before exporting, searches the
currently-configured WordPress site’s existing documents for a title match
against each not-yet-exported row, and writes the result into a “Possible
duplicate” column (“Yes”, “Maybe”, or “No match found”). This only reads
from the site, never changes anything there. It checks whichever site
Setup currently points at – if you’re about to import to the live site,
make sure you’ve re-run Setup pointing at the live URL first, otherwise
you’ll be checking against the wrong site’s documents. Requires the
updatedwdco-dlp-rest-api.php(adds read access to documents, alongside
the categories access it already had). - Export CSV for Document Library Pro – takes everything marked “New” in
the sheet, double-checks with you if anything is still flagged, makes sure
the categories exist on the site (creating any that don’t, with a
chronological, collision-free slug), and emails you a CSV file. On your site,
go to Document Library > Import > CSV upload, choose that file, and run
the importer – this is the one remaining manual step, and it applies the
category to everything in the same click.
Word documents are converted to PDF automatically
Any .doc or .docx attachment is converted to PDF before it’s saved to
Drive or listed in the sheet – you’ll see a .pdf filename in the “File
name” column even though the original email attachment was a Word document.
This is because Word documents were being rejected during the WordPress
import step (likely a hosting-level security restriction, not something
within Document Library Pro or WordPress’s own settings), while PDF – the
format used for the great majority of WDCO’s documents anyway – uploads
without issue.
If a particular file can’t be converted for some reason (rare – e.g. a
corrupted attachment), that row is flagged for review with an explanation,
and the original file is kept rather than the row silently failing.
About the permissions Google will ask for
Applying the “already handled” label to a processed email needs Google’sgmail.modify permission – there isn’t a narrower official option that covers
labelling a specific message without also nominally covering things like
marking read/unread. The script never uses it for anything beyond searching and
labelling. Permanent deletion and sending mail as you to other people are
scopes this script does not request at all (it uses a separate, narrower
scope just to email your own notifications and CSVs to yourself).
The Drive scope had to be widened from the original narrow drive.file to
full drive access – Apps Script’s permission check won’t allow looking up a
previously-created folder by its stored ID (which the script does on every
run, rather than re-searching by name each time) under the narrower scope,
even though that folder was created by the script itself. In practice the
code only ever reads or writes inside the one “WDCO Document Imports” folder
it created during setup – the broader grant is a limitation of what Google
lets you declare, not a change in what the script actually touches.
A note on the category-guessing rules
- Subject includes a full day + month + year (e.g. “2nd June 2026”) – used
directly. - Subject includes day + month only (e.g. “21st May”) – the year is taken from
when the email was sent, but only automatically if the meeting month is the
same as, or the one right after, the send month. Anything else (e.g. an
email sent in December about a meeting in February) is flagged rather than
guessed. - No date at all in the subject (e.g. “Further AGM papers”) – falls back to
the email’s own send month/year, always flagged for you to confirm.
If WDCO’s wording changes over time (a new meeting type, a different phrasing),
the rules live near the top of Code.gs in the TYPE_RULES list and are
straightforward to extend.
Filtering out other bodies
Only mail sent from the domains listed in ALLOWED_SENDER_DOMAINS near the
top of Code.gs (publicvoice.london and publicvoice.uk) is picked up, and any
message whose subject contains a phrase from EXCLUDED_SUBJECT_PHRASES
(heathside, mhdt, manor house development trust, partnership board, estate
management board) is skipped. Both checks run in the Gmail search and again
on each message. An attachment whose own file name contains one of the
phrases is kept but flagged “Needs review”, since a genuine WDCO pack
sometimes includes another body’s report. Edit either list if the rules
change. Note that the Gmail filter behind the watch label, if you use one,
is separate: it may still label mail from other senders, but the script will
ignore it.
Because the sender and subject are checked on each message rather than on the
thread as a whole, an unwanted message sharing a Gmail thread with a wanted
one is skipped on its own.