├── .codecov.yml
├── .gitignore
├── .travis.yml
├── LICENSE.md
├── README.md
├── assets
├── screenshot-1.png
└── screenshot-2.png
├── bin
├── bump-version.sh
├── install-wp-tests.sh
└── run-tests.sh
├── composer.json
├── includes
├── class-field-attributes.php
├── class-plugin-updater.php
├── class-wp-permalink.php
├── class-wp-post-meta.php
├── class-wp-request-processor.php
├── class-wp-rewrite-rules.php
└── main.php
├── phpcs.xml
├── phpunit.xml
├── readme.txt
├── test
├── integration
│ ├── bootstrap.php
│ ├── class-authsteps.php
│ ├── class-basetestcase.php
│ ├── class-customposttypesteps.php
│ ├── class-navigationasserter.php
│ ├── class-permalinkasserter.php
│ ├── class-permalinksteps.php
│ └── suites
│ │ ├── BasicPostNamePermalinkStructure
│ │ └── BasicPostNamePermalinkStructure.php
│ │ ├── CustomPostType
│ │ └── CustomPostTypeWithMetaKey.php
│ │ ├── MetaKeyPermalinkStructure
│ │ ├── PageWithMetaKey.php
│ │ ├── PostWithDuplicatedMetaKey.php
│ │ ├── PostWithDynamicallyCreatedMetaKey.php
│ │ ├── PostWithDynamicallyCreatedSingleMetaKey.php
│ │ ├── PostWithMetaKey.php
│ │ ├── PostWithMissingMetaKey.php
│ │ └── PrivatePostWithMetaKey.php
│ │ ├── MultipleMetaKeyPermalinkStructure
│ │ └── PostWithMetaKeyMultiple.php
│ │ ├── PermalinkWithAttributesStructure
│ │ └── PostWithMetaKey.php
│ │ └── Upgrade
│ │ └── PluginUpgrade.php
└── unit
│ ├── Field_Attributes_UnitTest.php
│ ├── WP_Permalink_UnitTest.php
│ ├── WP_Request_Processor_UnitTest.php
│ └── WP_Rewrite_Rules_UnitTest.php
└── wordpress-custom-fields-permalink-plugin.php
/.codecov.yml:
--------------------------------------------------------------------------------
1 | comment:
2 | layout: "diff, flags, files"
3 | behavior: new
4 | require_changes: false
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 |
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | dist: trusty
3 |
4 | language: php
5 |
6 | notifications:
7 | email:
8 | on_success: never
9 | on_failure: change
10 |
11 | branches:
12 | only:
13 | - master
14 | - /^feature.*/
15 |
16 | cache:
17 | directories:
18 | - $HOME/.composer/cache
19 |
20 | matrix:
21 | include:
22 | - php: 7.1
23 | env: WP_VERSION=latest
24 | - php: 7.0
25 | env: WP_VERSION=latest
26 | # - php: 5.6
27 | # env: WP_VERSION=3.0.0
28 | - php: 5.3 # PHP_MIN_HERE
29 | env: WP_VERSION=4.5.0 # WP_MIN_HERE
30 | dist: precise
31 | - php: 5.6
32 | env: WP_VERSION=latest
33 | # - php: 5.6
34 | # env: WP_VERSION=trunk
35 | - php: 5.6
36 | env: WP_TRAVISCI=phpcs
37 | # - php: 5.3
38 | # env: WP_VERSION=latest
39 | # dist: precise
40 |
41 | before_script:
42 | - export PATH="$HOME/.composer/vendor/bin:$PATH"
43 | #- |
44 | # if [ -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini ]; then
45 | # phpenv config-rm xdebug.ini
46 | # else
47 | # echo "xdebug.ini does not exist"
48 | # fi
49 | - |
50 | if [[ ! -z "$WP_VERSION" ]] ; then
51 | bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION
52 | composer global require "phpunit/phpunit=4.8.*|5.7.*"
53 | fi
54 | - |
55 | if [[ "$WP_TRAVISCI" == "phpcs" ]] ; then
56 | composer global require wp-coding-standards/wpcs
57 | phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs
58 | fi
59 |
60 | script:
61 | - |
62 | if [[ ! -z "$WP_VERSION" ]] ; then
63 | phpunit --coverage-clover clover.xml
64 | WP_MULTISITE=1 phpunit
65 | fi
66 | - |
67 | if [[ "$WP_TRAVISCI" == "phpcs" ]] ; then
68 | phpcs
69 | fi
70 |
71 | after_success:
72 | - bash <(curl -s https://codecov.io/bash)
73 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Piotr Pelczar (Athlan)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Custom Fields Permalink Redux
2 |
3 | Plugin allows to use post's custom fields values in permalink structure by adding %field_fieldname%, for posts, pages and custom post types.
4 |
5 | [](https://travis-ci.org/athlan/wordpress-custom-fields-permalink-plugin)
6 | [](https://codecov.io/gh/athlan/wordpress-custom-fields-permalink-plugin)
7 |
8 | ## Description
9 |
10 | Plugin allows to use post's custom fields values in permalink structure by adding `%field_fieldname%` rewrite tag.
11 |
12 | 
13 |
14 | Examples:
15 |
16 | * `http://example.com/%field_event_date_from%/%postname%/`
17 | * `http://example.com/post-type/%field_event_date_from%/%postname%/` (with Custom Post Type Permalinks plugin)
18 |
19 | You can also set different permalink structure depending on custom post type using Custom Post Type Permalinks plugin. You can create own post types by using Custom Post Type UI plugin.
20 |
21 | The plugin works for:
22 |
23 | * posts
24 | * pages
25 | * custom post types
26 |
27 | Plugin is also avaliable on GitHub:
28 | https://github.com/athlan/wordpress-custom-fields-permalink-plugin
29 |
30 | ## Installation
31 |
32 | Search for **Custom Fields Permalink 2** or follow the link
33 | https://wordpress.org/plugins/custom-fields-permalink-redux/
34 |
35 | ## Extensions
36 |
37 | ### Advanced Cutom Fields
38 |
39 | The extension of this plugin to fully support ACF plugin is availiable:
40 |
41 | https://github.com/athlan/acf-permalink
42 |
43 | ## Changelog
44 |
45 | Release notes: https://github.com/athlan/wordpress-custom-fields-permalink-plugin/releases
46 |
--------------------------------------------------------------------------------
/assets/screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/athlan/wordpress-custom-fields-permalink-plugin/1076a791348c3b6f22b5555874805e661c9b2feb/assets/screenshot-1.png
--------------------------------------------------------------------------------
/assets/screenshot-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/athlan/wordpress-custom-fields-permalink-plugin/1076a791348c3b6f22b5555874805e661c9b2feb/assets/screenshot-2.png
--------------------------------------------------------------------------------
/bin/bump-version.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | usage() {
4 | echo "usage: $0 "
5 | echo ""
6 | echo "version-type: plugin_version|wp_min|wp_to|php_min"
7 | echo ""
8 | }
9 |
10 | if [ $# -lt 2 ]; then
11 | usage
12 | exit 1
13 | fi
14 |
15 | version_type="handle_$1"
16 | version_to_bump="$2"
17 |
18 | file_plugin_main="wordpress-custom-fields-permalink-plugin.php"
19 | file_readme_repo="README.md"
20 | file_readme_wp="readme.txt"
21 | file_travisci=".travis.yml"
22 |
23 | handle_plugin_version() {
24 | echo "Starting bumping plugin version to $version_to_bump"
25 |
26 | sed -i -E "s/Version: (.+)/Version: $version_to_bump/" "$file_plugin_main"
27 | sed -i -E "s/'WORDPRESS_CUSTOM_FIELDS_PERMALINK_PLUGIN_VERSION', '(.+)'/'WORDPRESS_CUSTOM_FIELDS_PERMALINK_PLUGIN_VERSION', '$version_to_bump'/" "$file_plugin_main"
28 | echo "Version bumped in $file_plugin_main"
29 |
30 | sed -i -E "s/Stable tag: (.+)/Stable tag: $version_to_bump/" "$file_readme_repo"
31 | echo "Version bumped in $file_readme_repo"
32 |
33 | sed -i -E "s/Stable tag: (.+)/Stable tag: $version_to_bump/" "$file_readme_wp"
34 | echo "Version bumped in $file_readme_wp"
35 | }
36 |
37 | handle_wp_min() {
38 | echo "Starting bumping minimum Word Press version to $version_to_bump"
39 |
40 | sed -i -E "s/Requires at least: (.+)/Requires at least: $version_to_bump/" "$file_readme_repo"
41 | echo "Version bumped in $file_readme_repo"
42 |
43 | sed -i -E "s/Requires at least: (.+)/Requires at least: $version_to_bump/" "$file_readme_wp"
44 | echo "Version bumped in $file_readme_wp"
45 |
46 | sed -i -E "s/env: WP_VERSION=(.+) # WP_MIN_HERE/env: WP_VERSION=$version_to_bump # WP_MIN_HERE/" "$file_travisci"
47 | echo "Version bumped in $file_travisci"
48 | }
49 |
50 | handle_wp_to() {
51 | echo "Starting bumping tested up to Word Press version to $version_to_bump"
52 |
53 | sed -i -E "s/Tested up to: (.+)/Tested up to: $version_to_bump/" "$file_readme_repo"
54 | echo "Version bumped in $file_readme_repo"
55 |
56 | sed -i -E "s/Tested up to: (.+)/Tested up to: $version_to_bump/" "$file_readme_wp"
57 | echo "Version bumped in $file_readme_wp"
58 | }
59 |
60 | handle_php_min() {
61 | echo "Starting bumping php min version to $version_to_bump"
62 |
63 | sed -i -E "s/Requires PHP: (.+)/Requires PHP: $version_to_bump/" "$file_readme_repo"
64 | echo "Version bumped in $file_readme_repo"
65 |
66 | sed -i -E "s/Requires PHP: (.+)/Requires PHP: $version_to_bump/" "$file_readme_wp"
67 | echo "Version bumped in $file_readme_wp"
68 |
69 | sed -i -E "s/php: (.+) # PHP_MIN_HERE/php: $version_to_bump # PHP_MIN_HERE/" "$file_travisci"
70 | echo "Version bumped in $file_travisci"
71 | }
72 |
73 | if [ $(type -t $version_type) == function ]; then
74 | $version_type
75 | else
76 | usage
77 | exit 1
78 | fi
79 |
--------------------------------------------------------------------------------
/bin/install-wp-tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | if [ $# -lt 3 ]; then
4 | echo "usage: $0 [db-host] [wp-version] [skip-database-creation]"
5 | exit 1
6 | fi
7 |
8 | DB_NAME=$1
9 | DB_USER=$2
10 | DB_PASS=$3
11 | DB_HOST=${4-localhost}
12 | WP_VERSION=${5-latest}
13 | SKIP_DB_CREATE=${6-false}
14 |
15 | TMPDIR=${TMPDIR-/tmp}
16 | TMPDIR=$(echo $TMPDIR | sed -e "s/\/$//")
17 | WP_TESTS_DIR=${WP_TESTS_DIR-$TMPDIR/wordpress-tests-lib}
18 | WP_CORE_DIR=${WP_CORE_DIR-$TMPDIR/wordpress/}
19 |
20 | download() {
21 | if [ `which curl` ]; then
22 | curl -s "$1" > "$2";
23 | elif [ `which wget` ]; then
24 | wget -nv -O "$2" "$1"
25 | fi
26 | }
27 |
28 | if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then
29 | WP_TESTS_TAG="branches/$WP_VERSION"
30 | elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
31 | if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
32 | # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
33 | WP_TESTS_TAG="tags/${WP_VERSION%??}"
34 | else
35 | WP_TESTS_TAG="tags/$WP_VERSION"
36 | fi
37 | elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
38 | WP_TESTS_TAG="trunk"
39 | else
40 | # http serves a single offer, whereas https serves multiple. we only want one
41 | download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
42 | grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json
43 | LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
44 | if [[ -z "$LATEST_VERSION" ]]; then
45 | echo "Latest WordPress version could not be found"
46 | exit 1
47 | fi
48 | WP_TESTS_TAG="tags/$LATEST_VERSION"
49 | fi
50 |
51 | set -ex
52 |
53 | install_wp() {
54 |
55 | if [ -d $WP_CORE_DIR ]; then
56 | return;
57 | fi
58 |
59 | mkdir -p $WP_CORE_DIR
60 |
61 | if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
62 | mkdir -p $TMPDIR/wordpress-nightly
63 | download https://wordpress.org/nightly-builds/wordpress-latest.zip $TMPDIR/wordpress-nightly/wordpress-nightly.zip
64 | unzip -q $TMPDIR/wordpress-nightly/wordpress-nightly.zip -d $TMPDIR/wordpress-nightly/
65 | mv $TMPDIR/wordpress-nightly/wordpress/* $WP_CORE_DIR
66 | else
67 | if [ $WP_VERSION == 'latest' ]; then
68 | local ARCHIVE_NAME='latest'
69 | elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+ ]]; then
70 | # https serves multiple offers, whereas http serves single.
71 | download https://api.wordpress.org/core/version-check/1.7/ $TMPDIR/wp-latest.json
72 | if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
73 | # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
74 | LATEST_VERSION=${WP_VERSION%??}
75 | else
76 | # otherwise, scan the releases and get the most up to date minor version of the major release
77 | local VERSION_ESCAPED=`echo $WP_VERSION | sed 's/\./\\\\./g'`
78 | LATEST_VERSION=$(grep -o '"version":"'$VERSION_ESCAPED'[^"]*' $TMPDIR/wp-latest.json | sed 's/"version":"//' | head -1)
79 | fi
80 | if [[ -z "$LATEST_VERSION" ]]; then
81 | local ARCHIVE_NAME="wordpress-$WP_VERSION"
82 | else
83 | local ARCHIVE_NAME="wordpress-$LATEST_VERSION"
84 | fi
85 | else
86 | local ARCHIVE_NAME="wordpress-$WP_VERSION"
87 | fi
88 | download https://wordpress.org/${ARCHIVE_NAME}.tar.gz $TMPDIR/wordpress.tar.gz
89 | tar --strip-components=1 -zxmf $TMPDIR/wordpress.tar.gz -C $WP_CORE_DIR
90 | fi
91 |
92 | download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php
93 | }
94 |
95 | install_test_suite() {
96 | # portable in-place argument for both GNU sed and Mac OSX sed
97 | if [[ $(uname -s) == 'Darwin' ]]; then
98 | local ioption='-i .bak'
99 | else
100 | local ioption='-i'
101 | fi
102 |
103 | # set up testing suite if it doesn't yet exist
104 | if [ ! -d $WP_TESTS_DIR ]; then
105 | # set up testing suite
106 | mkdir -p $WP_TESTS_DIR
107 | svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
108 | svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data
109 | fi
110 |
111 | if [ ! -f wp-tests-config.php ]; then
112 | download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
113 | # remove all forward slashes in the end
114 | WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::")
115 | sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
116 | sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
117 | sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
118 | sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
119 | sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
120 | fi
121 |
122 | }
123 |
124 | install_db() {
125 |
126 | if [ ${SKIP_DB_CREATE} = "true" ]; then
127 | return 0
128 | fi
129 |
130 | # parse DB_HOST for port or socket references
131 | local PARTS=(${DB_HOST//\:/ })
132 | local DB_HOSTNAME=${PARTS[0]};
133 | local DB_SOCK_OR_PORT=${PARTS[1]};
134 | local EXTRA=""
135 |
136 | if ! [ -z $DB_HOSTNAME ] ; then
137 | if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then
138 | EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
139 | elif ! [ -z $DB_SOCK_OR_PORT ] ; then
140 | EXTRA=" --socket=$DB_SOCK_OR_PORT"
141 | elif ! [ -z $DB_HOSTNAME ] ; then
142 | EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
143 | fi
144 | fi
145 |
146 | # create database
147 | mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
148 | }
149 |
150 | install_wp
151 | install_test_suite
152 | install_db
153 |
--------------------------------------------------------------------------------
/bin/run-tests.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | phpunit --coverage-html target/test-coverage
4 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "athlan/custom-fields-permalink-plugin",
3 | "description": "Plugin allows to use post's custom fields values in permalink structure by adding %field_fieldname%, for posts, pages and custom post types.",
4 | "keywords": ["wordpress", "plugin", "custom fields", "permalink"],
5 | "homepage": "http://athlan.pl/wordpres-custom-fields-permalink-plugin/",
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "Piotr Pelczar",
10 | "email": "me@athlan.pl",
11 | "homepage": "http://athlan.pl"
12 | }
13 | ],
14 | "type": "wordpress-plugin",
15 | "require": {
16 | "php": ">=5.3.2",
17 | "composer/installers": "*"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/includes/class-field-attributes.php:
--------------------------------------------------------------------------------
1 | $value ) {
31 | if ( is_integer( $key ) ) {
32 | $result[ $value ] = true;
33 | } else {
34 | $result[ $key ] = $value;
35 | }
36 | }
37 |
38 | return $result;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/includes/class-plugin-updater.php:
--------------------------------------------------------------------------------
1 | update_plugin( $version_from, $version_to );
26 | update_option( $version_option_name, $version_to, true );
27 | }
28 | }
29 |
30 | /**
31 | * Upgrades the plugin.
32 | *
33 | * @param string $version_from Currently running version.
34 | * @param string $version_to Version upgrade to.
35 | */
36 | private function update_plugin( $version_from, $version_to ) {
37 | flush_rewrite_rules();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/includes/class-wp-permalink.php:
--------------------------------------------------------------------------------
1 | post_meta = $post_meta;
39 | $this->field_attributes = $field_attributes;
40 | }
41 |
42 | /**
43 | * Filters the permalink structure for a post before token replacement occurs..
44 | * The pre_post_link filter implementation.
45 | *
46 | * @param string $permalink The site's permalink structure.
47 | * @param WP_Post $post The post in question.
48 | * @param bool $leavename Whether to keep the post name.
49 | *
50 | * @link https://developer.wordpress.org/reference/hooks/pre_post_link/
51 | *
52 | * @return mixed
53 | */
54 | public function link_post( $permalink, $post, $leavename ) {
55 | return $this->link_rewrite_fields( $permalink, $post );
56 | }
57 |
58 | /**
59 | * Filters the permalink for a post of a custom post type.
60 | * The post_type_link filter implementation.
61 | *
62 | * @param string $permalink The post's permalink.
63 | * @param WP_Post $post The post in question.
64 | * @param bool $leavename Whether to keep the post name.
65 | * @param bool $sample Is it a sample permalink.
66 | *
67 | * @link https://developer.wordpress.org/reference/hooks/post_type_link/
68 | *
69 | * @return mixed
70 | */
71 | public function link_post_type( $permalink, $post, $leavename, $sample ) {
72 | return $this->link_rewrite_fields( $permalink, $post );
73 | }
74 |
75 | /**
76 | * Rewrites permalink replacing custom fields.
77 | *
78 | * @param string $permalink The permalink.
79 | * @param WP_Post $post The post.
80 | *
81 | * @return string
82 | */
83 | private function link_rewrite_fields( $permalink, $post ) {
84 | $that = $this;
85 | $field_attributes = $this->field_attributes;
86 | $replace_callback = function ( $matches ) use ( &$post, &$that, &$field_attributes ) {
87 | $field_name = $matches[ WP_Rewrite_Rules::FIELD_REGEXP_NAME_GROUP ];
88 |
89 | if ( isset( $matches[ WP_Rewrite_Rules::FIELD_REGEXP_ATTRIBUTES_GROUP ] ) ) {
90 | $field_attr = $field_attributes->parse_attributes( $matches[ WP_Rewrite_Rules::FIELD_REGEXP_ATTRIBUTES_GROUP ] );
91 | } else {
92 | $field_attr = array();
93 | }
94 |
95 | return $that->link_rewrite_fields_extract( $post, $field_name, $field_attr );
96 | };
97 |
98 | return preg_replace_callback( '#' . WP_Rewrite_Rules::FIELD_REGEXP . '#', $replace_callback, $permalink );
99 | }
100 |
101 | /**
102 | * Extract the metadata value from the post.
103 | *
104 | * @param WP_Post $post The post.
105 | * @param string $field_name The metadata key to extract.
106 | * @param array $field_attr The metadata field rewrite permalink attributes.
107 | *
108 | * @return string
109 | */
110 | public function link_rewrite_fields_extract( $post, $field_name, array $field_attr ) {
111 | $post_meta_value = $this->post_meta->get_post_meta_single( $post, $field_name, $field_attr );
112 | if ( ! isset( $post_meta_value ) ) {
113 | return '';
114 | }
115 | $value = $post_meta_value[0];
116 | $value = sanitize_title( $value );
117 |
118 | return $value;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/includes/class-wp-post-meta.php:
--------------------------------------------------------------------------------
1 | wpcfp_get_post_metadata filter.
19 | *
20 | * @param WP_Post $post The post.
21 | *
22 | * @return array
23 | */
24 | public function get_post_meta( $post ) {
25 | $post_meta = get_post_meta( $post->ID );
26 | /**
27 | * Filters of retrieved metadata of a post to link rewrite.
28 | *
29 | * @since 1.2.0
30 | *
31 | * @param array $post_meta The metadata returned from get_post_meta.
32 | * @param WP_Post $post The post object.
33 | */
34 | $filtered_post_meta = apply_filters( 'wpcfp_get_post_metadata', $post_meta, $post );
35 | // Do some fixes after user generated values.
36 | // If it's single value, wrap this in array, as WordPress internally does.
37 | // @see get_post_meta() with $single = false.
38 | foreach ( $filtered_post_meta as $key => &$value ) {
39 | if ( ! is_array( $value ) ) {
40 | $value = array( $value );
41 | }
42 | }
43 |
44 | return $filtered_post_meta;
45 | }
46 |
47 | /**
48 | * Get single post meta applying wpcfp_get_post_metadata_single
filter.
49 | *
50 | * @param WP_Post $post The post.
51 | * @param string $meta_key Name of metadata field.
52 | * @param array $meta_key_attrs The metadata field rewrite permalink attributes.
53 | *
54 | * @return array
55 | */
56 | public function get_post_meta_single( $post, $meta_key, array $meta_key_attrs ) {
57 | $post_meta = $this->get_post_meta( $post );
58 |
59 | if ( array_key_exists( $meta_key, $post_meta ) ) {
60 | $post_meta_value = $post_meta[ $meta_key ];
61 | } else {
62 | $post_meta_value = null;
63 | }
64 |
65 | /**
66 | * Filters of retrieved single metadata of a post to link rewrite.
67 | *
68 | * @since 1.4.0
69 | *
70 | * @param mixed|null $post_meta_value The metadata values returned from get_post_meta.
71 | * @param string $meta_key Name of metadata field.
72 | * @param array $meta_key_attrs The metadata field rewrite permalink attributes.
73 | * @param WP_Post $post The post object.
74 | */
75 | $filtered_post_meta_value = apply_filters( 'wpcfp_get_post_metadata_single', $post_meta_value, $meta_key, $meta_key_attrs, $post );
76 | if ( null === $filtered_post_meta_value ) {
77 | return null;
78 | }
79 |
80 | // Do some fixes after user generated values.
81 | // If it's single value, wrap this in array, as WordPress internally does.
82 | // @see get_post_meta() with $single = false.
83 | if ( ! is_array( $filtered_post_meta_value ) ) {
84 | $filtered_post_meta_value = array( $filtered_post_meta_value );
85 | }
86 |
87 | return $filtered_post_meta_value;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/includes/class-wp-request-processor.php:
--------------------------------------------------------------------------------
1 | post_meta = $post_meta;
34 | }
35 |
36 | /**
37 | * Filters the query variables whitelist before processing.
38 | * The query_vars filter implementation.
39 | *
40 | * @param array $public_query_vars The array of whitelisted query variables.
41 | *
42 | * @link https://developer.wordpress.org/reference/hooks/query_vars/
43 | *
44 | * @return mixed
45 | */
46 | public function register_extra_query_vars( $public_query_vars ) {
47 | array_push( $public_query_vars, self::PARAM_CUSTOMFIELD_PARAMS, self::PARAM_CUSTOMFIELD_PARAMS_ATTR );
48 |
49 | return $public_query_vars;
50 | }
51 |
52 | /**
53 | * Filters the array of parsed query variables.
54 | * The request filter implementation.
55 | *
56 | * @param array $query_vars The array of requested query variables.
57 | *
58 | * @link https://developer.wordpress.org/reference/hooks/request/
59 | *
60 | * @return mixed
61 | */
62 | public function process_request( $query_vars ) {
63 | // Additional parameters added to WordPress.
64 | // Main Loop query.
65 | return $query_vars;
66 | }
67 |
68 | /**
69 | * Filters whether to short-circuit default header status handling.
70 | *
71 | * Raises 404 if post has been rewrited, but:
72 | * 1. Custom field key does not exists or
73 | * 2. Custom field value does not matches.
74 | *
75 | * @param bool $preempt Whether to short-circuit default header status handling. Default false.
76 | * @param WP_Query $wp_query WordPress Query object.
77 | *
78 | * @return bool Returning a non-false value from the filter will short-circuit the handling
79 | * and return early.
80 | *
81 | * @link https://developer.wordpress.org/reference/hooks/pre_handle_404/
82 | */
83 | public function pre_handle_404( $preempt, $wp_query ) {
84 | // Analyse only if there is post parsed.
85 | if ( ! is_single() ) {
86 | return false;
87 | }
88 |
89 | $post = $wp_query->post;
90 | if ( null === $post ) {
91 | return false;
92 | }
93 |
94 | // Analyse only if custom field used in query.
95 | if ( ! array_key_exists( self::PARAM_CUSTOMFIELD_PARAMS, $wp_query->query_vars )
96 | || ! is_array( $wp_query->query_vars[ self::PARAM_CUSTOMFIELD_PARAMS ] )
97 | ) {
98 | return false;
99 | }
100 |
101 | $query_meta_params = $wp_query->query_vars[ self::PARAM_CUSTOMFIELD_PARAMS ];
102 | $query_meta_params_attr = $this->get_param_attr( $wp_query );
103 |
104 | $raise_404 = false;
105 |
106 | foreach ( $query_meta_params as $query_meta_key => $query_meta_value ) {
107 | if ( array_key_exists( $query_meta_key, $query_meta_params_attr ) ) {
108 | $field_attr = $query_meta_params_attr[ $query_meta_key ];
109 | } else {
110 | $field_attr = array();
111 | }
112 |
113 | $post_meta_values = $this->post_meta->get_post_meta_single( $post, $query_meta_key, $field_attr );
114 |
115 | if ( null === $post_meta_values || ! $post_meta_values ) {
116 | $raise_404 = true;
117 | break;
118 | } else {
119 | // Look for at least one value match.
120 | $value_matched = false;
121 | foreach ( $post_meta_values as $post_meta_value ) {
122 | $post_meta_value_sanitized = sanitize_title( $post_meta_value );
123 |
124 | if ( $query_meta_value == $post_meta_value_sanitized ) {
125 | $value_matched = true;
126 | break;
127 | }
128 | }
129 |
130 | if ( ! $value_matched ) {
131 | $raise_404 = true;
132 | }
133 | }
134 | }
135 |
136 | if ( $raise_404 ) {
137 | $wp_query->set_404();
138 | status_header( 404 );
139 | nocache_headers();
140 |
141 | // 404 already raised, break the circuit.
142 | return true;
143 | }
144 |
145 | return false;
146 | }
147 |
148 | /**
149 | * Gets custom fields parameters attributes from WP_Query.
150 | *
151 | * @param WP_Query $wp_query WordPress Query object.
152 | *
153 | * @access private
154 | * @return array
155 | */
156 | private function get_param_attr( WP_Query $wp_query ) {
157 | if ( ! isset( $wp_query->query_vars[ self::PARAM_CUSTOMFIELD_PARAMS_ATTR ] ) ) {
158 | return array();
159 | }
160 |
161 | $attrs = array();
162 | $query_meta_params_attr = $wp_query->query_vars[ self::PARAM_CUSTOMFIELD_PARAMS_ATTR ];
163 |
164 | foreach ( $query_meta_params_attr as $attr_field_and_key => $attr_value ) {
165 | list( $field_name, $field_attr_name ) = explode( '::', $attr_field_and_key );
166 |
167 | if ( ! array_key_exists( $field_name, $attrs ) ) {
168 | $attrs[ $field_name ] = array();
169 | }
170 |
171 | $attrs[ $field_name ][ $field_attr_name ] = $attr_value;
172 | }
173 |
174 | return $attrs;
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/includes/class-wp-rewrite-rules.php:
--------------------------------------------------------------------------------
1 | field_attributes = $field_attributes;
48 | }
49 |
50 | /**
51 | * Filters the full set of generated rewrite rules.
52 | * The rewrite_rules_array filter implementation.
53 | *
54 | * @param array $rules The compiled array of rewrite rules.
55 | *
56 | * @link https://developer.wordpress.org/reference/hooks/rewrite_rules_array/
57 | *
58 | * @return array
59 | */
60 | public function rewrite_rules_array_filter( $rules ) {
61 | $new_rules = array();
62 |
63 | foreach ( $rules as $key => $rule ) {
64 | if ( preg_match_all( '/' . self::FIELD_REGEXP . '/', $key, $key_matches ) ) {
65 | if ( $this->conflicts_with_page_permalink( $key, $key_matches ) ) {
66 | continue;
67 | }
68 |
69 | $key_new = preg_replace(
70 | '/' . self::FIELD_REGEXP . '/',
71 | '([^/]+)',
72 | // You can simply add next group to the url, because WordPress.
73 | // Detect them automatically and add next $matches indices.
74 | $key
75 | );
76 |
77 | $new_rule = $rule;
78 | foreach ( $key_matches[ self::FIELD_REGEXP_MAIN_GROUP ] as $i => $key_match ) {
79 | $new_rule_replacement = $this->build_rule_on_field_match( $key_matches, $i );
80 |
81 | $new_rule = str_replace(
82 | $key_match,
83 | $new_rule_replacement,
84 | // Here on the end will be pasted $matches[$i] from $keyNew,
85 | // so we can grab it it the future in self::PARAM_CUSTOMFIELD_VALUE parameter.
86 | $new_rule
87 | );
88 | }
89 |
90 | $new_rules[ $key_new ] = $new_rule;
91 | } else {
92 | $new_rules[ $key ] = $rule;
93 | }
94 | }
95 |
96 | return $new_rules;
97 | }
98 |
99 | /**
100 | * Fixes the permalink structure option which encodes as url the field definition.
101 | *
102 | * @param mixed $new_value The new value.
103 | *
104 | * @link https://codex.wordpress.org/Plugin_API/Filter_Reference/pre_update_option_(option_name)
105 | * @see WP_Rewrite::set_permalink_structure()
106 | *
107 | * @return mixed
108 | */
109 | public function permalink_structure_option_filter( $new_value ) {
110 | preg_match( '/' . self::FIELD_REGEXP . '/', $new_value, $matches );
111 |
112 | if ( isset( $matches[ self::FIELD_REGEXP_ATTRIBUTES_GROUP ] ) ) {
113 | $new_value_filtered = str_replace( $matches[ self::FIELD_REGEXP_ATTRIBUTES_GROUP ], urldecode( $matches[ self::FIELD_REGEXP_ATTRIBUTES_GROUP ] ), $new_value );
114 | return $new_value_filtered;
115 | } else {
116 | return $new_value;
117 | }
118 | }
119 |
120 | /**
121 | * Builds the part of rewrite rule replacement based on parameter match and its attributes.
122 | *
123 | * @param array $key_matches All found matches.
124 | * @param integer $i Match number.
125 | *
126 | * @access private
127 | * @return string The rewrite rule replacement.
128 | */
129 | private function build_rule_on_field_match( $key_matches, $i ) {
130 | $field_name = $key_matches[ self::FIELD_REGEXP_NAME_GROUP ][ $i ];
131 | $field_attributes = $this->field_attributes->parse_attributes( $key_matches[ self::FIELD_REGEXP_ATTRIBUTES_GROUP ][ $i ] );
132 |
133 | $rule_rewrite = array();
134 | $rule_rewrite[ WP_Request_Processor::PARAM_CUSTOMFIELD_PARAMS_ATTR ] = array();
135 | $rule_rewrite[ WP_Request_Processor::PARAM_CUSTOMFIELD_PARAMS ] = array();
136 |
137 | if ( $field_attributes ) {
138 | foreach ( $field_attributes as $attr_key => $attr_value ) {
139 | $rule_rewrite[ WP_Request_Processor::PARAM_CUSTOMFIELD_PARAMS_ATTR ][ $field_name . '::' . $attr_key ] = $attr_value;
140 | }
141 | }
142 |
143 | $rule_rewrite[ WP_Request_Processor::PARAM_CUSTOMFIELD_PARAMS ][ $field_name ] = '';
144 |
145 | return http_build_query( $rule_rewrite );
146 | }
147 |
148 | /**
149 | * Determines if rewrite rule contains only custom field tag and conflicts with pages permalink.
150 | *
151 | * @param string $key Rewrite rule.
152 | * @param array $key_matches All found matches.
153 | *
154 | * @access private
155 | * @return boolean Whether rewrite rule conflicts with page rule.
156 | */
157 | private function conflicts_with_page_permalink( $key, $key_matches ) {
158 | if ( count( $key_matches[ self::FIELD_REGEXP_MAIN_GROUP ] ) == 1 ) {
159 | // If the rewrite rule is only %field_some%/?$ it will be in conflict with pages rewrite rule.
160 | return preg_match( '/^' . self::FIELD_REGEXP . '\/\?\$$/', $key );
161 | }
162 |
163 | return false;
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/includes/main.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | Generally-applicable sniffs for WordPress plugins
4 |
5 |
6 |
7 |
8 |
9 |
10 | .
11 |
12 |
13 |
14 |
15 | */node_modules/*
16 | */vendor/*
17 |
18 |
19 |
20 | */test/integration/suites/*
21 | */test/unit/*
22 |
23 |
24 | */test/integration/suites/*
25 | */test/unit/*
26 |
27 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 | ./test/unit/
13 | ./test/integration/suites/
14 |
15 |
16 |
17 |
18 | ./includes/
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | === Custom Fields Permalink 2 ===
2 | Contributors: athlan
3 | Donate link: http://athlan.pl/wordpres-custom-fields-permalink-plugin/
4 | Tags: custom fields, permalinks, permalink, url, custom post types, post type, tax, taxonomy, types
5 | Requires at least: 4.5.0
6 | Tested up to: 5.0
7 | Stable tag: 1.5.0
8 | Requires PHP: 5.3
9 | License: MIT
10 | License URI: http://opensource.org/licenses/MIT
11 |
12 | Plugin allows to use post's custom fields values in permalink structure by adding %field_fieldname%, for posts, pages and custom post types.
13 |
14 | == Description ==
15 |
16 | Plugin allows to use post's custom fields values in permalink structure by adding `%field_fieldname%` rewrite tag.
17 |
18 | Examples:
19 |
20 | * `http://example.com/%field_event_date_from%/%postname%/`
21 | * `http://example.com/post-type/%field_event_date_from%/%postname%/` (with Custom Post Type Permalinks plugin)
22 |
23 | You can also set different permalink structure depending on custom post type using Custom Post Type Permalinks plugin. You can create own post types by using Custom Post Type UI plugin.
24 |
25 | The plugin works for:
26 |
27 | * posts
28 | * pages
29 | * custom post types
30 |
31 | Plugin is also available on GitHub:
32 | https://github.com/athlan/wordpress-custom-fields-permalink-plugin
33 |
34 | == Installation ==
35 |
36 | * Install plugin in WordPress system in Plugins section. You can search for "Custom Fields Permalink 2".
37 | * Done! Now you can use `%field_fieldname%` tag in Settings -> Permalinks.
38 |
39 | == Frequently Asked Questions ==
40 |
41 | = Found the bug. How to raise a ticket? =
42 |
43 | The best way is to raise the ticket under the GitHub repository:
44 | https://github.com/athlan/wordpress-custom-fields-permalink-plugin/issues/new
45 |
46 | = I want to make a contribution =
47 |
48 | We would be very grateful in any contribution. If you have a idea for the feature, please discuss it first by
49 | raising the ticket.
50 | When the assumptions are ready, please
51 | make a pull request at GitHub.
52 |
53 | = How to generate missing custom post meta keys and values =
54 |
55 | In case of missing custom post field values you can generate them on-the-fly using generate_dynamic_metadata
filter.
56 |
57 | Read the example.
58 |
59 | = How to generate calculated dynamic custom post meta keys and values =
60 |
61 | You can generate custom post fields dynamically coding some logic using generate_dynamic_metadata
filter.
62 |
63 | Read the example.
64 |
65 | == Screenshots ==
66 |
67 | 1. Pemralink settings
68 | 2. Custom post types Pemralink settings
69 |
70 | == Changelog ==
71 |
72 | Release notes: https://github.com/athlan/wordpress-custom-fields-permalink-plugin/releases
73 |
74 | == Upgrade Notice ==
75 |
76 | No upgrade notices.
77 |
--------------------------------------------------------------------------------
/test/integration/bootstrap.php:
--------------------------------------------------------------------------------
1 | ID, $result->user_login );
33 | }
34 |
35 | /**
36 | * Logged as admin.
37 | */
38 | public function given_logged_as_admin() {
39 | $this->given_logged_as( 'admin', 'password' );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/test/integration/class-basetestcase.php:
--------------------------------------------------------------------------------
1 | permalink_steps = new PermalinkSteps( $this );
55 | $this->custom_post_type_steps = new CustomPostTypeSteps( $this );
56 | $this->auth_steps = new AuthSteps( $this );
57 | $this->permalink_asserter = new PermalinkAsserter( $this );
58 | $this->navigation_asserter = new NavigationAsserter( $this );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/test/integration/class-customposttypesteps.php:
--------------------------------------------------------------------------------
1 | post_type = $post_type;
57 | }
58 |
59 | /**
60 | * Sets the given permalink structure.
61 | */
62 | public function end() {
63 | $this->init();
64 | }
65 |
66 | /**
67 | * Initializes all.
68 | */
69 | private function init() {
70 | $args = array(
71 | 'label' => $this->post_type,
72 | 'supports' => array( 'title', 'editor', 'custom-fields' ),
73 | 'public' => true,
74 | );
75 |
76 | if ( $this->rewrite_slug ) {
77 | $args['rewrite'] = array(
78 | 'slug' => $this->rewrite_slug,
79 | );
80 | }
81 |
82 | register_post_type( $this->post_type, $args );
83 |
84 | flush_rewrite_rules();
85 | }
86 |
87 | /**
88 | * Sets the given rewrite slug.
89 | *
90 | * @param string $rewrite_slug Rewrite slug.
91 | *
92 | * @return CustomPostTypeStepsBuilder
93 | */
94 | public function with_rewrite_slug( $rewrite_slug ) {
95 | $this->rewrite_slug = $rewrite_slug;
96 | return $this;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/test/integration/class-navigationasserter.php:
--------------------------------------------------------------------------------
1 | unit_test_case = $unit_test_case;
27 | }
28 |
29 | /**
30 | * Checks if post is displayed
31 | *
32 | * @param WP_Post|int $post The post or id.
33 | *
34 | * @return NavigationAsserter Fluent interface.
35 | */
36 | public function then_displayed_post( $post ) {
37 | $this->unit_test_case->assertTrue( is_single( $post ) );
38 | return $this;
39 | }
40 |
41 | /**
42 | * Checks if post is not displayed
43 | *
44 | * @param WP_Post|int $post The post or id.
45 | *
46 | * @return NavigationAsserter Fluent interface.
47 | */
48 | public function then_not_displayed_post( $post ) {
49 | $this->unit_test_case->assertFalse( is_single( $post ) );
50 | return $this;
51 | }
52 |
53 | /**
54 | * Checks if page is displayed
55 | *
56 | * @param WP_Post|int $post The post or id.
57 | *
58 | * @return NavigationAsserter Fluent interface.
59 | */
60 | public function then_displayed_page( $post ) {
61 | $this->unit_test_case->assertTrue( is_page( $post ) );
62 | return $this;
63 | }
64 |
65 | /**
66 | * Checks if page is not displayed
67 | *
68 | * @param WP_Post|int $post The post or id.
69 | *
70 | * @return NavigationAsserter Fluent interface.
71 | */
72 | public function then_not_displayed_page( $post ) {
73 | $this->unit_test_case->assertFalse( is_page( $post ) );
74 | return $this;
75 | }
76 |
77 | /**
78 | * Checks if 404 page is reached
79 | *
80 | * @return NavigationAsserter Fluent interface.
81 | */
82 | public function then_is_404() {
83 | $this->unit_test_case->assertTrue( is_404() );
84 | return $this;
85 | }
86 |
87 | /**
88 | * Fluent interface.
89 | *
90 | * @return NavigationAsserter Fluent interface.
91 | */
92 | public function and_also() {
93 | return $this;
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/test/integration/class-permalinkasserter.php:
--------------------------------------------------------------------------------
1 | unit_test_case = $unit_test_case;
27 | }
28 |
29 | /**
30 | * Checks if post has an expected permalink.
31 | *
32 | * @param WP_Post $post The post.
33 | * @param string $permalink Expected permalink.
34 | *
35 | * @return PermalinkAsserter Fluent interface.
36 | */
37 | public function has_permalink( $post, $permalink ) {
38 | $actual = wp_make_link_relative( get_the_permalink( $post ) );
39 |
40 | $this->unit_test_case->assertEquals( $permalink, $actual );
41 |
42 | return $this;
43 | }
44 |
45 | /**
46 | * Fluent interface.
47 | *
48 | * @return PermalinkAsserter Fluent interface.
49 | */
50 | public function and_also() {
51 | return $this;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/test/integration/class-permalinksteps.php:
--------------------------------------------------------------------------------
1 | init();
28 | $wp_rewrite->set_permalink_structure( $structure );
29 |
30 | /*
31 | * Fix the WordPress bug that ignores previously filtered formatted updated option
32 | * once it is new one during the addition. Submit the option twice.
33 | */
34 | $wp_rewrite->set_permalink_structure( $structure );
35 |
36 | $wp_rewrite->flush_rules();
37 | }
38 |
39 | /**
40 | * Sets the "/%postname%/" permalink structure.
41 | */
42 | public function given_postname_permalink_structure() {
43 | $this->given_permalink_structure( '/%postname%/' );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/test/integration/suites/BasicPostNamePermalinkStructure/BasicPostNamePermalinkStructure.php:
--------------------------------------------------------------------------------
1 | permalink_steps->given_postname_permalink_structure();
23 |
24 | $post_params = array(
25 | 'post_title' => 'Some post title',
26 | 'meta_input' => array(
27 | 'some_meta_key' => 'Some meta value',
28 | ),
29 | );
30 | $created_post_id = $this->factory()->post->create( $post_params );
31 |
32 | // when & then.
33 | $this->permalink_asserter->has_permalink( $created_post_id, '/some-post-title/' );
34 | }
35 |
36 | /**
37 | * Test case.
38 | */
39 | function test_go_to_post_when_simple_postname_permalink_structure_and_plugin_activated() {
40 | // given.
41 | $this->permalink_steps->given_postname_permalink_structure();
42 |
43 | $post_params = array(
44 | 'post_title' => 'Some post title',
45 | 'meta_input' => array(
46 | 'some_meta_key' => 'Some meta value',
47 | ),
48 | );
49 | $created_post_id = $this->factory()->post->create( $post_params );
50 |
51 | // when.
52 | $this->go_to( '/some-post-title/' );
53 |
54 | // then.
55 | $this->assertFalse( is_404() );
56 | $this->assertEquals( $created_post_id, get_the_ID() );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/test/integration/suites/CustomPostType/CustomPostTypeWithMetaKey.php:
--------------------------------------------------------------------------------
1 | permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
23 |
24 | $this->custom_post_type_steps->given_custom_post_type( 'custom_post_type' )
25 | ->with_rewrite_slug( 'custom/%field_some_meta_key%' )
26 | ->end();
27 |
28 | $post_params = array(
29 | 'post_title' => 'Some post title',
30 | 'post_type' => 'custom_post_type',
31 | 'meta_input' => array(
32 | 'some_meta_key' => 'Some meta value',
33 | 'some_other_meta_key' => 'Some other meta value',
34 | ),
35 | );
36 | $created_post_id = $this->factory()->post->create( $post_params );
37 |
38 | // when & then.
39 | $this->permalink_asserter->has_permalink( $created_post_id, '/custom/some-meta-value/some-post-title/' );
40 | }
41 |
42 | /**
43 | * Test case.
44 | */
45 | function test_go_to_post_using_meta_key_permalink_structure() {
46 | // given.
47 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
48 |
49 | $this->custom_post_type_steps->given_custom_post_type( 'custom_post_type' )
50 | ->with_rewrite_slug( 'custom/%field_some_meta_key%' )
51 | ->end();
52 |
53 | $post_params = array(
54 | 'post_title' => 'Some post title',
55 | 'post_type' => 'custom_post_type',
56 | 'meta_input' => array(
57 | 'some_meta_key' => 'Some meta value',
58 | 'some_other_meta_key' => 'Some other meta value',
59 | ),
60 | );
61 | $created_post_id = $this->factory()->post->create( $post_params );
62 |
63 | // when.
64 | $this->go_to( '/custom/some-meta-value/some-post-title/' );
65 |
66 | // then.
67 | $this->navigation_asserter->then_displayed_post( $created_post_id );
68 | }
69 |
70 | /**
71 | * Test case.
72 | */
73 | function test_not_go_to_the_post_when_invalid_value_of_meta_key_part_in_url() {
74 | // given.
75 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
76 |
77 | $this->custom_post_type_steps->given_custom_post_type( 'custom_post_type' )
78 | ->with_rewrite_slug( '%field_some_meta_key%' )
79 | ->end();
80 |
81 | $post_params = array(
82 | 'post_title' => 'Some post title',
83 | 'post_type' => 'custom_post_type',
84 | 'meta_input' => array(
85 | 'some_meta_key' => 'Some meta value',
86 | ),
87 | );
88 | $created_post_id = $this->factory()->post->create( $post_params );
89 |
90 | // when.
91 | $this->go_to( '/custom/some-different-meta-value/some-post-title/' );
92 |
93 | // then.
94 | $this->navigation_asserter->then_not_displayed_post( $created_post_id );
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/test/integration/suites/MetaKeyPermalinkStructure/PageWithMetaKey.php:
--------------------------------------------------------------------------------
1 | permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
26 |
27 | $page_params = array(
28 | 'post_type' => 'page',
29 | 'post_title' => 'Some page title',
30 | 'meta_input' => array(
31 | 'some_meta_key' => 'Some meta value',
32 | 'some_other_meta_key' => 'Some other meta value',
33 | ),
34 | );
35 | $created_page_id = $this->factory()->post->create( $page_params );
36 |
37 | // when & then.
38 | $this->permalink_asserter->has_permalink( $created_page_id, '/some-page-title/' );
39 | }
40 |
41 | /**
42 | * Test case.
43 | */
44 | function test_go_to_page_not_using_meta_key_permalink_structure() {
45 | // given.
46 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
47 |
48 | $post_params = array(
49 | 'post_type' => 'page',
50 | 'post_title' => 'Some page title',
51 | 'meta_input' => array(
52 | 'some_meta_key' => 'Some meta value',
53 | 'some_other_meta_key' => 'Some other meta value',
54 | ),
55 | );
56 | $created_page_id = $this->factory()->post->create( $post_params );
57 |
58 | // when.
59 | $this->go_to( '/some-page-title/' );
60 |
61 | // then.
62 | $this->navigation_asserter->then_displayed_page( $created_page_id );
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/test/integration/suites/MetaKeyPermalinkStructure/PostWithDuplicatedMetaKey.php:
--------------------------------------------------------------------------------
1 | permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
23 |
24 | $some_meta_key = 'some_meta_key';
25 | $post_params = array(
26 | 'post_title' => 'Some post title',
27 | 'meta_input' => array(
28 | $some_meta_key => 'Some meta value',
29 | ),
30 | );
31 | $created_post_id = $this->factory()->post->create( $post_params );
32 | add_post_meta( $created_post_id, $some_meta_key, 'Some duplicated meta value' );
33 |
34 | // when.
35 | $created_post_meta_values = get_post_meta( $created_post_id );
36 |
37 | // then.
38 | $this->assertCount( 2, $created_post_meta_values[ $some_meta_key ] );
39 | $this->permalink_asserter->has_permalink( $created_post_id, '/some-meta-value/some-post-title/' );
40 | }
41 |
42 | /**
43 | * Test case.
44 | */
45 | function test_go_to_post_when_duplicated_meta_key_and_use_first_one() {
46 | // given.
47 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
48 |
49 | $some_meta_key = 'some_meta_key';
50 | $post_params = array(
51 | 'post_title' => 'Some post title',
52 | 'meta_input' => array(
53 | $some_meta_key => 'Some meta value',
54 | ),
55 | );
56 | $created_post_id = $this->factory()->post->create( $post_params );
57 | add_post_meta( $created_post_id, $some_meta_key, 'Some duplicated meta value' );
58 |
59 | // when.
60 | $this->go_to( '/some-meta-value/some-post-title/' );
61 |
62 | // then.
63 | $this->navigation_asserter->then_displayed_post( $created_post_id );
64 | }
65 |
66 | /**
67 | * Test case.
68 | */
69 | function test_go_to_post_when_duplicated_meta_key_and_use_duplicate_one() {
70 | // given.
71 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
72 |
73 | $some_meta_key = 'some_meta_key';
74 | $post_params = array(
75 | 'post_title' => 'Some post title',
76 | 'meta_input' => array(
77 | $some_meta_key => 'Some meta value',
78 | ),
79 | );
80 | $created_post_id = $this->factory()->post->create( $post_params );
81 | add_post_meta( $created_post_id, $some_meta_key, 'Some duplicated meta value' );
82 |
83 | // when.
84 | $this->go_to( '/some-duplicated-meta-value/some-post-title/' );
85 |
86 | // then.
87 | $this->navigation_asserter->then_displayed_post( $created_post_id );
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/test/integration/suites/MetaKeyPermalinkStructure/PostWithDynamicallyCreatedMetaKey.php:
--------------------------------------------------------------------------------
1 | permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
47 |
48 | $post_params = array(
49 | 'post_title' => 'Some post title',
50 | 'meta_input' => array(
51 | // There is missing meta key here
52 | // 'some_meta_key' => 'Some meta value', .
53 | ),
54 | );
55 | $created_post_id = $this->factory()->post->create( $post_params );
56 |
57 | $this->given_hook_registered();
58 |
59 | // when & then.
60 | $this->permalink_asserter->has_permalink( $created_post_id, '/default-value/some-post-title/' );
61 | }
62 |
63 | /**
64 | * Test case.
65 | */
66 | function test_go_to_post_when_dynamic_generated_meta_value_without_hook() {
67 | // given.
68 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
69 |
70 | $post_params = array(
71 | 'post_title' => 'Some post title',
72 | 'meta_input' => array(
73 | // There is missing meta key here
74 | // 'some_meta_key' => 'Some meta value', .
75 | ),
76 | );
77 | $created_post_id = $this->factory()->post->create( $post_params );
78 |
79 | // when.
80 | $this->go_to( '/default-value/some-post-title/' );
81 |
82 | // then.
83 | $this->navigation_asserter->then_not_displayed_post( $created_post_id )
84 | ->and_also()
85 | ->then_is_404();
86 | }
87 |
88 | /**
89 | * Test case.
90 | */
91 | function test_go_to_post_when_dynamic_generated_meta_value_with_hook() {
92 | // given.
93 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
94 |
95 | $post_params = array(
96 | 'post_title' => 'Some post title',
97 | 'meta_input' => array(
98 | // There is missing meta key here
99 | // 'some_meta_key' => 'Some meta value', .
100 | ),
101 | );
102 | $created_post_id = $this->factory()->post->create( $post_params );
103 |
104 | $this->given_hook_registered();
105 |
106 | // when.
107 | $this->go_to( '/default-value/some-post-title/' );
108 |
109 | // then.
110 | $this->navigation_asserter->then_displayed_post( $created_post_id );
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/test/integration/suites/MetaKeyPermalinkStructure/PostWithDynamicallyCreatedSingleMetaKey.php:
--------------------------------------------------------------------------------
1 | permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
49 |
50 | $post_params = array(
51 | 'post_title' => 'Some post title',
52 | 'meta_input' => array(
53 | // There is missing meta key here
54 | // 'some_meta_key' => 'Some meta value', .
55 | ),
56 | );
57 | $created_post_id = $this->factory()->post->create( $post_params );
58 |
59 | $this->given_hook_registered();
60 |
61 | // when & then.
62 | $this->permalink_asserter->has_permalink( $created_post_id, '/default-value/some-post-title/' );
63 | }
64 |
65 | /**
66 | * Test case.
67 | */
68 | function test_go_to_post_when_dynamic_generated_meta_value_without_hook() {
69 | // given.
70 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
71 |
72 | $post_params = array(
73 | 'post_title' => 'Some post title',
74 | 'meta_input' => array(
75 | // There is missing meta key here
76 | // 'some_meta_key' => 'Some meta value', .
77 | ),
78 | );
79 | $created_post_id = $this->factory()->post->create( $post_params );
80 |
81 | // when.
82 | $this->go_to( '/default-value/some-post-title/' );
83 |
84 | // then.
85 | $this->navigation_asserter->then_not_displayed_post( $created_post_id )
86 | ->and_also()
87 | ->then_is_404();
88 | }
89 |
90 | /**
91 | * Test case.
92 | */
93 | function test_go_to_post_when_dynamic_generated_meta_value_with_hook() {
94 | // given.
95 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
96 |
97 | $post_params = array(
98 | 'post_title' => 'Some post title',
99 | 'meta_input' => array(
100 | // There is missing meta key here
101 | // 'some_meta_key' => 'Some meta value', .
102 | ),
103 | );
104 | $created_post_id = $this->factory()->post->create( $post_params );
105 |
106 | $this->given_hook_registered();
107 |
108 | // when.
109 | $this->go_to( '/default-value/some-post-title/' );
110 |
111 | // then.
112 | $this->navigation_asserter->then_displayed_post( $created_post_id );
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/test/integration/suites/MetaKeyPermalinkStructure/PostWithMetaKey.php:
--------------------------------------------------------------------------------
1 | permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
23 |
24 | $post_params = array(
25 | 'post_title' => 'Some post title',
26 | 'meta_input' => array(
27 | 'some_meta_key' => 'Some meta value',
28 | 'some_other_meta_key' => 'Some other meta value',
29 | ),
30 | );
31 | $created_post_id = $this->factory()->post->create( $post_params );
32 |
33 | // when & then.
34 | $this->permalink_asserter->has_permalink( $created_post_id, '/some-meta-value/some-post-title/' );
35 | }
36 |
37 | /**
38 | * Test case.
39 | */
40 | function test_go_to_post_using_meta_key_permalink_structure() {
41 | // given.
42 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
43 |
44 | $post_params = array(
45 | 'post_title' => 'Some post title',
46 | 'meta_input' => array(
47 | 'some_meta_key' => 'Some meta value',
48 | 'some_other_meta_key' => 'Some other meta value',
49 | ),
50 | );
51 | $created_post_id = $this->factory()->post->create( $post_params );
52 |
53 | // when.
54 | $this->go_to( '/some-meta-value/some-post-title/' );
55 |
56 | // then.
57 | $this->navigation_asserter->then_displayed_post( $created_post_id );
58 | }
59 |
60 | /**
61 | * Test case.
62 | */
63 | function test_not_go_to_the_post_when_invalid_value_of_meta_key_part_in_url() {
64 | // given.
65 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
66 |
67 | $post_params = array(
68 | 'post_title' => 'Some post title',
69 | 'meta_input' => array(
70 | 'some_meta_key' => 'Some meta value',
71 | ),
72 | );
73 | $created_post_id = $this->factory()->post->create( $post_params );
74 |
75 | // when.
76 | $this->go_to( '/some-different-meta-value/some-post-title/' );
77 |
78 | // then.
79 | $this->navigation_asserter->then_not_displayed_post( $created_post_id );
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/test/integration/suites/MetaKeyPermalinkStructure/PostWithMissingMetaKey.php:
--------------------------------------------------------------------------------
1 | permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
23 |
24 | $post_params = array(
25 | 'post_title' => 'Some post title',
26 | 'meta_input' => array(
27 | // There is missing meta key here
28 | // 'some_meta_key' => 'Some meta value', .
29 | ),
30 | );
31 | $created_post_id = $this->factory()->post->create( $post_params );
32 |
33 | // when & then.
34 | $this->permalink_asserter->has_permalink( $created_post_id, '/some-post-title/' );
35 | }
36 |
37 | /**
38 | * Test case.
39 | */
40 | function test_404_when_missing_meta_key() {
41 | // given.
42 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
43 |
44 | $post_params = array(
45 | 'post_title' => 'Some post title',
46 | 'meta_input' => array(
47 | // There is missing meta key here
48 | // 'some_meta_key' => 'Some meta value', .
49 | ),
50 | );
51 | $created_post_id = $this->factory()->post->create( $post_params );
52 |
53 | // when.
54 | $this->go_to( '/inexisting-meta-value/some-post-title/' );
55 |
56 | // then.
57 | $this->navigation_asserter->then_not_displayed_post( $created_post_id )
58 | ->and_also()
59 | ->then_is_404();
60 | }
61 |
62 | /**
63 | * Test case.
64 | */
65 | function test_not_go_to_the_post_when_missing_meta_key_part_in_url() {
66 | // given.
67 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
68 |
69 | $post_params = array(
70 | 'post_title' => 'Some post title',
71 | 'meta_input' => array(
72 | 'some_meta_key' => 'Some meta value',
73 | ),
74 | );
75 | $created_post_id = $this->factory()->post->create( $post_params );
76 |
77 | // when.
78 | $this->go_to( '/some-post-title/' );
79 |
80 | // then.
81 | $this->navigation_asserter->then_not_displayed_post( $created_post_id );
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/test/integration/suites/MetaKeyPermalinkStructure/PrivatePostWithMetaKey.php:
--------------------------------------------------------------------------------
1 | permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
23 |
24 | $post_params = array(
25 | 'post_title' => 'Some post title',
26 | 'post_status' => 'private',
27 | 'meta_input' => array(
28 | 'some_meta_key' => 'Some meta value',
29 | 'some_other_meta_key' => 'Some other meta value',
30 | ),
31 | );
32 | $created_post_id = $this->factory()->post->create( $post_params );
33 |
34 | // when & then.
35 | $this->permalink_asserter->has_permalink( $created_post_id, '/some-meta-value/some-post-title/' );
36 | }
37 |
38 | /**
39 | * Test case.
40 | */
41 | function test_not_go_to_private_post_using_meta_key_permalink_structure_as_anonymous_user() {
42 | // given.
43 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
44 |
45 | $post_params = array(
46 | 'post_title' => 'Some post title',
47 | 'post_status' => 'private',
48 | 'meta_input' => array(
49 | 'some_meta_key' => 'Some meta value',
50 | 'some_other_meta_key' => 'Some other meta value',
51 | ),
52 | );
53 | $created_post_id = $this->factory()->post->create( $post_params );
54 |
55 | // when.
56 | $this->go_to( '/some-meta-value/some-post-title/' );
57 |
58 | // then.
59 | $this->navigation_asserter->then_not_displayed_post( $created_post_id )
60 | ->and_also()
61 | ->then_is_404();
62 | }
63 |
64 | /**
65 | * Test case.
66 | */
67 | function test_go_to_private_post_using_meta_key_permalink_structure_as_admin_user() {
68 | // given.
69 | $this->auth_steps->given_logged_as_admin();
70 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
71 |
72 | $post_params = array(
73 | 'post_title' => 'Some post title',
74 | 'post_status' => 'private',
75 | 'meta_input' => array(
76 | 'some_meta_key' => 'Some meta value',
77 | 'some_other_meta_key' => 'Some other meta value',
78 | ),
79 | );
80 | $created_post_id = $this->factory()->post->create( $post_params );
81 |
82 | // when.
83 | $this->go_to( '/some-meta-value/some-post-title/' );
84 |
85 | // then.
86 | $this->navigation_asserter->then_displayed_post( $created_post_id );
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/test/integration/suites/MultipleMetaKeyPermalinkStructure/PostWithMetaKeyMultiple.php:
--------------------------------------------------------------------------------
1 | permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%field_some_meta_key2%/%postname%/' );
23 |
24 | $post_params = array(
25 | 'post_title' => 'Some post title',
26 | 'meta_input' => array(
27 | 'some_meta_key' => 'Some meta value',
28 | 'some_meta_key2' => 'Some second meta value',
29 | 'some_other_meta_key' => 'Some other meta value',
30 | ),
31 | );
32 | $created_post_id = $this->factory()->post->create( $post_params );
33 |
34 | // when & then.
35 | $this->permalink_asserter->has_permalink( $created_post_id, '/some-meta-value/some-second-meta-value/some-post-title/' );
36 | }
37 |
38 | /**
39 | * Test case.
40 | */
41 | function test_go_to_post_using_meta_key_permalink_structure() {
42 | // given.
43 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%field_some_meta_key2%/%postname%/' );
44 |
45 | $post_params = array(
46 | 'post_title' => 'Some post title',
47 | 'meta_input' => array(
48 | 'some_meta_key' => 'Some meta value',
49 | 'some_meta_key2' => 'Some second meta value',
50 | 'some_other_meta_key' => 'Some other meta value',
51 | ),
52 | );
53 | $created_post_id = $this->factory()->post->create( $post_params );
54 |
55 | // when.
56 | // Little hacky with "1" at the end, but wrong route is matched during the tests.
57 | $this->go_to( '/some-meta-value/some-second-meta-value/some-post-title/1' );
58 |
59 | // then.
60 | $this->navigation_asserter->then_displayed_post( $created_post_id );
61 | }
62 |
63 | /**
64 | * Test case.
65 | */
66 | function test_not_go_to_the_post_when_invalid_first_value_of_meta_key_part_in_url() {
67 | // given.
68 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%field_some_meta_key2%/%postname%/' );
69 |
70 | $post_params = array(
71 | 'post_title' => 'Some post title',
72 | 'meta_input' => array(
73 | 'some_meta_key' => 'Some meta value',
74 | 'some_meta_key2' => 'Some second meta value',
75 | ),
76 | );
77 | $created_post_id = $this->factory()->post->create( $post_params );
78 |
79 | // when.
80 | $this->go_to( '/some-different-meta-value/some-second-meta-value/some-post-title/1' );
81 |
82 | // then.
83 | $this->navigation_asserter->then_not_displayed_post( $created_post_id );
84 | }
85 |
86 | /**
87 | * Test case.
88 | */
89 | function test_not_go_to_the_post_when_invalid_second_value_of_meta_key_part_in_url() {
90 | // given.
91 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%field_some_meta_key2%/%postname%/' );
92 |
93 | $post_params = array(
94 | 'post_title' => 'Some post title',
95 | 'meta_input' => array(
96 | 'some_meta_key' => 'Some meta value',
97 | 'some_meta_key2' => 'Some second meta value',
98 | ),
99 | );
100 | $created_post_id = $this->factory()->post->create( $post_params );
101 |
102 | // when.
103 | $this->go_to( '/some-meta-value/some-different-meta-value/some-post-title/1' );
104 |
105 | // then.
106 | $this->navigation_asserter->then_not_displayed_post( $created_post_id );
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/test/integration/suites/PermalinkWithAttributesStructure/PostWithMetaKey.php:
--------------------------------------------------------------------------------
1 | hook_calls[ $meta_key ] = array(
37 | 'post_meta_value' => $post_meta_value,
38 | 'meta_key' => $meta_key,
39 | 'meta_key_attrs' => $meta_key_attrs,
40 | 'post' => $post,
41 | );
42 |
43 | return $post_meta_value;
44 | }
45 |
46 | /**
47 | * Test step that hook wpcfp_get_post_metadata has been registered.
48 | */
49 | private function given_hook_registered() {
50 | $this->hook_calls = array();
51 | add_filter( 'wpcfp_get_post_metadata_single', array( $this, 'get_post_metadata_single' ), 1, 4 );
52 | }
53 |
54 | /**
55 | * Test case.
56 | */
57 | function test_generates_permalink_to_post_using_meta_key() {
58 | // given.
59 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key(some_attribute)%/%postname%/' );
60 | $this->given_hook_registered();
61 |
62 | $post_params = array(
63 | 'post_title' => 'Some post title',
64 | 'meta_input' => array(
65 | 'some_meta_key' => 'Some meta value',
66 | 'some_other_meta_key' => 'Some other meta value',
67 | ),
68 | );
69 | $created_post_id = $this->factory()->post->create( $post_params );
70 |
71 | // when & then.
72 | $this->permalink_asserter->has_permalink( $created_post_id, '/some-meta-value/some-post-title/' );
73 |
74 | $this->assertThatHookWasCalledWith(
75 | 'some_meta_key',
76 | 'Some meta value',
77 | array( 'some_attribute' => true ),
78 | $created_post_id
79 | );
80 | $this->assertThatHookWasNotCalledForField( 'some_other_meta_key' );
81 | }
82 |
83 | /**
84 | * Test case.
85 | */
86 | function test_go_to_post_using_meta_key_permalink_structure() {
87 | // given.
88 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key(some_attribute)%/%postname%/' );
89 | $this->given_hook_registered();
90 |
91 | $post_params = array(
92 | 'post_title' => 'Some post title',
93 | 'meta_input' => array(
94 | 'some_meta_key' => 'Some meta value',
95 | 'some_other_meta_key' => 'Some other meta value',
96 | ),
97 | );
98 | $created_post_id = $this->factory()->post->create( $post_params );
99 |
100 | // when.
101 | $this->go_to( '/some-meta-value/some-post-title/' );
102 |
103 | // then.
104 | $this->navigation_asserter->then_displayed_post( $created_post_id );
105 |
106 | $this->assertThatHookWasCalledWith(
107 | 'some_meta_key',
108 | 'Some meta value',
109 | array( 'some_attribute' => true ),
110 | $created_post_id
111 | );
112 | $this->assertThatHookWasNotCalledForField( 'some_other_meta_key' );
113 | }
114 |
115 | /**
116 | * Test case.
117 | */
118 | function test_go_to_post_using_meta_key_permalink_structure_multiple_attributes() {
119 | // given.
120 | $this->permalink_steps->given_permalink_structure( '/%field_some_meta_key(some_attribute some_second_attribute=\'some value\')%/%postname%/' );
121 | $this->given_hook_registered();
122 |
123 | $post_params = array(
124 | 'post_title' => 'Some post title',
125 | 'meta_input' => array(
126 | 'some_meta_key' => 'Some meta value',
127 | 'some_other_meta_key' => 'Some other meta value',
128 | ),
129 | );
130 | $created_post_id = $this->factory()->post->create( $post_params );
131 |
132 | // when.
133 | $this->go_to( '/some-meta-value/some-post-title/' );
134 |
135 | // then.
136 | $this->navigation_asserter->then_displayed_post( $created_post_id );
137 |
138 | $this->assertThatHookWasCalledWith(
139 | 'some_meta_key',
140 | 'Some meta value',
141 | array(
142 | 'some_attribute' => true,
143 | 'some_second_attribute' => 'some value',
144 | ),
145 | $created_post_id
146 | );
147 | $this->assertThatHookWasNotCalledForField( 'some_other_meta_key' );
148 | }
149 |
150 | /**
151 | * Asserter.
152 | *
153 | * @param string $field_name Name of metadata field.
154 | * @param mixed|null $value The metadata value returned from get_post_meta.
155 | * @param array $field_attr The metadata field rewrite permalink attributes.
156 | * @param WP_Post $post_id The post id.
157 | */
158 | private function assertThatHookWasCalledWith( $field_name, $value, $field_attr, $post_id ) {
159 | $this->assertArrayHasKey( $field_name, $this->hook_calls );
160 |
161 | $hook_call = $this->hook_calls[ $field_name ];
162 | $this->assertTrue( $hook_call['post_meta_value'][0] === $value );
163 | $this->assertTrue( $hook_call['meta_key_attrs'] == $field_attr );
164 | $this->assertTrue( $hook_call['post']->ID === $post_id );
165 | }
166 |
167 | /**
168 | * Asserter.
169 | *
170 | * @param string $field_name Name of metadata field.
171 | */
172 | private function assertThatHookWasNotCalledForField( $field_name ) {
173 | $this->assertArrayNotHasKey( $field_name, $this->hook_calls );
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/test/integration/suites/Upgrade/PluginUpgrade.php:
--------------------------------------------------------------------------------
1 | given_stored_plugin_version( null );
27 | $this->given_rewrite_rules_are_corrupted();
28 |
29 | // when.
30 | $plugin_updater->on_init_hook();
31 |
32 | // then.
33 | $rules = $wp_rewrite->wp_rewrite_rules();
34 |
35 | $this->assertNotEquals( 'CORRUPTED', $rules );
36 | $this->assertPluginVersionUpdated();
37 | }
38 |
39 | /**
40 | * Update plugin version.
41 | *
42 | * @param string $version The plugin version.
43 | */
44 | private function given_stored_plugin_version( $version ) {
45 | update_option( '_wordpress_custom_fields_permalink_plugin_version', $version );
46 | }
47 |
48 | /**
49 | * Makes rewrite rules corrupted.
50 | */
51 | private function given_rewrite_rules_are_corrupted() {
52 | global $wp_rewrite;
53 |
54 | update_option( 'rewrite_rules', 'CORRUPTED' );
55 | $rules = $wp_rewrite->wp_rewrite_rules();
56 |
57 | // Sanity check.
58 | $this->assertEquals( 'CORRUPTED', $rules );
59 | }
60 |
61 | /**
62 | * Assert if plugin version is up to date.
63 | */
64 | private function assertPluginVersionUpdated() {
65 | $this->assertEquals( WORDPRESS_CUSTOM_FIELDS_PERMALINK_PLUGIN_VERSION, get_option( '_wordpress_custom_fields_permalink_plugin_version' ) );
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/test/unit/Field_Attributes_UnitTest.php:
--------------------------------------------------------------------------------
1 | parse_attributes( $attributes_string );
25 |
26 | // then no exception.
27 | $this->assertArrayHasKey( 'attr_one', $attributes );
28 | $this->assertTrue( true === $attributes['attr_one'] );
29 | }
30 |
31 | /**
32 | * Test case.
33 | */
34 | public function test_parses_single_attribute_with_value() {
35 | // given.
36 | $field_attributes = new Field_Attributes();
37 | $attributes_string = 'attr_one=value1';
38 |
39 | // when.
40 | $attributes = $field_attributes->parse_attributes( $attributes_string );
41 |
42 | // then no exception.
43 | $this->assertArrayHasKey( 'attr_one', $attributes );
44 | $this->assertTrue( 'value1' === $attributes['attr_one'] );
45 | }
46 |
47 | /**
48 | * Test case.
49 | */
50 | public function test_parses_multiple_attributes() {
51 | // given.
52 | $field_attributes = new Field_Attributes();
53 | $attributes_string = 'attr_one attr_two=value2 attr_three';
54 |
55 | // when.
56 | $attributes = $field_attributes->parse_attributes( $attributes_string );
57 |
58 | // then no exception.
59 | $this->assertArrayHasKey( 'attr_one', $attributes );
60 | $this->assertArrayHasKey( 'attr_two', $attributes );
61 | $this->assertArrayHasKey( 'attr_three', $attributes );
62 | $this->assertTrue( true === $attributes['attr_one'] );
63 | $this->assertTrue( 'value2' === $attributes['attr_two'] );
64 | $this->assertTrue( true === $attributes['attr_three'] );
65 | }
66 |
67 | /**
68 | * Test case.
69 | */
70 | public function test_parses_multiple_attributes_one_in_quote() {
71 | // given.
72 | $field_attributes = new Field_Attributes();
73 | $attributes_string = 'attr_one attr_two=\'some value2\' attr_three';
74 |
75 | // when.
76 | $attributes = $field_attributes->parse_attributes( $attributes_string );
77 |
78 | // then no exception.
79 | $this->assertArrayHasKey( 'attr_one', $attributes );
80 | $this->assertArrayHasKey( 'attr_two', $attributes );
81 | $this->assertArrayHasKey( 'attr_three', $attributes );
82 | $this->assertTrue( true === $attributes['attr_one'] );
83 | $this->assertTrue( 'some value2' === $attributes['attr_two'] );
84 | $this->assertTrue( true === $attributes['attr_three'] );
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/test/unit/WP_Permalink_UnitTest.php:
--------------------------------------------------------------------------------
1 | assertTrue( null !== $permalink );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/test/unit/WP_Request_Processor_UnitTest.php:
--------------------------------------------------------------------------------
1 | assertTrue( null !== $request_processor );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/test/unit/WP_Rewrite_Rules_UnitTest.php:
--------------------------------------------------------------------------------
1 | assertTrue( null !== $rewrite_rules );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/wordpress-custom-fields-permalink-plugin.php:
--------------------------------------------------------------------------------
1 |