WooCommerce Docs: Delete posts when it removed from the manifest (#39395)

This commit is contained in:
Paul Sealock 2023-08-04 14:00:50 +12:00 committed by GitHub
parent 0d8d824b47
commit b14653ede0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 203 additions and 25 deletions

View File

@ -10,7 +10,7 @@
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/plugins/woocommerce-docs/example-docs/get-started/local-development.md",
"id": "1a3672ea88756c6d00a3b3baa3f7481b361c8a1e",
"links": {
"./installation/install-plugin.md": "16d17f790732fcdc0560d2ae24490be272e2fe39"
"./installation/install-plugin.md": "6c7bb21cb195798a444844fef0ff79aacff86de1"
}
}
],
@ -38,7 +38,7 @@
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/plugins/woocommerce-docs/example-docs/get-started/troubleshooting/what-went-wrong.md",
"id": "e2f590a5994fada97bdbdcac751e8bc441530868",
"links": {
"../../testing/unit-tests.md": "079882c5dbbc1da106e3acc8df4102643e6c2f59"
"../../testing/unit-tests.md": "6f1b9c74de42a10cf4c77c2843e0fbdf1ff46316"
}
}
],
@ -67,5 +67,5 @@
"categories": []
}
],
"hash": "00958a305458e9fc9191eb56309ab88ab459f10d059cad5fbb74824f9e0d4010"
"hash": "c727b2b8092cae90356d44d2803e5c70688b548b474467c994f55431055fbb69"
}

View File

@ -118,10 +118,15 @@ class DocsStore {
/**
* Delete a docs post
*
* @param int $post_id The post ID to delete.
* @param int $doc_id The ID to delete from a post's entry in the manifest.
*/
public static function delete_docs_post( $post_id ) {
return wp_delete_post( $post_id );
public static function delete_docs_post( $doc_id ) {
$post = self::get_post( $doc_id );
if ( null !== $post ) {
return wp_delete_post( $post->ID, true );
} else {
return false;
}
}
/**

View File

@ -75,9 +75,12 @@ class ManifestJob {
\ActionScheduler_Logger::instance()->log( $action_id, "Manifest hash changed: `$hash`, processing manifest." );
} else {
\ActionScheduler_Logger::instance()->log( $action_id, 'No previous manifest found, processing manifest.' );
$existing_manifest = null;
}
$doc_ids = ManifestProcessor::process_manifest( $json, $action_id );
ManifestProcessor::process_manifest( $json, $action_id, $existing_manifest );
$doc_ids = ManifestProcessor::collect_doc_ids_from_manifest( $json );
$relative_links = RelativeLinkParser::extract_links_from_manifest( $json );
foreach ( $doc_ids as $doc_id ) {
@ -92,6 +95,7 @@ class ManifestJob {
\ActionScheduler_Logger::instance()->log( $action_id, "During link replacement, post was not found for doc: `$doc_id`" );
}
}
Data\ManifestStore::update_manifest( $manifest_url, $json );
} else {
\ActionScheduler_Logger::instance()->log( $action_id, "Manifest hash unchanged: `$hash`, skipping manifest." );

View File

@ -15,11 +15,13 @@ class ManifestProcessor {
*
* @param Object $manifest The manifest to process.
* @param int $logger_action_id The logger action ID.
* @param Object $previous_manifest The previous manifest.
*/
public static function process_manifest( $manifest, $logger_action_id ) {
$doc_ids = array();
self::process_categories( $manifest['categories'], $logger_action_id, $doc_ids );
return $doc_ids;
public static function process_manifest( $manifest, $logger_action_id, $previous_manifest = null ) {
if ( $previous_manifest ) {
PostRemover::remove_deleted_posts( $manifest, $previous_manifest, $logger_action_id );
}
self::process_categories( $manifest['categories'], $logger_action_id );
}
/**
@ -27,10 +29,9 @@ class ManifestProcessor {
*
* @param array $categories The categories to process.
* @param int $logger_action_id The logger action ID.
* @param array $doc_ids An array to maintain a list of created/updated post IDs.
* @param int $parent_id The parent ID.
*/
private static function process_categories( $categories, $logger_action_id, &$doc_ids, $parent_id = 0 ) {
private static function process_categories( $categories, $logger_action_id, $parent_id = 0 ) {
foreach ( $categories as $category ) {
$term = CategoryCreator::create_or_update_category_from_manifest_entry( $category, $parent_id );
@ -48,19 +49,33 @@ class ManifestProcessor {
$content = wp_remote_retrieve_body( $response );
$post_id = PostCreator::create_or_update_post_from_manifest_entry( $post, $content, $category['category_title'], $logger_action_id );
$doc_id = DocsStore::get_doc_id_by_post_id( $post_id );
// Add the post ID to the list of post IDs.
$doc_ids[] = $doc_id;
wp_set_post_categories( $post_id, array( $term['term_id'] ) );
}
// Process any sub-categories.
if ( ! empty( $category['categories'] ) ) {
self::process_categories( $category['categories'], $logger_action_id, $doc_ids, $term['term_id'] );
self::process_categories( $category['categories'], $logger_action_id, $term['term_id'] );
}
}
}
/**
* Recusively collect post IDs from a manifest.
*
* @param Object $manifest The manifest to process.
*/
public static function collect_doc_ids_from_manifest( $manifest ) {
$doc_ids = array();
foreach ( $manifest['categories'] as $category ) {
foreach ( $category['posts'] as $post ) {
$doc_ids[] = $post['id'];
}
$subcategory_ids = self::collect_doc_ids_from_manifest( $category );
$doc_ids = array_merge( $doc_ids, $subcategory_ids );
}
return $doc_ids;
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace WooCommerceDocs\Manifest;
use WooCommerceDocs\Data\DocsStore;
/**
* Class Remover
*
* Remove posts that are no longer in the manifest.
*
* @package WooCommerceDocs\Manifest
*/
class PostRemover {
/**
* Remove posts that are no longer in the manifest.
*
* @param Object $manifest The manifest to process.
* @param Object $previous_manifest The previous manifest.
* @param int $logger_action_id The logger action ID.
*/
public static function remove_deleted_posts( $manifest, $previous_manifest, $logger_action_id ) {
$doc_ids_to_delete = self::get_doc_ids_to_delete( $manifest, $previous_manifest );
foreach ( $doc_ids_to_delete as $doc_id ) {
\ActionScheduler_Logger::instance()->log( $logger_action_id, 'Removing post deleted post with document id: ' . $doc_id );
DocsStore::delete_docs_post( $doc_id );
}
}
/**
* Get a list of doc IDs to delete.
*
* @param Object $manifest The manifest to process.
* @param Object $previous_manifest The previous manifest.
*/
public static function get_doc_ids_to_delete( $manifest, $previous_manifest ) {
$manifest_doc_ids = ManifestProcessor::collect_doc_ids_from_manifest( $manifest );
$previous_manifest_doc_ids = ManifestProcessor::collect_doc_ids_from_manifest( $previous_manifest );
return array_diff( $previous_manifest_doc_ids, $manifest_doc_ids );
}
}

View File

@ -122,4 +122,18 @@ class ManifestProcessorTest extends WP_UnitTestCase {
$edit_url_what_went_wrong_post = DocsStore::get_edit_url_from_docs_post( $what_went_wrong_post->ID, 'edit_url', true );
$this->assertEquals( 'https://example.com/edit/get-started/troubleshooting/what-went-wrong.md', $edit_url_what_went_wrong_post );
}
/**
* Test collecting doc IDs from a manifest.
*/
public function test_collect_doc_ids_from_manifest() {
$manifest = json_decode( file_get_contents( __DIR__ . '/fixtures/manifest.json' ), true );
$doc_ids = ManifestProcessor::collect_doc_ids_from_manifest( $manifest );
$this->assertEquals( 4, count( $doc_ids ) );
$this->assertContains( 'c068ce54044fa44c760a69bd71ef21274f2a5a37', $doc_ids );
$this->assertContains( 'fb59bd01dda7b090e5b0a557948e155a6b679d6a', $doc_ids );
$this->assertContains( '1f88c4d039e72c059c928ab475ad1ea0a02c8abb', $doc_ids );
$this->assertContains( '120770c899215a889246b47ac883e4dda1f97b8b', $doc_ids );
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace WooCommerceDocs\Tests\Manifest;
use WP_UnitTestCase;
use WooCommerceDocs\Manifest\PostRemover;
/**
* Class PostRemoverTest
*
* @package WooCommerceDocs\Tests\Manifest
*/
class PostRemoverTest extends WP_UnitTestCase {
/**
* Test getting doc IDs to delete.
*/
public function test_get_doc_ids_to_delete() {
// Test identical manifests that should return no doc IDs to delete.
$manifest = json_decode( file_get_contents( __DIR__ . '/fixtures/manifest.json' ), true );
$previous_manifest = json_decode( file_get_contents( __DIR__ . '/fixtures/manifest.json' ), true );
$doc_ids_to_delete = PostRemover::get_doc_ids_to_delete( $manifest, $previous_manifest );
$this->assertEquals( 0, count( $doc_ids_to_delete ) );
// Test a post removed by adding a post to the previous_manifest.
$updated_previous_manifest = $manifest;
$updated_previous_manifest['categories'][0]['posts'][] = array(
'id' => '123456789',
'post_title' => 'Test Post Title',
);
$doc_ids_to_delete = PostRemover::get_doc_ids_to_delete( $manifest, $updated_previous_manifest );
$this->assertEquals( 1, count( $doc_ids_to_delete ) );
$this->assertContains( '123456789', $doc_ids_to_delete );
}
}

View File

@ -73,6 +73,7 @@ export const generateManifestCommand = new Command( 'create' )
const manifestWithLinks = await processMarkdownLinks(
manifest,
absoluteRootDir,
absoluteSubDir,
projectName
);

View File

@ -0,0 +1,47 @@
/**
* External dependencies
*/
import path from 'path';
/**
* Internal dependencies
*/
import { generateManifestFromDirectory } from '../generate-manifest';
import { processMarkdownLinks } from '../markdown-links';
describe( 'processMarkdownLinks', () => {
const dir = path.join( __dirname, './fixtures/example-docs' );
const rootDir = path.join( __dirname, './fixtures' );
it( 'should add the correct relative links to a manifest', async () => {
// generate the manifest from fixture directory
const manifest = await generateManifestFromDirectory(
rootDir,
dir,
'example-docs',
'https://example.com',
'https://example.com/edit'
);
const manifestWithLinks = await processMarkdownLinks(
manifest,
rootDir,
dir,
'example-docs'
);
const localDevelopmentPost =
manifestWithLinks.categories[ 0 ].posts[ 0 ];
expect(
localDevelopmentPost.links[ './installation/install-plugin.md' ]
).toBeDefined();
const installationPost =
manifestWithLinks.categories[ 0 ].categories[ 0 ].posts[ 0 ];
expect(
localDevelopmentPost.links[ './installation/install-plugin.md' ]
).toEqual( installationPost.id );
} );
} );

View File

@ -12,13 +12,15 @@ import { Category, Post, generatePostId } from './generate-manifest';
/**
* Process relative markdown links in the manifest.
*
* @param manifest Category or Post
* @param rootDirectory Root directory of the project
* @param projectName Name of the project
* @param manifest Category or Post
* @param rootDirectory Root directory of the project
* @param absoluteSubDir Path to directory of Markdown files to generate the manifest from.
* @param projectName Name of the project
*/
export const processMarkdownLinks = (
manifest: Category,
rootDirectory: string,
absoluteSubDir: string,
projectName: string
) => {
const updatedManifest: Category = { ...manifest };
@ -36,14 +38,18 @@ export const processMarkdownLinks = (
let match;
while ( ( match = linkRegex.exec( fileContent ) ) ) {
const relativePath = match[ 1 ];
const linkedFilePath = path.resolve(
const absoluteLinkedFilePath = path.resolve(
path.dirname( filePath ),
relativePath
);
const relativeLinkedFilePath = path.relative(
absoluteSubDir,
absoluteLinkedFilePath
);
if ( fs.existsSync( linkedFilePath ) ) {
if ( fs.existsSync( absoluteLinkedFilePath ) ) {
const linkedId = generatePostId(
linkedFilePath,
relativeLinkedFilePath,
projectName
);
updatedPost.links = updatedPost.links || {};
@ -60,7 +66,12 @@ export const processMarkdownLinks = (
if ( updatedManifest.categories ) {
updatedManifest.categories = updatedManifest.categories.map(
( category ) =>
processMarkdownLinks( category, rootDirectory, projectName )
processMarkdownLinks(
category,
rootDirectory,
absoluteSubDir,
projectName
)
);
}