Remove docs plugin from monorepo (#44013)
* Remove docs plugin from monorepo * Add language to md-docs readme * Fix lint error in blocks * Add changefile(s) from automation for the following project(s): woocommerce-blocks --------- Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
parent
d66a48e8e5
commit
9b98a85380
|
@ -67,9 +67,6 @@
|
|||
'plugin: woo-ai':
|
||||
- plugins/woo-ai/**/*
|
||||
|
||||
'plugin: woocommerce docs':
|
||||
- plugins/woocommerce-docs/**/*
|
||||
|
||||
'focus: performance tests':
|
||||
- plugins/woocommerce/tests/performance/**/*
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ jobs:
|
|||
**/*.md
|
||||
files_ignore: |
|
||||
docs/**/*.md
|
||||
plugins/woocommerce-docs/tests/src/Blocks/fixtures/*.md
|
||||
|
||||
- name: Get docs changed files
|
||||
id: docs-changed-files
|
||||
|
|
|
@ -7,7 +7,6 @@ import { cli } from '@woocommerce/e2e-utils';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { REGULAR_PRICED_PRODUCT_NAME } from '../checkout/constants';
|
||||
import { CheckoutPage } from '../checkout/checkout.page';
|
||||
|
||||
const test = base.extend< { checkoutPageObject: CheckoutPage } >( {
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"root": true,
|
||||
"extends": [ "plugin:@woocommerce/eslint-plugin/recommended" ],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
},
|
||||
"rules": {
|
||||
"camelcase": 0,
|
||||
"react/react-in-jsx-scope": "off",
|
||||
"no-alert": "off",
|
||||
"@wordpress/no-unsafe-wp-apis": "off"
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
// Import the default config file and expose it in the project root.
|
||||
// Useful for editor integrations.
|
||||
module.exports = require('@wordpress/prettier-config');
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"phpVersion": "7.4",
|
||||
"plugins": [ "." ],
|
||||
"config": {
|
||||
"WP_DEBUG_LOG": true,
|
||||
"WP_DEBUG_DISPLAY": true
|
||||
},
|
||||
"env": {
|
||||
"development": {},
|
||||
"tests": {
|
||||
"port": 8086,
|
||||
"plugins": [ "." ],
|
||||
"themes": [
|
||||
"https://downloads.wordpress.org/theme/twentynineteen.zip"
|
||||
],
|
||||
"config": {
|
||||
"WP_TESTS_DOMAIN": "localhost"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
# WooCommerce Docs Plugin
|
||||
|
||||
This is a work-in-progress plugin with the desired goal of consolidating documentation from various sources
|
||||
into Wordpress posts.
|
||||
|
||||
Although this is called WooCommerce Docs, it should be able to be used with any Wordpress site and
|
||||
a manifest conforming to the data structure (TBD) to create Wordpress posts from Markdown content.
|
||||
|
||||
## Development
|
||||
|
||||
Set up the monorepo as usual, now from this directory run `pnpm build` to build the webpack assets.
|
||||
This plugin creates a top level menu called "WooCommerce Docs" that you can navigate to once
|
||||
you've mounted the plugin in your development environment.
|
||||
|
||||
You can use monorepo utils from the repo root to generate new manifests:
|
||||
|
||||
```
|
||||
pnpm utils md-docs create ./plugins/woocommerce-docs/example-docs woodocs --outputFilePath ./plugins/woocommerce-docs/scripts/manifest.json
|
||||
```
|
||||
|
||||
To load the manifest as a source in the plugin go to the plugin page and add a manifest with url:
|
||||
|
||||
`http://your-local-wp-host/wp-content/plugins/woocommerce-docs/scripts/manifest.json`
|
||||
|
||||
Please note that if you're hosting the file within Docker, that localhost will not work as the host for your file because that's reserved for localhost within the container. You'll need to use the IP address of your machine instead or on Mac OS you can use the Docker DNS name `host.docker.internal`.
|
|
@ -1,87 +0,0 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import {
|
||||
Card,
|
||||
CardBody,
|
||||
CardHeader,
|
||||
// @ts-ignore No types for this exist yet.
|
||||
__experimentalItem as Item,
|
||||
// @ts-ignore No types for this exist yet.
|
||||
__experimentalItemGroup as ItemGroup,
|
||||
// @ts-ignore No types for this exist yet.
|
||||
__experimentalScrollable as Scrollable,
|
||||
Spinner,
|
||||
} from '@wordpress/components';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { useJobLog } from '../data/useJobs';
|
||||
|
||||
export const JobLog = () => {
|
||||
const { jobLogs, isLoading, error } = useJobLog();
|
||||
|
||||
if ( isLoading ) {
|
||||
return (
|
||||
<Card elevation={ 3 }>
|
||||
<CardHeader>
|
||||
<h2>Job Log</h2>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<Spinner />
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
if ( error ) {
|
||||
return (
|
||||
<Card elevation={ 3 }>
|
||||
<CardHeader>
|
||||
<h2>Job Log</h2>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<p>{ error }</p>
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! jobLogs.length && ! isLoading ) {
|
||||
return (
|
||||
<Card elevation={ 3 }>
|
||||
<CardHeader>
|
||||
<h2>Job Log</h2>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<p>No job logs found.</p>
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Card elevation={ 3 }>
|
||||
<CardHeader>
|
||||
<h2>Job Log</h2>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<Scrollable style={ { maxHeight: 300 } }>
|
||||
<ItemGroup>
|
||||
{ jobLogs.map( ( jobLog, i ) => (
|
||||
<div key={ `${ jobLog.date }:${ i }` }>
|
||||
<Item>
|
||||
Message: { jobLog.message }
|
||||
<br></br>
|
||||
Logged at: { jobLog.date }
|
||||
</Item>
|
||||
<hr />
|
||||
</div>
|
||||
) ) }
|
||||
</ItemGroup>
|
||||
</Scrollable>
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
};
|
|
@ -1,106 +0,0 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import {
|
||||
Button,
|
||||
// @ts-ignore No types for this exist yet.
|
||||
__experimentalItem as Item,
|
||||
// @ts-ignore No types for this exist yet.
|
||||
__experimentalItemGroup as ItemGroup,
|
||||
Card,
|
||||
CardBody,
|
||||
CardHeader,
|
||||
CardFooter,
|
||||
Spinner,
|
||||
} from '@wordpress/components';
|
||||
import { useState } from 'react';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { useManifests } from '../data/useManifests';
|
||||
import { isURL } from '../util/url';
|
||||
|
||||
export const ManifestList = () => {
|
||||
const { manifests, isLoading, error, createManifest, deleteManifest } =
|
||||
useManifests();
|
||||
const [ newManifest, setNewManifest ] = useState< string >( '' );
|
||||
|
||||
if ( isLoading ) {
|
||||
return (
|
||||
<Card elevation={ 3 }>
|
||||
<CardHeader>
|
||||
<h2>Manifests</h2>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<Spinner />
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
if ( error ) {
|
||||
return (
|
||||
<Card elevation={ 3 }>
|
||||
<CardHeader>
|
||||
<h2>Manifests</h2>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<p>{ error }</p>
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Card elevation={ 3 }>
|
||||
<CardHeader>
|
||||
<h2>Manifests</h2>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<ItemGroup>
|
||||
{ ! manifests.length && ! isLoading && (
|
||||
<p>No manifests found.</p>
|
||||
) }
|
||||
{ manifests.map( ( [ manifestUrl ] ) => (
|
||||
<Item key={ manifestUrl }>
|
||||
{ manifestUrl }
|
||||
<Button
|
||||
variant="tertiary"
|
||||
onClick={ () => {
|
||||
deleteManifest( manifestUrl );
|
||||
} }
|
||||
>
|
||||
Remove this manifest
|
||||
</Button>
|
||||
</Item>
|
||||
) ) }
|
||||
</ItemGroup>
|
||||
</CardBody>
|
||||
<CardFooter>
|
||||
<input
|
||||
type="text"
|
||||
value={ newManifest }
|
||||
onChange={ ( e ) => setNewManifest( e.target.value ) }
|
||||
/>
|
||||
{ !! newManifest.length && ! isURL( newManifest ) && (
|
||||
<p>Invalid URL</p>
|
||||
) }
|
||||
<Button
|
||||
variant="primary"
|
||||
disabled={
|
||||
! newManifest &&
|
||||
! newManifest.length &&
|
||||
! isURL( newManifest )
|
||||
}
|
||||
onClick={ () => {
|
||||
createManifest( newManifest );
|
||||
setNewManifest( '' );
|
||||
} }
|
||||
>
|
||||
Add manifest URL
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
};
|
|
@ -1,50 +0,0 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useEffect, useState } from 'react';
|
||||
import apiFetch from '@wordpress/api-fetch';
|
||||
|
||||
const API_NAMESPACE = 'woocommerce-docs/v1';
|
||||
|
||||
type JobLog = {
|
||||
action_id: string;
|
||||
date: string;
|
||||
message: string;
|
||||
};
|
||||
|
||||
export const useJobLog = () => {
|
||||
const [ jobLogs, setJobLogs ] = useState< JobLog[] >( [] );
|
||||
const [ loading, setLoading ] = useState< boolean >( true );
|
||||
const [ error, setError ] = useState< string | null >( null );
|
||||
|
||||
useEffect( () => {
|
||||
const getJobLog = async () => {
|
||||
try {
|
||||
const res = await apiFetch< JobLog[] >( {
|
||||
path: `${ API_NAMESPACE }/job_log`,
|
||||
method: 'GET',
|
||||
} );
|
||||
|
||||
setJobLogs( res );
|
||||
setLoading( false );
|
||||
} catch ( err: unknown ) {
|
||||
if (
|
||||
err &&
|
||||
typeof err === 'object' &&
|
||||
'message' in err &&
|
||||
typeof err.message === 'string'
|
||||
) {
|
||||
setError( `Error occurred: ${ err.message }` );
|
||||
setLoading( false );
|
||||
} else {
|
||||
setError( 'An unknown error occurred.' );
|
||||
setLoading( false );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
getJobLog();
|
||||
}, [] );
|
||||
|
||||
return { jobLogs, isLoading: loading, error };
|
||||
};
|
|
@ -1,106 +0,0 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useEffect, useState } from 'react';
|
||||
import apiFetch from '@wordpress/api-fetch';
|
||||
|
||||
const API_NAMESPACE = 'woocommerce-docs/v1';
|
||||
|
||||
export const useManifests = () => {
|
||||
const [ manifests, setManifests ] = useState< string[] >( [] );
|
||||
const [ loading, setLoading ] = useState< boolean >( true );
|
||||
const [ error, setError ] = useState< string | null >( null );
|
||||
|
||||
useEffect( () => {
|
||||
const getManifests = async () => {
|
||||
try {
|
||||
const res = await apiFetch< string[] >( {
|
||||
path: `${ API_NAMESPACE }/manifests`,
|
||||
method: 'GET',
|
||||
} );
|
||||
|
||||
setManifests( res );
|
||||
setLoading( false );
|
||||
} catch ( err: unknown ) {
|
||||
if (
|
||||
err &&
|
||||
typeof err === 'object' &&
|
||||
'message' in err &&
|
||||
typeof err.message === 'string'
|
||||
) {
|
||||
setError( `Error occurred: ${ err.message }` );
|
||||
setLoading( false );
|
||||
} else {
|
||||
setError( 'An unknown error occurred.' );
|
||||
setLoading( false );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
getManifests();
|
||||
}, [] );
|
||||
|
||||
const deleteManifest = async ( manifest: string ) => {
|
||||
setLoading( true );
|
||||
|
||||
try {
|
||||
const res = await apiFetch< string[] >( {
|
||||
path: `${ API_NAMESPACE }/manifests`,
|
||||
method: 'DELETE',
|
||||
data: { manifest },
|
||||
} );
|
||||
|
||||
setManifests( res );
|
||||
setLoading( false );
|
||||
} catch ( err: unknown ) {
|
||||
if (
|
||||
err &&
|
||||
typeof err === 'object' &&
|
||||
'message' in err &&
|
||||
typeof err.message === 'string'
|
||||
) {
|
||||
setError( `Error occurred: ${ err.message }` );
|
||||
setLoading( false );
|
||||
} else {
|
||||
setError( 'An unknown error occurred.' );
|
||||
setLoading( false );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const createManifest = async ( manifest: string ) => {
|
||||
setLoading( true );
|
||||
|
||||
try {
|
||||
const res = await apiFetch< string[] >( {
|
||||
path: `${ API_NAMESPACE }/manifests`,
|
||||
method: 'POST',
|
||||
data: { manifest },
|
||||
} );
|
||||
|
||||
setManifests( res );
|
||||
setLoading( false );
|
||||
} catch ( err: unknown ) {
|
||||
if (
|
||||
err &&
|
||||
typeof err === 'object' &&
|
||||
'message' in err &&
|
||||
typeof err.message === 'string'
|
||||
) {
|
||||
setError( `Error occurred: ${ err.message }` );
|
||||
setLoading( false );
|
||||
} else {
|
||||
setError( 'An unknown error occurred.' );
|
||||
setLoading( false );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
manifests,
|
||||
error,
|
||||
isLoading: loading,
|
||||
createManifest,
|
||||
deleteManifest,
|
||||
};
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ManifestList } from './components/ManifestList';
|
||||
import { JobLog } from './components/JobLog';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<>
|
||||
<h1>WooCommerce Docs Administration</h1>
|
||||
<ManifestList />
|
||||
<JobLog />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
ReactDOM.render( <App />, document.getElementById( 'root' ) );
|
|
@ -1,8 +0,0 @@
|
|||
export const isURL = ( urlString: string ): boolean => {
|
||||
try {
|
||||
const url = new URL( urlString );
|
||||
return url.protocol === 'http:' || url.protocol === 'https:';
|
||||
} catch ( e ) {
|
||||
return false;
|
||||
}
|
||||
};
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"name": "woocommerce/docs",
|
||||
"description": "The WooCommerce documentation plugin.",
|
||||
"type": "wordpress-plugin",
|
||||
"require": {
|
||||
"woocommerce/action-scheduler": "^3.6",
|
||||
"league/commonmark": "^2.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"WooCommerceDocs\\": "src/"
|
||||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"woocommerce/woocommerce-sniffs": "^0.1.3",
|
||||
"phpunit/phpunit": "^9.6",
|
||||
"yoast/phpunit-polyfills": "^2.0",
|
||||
"php-stubs/wordpress-tests-stubs": "^6.2"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +0,0 @@
|
|||
---
|
||||
category_title: Getting Started with WooCommerce
|
||||
---
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
post_title: Install the Plugin
|
||||
---
|
||||
|
||||
## Install the plugin
|
||||
|
||||
1. Download the plugin from the [GitHub repository](https://example.com).
|
||||
2. Upload the plugin to your WordPress site.
|
||||
3. Activate the plugin.
|
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
post_title: Local Development
|
||||
---
|
||||
|
||||
## Local Development
|
||||
|
||||
1. [Install](./installation/install-plugin.md).
|
||||
2. Configure.
|
||||
3. Profit!
|
||||
|
||||
```
|
||||
$ cd /path/to/woocommerce-docs
|
||||
```
|
||||
|
||||
> This is a blockquote.
|
||||
|
||||
| First Header | Second Header |
|
||||
| ------------ | ------------- |
|
||||
| Content Cell | Content Cell |
|
||||
| Content Cell | Content Cell |
|
|
@ -1,3 +0,0 @@
|
|||
---
|
||||
category_title: Troubleshooting Problems
|
||||
---
|
|
@ -1,19 +0,0 @@
|
|||
---
|
||||
post_title: What Went Wrong?
|
||||
---
|
||||
|
||||
## Try some troubleshooting
|
||||
|
||||
1. Restart?
|
||||
2. Refresh?
|
||||
3. Profit!
|
||||
|
||||
Try some different things. _Broken?_ Try something else. **Unresponsive?** Try again.
|
||||
|
||||
If you would like to do a search you can go to [A search engine](google.com).
|
||||
|
||||
---
|
||||
|
||||
![An image](https://picsum.photos/200/300 'This is an image.')
|
||||
|
||||
You could also try [running the unit tests](../../testing/unit-tests.md)!
|
|
@ -1,3 +0,0 @@
|
|||
---
|
||||
category_title: Testing WooCommerce
|
||||
---
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
post_title: Integration Testing
|
||||
---
|
||||
|
||||
## Integration Tests
|
||||
|
||||
Elementary, my dear Watson! Write integration tests.
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
post_title: Unit Testing
|
||||
---
|
||||
|
||||
## Unit Test
|
||||
|
||||
It's simple really, write tests!
|
|
@ -1,75 +0,0 @@
|
|||
{
|
||||
"name": "@woocommerce/plugin-woocommerce-docs",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"description": "WooCommerce Docs Plugin",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "pnpm --if-present --workspace-concurrency=Infinity --stream --filter=\"$npm_package_name...\" '/^build:project:.*$/'",
|
||||
"build:project": "pnpm --if-present '/^build:project:.*$/'",
|
||||
"build:project:wp-scripts": "wireit",
|
||||
"start": "wp-scripts start",
|
||||
"postinstall": "composer install",
|
||||
"test": "pnpm test:php",
|
||||
"test:env:start": "wp-env start && wp-env run cli --env-cwd=wp-content/plugins/woocommerce-docs composer install",
|
||||
"test:php": "wp-env run tests-cli vendor/bin/phpunit --env-cwd=wp-content/plugins/woocommerce-docs",
|
||||
"test:env-setup": "pnpm test:env:start",
|
||||
"test:unit": "pnpm test:env:start && pnpm test:php"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "GPL-3.0+",
|
||||
"dependencies": {
|
||||
"@wordpress/api-fetch": "wp-6.0",
|
||||
"@wordpress/components": "wp-6.0",
|
||||
"directory-tree": "^3.5.1",
|
||||
"glob": "^10.3.10",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.18.68",
|
||||
"@types/react": "^17.0.71",
|
||||
"@types/react-dom": "^17.0.25",
|
||||
"@types/wordpress__components": "^19.10.5",
|
||||
"@woocommerce/dependency-extraction-webpack-plugin": "workspace:*",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"@wordpress/env": "^8.13.0",
|
||||
"@wordpress/prettier-config": "2.17.0",
|
||||
"@wordpress/scripts": "^26.18.0",
|
||||
"eslint": "^8.55.0",
|
||||
"gray-matter": "^4.0.3",
|
||||
"prettier": "npm:wp-prettier@^2.8.5",
|
||||
"ts-loader": "^9.5.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.3.3",
|
||||
"wireit": "0.14.3"
|
||||
},
|
||||
"wireit": {
|
||||
"build:project:wp-scripts": {
|
||||
"command": "wp-scripts build",
|
||||
"clean": "if-file-deleted",
|
||||
"files": [
|
||||
"webpack.config.js",
|
||||
"tsconfig.json",
|
||||
"client"
|
||||
],
|
||||
"output": [
|
||||
"build"
|
||||
],
|
||||
"dependencies": [
|
||||
"dependencyOutputs"
|
||||
]
|
||||
},
|
||||
"dependencyOutputs": {
|
||||
"allowUsuallyExcludedPaths": true,
|
||||
"files": [
|
||||
"node_modules/@woocommerce/eslint-plugin/configs",
|
||||
"node_modules/@woocommerce/eslint-plugin/rules",
|
||||
"node_modules/@woocommerce/eslint-plugin/index.js",
|
||||
"node_modules/@woocommerce/dependency-extraction-webpack-plugin/src/",
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
bootstrap="tests/bootstrap.php"
|
||||
backupGlobals="false"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
verbose="true"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
|
||||
<testsuites>
|
||||
<testsuite name="WooCommerceDocs Test Suite">
|
||||
<directory suffix=".php">./tests/src</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<coverage includeUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">./src</directory>
|
||||
<file>woocommerce-docs.php</file>
|
||||
</include>
|
||||
</coverage>
|
||||
</phpunit>
|
|
@ -1,71 +0,0 @@
|
|||
{
|
||||
"categories": [
|
||||
{
|
||||
"category_title": "Getting Started with WooCommerce",
|
||||
"posts": [
|
||||
{
|
||||
"post_title": "Local Development",
|
||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/plugins/woocommerce-docs/example-docs/get-started/local-development.md",
|
||||
"hash": "800191ff979d3367557260c662af59f9a67e07f2c22b5360afe87b04c80bcc56",
|
||||
"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": "6c7bb21cb195798a444844fef0ff79aacff86de1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"category_title": "Installation",
|
||||
"posts": [
|
||||
{
|
||||
"post_title": "Install the Plugin",
|
||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/plugins/woocommerce-docs/example-docs/get-started/installation/install-plugin.md",
|
||||
"hash": "89be25e4e91f5c807c7dc9ff778b2b76c6f7061cb9aca6e0cfc7fddb0cc28b6b",
|
||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/plugins/woocommerce-docs/example-docs/get-started/installation/install-plugin.md",
|
||||
"id": "6c7bb21cb195798a444844fef0ff79aacff86de1"
|
||||
}
|
||||
],
|
||||
"categories": []
|
||||
},
|
||||
{
|
||||
"category_title": "Troubleshooting Problems",
|
||||
"posts": [
|
||||
{
|
||||
"post_title": "What Went Wrong?",
|
||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/plugins/woocommerce-docs/example-docs/get-started/troubleshooting/what-went-wrong.md",
|
||||
"hash": "3195800696a9f641d075fc12da6c40b3dce66ba423807705c07d14a7f6758094",
|
||||
"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": "6f1b9c74de42a10cf4c77c2843e0fbdf1ff46316"
|
||||
}
|
||||
}
|
||||
],
|
||||
"categories": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"category_title": "Testing WooCommerce",
|
||||
"posts": [
|
||||
{
|
||||
"post_title": "Unit Testing",
|
||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/plugins/woocommerce-docs/example-docs/testing/unit-tests.md",
|
||||
"hash": "f4950c5597f1ef70f546fd3c4b92fd3c23518317aca2d72edb5a7da519c9946f",
|
||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/plugins/woocommerce-docs/example-docs/testing/unit-tests.md",
|
||||
"id": "6f1b9c74de42a10cf4c77c2843e0fbdf1ff46316"
|
||||
},
|
||||
{
|
||||
"post_title": "Integration Testing",
|
||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/plugins/woocommerce-docs/example-docs/testing/integration-tests.md",
|
||||
"hash": "6929e58b2a32d027f1049eea2ff6136f47b8fb52d4d1781f257de59b999155b0",
|
||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/plugins/woocommerce-docs/example-docs/testing/integration-tests.md",
|
||||
"id": "09c092c2b450edc45b9c247e0a983b7d176984a1"
|
||||
}
|
||||
],
|
||||
"categories": []
|
||||
}
|
||||
],
|
||||
"hash": "c727b2b8092cae90356d44d2803e5c70688b548b474467c994f55431055fbb69"
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* JobAPI class file
|
||||
*
|
||||
* @package WooCommerceDocs
|
||||
*/
|
||||
|
||||
namespace WooCommerceDocs\API;
|
||||
|
||||
/**
|
||||
* A class to register the job API endpoints.
|
||||
*/
|
||||
class JobAPI {
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*/
|
||||
public static function register_routes() {
|
||||
register_rest_route(
|
||||
'woocommerce-docs/v1',
|
||||
'/job_log',
|
||||
array(
|
||||
'methods' => 'GET',
|
||||
'callback' => array( '\WooCommerceDocs\API\JobAPI', 'get_job_log' ),
|
||||
'permission_callback' => array( '\WooCommerceDocs\API\JobAPI', 'permission_check' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of ActionScheduler completed jobs for the manifest job.
|
||||
*/
|
||||
public static function get_job_log() {
|
||||
$action_id = \ActionScheduler::store()->query_action(
|
||||
array(
|
||||
'hook' => 'woocommerce_docs_manifest_job',
|
||||
)
|
||||
);
|
||||
$log_entries = \ActionScheduler::logger()->get_logs( $action_id );
|
||||
|
||||
$entries = array();
|
||||
|
||||
foreach ( $log_entries as $log_entry ) {
|
||||
$entries[] = array(
|
||||
'action_id' => $log_entry->get_action_id(),
|
||||
'message' => $log_entry->get_message(),
|
||||
'date' => $log_entry->get_date()->format( 'Y-m-d H:i:s' ),
|
||||
);
|
||||
}
|
||||
|
||||
$response = new \WP_REST_Response( $entries );
|
||||
$response->set_status( 200 );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is allowed to use this endpoint.
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public static function permission_check( $request ) {
|
||||
return current_user_can( 'edit_posts' );
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* ManifestAPI class file
|
||||
*
|
||||
* @package WooCommerceDocs
|
||||
*/
|
||||
|
||||
namespace WooCommerceDocs\API;
|
||||
|
||||
/**
|
||||
* A class to register the manifest API endpoints.
|
||||
*/
|
||||
class ManifestAPI {
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*/
|
||||
public static function register_routes() {
|
||||
register_rest_route(
|
||||
'woocommerce-docs/v1',
|
||||
'/manifests',
|
||||
array(
|
||||
'methods' => 'GET',
|
||||
'callback' => array( '\WooCommerceDocs\API\ManifestAPI', 'get_manifests' ),
|
||||
'permission_callback' => array( '\WooCommerceDocs\API\ManifestAPI', 'permission_check' ),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
'woocommerce-docs/v1',
|
||||
'/manifests',
|
||||
array(
|
||||
'methods' => 'POST',
|
||||
'callback' => array( '\WooCommerceDocs\API\ManifestAPI', 'add_manifest' ),
|
||||
'permission_callback' => array( '\WooCommerceDocs\API\ManifestAPI', 'permission_check' ),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
'woocommerce-docs/v1',
|
||||
'/manifests',
|
||||
array(
|
||||
'methods' => 'DELETE',
|
||||
'callback' => array( '\WooCommerceDocs\API\ManifestAPI', 'delete_manifest' ),
|
||||
'permission_callback' => array( '\WooCommerceDocs\API\ManifestAPI', 'permission_check' ),
|
||||
'args' => array(
|
||||
'manifest' => array(
|
||||
'required' => true,
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of manifest urls
|
||||
*/
|
||||
public static function get_manifests() {
|
||||
$manifests = \WooCommerceDocs\Data\ManifestStore::get_manifest_list();
|
||||
|
||||
return new \WP_REST_Response( $manifests, 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a manifest url to the list
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
public static function add_manifest( $request ) {
|
||||
$manifest_url = $request->get_param( 'manifest' );
|
||||
if ( ! $manifest_url ) {
|
||||
return new \WP_Error( 'invalid_manifest_url', 'Invalid manifest url', array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
\WooCommerceDocs\Data\ManifestStore::add_manifest( $manifest_url );
|
||||
|
||||
return new \WP_REST_Response( \WooCommerceDocs\Data\ManifestStore::get_manifest_list(), 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a manifest url from the list.
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
public static function delete_manifest( $request ) {
|
||||
$manifest_url = $request->get_param( 'manifest' );
|
||||
if ( ! $manifest_url ) {
|
||||
return new \WP_Error( 'no_manifest_url', 'Manifest url not passed', array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
$manifest = \WooCommerceDocs\Data\ManifestStore::get_manifest_by_url( $manifest_url );
|
||||
|
||||
if ( null === $manifest ) {
|
||||
return new \WP_Error( 'invalid_manifest_url', 'Invalid manifest url', array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
\WooCommerceDocs\Data\ManifestStore::remove_manifest( $manifest_url );
|
||||
|
||||
return new \WP_REST_Response( \WooCommerceDocs\Data\ManifestStore::get_manifest_list(), 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is allowed to use this endpoint.
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public static function permission_check( $request ) {
|
||||
return current_user_can( 'edit_posts' );
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Bootstrap class file.
|
||||
*
|
||||
* @package WooCommerceDocs
|
||||
*/
|
||||
|
||||
namespace WooCommerceDocs\App;
|
||||
|
||||
use WooCommerceDocs\Data;
|
||||
use WooCommerceDocs\API;
|
||||
|
||||
/**
|
||||
* A class to set up the plugin.
|
||||
*/
|
||||
class Bootstrap {
|
||||
|
||||
/**
|
||||
* Bootstrap the plugin.
|
||||
*/
|
||||
public static function bootstrap() {
|
||||
add_action( 'admin_menu', array( __CLASS__, 'add_admin_menu' ) );
|
||||
add_action( 'admin_enqueue_scripts', array( __CLASS__, 'register_scripts' ) );
|
||||
add_action( 'rest_api_init', array( __CLASS__, 'register_api_endpoints' ) );
|
||||
add_action( 'init', array( __CLASS__, 'setup_stores' ) );
|
||||
|
||||
// Register the manifest job.
|
||||
new \WooCommerceDocs\Job\ManifestJob();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register client-side scripts.
|
||||
*/
|
||||
public static function register_scripts() {
|
||||
$script_path = 'build/wc-docs.js';
|
||||
$script_asset_path = WOOCOMMERCE_DOCS_PLUGIN_PATH . '/build/wc-docs.asset.php';
|
||||
$script_asset = file_exists( $script_asset_path )
|
||||
? require $script_asset_path
|
||||
: array(
|
||||
'dependencies' => array(),
|
||||
'version' => filemtime( $script_path ),
|
||||
);
|
||||
$script_url = WOOCOMMERCE_DOCS_ROOT_URL . $script_path;
|
||||
|
||||
wp_register_script(
|
||||
'wc_docs',
|
||||
$script_url,
|
||||
$script_asset['dependencies'],
|
||||
$script_asset['version'],
|
||||
true
|
||||
);
|
||||
wp_enqueue_script( 'wc_docs' );
|
||||
wp_enqueue_style( 'wp-components' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the add_admin_menu function
|
||||
*/
|
||||
public static function add_admin_menu() {
|
||||
// Add a top-level menu item to the admin menu.
|
||||
add_menu_page(
|
||||
'WooCommerce Docs',
|
||||
'WooCommerce Docs',
|
||||
'manage_options',
|
||||
'woocommerce-docs',
|
||||
array( __CLASS__, 'render_admin_page' ),
|
||||
'dashicons-media-document',
|
||||
6
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render admin page
|
||||
*/
|
||||
public static function render_admin_page() {
|
||||
// Include the admin page template.
|
||||
include_once WOOCOMMERCE_DOCS_PLUGIN_PATH . '/src/views/admin.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Register API endpoints
|
||||
*/
|
||||
public static function register_api_endpoints() {
|
||||
API\ManifestAPI::register_routes();
|
||||
API\JobAPI::register_routes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any setup for data stores
|
||||
*/
|
||||
public static function setup_stores() {
|
||||
Data\DocsStore::setup();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,205 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace WooCommerceDocs\Blocks;
|
||||
|
||||
use League\CommonMark\Environment\Environment;
|
||||
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
|
||||
use League\CommonMark\MarkdownConverter;
|
||||
use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
|
||||
|
||||
/**
|
||||
* Class MarkdownParser
|
||||
*/
|
||||
class BlockConverter {
|
||||
|
||||
/** // phpcs:ignore Generic.Commenting.DocComment.MissingShort
|
||||
*
|
||||
* @var MarkdownParser The MarkdownParser instance.
|
||||
*/
|
||||
private $parser;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$environment = new Environment();
|
||||
$environment->addExtension( new CommonMarkCoreExtension() );
|
||||
$environment->addExtension( new GithubFlavoredMarkdownExtension() );
|
||||
$this->parser = new MarkdownConverter( $environment );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert Markdown to Gutenberg blocks.
|
||||
*
|
||||
* @param string $content The Markdown content.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert_markdown_to_gb_blocks( $content ) {
|
||||
$markdown_without_frontmatter = $this->strip_frontmatter( $content );
|
||||
$html = $this->parser->convert( $markdown_without_frontmatter )->__toString();
|
||||
return $this->convert_html_to_blocks( $html );
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip frontmatter from Markdown.
|
||||
*
|
||||
* @param string $content The Markdown content.
|
||||
*/
|
||||
public function strip_frontmatter( $content ) {
|
||||
return preg_replace( '/^---[\s\S]*?---/', '', $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert HTML to blocks.
|
||||
*
|
||||
* @param string $html The HTML content.
|
||||
*/
|
||||
private function convert_html_to_blocks( $html ) {
|
||||
$blocks_html = '';
|
||||
$dom = new \DOMDocument();
|
||||
|
||||
$dom->loadHTML( $html );
|
||||
$xpath = new \DOMXPath( $dom );
|
||||
$nodes = $xpath->query( '//body/*' );
|
||||
|
||||
foreach ( $nodes as $node ) {
|
||||
$blocks_html .= $this->convert_node_to_block( $node );
|
||||
}
|
||||
|
||||
return $blocks_html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a DOM node to a block.
|
||||
*
|
||||
* @param \DOMNode $node The DOM node.
|
||||
*/
|
||||
private function convert_node_to_block( $node ) {
|
||||
$node_name = $node->nodeName; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$node_value = $node->nodeValue; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
|
||||
$node_content = $this->convert_child_nodes_to_blocks_or_html( $node );
|
||||
|
||||
switch ( $node_name ) {
|
||||
case 'blockquote':
|
||||
return $this->create_block( 'quote', $node_name, $node_content );
|
||||
case 'table':
|
||||
return $this->create_block( 'table', $node_name, $node_content );
|
||||
case 'pre':
|
||||
return $this->create_block( 'code', $node_name, $node_content );
|
||||
case 'p':
|
||||
return $this->create_block( 'paragraph', $node_name, $node_content );
|
||||
case 'h1':
|
||||
return $this->create_block( 'heading', $node_name, $node_content, array( 'level' => 1 ) );
|
||||
case 'h2':
|
||||
return $this->create_block( 'heading', $node_name, $node_content, array( 'level' => 2 ) );
|
||||
case 'h3':
|
||||
return $this->create_block( 'heading', $node_name, $node_content, array( 'level' => 3 ) );
|
||||
case 'h4':
|
||||
return $this->create_block( 'heading', $node_name, $node_content, array( 'level' => 4 ) );
|
||||
case 'h5':
|
||||
return $this->create_block( 'heading', $node_name, $node_content, array( 'level' => 5 ) );
|
||||
case 'h6':
|
||||
return $this->create_block( 'heading', $node_name, $node_content, array( 'level' => 6 ) );
|
||||
case 'ul':
|
||||
return $this->create_block( 'list', $node_name, $node_content, array( 'ordered' => false ) );
|
||||
case 'ol':
|
||||
return $this->create_block( 'list', $node_name, $node_content, array( 'ordered' => true ) );
|
||||
case 'li':
|
||||
return $this->create_block( 'list-item', $node_name, $node_content );
|
||||
case 'hr':
|
||||
return $this->create_block( 'separator', $node_name, null );
|
||||
default:
|
||||
return $node_value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a block.
|
||||
*
|
||||
* @param string $block_name The block name.
|
||||
* @param string $node_name The node name.
|
||||
* @param string $content The content.
|
||||
* @param array $attrs The attributes.
|
||||
*/
|
||||
private function create_block( $block_name, $node_name, $content = null, $attrs = array() ) {
|
||||
$json_attrs = count( $attrs ) > 0 ? ' ' . wp_json_encode( $attrs ) : '';
|
||||
|
||||
$block_html = "<!-- wp:{$block_name}{$json_attrs} -->\n";
|
||||
|
||||
// Special case for hr, at some point we could support other self-closing tags if needed.
|
||||
if ( 'hr' === $node_name ) {
|
||||
$block_html .= "<{$node_name} class=\"wp-block-separator has-alpha-channel-opacity\" />\n";
|
||||
} elseif ( null !== $content ) {
|
||||
// Gutenberg seems to require class name to avoid block recovery error on some blocks.
|
||||
if ( 'pre' === $node_name ) {
|
||||
$block_html .= "<pre class=\"wp-block-code\">{$content}</pre>\n";
|
||||
} elseif ( 'blockquote' === $node_name ) {
|
||||
$block_html .= "<blockquote class=\"wp-block-quote\">{$content}</blockquote>\n";
|
||||
} elseif ( 'table' === $node_name ) {
|
||||
$block_html .= "<figure class=\"wp-block-table\"><table>{$content}</table></figure>\n";
|
||||
} else {
|
||||
$block_html .= "<{$node_name}>{$content}</{$node_name}>\n";
|
||||
}
|
||||
}
|
||||
$block_html .= "<!-- /wp:{$block_name} -->\n";
|
||||
return $block_html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape a full URL.
|
||||
*
|
||||
* @param mixed $url The URL to escape.
|
||||
* @return string The escaped URL.
|
||||
*/
|
||||
private static function escape_full_url( $url ) {
|
||||
// Check if the URL is a relative link, relative URLs will be replaced later.
|
||||
$is_relative_link = ( strpos( $url, '://' ) === false );
|
||||
return $is_relative_link ? $url : esc_url( $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert child nodes to blocks.
|
||||
*
|
||||
* @param \DOMNode $node The DOM node.
|
||||
*/
|
||||
private function convert_child_nodes_to_blocks_or_html( $node ) {
|
||||
$content = '';
|
||||
|
||||
foreach ( $node->childNodes as $child_node ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$node_type = $child_node->nodeType; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$node_name = $child_node->nodeName; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
|
||||
if ( XML_ELEMENT_NODE === $node_type ) {
|
||||
if ( 'td' === $node_name || 'thead' === $node_name || 'tbody' === $node_name || 'tr' === $node_name || 'th' === $node_name ) {
|
||||
$inline_content = $this->convert_child_nodes_to_blocks_or_html( $child_node );
|
||||
$content .= "<{$node_name}>{$inline_content}</{$node_name}>";
|
||||
} elseif ( 'a' === $node_name ) {
|
||||
$href = self::escape_full_url( $child_node->getAttribute( 'href' ) );
|
||||
$link_content = $this->convert_child_nodes_to_blocks_or_html( $child_node );
|
||||
$content .= "<a href=\"{$href}\">{$link_content}</a>";
|
||||
} elseif ( 'em' === $node_name || 'strong' === $node_name ) {
|
||||
$inline_content = $this->convert_child_nodes_to_blocks_or_html( $child_node );
|
||||
$content .= "<{$node_name}>{$inline_content}</{$node_name}>";
|
||||
} elseif ( 'img' === $node_name ) {
|
||||
// Only handle images as inline content for now due to how Markdown is processed by CommonMark.
|
||||
$src = esc_url( $child_node->getAttribute( 'src' ) );
|
||||
$alt = esc_attr( $child_node->getAttribute( 'alt' ) );
|
||||
$content .= "<img src=\"{$src}\" alt=\"{$alt}\" />";
|
||||
} elseif ( 'code' === $node_name ) {
|
||||
$inline_content = $this->convert_child_nodes_to_blocks_or_html( $child_node );
|
||||
$content .= "<code>{$inline_content}</code>";
|
||||
} else {
|
||||
$content .= $this->convert_node_to_block( $child_node );
|
||||
}
|
||||
} elseif ( XML_TEXT_NODE === $node_type ) {
|
||||
$content .= $child_node->nodeValue; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* DocsStore class file
|
||||
*
|
||||
* @package WooCommerceDocs
|
||||
*/
|
||||
|
||||
namespace WooCommerceDocs\Data;
|
||||
|
||||
/**
|
||||
* DocsStore class file
|
||||
*
|
||||
* @package WooCommerceDocs
|
||||
*/
|
||||
class DocsStore {
|
||||
|
||||
/**
|
||||
* Get a list of docs posts
|
||||
*/
|
||||
public static function get_posts() {
|
||||
$args = array(
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => -1,
|
||||
'orderby' => 'title',
|
||||
'order' => 'ASC',
|
||||
'tag' => 'woocommerce_docs',
|
||||
);
|
||||
|
||||
return get_posts( $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a docs post by doc ID.
|
||||
*
|
||||
* @param int $doc_id The doc ID to get.
|
||||
*/
|
||||
public static function get_post( $doc_id ) {
|
||||
$args = array(
|
||||
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
|
||||
'meta_key' => 'docs_id',
|
||||
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
|
||||
'meta_value' => $doc_id,
|
||||
'tag' => 'woocommerce_docs',
|
||||
);
|
||||
|
||||
$existing_page = get_posts( $args );
|
||||
|
||||
return $existing_page[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a docs post
|
||||
*
|
||||
* @param array $post The post to add.
|
||||
* @param int $doc_id The doc ID to assign to the post.
|
||||
*/
|
||||
public static function insert_docs_post( $post, $doc_id ) {
|
||||
$post_id = wp_insert_post( $post );
|
||||
|
||||
update_post_meta( $post_id, 'docs_id', $doc_id );
|
||||
wp_set_post_tags( $post_id, 'woocommerce_docs', true );
|
||||
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the doc ID from a post ID
|
||||
*
|
||||
* @param int $post_id The post ID to get the doc ID from.
|
||||
*/
|
||||
public static function get_doc_id_by_post_id( $post_id ) {
|
||||
return get_post_meta( $post_id, 'docs_id', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an edit URL to a docs post
|
||||
*
|
||||
* @param int $post_id - The post ID to add the edit URL to.
|
||||
* @param string $edit_url - The edit URL to add.
|
||||
* @return void
|
||||
*/
|
||||
public static function add_edit_url_to_docs_post( $post_id, $edit_url ) {
|
||||
update_post_meta( $post_id, 'edit_url', $edit_url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the edit URL from a docs post
|
||||
*
|
||||
* @param int $post_id - The post ID to get the edit URL from.
|
||||
* @return string The edit URL.
|
||||
*/
|
||||
public static function get_edit_url_from_docs_post( $post_id ) {
|
||||
return get_post_meta( $post_id, 'edit_url', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a docs post
|
||||
*
|
||||
* @param array $post The post to update.
|
||||
* @param int $doc_id The doc ID of the post to update.
|
||||
*/
|
||||
public static function update_docs_post( $post, $doc_id ) {
|
||||
$args = array(
|
||||
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
|
||||
'meta_key' => 'docs_id',
|
||||
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
|
||||
'meta_value' => $doc_id,
|
||||
'tag' => 'woocommerce_docs',
|
||||
);
|
||||
|
||||
$existing_doc = get_posts( $args );
|
||||
|
||||
if ( ! empty( $existing_doc ) ) {
|
||||
return wp_update_post( $post );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a docs post
|
||||
*
|
||||
* @param int $doc_id The ID to delete from a post's entry in the manifest.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the docs store.
|
||||
*/
|
||||
public static function setup() {
|
||||
self::create_docs_tag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the docs tag
|
||||
*/
|
||||
private static function create_docs_tag() {
|
||||
$tag = 'woocommerce_docs';
|
||||
$taxonomy = 'post_tag';
|
||||
|
||||
$existing_tag = term_exists( $tag, $taxonomy );
|
||||
|
||||
if ( ! $existing_tag ) {
|
||||
$tag_args = array(
|
||||
'slug' => sanitize_title( $tag ),
|
||||
);
|
||||
wp_insert_term( $tag, $taxonomy, $tag_args );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* ManifestStore class file
|
||||
*
|
||||
* @package WooCommerceDocs
|
||||
*/
|
||||
|
||||
namespace WooCommerceDocs\Data;
|
||||
|
||||
/**
|
||||
* A class to store the list of manifests in the WordPress options table. It is represented
|
||||
* as a tuple, with url as key and value being json data.
|
||||
*/
|
||||
class ManifestStore {
|
||||
private const MANIFEST_OPTION = 'woocommerce_docs_manifest_list';
|
||||
|
||||
/**
|
||||
* Remove a manifest url from the list
|
||||
*
|
||||
* @param string $manifest_url The url of the manifest to remove.
|
||||
*/
|
||||
public static function remove_manifest( $manifest_url ) {
|
||||
$default_value = wp_json_encode( array() );
|
||||
$json = get_option( self::MANIFEST_OPTION, $default_value );
|
||||
$data = json_decode( $json, true );
|
||||
$data = array_filter(
|
||||
$data,
|
||||
function( $tuple ) use ( $manifest_url ) {
|
||||
return $tuple[0] !== $manifest_url;
|
||||
}
|
||||
);
|
||||
|
||||
$data = array_values( $data );
|
||||
$json = wp_json_encode( $data );
|
||||
self::save( $json );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the list of manifest tuples
|
||||
*/
|
||||
public static function get_manifest_list() {
|
||||
$default_value = wp_json_encode( array() );
|
||||
$json = get_option( self::MANIFEST_OPTION, $default_value );
|
||||
$data = json_decode( $json, true );
|
||||
|
||||
foreach ( $data as &$tuple ) {
|
||||
$tuple[1] = json_decode( $tuple[1], true );
|
||||
}
|
||||
unset( $tuple );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the manifest data for a given url
|
||||
*
|
||||
* @param string $url The url of the manifest to retrieve.
|
||||
*/
|
||||
public static function get_manifest_by_url( $url ) {
|
||||
$json = get_option( self::MANIFEST_OPTION, wp_json_encode( array() ) );
|
||||
$data = json_decode( $json, true );
|
||||
|
||||
foreach ( $data as $tuple ) {
|
||||
if ( $tuple[0] === $url ) {
|
||||
return json_decode( $tuple[1], true );
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an empty manifest to the list.
|
||||
*
|
||||
* @param string $url The url of the manifest to add. The JSON value
|
||||
* will be an empty object.
|
||||
*/
|
||||
public static function add_manifest( $url ) {
|
||||
$json = get_option( self::MANIFEST_OPTION, wp_json_encode( array() ) );
|
||||
$data = json_decode( $json, true );
|
||||
$data[] = array( $url, wp_json_encode( new \stdClass() ) );
|
||||
$json = wp_json_encode( $data );
|
||||
|
||||
self::save( $json );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the manifest data for a given url
|
||||
*
|
||||
* @param string $url The url of the manifest to update.
|
||||
* @param array $new_data The data to update the manifest with.
|
||||
*/
|
||||
public static function update_manifest( $url, $new_data ) {
|
||||
$default_value = wp_json_encode( array() );
|
||||
$existing_data = json_decode( get_option( self::MANIFEST_OPTION, $default_value ), true );
|
||||
|
||||
$updated_data = array_map(
|
||||
function( $tuple ) use ( $url, $new_data ) {
|
||||
if ( $tuple[0] === $url ) {
|
||||
return array( $url, wp_json_encode( $new_data, true ) );
|
||||
}
|
||||
|
||||
return $tuple;
|
||||
},
|
||||
$existing_data
|
||||
);
|
||||
|
||||
$json = wp_json_encode( $updated_data );
|
||||
self::save( $json );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save the manifest list
|
||||
*
|
||||
* @param array $manifest_list The list of manifest tuples to save.
|
||||
*/
|
||||
private static function save( $manifest_list ) {
|
||||
update_option( self::MANIFEST_OPTION, $manifest_list );
|
||||
}
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* ManifestJob class file
|
||||
*
|
||||
* @package WooCommerceDocs
|
||||
*/
|
||||
|
||||
namespace WooCommerceDocs\Job;
|
||||
|
||||
use WooCommerceDocs\Data;
|
||||
use WooCommerceDocs\Data\DocsStore;
|
||||
use WooCommerceDocs\Manifest\ManifestProcessor;
|
||||
use WooCommerceDocs\Manifest\RelativeLinkParser;
|
||||
|
||||
/**
|
||||
* A class to handle the manifest job.
|
||||
*/
|
||||
class ManifestJob {
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'schedule_job' ) );
|
||||
add_action( 'woocommerce_docs_manifest_job', array( $this, 'run_job' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule the job
|
||||
*/
|
||||
public function schedule_job() {
|
||||
if ( ! as_has_scheduled_action( 'woocommerce_docs_manifest_job' ) ) {
|
||||
as_enqueue_async_action( 'woocommerce_docs_manifest_job', array(), '', false );
|
||||
as_schedule_recurring_action( time() + 60, 60, 'woocommerce_docs_manifest_job', array(), '', false );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the job
|
||||
*/
|
||||
public function run_job() {
|
||||
$action_id = \ActionScheduler::store()->query_action(
|
||||
array(
|
||||
'hook' => current_action(),
|
||||
'args' => func_get_args(),
|
||||
)
|
||||
);
|
||||
|
||||
// Manifests are a list of tuples like ["url", {...}].
|
||||
$manifests = Data\ManifestStore::get_manifest_list();
|
||||
|
||||
try {
|
||||
foreach ( $manifests as $manifest ) {
|
||||
$manifest_url = $manifest[0];
|
||||
$response = wp_remote_get( $manifest_url );
|
||||
|
||||
if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
|
||||
\ActionScheduler_Logger::instance()->log( $action_id, 'Error retrieving manifest: ' . $response->get_error_message() );
|
||||
continue;
|
||||
}
|
||||
|
||||
$json = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
|
||||
if ( json_last_error() !== JSON_ERROR_NONE ) {
|
||||
\ActionScheduler_Logger::instance()->log( $action_id, 'Error decoding manifest: ' . json_last_error_msg() );
|
||||
continue;
|
||||
}
|
||||
|
||||
// first check if the manifest has changed.
|
||||
$existing_manifest = Data\ManifestStore::get_manifest_by_url( $manifest_url );
|
||||
$hash = array_key_exists( 'hash', $json ) ? $json['hash'] : null;
|
||||
$hash_changed = array_key_exists( 'hash', $existing_manifest ) && $existing_manifest['hash'] !== $hash;
|
||||
|
||||
if ( ! array_key_exists( 'hash', $existing_manifest ) || $hash_changed ) {
|
||||
if ( $hash_changed ) {
|
||||
\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;
|
||||
}
|
||||
|
||||
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 ) {
|
||||
$post = DocsStore::get_post( $doc_id );
|
||||
|
||||
if ( null !== $post ) {
|
||||
$content = $post->post_content;
|
||||
$updated_content = RelativeLinkParser::replace_relative_links( $content, $relative_links, $action_id );
|
||||
$post->post_content = $updated_content;
|
||||
DocsStore::update_docs_post( $post, $doc_id );
|
||||
} else {
|
||||
\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." );
|
||||
}
|
||||
}
|
||||
} catch ( \Exception $e ) {
|
||||
\ActionScheduler_Logger::instance()->log( $action_id, 'Error processing manifests: ' . $e->getMessage() );
|
||||
}
|
||||
|
||||
\ActionScheduler_Logger::instance()->log( $action_id, 'Manifest job completed.' );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace WooCommerceDocs\Manifest;
|
||||
|
||||
/**
|
||||
* Class CategoryCreator
|
||||
*
|
||||
* @package WooCommerceDocs\Manifest
|
||||
*/
|
||||
class CategoryCreator {
|
||||
/**
|
||||
* Create categories from manifest.
|
||||
*
|
||||
* @param mixed $manifest_category The manifest category.
|
||||
* @param mixed $parent_id The parent ID.
|
||||
* @return array The term.
|
||||
*/
|
||||
public static function create_or_update_category_from_manifest_entry( $manifest_category, $parent_id ) {
|
||||
$term = term_exists( $manifest_category['category_title'], 'category' );
|
||||
$category_args = array( 'parent' => $parent_id );
|
||||
|
||||
if ( isset( $manifest_category['category_slug'] ) ) {
|
||||
$category_args['slug'] = $manifest_category['category_slug'];
|
||||
}
|
||||
|
||||
// If the category doesn't exist, create it.
|
||||
if ( 0 === $term || null === $term ) {
|
||||
$term = wp_insert_term(
|
||||
$manifest_category['category_title'],
|
||||
'category',
|
||||
$category_args
|
||||
);
|
||||
} else {
|
||||
// If the category exists, update it.
|
||||
$term = wp_update_term(
|
||||
$term['term_id'],
|
||||
'category',
|
||||
$category_args
|
||||
);
|
||||
}
|
||||
|
||||
return $term;
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace WooCommerceDocs\Manifest;
|
||||
|
||||
use WooCommerceDocs\Data\DocsStore;
|
||||
|
||||
/**
|
||||
* Class ManifestProcessor
|
||||
*
|
||||
* @package WooCommerceDocs\Manifest
|
||||
*/
|
||||
class ManifestProcessor {
|
||||
/**
|
||||
* Process manifest object into WordPress posts and categories.
|
||||
*
|
||||
* @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, $previous_manifest = null ) {
|
||||
if ( $previous_manifest ) {
|
||||
PostRemover::remove_deleted_posts( $manifest, $previous_manifest, $logger_action_id );
|
||||
}
|
||||
self::process_categories( $manifest['categories'], $logger_action_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process categories
|
||||
*
|
||||
* @param array $categories The categories to process.
|
||||
* @param int $logger_action_id The logger action ID.
|
||||
* @param int $parent_id The parent ID.
|
||||
*/
|
||||
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 );
|
||||
|
||||
// Now, process the posts for this category.
|
||||
foreach ( $category['posts'] as $post ) {
|
||||
$response = wp_remote_get( $post['url'] );
|
||||
$content = wp_remote_retrieve_body( $response );
|
||||
|
||||
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
$error_code = wp_remote_retrieve_response_code( $response );
|
||||
\ActionScheduler_Logger::instance()->log( $logger_action_id, 'Could not retrieve ' . $post['url'] . '. status: ' . $error_code );
|
||||
continue;
|
||||
}
|
||||
|
||||
$content = wp_remote_retrieve_body( $response );
|
||||
|
||||
$post_id = PostCreator::create_or_update_post_from_manifest_entry( $post, $content, $category['category_title'], $logger_action_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, $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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace WooCommerceDocs\Manifest;
|
||||
|
||||
/**
|
||||
* Generate post args from manifest.
|
||||
*
|
||||
* @package WooCommerceDocs\Manifest
|
||||
*/
|
||||
class PostArgs {
|
||||
/**
|
||||
* Post args
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $args = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param mixed $manifest_post - The manifest representation of a post.
|
||||
* @param string $post_content - The post content.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $manifest_post, $post_content ) {
|
||||
|
||||
$possible_attributes = array(
|
||||
'post_title',
|
||||
'post_author',
|
||||
'post_date',
|
||||
'comment_status',
|
||||
'post_status',
|
||||
);
|
||||
|
||||
$args = array();
|
||||
|
||||
foreach ( $possible_attributes as $attribute ) {
|
||||
if ( isset( $manifest_post[ $attribute ] ) ) {
|
||||
$args[ $attribute ] = $manifest_post[ $attribute ];
|
||||
}
|
||||
}
|
||||
|
||||
$args['post_content'] = $post_content;
|
||||
|
||||
if ( ! isset( $args['post_status'] ) ) {
|
||||
$args['post_status'] = 'publish';
|
||||
}
|
||||
|
||||
$this->args = $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post args.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_args() {
|
||||
return $this->args;
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace WooCommerceDocs\Manifest;
|
||||
|
||||
use WooCommerceDocs\Data\DocsStore;
|
||||
use WooCommerceDocs\Blocks\BlockConverter;
|
||||
|
||||
/**
|
||||
* Class PostCreator
|
||||
*
|
||||
* Create a post from a manifest entry.
|
||||
*
|
||||
* @package WooCommerceDocs\Manifest
|
||||
*/
|
||||
class PostCreator {
|
||||
/**
|
||||
* Get the Markdown converter.
|
||||
*/
|
||||
private static function get_converter() {
|
||||
static $converter = null;
|
||||
if ( null === $converter ) {
|
||||
$converter = new BlockConverter();
|
||||
}
|
||||
return $converter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a post from a manifest entry and file contents.
|
||||
*
|
||||
* @param mixed $manifest_post The manifest representation of the post.
|
||||
* @param string $post_content The post content as a string.
|
||||
* @param int $logger_action_id The logger action ID.
|
||||
* @return int The post ID.
|
||||
*/
|
||||
public static function create_or_update_post_from_manifest_entry( $manifest_post, $post_content, $logger_action_id ) {
|
||||
$existing_post = DocsStore::get_post( $manifest_post['id'] );
|
||||
|
||||
$blocks = self::get_converter()->convert_markdown_to_gb_blocks( $post_content );
|
||||
|
||||
// Generate post args.
|
||||
$post_args = new PostArgs( $manifest_post, $blocks );
|
||||
|
||||
// If the post doesn't exist, create it.
|
||||
if ( ! $existing_post ) {
|
||||
$post_id = DocsStore::insert_docs_post(
|
||||
$post_args->get_args(),
|
||||
$manifest_post['id']
|
||||
);
|
||||
|
||||
if ( isset( $manifest_post['edit_url'] ) ) {
|
||||
DocsStore::add_edit_url_to_docs_post( $post_id, $manifest_post['edit_url'] );
|
||||
}
|
||||
|
||||
\ActionScheduler_Logger::instance()->log( $logger_action_id, 'Created post with id: ' . $post_id );
|
||||
} else {
|
||||
$post_update = array_merge( $post_args->get_args(), array( 'ID' => $existing_post->ID ) );
|
||||
|
||||
// if the post exists, update it .
|
||||
$post_id = \WoocommerceDocs\Data\DocsStore::update_docs_post(
|
||||
$post_update,
|
||||
$manifest_post['id']
|
||||
);
|
||||
|
||||
if ( isset( $manifest_post['edit_url'] ) ) {
|
||||
DocsStore::add_edit_url_to_docs_post( $post_id, $manifest_post['edit_url'] );
|
||||
}
|
||||
|
||||
\ActionScheduler_Logger::instance()->log( $logger_action_id, 'Updated post with id: ' . $post_id );
|
||||
}
|
||||
|
||||
return $post_id;
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
<?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 );
|
||||
}
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace WooCommerceDocs\Manifest;
|
||||
|
||||
use WooCommerceDocs\Data\DocsStore;
|
||||
|
||||
/**
|
||||
* Class RelativeLinkParser
|
||||
*/
|
||||
class RelativeLinkParser {
|
||||
/**
|
||||
* Extract links from the given manifest and create a lookup object.
|
||||
*
|
||||
* @param array $manifest The manifest array.
|
||||
* @return array The lookup object containing the links.
|
||||
*/
|
||||
public static function extract_links_from_manifest( $manifest ) {
|
||||
$links = array();
|
||||
|
||||
self::process_categories( $manifest['categories'], $links );
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the categories recursively and extract links.
|
||||
*
|
||||
* @param array $categories The categories array.
|
||||
* @param array $links The array to store the extracted links.
|
||||
*/
|
||||
private static function process_categories( $categories, &$links ) {
|
||||
foreach ( $categories as $category ) {
|
||||
if ( isset( $category['links'] ) ) {
|
||||
$links = array_merge( $links, $category['links'] );
|
||||
}
|
||||
|
||||
if ( isset( $category['categories'] ) ) {
|
||||
self::process_categories( $category['categories'], $links );
|
||||
}
|
||||
|
||||
if ( isset( $category['posts'] ) ) {
|
||||
self::process_posts( $category['posts'], $links );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the posts and extract links.
|
||||
*
|
||||
* @param array $posts The posts array.
|
||||
* @param array $links The array to store the extracted links.
|
||||
*/
|
||||
private static function process_posts( $posts, &$links ) {
|
||||
foreach ( $posts as $post ) {
|
||||
if ( isset( $post['links'] ) ) {
|
||||
$links = array_merge( $links, $post['links'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace relative links with permalinks in the given content using the lookup object.
|
||||
*
|
||||
* @param string $content The content to update.
|
||||
* @param array $link_lookup The lookup object containing the links.
|
||||
* @param int $action_id The action id used for logging.
|
||||
* @return string The updated content.
|
||||
*/
|
||||
public static function replace_relative_links( $content, $link_lookup, $action_id ) {
|
||||
$dom = new \DOMDocument();
|
||||
$dom->loadHTML( $content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );
|
||||
|
||||
$anchors = $dom->getElementsByTagName( 'a' );
|
||||
|
||||
foreach ( $anchors as $anchor ) {
|
||||
$href = $anchor->getAttribute( 'href' );
|
||||
|
||||
// Check if its a url or relative path.
|
||||
if ( ! preg_match( '/^https?:\/\//', $href ) ) {
|
||||
// Check if the link exists in the lookup object.
|
||||
if ( isset( $link_lookup[ $href ] ) ) {
|
||||
$post = DocsStore::get_post( $link_lookup[ $href ] );
|
||||
|
||||
if ( $post ) {
|
||||
$post_id = $post->ID;
|
||||
// get permalink from lookup object.
|
||||
$permalink = get_permalink( $post_id );
|
||||
$anchor->setAttribute( 'href', $permalink );
|
||||
} else {
|
||||
\ActionScheduler_Logger::instance()->log( $action_id, "Could not replace file link with post link, post with ID: $post_id not found." );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$updated_content = $dom->saveHTML();
|
||||
|
||||
return $updated_content;
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Main admin view
|
||||
*
|
||||
* @package WooCommerce_Docs
|
||||
*/
|
||||
|
||||
echo '<div class="wrap" id="root"></div>';
|
|
@ -1,16 +0,0 @@
|
|||
<?php // phpcs:ignore Squiz.Commenting.FileComment.Missing
|
||||
/**
|
||||
* PHPUnit bootstrap file
|
||||
*
|
||||
* @package WooCommerce_Docs
|
||||
*/
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
require_once __DIR__ . '/../vendor/yoast/phpunit-polyfills/phpunitpolyfills-autoload.php';
|
||||
|
||||
$tests_dir = getenv( 'WP_TESTS_DIR' );
|
||||
|
||||
require_once $tests_dir . '/includes/functions.php';
|
||||
require_once $tests_dir . '/includes/bootstrap.php';
|
||||
|
||||
// Require action-scheduler manually.
|
||||
require_once __DIR__ . '/../vendor/woocommerce/action-scheduler/action-scheduler.php';
|
|
@ -1,27 +0,0 @@
|
|||
<?php
|
||||
|
||||
use WooCommerceDocs\Blocks\BlockConverter;
|
||||
|
||||
/**
|
||||
* Class BlockConverterTest
|
||||
*/
|
||||
class BlockConverterTest extends WP_UnitTestCase {
|
||||
|
||||
/**
|
||||
* Test blocks are converted correctly from sample markdown.
|
||||
*/
|
||||
public function test_blocks_converted() {
|
||||
$block_converter = new BlockConverter();
|
||||
$converted = $block_converter->convert_markdown_to_gb_blocks( file_get_contents( __DIR__ . '/fixtures/test.md' ) );
|
||||
$this->assertEquals( file_get_contents( __DIR__ . '/fixtures/expected.html' ), $converted );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test frontmatter is stripped correctly from sample markdown.
|
||||
*/
|
||||
public function test_frontmatter_stripped() {
|
||||
$block_converter = new BlockConverter();
|
||||
$stripped = $block_converter->strip_frontmatter( file_get_contents( __DIR__ . '/fixtures/test.md' ) );
|
||||
$this->assertEquals( file_get_contents( __DIR__ . '/fixtures/no-frontmatter.md' ), $stripped );
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
<!-- wp:heading {"level":1} -->
|
||||
<h1>Heading 1</h1>
|
||||
<!-- /wp:heading -->
|
||||
<!-- wp:heading {"level":2} -->
|
||||
<h2>Heading 2</h2>
|
||||
<!-- /wp:heading -->
|
||||
<!-- wp:heading {"level":3} -->
|
||||
<h3>Heading 3</h3>
|
||||
<!-- /wp:heading -->
|
||||
<!-- wp:heading {"level":4} -->
|
||||
<h4>Heading 4</h4>
|
||||
<!-- /wp:heading -->
|
||||
<!-- wp:heading {"level":5} -->
|
||||
<h5>Heading 5</h5>
|
||||
<!-- /wp:heading -->
|
||||
<!-- wp:heading {"level":6} -->
|
||||
<h6>Heading 6</h6>
|
||||
<!-- /wp:heading -->
|
||||
<!-- wp:list {"ordered":true} -->
|
||||
<ol>
|
||||
<!-- wp:list-item -->
|
||||
<li>Item 1</li>
|
||||
<!-- /wp:list-item -->
|
||||
|
||||
<!-- wp:list-item -->
|
||||
<li>Item 2</li>
|
||||
<!-- /wp:list-item -->
|
||||
|
||||
<!-- wp:list-item -->
|
||||
<li>Item 3</li>
|
||||
<!-- /wp:list-item -->
|
||||
|
||||
</ol>
|
||||
<!-- /wp:list -->
|
||||
<!-- wp:list {"ordered":false} -->
|
||||
<ul>
|
||||
<!-- wp:list-item -->
|
||||
<li>Unordered Item 1</li>
|
||||
<!-- /wp:list-item -->
|
||||
|
||||
<!-- wp:list-item -->
|
||||
<li>Unordered Item 2</li>
|
||||
<!-- /wp:list-item -->
|
||||
|
||||
<!-- wp:list-item -->
|
||||
<li>Unordered Item 3</li>
|
||||
<!-- /wp:list-item -->
|
||||
|
||||
</ul>
|
||||
<!-- /wp:list -->
|
||||
<!-- wp:paragraph -->
|
||||
<p>Try some different things. <em>Italics</em> Try something else. <strong>Bold</strong> Try again.</p>
|
||||
<!-- /wp:paragraph -->
|
||||
<!-- wp:paragraph -->
|
||||
<p>Here is a link: <a href="https://woo.com">Woo.com</a>.</p>
|
||||
<!-- /wp:paragraph -->
|
||||
<!-- wp:separator -->
|
||||
<hr class="wp-block-separator has-alpha-channel-opacity" />
|
||||
<!-- /wp:separator -->
|
||||
<!-- wp:paragraph -->
|
||||
<p><img src="https://picsum.photos/200/300" alt="An image" /></p>
|
||||
<!-- /wp:paragraph -->
|
||||
<!-- wp:code -->
|
||||
<pre class="wp-block-code"><code>$ cd /path/to/woocommerce-docs
|
||||
</code></pre>
|
||||
<!-- /wp:code -->
|
||||
<!-- wp:quote -->
|
||||
<blockquote class="wp-block-quote">
|
||||
<!-- wp:paragraph -->
|
||||
<p>This is a blockquote.</p>
|
||||
<!-- /wp:paragraph -->
|
||||
|
||||
</blockquote>
|
||||
<!-- /wp:quote -->
|
||||
<!-- wp:table -->
|
||||
<figure class="wp-block-table"><table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>First Header</th>
|
||||
<th>Second Header</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Content Cell</td>
|
||||
<td>Content Cell</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Content Cell</td>
|
||||
<td>Content Cell</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></figure>
|
||||
<!-- /wp:table -->
|
|
@ -1,40 +0,0 @@
|
|||
|
||||
|
||||
# Heading 1
|
||||
|
||||
## Heading 2
|
||||
|
||||
### Heading 3
|
||||
|
||||
#### Heading 4
|
||||
|
||||
##### Heading 5
|
||||
|
||||
###### Heading 6
|
||||
|
||||
1. Item 1
|
||||
2. Item 2
|
||||
3. Item 3
|
||||
|
||||
- Unordered Item 1
|
||||
- Unordered Item 2
|
||||
- Unordered Item 3
|
||||
|
||||
Try some different things. _Italics_ Try something else. **Bold** Try again.
|
||||
|
||||
Here is a link: [Woo.com](https://woo.com).
|
||||
|
||||
---
|
||||
|
||||
![An image](https://picsum.photos/200/300 'This is an image.')
|
||||
|
||||
```
|
||||
$ cd /path/to/woocommerce-docs
|
||||
```
|
||||
|
||||
> This is a blockquote.
|
||||
|
||||
| First Header | Second Header |
|
||||
| ------------ | ------------- |
|
||||
| Content Cell | Content Cell |
|
||||
| Content Cell | Content Cell |
|
|
@ -1,42 +0,0 @@
|
|||
---
|
||||
title: Some frontmatter
|
||||
---
|
||||
|
||||
# Heading 1
|
||||
|
||||
## Heading 2
|
||||
|
||||
### Heading 3
|
||||
|
||||
#### Heading 4
|
||||
|
||||
##### Heading 5
|
||||
|
||||
###### Heading 6
|
||||
|
||||
1. Item 1
|
||||
2. Item 2
|
||||
3. Item 3
|
||||
|
||||
- Unordered Item 1
|
||||
- Unordered Item 2
|
||||
- Unordered Item 3
|
||||
|
||||
Try some different things. _Italics_ Try something else. **Bold** Try again.
|
||||
|
||||
Here is a link: [Woo.com](https://woo.com).
|
||||
|
||||
---
|
||||
|
||||
![An image](https://picsum.photos/200/300 'This is an image.')
|
||||
|
||||
```
|
||||
$ cd /path/to/woocommerce-docs
|
||||
```
|
||||
|
||||
> This is a blockquote.
|
||||
|
||||
| First Header | Second Header |
|
||||
| ------------ | ------------- |
|
||||
| Content Cell | Content Cell |
|
||||
| Content Cell | Content Cell |
|
|
@ -1,57 +0,0 @@
|
|||
<?php
|
||||
|
||||
use WooCommerceDocs\Data\ManifestStore;
|
||||
|
||||
/**
|
||||
* Class ManifestStoreTest
|
||||
*/
|
||||
class ManifestStoreTest extends WP_UnitTestCase {
|
||||
|
||||
/**
|
||||
* Test the manifest store stores manifests in a list.
|
||||
*/
|
||||
public function test_adding_a_manifest_stores_it_in_the_list() {
|
||||
ManifestStore::add_manifest( 'https://example.com/manifest.json' );
|
||||
ManifestStore::update_manifest( 'https://example.com/manifest.json', array( 'foo' => 'bar' ) );
|
||||
|
||||
$manifest_list = ManifestStore::get_manifest_list();
|
||||
|
||||
$this->assertEquals( $manifest_list, array( array( 'https://example.com/manifest.json', array( 'foo' => 'bar' ) ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test retrieving a single manifest by url.
|
||||
*/
|
||||
public function test_retrieving_a_single_manifest_by_url() {
|
||||
ManifestStore::add_manifest( 'https://example.com/manifest.json' );
|
||||
ManifestStore::update_manifest( 'https://example.com/manifest.json', array( 'foo' => 'bar' ) );
|
||||
|
||||
$manifest = ManifestStore::get_manifest_by_url( 'https://example.com/manifest.json' );
|
||||
$this->assertEquals( $manifest['foo'], 'bar' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test removing a manifest by url.
|
||||
*/
|
||||
public function test_removing_a_manifest_by_url() {
|
||||
ManifestStore::add_manifest( 'https://example.com/manifest.json' );
|
||||
ManifestStore::remove_manifest( 'https://example.com/manifest.json' );
|
||||
$manifest_list = ManifestStore::get_manifest_list();
|
||||
$this->assertEquals( $manifest_list, array() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test updating an existing manifest.
|
||||
*/
|
||||
public function test_updating_a_manifest() {
|
||||
ManifestStore::add_manifest( 'https://example.com/manifest.json' );
|
||||
ManifestStore::update_manifest( 'https://example.com/manifest.json', array( 'foo' => 'bar' ) );
|
||||
|
||||
$manifest = ManifestStore::get_manifest_by_url( 'https://example.com/manifest.json' );
|
||||
$this->assertEquals( $manifest['foo'], 'bar' );
|
||||
|
||||
ManifestStore::update_manifest( 'https://example.com/manifest.json', array( 'foo' => 'baz' ) );
|
||||
$updated_manifest = ManifestStore::get_manifest_by_url( 'https://example.com/manifest.json' );
|
||||
$this->assertEquals( $updated_manifest['foo'], 'baz' );
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace WooCommerceDocs\Tests\Manifest;
|
||||
|
||||
use WP_UnitTestCase;
|
||||
use WooCommerceDocs\Manifest\CategoryCreator;
|
||||
|
||||
|
||||
/**
|
||||
* Class CategoryCreatorTest
|
||||
*
|
||||
* @package WooCommerceDocs\Tests\Manifest
|
||||
*/
|
||||
class CategoryCreatorTest extends WP_UnitTestCase {
|
||||
|
||||
/**
|
||||
* Test a category is created from a manifest entry.
|
||||
*/
|
||||
public function test_create_category() {
|
||||
$manifest_category = array(
|
||||
'category_title' => 'Test Category',
|
||||
'category_slug' => 'test-category',
|
||||
);
|
||||
|
||||
$term = CategoryCreator::create_or_update_category_from_manifest_entry( $manifest_category, null );
|
||||
$id = $term['term_id'];
|
||||
|
||||
$category = get_category( $id );
|
||||
|
||||
$this->assertEquals( 'Test Category', $category->name );
|
||||
$this->assertEquals( 'test-category', $category->slug );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a category is updated from a manifest entry if it exists.
|
||||
*/
|
||||
public function test_update_category() {
|
||||
$manifest_category = array(
|
||||
'category_title' => 'Test Category',
|
||||
'category_slug' => 'test-category',
|
||||
);
|
||||
|
||||
$category_id = CategoryCreator::create_or_update_category_from_manifest_entry( $manifest_category, null );
|
||||
|
||||
$manifest_category = array(
|
||||
'category_title' => 'Test Category 2',
|
||||
'category_slug' => 'custom-slug',
|
||||
);
|
||||
|
||||
$term = CategoryCreator::create_or_update_category_from_manifest_entry( $manifest_category, null );
|
||||
$id = $term['term_id'];
|
||||
|
||||
$category = get_category( $id );
|
||||
|
||||
$this->assertEquals( 'Test Category 2', $category->name );
|
||||
$this->assertEquals( 'custom-slug', $category->slug );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a category can be created without a slug and it generates a
|
||||
* default one from the title.
|
||||
*/
|
||||
public function test_create_category_no_slug() {
|
||||
$manifest_category = array(
|
||||
'category_title' => 'My Category',
|
||||
);
|
||||
|
||||
$term = CategoryCreator::create_or_update_category_from_manifest_entry( $manifest_category, null );
|
||||
$category = get_category( $term['term_id'] );
|
||||
|
||||
$this->assertEquals( 'my-category', $category->slug );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace WooCommerceDocs\Tests\Manifest;
|
||||
|
||||
use WooCommerceDocs\Manifest\ManifestProcessor;
|
||||
use WP_UnitTestCase;
|
||||
use WooCommerceDocs\Data\DocsStore;
|
||||
|
||||
/**
|
||||
* Class ManifestProcessorTest
|
||||
*
|
||||
* @package WooCommerceDocs\Tests\Manifest
|
||||
*/
|
||||
class ManifestProcessorTest extends WP_UnitTestCase {
|
||||
|
||||
/**
|
||||
* Test processing a manifest into WordPress posts and categories.
|
||||
*/
|
||||
public function test_process_manifest() {
|
||||
|
||||
$manifest = json_decode( file_get_contents( __DIR__ . '/fixtures/manifest.json' ), true );
|
||||
$md_file = file_get_contents( __DIR__ . '/fixtures/test.md' );
|
||||
|
||||
// Mock the wp_remote_get function with a filter.
|
||||
add_filter(
|
||||
'pre_http_request',
|
||||
function ( $preempt, $args, $url ) use ( $md_file ) {
|
||||
return array(
|
||||
'response' => array(
|
||||
'code' => 200,
|
||||
'message' => 'OK',
|
||||
),
|
||||
'body' => $md_file,
|
||||
);
|
||||
},
|
||||
10,
|
||||
3
|
||||
);
|
||||
|
||||
ManifestProcessor::process_manifest( $manifest, 123 );
|
||||
|
||||
$get_started_category = get_term_by( 'name', 'Getting Started with WooCommerce', 'category' );
|
||||
$this->assertNotFalse( $get_started_category );
|
||||
|
||||
$install_category = get_term_by( 'name', 'Installation', 'category' );
|
||||
$this->assertNotFalse( $install_category );
|
||||
// Check parent is correct.
|
||||
$this->assertEquals( $get_started_category->term_id, $install_category->parent );
|
||||
|
||||
$troubleshoot_category = get_term_by( 'name', 'Troubleshooting Problems', 'category' );
|
||||
$this->assertNotFalse( $troubleshoot_category );
|
||||
// Check parent is correct.
|
||||
$this->assertEquals( $get_started_category->term_id, $troubleshoot_category->parent );
|
||||
|
||||
$testing_category = get_term_by( 'name', 'Testing WooCommerce', 'category' );
|
||||
$this->assertNotFalse( $testing_category );
|
||||
|
||||
// check posts exist using the DocStore.
|
||||
$posts = DocsStore::get_posts();
|
||||
$this->assertEquals( 4, count( $posts ) );
|
||||
|
||||
$install_plugin_post = $posts[0];
|
||||
$local_dev_post = $posts[1];
|
||||
$unit_testing_post = $posts[2];
|
||||
$what_went_wrong_post = $posts[3];
|
||||
|
||||
// check doc titles (note that they are returned in alpha order).
|
||||
$this->assertEquals( 'Install the Plugin', $install_plugin_post->post_title );
|
||||
$this->assertEquals( 'Local Development', $local_dev_post->post_title );
|
||||
$this->assertEquals( 'Unit Testing', $unit_testing_post->post_title );
|
||||
$this->assertEquals( 'What Went Wrong?', $what_went_wrong_post->post_title );
|
||||
|
||||
// Assert that post was assigned to categories.
|
||||
$this->assertTrue( has_category( $install_category->term_id, $install_plugin_post->ID ) );
|
||||
$this->assertTrue( has_category( $troubleshoot_category->term_id, $what_went_wrong_post->ID ) );
|
||||
$this->assertTrue( has_category( $testing_category->term_id, $unit_testing_post->ID ) );
|
||||
$this->assertTrue( has_category( $troubleshoot_category->term_id, $what_went_wrong_post->ID ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test processing a manifest attaches edit url post meta.
|
||||
*/
|
||||
public function test_edit_url() {
|
||||
|
||||
$manifest = json_decode( file_get_contents( __DIR__ . '/fixtures/manifest.json' ), true );
|
||||
$md_file = file_get_contents( __DIR__ . '/fixtures/test.md' );
|
||||
|
||||
// Mock the wp_remote_get function with a filter.
|
||||
add_filter(
|
||||
'pre_http_request',
|
||||
function ( $preempt, $args, $url ) use ( $md_file ) {
|
||||
return array(
|
||||
'response' => array(
|
||||
'code' => 200,
|
||||
'message' => 'OK',
|
||||
),
|
||||
'body' => $md_file,
|
||||
);
|
||||
},
|
||||
10,
|
||||
3
|
||||
);
|
||||
|
||||
ManifestProcessor::process_manifest( $manifest, 123 );
|
||||
|
||||
$posts = DocsStore::get_posts();
|
||||
|
||||
$install_plugin_post = $posts[0];
|
||||
$local_dev_post = $posts[1];
|
||||
$unit_testing_post = $posts[2];
|
||||
$what_went_wrong_post = $posts[3];
|
||||
|
||||
$edit_url_plugin_post = DocsStore::get_edit_url_from_docs_post( $install_plugin_post->ID, 'edit_url', true );
|
||||
$this->assertEquals( 'https://example.com/edit/get-started/installation/install-plugin.md', $edit_url_plugin_post );
|
||||
|
||||
$edit_url_local_dev_post = DocsStore::get_edit_url_from_docs_post( $local_dev_post->ID, 'edit_url', true );
|
||||
$this->assertEquals( 'https://example.com/edit/get-started/local-development.md', $edit_url_local_dev_post );
|
||||
|
||||
$edit_url_unit_testing_post = DocsStore::get_edit_url_from_docs_post( $unit_testing_post->ID, 'edit_url', true );
|
||||
$this->assertEquals( 'https://example.com/edit/testing/unit-tests.md', $edit_url_unit_testing_post );
|
||||
|
||||
$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 );
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace WooCommerceDocs\Tests\Manifest;
|
||||
|
||||
use WP_UnitTestCase;
|
||||
use WooCommerceDocs\Manifest\PostArgs;
|
||||
|
||||
|
||||
/**
|
||||
* Class PostArgsTest
|
||||
*
|
||||
* @package WooCommerceDocs\Tests\Manifest
|
||||
*/
|
||||
class PostArgsTest extends WP_UnitTestCase {
|
||||
|
||||
/**
|
||||
* Test post attributes are filtered to a subset of allowed attributes.
|
||||
*/
|
||||
public function test_post_attributes() {
|
||||
$manifest_post = array(
|
||||
'post_title' => 'Test Post Title',
|
||||
'post_content' => 'Test Content',
|
||||
'post_excerpt' => 'Test Excerpt',
|
||||
'post_status' => 'draft',
|
||||
'post_author' => 1,
|
||||
'post_type' => 'post',
|
||||
'post_date' => '2019-01-01 00:00:00',
|
||||
'comment_status' => 'closed',
|
||||
);
|
||||
|
||||
$actual_content = 'Hello World';
|
||||
$post_args = new PostArgs( $manifest_post, $actual_content );
|
||||
$args = $post_args->get_args();
|
||||
|
||||
// Attributes that are set.
|
||||
$this->assertEquals( 'Test Post Title', $args['post_title'] );
|
||||
$this->assertEquals( 'Hello World', $args['post_content'] );
|
||||
$this->assertEquals( 'draft', $args['post_status'] );
|
||||
$this->assertEquals( 1, $args['post_author'] );
|
||||
$this->assertEquals( 'closed', $args['comment_status'] );
|
||||
$this->assertEquals( '2019-01-01 00:00:00', $args['post_date'] );
|
||||
|
||||
// Attributes that are not set.
|
||||
$this->assertArrayNotHasKey( 'post_type', $args );
|
||||
$this->assertArrayNotHasKey( 'post_excerpt', $args );
|
||||
}
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace WooCommerceDocs\Tests\Manifest;
|
||||
|
||||
use WP_UnitTestCase;
|
||||
use WooCommerceDocs\Manifest\PostCreator;
|
||||
|
||||
|
||||
/**
|
||||
* Class PostCreatorTest
|
||||
*
|
||||
* @package WooCommerceDocs\Tests\Manifest
|
||||
*/
|
||||
class PostCreatorTest extends WP_UnitTestCase {
|
||||
|
||||
/**
|
||||
* Test a post is created from a manifest entry.
|
||||
*/
|
||||
public function test_create_post() {
|
||||
$manifest_post = array(
|
||||
'post_title' => 'Test Post Title',
|
||||
'post_status' => 'draft',
|
||||
'post_date' => '2019-01-01 00:00:00',
|
||||
'comment_status' => 'closed',
|
||||
);
|
||||
|
||||
$actual_content = 'Hello World';
|
||||
|
||||
$post_id = PostCreator::create_or_update_post_from_manifest_entry( $manifest_post, $actual_content, 123 );
|
||||
|
||||
$post = get_post( $post_id );
|
||||
|
||||
$block_content = '<!-- wp:paragraph -->
|
||||
<p>Hello World</p>
|
||||
<!-- /wp:paragraph -->
|
||||
';
|
||||
|
||||
$this->assertEquals( 'Test Post Title', $post->post_title );
|
||||
$this->assertEquals( $block_content, $post->post_content );
|
||||
$this->assertEquals( 'draft', $post->post_status );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a post is updated from a manifest entry if it exists.
|
||||
*/
|
||||
public function test_update_post() {
|
||||
$manifest_post = array(
|
||||
'post_title' => 'Test Post Title',
|
||||
'post_status' => 'draft',
|
||||
'post_date' => '2019-01-01 00:00:00',
|
||||
'comment_status' => 'closed',
|
||||
);
|
||||
|
||||
$actual_content = 'Hello World';
|
||||
$post_id = PostCreator::create_or_update_post_from_manifest_entry( $manifest_post, $actual_content, 123 );
|
||||
$post = get_post( $post_id );
|
||||
|
||||
$manifest_post = array(
|
||||
'post_title' => 'Test Post Title 2',
|
||||
'post_status' => 'publish',
|
||||
'post_date' => '2019-01-01 00:00:00',
|
||||
'comment_status' => 'closed',
|
||||
);
|
||||
|
||||
$actual_content = 'Hello World 2';
|
||||
|
||||
$post_id = PostCreator::create_or_update_post_from_manifest_entry( $manifest_post, $actual_content, 123 );
|
||||
|
||||
$post = get_post( $post_id );
|
||||
|
||||
$block_content = '<!-- wp:paragraph -->
|
||||
<p>Hello World 2</p>
|
||||
<!-- /wp:paragraph -->
|
||||
';
|
||||
|
||||
$this->assertEquals( 'Test Post Title 2', $post->post_title );
|
||||
$this->assertEquals( $block_content, $post->post_content );
|
||||
$this->assertEquals( 'publish', $post->post_status );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a post has edit url post meta added if its provided.
|
||||
*/
|
||||
public function test_edit_url_post_meta() {
|
||||
$manifest_post = array(
|
||||
'post_title' => 'Test Post Title',
|
||||
'post_status' => 'draft',
|
||||
'post_date' => '2019-01-01 00:00:00',
|
||||
'comment_status' => 'closed',
|
||||
'edit_url' => 'https://example.com/edit',
|
||||
);
|
||||
|
||||
$actual_content = 'Hello World';
|
||||
|
||||
$post_id = PostCreator::create_or_update_post_from_manifest_entry( $manifest_post, $actual_content, 123 );
|
||||
|
||||
$this->assertEquals( 'https://example.com/edit', get_post_meta( $post_id, 'edit_url', true ) );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
<?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 );
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace WooCommerceDocs\Tests\Manifest;
|
||||
|
||||
use WooCommerceDocs\Data\DocsStore;
|
||||
use WooCommerceDocs\Manifest\PostArgs;
|
||||
use WP_UnitTestCase;
|
||||
use WooCommerceDocs\Manifest\RelativeLinkParser;
|
||||
|
||||
|
||||
/**
|
||||
* Class PostCreatorTest
|
||||
*
|
||||
* @package WooCommerceDocs\Tests\Manifest
|
||||
*/
|
||||
class RelativeLinkParserTest extends WP_UnitTestCase {
|
||||
|
||||
/**
|
||||
* Test that relative links are extracted from a manifest.
|
||||
*/
|
||||
public function test_extract_links_from_manifest() {
|
||||
$manifest = json_decode( file_get_contents( __DIR__ . '/fixtures/manifest.json' ), true );
|
||||
$links = RelativeLinkParser::extract_links_from_manifest( $manifest );
|
||||
|
||||
$this->assertEquals( 2, count( $links ) );
|
||||
|
||||
$keys = array_keys( $links );
|
||||
$this->assertEquals( '../../testing/unit-tests.md', $keys[0] );
|
||||
$this->assertEquals( './installation/install-plugin.md', $keys[1] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that relative links can be replaced from a manifest.
|
||||
*/
|
||||
public function test_replace_links_in_manifest() {
|
||||
$manifest = json_decode( file_get_contents( __DIR__ . '/fixtures/manifest.json' ), true );
|
||||
$links = RelativeLinkParser::extract_links_from_manifest( $manifest );
|
||||
|
||||
// First create a post with the relative links.
|
||||
$dummy_post = $manifest['categories'][0]['posts'][0];
|
||||
// ID from the manifest post that is being linked to in the example content.
|
||||
$dummy_post_id = '120770c899215a889246b47ac883e4dda1f97b8b';
|
||||
|
||||
$post_args = new PostArgs(
|
||||
$dummy_post,
|
||||
'
|
||||
<div>
|
||||
<a href="../../testing/unit-tests.md">Unit Tests</a>
|
||||
<a href="./does/not/exist.md">Install Plugin</a>
|
||||
<a href="https://example.com">External Link</a>
|
||||
</div>
|
||||
'
|
||||
);
|
||||
$post_id = DocsStore::insert_docs_post( $post_args->get_args(), $dummy_post_id );
|
||||
$post_content = get_post( $post_id )->post_content;
|
||||
$replaced = RelativeLinkParser::replace_relative_links( $post_content, $links, 123 );
|
||||
|
||||
// Replaced the link available in the lookup object.
|
||||
$this->assertStringContainsString(
|
||||
get_permalink( $post_id ),
|
||||
$replaced
|
||||
);
|
||||
|
||||
// Did not replace the link that is not available in the lookup object.
|
||||
$this->assertStringContainsString(
|
||||
'./does/not/exist.md',
|
||||
$replaced
|
||||
);
|
||||
|
||||
// Did not replace the external link.
|
||||
$this->assertStringContainsString(
|
||||
'https://example.com',
|
||||
$replaced
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
{
|
||||
"categories": [
|
||||
{
|
||||
"category_title": "Getting Started with WooCommerce",
|
||||
"posts": [
|
||||
{
|
||||
"post_title": "Local Development",
|
||||
"edit_url": "https://example.com/edit/get-started/local-development.md",
|
||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/d3b2eaf56234412fdafab63cbe75c133b8706234/plugins/woocommerce-docs/example-docs/get-started/local-development.md",
|
||||
"id": "c068ce54044fa44c760a69bd71ef21274f2a5a37",
|
||||
"links": {
|
||||
"./installation/install-plugin.md": "fb59bd01dda7b090e5b0a557948e155a6b679d6a"
|
||||
}
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"category_title": "Installation",
|
||||
"posts": [
|
||||
{
|
||||
"post_title": "Install the Plugin",
|
||||
"edit_url": "https://example.com/edit/get-started/installation/install-plugin.md",
|
||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/d3b2eaf56234412fdafab63cbe75c133b8706234/plugins/woocommerce-docs/example-docs/get-started/installation/install-plugin.md",
|
||||
"id": "fb59bd01dda7b090e5b0a557948e155a6b679d6a"
|
||||
}
|
||||
],
|
||||
"categories": []
|
||||
},
|
||||
{
|
||||
"category_title": "Troubleshooting Problems",
|
||||
"posts": [
|
||||
{
|
||||
"post_title": "What Went Wrong?",
|
||||
"edit_url": "https://example.com/edit/get-started/troubleshooting/what-went-wrong.md",
|
||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/d3b2eaf56234412fdafab63cbe75c133b8706234/plugins/woocommerce-docs/example-docs/get-started/troubleshooting/what-went-wrong.md",
|
||||
"id": "1f88c4d039e72c059c928ab475ad1ea0a02c8abb",
|
||||
"links": {
|
||||
"../../testing/unit-tests.md": "120770c899215a889246b47ac883e4dda1f97b8b"
|
||||
}
|
||||
}
|
||||
],
|
||||
"categories": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"category_title": "Testing WooCommerce",
|
||||
"posts": [
|
||||
{
|
||||
"post_title": "Unit Testing",
|
||||
"edit_url": "https://example.com/edit/testing/unit-tests.md",
|
||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/d3b2eaf56234412fdafab63cbe75c133b8706234/plugins/woocommerce-docs/example-docs/testing/unit-tests.md",
|
||||
"id": "120770c899215a889246b47ac883e4dda1f97b8b"
|
||||
}
|
||||
],
|
||||
"categories": []
|
||||
}
|
||||
],
|
||||
"hash": "8fb4d0d2ssssssssssssssssa544fffe21157e00aec6d7981ea71a532373417a24087a8aeb78f4de"
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
post_title: Testing Post
|
||||
---
|
||||
|
||||
### Testing Post
|
||||
|
||||
This is a test post.
|
|
@ -1,27 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
// Target latest version of ECMAScript.
|
||||
"target": "esnext",
|
||||
|
||||
// Make sure we're not pulling types from external projects.
|
||||
"typeRoots": [ "./typings", "./node_modules/@types" ],
|
||||
|
||||
// Search under node_modules for non-relative imports.
|
||||
"moduleResolution": "node",
|
||||
|
||||
"jsx": "react-jsx",
|
||||
|
||||
// Temporary for resolving the test data json, remove when moving to using the API
|
||||
"resolveJsonModule": true,
|
||||
|
||||
// Enable strictest settings like strictNullChecks & noImplicitAny.
|
||||
"strict": true,
|
||||
|
||||
// Import non-ES modules as default imports.
|
||||
"esModuleInterop": true,
|
||||
|
||||
// Skip type checking of declaration files because some libraries define two copies of the same type in an inconsistent way
|
||||
"skipLibCheck": true,
|
||||
"module": "CommonJS"
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
|
||||
const WooCommerceDependencyExtractionWebpackPlugin = require( '@woocommerce/dependency-extraction-webpack-plugin' );
|
||||
|
||||
module.exports = {
|
||||
...defaultConfig,
|
||||
entry: {
|
||||
...defaultConfig.entry,
|
||||
'wc-docs': './client/index.tsx',
|
||||
},
|
||||
module: {
|
||||
...defaultConfig.module,
|
||||
rules: [
|
||||
...defaultConfig.module.rules,
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: [ '.js', '.jsx', '.tsx', '.ts' ],
|
||||
},
|
||||
plugins: [
|
||||
...defaultConfig.plugins.filter(
|
||||
( plugin ) =>
|
||||
plugin.constructor.name !== 'DependencyExtractionWebpackPlugin'
|
||||
),
|
||||
new WooCommerceDependencyExtractionWebpackPlugin(),
|
||||
],
|
||||
};
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Plugin Name: WooCommerce Docs
|
||||
* Plugin URI: https://woo.com/
|
||||
* Description: A plugin for consolidating Markdown documentation from remote sources.
|
||||
* Version: 1.0
|
||||
* Author: Automattic
|
||||
* Author URI: https://woo.com
|
||||
* Text Domain: woocommerce-docs
|
||||
* Domain Path: /i18n/languages/
|
||||
* Requires at least: 6.1
|
||||
* Requires PHP: 7.4
|
||||
*
|
||||
* @package WooCommerce
|
||||
*/
|
||||
|
||||
$autoload = __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
|
||||
// Get around lint that complains upstream files autoloaded don't have file comments.
|
||||
require $autoload;
|
||||
|
||||
define( 'WOOCOMMERCE_DOCS_ROOT_URL', plugin_dir_url( __FILE__ ) );
|
||||
const WOOCOMMERCE_DOCS_PLUGIN_PATH = __DIR__;
|
||||
|
||||
// Require action-scheduler manually.
|
||||
require_once __DIR__ . '/vendor/woocommerce/action-scheduler/action-scheduler.php';
|
||||
|
||||
\WooCommerceDocs\App\Bootstrap::bootstrap();
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
Comment: This PR fixes a linting error and does not require a change entry
|
||||
|
1608
pnpm-lock.yaml
1608
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,7 @@
|
|||
|
||||
This is a CLI tool designed to generate JSON manifests of Markdown files in a directory.
|
||||
|
||||
This manifest is currently designed to be consumed by the [WooCommerce Docs](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-docs) plugin.
|
||||
This manifest is currently designed to be consumed by the WooCommerce Docs plugin.
|
||||
|
||||
## Usage
|
||||
|
||||
|
@ -10,7 +10,7 @@ This command is built on postinstall and can be run from monorepo root.
|
|||
|
||||
To create a manifest:
|
||||
|
||||
```
|
||||
```shell
|
||||
pnpm utils md-docs create <path-to-directory> <projectName>
|
||||
```
|
||||
|
||||
|
@ -18,6 +18,6 @@ pnpm utils md-docs create <path-to-directory> <projectName>
|
|||
|
||||
To find out more about the arguments and options available, run:
|
||||
|
||||
```
|
||||
```shell
|
||||
pnpm utils md-docs create --help
|
||||
```
|
||||
|
|
Loading…
Reference in New Issue