Privacy: Add rel="privacy-policy" to the Privacy Policy link.

This changeset adds a `rel="privacy-policy"` attribute to user-facing links to the Privacy Policy of the website, when a privacy policy page is set and available. While this `rel` value is still a RFC of the Link Types HTML specification, this changeset helps to make Privacy Policy link more discoverable for user agents and HTML parsers. 

Props dshanske, audrasjb, bhavz-10, bookwyrm, faisal03, JeffPaul, peterwilsoncc, paapst, davidbaumwald, costdev, robinwpdeveloper, kawserz.
Fixes #56345.


git-svn-id: https://develop.svn.wordpress.org/trunk@55261 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Jb Audras 2023-02-07 14:03:26 +00:00
parent 4c535ee6d5
commit 3ba96e225d
4 changed files with 236 additions and 2 deletions

View File

@ -182,7 +182,17 @@ class Walker_Nav_Menu extends Walker {
} else {
$atts['rel'] = $menu_item->xfn;
}
$atts['href'] = ! empty( $menu_item->url ) ? $menu_item->url : '';
if ( ! empty( $menu_item->url ) ) {
if ( get_privacy_policy_url() === $menu_item->url ) {
$atts['rel'] = empty( $atts['rel'] ) ? 'privacy-policy' : $atts['rel'] . ' privacy-policy';
}
$atts['href'] = $menu_item->url;
} else {
$atts['href'] = '';
}
$atts['aria-current'] = $menu_item->current ? 'page' : '';
/**

View File

@ -4664,7 +4664,7 @@ function get_the_privacy_policy_link( $before = '', $after = '' ) {
if ( $privacy_policy_url && $page_title ) {
$link = sprintf(
'<a class="privacy-policy-link" href="%s">%s</a>',
'<a class="privacy-policy-link" href="%s" rel="privacy-policy">%s</a>',
esc_url( $privacy_policy_url ),
esc_html( $page_title )
);

View File

@ -160,4 +160,15 @@ class Tests_Link_GetThePrivacyPolicyLink extends WP_UnitTestCase {
public static function modify_link_markup( $link, $privacy_policy_url ) {
return 'Policy: ' . $privacy_policy_url;
}
/**
* Tests that `get_the_privacy_policy_link()` adds `rel="privacy-policy"`.
*
* @ticket 56345
*/
public function test_get_the_privacy_policy_link_should_add_rel_privacy_policy() {
update_option( 'wp_page_for_privacy_policy', self::$privacy_policy_page_id );
$this->assertStringContainsString( 'rel="privacy-policy"', get_the_privacy_policy_link() );
}
}

View File

@ -152,4 +152,217 @@ class Tests_Menu_Walker_Nav_Menu extends WP_UnitTestCase {
),
);
}
/**
* Tests that `Walker_Nav_Menu::start_el()` adds `rel="privacy-policy"`.
*
* @ticket 56345
*
* @covers Walker_Nav_Menu::start_el
*
* @dataProvider data_walker_nav_menu_start_el_should_add_rel_privacy_policy_to_privacy_policy_url
*
* @param string $expected The expected substring containing the "rel" attribute and value.
* @param string $xfn Optional. The XFN value. Default empty string.
* @param string $target Optional. The target value. Default empty string.
*/
public function test_walker_nav_menu_start_el_should_add_rel_privacy_policy_to_privacy_policy_url( $expected, $xfn = '', $target = '' ) {
$post_id = self::factory()->post->create(
array(
'post_type' => 'page',
'post_title' => 'Test Privacy Policy',
'post_status' => 'publish',
)
);
// Set the privacy policy page.
update_option( 'wp_page_for_privacy_policy', $post_id );
$privacy_policy_id = (int) get_option( 'wp_page_for_privacy_policy' );
$output = '';
$item = array(
'ID' => $privacy_policy_id,
'object_id' => $privacy_policy_id,
'title' => 'Privacy Policy',
'target' => $target,
'xfn' => $xfn,
'current' => false,
'url' => get_privacy_policy_url(),
);
$args = array(
'before' => '',
'after' => '',
'link_before' => '',
'link_after' => '',
);
$this->walker->start_el( $output, (object) $item, 0, (object) $args );
$this->assertStringContainsString( $expected, $output );
}
/**
* Data provider.
*
* @return array[]
*/
public function data_walker_nav_menu_start_el_should_add_rel_privacy_policy_to_privacy_policy_url() {
return array(
'no xfn value' => array(
'expected' => 'rel="privacy-policy"',
),
'an xfn value' => array(
'expected' => 'rel="nofollow privacy-policy"',
'xfn' => 'nofollow',
),
'no xfn value and a target of "_blank"' => array(
'expected' => 'rel="noopener privacy-policy"',
'xfn' => '',
'target' => '_blank',
),
'an xfn value and a target of "_blank"' => array(
'expected' => 'rel="nofollow privacy-policy"',
'xfn' => 'nofollow',
'target' => '_blank',
),
);
}
/**
* Tests that `Walker_Nav_Menu::start_el()` does not add `rel="privacy-policy"` when no
* privacy policy page exists.
*
* @ticket 56345
*
* @covers Walker_Nav_Menu::start_el
*/
public function test_walker_nav_menu_start_el_should_not_add_rel_privacy_policy_when_no_privacy_policy_exists() {
$post_id = self::factory()->post->create(
array(
'post_type' => 'page',
'post_title' => 'Test Privacy Policy',
'post_status' => 'publish',
)
);
// Do not set the privacy policy page.
$output = '';
$item = array(
'ID' => $post_id,
'object_id' => $post_id,
'title' => 'Privacy Policy',
'target' => '',
'xfn' => '',
'current' => false,
'url' => get_the_permalink( $post_id ),
);
$args = array(
'before' => '',
'after' => '',
'link_before' => '',
'link_after' => '',
);
$this->walker->start_el( $output, (object) $item, 0, (object) $args );
$this->assertStringNotContainsString( 'rel="privacy-policy"', $output );
}
/**
* Tests that `Walker_Nav_Menu::start_el()` does not add `rel="privacy-policy"` when no URL
* is passed in the menu item object.
*
* @ticket 56345
*
* @covers Walker_Nav_Menu::start_el
*/
public function test_walker_nav_menu_start_el_should_not_add_rel_privacy_policy_when_no_url_is_passed() {
$post_id = self::factory()->post->create(
array(
'post_type' => 'page',
'post_title' => 'Test Privacy Policy',
'post_status' => 'publish',
)
);
// Set the privacy policy page.
update_option( 'wp_page_for_privacy_policy', $post_id );
$privacy_policy_id = (int) get_option( 'wp_page_for_privacy_policy' );
$output = '';
$item = array(
'ID' => $privacy_policy_id,
'object_id' => $privacy_policy_id,
'title' => 'Privacy Policy',
'target' => '',
'xfn' => '',
'current' => false,
// Do not pass URL.
);
$args = array(
'before' => '',
'after' => '',
'link_before' => '',
'link_after' => '',
);
$this->walker->start_el( $output, (object) $item, 0, (object) $args );
$this->assertStringNotContainsString( 'rel="privacy-policy"', $output );
}
/**
* Tests that `Walker_Nav_Menu::start_el()` does not add `rel="privacy-policy"` when the
* menu item's ID does not match the privacy policy page, but the URL does.
*
* @ticket 56345
*
* @covers Walker_Nav_Menu::start_el
*/
public function test_walker_nav_menu_start_el_should_add_rel_privacy_policy_when_id_does_not_match_but_url_does() {
$post_id = self::factory()->post->create(
array(
'post_type' => 'page',
'post_title' => 'Test Privacy Policy',
'post_status' => 'publish',
)
);
// Set the privacy policy page.
update_option( 'wp_page_for_privacy_policy', $post_id );
$privacy_policy_id = (int) get_option( 'wp_page_for_privacy_policy' );
$output = '';
// Ensure the ID does not match the privacy policy.
$not_privacy_policy_id = $privacy_policy_id - 1;
$item = array(
'ID' => $not_privacy_policy_id,
'object_id' => $not_privacy_policy_id,
'title' => 'Privacy Policy',
'target' => '',
'xfn' => '',
'current' => false,
'url' => get_privacy_policy_url(),
);
$args = array(
'before' => '',
'after' => '',
'link_before' => '',
'link_after' => '',
);
$this->walker->start_el( $output, (object) $item, 0, (object) $args );
$this->assertStringContainsString( 'rel="privacy-policy"', $output );
}
}