From 65bd3654cc320854e91df04a0bf3ebda21c397ab Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Thu, 21 Mar 2019 19:47:29 +0000 Subject: [PATCH] Privacy: Introduce Privacy Policy page helpers: * `is_privacy_policy()` template tag * `privacy-policy.php` template * `.privacy-policy` body class * `.menu-item-privacy-policy` menu item class Props garrett-eclipse, birgire, xkon, Clorith. Fixes #44005. git-svn-id: https://develop.svn.wordpress.org/trunk@44966 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/file.php | 1 + src/wp-includes/class-wp-query.php | 38 +++++++++++ src/wp-includes/nav-menu-template.php | 10 ++- src/wp-includes/post-template.php | 3 + src/wp-includes/query.php | 30 +++++++++ src/wp-includes/template-loader.php | 1 + src/wp-includes/template.php | 22 ++++++- tests/phpunit/includes/abstract-testcase.php | 1 + tests/phpunit/tests/post/getBodyClass.php | 24 +++++++ tests/phpunit/tests/post/nav-menu.php | 65 +++++++++++++++++++ tests/phpunit/tests/query/conditionals.php | 20 ++++++ tests/phpunit/tests/template.php | 36 ++++++++++ tests/phpunit/tests/theme.php | 1 + .../phpunit/tests/url/getPrivacyPolicyUrl.php | 5 +- 14 files changed, 250 insertions(+), 7 deletions(-) diff --git a/src/wp-admin/includes/file.php b/src/wp-admin/includes/file.php index 0cb55806c3..11e5f9231f 100644 --- a/src/wp-admin/includes/file.php +++ b/src/wp-admin/includes/file.php @@ -36,6 +36,7 @@ $wp_file_descriptions = array( 'single.php' => __( 'Single Post' ), 'page.php' => __( 'Single Page' ), 'front-page.php' => __( 'Homepage' ), + 'privacy-policy.php' => __( 'Privacy Policy Page' ), // Attachments 'attachment.php' => __( 'Attachment Template' ), 'image.php' => __( 'Image Attachment Template' ), diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index cd938061db..953f917d27 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -325,6 +325,14 @@ class WP_Query { */ public $is_home = false; + /** + * Signifies whether the current query is for the Privacy Policy page. + * + * @since 5.2.0 + * @var bool + */ + public $is_privacy_policy = false; + /** * Signifies whether the current query couldn't find anything. * @@ -463,6 +471,7 @@ class WP_Query { $this->is_comment_feed = false; $this->is_trackback = false; $this->is_home = false; + $this->is_privacy_policy = false; $this->is_404 = false; $this->is_paged = false; $this->is_admin = false; @@ -998,6 +1007,10 @@ class WP_Query { $this->is_home = true; $this->is_posts_page = true; } + + if ( isset( $this->queried_object_id ) && $this->queried_object_id == get_option( 'wp_page_for_privacy_policy' ) ) { + $this->is_privacy_policy = true; + } } if ( $qv['page_id'] ) { @@ -1006,6 +1019,10 @@ class WP_Query { $this->is_home = true; $this->is_posts_page = true; } + + if ( $qv['page_id'] == get_option( 'wp_page_for_privacy_policy' ) ) { + $this->is_privacy_policy = true; + } } if ( ! empty( $qv['post_type'] ) ) { @@ -3877,6 +3894,27 @@ class WP_Query { return (bool) $this->is_home; } + /** + * Is the query for the Privacy Policy page? + * + * This is the page which shows the Privacy Policy content of your site. + * + * Depends on the site's "Change your Privacy Policy page" Privacy Settings 'wp_page_for_privacy_policy'. + * + * This function will return true only on the page you set as the "Privacy Policy page". + * + * @since 5.2.0 + * + * @return bool True, if Privacy Policy page. + */ + public function is_privacy_policy() { + if ( get_option( 'wp_page_for_privacy_policy' ) && $this->is_page( get_option( 'wp_page_for_privacy_policy' ) ) ) { + return true; + } else { + return false; + } + } + /** * Is the query for an existing month archive? * diff --git a/src/wp-includes/nav-menu-template.php b/src/wp-includes/nav-menu-template.php index 2c8a64ade7..45d9e47de4 100644 --- a/src/wp-includes/nav-menu-template.php +++ b/src/wp-includes/nav-menu-template.php @@ -361,8 +361,9 @@ function _wp_menu_item_classes_by_context( &$menu_items ) { $possible_object_parents = array_filter( $possible_object_parents ); - $front_page_url = home_url(); - $front_page_id = (int) get_option( 'page_on_front' ); + $front_page_url = home_url(); + $front_page_id = (int) get_option( 'page_on_front' ); + $privacy_policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' ); foreach ( (array) $menu_items as $key => $menu_item ) { @@ -378,6 +379,11 @@ function _wp_menu_item_classes_by_context( &$menu_items ) { $classes[] = 'menu-item-home'; } + // This menu item is set as the 'Privacy Policy Page'. + if ( 'post_type' === $menu_item->type && $privacy_policy_page_id === (int) $menu_item->object_id ) { + $classes[] = 'menu-item-privacy-policy'; + } + // if the menu item corresponds to a taxonomy term for the currently-queried non-hierarchical post object if ( $wp_query->is_singular && 'taxonomy' == $menu_item->type && in_array( $menu_item->object_id, $possible_object_parents ) ) { $active_parent_object_ids[] = (int) $menu_item->object_id; diff --git a/src/wp-includes/post-template.php b/src/wp-includes/post-template.php index 2aad0a03e0..b817edec4f 100644 --- a/src/wp-includes/post-template.php +++ b/src/wp-includes/post-template.php @@ -621,6 +621,9 @@ function get_body_class( $class = '' ) { if ( is_home() ) { $classes[] = 'blog'; } + if ( is_privacy_policy() ) { + $classes[] = 'privacy-policy'; + } if ( is_archive() ) { $classes[] = 'archive'; } diff --git a/src/wp-includes/query.php b/src/wp-includes/query.php index 98f1934b19..a2c7d19684 100644 --- a/src/wp-includes/query.php +++ b/src/wp-includes/query.php @@ -489,6 +489,36 @@ function is_home() { return $wp_query->is_home(); } +/** + * Determines whether the query is for the Privacy Policy page. + * + * The Privacy Policy page is the page that shows the Privacy Policy content of the site. + * + * is_privacy_policy() is dependent on the site's "Change your Privacy Policy page" Privacy Settings 'wp_page_for_privacy_policy'. + * + * This function will return true only on the page you set as the "Privacy Policy page". + * + * For more information on this and similar theme functions, check out + * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ + * Conditional Tags} article in the Theme Developer Handbook. + * + * @since 5.2.0 + * + * @global WP_Query $wp_query Global WP_Query instance. + * + * @return bool + */ +function is_privacy_policy() { + global $wp_query; + + if ( ! isset( $wp_query ) ) { + _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); + return false; + } + + return $wp_query->is_privacy_policy(); +} + /** * Determines whether the query is for an existing month archive. * diff --git a/src/wp-includes/template-loader.php b/src/wp-includes/template-loader.php index 0879798f55..7e627c508b 100644 --- a/src/wp-includes/template-loader.php +++ b/src/wp-includes/template-loader.php @@ -51,6 +51,7 @@ if ( wp_using_themes() ) : elseif ( is_search() && $template = get_search_template() ) : elseif ( is_front_page() && $template = get_front_page_template() ) : elseif ( is_home() && $template = get_home_template() ) : + elseif ( is_privacy_policy() && $template = get_privacy_policy_template() ) : elseif ( is_post_type_archive() && $template = get_post_type_archive_template() ) : elseif ( is_tax() && $template = get_taxonomy_template() ) : elseif ( is_attachment() && $template = get_attachment_template() ) : diff --git a/src/wp-includes/template.php b/src/wp-includes/template.php index 862b2ccbdf..67db6dd610 100644 --- a/src/wp-includes/template.php +++ b/src/wp-includes/template.php @@ -33,7 +33,7 @@ function get_query_template( $type, $templates = array() ) { * The last element in the array should always be the fallback template for this query type. * * Possible values for `$type` include: 'index', '404', 'archive', 'author', 'category', 'tag', 'taxonomy', 'date', - * 'embed', 'home', 'frontpage', 'page', 'paged', 'search', 'single', 'singular', and 'attachment'. + * 'embed', 'home', 'frontpage', 'privacypolicy', 'page', 'paged', 'search', 'single', 'singular', and 'attachment'. * * @since 4.7.0 * @@ -51,7 +51,7 @@ function get_query_template( $type, $templates = array() ) { * This hook also applies to various types of files loaded as part of the Template Hierarchy. * * Possible values for `$type` include: 'index', '404', 'archive', 'author', 'category', 'tag', 'taxonomy', 'date', - * 'embed', 'home', 'frontpage', 'page', 'paged', 'search', 'single', 'singular', and 'attachment'. + * 'embed', 'home', 'frontpage', 'privacypolicy', 'page', 'paged', 'search', 'single', 'singular', and 'attachment'. * * @since 1.5.0 * @since 4.8.0 The `$type` and `$templates` parameters were added. @@ -376,6 +376,24 @@ function get_front_page_template() { return get_query_template( 'front_page', $templates ); } +/** + * Retrieve path of Privacy Policy page template in current or parent template. + * + * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'} + * and {@see '$type_template'} dynamic hooks, where `$type` is 'privacypolicy'. + * + * @since 5.2.0 + * + * @see get_query_template() + * + * @return string Full path to front page template file. + */ +function get_privacy_policy_template() { + $templates = array( 'privacy-policy.php' ); + + return get_query_template( 'privacy_policy', $templates ); +} + /** * Retrieve path of page template in current or parent template. * diff --git a/tests/phpunit/includes/abstract-testcase.php b/tests/phpunit/includes/abstract-testcase.php index 76eca84958..69c86bc3e3 100644 --- a/tests/phpunit/includes/abstract-testcase.php +++ b/tests/phpunit/includes/abstract-testcase.php @@ -926,6 +926,7 @@ abstract class WP_UnitTestCase_Base extends PHPUnit_Framework_TestCase { 'is_feed', 'is_front_page', 'is_home', + 'is_privacy_policy', 'is_month', 'is_page', 'is_paged', diff --git a/tests/phpunit/tests/post/getBodyClass.php b/tests/phpunit/tests/post/getBodyClass.php index 5b0ade1bff..9c8ce670e6 100644 --- a/tests/phpunit/tests/post/getBodyClass.php +++ b/tests/phpunit/tests/post/getBodyClass.php @@ -202,4 +202,28 @@ class Tests_Post_GetBodyClass extends WP_UnitTestCase { $this->assertContains( "attachmentid-{$attachment_id}", $class ); $this->assertContains( 'attachment-jpeg', $class ); } + + /** + * @ticket 44005 + * @group privacy + */ + public function test_privacy_policy_body_class() { + $page_id = self::factory()->post->create( + array( + 'post_type' => 'page', + 'post_title' => 'Privacy Policy', + ) + ); + update_option( 'wp_page_for_privacy_policy', $page_id ); + + $this->go_to( get_permalink( $page_id ) ); + + $class = get_body_class(); + + $this->assertContains( 'privacy-policy', $class ); + $this->assertContains( 'page-template-default', $class ); + $this->assertContains( 'page', $class ); + $this->assertContains( "page-id-{$page_id}", $class ); + } + } diff --git a/tests/phpunit/tests/post/nav-menu.php b/tests/phpunit/tests/post/nav-menu.php index 9ef3f8e390..c6e86ffb3c 100644 --- a/tests/phpunit/tests/post/nav-menu.php +++ b/tests/phpunit/tests/post/nav-menu.php @@ -861,4 +861,69 @@ class Test_Nav_Menus extends WP_UnitTestCase { } } + /** + * @ticket 44005 + * @group privacy + */ + function test_no_privacy_policy_class_applied() { + $page_id = self::factory()->post->create( + array( + 'post_type' => 'page', + 'post_title' => 'Privacy Policy Page', + ) + ); + + wp_update_nav_menu_item( + $this->menu_id, + 0, + array( + 'menu-item-type' => 'post_type', + 'menu-item-object' => 'page', + 'menu-item-object-id' => $page_id, + 'menu-item-status' => 'publish', + ) + ); + + $menu_items = wp_get_nav_menu_items( $this->menu_id ); + _wp_menu_item_classes_by_context( $menu_items ); + + $classes = $menu_items[0]->classes; + + $this->assertNotContains( 'menu-item-privacy-policy', $classes ); + } + + /** + * @ticket 44005 + * @group privacy + */ + function test_class_applied_to_privacy_policy_page_item() { + $page_id = self::factory()->post->create( + array( + 'post_type' => 'page', + 'post_title' => 'Privacy Policy Page', + ) + ); + update_option( 'wp_page_for_privacy_policy', $page_id ); + + wp_update_nav_menu_item( + $this->menu_id, + 0, + array( + 'menu-item-type' => 'post_type', + 'menu-item-object' => 'page', + 'menu-item-object-id' => $page_id, + 'menu-item-status' => 'publish', + ) + ); + + $menu_items = wp_get_nav_menu_items( $this->menu_id ); + _wp_menu_item_classes_by_context( $menu_items ); + + $classes = $menu_items[0]->classes; + + delete_option( 'wp_page_for_privacy_policy' ); + + $this->assertContains( 'menu-item-privacy-policy', $classes ); + } + } diff --git a/tests/phpunit/tests/query/conditionals.php b/tests/phpunit/tests/query/conditionals.php index 6be39befed..c3483e1d26 100644 --- a/tests/phpunit/tests/query/conditionals.php +++ b/tests/phpunit/tests/query/conditionals.php @@ -1590,4 +1590,24 @@ class Tests_Query_Conditionals extends WP_UnitTestCase { $this->assertTrue( is_single( $p2 ) ); $this->assertFalse( is_single( $p1 ) ); } + + /** + * @ticket 44005 + * @group privacy + */ + public function test_is_privacy_policy() { + $page_id = self::factory()->post->create( + array( + 'post_type' => 'page', + 'post_title' => 'Privacy Policy', + ) + ); + + update_option( 'wp_page_for_privacy_policy', $page_id ); + + $this->go_to( get_permalink( $page_id ) ); + + $this->assertQueryTrue( 'is_page', 'is_singular', 'is_privacy_policy' ); + } + } diff --git a/tests/phpunit/tests/template.php b/tests/phpunit/tests/template.php index 3a0b66b752..9e6e5a1ffa 100644 --- a/tests/phpunit/tests/template.php +++ b/tests/phpunit/tests/template.php @@ -13,6 +13,15 @@ class Tests_Template extends WP_UnitTestCase { protected static $page; protected static $post; + /** + * Page For Privacy Policy. + * + * @since 5.2.0 + * + * @var WP_Post $page_for_privacy_policy + */ + protected static $page_for_privacy_policy; + public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { self::$page_on_front = $factory->post->create_and_get( array( @@ -45,6 +54,13 @@ class Tests_Template extends WP_UnitTestCase { ); set_post_format( self::$post, 'quote' ); add_post_meta( self::$post->ID, '_wp_page_template', 'templates/post.php' ); + + self::$page_for_privacy_policy = $factory->post->create_and_get( + array( + 'post_type' => 'page', + 'post_title' => 'Privacy Policy', + ) + ); } public function setUp() { @@ -272,6 +288,25 @@ class Tests_Template extends WP_UnitTestCase { ); } + /** + * @ticket 44005 + * @group privacy + */ + public function test_privacy_template_hierarchy() { + update_option( 'wp_page_for_privacy_policy', self::$page_for_privacy_policy->ID ); + + $this->assertTemplateHierarchy( + get_permalink( self::$page_for_privacy_policy->ID ), + array( + 'privacy-policy.php', + 'page-privacy-policy.php', + 'page-' . self::$page_for_privacy_policy->ID . '.php', + 'page.php', + 'singular.php', + ) + ); + } + /** * @ticket 18375 */ @@ -436,6 +471,7 @@ class Tests_Template extends WP_UnitTestCase { 'search' => 'is_search', 'front_page' => 'is_front_page', 'home' => 'is_home', + 'privacy_policy' => 'is_privacy_policy', 'post_type_archive' => 'is_post_type_archive', 'taxonomy' => 'is_tax', 'attachment' => 'is_attachment', diff --git a/tests/phpunit/tests/theme.php b/tests/phpunit/tests/theme.php index 7e2ea89efc..bf3ec670e5 100644 --- a/tests/phpunit/tests/theme.php +++ b/tests/phpunit/tests/theme.php @@ -288,6 +288,7 @@ class Tests_Theme extends WP_UnitTestCase { $this->assertEquals( get_category_template(), get_query_template( 'category' ) ); $this->assertEquals( get_date_template(), get_query_template( 'date' ) ); $this->assertEquals( get_home_template(), get_query_template( 'home', array( 'home.php', 'index.php' ) ) ); + $this->assertEquals( get_privacy_policy_template(), get_query_template( 'privacy_policy', array( 'privacy-policy.php' ) ) ); $this->assertEquals( get_page_template(), get_query_template( 'page' ) ); $this->assertEquals( get_search_template(), get_query_template( 'search' ) ); $this->assertEquals( get_single_template(), get_query_template( 'single' ) ); diff --git a/tests/phpunit/tests/url/getPrivacyPolicyUrl.php b/tests/phpunit/tests/url/getPrivacyPolicyUrl.php index b6d6a23ba3..69384702da 100644 --- a/tests/phpunit/tests/url/getPrivacyPolicyUrl.php +++ b/tests/phpunit/tests/url/getPrivacyPolicyUrl.php @@ -45,8 +45,6 @@ class Tests_Url_GetPrivacyPolicyUrl extends WP_UnitTestCase { 'post_title' => WP_TESTS_DOMAIN . ' Privacy Policy', ) ); - - self::$privacy_policy_url = get_permalink( self::$privacy_policy_page_id ); } /** @@ -60,9 +58,10 @@ class Tests_Url_GetPrivacyPolicyUrl extends WP_UnitTestCase { * The function should return the privacy policy URL when `wp_page_for_privacy_policy` is set. */ public function test_get_privacy_policy_url_should_return_valid_url_when_policy_page_set() { + $privacy_policy_url = get_permalink( self::$privacy_policy_page_id ); update_option( 'wp_page_for_privacy_policy', self::$privacy_policy_page_id ); - $this->assertSame( self::$privacy_policy_url, get_privacy_policy_url() ); + $this->assertSame( $privacy_policy_url, get_privacy_policy_url() ); } /**