License: GPLv2
License URI: http://www.gnu.org/licenses/gpl-2.0.html
This WordPress plugin allows you writing on GitHub (or Jekyll site). This was forked from litefeel/writing-on-github and contains modifications specific to the Embedded Artistry website.
This plugin provides the following services to our organization:
- Posts of specified types are automatically exported to the associated GitHub repository upon creation
- Edits to a post on the Wordpress front-end will be synchronized to GitHub
- Changes made in the GitHub repository will be synchronized with the Wordpress front-end.
Specified types:
- post
- page
- courses
- lessons
- newsletters
- Field Atlas entries
- Glossary entries
- WooCommerce products and product variations
Caveats:
- Posts cannot be deleted on the front-end by removing files from the repository
- Posts cannot be added to the front-end by adding new files with the appropriate metadata header to the repository (unlike the litefeel version)
These limitations are in place to prevent front-end problems, whether due to a bad commit or due to the need for complex
The sync action is based on two web hooks:
- A per-post sync fired in response to WordPress's
save_posthook which pushes content to GitHub - A sync of all changed files triggered by GitHub's
pushweb hook (outbound API call)
The plugin runs the import/export path as the configured user (set in the Wordpress front-end settings page for this plugin). This user must have the appropriate permissions to access the relevant content.
Products and product variations are synced bidirectionally alongside posts. Files land at:
products/<slug>.md # simple, external, variable parent
products/<parent-slug>/variations/<variation-slug>.md # variations of a variable product
The frontmatter captures product configuration: identity (product_type, sku, featured, catalog_visibility), pricing (regular_price, sale_price, sale dates, tax fields), inventory configuration (manage_stock, stock_status, backorders, sold_individually), shipping (weight, dimensions, shipping_class), type flags (virtual, downloadable), external-product fields (product_url, button_text), taxonomies (product_categories, product_tags), and an attributes block for both global (pa_*) and local attributes. Variable parents include a variations: index listing the slugs of their child files. Variation files include a parent_slug reference and an attribute_values map.
- Order-driven runtime state:
_stock/_stock_quantity,total_sales, and the derived_price. These mutate every time an order is placed; excluding them keeps the repo from churning. WooCommerce recomputes_pricefromregular_price/sale_priceon import. - Downloadable file metadata:
_download_files,_download_limit,_download_expiry. File paths are environment-specific. - Cross-product references:
_upsell_ids,_crosssell_ids. Attachment IDs do not round-trip cleanly when used purely for navigation. - Reviews:
_wc_average_rating,_wc_review_count. Reviews are user-generated state, not configuration.
- WooCommerce code paths that bypass
save_post(most of the REST API and some bulk-edit flows) will not trigger an export. Edits made through the standard product-editor UI sync as expected. - Global attribute taxonomies (
pa_*) are not auto-created on import. If a referencedpa_*taxonomy does not exist on the target site, the attribute is downgraded to a local attribute and a warning is logged.
Image references in product frontmatter use attachment IDs (featured_image_id, gallery_image_ids). To make those IDs human-discoverable when you are authoring a product file in git, the plugin maintains a media-index.json file at the root of the repo. Each entry maps an attachment ID to its source URL, file path, mime type, alt text, and title:
{
"4271": {
"url": "https://embeddedartistry.com/wp-content/uploads/2024/03/foo.jpg",
"file": "2024/03/foo.jpg",
"mime": "image/jpeg",
"alt": "Foo product photo",
"title": "Foo"
}
}The index is rebuilt and pushed to GitHub at most once per request, on shutdown, after any of add_attachment, attachment_updated, or delete_attachment fires. Bulk uploads produce a single commit. Pushes are skipped when the rendered content matches what is already in the repo.
-
Upload images in the WordPress media library.
-
git pulland openmedia-index.jsonto find the attachment IDs you want. -
Reference them in your product file:
featured_image_id: 4271 gallery_image_ids: [4272, 4273]
-
Push. On import, the plugin sets the featured image and
_product_image_gallerydirectly. Any ID that does not exist in the local media library is logged as a warning and skipped.
On first run, seed the full library with:
$ wp wghs media_index_rebuild
After that, the per-request hooks keep it current.
You cannot clone this repository directly to the server - it needs to be prepared for release with composer, or you need to run the command below inside the git repository on the server.
Run this command from the plugin root:
$ composer install
Settings and dependencies are defined in composer.json.
Once composer has been installed, you can
TODO: UPDATE THIS ONCE PROCESS IS IMPROVED
- Navigate to the 'Add New' in the Wordpress Plugin dashboard
- Navigate to the 'Upload' area
- Select
wordpress-github-sync.zipfrom your computer - Click 'Install Now'
- Activate the plugin in the Plugin dashboard
You can also SSH into the web server. Navigate to public_html/wp_content/plugins and clone the repository:
git clone https://github.com/embeddedartistry/wordpress-github-sync.git
Enter the directory and run composer install.
Now you can navigate to the Plugin dashboard in the Wordpress front-end and activate the new plugin.
- Create a personal oauth token with the
public_reposcope. If you'd prefer not to use your account, you can create another GitHub account for this. - Configure your GitHub host, repository, secret (defined in the next step), and OAuth Token on the Wordpress-GitHub Sync settings page within WordPress's administrative interface. Make sure the repository has an initial commit or the export will fail.
- Create a WebHook within your repository with the provided callback URL and callback secret, using
application/jsonas the content type. To set up a web hook on GitHub, head over to the Settings page of your repository, and click on Webhooks & services. After that, click on Add webhook. - Click
Export to GitHub
You can export posts through the CLI using this command. Note that a user ID of 0 will use the default configured in the admin screen.
$ wp wghs export all <user id> --debug
You can import existing posts through the CLI using this command.
wp wghs import 2
Pushes a fresh media-index.json to the repo root, dumping the entire WordPress media library. Use on first run, or any time you need to force a full rebuild.
$ wp wghs media_index_rebuild
TODO
Wordpress-GitHub Sync exports all posts as .md files for better display on GitHub (and, importantly for us, for use with pandoc for generating e-book files) However, note that all content is exported and imported as its original HTML. To enable writing, importing, and exporting in Markdown, please install and enable WP-Markdown, and Wordpress-GitHub Sync will use it to convert your posts to and from Markdown.
You can also activate the Markdown module from Jetpack or the standalone JP Markdown to save in Markdown and export that version to GitHub.
Note: There is a limitation with at least the Jetpack Markdown plugin. It will export both the markdown and the HTML contents. changes are not reflected properly unless you edit both.
This plugin depends on the following plugins to be installed:
- WP Rocket (for clearing the cache when a post is updated)
- Sensei LMS suite (for accessing course and lesson content)
- WooCommerce (for product and product variation sync; the product code paths are guarded by
function_exists( 'wc_get_product' )and inactive when WooCommerce is not loaded)