=== SteadyPost ===
Contributors: seanliew, steadydevs
Tags: import, csv, excel, bulk edit, spreadsheet
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.3.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Create and update posts in bulk from a CSV or Excel spreadsheet. Optionally import from Google Sheets, with post content from Google Docs.

== Description ==

SteadyPost turns a spreadsheet into WordPress posts. Each row is a post; each column is a field — title, content, excerpt, slug, status, categories, tags, featured image, publish date, author, and SEO title, description and keywords.

It works on its own. Download a sample or blank template (Excel or CSV), fill it in with any spreadsheet app, and upload it back. No account or external service is needed.

= Importing =

* **Templates** — Excel templates come with a frozen header row, a Status dropdown and an Instructions sheet. Columns for your site's own custom fields and custom taxonomies are included automatically.
* **Automatic column mapping** — template columns map themselves. Any other spreadsheet can be mapped field by field, right on the Import screen.
* **Content as plain text, Markdown or HTML** — detected per row. Block-editor markup is kept exactly as it is.
* **Images by filename** — upload a zip of images and refer to `hero.jpg` in a row, or reuse an image already in your media library. Each image is added to the library once.
* **Preview and pick rows** — see every row and column before importing, tick exactly the rows you want, or let a "ready" column decide.
* **Dry run** — find out what would be created or updated, which categories are new and which authors or images are missing, without saving anything.
* **Safe re-imports** — running the same sheet again updates the posts it created instead of duplicating them.

= Editing in bulk =

* **Export** existing posts — any post type, filtered by status, category and date — to Excel or CSV, edit them, and upload the file to update them all at once. This works for posts SteadyPost did not create, too.

= History and undo =

* Every import is recorded with its full row-by-row log.
* **Undo** a run: the posts it created go to the Trash, and the posts it updated are restored to the revision saved just before the import changed them.

= SEO plugins =

SEO columns are written to whichever SEO plugin is active: Yoast SEO, Rank Math or SEOPress, as well as Mikado/Qode theme SEO fields or meta keys you name yourself.

= Optional: Google Sheets and Google Docs =

Instead of uploading a file, SteadyPost can read rows straight from a Google Sheet — anonymously for link-shared files, or as a Google service account for privately shared ones — and re-import it on a schedule. Any row can point at a Google Doc to use as the post body, with its headings, formatting, links, tables and images. See External services below.

= Privacy =

SteadyPost adds no tracking and sends no data anywhere unless you use the optional Google features. Uploaded spreadsheets are stored in a private folder in `wp-content/uploads` that is blocked from the web, and replaced each time you upload a new one.

== External services ==

SteadyPost connects to Google only when you choose to. If you import from an uploaded CSV or Excel file and leave the Google Doc column empty, it makes no outside requests at all. Requests to images on other sites are made only for image URLs you put in your spreadsheet.

**Google Sheets** — used when Settings → Source is set to a Google Sheet. When you open the Settings screen, preview, run an import or a scheduled sync runs, SteadyPost requests the sheet's contents. It sends the spreadsheet ID from the URL you entered, your Sheets API key if you set one, and your site's address in the User-Agent header.

* `https://docs.google.com/spreadsheets/d/{id}/export` — CSV and XLSX exports of the sheet.
* `https://sheets.googleapis.com/v4/spreadsheets/{id}` — the Google Sheets API, in Sheets API mode.

**Google Docs and Google Drive** — used when a row links a Google Doc as its content, or names a Google Drive image. During the import of that row, SteadyPost downloads the document as HTML, or the image file. It sends the document or file ID from the link.

* `https://docs.google.com/document/d/{id}/export`
* `https://drive.google.com/uc`

**Google OAuth** — used only if you connect a Google service account to read privately shared files. To get an access token, SteadyPost sends `https://oauth2.googleapis.com/token` a request signed with the service account's private key. It contains the service account's email address and the read-only access it asks for. The key itself is never sent. Tokens are requested when a Google file is read and when the Settings screen checks the connection.

These services are provided by Google: [Google Terms of Service](https://policies.google.com/terms), [Google Privacy Policy](https://policies.google.com/privacy), [Google APIs Terms of Service](https://developers.google.com/terms).

== Installation ==

1. Install SteadyPost from Plugins → Add New, or upload the zip under Plugins → Add New → Upload Plugin, and activate it.
2. Go to **SteadyPost → Import** and download the sample spreadsheet.
3. Fill in one row per post. Only Title is required.
4. Upload the file. Its columns are mapped for you; adjust the mapping on the same screen if you renamed any.
5. Press **Dry run** to check, then **Run import**.

To import from Google instead, choose a Google Sheet under **SteadyPost → Settings → Source** and follow the instructions there.

== Frequently Asked Questions ==

= Which file formats can I upload? =

`.xlsx` (Excel, Numbers, LibreOffice and Google Sheets can all save it) and `.csv`. Excel files are read from their first sheet. CSV files saved by Excel in Windows-1252 encoding or with semicolons as separators are detected automatically.

= Will importing the same file twice create duplicates? =

No. Each row is matched to the post it created — by a Ref column, the slug, or the title — and updated in place. Turn off "update existing" in Settings to skip those rows instead.

= How do I bulk-edit posts I already have? =

Export them under SteadyPost → Export, edit the spreadsheet, and upload it on the Import screen. The Post ID column tells SteadyPost which post each row belongs to.

= Can I undo an import? =

Yes, from SteadyPost → History. Created posts go to the Trash, so you can still restore them from there. Updated posts get back the title, content and excerpt they had before the import.

= How do I write the post body? =

In the Content column, as plain text (a blank line starts a new paragraph), Markdown, or HTML. Or put a Google Doc link in the Google Doc column and the doc becomes the body.

= How do I import custom fields and taxonomies? =

Add a column named `meta:your_field` or `tax:your_taxonomy`. Templates and exports already include these columns for the default post type's registered custom fields, simple Advanced Custom Fields fields and public custom taxonomies.

= What happens to my data when I delete the plugin? =

SteadyPost's settings, import history and uploaded files are removed. Your posts, and the images in your media library, stay.

== Screenshots ==

1. Overview: posts managed, recent imports and quick actions.
2. Import: download a template, upload your spreadsheet, and check the column mapping.
3. Preview every row and tick the ones to import; dry run shows what would happen.
4. History: every import with its log, and undo.
5. Export existing posts to a spreadsheet for bulk editing.
6. Settings: source, row filter, SEO fields and defaults.

== Changelog ==

= 1.3.0 =
* New: import from an uploaded CSV or Excel file — no Google account needed. Google Sheets is now optional.
* New: blank and sample templates, with your custom fields and taxonomies as columns.
* New: export posts to a spreadsheet and re-import them to bulk-edit.
* New: dry run, import history and undo.
* New: Markdown in the Content column; images by filename from a zip or the media library.
* New: column mapping on the Import screen; Overview screen.
* New: scheduled sync for Google Sheets.
* Changed: publish dates are read in the site's timezone.
* Changed: admin screens redesigned.

= 1.2.0 =
* Google service accounts for privately shared sheets and docs; row filter and row picker; SEO plugin support.

== Upgrade Notice ==

= 1.3.0 =
Import from CSV or Excel without Google, plus export, dry run, history and undo. Publish dates are now read in your site's timezone. Check any scheduled rows after upgrading.
