Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Data Liberation] Use WordPress for editing static files in a local directory #2098

Draft
wants to merge 27 commits into
base: trunk
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1c66dd0
[Data Liberation] Add HTML to Blocks converter
adamziel Dec 17, 2024
a46edf9
Add docstrings and a missing constant
adamziel Dec 17, 2024
92ced0a
Lightly document WP_Entity_Reader
adamziel Dec 17, 2024
92fda0a
Update tests
adamziel Dec 17, 2024
2bf0ce0
Merge branch 'trunk' into html-importer
adamziel Dec 17, 2024
2d0198a
Update test fixture
adamziel Dec 17, 2024
d32f0dd
Update test fixtures, disable autoformatting
adamziel Dec 17, 2024
0faab1a
[Data Liberation] Reorganize reader classes
adamziel Dec 17, 2024
55c9e4e
Remove epub reader reference
adamziel Dec 17, 2024
e01dec8
[Data Liberation] Add Epub importer
adamziel Dec 17, 2024
d293c22
Use WP_XML_Reader for EPubs, support simple DOCTYPE declarations in XML
adamziel Dec 17, 2024
58def6c
Parse EPubs as XHTML
adamziel Dec 17, 2024
608b5e8
[Data Liberation] Import static files from a local static-pages direc…
adamziel Dec 17, 2024
e44d2c2
Experimental static page editing workflow and blocks -> markdown conv…
adamziel Dec 18, 2024
eab1317
Improve conversion to markdown
adamziel Dec 18, 2024
1cb383a
Unit test the directory reader commit the missing files
adamziel Dec 19, 2024
273fb8f
Split out WP_Filesystem_To_Post_Hierarchy to enable turning each file…
adamziel Dec 19, 2024
753993c
Remove the unimplemented get_reentrancy_cursor method
adamziel Dec 19, 2024
daa1e87
Use a generic WP_Block_Markup_Entity_Reader for sourcing entities fro…
adamziel Dec 19, 2024
851ad04
Adjust the used array heys
adamziel Dec 19, 2024
cbdbb8e
Save data to the original static file path
adamziel Dec 20, 2024
0375bbe
Rewrite Blocks to Markdown
adamziel Dec 20, 2024
f9eb988
Two way Blocks <-> Markdown conversion pipeline
adamziel Dec 20, 2024
63c1f6b
Early concept of synchronizing page saves to local files
adamziel Dec 20, 2024
9b65f92
Propagate WP Admin changes to the local disk directory
adamziel Dec 22, 2024
3c04e0f
Document a bunch of todos
adamziel Dec 22, 2024
cb20c92
Adjust docstrings
adamziel Dec 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ __pycache__
packages/playground/wordpress-builds/src/wordpress
packages/playground/wordpress-builds/public
packages/playground/sync/src/test/wp-*
packages/playground/data-liberation/tests/fixtures
packages/php-wasm/node/src/test/__test*
*.timestamp-1678999213403.mjs
.local
Expand Down
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
/packages/playground/wordpress-builds/build/build-assets
/packages/playground/wordpress-builds/src/wordpress
/packages/playground/wordpress-builds/public/
/packages/playground/data-liberation/tests/fixtures
/packages/php-wasm/node/src/test/__test*
__pycache__
*.timestamp-1678999213403.mjs
Expand Down
117 changes: 97 additions & 20 deletions packages/playground/blueprints/src/lib/steps/activate-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { phpVar } from '@php-wasm/util';
import { StepHandler } from '.';
import { logger } from '@php-wasm/logger';

/**
* @inheritDoc activatePlugin
* @example
Expand Down Expand Up @@ -39,18 +37,18 @@ export const activatePlugin: StepHandler<ActivatePluginStep> = async (
progress?.tracker.setCaption(`Activating ${pluginName || pluginPath}`);

const docroot = await playground.documentRoot;
const result = await playground.run({
const activatePluginResult = await playground.run({
code: `<?php
define( 'WP_ADMIN', true );
require_once( ${phpVar(docroot)}. "/wp-load.php" );
require_once( ${phpVar(docroot)}. "/wp-admin/includes/plugin.php" );
require_once( getenv('DOCROOT') . "/wp-load.php" );
require_once( getenv('DOCROOT') . "/wp-admin/includes/plugin.php" );

// Set current user to admin
wp_set_current_user( get_users(array('role' => 'Administrator') )[0]->ID );

$plugin_path = ${phpVar(pluginPath)};
$plugin_path = getenv('PLUGIN_PATH');
$response = false;
if (!is_dir($plugin_path)) {
if ( ! is_dir( $plugin_path)) {
$response = activate_plugin($plugin_path);
}

Expand All @@ -65,22 +63,101 @@ export const activatePlugin: StepHandler<ActivatePluginStep> = async (
}
}

if ( null === $response ) {
die('Plugin activated successfully');
} else if ( is_wp_error( $response ) ) {
throw new Exception( $response->get_error_message() );
if ( is_wp_error($response) ) {
die( $response->get_error_message() );
} else if ( false === $response ) {
die( "The activatePlugin step wasn't able to find the plugin $plugin_path." );
}

throw new Exception( 'Unable to activate plugin' );
`,
env: {
PLUGIN_PATH: pluginPath,
DOCROOT: docroot,
},
});
if (result.text !== 'Plugin activated successfully') {
logger.debug(result);
throw new Error(
`Plugin ${pluginPath} could not be activated – WordPress exited with no error. ` +
`Sometimes, when $_SERVER or site options are not configured correctly, ` +
`WordPress exits early with a 301 redirect. ` +
`Inspect the "debug" logs in the console for more details`
if (activatePluginResult.text) {
logger.warn(
`Plugin ${pluginPath} activation printed the following bytes: ${activatePluginResult.text}`
);
}

/**
* Instead of checking the plugin activation response,
* check if the plugin is active by looking at the active plugins list.
*
* We have to split the activation and the check into two PHP runs
* because some plugins might redirect during activation,
* which would prevent any output that happens after activation from being returned.
*
* Relying on the plugin activation response is not reliable because if the plugin activation
* produces any output, WordPress will assume it's an activation error and return a WP_Error.
* WordPress will still activate the plugin and load the required page,
* but it will also show the error as a notice in wp-admin.
* See WordPress source code for more details:
* https://github.com/WordPress/wordpress-develop/blob/6.7/src/wp-admin/includes/plugin.php#L733
*
* Because some plugins can create an output, we need to use output buffering
* to ensure the 'true' response is not polluted by other outputs.
* If the plugin activation fails, we will return the buffered output as it might
* contain more information about the failure.
*/
const isActiveCheckResult = await playground.run({
code: `<?php
ob_start();
require_once( getenv( 'DOCROOT' ) . "/wp-load.php" );

/**
* Extracts the relative plugin path from either an absolute or relative plugin path.
*
* Absolute paths starting with plugin directory (e.g., '/wordpress/wp-content/plugins/test-plugin/index.php')
* should be converted to relative paths (e.g., 'test-plugin/index.php')
*
* Directories should finish with a trailing slash to ensure we match the full plugin directory name.
*
* Examples:
* - '/wordpress/wp-content/plugins/test-plugin/index.php' → 'test-plugin/index.php'
* - '/wordpress/wp-content/plugins/test-plugin/' → 'test-plugin/'
* - '/wordpress/wp-content/plugins/test-plugin' → 'test-plugin/'
* - 'test-plugin/index.php' → 'test-plugin/index.php'
* - 'test-plugin/' → 'test-plugin/'
* - 'test-plugin' → 'test-plugin/'
*/
$plugin_directory = WP_PLUGIN_DIR . '/';
$relative_plugin_path = getenv( 'PLUGIN_PATH' );
if (strpos($relative_plugin_path, $plugin_directory) === 0) {
$relative_plugin_path = substr($relative_plugin_path, strlen($plugin_directory));
}

if ( is_dir( $plugin_directory . $relative_plugin_path ) ) {
$relative_plugin_path = rtrim( $relative_plugin_path, '/' ) . '/';
}

$active_plugins = get_option( 'active_plugins' );
foreach ( $active_plugins as $plugin ) {
if ( substr( $plugin, 0, strlen( $relative_plugin_path ) ) === $relative_plugin_path ) {
ob_end_clean();
die( 'true' );
}
}
die( ob_get_flush() ?: 'false' );
`,
env: {
DOCROOT: docroot,
PLUGIN_PATH: pluginPath,
},
});

if (isActiveCheckResult.text === 'true') {
// Plugin activation was successful, yay!
return;
}

if (isActiveCheckResult.text !== 'false') {
logger.debug(isActiveCheckResult.text);
}
throw new Error(
`Plugin ${pluginPath} could not be activated – WordPress exited with no error. ` +
`Sometimes, when $_SERVER or site options are not configured correctly, ` +
`WordPress exits early with a 301 redirect. ` +
`Inspect the "debug" logs in the console for more details.`
);
};
5 changes: 5 additions & 0 deletions packages/playground/data-liberation-markdown/plugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php
/**
* Plugin Name: Data Liberation – Markdown importer
*/
require_once __DIR__ . '/src/bootstrap.php';
Loading
Loading