Skip to content

Commit

Permalink
Rewrite WordPress URLs to relative URLs when serializing to markdown
Browse files Browse the repository at this point in the history
  • Loading branch information
adamziel committed Jan 2, 2025
1 parent b2755d7 commit a9202bb
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ private function block_to_markdown($block) {
return "{$fence}{$language}\n{$code}\n{$fence}\n\n";

case 'core/image':
if(!isset($attributes['url'])) {
$processor = WP_Data_Liberation_HTML_Processor::create_fragment($inner_html);
if($processor->next_tag('img')) {
$attributes['url'] = $processor->get_attribute('src');
$attributes['alt'] = $processor->get_attribute('alt');
}
}
return "![" . ($attributes['alt'] ?? '') . "](" . ($attributes['url'] ?? '') . ")\n\n";

case 'core/heading':
Expand Down
61 changes: 54 additions & 7 deletions packages/playground/data-liberation-static-files-editor/plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@
use WordPress\Filesystem\WP_Filesystem_Visitor;
use WordPress\Filesystem\WP_Uploaded_Directory_Tree_Filesystem;

if ( ! defined( 'WP_STATIC_CONTENT_DIR' ) ) {
define( 'WP_STATIC_CONTENT_DIR', WP_CONTENT_DIR . '/uploads/static-pages' );
if ( ! defined( 'WP_STATIC_PAGES_DIR' ) ) {
define( 'WP_STATIC_PAGES_DIR', WP_CONTENT_DIR . '/uploads/static-pages' );
}

if ( ! defined( 'WP_STATIC_MEDIA_DIR' ) ) {
define( 'WP_STATIC_MEDIA_DIR', WP_STATIC_PAGES_DIR . '/media' );
}

if( ! defined( 'WP_LOCAL_FILE_POST_TYPE' )) {
Expand Down Expand Up @@ -52,11 +56,10 @@ class WP_Static_Files_Editor_Plugin {

static private function get_fs() {
if(!self::$fs) {
$dot_git_path = WP_CONTENT_DIR . '/.static-pages.git';
if(!is_dir($dot_git_path)) {
mkdir($dot_git_path, 0777, true);
if(!is_dir(WP_STATIC_PAGES_DIR)) {
mkdir(WP_STATIC_PAGES_DIR, 0777, true);
}
$local_fs = new WP_Local_Filesystem($dot_git_path);
$local_fs = new WP_Local_Filesystem(WP_STATIC_PAGES_DIR);
$repo = new WP_Git_Repository($local_fs);
$repo->add_remote('origin', GIT_REPO_URL);
$repo->set_ref_head('HEAD', 'refs/heads/' . GIT_BRANCH);
Expand Down Expand Up @@ -517,6 +520,8 @@ static private function convert_post_to_string($path, $post) {
// ones explicitly set by the user in the editor?
$content = get_post_field('post_content', $post_id);
$content = self::unwordpressify_static_assets_urls($content);

switch($extension) {
// @TODO: Add support for HTML and XHTML
case 'html':
Expand All @@ -530,6 +535,48 @@ static private function convert_post_to_string($path, $post) {
return $converter->get_result();
}

/**
* Convert references to files served via download_file_endpoint
* to an absolute path referring to the corresponding static files
* in the local filesystem.
*/
static private function unwordpressify_static_assets_urls($content) {
$site_url = WP_URL::parse(get_site_url());
$expected_endpoint_path = '/wp-json/static-files-editor/v1/download-file';
$p = WP_Block_Markup_Url_Processor::create_from_html($content, $site_url);
while($p->next_url()) {
$url = $p->get_parsed_url();
if(!is_child_url_of($url, get_site_url())) {
continue;
}

// Account for sites with no nice permalink structure
if($url->searchParams->has('rest_route')) {
$url = WP_URL::parse($url->searchParams->get('rest_route'), $site_url);
}

// Naively check for the endpoint that serves the file.
// WordPress can use a custom REST API prefix which this
// check doesn't account for. It assumes the endpoint path
// is unique enough to not conflict with other paths.
//
// It may need to be revisited if any conflicts arise in
// the future.
if(!str_ends_with($url->pathname, $expected_endpoint_path)) {
continue;
}

// At this point we're certain the URL intends to download
// a static file managed by this plugin.

// Let's replace the URL in the content with the relative URL.
$original_url = $url->searchParams->get('path');
$p->set_raw_url($original_url);
}

return $p->get_updated_html();
}

static public function get_local_files_tree($subdirectory = '') {
$tree = [];
$fs = self::get_fs();
Expand Down Expand Up @@ -608,7 +655,7 @@ static private function build_local_file_tree_recursive($fs, $dir, &$tree, $path
* @TODO: Error handling
*/
static public function import_static_pages() {
if ( ! is_dir( WP_STATIC_CONTENT_DIR ) ) {
if ( ! is_dir( WP_STATIC_PAGES_DIR ) ) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ import {
import apiFetch from '@wordpress/api-fetch';
import {
addComponentToEditorContentArea,
addLoadingOverlay,
addLocalFilesTab,
} from './add-local-files-tab';
import { store as blockEditorStore } from '@wordpress/block-editor';
import { Spinner, Button } from '@wordpress/components';
import { Spinner } from '@wordpress/components';
import { useEntityProp, store as coreStore } from '@wordpress/core-data';
import css from './style.module.css';
import { FileTree } from 'components/FilePickerTree/types';
Expand Down Expand Up @@ -79,42 +78,39 @@ function ConnectedFilePickerTree() {

// Get the current post's file path from meta
const [meta] = useEntityProp('postType', WP_LOCAL_FILE_POST_TYPE, 'meta');
const [selectedPath, setSelectedPath] = useState(
meta?.local_file_path || '/'

const initialPostId = useSelect(
(select) => select(editorStore).getCurrentPostId(),
[]
);

const [selectedNode, setSelectedNode] = useState({
path: meta?.local_file_path || '/',
postId: initialPostId,
type: 'folder' as 'file' | 'folder',
});

useEffect(() => {
async function refreshPostId() {
console.log(
'refreshPostId',
selectedPath,
isStaticAssetPath(selectedPath)
);
if (isStaticAssetPath(selectedPath)) {
if (isStaticAssetPath(selectedNode.path)) {
setPostLoading(false);
setSelectedPostId(null);
setPreviewPath(selectedPath);
} else {
setSelectedNode((prev) => ({ ...prev, postId: null }));
setPreviewPath(selectedNode.path);
} else if (selectedNode.type === 'file') {
setPostLoading(true);
if (!selectedPostId) {
if (!selectedNode.postId) {
const { post_id } = (await apiFetch({
path: '/static-files-editor/v1/get-or-create-post-for-file',
method: 'POST',
data: { path: selectedPath },
data: { path: selectedNode.path },
})) as { post_id: string };
setSelectedPostId(post_id);
setSelectedNode((prev) => ({ ...prev, postId: post_id }));
}
setPreviewPath(null);
}
}
refreshPostId();
}, [selectedPath]);

const initialPostId = useSelect(
(select) => select(editorStore).getCurrentPostId(),
[]
);
const [selectedPostId, setSelectedPostId] = useState(initialPostId);
}, [selectedNode.path]);

const { post, hasLoadedPost, onNavigateToEntityRecord } = useSelect(
(select) => {
Expand All @@ -127,16 +123,16 @@ function ConnectedFilePickerTree() {
post: getEntityRecord(
'postType',
WP_LOCAL_FILE_POST_TYPE,
selectedPostId
selectedNode.postId
),
hasLoadedPost: hasFinishedResolution('getEntityRecord', [
'postType',
WP_LOCAL_FILE_POST_TYPE,
selectedPostId,
selectedNode.postId,
]),
};
},
[selectedPostId]
[selectedNode.postId]
);

const { setPostLoading, setPreviewPath } = useDispatch(STORE_NAME);
Expand All @@ -145,16 +141,16 @@ function ConnectedFilePickerTree() {
// Only navigate once the post has been loaded. Otherwise the editor
// will disappear for a second – the <Editor> component renders its
// children conditionally on having the post available.
if (selectedPostId) {
if (selectedNode.postId) {
setPostLoading(!hasLoadedPost);
if (hasLoadedPost && post) {
onNavigateToEntityRecord({
postId: selectedPostId,
postId: selectedNode.postId,
postType: WP_LOCAL_FILE_POST_TYPE,
});
}
}
}, [hasLoadedPost, post, setPostLoading, selectedPostId]);
}, [hasLoadedPost, post, setPostLoading, selectedNode.postId]);

const refreshFileTree = useCallback(async () => {
fileTreePromise = apiFetch({
Expand Down Expand Up @@ -190,12 +186,11 @@ function ConnectedFilePickerTree() {
};

const handleFileClick = async (filePath: string, node: FileNode) => {
setSelectedPath(filePath);
if (node.post_id && !isStaticAssetPath(filePath)) {
setSelectedPostId(node.post_id);
} else {
setSelectedPostId(null);
}
setSelectedNode({
path: filePath,
postId: node.post_id,
type: node.type,
});
};

const handleNodesCreated = async (tree: FileTree) => {
Expand Down Expand Up @@ -305,7 +300,7 @@ function ConnectedFilePickerTree() {
<FilePickerTree
files={fileTree}
onSelect={handleFileClick}
initialPath={selectedPath}
initialPath={selectedNode.path}
onNodesCreated={handleNodesCreated}
onNodeDeleted={handleNodeDeleted}
onNodeMoved={handleNodeMoved}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ class WP_Block_Markup_Url_Processor extends WP_Block_Markup_Processor {
private $url_in_text_node_updated;
private $inspected_url_attribute_idx = - 1;

/**
* @return WP_Block_Markup_Url_Processor
*/
public static function create_from_html( $html, $base_url_string = null ) {
$processor = static::create_fragment( $html );
$processor->base_url_string = $base_url_string;
Expand Down

0 comments on commit a9202bb

Please sign in to comment.