diff --git a/.eslintrc b/.eslintrc
index 9cb1554..d46cb4d 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -15,7 +15,7 @@
"Vue": false
},
"extends": [
- "plugin:@wordpress/eslint-plugin/recommended"
+ "plugin:@wordpress/eslint-plugin/recommended-with-formatting"
],
"rules": {
"no-alert": "off",
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..8de0ddb
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,15 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+ - package-ecosystem: "composer"
+ directory: "/"
+ schedule:
+ interval: "monthly"
+ - package-ecosystem: "npm"
+ directory: "/"
+ schedule:
+ interval: "monthly"
diff --git a/.github/workflows/wordpress.yml b/.github/workflows/wordpress.yml
index 2440daa..2f27164 100644
--- a/.github/workflows/wordpress.yml
+++ b/.github/workflows/wordpress.yml
@@ -12,54 +12,20 @@ on:
jobs:
test:
- runs-on: ${{ matrix.operating-system }}
- strategy:
- matrix:
- operating-system: [ ubuntu-18.04 ] # OS. ubuntu-18.04 is also available.
- php: [ '5.6', '7.2', '7.4' ] # PHP versions to check.
- wp: [ 'latest', '5.4' ] # WordPress version to check.
- services:
- mysql:
- image: mysql:5.7
- options: --health-cmd "mysqladmin ping --host 127.0.0.1 --port 3306" --health-interval 20s --health-timeout 10s --health-retries 10
- ports:
- - 3306/tcp
- env:
- MYSQL_ROOT_PASSWORD: root
- name: WordPress ${{ matrix.wp }} in PHP ${{ matrix.php }} UnitTest
- steps:
- - uses: actions/checkout@master
-
- - name: Setup PHP
- uses: nanasess/setup-php@master
- with:
- php-version: ${{ matrix.php }}
-
- - name: Validate composer.json and composer.lock
- run: composer validate
-
- - name: Install dependencies
- run: composer install --prefer-dist --no-progress --no-suggest
-
- - name: Start MySQL
- run: sudo systemctl start mysql
-
- - name: Install WordPress
- run: bash bin/install-wp-tests.sh wordpress root root 127.0.0.1:3306 ${{ matrix.wp }}
-
- - name: Check PHP syntax
- run: composer test
+ uses: tarosky/workflows/.github/workflows/phpcs.yml@main
+ with:
+ version: 7.2
assets:
name: Assets Test
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@master
+ - uses: actions/checkout@main
- name: Install Node
- uses: actions/setup-node@v1
+ uses: actions/setup-node@v3
with:
- node-version: '12'
+ node-version: '16'
- name: Install NPM Packages
run: npm install
@@ -67,27 +33,45 @@ jobs:
- name: Check JS & CSS syntax
run: npm run lint
+ phplint:
+ uses: tarosky/workflows/.github/workflows/phplint.yml@main
+
release:
name: Deploy WordPress.org
- needs: [ test, assets ]
+ needs: [ test, assets, phplint ]
if: contains(github.ref, 'tags/')
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@v2
+ uses: actions/checkout@main
- name: Setup PHP
- uses: nanasess/setup-php@master
+ uses: shivammathur/setup-php@v2
with:
- php-version: 5.6
+ php-version: 7.2
+ tools: composer
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install Node
- uses: actions/setup-node@v1
+ uses: actions/setup-node@v3
with:
- node-version: '12'
+ node-version: '16'
- name: Build Plugin
- run: bash bin/build.sh ${{ github.ref }}
+ run: |
+ composer install --prefer-dist --no-dev
+ npm install
+ npm run package
+
+ - name: Generate readme.txt
+ uses: tarosky/workflows/actions/wp-readme@main
+
+ - name: Versioning
+ uses: tarosky/workflows/actions/versioning@main
+ with:
+ version: ${{ github.ref }}
+ files: readme.txt,taro-series.php
- name: Deploy to WordPress Directory
id: deploy
diff --git a/.github/workflows/wp-outdated.yml b/.github/workflows/wp-outdated.yml
new file mode 100644
index 0000000..f90ae61
--- /dev/null
+++ b/.github/workflows/wp-outdated.yml
@@ -0,0 +1,39 @@
+name: Latest WP Support
+
+on:
+ schedule:
+ - cron: "0 2 5 * *" # Every month on the 5th at 2am UTC
+
+jobs:
+ is-outdated:
+ name: Check if WP version is outdated
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@main
+
+ - name: Install Node
+ uses: actions/setup-node@master
+ with:
+ node-version: '18'
+
+ - name: Check wp version
+ uses: tarosky/farmhand-wp-aciton@v1
+ id: wp_version
+
+ - name: Update Issue if needed
+ if: steps.wp_version.outputs.should_update
+ uses: actions-ecosystem/action-create-issue@v1
+ with:
+ github_token: ${{ secrets.github_token }}
+ title: ${{ steps.wp_version.outputs.version }}
+ body: |
+ ## TODO
+
+ - [ ] Check if plugin works with the latest WP version
+ - [ ] Bump "Tested up to" version in README.md
+
+ labels: |
+ update
+ assignees: |
+ user1
diff --git a/.wordpress_org/icon.svg b/.wordpress-org/icon.svg
similarity index 100%
rename from .wordpress_org/icon.svg
rename to .wordpress-org/icon.svg
diff --git a/README.md b/README.md
index 98f00bb..3e94cd8 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,9 @@
Tags: series, posts, news
Contributors: tarosky, Takahashi_Fumiki
-Tested up to: 5.8
-Requires at least: 5.4
-Requires PHP: 5.6
+Tested up to: 6.5
+Requires at least: 5.9
+Requires PHP: 7.2
Stable Tag: nightly
License: GPLv3 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.txt
@@ -75,6 +75,12 @@ Create a new [issue](https://github.com/tarosky/taro-series/issues) or send [pul
## Changelog
+### 2.0.0
+
+* Add WP_Query orderby parameter `series-updated`.
+* Bump minimum PHP requiremtns to PHP 7.2 and over.
+* Bump minimum WordPress version to 5.9.
+
### 1.1.2
* Fix bug in articles count.
diff --git a/assets/js/post-editor.js b/assets/js/post-editor.js
index 1e1bd13..f7f5f71 100644
--- a/assets/js/post-editor.js
+++ b/assets/js/post-editor.js
@@ -12,9 +12,8 @@ const { __ } = wp.i18n;
const { apiFetch } = wp;
class SeriesRender extends Component {
-
- constructor(prop) {
- super(prop);
+ constructor( prop ) {
+ super( prop );
this.state = {
loading: false,
post: null,
@@ -43,11 +42,11 @@ class SeriesRender extends Component {
loading: true,
}, () => {
apiFetch( {
- path: `taro-series/v1/available/${this.props.postType}?p=${postId}`,
+ path: `taro-series/v1/available/${ this.props.postType }?p=${ postId }`,
} ).then( ( res ) => {
this.setState( {
loading: false,
- post: res[0],
+ post: res[ 0 ],
}, () => {
this.fetching = false;
} );
@@ -59,7 +58,7 @@ class SeriesRender extends Component {
this.fetching = false;
} );
} );
- });
+ } );
} else {
this.setState( {
post: null,
@@ -76,7 +75,7 @@ class SeriesRender extends Component {
let link = false;
let title = '';
if ( post ) {
- link = post.edit_link;
+ link = post.edit_link;
title = post.title;
} else if ( 0 < this.props.postId ) {
title = __( 'Loading…', 'taro-series' );
@@ -100,7 +99,7 @@ class SeriesRender extends Component {
{ title }
+ } }>{ __( 'Leave Out', 'taro-series' ) }
>
) : (
{ title }
@@ -112,9 +111,8 @@ class SeriesRender extends Component {
}
class SeriesChooser extends Component {
-
- constructor(props) {
- super(props);
+ constructor( props ) {
+ super( props );
this.state = {
loading: false,
posts: [],
@@ -138,7 +136,7 @@ class SeriesChooser extends Component {
fetch() {
this.setState( { loading: true }, () => {
apiFetch( {
- path: `taro-series/v1/available/${this.props.postType}?s=${this.state.s}`,
+ path: `taro-series/v1/available/${ this.props.postType }?s=${ this.state.s }`,
} ).then( ( res ) => {
this.setState( {
loading: false,
@@ -174,7 +172,7 @@ class SeriesChooser extends Component {
value: parseInt( p.id, 10 ),
label: p.title,
} );
- } )
+ } );
result.push(
);
@@ -201,9 +199,8 @@ class SeriesChooser extends Component {
}
class SeriesSelector extends Component {
-
- constructor(props) {
- super(props);
+ constructor( props ) {
+ super( props );
this.state = {
postId: parseInt( props.postId, 10 ),
};
@@ -230,5 +227,5 @@ class SeriesSelector extends Component {
// If meta box exists.
const metaBox = document.getElementById( 'taro-series-selector' );
if ( metaBox ) {
- render( , metaBox );
+ render( , metaBox );
}
diff --git a/assets/js/series-editor.js b/assets/js/series-editor.js
index 397778f..41f9876 100644
--- a/assets/js/series-editor.js
+++ b/assets/js/series-editor.js
@@ -18,7 +18,7 @@ const message = ( content, status ) => {
isDismissible: true,
explicitDismiss: false,
} );
-}
+};
const listStyle = {
borderBottom: '1px solid #ddd',
@@ -36,7 +36,6 @@ const labelStyle = {
const linkStyle = { marginRight: '10px' };
class SearchItem extends Component {
-
constructor( props ) {
super( props );
this.state = {
@@ -47,11 +46,11 @@ class SearchItem extends Component {
add( post ) {
this.setState( { loading: true }, () => {
apiFetch( {
- path: `taro-series/v1/series/${this.props.seriesId}`,
+ path: `taro-series/v1/series/${ this.props.seriesId }`,
method: 'post',
data: {
- post_id: post.id
- }
+ post_id: post.id,
+ },
} ).then( () => {
this.props.onAdd( post );
} ).catch( ( res ) => {
@@ -83,7 +82,6 @@ class SearchItem extends Component {
}
class Articles extends Component {
-
constructor( props ) {
super( props );
this.state = {
@@ -101,7 +99,7 @@ class Articles extends Component {
loading: true,
}, () => {
apiFetch( {
- path: `taro-series/v1/series/${this.props.seriesId}`,
+ path: `taro-series/v1/series/${ this.props.seriesId }`,
method: 'get',
} ).then( ( res ) => {
this.setState( {
@@ -122,7 +120,7 @@ class Articles extends Component {
loading: true,
}, () => {
apiFetch( {
- path: `taro-series/v1/series/${this.props.seriesId}?s=${this.state.term}`,
+ path: `taro-series/v1/series/${ this.props.seriesId }?s=${ this.state.term }`,
method: 'get',
} ).then( ( res ) => {
this.setState( {
@@ -150,16 +148,16 @@ class Articles extends Component {
return 0;
}
return a.date < b.date ? -1 : 1;
- } )
+ } );
this.setState( {
- posts
+ posts,
} );
}
remove( postId ) {
this.setState( { loading: false }, () => {
apiFetch( {
- path: `taro-series/v1/series/${this.props.seriesId}?post_id=${postId}`,
+ path: `taro-series/v1/series/${ this.props.seriesId }?post_id=${ postId }`,
method: 'delete',
} ).then( () => {
// Successfully removed.
@@ -167,7 +165,7 @@ class Articles extends Component {
loading: false,
posts: this.state.posts.filter( ( post ) => {
return post.id !== postId;
- } )
+ } ),
}, () => {
// translators: %d is post id.
message( sprintf( __( '#%d is removed from the articles of this series.', 'taro-series' ), postId ), 'success' );
@@ -188,7 +186,7 @@ class Articles extends Component {
results: [],
resultCount: 0,
term: '',
- } )
+ } );
}
render() {
@@ -206,12 +204,12 @@ class Articles extends Component {
{ posts.map( ( post ) => {
return (
- -
+
-
{ post.title }
- {post.statusLabel}
+ { post.statusLabel }
{ post.postTypeLabel }
- {post.dateFormatted}
+ { post.dateFormatted }
{ __( 'Edit', 'taro-series' ) }
@@ -248,7 +246,7 @@ class Articles extends Component {
{ results.map( ( post ) => {
return (
- this.add( p ) } />
+ this.add( p ) } />
);
} ) }
diff --git a/bin/build.sh b/bin/build.sh
deleted file mode 100755
index d817f1f..0000000
--- a/bin/build.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-
-# Set variables.
-PREFIX="refs/tags/"
-VERSION=${1#"$PREFIX"}
-
-echo "Building Taro Series v${VERSION}..."
-
-# Install composer.
-composer install --no-dev --prefer-dist
-
-# Install NPM.
-npm install
-npm run package
-
-# Create README.txt
-curl -L https://raw.githubusercontent.com/fumikito/wp-readme/master/wp-readme.php | php
-
-# Change version string.
-sed -i.bak "s/^Version: .*/Version: ${VERSION}/g" ./taro-series.php
-sed -i.bak "s/^Stable Tag: .*/Stable Tag: ${VERSION}/g" ./readme.txt
diff --git a/bin/clean.sh b/bin/clean.sh
deleted file mode 100644
index 932bd4f..0000000
--- a/bin/clean.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-
-# Remove unwanted files in distignore.
-files=(`cat ".distignore"`)
-
-for item in "${files[@]}"; do
- if [ -e $item ]; then
- rm -frv $item
- fi
-done
diff --git a/composer.json b/composer.json
index e7af456..c040e96 100644
--- a/composer.json
+++ b/composer.json
@@ -4,12 +4,10 @@
"minimum-stability": "stable",
"license": "GPL-3.0-or-later",
"scripts": {
- "test": [
- "phpcs --config-set installed_paths $(pwd)/vendor/wp-coding-standards/wpcs",
+ "lint": [
"phpcs --standard=phpcs.ruleset.xml $(find ./ -name '*.php')"
],
"fix": [
- "phpcs --config-set installed_paths $(pwd)/vendor/wp-coding-standards/wpcs",
"phpcbf --standard=phpcs.ruleset.xml $(find ./ -name '*.php')"
]
},
@@ -20,15 +18,22 @@
}
],
"require": {
- "php": "^5.6|^7.0"
+ "php": ">=7.2"
},
"require-dev": {
"squizlabs/php_codesniffer": "^3.0",
- "wp-coding-standards/wpcs": "^2.0"
+ "wp-coding-standards/wpcs": "^2.0",
+ "phpcompatibility/php-compatibility": "^9.3",
+ "dealerdirect/phpcodesniffer-composer-installer": "^1.0"
},
"autoload": {
"psr-0": {
"Tarosky\\Series": "src"
}
+ },
+ "config": {
+ "allow-plugins": {
+ "dealerdirect/phpcodesniffer-composer-installer": true
+ }
}
}
diff --git a/gulpfile.js b/gulpfile.js
index 0a2682f..4d77d6b 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -5,6 +5,7 @@ const webpack = require( 'webpack-stream' );
const webpackBundle = require( 'webpack' );
const named = require( 'vinyl-named' );
const { dumpSetting } = require('@kunoichi/grab-deps');
+const sass = require( 'gulp-sass' )( require( 'sass' ) );
let plumber = true;
@@ -17,7 +18,7 @@ gulp.task( 'sass', function () {
} ) )
.pipe( $.sassGlob() )
.pipe( $.sourcemaps.init() )
- .pipe( $.sass( {
+ .pipe( sass( {
errLogToConsole: true,
outputStyle: 'compressed',
sourceComments: false,
diff --git a/package.json b/package.json
index a9ffd9a..f70fb24 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
"@babel/plugin-transform-react-jsx": "^7.0.0",
"@babel/preset-env": "^7.1.0",
"@kunoichi/grab-deps": "^1.2.2",
- "@wordpress/env": "^4.0",
+ "@wordpress/env": "^9.7.0",
"@wordpress/eslint-plugin": "^9.0",
"babel-eslint": "^10.0.1",
"babel-loader": "^8.0.5",
@@ -35,15 +35,18 @@
"gulp-notify": "^3.2.0",
"gulp-plumber": "^1.2.0",
"gulp-rename": "^1.4.0",
- "gulp-sass": "^4.0.2",
+ "gulp-sass": "5.0",
"gulp-sass-glob": "^1.0.9",
"gulp-sourcemaps": "^3.0",
"gulp-stylelint": "^13.0.0",
+ "sass": "^1.74.1",
"stylelint": "^13.13.1",
"stylelint-config-wordpress": "^17.0.0",
"vinyl-named": "^1.1.0",
"webpack": "^5.3",
"webpack-stream": "^6.1"
},
- "dependencies": {}
+ "volta": {
+ "node": "16.20.2"
+ }
}
diff --git a/phpcs.ruleset.xml b/phpcs.ruleset.xml
index 2a3841f..f6925a3 100644
--- a/phpcs.ruleset.xml
+++ b/phpcs.ruleset.xml
@@ -26,6 +26,10 @@
+
+
+
+
*/node_modules/*
*.js
*/vendor/*
diff --git a/src/Tarosky/Series/Bootstrap.php b/src/Tarosky/Series/Bootstrap.php
index c573cc8..29e5a06 100644
--- a/src/Tarosky/Series/Bootstrap.php
+++ b/src/Tarosky/Series/Bootstrap.php
@@ -56,6 +56,8 @@ protected function init() {
ArchiveLink::get_instance();
// Block
TocBlock::get_instance();
+ // Shortcode
+ add_shortcode( 'taro_series', [ $this, 'do_shortcode' ] );
}
/**
@@ -103,4 +105,39 @@ public function register_script() {
}
}
}
+
+ /**
+ * Render shortcode for debugging.
+ *
+ * @param array $attrs Shortcode attributes.
+ * @param string $contents Shortcode contents.
+ *
+ * @return string
+ */
+ public function do_shortcode( $attrs = [], $contents = '' ) {
+ $attrs = shortcode_atts( [
+ 'order' => 'DESC',
+ 'posts_per_page' => 10,
+ ], $attrs, 'taro_series' );
+ $query_args = array_merge( [
+ 'post_type' => taro_series_parent_post_type(),
+ 'post_status' => 'publish',
+ 'orderby' => 'series-updated',
+ ], $attrs );
+ $query = new \WP_Query( $query_args );
+ if ( ! $query->have_posts() ) {
+ return '';
+ }
+ ob_start();
+ echo '';
+ foreach ( $query->posts as $post ) {
+ printf(
+ '- %s
',
+ get_permalink( $post ),
+ get_the_title( $post )
+ );
+ }
+ echo '
';
+ return ob_get_clean();
+ }
}
diff --git a/src/Tarosky/Series/Controller/Rewrite.php b/src/Tarosky/Series/Controller/Rewrite.php
index dcf2fe9..fe3cee3 100644
--- a/src/Tarosky/Series/Controller/Rewrite.php
+++ b/src/Tarosky/Series/Controller/Rewrite.php
@@ -18,7 +18,10 @@ class Rewrite extends Singleton {
protected function init() {
add_filter( 'query_vars', [ $this, 'query_vars' ] );
add_filter( 'rewrite_rules_array', [ $this, 'rewrite_rules' ] );
- add_action( 'pre_get_posts', [ $this, 'pre_get_posts' ] );
+ add_action( 'pre_get_posts', [ $this, 'query_in_series' ] );
+ add_action( 'pre_get_posts', [ $this, 'query_series_top' ] );
+ add_filter( 'posts_join', [ $this, 'posts_join' ], 10, 2 );
+ add_filter( 'posts_orderby', [ $this, 'posts_orderby' ], 10, 2 );
add_filter( 'get_the_archive_title', [ $this, 'archive_title' ] );
add_filter( 'index_template_hierarchy', [ $this, 'template_hierarchy' ] );
add_filter( 'archive_template_hierarchy', [ $this, 'template_hierarchy' ] );
@@ -32,7 +35,7 @@ protected function init() {
* @return string[]
*/
public function query_vars( $vars ) {
- $vars[] = 'series_in';
+ $vars[] = 'series_in'; // Posts in specific series.
return $vars;
}
@@ -54,7 +57,7 @@ public function rewrite_rules( $rules ) {
*
* @param \WP_Query $wp_query Query object.
*/
- public function pre_get_posts( $wp_query ) {
+ public function query_in_series( $wp_query ) {
$series_in = $wp_query->get( 'series_in' );
if ( ! $series_in ) {
return;
@@ -153,4 +156,82 @@ public function get_current_series( $slug = '' ) {
}
return get_page_by_path( $slug, OBJECT, taro_series_parent_post_type() );
}
+
+ /**
+ * If this is series list, change query.
+ *
+ * @param \WP_Query $wp_query
+ * @return void
+ */
+ public function query_series_top( $wp_query ) {
+ if ( ! $this->is_series_update( $wp_query ) ) {
+ return;
+ }
+ // Force post type to be series.
+ $wp_query->set( 'post_type', taro_series_parent_post_type() );
+ // Order should be asc or desc.
+ if ( 'ASC' !== strtoupper( $wp_query->get( 'order' ) ) ) {
+ $wp_query->set( 'order', 'DESC' );
+ }
+ }
+
+ /**
+ * @param $join
+ * @param \WP_Query $wp_query
+ *
+ * @return mixed|string
+ */
+ public function posts_join( $join, $wp_query ) {
+ if ( $this->is_series_update( $wp_query ) ) {
+ /* @var \wpdb $wpdb */
+ global $wpdb;
+ $post_types = implode( ', ', array_map( function( $post_type ) use ( $wpdb ) {
+ return $wpdb->prepare( '%s', $post_type );
+ }, taro_series_post_types() ) );
+ $func = ( 'ASC' === strtoupper( $wp_query->get( 'order' ) ) ) ? 'MIN' : 'MAX';
+ $sql = <<posts} AS p
+ LEFT JOIN {$wpdb->postmeta} AS pm
+ ON pm.meta_key = %s AND pm.post_id = p.ID
+ WHERE p.post_type IN ({$post_types})
+ AND p.post_status = 'publish'
+ AND pm.meta_value IS NOT NULL
+ GROUP BY pm.meta_value
+ ) AS taro_series ON taro_series.series_id = {$wpdb->posts}.ID
+SQL;
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
+ $sql = $wpdb->prepare( $sql, taro_series_meta_key() );
+ $join .= $sql;
+ }
+ return $join;
+ }
+
+ /**
+ * Customize order by query.
+ *
+ * @param string $orderby
+ * @param \WP_Query $wp_query
+ *
+ * @return mixed
+ */
+ public function posts_orderby( $orderby, $wp_query ) {
+ if ( $this->is_series_update( $wp_query ) ) {
+ /* @var \wpdb $wpdb */
+ global $wpdb;
+ $orderby = sprintf( 'taro_series.last_updated %s', ( 'ASC' === strtoupper( $wp_query->get( 'order' ) ) ? 'ASC' : 'DESC' ) );
+ }
+ return $orderby;
+ }
+
+ /**
+ * Detect if query is series update list.
+ *
+ * @param \WP_Query $wp_query
+ * @return bool
+ */
+ public function is_series_update( $wp_query ) {
+ return 'series-updated' === $wp_query->get( 'orderby' );
+ }
}