<?php
namespace Automattic\Gravatar\GravatarEnhanced\QuickEditor;
use Automattic\Gravatar\GravatarEnhanced\Module;
use Automattic\Gravatar\GravatarEnhanced\Shared\HovercardsI18n;
use WP_User;
class QuickEditor implements Module {
private const SECTION_ABOUT = 'about';
private const SECTION_NAME = 'name';
private const SECTION_CONTACT = 'contact';
private const SECTION_BEFORE = 'before';
private const SECTION_AFTER = 'after';
/**
* @return void
*/
public function init() {
add_action( 'admin_init', [ $this, 'admin_init' ] );
}
/**
* Main admin_init function used to hook into and register stuff and init plugin settings.
*
* @return void
*/
public function admin_init() {
add_action( 'admin_head-profile.php', [ $this, 'start_capture_page' ] );
add_action( 'admin_footer-profile.php', [ $this, 'end_capture_page' ] );
add_action( 'admin_head-user-edit.php', [ $this, 'start_capture_page' ] );
add_action( 'admin_footer-user-edit.php', [ $this, 'end_capture_page' ] );
add_filter( 'get_avatar_url', [ $this, 'get_avatar_url' ], 15 );
add_filter( 'user_profile_picture_description', [ $this, 'user_profile_picture_description' ] );
}
/**
* @param string $description
* @return string
*/
public function user_profile_picture_description( $description ) {
return sprintf(
/* translators: URL */
__( 'Gravatar powers your profile image - a globally recognized avatar. <a href="%s">Edit your Gravatar</a>.', 'gravatar-enhanced' ),
'https://gravatar.com/profile/avatars'
);
}
/**
* @return void
*/
public function start_capture_page() {
$this->add_quick_editor();
ob_start();
}
/**
* Do all of the bad stuff
*
* @return void
*/
public function end_capture_page() {
$profile_page = ob_get_contents();
ob_end_clean();
if ( $profile_page === false ) {
return;
}
$sections = $this->grab_sections( $profile_page );
if ( $sections === false ) {
// Leave page alone
echo $profile_page;
return;
}
$sections[ self::SECTION_NAME ] = $this->modify_name_section( $sections[ self::SECTION_NAME ] );
$new_order = [
'user-profile-picture',
'user-verified-services',
'user-user-login-wrap',
'user-first-name-wrap',
'user-last-name-wrap',
'user-nickname-wrap',
'user-display-name-wrap',
'user-description-wrap',
'user-gravatar-card',
];
$about_yourself = $this->merge_about_and_name( $sections[ self::SECTION_ABOUT ], $sections[ self::SECTION_NAME ] );
$about_yourself = $this->insert_row( $about_yourself, $this->get_verified_services_section() );
$about_yourself = $this->insert_row( $about_yourself, $this->get_gravatar_card_section() );
$about_yourself = $this->reorder_section( $about_yourself, $new_order );
// Now form the page back
echo implode(
'',
[
$sections[ self::SECTION_BEFORE ],
$about_yourself,
$sections[ self::SECTION_CONTACT ],
$sections[ self::SECTION_AFTER ],
]
);
}
/**
* @param string $text
* @param string $row
* @return string
*/
private function insert_row( $text, $row ) {
return (string) preg_replace( '@</table>$@s', $row . '</table>', $text, 1 );
}
/**
* @return string
*/
private function get_verified_services_section() {
$verified_services = esc_html( __( 'Verified Services', 'gravatar-enhanced' ) );
$description = sprintf(
/* translators: URL */
__( 'Let people know where they can find you online. <a href="%s">Edit your verified accounts.</a>', 'gravatar-enhanced' ),
'https://gravatar.com/profile/verified-accounts'
);
return <<<HTML
<tr class="user-verified-services">
<th>$verified_services</th>
<td>
<div id="gravatar-verified-services" class="gravatar-profile__loading"></div>
<p class="description">$description</p>
</td>
</tr>
HTML;
}
/**
* @return string
*/
private function get_gravatar_card_section() {
$current_user = $this->get_user();
if ( ! $current_user ) {
return '';
}
$title = esc_html( __( 'Gravatar Card', 'gravatar-enhanced' ) );
$description = __( 'Your Gravatar card is shown in comments and profile blocks. Gravatar profiles travel with you across millions of sites, showing your photo, bio, and links - your digital business card.', 'gravatar-enhanced' );
$edit = esc_html( __( 'Edit your Gravatar card', 'gravatar-enhanced' ) );
$avatar_url = get_avatar_url( $current_user->ID );
$alt = esc_attr( $current_user->display_name );
return <<<HTML
<tr class="user-gravatar-card">
<th>$title</th>
<td>
<div class="gravatar-hovercard-container">
<div class="gravatar-hovercard gravatar-profile__loading">
<div class="gravatar-hovercard">
<div class="gravatar-hovercard__inner">
<div class="gravatar-hovercard__header">
<img class="gravatar-hovercard__avatar" src="$avatar_url" width="104" height="104" alt="$alt" />
<h4 class="gravatar-hovercard__name"></h4>
</div>
<div class="gravatar-hovercard__body">
<p class="gravatar-hovercard__description"></p>
</div>
<div class="gravatar-hovercard__footer">
<div class="gravatar-hovercard__social-links">
</div>
</div>
</div>
</div>
</div>
</div>
<p class="description">$description</p>
<p><button type="button" class="button button-secondary">$edit</button></p>
</td>
</tr>
HTML;
}
/**
* Reorder table rows
* @param string $section
* @param string[] $order
* @return string
*/
private function reorder_section( $section, $order ) {
// Split into rows
if ( preg_match_all( '@<tr class="(.*?)">(.*?)</tr>@s', $section, $matches ) > 0 ) {
$new_section = '';
foreach ( $order as $class_name ) {
foreach ( $matches[1] as $pos => $section_class ) {
if ( $class_name === $section_class ) {
$content = $matches[2][ $pos ];
$new_section .= "<tr class=\"$section_class\">$content</tr>";
break;
}
}
}
return (string) preg_replace( '@<tr.*</tr>@s', $new_section, $section );
}
return $section;
}
/**
* @param string $about
* @param string $name
* @return string
*/
private function merge_about_and_name( $about, $name ) {
return (string) preg_replace( '@</table>\s*<table.*?>@s', '', $about . $name );
}
/**
* @param string $name_section
* @return string
*/
private function modify_name_section( $name_section ) {
return str_replace( '<h2>' . __( 'Name' ) . '</h2>', '', $name_section );
}
/**
* @param string $profile_page
* @return array{'about': string, 'name': string, 'contact': string, 'before': string, 'after': string}|false
*/
private function grab_sections( $profile_page ) {
$about_yourself_title = preg_quote( __( 'About Yourself' ), '@' );
$name_title = preg_quote( __( 'Name' ), '@' );
$contact_info_title = preg_quote( __( 'Contact Info' ), '@' );
$content = [
self::SECTION_ABOUT => '',
self::SECTION_NAME => '',
self::SECTION_CONTACT => '',
self::SECTION_BEFORE => '',
self::SECTION_AFTER => '',
];
$sections = [
self::SECTION_ABOUT => "@<h2>$about_yourself_title</h2>(.*?)</table>@s",
self::SECTION_NAME => "@<h2>$name_title</h2>(.*?)</table>@s",
self::SECTION_CONTACT => "@<h2>$contact_info_title</h2>(.*?)</table>@s",
self::SECTION_BEFORE => '@^(.*?<form.*?(?=<h2>))@s',
];
// Grab section content into $content
foreach ( $sections as $title => $regex ) {
if ( preg_match( $regex, $profile_page, $matches ) === 0 || ! isset( $matches[0] ) ) {
return false;
}
$content[ $title ] = $matches[0];
}
// Now remove the sections
foreach ( $sections as $title => $regex ) {
$profile_page = (string) preg_replace( $regex, '', $profile_page, 1 );
}
// And add the rest of the content
$content[ self::SECTION_AFTER ] = $profile_page;
return $content;
}
/**
* Add a cache busting parameter to the Gravatar URL on the profile page. This ensures it is always up to date.
*
* @param string $url
* @return string
*/
public function get_avatar_url( $url ) {
return add_query_arg( 't', time(), $url );
}
/**
* Initialise editor, if enabled.
*
* @return void
*/
public function add_quick_editor() {
$current_user = $this->get_user();
if ( ! $current_user ) {
return;
}
$current_user_email = strtolower( $current_user->user_email );
$current_user_locale = $this->get_gravatar_locale( get_user_locale( $current_user ) );
$settings = [
'email' => $current_user_email,
'locale' => $current_user_locale,
'hash' => hash( 'sha256', $current_user_email ),
'avatar' => get_avatar_url( $current_user_email ),
'canEdit' => defined( 'IS_PROFILE_PAGE' ) && IS_PROFILE_PAGE ? true : false,
'text' => [
'createButton' => __( 'Claim your free profile', 'gravatar-enhanced' ),
'updateButton' => __( 'Edit profile', 'gravatar-enhanced' ),
'viewButton' => __( 'View profile', 'gravatar-enhanced' ),
'errorTitle' => __( 'Profile failed', 'gravatar-enhanced' ),
'errorDescription' => __( 'There was an error loading this profile. Please try again later.', 'gravatar-enhanced' ),
'unknownTitle' => __( 'Your name', 'gravatar-enhanced' ),
'unknownDescription' => __( 'This site uses Gravatar for managing avatars and profiles.', 'gravatar-enhanced' ),
'otherUnknownTitle' => __( 'Profile name', 'gravatar-enhanced' ),
'otherUnknownDescription' => __( 'This site uses Gravatar for managing avatars and profiles.', 'gravatar-enhanced' ),
],
'hovercardsI18n' => HovercardsI18n::get_translations(),
];
$asset_file = dirname( GRAVATAR_ENHANCED_PLUGIN_FILE ) . '/build/quick-editor.asset.php';
$assets = file_exists( $asset_file ) ? require $asset_file : [ 'dependencies' => [], 'version' => time() ];
wp_enqueue_script( 'gravatar-enhanced-qe', plugins_url( 'build/quick-editor.js', GRAVATAR_ENHANCED_PLUGIN_FILE ), $assets['dependencies'], $assets['version'], true );
wp_localize_script( 'gravatar-enhanced-qe', 'geQuickEditor', $settings );
wp_register_style( 'gravatar-enhanced-qe', plugins_url( 'build/style-quick-editor.css', GRAVATAR_ENHANCED_PLUGIN_FILE ), [], $assets['version'] );
wp_enqueue_style( 'gravatar-enhanced-qe' );
// We always want hovercards loaded on the profile page
$asset_file = dirname( GRAVATAR_ENHANCED_PLUGIN_FILE ) . '/build/hovercards.asset.php';
$assets = file_exists( $asset_file ) ? require $asset_file : [ 'dependencies' => [], 'version' => time() ];
wp_enqueue_script( 'gravatar-enhanced-hovercards', plugins_url( 'build/hovercards.js', GRAVATAR_ENHANCED_PLUGIN_FILE ), $assets['dependencies'], $assets['version'], true );
wp_register_style( 'gravatar-enhanced-hovercards', plugins_url( 'build/style-hovercards.css', GRAVATAR_ENHANCED_PLUGIN_FILE ), [], $assets['version'] );
wp_enqueue_style( 'gravatar-enhanced-hovercards' );
}
/**
* Get the locale for the user.
*
* @param string $locale
* @return string
*/
private function get_gravatar_locale( $locale ) {
$current_user_locale = strtolower( $locale );
// Gravatar only wants the first part of a locale, so we strip the country code unless it's one of the exceptions
$exceptions = [
'zh_tw',
'fr_ca',
];
if ( in_array( $current_user_locale, $exceptions, true ) ) {
return str_replace( '_', '-', $current_user_locale );
}
$current_user_locale = (string) preg_replace( '/[_-].*$/', '', $current_user_locale );
$current_user_locale = str_replace( 'zh', 'cn', $current_user_locale );
$current_user_locale = str_replace( 'en', '', $current_user_locale );
return $current_user_locale;
}
/**
* @return false|WP_User
*/
private function get_user() {
$user_id = ! empty( $_GET['user_id'] ) ? absint( $_GET['user_id'] ) : wp_get_current_user()->ID;
return get_userdata( $user_id );
}
/**
* @return void
*/
public function uninstall() {}
}