modified file `plugins`

This commit is contained in:
KawaiiPunk 2023-10-22 22:21:44 +00:00 committed by Gitium
parent c72a65abc1
commit 96c0ee892f
4817 changed files with 752216 additions and 0 deletions

View File

@ -0,0 +1,38 @@
.DS_Store
.editorconfig
.git
.gitignore
.github
.travis.yml
.codeclimate.yml
.data
.svnignore
.wordpress-org
.php_cs
Gruntfile.js
LINGUAS
Makefile
README.md
readme.md
CODE_OF_CONDUCT.md
LICENSE.md
_site
_config.yml
bin
composer.json
composer.lock
docker-compose.yml
docker-compose-test.yml
Dockerfile
gulpfile.js
package.json
node_modules
npm-debug.log
phpcs.xml
package.json
package-lock.json
phpunit.xml
phpunit.xml.dist
tests
node_modules
vendor

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Matthias Pfefferle
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,141 @@
<?php
/**
* Plugin Name: ActivityPub
* Plugin URI: https://github.com/pfefferle/wordpress-activitypub/
* Description: The ActivityPub protocol is a decentralized social networking protocol based upon the ActivityStreams 2.0 data format.
* Version: 0.17.0
* Author: Matthias Pfefferle & Automattic
* Author URI: https://automattic.com/
* License: MIT
* License URI: http://opensource.org/licenses/MIT
* Requires PHP: 5.6
* Text Domain: activitypub
* Domain Path: /languages
*/
namespace Activitypub;
/**
* Initialize plugin
*/
function init() {
\defined( 'ACTIVITYPUB_EXCERPT_LENGTH' ) || \define( 'ACTIVITYPUB_EXCERPT_LENGTH', 400 );
\defined( 'ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS' ) || \define( 'ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS', 3 );
\defined( 'ACTIVITYPUB_HASHTAGS_REGEXP' ) || \define( 'ACTIVITYPUB_HASHTAGS_REGEXP', '(?:(?<=\s)|(?<=<p>)|(?<=<br>)|^)#([A-Za-z0-9_]+)(?:(?=\s|[[:punct:]]|$))' );
\defined( 'ACTIVITYPUB_USERNAME_REGEXP' ) || \define( 'ACTIVITYPUB_USERNAME_REGEXP', '(?:([A-Za-z0-9_-]+)@((?:[A-Za-z0-9_-]+\.)+[A-Za-z]+))' );
\defined( 'ACTIVITYPUB_ALLOWED_HTML' ) || \define( 'ACTIVITYPUB_ALLOWED_HTML', '<strong><a><p><ul><ol><li><code><blockquote><pre><img>' );
\defined( 'ACTIVITYPUB_CUSTOM_POST_CONTENT' ) || \define( 'ACTIVITYPUB_CUSTOM_POST_CONTENT', "<p><strong>[ap_title]</strong></p>\n\n[ap_content]\n\n<p>[ap_hashtags]</p>\n\n<p>[ap_shortlink]</p>" );
\define( 'ACTIVITYPUB_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
\define( 'ACTIVITYPUB_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
\define( 'ACTIVITYPUB_PLUGIN_FILE', plugin_dir_path( __FILE__ ) . '/' . basename( __FILE__ ) );
require_once \dirname( __FILE__ ) . '/includes/table/followers-list.php';
require_once \dirname( __FILE__ ) . '/includes/class-signature.php';
require_once \dirname( __FILE__ ) . '/includes/class-webfinger.php';
require_once \dirname( __FILE__ ) . '/includes/peer/class-followers.php';
require_once \dirname( __FILE__ ) . '/includes/functions.php';
require_once \dirname( __FILE__ ) . '/includes/model/class-activity.php';
require_once \dirname( __FILE__ ) . '/includes/model/class-post.php';
require_once \dirname( __FILE__ ) . '/includes/class-activity-dispatcher.php';
\Activitypub\Activity_Dispatcher::init();
require_once \dirname( __FILE__ ) . '/includes/class-activitypub.php';
\Activitypub\Activitypub::init();
// Configure the REST API route
require_once \dirname( __FILE__ ) . '/includes/rest/class-outbox.php';
\Activitypub\Rest\Outbox::init();
require_once \dirname( __FILE__ ) . '/includes/rest/class-inbox.php';
\Activitypub\Rest\Inbox::init();
require_once \dirname( __FILE__ ) . '/includes/rest/class-followers.php';
\Activitypub\Rest\Followers::init();
require_once \dirname( __FILE__ ) . '/includes/rest/class-following.php';
\Activitypub\Rest\Following::init();
require_once \dirname( __FILE__ ) . '/includes/rest/class-webfinger.php';
\Activitypub\Rest\Webfinger::init();
// load NodeInfo endpoints only if blog is public
if ( true === (bool) \get_option( 'blog_public', 1 ) ) {
require_once \dirname( __FILE__ ) . '/includes/rest/class-nodeinfo.php';
\Activitypub\Rest\NodeInfo::init();
}
require_once \dirname( __FILE__ ) . '/includes/class-admin.php';
\Activitypub\Admin::init();
require_once \dirname( __FILE__ ) . '/includes/class-hashtag.php';
\Activitypub\Hashtag::init();
require_once \dirname( __FILE__ ) . '/includes/class-shortcodes.php';
\Activitypub\Shortcodes::init();
require_once \dirname( __FILE__ ) . '/includes/class-mention.php';
\Activitypub\Mention::init();
require_once \dirname( __FILE__ ) . '/includes/class-debug.php';
\Activitypub\Debug::init();
require_once \dirname( __FILE__ ) . '/includes/class-health-check.php';
\Activitypub\Health_Check::init();
if ( \WP_DEBUG ) {
require_once \dirname( __FILE__ ) . '/includes/debug.php';
}
}
\add_action( 'plugins_loaded', '\Activitypub\init' );
/**
* Add plugin settings link
*/
function plugin_settings_link( $actions ) {
$settings_link[] = \sprintf(
'<a href="%1s">%2s</a>',
\menu_page_url( 'activitypub', false ),
\__( 'Settings', 'activitypub' )
);
return \array_merge( $settings_link, $actions );
}
\add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), '\Activitypub\plugin_settings_link' );
/**
* Add rewrite rules
*/
function add_rewrite_rules() {
if ( ! \class_exists( 'Webfinger' ) ) {
\add_rewrite_rule( '^.well-known/webfinger', 'index.php?rest_route=/activitypub/1.0/webfinger', 'top' );
}
if ( ! \class_exists( 'Nodeinfo' ) || ! (bool) \get_option( 'blog_public', 1 ) ) {
\add_rewrite_rule( '^.well-known/nodeinfo', 'index.php?rest_route=/activitypub/1.0/nodeinfo/discovery', 'top' );
\add_rewrite_rule( '^.well-known/x-nodeinfo2', 'index.php?rest_route=/activitypub/1.0/nodeinfo2', 'top' );
}
\add_rewrite_endpoint( 'activitypub', EP_AUTHORS | EP_PERMALINK | EP_PAGES );
}
\add_action( 'init', '\Activitypub\add_rewrite_rules', 1 );
/**
* Flush rewrite rules;
*/
function flush_rewrite_rules() {
\Activitypub\add_rewrite_rules();
\flush_rewrite_rules();
}
\register_activation_hook( __FILE__, '\Activitypub\flush_rewrite_rules' );
\register_deactivation_hook( __FILE__, '\flush_rewrite_rules' );
/**
* Only load code that needs BuddyPress to run once BP is loaded and initialized.
*/
function enable_buddypress_features() {
require_once \dirname( __FILE__ ) . '/integration/class-buddypress.php';
\Activitypub\Integration\Buddypress::init();
}
add_action( 'bp_include', '\Activitypub\enable_buddypress_features' );

View File

@ -0,0 +1,141 @@
.settings_page_activitypub .notice {
max-width: 800px;
margin: auto;
margin-top: 10px;
}
.activitypub-settings-header {
text-align: center;
margin: 0 0 1rem;
background: #fff;
border-bottom: 1px solid #dcdcde;
}
.activitypub-settings-title-section {
display: flex;
align-items: center;
justify-content: center;
clear: both;
padding-top: 8px;
}
.settings_page_activitypub #wpcontent {
padding-left: 0;
}
.activitypub-settings-tabs-wrapper {
display: -ms-inline-grid;
-ms-grid-columns: 1fr 1fr;
vertical-align: top;
display: inline-grid;
grid-template-columns: 1fr 1fr;
}
.activitypub-settings-tab.active {
box-shadow: inset 0 -3px #3582c4;
font-weight: 600;
}
.activitypub-settings-tab {
display: block;
text-decoration: none;
color: inherit;
padding: .5rem 1rem 1rem;
margin: 0 1rem;
transition: box-shadow .5s ease-in-out;
}
.wp-header-end {
visibility: hidden;
margin: -2px 0 0;
}
summary {
cursor: pointer;
text-decoration: underline;
color: #2271b1;
}
.activitypub-settings-accordion {
border: 1px solid #c3c4c7;
}
.activitypub-settings-accordion-heading {
margin: 0;
border-top: 1px solid #c3c4c7;
font-size: inherit;
line-height: inherit;
font-weight: 600;
color: inherit;
}
.activitypub-settings-accordion-heading:first-child {
border-top: none;
}
.activitypub-settings-accordion-panel {
margin: 0;
padding: 1em 1.5em;
background: #fff;
}
.activitypub-settings-accordion-trigger {
background: #fff;
border: 0;
color: #2c3338;
cursor: pointer;
display: flex;
font-weight: 400;
margin: 0;
padding: 1em 3.5em 1em 1.5em;
min-height: 46px;
position: relative;
text-align: left;
width: 100%;
align-items: center;
justify-content: space-between;
-webkit-user-select: auto;
user-select: auto;
}
.activitypub-settings-accordion-trigger {
color: #2c3338;
cursor: pointer;
font-weight: 400;
text-align: left;
}
.activitypub-settings-accordion-trigger .title {
pointer-events: none;
font-weight: 600;
flex-grow: 1;
}
.activitypub-settings-accordion-trigger .icon, .activitypub-settings-accordion-viewed .icon {
border: solid #50575e medium;
border-width: 0 2px 2px 0;
height: .5rem;
pointer-events: none;
position: absolute;
right: 1.5em;
top: 50%;
transform: translateY(-70%) rotate(45deg);
width: .5rem;
}
.activitypub-settings-accordion-trigger[aria-expanded="true"] .icon {
transform: translateY(-30%) rotate(-135deg);
}
.activitypub-settings-accordion-trigger:active, .activitypub-settings-accordion-trigger:hover {
background: #f6f7f7;
}
.activitypub-settings-accordion-trigger:focus {
color: #1d2327;
border: none;
box-shadow: none;
outline-offset: -1px;
outline: 2px solid #2271b1;
background-color: #f6f7f7;
}

View File

@ -0,0 +1,20 @@
jQuery( function( $ ) {
// Accordion handling in various areas.
$( '.activitypub-settings-accordion' ).on( 'click', '.activitypub-settings-accordion-trigger', function() {
var isExpanded = ( 'true' === $( this ).attr( 'aria-expanded' ) );
if ( isExpanded ) {
$( this ).attr( 'aria-expanded', 'false' );
$( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', true );
} else {
$( this ).attr( 'aria-expanded', 'true' );
$( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', false );
}
} );
$(document).on( 'wp-plugin-install-success', function( event, response ) {
setTimeout( function() {
$( '.activate-now' ).removeClass( 'thickbox open-plugin-details-modal' );
}, 1200 );
} );
} );

View File

@ -0,0 +1,99 @@
<?php
namespace Activitypub;
/**
* ActivityPub Activity_Dispatcher Class
*
* @author Matthias Pfefferle
*
* @see https://www.w3.org/TR/activitypub/
*/
class Activity_Dispatcher {
/**
* Initialize the class, registering WordPress hooks.
*/
public static function init() {
\add_action( 'activitypub_send_post_activity', array( '\Activitypub\Activity_Dispatcher', 'send_post_activity' ) );
\add_action( 'activitypub_send_update_activity', array( '\Activitypub\Activity_Dispatcher', 'send_update_activity' ) );
\add_action( 'activitypub_send_delete_activity', array( '\Activitypub\Activity_Dispatcher', 'send_delete_activity' ) );
}
/**
* Send "create" activities.
*
* @param \Activitypub\Model\Post $activitypub_post
*/
public static function send_post_activity( Model\Post $activitypub_post ) {
// get latest version of post
$user_id = $activitypub_post->get_post_author();
$activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_FULL );
$activitypub_activity->from_post( $activitypub_post );
$inboxes = \Activitypub\get_follower_inboxes( $user_id );
$followers_url = \get_rest_url( null, '/activitypub/1.0/users/' . intval( $user_id ) . '/followers' );
foreach ( $activitypub_activity->get_cc() as $cc ) {
if ( $cc === $followers_url ) {
continue;
}
$inbox = \Activitypub\get_inbox_by_actor( $cc );
if ( ! $inbox || \is_wp_error( $inbox ) ) {
continue;
}
// init array if empty
if ( ! isset( $inboxes[ $inbox ] ) ) {
$inboxes[ $inbox ] = array();
}
$inboxes[ $inbox ][] = $cc;
}
foreach ( $inboxes as $inbox => $to ) {
$to = array_values( array_unique( $to ) );
$activitypub_activity->set_to( $to );
$activity = $activitypub_activity->to_json();
\Activitypub\safe_remote_post( $inbox, $activity, $user_id );
}
}
/**
* Send "update" activities.
*
* @param \Activitypub\Model\Post $activitypub_post
*/
public static function send_update_activity( $activitypub_post ) {
// get latest version of post
$user_id = $activitypub_post->get_post_author();
$activitypub_activity = new \Activitypub\Model\Activity( 'Update', \Activitypub\Model\Activity::TYPE_FULL );
$activitypub_activity->from_post( $activitypub_post );
foreach ( \Activitypub\get_follower_inboxes( $user_id ) as $inbox => $to ) {
$activitypub_activity->set_to( $to );
$activity = $activitypub_activity->to_json(); // phpcs:ignore
\Activitypub\safe_remote_post( $inbox, $activity, $user_id );
}
}
/**
* Send "delete" activities.
*
* @param \Activitypub\Model\Post $activitypub_post
*/
public static function send_delete_activity( $activitypub_post ) {
// get latest version of post
$user_id = $activitypub_post->get_post_author();
$activitypub_activity = new \Activitypub\Model\Activity( 'Delete', \Activitypub\Model\Activity::TYPE_FULL );
$activitypub_activity->from_post( $activitypub_post );
foreach ( \Activitypub\get_follower_inboxes( $user_id ) as $inbox => $to ) {
$activitypub_activity->set_to( $to );
$activity = $activitypub_activity->to_json(); // phpcs:ignore
\Activitypub\safe_remote_post( $inbox, $activity, $user_id );
}
}
}

View File

@ -0,0 +1,204 @@
<?php
namespace Activitypub;
/**
* ActivityPub Class
*
* @author Matthias Pfefferle
*/
class Activitypub {
/**
* Initialize the class, registering WordPress hooks.
*/
public static function init() {
\add_filter( 'template_include', array( '\Activitypub\Activitypub', 'render_json_template' ), 99 );
\add_filter( 'query_vars', array( '\Activitypub\Activitypub', 'add_query_vars' ) );
\add_filter( 'pre_get_avatar_data', array( '\Activitypub\Activitypub', 'pre_get_avatar_data' ), 11, 2 );
// Add support for ActivityPub to custom post types
$post_types = \get_option( 'activitypub_support_post_types', array( 'post', 'page' ) ) ? \get_option( 'activitypub_support_post_types', array( 'post', 'page' ) ) : array();
foreach ( $post_types as $post_type ) {
\add_post_type_support( $post_type, 'activitypub' );
}
\add_action( 'transition_post_status', array( '\Activitypub\Activitypub', 'schedule_post_activity' ), 33, 3 );
\add_action( 'wp_trash_post', array( '\Activitypub\Activitypub', 'trash_post' ), 1 );
\add_action( 'untrash_post', array( '\Activitypub\Activitypub', 'untrash_post' ), 1 );
}
/**
* Return a AS2 JSON version of an author, post or page.
*
* @param string $template The path to the template object.
*
* @return string The new path to the JSON template.
*/
public static function render_json_template( $template ) {
if ( ! \is_author() && ! \is_singular() && ! \is_home() ) {
return $template;
}
// check if user can publish posts
if ( \is_author() && ! user_can( \get_the_author_meta( 'ID' ), 'publish_posts' ) ) {
return $template;
}
if ( \is_author() ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/author-json.php';
} elseif ( \is_singular() ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/post-json.php';
} elseif ( \is_home() ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/blog-json.php';
}
global $wp_query;
if ( isset( $wp_query->query_vars['activitypub'] ) ) {
return $json_template;
}
if ( ! isset( $_SERVER['HTTP_ACCEPT'] ) ) {
return $template;
}
$accept_header = $_SERVER['HTTP_ACCEPT'];
if (
\stristr( $accept_header, 'application/activity+json' ) ||
\stristr( $accept_header, 'application/ld+json' )
) {
return $json_template;
}
// Accept header as an array.
$accept = \explode( ',', \trim( $accept_header ) );
if (
\in_array( 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"', $accept, true ) ||
\in_array( 'application/activity+json', $accept, true ) ||
\in_array( 'application/ld+json', $accept, true ) ||
\in_array( 'application/json', $accept, true )
) {
return $json_template;
}
return $template;
}
/**
* Add the 'activitypub' query variable so WordPress won't mangle it.
*/
public static function add_query_vars( $vars ) {
$vars[] = 'activitypub';
return $vars;
}
/**
* Schedule Activities.
*
* @param string $new_status New post status.
* @param string $old_status Old post status.
* @param WP_Post $post Post object.
*/
public static function schedule_post_activity( $new_status, $old_status, $post ) {
// Do not send activities if post is password protected.
if ( \post_password_required( $post ) ) {
return;
}
// Check if post-type supports ActivityPub.
$post_types = \get_post_types_by_support( 'activitypub' );
if ( ! \in_array( $post->post_type, $post_types, true ) ) {
return;
}
$activitypub_post = new \Activitypub\Model\Post( $post );
if ( 'publish' === $new_status && 'publish' !== $old_status ) {
\wp_schedule_single_event( \time(), 'activitypub_send_post_activity', array( $activitypub_post ) );
} elseif ( 'publish' === $new_status ) {
\wp_schedule_single_event( \time(), 'activitypub_send_update_activity', array( $activitypub_post ) );
} elseif ( 'trash' === $new_status ) {
\wp_schedule_single_event( \time(), 'activitypub_send_delete_activity', array( $activitypub_post ) );
}
}
/**
* Replaces the default avatar.
*
* @param array $args Arguments passed to get_avatar_data(), after processing.
* @param int|string|object $id_or_email A user ID, email address, or comment object.
*
* @return array $args
*/
public static function pre_get_avatar_data( $args, $id_or_email ) {
if (
! $id_or_email instanceof \WP_Comment ||
! isset( $id_or_email->comment_type ) ||
$id_or_email->user_id
) {
return $args;
}
$allowed_comment_types = \apply_filters( 'get_avatar_comment_types', array( 'comment' ) );
if ( ! empty( $id_or_email->comment_type ) && ! \in_array( $id_or_email->comment_type, (array) $allowed_comment_types, true ) ) {
$args['url'] = false;
/** This filter is documented in wp-includes/link-template.php */
return \apply_filters( 'get_avatar_data', $args, $id_or_email );
}
// Check if comment has an avatar.
$avatar = self::get_avatar_url( $id_or_email->comment_ID );
if ( $avatar ) {
if ( ! isset( $args['class'] ) || ! \is_array( $args['class'] ) ) {
$args['class'] = array( 'u-photo' );
} else {
$args['class'][] = 'u-photo';
$args['class'] = \array_unique( $args['class'] );
}
$args['url'] = $avatar;
$args['class'][] = 'avatar-activitypub';
}
return $args;
}
/**
* Function to retrieve Avatar URL if stored in meta.
*
* @param int|WP_Comment $comment
*
* @return string $url
*/
public static function get_avatar_url( $comment ) {
if ( \is_numeric( $comment ) ) {
$comment = \get_comment( $comment );
}
return \get_comment_meta( $comment->comment_ID, 'avatar_url', true );
}
/**
* Store permalink in meta, to send delete Activity
*
* @param string $post_id The Post ID
*
* @return void
*/
public static function trash_post( $post_id ) {
\add_post_meta( $post_id, 'activitypub_canonical_url', \get_permalink( $post_id ), true );
}
/**
* Delete permalink from meta
*
* @param string $post_id The Post ID
*
* @return void
*/
public static function untrash_post( $post_id ) {
\delete_post_meta( $post_id, 'activitypub_canonical_url' );
}
}

View File

@ -0,0 +1,168 @@
<?php
namespace Activitypub;
/**
* ActivityPub Admin Class
*
* @author Matthias Pfefferle
*/
class Admin {
/**
* Initialize the class, registering WordPress hooks
*/
public static function init() {
\add_action( 'admin_menu', array( '\Activitypub\Admin', 'admin_menu' ) );
\add_action( 'admin_init', array( '\Activitypub\Admin', 'register_settings' ) );
\add_action( 'show_user_profile', array( '\Activitypub\Admin', 'add_fediverse_profile' ) );
\add_action( 'admin_enqueue_scripts', array( '\Activitypub\Admin', 'enqueue_scripts' ) );
}
/**
* Add admin menu entry
*/
public static function admin_menu() {
$settings_page = \add_options_page(
'Welcome',
'ActivityPub',
'manage_options',
'activitypub',
array( '\Activitypub\Admin', 'settings_page' )
);
\add_action( 'load-' . $settings_page, array( '\Activitypub\Admin', 'add_settings_help_tab' ) );
$followers_list_page = \add_users_page( \__( 'Followers', 'activitypub' ), \__( 'Followers (Fediverse)', 'activitypub' ), 'read', 'activitypub-followers-list', array( '\Activitypub\Admin', 'followers_list_page' ) );
\add_action( 'load-' . $followers_list_page, array( '\Activitypub\Admin', 'add_followers_list_help_tab' ) );
}
/**
* Load settings page
*/
public static function settings_page() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( empty( $_GET['tab'] ) ) {
$tab = 'welcome';
} else {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$tab = sanitize_key( $_GET['tab'] );
}
switch ( $tab ) {
case 'settings':
\Activitypub\Model\Post::upgrade_post_content_template();
\load_template( \dirname( __FILE__ ) . '/../templates/settings.php' );
break;
case 'welcome':
default:
wp_enqueue_script( 'plugin-install' );
add_thickbox();
wp_enqueue_script( 'updates' );
\load_template( \dirname( __FILE__ ) . '/../templates/welcome.php' );
break;
}
}
/**
* Load user settings page
*/
public static function followers_list_page() {
\load_template( \dirname( __FILE__ ) . '/../templates/followers-list.php' );
}
/**
* Register ActivityPub settings
*/
public static function register_settings() {
\register_setting(
'activitypub',
'activitypub_post_content_type',
array(
'type' => 'string',
'description' => \__( 'Use title and link, summary, full or custom content', 'activitypub' ),
'show_in_rest' => array(
'schema' => array(
'enum' => array( 'title', 'excerpt', 'content' ),
),
),
'default' => 'content',
)
);
\register_setting(
'activitypub',
'activitypub_custom_post_content',
array(
'type' => 'string',
'description' => \__( 'Define your own custom post template', 'activitypub' ),
'show_in_rest' => true,
'default' => ACTIVITYPUB_CUSTOM_POST_CONTENT,
)
);
\register_setting(
'activitypub',
'activitypub_max_image_attachments',
array(
'type' => 'integer',
'description' => \__( 'Number of images to attach to posts.', 'activitypub' ),
'default' => ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS,
)
);
\register_setting(
'activitypub',
'activitypub_object_type',
array(
'type' => 'string',
'description' => \__( 'The Activity-Object-Type', 'activitypub' ),
'show_in_rest' => array(
'schema' => array(
'enum' => array( 'note', 'article', 'wordpress-post-format' ),
),
),
'default' => 'note',
)
);
\register_setting(
'activitypub',
'activitypub_use_hashtags',
array(
'type' => 'boolean',
'description' => \__( 'Add hashtags in the content as native tags and replace the #tag with the tag-link', 'activitypub' ),
'default' => 0,
)
);
\register_setting(
'activitypub',
'activitypub_support_post_types',
array(
'type' => 'string',
'description' => \esc_html__( 'Enable ActivityPub support for post types', 'activitypub' ),
'show_in_rest' => true,
'default' => array( 'post', 'pages' ),
)
);
}
public static function add_settings_help_tab() {
require_once \dirname( __FILE__ ) . '/help.php';
}
public static function add_followers_list_help_tab() {
// todo
}
public static function add_fediverse_profile( $user ) {
?>
<h2 id="activitypub"><?php \esc_html_e( 'ActivityPub', 'activitypub' ); ?></h2>
<?php
\Activitypub\get_identifier_settings( $user->ID );
}
public static function enqueue_scripts( $hook_suffix ) {
if ( false !== strpos( $hook_suffix, 'activitypub' ) ) {
wp_enqueue_style( 'activitypub-admin-styles', plugins_url( 'assets/css/activitypub-admin.css', ACTIVITYPUB_PLUGIN_FILE ), array(), '1.0.0' );
wp_enqueue_script( 'activitypub-admin-styles', plugins_url( 'assets/js/activitypub-admin.js', ACTIVITYPUB_PLUGIN_FILE ), array( 'jquery' ), '1.0.0', false );
}
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace Activitypub;
/**
* ActivityPub Debug Class
*
* @author Matthias Pfefferle
*/
class Debug {
/**
* Initialize the class, registering WordPress hooks
*/
public static function init() {
if ( WP_DEBUG && WP_DEBUG_LOG ) {
\add_action( 'activitypub_safe_remote_post_response', array( '\Activitypub\Debug', 'log_remote_post_responses' ), 10, 4 );
}
}
public static function log_remote_post_responses( $response, $url, $body, $user_id ) {
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log, WordPress.PHP.DevelopmentFunctions.error_log_print_r
\error_log( "Request to: {$url} with response: " . \print_r( $response, true ) );
}
public static function write_log( $log ) {
if ( \is_array( $log ) || \is_object( $log ) ) {
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log, WordPress.PHP.DevelopmentFunctions.error_log_print_r
\error_log( \print_r( $log, true ) );
} else {
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
\error_log( $log );
}
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace Activitypub;
/**
* ActivityPub Hashtag Class
*
* @author Matthias Pfefferle
*/
class Hashtag {
/**
* Initialize the class, registering WordPress hooks
*/
public static function init() {
if ( '1' === \get_option( 'activitypub_use_hashtags', '1' ) ) {
\add_filter( 'wp_insert_post', array( '\Activitypub\Hashtag', 'insert_post' ), 10, 2 );
\add_filter( 'the_content', array( '\Activitypub\Hashtag', 'the_content' ), 10, 2 );
}
}
/**
* Filter to save #tags as real WordPress tags
*
* @param int $id the rev-id
* @param WP_Post $post the post
*
* @return
*/
public static function insert_post( $id, $post ) {
if ( \preg_match_all( '/' . ACTIVITYPUB_HASHTAGS_REGEXP . '/i', $post->post_content, $match ) ) {
$tags = \implode( ', ', $match[1] );
\wp_add_post_tags( $post->post_parent, $tags );
}
return $id;
}
/**
* Filter to replace the #tags in the content with links
*
* @param string $the_content the post-content
*
* @return string the filtered post-content
*/
public static function the_content( $the_content ) {
$protected_tags = array();
$protect = function( $m ) use ( &$protected_tags ) {
$c = count( $protected_tags );
$protect = '!#!#PROTECT' . $c . '#!#!';
$protected_tags[ $protect ] = $m[0];
return $protect;
};
$the_content = preg_replace_callback(
'#<!\[CDATA\[.*?\]\]>#is',
$protect,
$the_content
);
$the_content = preg_replace_callback(
'#<(pre|code|textarea|style)\b[^>]*>.*?</\1[^>]*>#is',
$protect,
$the_content
);
$the_content = preg_replace_callback(
'#<[^>]+>#i',
$protect,
$the_content
);
$the_content = \preg_replace_callback( '/' . ACTIVITYPUB_HASHTAGS_REGEXP . '/i', array( '\Activitypub\Hashtag', 'replace_with_links' ), $the_content );
$the_content = str_replace( array_reverse( array_keys( $protected_tags ) ), array_reverse( array_values( $protected_tags ) ), $the_content );
return $the_content;
}
/**
* A callback for preg_replace to build the term links
*
* @param array $result the preg_match results
* @return string the final string
*/
public static function replace_with_links( $result ) {
$tag = $result[1];
$tag_object = \get_term_by( 'name', $tag, 'post_tag' );
if ( $tag_object ) {
$link = \get_term_link( $tag_object, 'post_tag' );
return \sprintf( '<a rel="tag" class="u-tag u-category" href="%s">#%s</a>', $link, $tag );
}
return '#' . $tag;
}
}

View File

@ -0,0 +1,296 @@
<?php
namespace Activitypub;
/**
* ActivityPub Health_Check Class
*
* @author Matthias Pfefferle
*/
class Health_Check {
/**
* Initialize health checks
*
* @return void
*/
public static function init() {
\add_filter( 'site_status_tests', array( '\Activitypub\Health_Check', 'add_tests' ) );
\add_filter( 'debug_information', array( '\Activitypub\Health_Check', 'debug_information' ) );
}
public static function add_tests( $tests ) {
$tests['direct']['activitypub_test_author_url'] = array(
'label' => \__( 'Author URL test', 'activitypub' ),
'test' => array( '\Activitypub\Health_Check', 'test_author_url' ),
);
$tests['direct']['activitypub_test_webfinger'] = array(
'label' => __( 'WebFinger Test', 'activitypub' ),
'test' => array( '\Activitypub\Health_Check', 'test_webfinger' ),
);
return $tests;
}
/**
* Author URL tests
*
* @return void
*/
public static function test_author_url() {
$result = array(
'label' => \__( 'Author URL accessible', 'activitypub' ),
'status' => 'good',
'badge' => array(
'label' => \__( 'ActivityPub', 'activitypub' ),
'color' => 'green',
),
'description' => \sprintf(
'<p>%s</p>',
\__( 'Your author URL is accessible and supports the required "Accept" header.', 'activitypub' )
),
'actions' => '',
'test' => 'test_author_url',
);
$check = self::is_author_url_accessible();
if ( true === $check ) {
return $result;
}
$result['status'] = 'critical';
$result['label'] = \__( 'Author URL is not accessible', 'activitypub' );
$result['badge']['color'] = 'red';
$result['description'] = \sprintf(
'<p>%s</p>',
$check->get_error_message()
);
return $result;
}
/**
* WebFinger tests
*
* @return void
*/
public static function test_webfinger() {
$result = array(
'label' => \__( 'WebFinger endpoint', 'activitypub' ),
'status' => 'good',
'badge' => array(
'label' => \__( 'ActivityPub', 'activitypub' ),
'color' => 'green',
),
'description' => \sprintf(
'<p>%s</p>',
\__( 'Your WebFinger endpoint is accessible and returns the correct informations.', 'activitypub' )
),
'actions' => '',
'test' => 'test_webfinger',
);
$check = self::is_webfinger_endpoint_accessible();
if ( true === $check ) {
return $result;
}
$result['status'] = 'critical';
$result['label'] = \__( 'WebFinger endpoint is not accessible', 'activitypub' );
$result['badge']['color'] = 'red';
$result['description'] = \sprintf(
'<p>%s</p>',
$check->get_error_message()
);
return $result;
}
/**
* Check if `author_posts_url` is accessible and that requerst returns correct JSON
*
* @return boolean|WP_Error
*/
public static function is_author_url_accessible() {
$user = \wp_get_current_user();
$author_url = \get_author_posts_url( $user->ID );
$reference_author_url = self::get_author_posts_url( $user->ID, $user->user_nicename );
// check for "author" in URL
if ( $author_url !== $reference_author_url ) {
return new \WP_Error(
'author_url_not_accessible',
\sprintf(
// translators: %s: Author URL
\__(
'<p>Your author URL <code>%s</code> was replaced, this is often done by plugins.</p>',
'activitypub'
),
$author_url
)
);
}
// try to access author URL
$response = \wp_remote_get(
$author_url,
array(
'headers' => array( 'Accept' => 'application/activity+json' ),
'redirection' => 0,
)
);
if ( \is_wp_error( $response ) ) {
return new \WP_Error(
'author_url_not_accessible',
\sprintf(
// translators: %s: Author URL
\__(
'<p>Your author URL <code>%s</code> is not accessible. Please check your WordPress setup or permalink structure. If the setup seems fine, maybe check if a plugin might restrict the access.</p>',
'activitypub'
),
$author_url
)
);
}
$response_code = \wp_remote_retrieve_response_code( $response );
// check for redirects
if ( \in_array( $response_code, array( 301, 302, 307, 308 ), true ) ) {
return new \WP_Error(
'author_url_not_accessible',
\sprintf(
// translators: %s: Author URL
\__(
'<p>Your author URL <code>%s</code> is redirecting to another page, this is often done by SEO plugins like "Yoast SEO".</p>',
'activitypub'
),
$author_url
)
);
}
// check if response is JSON
$body = \wp_remote_retrieve_body( $response );
if ( ! \is_string( $body ) || ! \is_array( \json_decode( $body, true ) ) ) {
return new \WP_Error(
'author_url_not_accessible',
\sprintf(
// translators: %s: Author URL
\__(
'<p>Your author URL <code>%s</code> does not return valid JSON for <code>application/activity+json</code>. Please check if your hosting supports alternate <code>Accept</code> headers.</p>',
'activitypub'
),
$author_url
)
);
}
return true;
}
/**
* Check if WebFinger endoint is accessible and profile requerst returns correct JSON
*
* @return boolean|WP_Error
*/
public static function is_webfinger_endpoint_accessible() {
$user = \wp_get_current_user();
$account = \Activitypub\get_webfinger_resource( $user->ID );
$url = \Activitypub\Webfinger::resolve( $account );
if ( \is_wp_error( $url ) ) {
$health_messages = array(
'webfinger_url_not_accessible' => \sprintf(
// translators: %s: Author URL
\__(
'<p>Your WebFinger endpoint <code>%s</code> is not accessible. Please check your WordPress setup or permalink structure.</p>',
'activitypub'
),
$url->get_error_data()
),
'webfinger_url_invalid_response' => \sprintf(
// translators: %s: Author URL
\__(
'<p>Your WebFinger endpoint <code>%s</code> does not return valid JSON for <code>application/jrd+json</code>.</p>',
'activitypub'
),
$url->get_error_data()
),
);
$message = null;
if ( isset( $health_messages[ $url->get_error_code() ] ) ) {
$message = $health_messages[ $url->get_error_code() ];
}
return new \WP_Error(
$url->get_error_code(),
$message,
$url->get_error_data()
);
}
return true;
}
/**
* Retrieve the URL to the author page for the user with the ID provided.
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*
* @param int $author_id Author ID.
* @param string $author_nicename Optional. The author's nicename (slug). Default empty.
*
* @return string The URL to the author's page.
*/
public static function get_author_posts_url( $author_id, $author_nicename = '' ) {
global $wp_rewrite;
$auth_id = (int) $author_id;
$link = $wp_rewrite->get_author_permastruct();
if ( empty( $link ) ) {
$file = home_url( '/' );
$link = $file . '?author=' . $auth_id;
} else {
if ( '' === $author_nicename ) {
$user = get_userdata( $author_id );
if ( ! empty( $user->user_nicename ) ) {
$author_nicename = $user->user_nicename;
}
}
$link = str_replace( '%author%', $author_nicename, $link );
$link = home_url( user_trailingslashit( $link ) );
}
return $link;
}
/**
* Static function for generating site debug data when required.
*
* @param array $info The debug information to be added to the core information page.
* @return array The filtered informations
*/
public static function debug_information( $info ) {
$info['activitypub'] = array(
'label' => __( 'ActivityPub', 'activitypub' ),
'fields' => array(
'webfinger' => array(
'label' => __( 'WebFinger Resource', 'activitypub' ),
'value' => \Activitypub\Webfinger::get_user_resource( wp_get_current_user()->ID ),
'private' => true,
),
'author_url' => array(
'label' => __( 'Author URL', 'activitypub' ),
'value' => get_author_posts_url( wp_get_current_user()->ID ),
'private' => true,
),
),
);
return $info;
}
}

View File

@ -0,0 +1,97 @@
<?php
namespace Activitypub;
/**
* ActivityPub Mention Class
*
* @author Alex Kirk
*/
class Mention {
/**
* Initialize the class, registering WordPress hooks
*/
public static function init() {
\add_filter( 'the_content', array( '\Activitypub\Mention', 'the_content' ), 99, 2 );
\add_filter( 'activitypub_extract_mentions', array( '\Activitypub\Mention', 'extract_mentions' ), 99, 2 );
}
/**
* Filter to replace the mentions in the content with links
*
* @param string $the_content the post-content
*
* @return string the filtered post-content
*/
public static function the_content( $the_content ) {
$protected_tags = array();
$protect = function( $m ) use ( &$protected_tags ) {
$c = count( $protected_tags );
$protect = '!#!#PROTECT' . $c . '#!#!';
$protected_tags[ $protect ] = $m[0];
return $protect;
};
$the_content = preg_replace_callback(
'#<!\[CDATA\[.*?\]\]>#is',
$protect,
$the_content
);
$the_content = preg_replace_callback(
'#<(pre|code|textarea|style)\b[^>]*>.*?</\1[^>]*>#is',
$protect,
$the_content
);
$the_content = preg_replace_callback(
'#<a.*?href=[^>]+>.*?</a>#i',
$protect,
$the_content
);
$the_content = \preg_replace_callback( '/@' . ACTIVITYPUB_USERNAME_REGEXP . '/', array( '\Activitypub\Mention', 'replace_with_links' ), $the_content );
$the_content = str_replace( array_reverse( array_keys( $protected_tags ) ), array_reverse( array_values( $protected_tags ) ), $the_content );
return $the_content;
}
/**
* A callback for preg_replace to build the user links
*
* @param array $result the preg_match results
* @return string the final string
*/
public static function replace_with_links( $result ) {
$metadata = \ActivityPub\get_remote_metadata_by_actor( $result[0] );
if ( ! is_wp_error( $metadata ) && ! empty( $metadata['url'] ) ) {
$username = ltrim( $result[0], '@' );
if ( ! empty( $metadata['name'] ) ) {
$username = $metadata['name'];
}
if ( ! empty( $metadata['preferredUsername'] ) ) {
$username = $metadata['preferredUsername'];
}
$username = '@<span>' . $username . '</span>';
return \sprintf( '<a rel="mention" class="u-url mention" href="%s">%s</a>', $metadata['url'], $username );
}
return $result[0];
}
/**
* Extract the mentions from the post_content.
*
* @param array $mentions The already found mentions.
* @param string $post_content The post content.
* @return mixed The discovered mentions.
*/
public static function extract_mentions( $mentions, $post_content ) {
\preg_match_all( '/@' . ACTIVITYPUB_USERNAME_REGEXP . '/i', $post_content, $matches );
foreach ( $matches[0] as $match ) {
$link = \Activitypub\Webfinger::resolve( $match );
if ( ! is_wp_error( $link ) ) {
$mentions[ $match ] = $link;
}
}
return $mentions;
}
}

View File

@ -0,0 +1,527 @@
<?php
namespace Activitypub;
class Shortcodes {
/**
* Class constructor, registering WordPress then shortcodes
*
* @param WP_Post $post A WordPress Post Object
*/
public static function init() {
foreach ( get_class_methods( 'Activitypub\Shortcodes' ) as $shortcode ) {
if ( 'init' !== $shortcode ) {
add_shortcode( 'ap_' . $shortcode, array( 'Activitypub\Shortcodes', $shortcode ) );
}
}
}
/**
* Generates output for the ap_hashtags shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function hashtags( $atts, $content, $tag ) {
$post_id = get_the_ID();
if ( ! $post_id ) {
return '';
}
$tags = \get_the_tags( $post_id );
if ( ! $tags ) {
return '';
}
$hash_tags = array();
foreach ( $tags as $tag ) {
$hash_tags[] = \sprintf(
'<a rel="tag" class="u-tag u-category" href="%s">#%s</a>',
\get_tag_link( $tag ),
$tag->slug
);
}
return \implode( ' ', $hash_tags );
}
/**
* Generates output for the ap_title shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function title( $atts, $content, $tag ) {
$post_id = get_the_ID();
if ( ! $post_id ) {
return '';
}
return \get_the_title( $post_id );
}
/**
* Generates output for the ap_excerpt shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function excerpt( $atts, $content, $tag ) {
$post = get_post();
if ( ! $post || \post_password_required( $post ) ) {
return '';
}
$atts = shortcode_atts(
array( 'length' => ACTIVITYPUB_EXCERPT_LENGTH ),
$atts,
$tag
);
$excerpt_length = intval( $atts['length'] );
if ( 0 === $excerpt_length ) {
$excerpt_length = ACTIVITYPUB_EXCERPT_LENGTH;
}
$excerpt = \get_post_field( 'post_excerpt', $post );
if ( '' === $excerpt ) {
$content = \get_post_field( 'post_content', $post );
// An empty string will make wp_trim_excerpt do stuff we do not want.
if ( '' !== $content ) {
$excerpt = \strip_shortcodes( $content );
/** This filter is documented in wp-includes/post-template.php */
$excerpt = \apply_filters( 'the_content', $excerpt );
$excerpt = \str_replace( ']]>', ']]>', $excerpt );
}
}
// Strip out any remaining tags.
$excerpt = \wp_strip_all_tags( $excerpt );
/** This filter is documented in wp-includes/formatting.php */
$excerpt_more = \apply_filters( 'excerpt_more', ' [...]' );
$excerpt_more_len = strlen( $excerpt_more );
// We now have a excerpt, but we need to check it's length, it may be longer than we want for two reasons:
//
// * The user has entered a manual excerpt which is longer that what we want.
// * No manual excerpt exists so we've used the content which might be longer than we want.
//
// Either way, let's trim it up if we need too. Also, don't forget to take into account the more indicator
// as part of the total length.
//
// Setup a variable to hold the current excerpts length.
$current_excerpt_length = strlen( $excerpt );
// Setup a variable to keep track of our target length.
$target_excerpt_length = $excerpt_length - $excerpt_more_len;
// Setup a variable to keep track of the current max length.
$current_excerpt_max = $target_excerpt_length;
// This is a loop since we can't calculate word break the string after 'the_excpert' filter has run (we would break
// all kinds of html tags), so we have to cut the excerpt down a bit at a time until we hit our target length.
while ( $current_excerpt_length > $target_excerpt_length && $current_excerpt_max > 0 ) {
// Trim the excerpt based on wordwrap() positioning.
// Note: we're using <br> as the linebreak just in case there are any newlines existing in the excerpt from the user.
// There won't be any <br> left after we've run wp_strip_all_tags() in the code above, so they're
// safe to use here. It won't be included in the final excerpt as the substr() will trim it off.
$excerpt = substr( $excerpt, 0, strpos( wordwrap( $excerpt, $current_excerpt_max, '<br>' ), '<br>' ) );
// If something went wrong, or we're in a language that wordwrap() doesn't understand,
// just chop it off and don't worry about breaking in the middle of a word.
if ( strlen( $excerpt ) > $excerpt_length - $excerpt_more_len ) {
$excerpt = substr( $excerpt, 0, $current_excerpt_max );
}
// Add in the more indicator.
$excerpt = $excerpt . $excerpt_more;
// Run it through the excerpt filter which will add some html tags back in.
$excerpt_filtered = apply_filters( 'the_excerpt', $excerpt );
// Now set the current excerpt length to this new filtered length.
$current_excerpt_length = strlen( $excerpt_filtered );
// Check to see if we're over the target length.
if ( $current_excerpt_length > $target_excerpt_length ) {
// If so, remove 20 characters from the current max and run the loop again.
$current_excerpt_max = $current_excerpt_max - 20;
}
}
return \apply_filters( 'the_excerpt', $excerpt );
}
/**
* Generates output for the ap_content shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function content( $atts, $content, $tag ) {
$post = get_post();
if ( ! $post || \post_password_required( $post ) ) {
return '';
}
$atts = shortcode_atts(
array( 'apply_filters' => 'yes' ),
$atts,
$tag
);
$content = \get_post_field( 'post_content', $post );
if ( 'yes' === $atts['apply_filters'] ) {
$content = \apply_filters( 'the_content', $content );
} else {
$content = do_blocks( $content );
$content = wptexturize( $content );
$content = wp_filter_content_tags( $content );
}
// replace script and style elements
$content = \preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $content );
$content = \trim( \preg_replace( '/[\n\r\t]/', '', $content ) );
return $content;
}
/**
* Generates output for the ap_permalink shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function permalink( $atts, $content, $tag ) {
$post = get_post();
if ( ! $post ) {
return '';
}
$atts = shortcode_atts(
array(
'type' => 'url',
),
$atts,
$tag
);
if ( 'url' === $atts['type'] ) {
return \esc_url( \get_permalink( $post->ID ) );
}
return \sprintf( '<a href="%1$s">%1$s</a>', \esc_url( \get_permalink( $post->ID ) ) );
}
/**
* Generates output for the ap_shortlink shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function shortlink( $atts, $content, $tag ) {
$post = get_post();
if ( ! $post ) {
return '';
}
$atts = shortcode_atts(
array(
'type' => 'url',
),
$atts,
$tag
);
if ( 'url' === $atts['type'] ) {
return \esc_url( \wp_get_shortlink( $post->ID ) );
}
return \sprintf( '<a href="%1$s">%1$s</a>', \esc_url( \wp_get_shortlink( $post->ID ) ) );
}
/**
* Generates output for the ap_image shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function image( $atts, $content, $tag ) {
$post_id = get_the_ID();
if ( ! $post_id ) {
return '';
}
$atts = shortcode_atts(
array(
'type' => 'full',
),
$atts,
$tag
);
$size = 'full';
if ( in_array(
$atts['type'],
array( 'thumbnail', 'medium', 'large', 'full' ),
true
) ) {
$size = $atts['type'];
}
$image = \get_the_post_thumbnail_url( $post_id, $size );
if ( ! $image ) {
return '';
}
return \esc_url( $image );
}
/**
* Generates output for the ap_hashcats shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function hashcats( $atts, $content, $tag ) {
$post_id = get_the_ID();
if ( ! $post_id ) {
return '';
}
$categories = \get_the_category( $post_id );
if ( ! $categories ) {
return '';
}
$hash_tags = array();
foreach ( $categories as $category ) {
$hash_tags[] = \sprintf( '<a rel="tag" class="u-tag u-category" href="%s">#%s</a>', \get_category_link( $category ), $category->slug );
}
return \implode( ' ', $hash_tags );
}
/**
* Generates output for the ap_author shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function author( $atts, $content, $tag ) {
$post = get_post();
if ( ! $post ) {
return '';
}
$name = \get_the_author_meta( 'display_name', $post->post_author );
if ( ! $name ) {
return '';
}
return $name;
}
/**
* Generates output for the ap_authorurl shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function authorurl( $atts, $content, $tag ) {
$post = get_post();
if ( ! $post ) {
return '';
}
$url = \get_the_author_meta( 'user_url', $post->post_author );
if ( ! $url ) {
return '';
}
return \esc_url( $url );
}
/**
* Generates output for the ap_blogurl shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function blogurl( $atts, $content, $tag ) {
return \esc_url( \get_bloginfo( 'url' ) );
}
/**
* Generates output for the ap_blogname shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function blogname( $atts, $content, $tag ) {
return \get_bloginfo( 'name' );
}
/**
* Generates output for the ap_blogdesc shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function blogdesc( $atts, $content, $tag ) {
return \get_bloginfo( 'description' );
}
/**
* Generates output for the ap_date shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function date( $atts, $content, $tag ) {
$post = get_post();
if ( ! $post ) {
return '';
}
$datetime = \get_post_datetime( $post );
$dateformat = \get_option( 'date_format' );
$timeformat = \get_option( 'time_format' );
$date = $datetime->format( $dateformat );
if ( ! $date ) {
return '';
}
return $date;
}
/**
* Generates output for the ap_time shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function time( $atts, $content, $tag ) {
$post = get_post();
if ( ! $post ) {
return '';
}
$datetime = \get_post_datetime( $post );
$dateformat = \get_option( 'date_format' );
$timeformat = \get_option( 'time_format' );
$date = $datetime->format( $timeformat );
if ( ! $date ) {
return '';
}
return $date;
}
/**
* Generates output for the ap_datetime shortcode
*
* @param array $atts shortcode attributes
* @param string $content shortcode content
* @param string $tag shortcode tag name
*
* @return string
*/
public static function datetime( $atts, $content, $tag ) {
$post = get_post();
if ( ! $post ) {
return '';
}
$datetime = \get_post_datetime( $post );
$dateformat = \get_option( 'date_format' );
$timeformat = \get_option( 'time_format' );
$date = $datetime->format( $dateformat . ' @ ' . $timeformat );
if ( ! $date ) {
return '';
}
return $date;
}
}

View File

@ -0,0 +1,118 @@
<?php
namespace Activitypub;
/**
* ActivityPub Signature Class
*
* @author Matthias Pfefferle
*/
class Signature {
/**
* @param int $user_id
*
* @return mixed
*/
public static function get_public_key( $user_id, $force = false ) {
$key = \get_user_meta( $user_id, 'magic_sig_public_key' );
if ( $key && ! $force ) {
return $key[0];
}
self::generate_key_pair( $user_id );
$key = \get_user_meta( $user_id, 'magic_sig_public_key' );
return $key[0];
}
/**
* @param int $user_id
*
* @return mixed
*/
public static function get_private_key( $user_id, $force = false ) {
$key = \get_user_meta( $user_id, 'magic_sig_private_key' );
if ( $key && ! $force ) {
return $key[0];
}
self::generate_key_pair( $user_id );
$key = \get_user_meta( $user_id, 'magic_sig_private_key' );
return $key[0];
}
/**
* Generates the pair keys
*
* @param int $user_id
*/
public static function generate_key_pair( $user_id ) {
$config = array(
'digest_alg' => 'sha512',
'private_key_bits' => 2048,
'private_key_type' => \OPENSSL_KEYTYPE_RSA,
);
$key = \openssl_pkey_new( $config );
$priv_key = null;
\openssl_pkey_export( $key, $priv_key );
// private key
\update_user_meta( $user_id, 'magic_sig_private_key', $priv_key );
$detail = \openssl_pkey_get_details( $key );
// public key
\update_user_meta( $user_id, 'magic_sig_public_key', $detail['key'] );
}
public static function generate_signature( $user_id, $http_method, $url, $date, $digest = null ) {
$key = self::get_private_key( $user_id );
$url_parts = \wp_parse_url( $url );
$host = $url_parts['host'];
$path = '/';
// add path
if ( ! empty( $url_parts['path'] ) ) {
$path = $url_parts['path'];
}
// add query
if ( ! empty( $url_parts['query'] ) ) {
$path .= '?' . $url_parts['query'];
}
if ( ! empty( $digest ) ) {
$signed_string = "(request-target): $http_method $path\nhost: $host\ndate: $date\ndigest: SHA-256=$digest";
} else {
$signed_string = "(request-target): $http_method $path\nhost: $host\ndate: $date";
}
$signature = null;
\openssl_sign( $signed_string, $signature, $key, \OPENSSL_ALGO_SHA256 );
$signature = \base64_encode( $signature ); // phpcs:ignore
$key_id = \get_author_posts_url( $user_id ) . '#main-key';
if ( ! empty( $digest ) ) {
return \sprintf( 'keyId="%s",algorithm="rsa-sha256",headers="(request-target) host date digest",signature="%s"', $key_id, $signature );
} else {
return \sprintf( 'keyId="%s",algorithm="rsa-sha256",headers="(request-target) host date",signature="%s"', $key_id, $signature );
}
}
public static function verify_signature( $headers, $signature ) {
}
public static function generate_digest( $body ) {
$digest = \base64_encode( \hash( 'sha256', $body, true ) ); // phpcs:ignore
return "$digest";
}
}

View File

@ -0,0 +1,84 @@
<?php
namespace Activitypub;
/**
* ActivityPub WebFinger Class
*
* @author Matthias Pfefferle
*
* @see https://webfinger.net/
*/
class Webfinger {
/**
* Returns a users WebFinger "resource"
*
* @param int $user_id
*
* @return string The user-resource
*/
public static function get_user_resource( $user_id ) {
// use WebFinger plugin if installed
if ( \function_exists( '\get_webfinger_resource' ) ) {
return \get_webfinger_resource( $user_id, false );
}
$user = \get_user_by( 'id', $user_id );
return $user->user_login . '@' . \wp_parse_url( \home_url(), \PHP_URL_HOST );
}
public static function resolve( $account ) {
if ( ! preg_match( '/^@?' . ACTIVITYPUB_USERNAME_REGEXP . '$/i', $account, $m ) ) {
return null;
}
$transient_key = 'activitypub_resolve_' . ltrim( $account, '@' );
$link = \get_transient( $transient_key );
if ( $link ) {
return $link;
}
$url = \add_query_arg( 'resource', 'acct:' . ltrim( $account, '@' ), 'https://' . $m[2] . '/.well-known/webfinger' );
if ( ! \wp_http_validate_url( $url ) ) {
$response = new \WP_Error( 'invalid_webfinger_url', null, $url );
\set_transient( $transient_key, $response, HOUR_IN_SECONDS ); // Cache the error for a shorter period.
return $response;
}
// try to access author URL
$response = \wp_remote_get(
$url,
array(
'headers' => array( 'Accept' => 'application/activity+json' ),
'redirection' => 0,
'timeout' => 2,
)
);
if ( \is_wp_error( $response ) ) {
$link = new \WP_Error( 'webfinger_url_not_accessible', null, $url );
\set_transient( $transient_key, $link, HOUR_IN_SECONDS ); // Cache the error for a shorter period.
return $link;
}
$body = \wp_remote_retrieve_body( $response );
$body = \json_decode( $body, true );
if ( empty( $body['links'] ) ) {
$link = new \WP_Error( 'webfinger_url_invalid_response', null, $url );
\set_transient( $transient_key, $link, HOUR_IN_SECONDS ); // Cache the error for a shorter period.
return $link;
}
foreach ( $body['links'] as $link ) {
if ( 'self' === $link['rel'] && 'application/activity+json' === $link['type'] ) {
\set_transient( $transient_key, $link['href'], WEEK_IN_SECONDS );
return $link['href'];
}
}
$link = new \WP_Error( 'webfinger_url_no_activity_pub', null, $body );
\set_transient( $transient_key, $link, HOUR_IN_SECONDS ); // Cache the error for a shorter period.
return $link;
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace Activitypub;
/**
* Allow localhost URLs if WP_DEBUG is true.
*
* @param array $r Array of HTTP request args.
* @param string $url The request URL.
* @return array $args Array or string of HTTP request arguments.
*/
function allow_localhost( $r, $url ) {
$r['reject_unsafe_urls'] = false;
return $r;
}
add_filter( 'http_request_args', '\Activitypub\allow_localhost', 10, 2 );

View File

@ -0,0 +1,322 @@
<?php
namespace Activitypub;
/**
* Returns the ActivityPub default JSON-context
*
* @return array the activitypub context
*/
function get_context() {
$context = array(
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
array(
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
'PropertyValue' => 'schema:PropertyValue',
'schema' => 'http://schema.org#',
'pt' => 'https://joinpeertube.org/ns#',
'toot' => 'http://joinmastodon.org/ns#',
'value' => 'schema:value',
'Hashtag' => 'as:Hashtag',
'featured' => array(
'@id' => 'toot:featured',
'@type' => '@id',
),
'featuredTags' => array(
'@id' => 'toot:featuredTags',
'@type' => '@id',
),
),
);
return \apply_filters( 'activitypub_json_context', $context );
}
function safe_remote_post( $url, $body, $user_id ) {
$date = \gmdate( 'D, d M Y H:i:s T' );
$digest = \Activitypub\Signature::generate_digest( $body );
$signature = \Activitypub\Signature::generate_signature( $user_id, 'post', $url, $date, $digest );
$wp_version = \get_bloginfo( 'version' );
$user_agent = \apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . \get_bloginfo( 'url' ) );
$args = array(
'timeout' => 100,
'limit_response_size' => 1048576,
'redirection' => 3,
'user-agent' => "$user_agent; ActivityPub",
'headers' => array(
'Accept' => 'application/activity+json',
'Content-Type' => 'application/activity+json',
'Digest' => "SHA-256=$digest",
'Signature' => $signature,
'Date' => $date,
),
'body' => $body,
);
$response = \wp_safe_remote_post( $url, $args );
\do_action( 'activitypub_safe_remote_post_response', $response, $url, $body, $user_id );
return $response;
}
function safe_remote_get( $url, $user_id ) {
$date = \gmdate( 'D, d M Y H:i:s T' );
$signature = \Activitypub\Signature::generate_signature( $user_id, 'get', $url, $date );
$wp_version = \get_bloginfo( 'version' );
$user_agent = \apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . \get_bloginfo( 'url' ) );
$args = array(
'timeout' => apply_filters( 'activitypub_remote_get_timeout', 100 ),
'limit_response_size' => 1048576,
'redirection' => 3,
'user-agent' => "$user_agent; ActivityPub",
'headers' => array(
'Accept' => 'application/activity+json',
'Content-Type' => 'application/activity+json',
'Signature' => $signature,
'Date' => $date,
),
);
$response = \wp_safe_remote_get( $url, $args );
\do_action( 'activitypub_safe_remote_get_response', $response, $url, $user_id );
return $response;
}
/**
* Returns a users WebFinger "resource"
*
* @param int $user_id
*
* @return string The user-resource
*/
function get_webfinger_resource( $user_id ) {
return \Activitypub\Webfinger::get_user_resource( $user_id );
}
/**
* [get_metadata_by_actor description]
*
* @param string $actor
*
* @return array
*/
function get_remote_metadata_by_actor( $actor ) {
$pre = apply_filters( 'pre_get_remote_metadata_by_actor', false, $actor );
if ( $pre ) {
return $pre;
}
if ( preg_match( '/^@?' . ACTIVITYPUB_USERNAME_REGEXP . '$/i', $actor ) ) {
$actor = Webfinger::resolve( $actor );
}
if ( ! $actor ) {
return null;
}
if ( is_wp_error( $actor ) ) {
return $actor;
}
$transient_key = 'activitypub_' . $actor;
$metadata = \get_transient( $transient_key );
if ( $metadata ) {
return $metadata;
}
if ( ! \wp_http_validate_url( $actor ) ) {
$metadata = new \WP_Error( 'activitypub_no_valid_actor_url', \__( 'The "actor" is no valid URL', 'activitypub' ), $actor );
\set_transient( $transient_key, $metadata, HOUR_IN_SECONDS ); // Cache the error for a shorter period.
return $metadata;
}
$user = \get_users(
array(
'number' => 1,
'capability__in' => array( 'publish_posts' ),
'fields' => 'ID',
)
);
// we just need any user to generate a request signature
$user_id = \reset( $user );
$short_timeout = function() {
return 3;
};
add_filter( 'activitypub_remote_get_timeout', $short_timeout );
$response = \Activitypub\safe_remote_get( $actor, $user_id );
remove_filter( 'activitypub_remote_get_timeout', $short_timeout );
if ( \is_wp_error( $response ) ) {
\set_transient( $transient_key, $response, HOUR_IN_SECONDS ); // Cache the error for a shorter period.
return $response;
}
$metadata = \wp_remote_retrieve_body( $response );
$metadata = \json_decode( $metadata, true );
if ( ! $metadata ) {
$metadata = new \WP_Error( 'activitypub_invalid_json', \__( 'No valid JSON data', 'activitypub' ), $actor );
\set_transient( $transient_key, $metadata, HOUR_IN_SECONDS ); // Cache the error for a shorter period.
return $metadata;
}
\set_transient( $transient_key, $metadata, WEEK_IN_SECONDS );
return $metadata;
}
/**
* [get_inbox_by_actor description]
* @param [type] $actor [description]
* @return [type] [description]
*/
function get_inbox_by_actor( $actor ) {
$metadata = \Activitypub\get_remote_metadata_by_actor( $actor );
if ( \is_wp_error( $metadata ) ) {
return $metadata;
}
if ( isset( $metadata['endpoints'] ) && isset( $metadata['endpoints']['sharedInbox'] ) ) {
return $metadata['endpoints']['sharedInbox'];
}
if ( \array_key_exists( 'inbox', $metadata ) ) {
return $metadata['inbox'];
}
return new \WP_Error( 'activitypub_no_inbox', \__( 'No "Inbox" found', 'activitypub' ), $metadata );
}
/**
* [get_inbox_by_actor description]
* @param [type] $actor [description]
* @return [type] [description]
*/
function get_publickey_by_actor( $actor, $key_id ) {
$metadata = \Activitypub\get_remote_metadata_by_actor( $actor );
if ( \is_wp_error( $metadata ) ) {
return $metadata;
}
if (
isset( $metadata['publicKey'] ) &&
isset( $metadata['publicKey']['id'] ) &&
isset( $metadata['publicKey']['owner'] ) &&
isset( $metadata['publicKey']['publicKeyPem'] ) &&
$key_id === $metadata['publicKey']['id'] &&
$actor === $metadata['publicKey']['owner']
) {
return $metadata['publicKey']['publicKeyPem'];
}
return new \WP_Error( 'activitypub_no_public_key', \__( 'No "Public-Key" found', 'activitypub' ), $metadata );
}
function get_follower_inboxes( $user_id ) {
$followers = \Activitypub\Peer\Followers::get_followers( $user_id );
$inboxes = array();
foreach ( $followers as $follower ) {
$inbox = \Activitypub\get_inbox_by_actor( $follower );
if ( ! $inbox || \is_wp_error( $inbox ) ) {
continue;
}
// init array if empty
if ( ! isset( $inboxes[ $inbox ] ) ) {
$inboxes[ $inbox ] = array();
}
$inboxes[ $inbox ][] = $follower;
}
return $inboxes;
}
function get_identifier_settings( $user_id ) {
?>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label><?php \esc_html_e( 'Profile identifier', 'activitypub' ); ?></label>
</th>
<td>
<p><code><?php echo \esc_html( \Activitypub\get_webfinger_resource( $user_id ) ); ?></code> or <code><?php echo \esc_url( \get_author_posts_url( $user_id ) ); ?></code></p>
<?php // translators: the webfinger resource ?>
<p class="description"><?php \printf( \esc_html__( 'Try to follow "@%s" by searching for it on Mastodon,Friendica & Co.', 'activitypub' ), \esc_html( \Activitypub\get_webfinger_resource( $user_id ) ) ); ?></p>
</td>
</tr>
</tbody>
</table>
<?php
}
function get_followers( $user_id ) {
$followers = \Activitypub\Peer\Followers::get_followers( $user_id );
if ( ! $followers ) {
return array();
}
return $followers;
}
function count_followers( $user_id ) {
$followers = \Activitypub\get_followers( $user_id );
return \count( $followers );
}
/**
* Examine a url and try to determine the author ID it represents.
*
* Checks are supposedly from the hosted site blog.
*
* @param string $url Permalink to check.
*
* @return int User ID, or 0 on failure.
*/
function url_to_authorid( $url ) {
global $wp_rewrite;
// check if url hase the same host
if ( \wp_parse_url( \site_url(), \PHP_URL_HOST ) !== \wp_parse_url( $url, \PHP_URL_HOST ) ) {
return 0;
}
// first, check to see if there is a 'author=N' to match against
if ( \preg_match( '/[?&]author=(\d+)/i', $url, $values ) ) {
$id = \absint( $values[1] );
if ( $id ) {
return $id;
}
}
// check to see if we are using rewrite rules
$rewrite = $wp_rewrite->wp_rewrite_rules();
// not using rewrite rules, and 'author=N' method failed, so we're out of options
if ( empty( $rewrite ) ) {
return 0;
}
// generate rewrite rule for the author url
$author_rewrite = $wp_rewrite->get_author_permastruct();
$author_regexp = \str_replace( '%author%', '', $author_rewrite );
// match the rewrite rule with the passed url
if ( \preg_match( '/https?:\/\/(.+)' . \preg_quote( $author_regexp, '/' ) . '([^\/]+)/i', $url, $match ) ) {
$user = \get_user_by( 'slug', $match[2] );
if ( $user ) {
return $user->ID;
}
}
return 0;
}

View File

@ -0,0 +1,77 @@
<?php
\get_current_screen()->add_help_tab(
array(
'id' => 'template-tags',
'title' => \__( 'Template Tags', 'activitypub' ),
'content' =>
'<p>' . __( 'The following Template Tags are available:', 'activitypub' ) . '</p>' .
'<dl>' .
'<dt><code>[ap_title]</code></dt>' .
'<dd>' . \wp_kses( __( 'The post\'s title.', 'activitypub' ), 'default' ) . '</dd>' .
'<dt><code>[ap_content apply_filters="yes"]</code></dt>' .
'<dd>' . \wp_kses( __( 'The post\'s content. With <code>apply_filters</code> you can decide if filters should be applied or not (default is <code>yes</code>). The values can be <code>yes</code> or <code>no</code>. <code>apply_filters</code> attribute is optional.', 'activitypub' ), 'default' ) . '</dd>' .
'<dt><code>[ap_excerpt lenght="400"]</code></dt>' .
'<dd>' . \wp_kses( __( 'The post\'s excerpt (default 400 chars). <code>length</code> attribute is optional.', 'activitypub' ), 'default' ) . '</dd>' .
'<dt><code>[ap_permalink type="url"]</code></dt>' .
'<dd>' . \wp_kses( __( 'The post\'s permalink. <code>type</code> can be either: <code>url</code> or <code>html</code> (an &lt;a /&gt; tag). <code>type</code> attribute is optional.', 'activitypub' ), 'default' ) . '</dd>' .
'<dt><code>[ap_shortlink type="url"]</code></dt>' .
'<dd>' . \wp_kses( __( 'The post\'s shortlink. <code>type</code> can be either <code>url</code> or <code>html</code> (an &lt;a /&gt; tag). I can recommend <a href="https://wordpress.org/plugins/hum/" target="_blank">Hum</a>, to prettify the Shortlinks. <code>type</code> attribute is optional.', 'activitypub' ), 'default' ) . '</dd>' .
'<dt><code>[ap_hashtags]</code></dt>' .
'<dd>' . \wp_kses( __( 'The post\'s tags as hashtags.', 'activitypub' ), 'default' ) . '</dd>' .
'<dt><code>[ap_hashcats]</code></dt>' .
'<dd>' . \wp_kses( __( 'The post\'s categories as hashtags.', 'activitypub' ), 'default' ) . '</dd>' .
'<dt><code>[ap_image type=full]</code></dt>' .
'<dd>' . \wp_kses( __( 'The URL for the post\'s featured image, defaults to full size. The type attribute can be any of the following: <code>thumbnail</code>, <code>medium</code>, <code>large</code>, <code>full</code>. <code>type</code> attribute is optional.', 'activitypub' ), 'default' ) . '</dd>' .
'<dt><code>[ap_author]</code></dt>' .
'<dd>' . \wp_kses( __( 'The author\'s name.', 'activitypub' ), 'default' ) . '</dd>' .
'<dt><code>[ap_authorurl]</code></dt>' .
'<dd>' . \wp_kses( __( 'The URL to the author\'s profile page.', 'activitypub' ), 'default' ) . '</dd>' .
'<dt><code>[ap_date]</code></dt>' .
'<dd>' . \wp_kses( __( 'The post\'s date.', 'activitypub' ), 'default' ) . '</dd>' .
'<dt><code>[ap_time]</code></dt>' .
'<dd>' . \wp_kses( __( 'The post\'s time.', 'activitypub' ), 'default' ) . '</dd>' .
'<dt><code>[ap_datetime]</code></dt>' .
'<dd>' . \wp_kses( __( 'The post\'s date/time formated as "date @ time".', 'activitypub' ), 'default' ) . '</dd>' .
'<dt><code>[ap_blogurl]</code></dt>' .
'<dd>' . \wp_kses( __( 'The URL to the site.', 'activitypub' ), 'default' ) . '</dd>' .
'<dt><code>[ap_blogname]</code></dt>' .
'<dd>' . \wp_kses( __( 'The name of the site.', 'activitypub' ), 'default' ) . '</dd>' .
'<dt><code>[ap_blogdesc]</code></dt>' .
'<dd>' . \wp_kses( __( 'The description of the site.', 'activitypub' ), 'default' ) . '</dd>' .
'</dl>' .
'<p>' . __( 'You may also use any Shortcode normally available to you on your site, however be aware that Shortcodes may significantly increase the size of your content depending on what they do.', 'activitypub' ) . '</p>' .
'<p>' . __( 'Note: the old Template Tags are now deprecated and automatically converted to the new ones.', 'activitypub' ) . '</p>' .
'<p>' . \wp_kses( \__( '<a href="https://github.com/pfefferle/wordpress-activitypub/issues/new" target="_blank">Let me know</a> if you miss a Template Tag.', 'activitypub' ), 'activitypub' ) . '</p>',
)
);
\get_current_screen()->add_help_tab(
array(
'id' => 'glossar',
'title' => \__( 'Glossar', 'activitypub' ),
'content' =>
'<p><h2>' . \__( 'Fediverse', 'activitypub' ) . '</h2></p>' .
'<p>' . \__( 'The Fediverse is a new word made of two words: "federation" + "universe"', 'activitypub' ) . '</p>' .
'<p>' . \__( 'It is a federated social network running on free open software on a myriad of computers across the globe. Many independent servers are interconnected and allow people to interact with one another. There\'s no one central site: you choose a server to register. This ensures some decentralization and sovereignty of data. Fediverse (also called Fedi) has no built-in advertisements, no tricky algorithms, no one big corporation dictating the rules. Instead we have small cozy communities of like-minded people. Welcome!', 'activitypub' ) . '</p>' .
'<p>' . \__( 'For more informations please visit <a href="https://fediverse.party/" target="_blank">fediverse.party</a>', 'activitypub' ) . '</p>' .
'<p><h2>' . \__( 'ActivityPub', 'activitypub' ) . '</h2></p>' .
'<p>' . \__( 'ActivityPub is a decentralized social networking protocol based on the ActivityStreams 2.0 data format. ActivityPub is an official W3C recommended standard published by the W3C Social Web Working Group. It provides a client to server API for creating, updating and deleting content, as well as a federated server to server API for delivering notifications and subscribing to content.', 'activitypub' ) . '</p>' .
'<p><h2>' . \__( 'WebFinger', 'activitypub' ) . '</h2></p>' .
'<p>' . \__( 'WebFinger is used to discover information about people or other entities on the Internet that are identified by a URI using standard Hypertext Transfer Protocol (HTTP) methods over a secure transport. A WebFinger resource returns a JavaScript Object Notation (JSON) object describing the entity that is queried. The JSON object is referred to as the JSON Resource Descriptor (JRD).', 'activitypub' ) . '</p>' .
'<p>' . \__( 'For a person, the type of information that might be discoverable via WebFinger includes a personal profile address, identity service, telephone number, or preferred avatar. For other entities on the Internet, a WebFinger resource might return JRDs containing link relations that enable a client to discover, for example, that a printer can print in color on A4 paper, the physical location of a server, or other static information.', 'activitypub' ) . '</p>' .
'<p>' . \__( 'On Mastodon [and other Plattforms], user profiles can be hosted either locally on the same website as yours, or remotely on a completely different website. The same username may be used on a different domain. Therefore, a Mastodon user\'s full mention consists of both the username and the domain, in the form <code>@username@domain</code>. In practical terms, <code>@user@example.com</code> is not the same as <code>@user@example.org</code>. If the domain is not included, Mastodon will try to find a local user named <code>@username</code>. However, in order to deliver to someone over ActivityPub, the <code>@username@domain</code> mention is not enough mentions must be translated to an HTTPS URI first, so that the remote actor\'s inbox and outbox can be found. (This paragraph is copied from the <a href="https://docs.joinmastodon.org/spec/webfinger/" target="_blank">Mastodon Documentation</a>)', 'activitypub' ) . '</p>' .
'<p>' . \__( 'For more informations please visit <a href="https://webfinger.net/" target="_blank">webfinger.net</a>', 'activitypub' ) . '</p>' .
'<p><h2>' . \__( 'NodeInfo', 'activitypub' ) . '</h2></p>' .
'<p>' . \__( 'NodeInfo is an effort to create a standardized way of exposing metadata about a server running one of the distributed social networks. The two key goals are being able to get better insights into the user base of distributed social networking and the ability to build tools that allow users to choose the best fitting software and server for their needs.', 'activitypub' ) . '</p>' .
'<p>' . \__( 'For more informations please visit <a href="http://nodeinfo.diaspora.software/" target="_blank">nodeinfo.diaspora.software</a>', 'activitypub' ) . '</p>',
)
);
\get_current_screen()->set_help_sidebar(
'<p><strong>' . \__( 'For more information:', 'activitypub' ) . '</strong></p>' .
'<p>' . \__( '<a href="https://wordpress.org/support/plugin/activitypub/">Get support</a>', 'activitypub' ) . '</p>' .
'<p>' . \__( '<a href="https://github.com/pfefferle/wordpress-activitypub/issues">Report an issue</a>', 'activitypub' ) . '</p>' .
'<hr />' .
'<p>' . \__( '<a href="https://notiz.blog/donate">Donate</a>', 'activitypub' ) . '</p>'
);

View File

@ -0,0 +1,126 @@
<?php
namespace Activitypub\Model;
/**
* ActivityPub Post Class
*
* @author Matthias Pfefferle
*
* @see https://www.w3.org/TR/activitypub/
*/
class Activity {
private $context = array( 'https://www.w3.org/ns/activitystreams' );
private $published = '';
private $id = '';
private $type = 'Create';
private $actor = '';
private $to = array( 'https://www.w3.org/ns/activitystreams#Public' );
private $cc = array( 'https://www.w3.org/ns/activitystreams#Public' );
private $object = null;
const TYPE_SIMPLE = 'simple';
const TYPE_FULL = 'full';
const TYPE_NONE = 'none';
public function __construct( $type = 'Create', $context = self::TYPE_SIMPLE ) {
if ( 'none' === $context ) {
$this->context = null;
} elseif ( 'full' === $context ) {
$this->context = \Activitypub\get_context();
}
$this->type = \ucfirst( $type );
$this->published = \gmdate( 'Y-m-d\TH:i:s\Z', \strtotime( 'now' ) );
}
public function __call( $method, $params ) {
$var = \strtolower( \substr( $method, 4 ) );
if ( \strncasecmp( $method, 'get', 3 ) === 0 ) {
return $this->$var;
}
if ( \strncasecmp( $method, 'set', 3 ) === 0 ) {
$this->$var = $params[0];
}
}
public function from_post( Post $post ) {
$this->object = $post->to_array();
if ( isset( $object['published'] ) ) {
$this->published = $object['published'];
}
$this->cc = array( \get_rest_url( null, '/activitypub/1.0/users/' . intval( $post->get_post_author() ) . '/followers' ) );
if ( isset( $this->object['attributedTo'] ) ) {
$this->actor = $this->object['attributedTo'];
}
foreach ( $post->get_tags() as $tag ) {
if ( 'Mention' === $tag['type'] ) {
$this->cc[] = $tag['href'];
}
}
$type = \strtolower( $this->type );
if ( isset( $this->object['id'] ) ) {
$this->id = add_query_arg( 'activity', $type, $this->object['id'] );
}
}
public function from_comment( $object ) {
}
public function to_comment() {
}
public function from_remote_array( $array ) {
}
public function to_array() {
$array = array_filter( \get_object_vars( $this ) );
if ( $this->context ) {
$array = array( '@context' => $this->context ) + $array;
}
unset( $array['context'] );
return $array;
}
/**
* Convert to JSON
*
* @return void
*/
public function to_json() {
return \wp_json_encode( $this->to_array(), \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT );
}
public function to_simple_array() {
$activity = array(
'@context' => $this->context,
'type' => $this->type,
'actor' => $this->actor,
'object' => $this->object,
'to' => $this->to,
'cc' => $this->cc,
);
if ( $this->id ) {
$activity['id'] = $this->id;
}
return $activity;
}
public function to_simple_json() {
return \wp_json_encode( $this->to_simple_array(), \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT );
}
}

View File

@ -0,0 +1,477 @@
<?php
namespace Activitypub\Model;
/**
* ActivityPub Post Class
*
* @author Matthias Pfefferle
*/
class Post {
/**
* The WordPress Post Object.
*
* @var WP_Post
*/
private $post;
/**
* The Post Author.
*
* @var string
*/
private $post_author;
/**
* The Object ID.
*
* @var string
*/
private $id;
/**
* The Object Summary.
*
* @var string
*/
private $summary;
/**
* The Object Summary
*
* @var string
*/
private $content;
/**
* The Object Attachments. This is usually a list of Images.
*
* @var array
*/
private $attachments;
/**
* The Object Tags. This is usually the list of used Hashtags.
*
* @var array
*/
private $tags;
/**
* The Onject Type
*
* @var string
*/
private $object_type;
/**
* The Allowed Tags, used in the content.
*
* @var array
*/
private $allowed_tags = array(
'a' => array(
'href' => array(),
'title' => array(),
'class' => array(),
'rel' => array(),
),
'br' => array(),
'p' => array(
'class' => array(),
),
'span' => array(
'class' => array(),
),
'div' => array(
'class' => array(),
),
'ul' => array(),
'ol' => array(),
'li' => array(),
'strong' => array(
'class' => array(),
),
'b' => array(
'class' => array(),
),
'i' => array(
'class' => array(),
),
'em' => array(
'class' => array(),
),
'blockquote' => array(),
'cite' => array(),
);
/**
* Constructor
*
* @param WP_Post $post
*/
public function __construct( $post ) {
$this->post = \get_post( $post );
}
/**
* Magic function to implement getter and setter
*
* @param string $method
* @param string $params
*
* @return void
*/
public function __call( $method, $params ) {
$var = \strtolower( \substr( $method, 4 ) );
if ( \strncasecmp( $method, 'get', 3 ) === 0 ) {
if ( empty( $this->$var ) && ! empty( $this->post->$var ) ) {
return $this->post->$var;
}
return $this->$var;
}
if ( \strncasecmp( $method, 'set', 3 ) === 0 ) {
$this->$var = $params[0];
}
}
/**
* Converts this Object into an Array.
*
* @return array
*/
public function to_array() {
$post = $this->post;
$array = array(
'id' => $this->get_id(),
'type' => $this->get_object_type(),
'published' => \gmdate( 'Y-m-d\TH:i:s\Z', \strtotime( $post->post_date_gmt ) ),
'attributedTo' => \get_author_posts_url( $post->post_author ),
'summary' => $this->get_summary(),
'inReplyTo' => null,
'content' => $this->get_content(),
'contentMap' => array(
\strstr( \get_locale(), '_', true ) => $this->get_content(),
),
'to' => array( 'https://www.w3.org/ns/activitystreams#Public' ),
'cc' => array( 'https://www.w3.org/ns/activitystreams#Public' ),
'attachment' => $this->get_attachments(),
'tag' => $this->get_tags(),
);
return \apply_filters( 'activitypub_post', $array, $this->post );
}
/**
* Converts this Object into a JSON String
*
* @return string
*/
public function to_json() {
return \wp_json_encode( $this->to_array(), \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT );
}
/**
* Returns the ID of an Activity Object
*
* @return string
*/
public function get_id() {
if ( $this->id ) {
return $this->id;
}
$post = $this->post;
if ( 'trash' === get_post_status( $post ) ) {
$permalink = \get_post_meta( $post->ID, 'activitypub_canonical_url', true );
} else {
$permalink = \get_permalink( $post );
}
$this->id = $permalink;
return $permalink;
}
/**
* Returns a list of Image Attachments
*
* @return array
*/
public function get_attachments() {
if ( $this->attachments ) {
return $this->attachments;
}
$max_images = intval( \apply_filters( 'activitypub_max_image_attachments', \get_option( 'activitypub_max_image_attachments', ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS ) ) );
$images = array();
// max images can't be negative or zero
if ( $max_images <= 0 ) {
return $images;
}
$id = $this->post->ID;
$image_ids = array();
// list post thumbnail first if this post has one
if ( \function_exists( 'has_post_thumbnail' ) && \has_post_thumbnail( $id ) ) {
$image_ids[] = \get_post_thumbnail_id( $id );
$max_images--;
}
if ( $max_images > 0 ) {
// then list any image attachments
$query = new \WP_Query(
array(
'post_parent' => $id,
'post_status' => 'inherit',
'post_type' => 'attachment',
'post_mime_type' => 'image',
'order' => 'ASC',
'orderby' => 'menu_order ID',
'posts_per_page' => $max_images,
)
);
foreach ( $query->get_posts() as $attachment ) {
if ( ! \in_array( $attachment->ID, $image_ids, true ) ) {
$image_ids[] = $attachment->ID;
}
}
}
$image_ids = \array_unique( $image_ids );
// get URLs for each image
foreach ( $image_ids as $id ) {
$alt = \get_post_meta( $id, '_wp_attachment_image_alt', true );
$thumbnail = \wp_get_attachment_image_src( $id, 'full' );
$mimetype = \get_post_mime_type( $id );
if ( $thumbnail ) {
$image = array(
'type' => 'Image',
'url' => $thumbnail[0],
'mediaType' => $mimetype,
);
if ( $alt ) {
$image['name'] = $alt;
}
$images[] = $image;
}
}
$this->attachments = $images;
return $images;
}
/**
* Returns a list of Tags, used in the Post
*
* @return array
*/
public function get_tags() {
if ( $this->tags ) {
return $this->tags;
}
$tags = array();
$post_tags = \get_the_tags( $this->post->ID );
if ( $post_tags ) {
foreach ( $post_tags as $post_tag ) {
$tag = array(
'type' => 'Hashtag',
'href' => \get_tag_link( $post_tag->term_id ),
'name' => '#' . $post_tag->slug,
);
$tags[] = $tag;
}
}
$mentions = apply_filters( 'activitypub_extract_mentions', array(), $this->post->post_content, $this );
if ( $mentions ) {
foreach ( $mentions as $mention => $url ) {
$tag = array(
'type' => 'Mention',
'href' => $url,
'name' => $mention,
);
$tags[] = $tag;
}
}
$this->tags = $tags;
return $tags;
}
/**
* Returns the as2 object-type for a given post
*
* @return string the object-type
*/
public function get_object_type() {
if ( $this->object_type ) {
return $this->object_type;
}
if ( 'wordpress-post-format' !== \get_option( 'activitypub_object_type', 'note' ) ) {
return \ucfirst( \get_option( 'activitypub_object_type', 'note' ) );
}
$post_type = \get_post_type( $this->post );
switch ( $post_type ) {
case 'post':
$post_format = \get_post_format( $this->post );
switch ( $post_format ) {
case 'aside':
case 'status':
case 'quote':
case 'note':
$object_type = 'Note';
break;
case 'gallery':
case 'image':
$object_type = 'Image';
break;
case 'video':
$object_type = 'Video';
break;
case 'audio':
$object_type = 'Audio';
break;
default:
$object_type = 'Article';
break;
}
break;
case 'page':
$object_type = 'Page';
break;
case 'attachment':
$mime_type = \get_post_mime_type();
$media_type = \preg_replace( '/(\/[a-zA-Z]+)/i', '', $mime_type );
switch ( $media_type ) {
case 'audio':
$object_type = 'Audio';
break;
case 'video':
$object_type = 'Video';
break;
case 'image':
$object_type = 'Image';
break;
}
break;
default:
$object_type = 'Article';
break;
}
$this->object_type = $object_type;
return $object_type;
}
/**
* Returns the content for the ActivityPub Item.
*
* @return string the content
*/
public function get_content() {
global $post;
if ( $this->content ) {
return $this->content;
}
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$post = $this->post;
$content = $this->get_post_content_template();
// Fill in the shortcodes.
setup_postdata( $post );
$content = do_shortcode( $content );
wp_reset_postdata();
$content = \wpautop( \wp_kses( $content, $this->allowed_tags ) );
$content = \trim( \preg_replace( '/[\n\r\t]/', '', $content ) );
$content = \apply_filters( 'activitypub_the_content', $content, $post );
$content = \html_entity_decode( $content, \ENT_QUOTES, 'UTF-8' );
$this->content = $content;
return $content;
}
/**
* Gets the template to use to generate the content of the activitypub item.
*
* @return string the template
*/
public function get_post_content_template() {
if ( 'excerpt' === \get_option( 'activitypub_post_content_type', 'content' ) ) {
return "[ap_excerpt]\n\n[ap_permalink type=\"html\"]";
}
if ( 'title' === \get_option( 'activitypub_post_content_type', 'content' ) ) {
return "[ap_title]\n\n[ap_permalink type=\"html\"]";
}
if ( 'content' === \get_option( 'activitypub_post_content_type', 'content' ) ) {
return "[ap_content]\n\n[ap_hashtags]\n\n[ap_permalink type=\"html\"]";
}
// Upgrade from old template codes to shortcodes.
$content = self::upgrade_post_content_template();
return $content;
}
/**
* Updates the custom template to use shortcodes instead of the deprecated templates.
*
* @return string the updated template content
*/
public static function upgrade_post_content_template() {
// Get the custom template.
$old_content = \get_option( 'activitypub_custom_post_content', ACTIVITYPUB_CUSTOM_POST_CONTENT );
// If the old content exists but is a blank string, we're going to need a flag to updated it even
// after setting it to the default contents.
$need_update = false;
// If the old contents is blank, use the defaults.
if ( '' === $old_content ) {
$old_content = ACTIVITYPUB_CUSTOM_POST_CONTENT;
$need_update = true;
}
// Set the new content to be the old content.
$content = $old_content;
// Convert old templates to shortcodes.
$content = \str_replace( '%title%', '[ap_title]', $content );
$content = \str_replace( '%excerpt%', '[ap_excerpt]', $content );
$content = \str_replace( '%content%', '[ap_content]', $content );
$content = \str_replace( '%permalink%', '[ap_permalink type="html"]', $content );
$content = \str_replace( '%shortlink%', '[ap_shortlink type="html"]', $content );
$content = \str_replace( '%hashtags%', '[ap_hashtags]', $content );
$content = \str_replace( '%tags%', '[ap_hashtags]', $content );
// Store the new template if required.
if ( $content !== $old_content || $need_update ) {
\update_option( 'activitypub_custom_post_content', $content );
}
return $content;
}
}

View File

@ -0,0 +1,84 @@
<?php
namespace Activitypub\Peer;
/**
* ActivityPub Followers DB-Class
*
* @author Matthias Pfefferle
*/
class Followers {
public static function get_followers( $author_id ) {
$followers = \get_user_option( 'activitypub_followers', $author_id );
if ( ! $followers ) {
return array();
}
foreach ( $followers as $key => $follower ) {
if (
\is_array( $follower ) &&
isset( $follower['type'] ) &&
'Person' === $follower['type'] &&
isset( $follower['id'] ) &&
false !== \filter_var( $follower['id'], \FILTER_VALIDATE_URL )
) {
$followers[ $key ] = $follower['id'];
}
}
return $followers;
}
public static function count_followers( $author_id ) {
$followers = self::get_followers( $author_id );
return \count( $followers );
}
public static function add_follower( $actor, $author_id ) {
$followers = \get_user_option( 'activitypub_followers', $author_id );
if ( ! \is_string( $actor ) ) {
if (
\is_array( $actor ) &&
isset( $actor['type'] ) &&
'Person' === $actor['type'] &&
isset( $actor['id'] ) &&
false !== \filter_var( $actor['id'], \FILTER_VALIDATE_URL )
) {
$actor = $actor['id'];
}
return new \WP_Error(
'invalid_actor_object',
\__( 'Unknown Actor schema', 'activitypub' ),
array(
'status' => 404,
)
);
}
if ( ! \is_array( $followers ) ) {
$followers = array( $actor );
} else {
$followers[] = $actor;
}
$followers = \array_unique( $followers );
\update_user_meta( $author_id, 'activitypub_followers', $followers );
}
public static function remove_follower( $actor, $author_id ) {
$followers = \get_user_option( 'activitypub_followers', $author_id );
foreach ( $followers as $key => $value ) {
if ( $value === $actor ) {
unset( $followers[ $key ] );
}
}
\update_user_meta( $author_id, 'activitypub_followers', $followers );
}
}

View File

@ -0,0 +1,67 @@
<?php
namespace Activitypub\Peer;
/**
* ActivityPub Users DB-Class
*
* @author Matthias Pfefferle
*/
class Users {
/**
* Undocumented function
*
* @return void
*/
public static function get_user_by_various( $data ) {
}
/**
* Examine a url and try to determine the author ID it represents.
*
* Checks are supposedly from the hosted site blog.
*
* @param string $url Permalink to check.
*
* @return int User ID, or 0 on failure.
*/
public static function url_to_authorid( $url ) {
global $wp_rewrite;
// check if url hase the same host
if ( \wp_parse_url( \site_url(), \PHP_URL_HOST ) !== \wp_parse_url( $url, \PHP_URL_HOST ) ) {
return 0;
}
// first, check to see if there is a 'author=N' to match against
if ( \preg_match( '/[?&]author=(\d+)/i', $url, $values ) ) {
$id = \absint( $values[1] );
if ( $id ) {
return $id;
}
}
// check to see if we are using rewrite rules
$rewrite = $wp_rewrite->wp_rewrite_rules();
// not using rewrite rules, and 'author=N' method failed, so we're out of options
if ( empty( $rewrite ) ) {
return 0;
}
// generate rewrite rule for the author url
$author_rewrite = $wp_rewrite->get_author_permastruct();
$author_regexp = \str_replace( '%author%', '', $author_rewrite );
// match the rewrite rule with the passed url
if ( \preg_match( '/https?:\/\/(.+)' . \preg_quote( $author_regexp, '/' ) . '([^\/]+)/i', $url, $match ) ) {
$user = \get_user_by( 'slug', $match[2] );
if ( $user ) {
return $user->ID;
}
}
return 0;
}
}

View File

@ -0,0 +1,111 @@
<?php
namespace Activitypub\Rest;
/**
* ActivityPub Followers REST-Class
*
* @author Matthias Pfefferle
*
* @see https://www.w3.org/TR/activitypub/#followers
*/
class Followers {
/**
* Initialize the class, registering WordPress hooks
*/
public static function init() {
\add_action( 'rest_api_init', array( '\Activitypub\Rest\Followers', 'register_routes' ) );
}
/**
* Register routes
*/
public static function register_routes() {
\register_rest_route(
'activitypub/1.0',
'/users/(?P<user_id>\d+)/followers',
array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array( '\Activitypub\Rest\Followers', 'get' ),
'args' => self::request_parameters(),
'permission_callback' => '__return_true',
),
)
);
}
/**
* Handle GET request
*
* @param WP_REST_Request $request
*
* @return WP_REST_Response
*/
public static function get( $request ) {
$user_id = $request->get_param( 'user_id' );
$user = \get_user_by( 'ID', $user_id );
if ( ! $user ) {
return new \WP_Error(
'rest_invalid_param',
\__( 'User not found', 'activitypub' ),
array(
'status' => 404,
'params' => array(
'user_id' => \__( 'User not found', 'activitypub' ),
),
)
);
}
/*
* Action triggerd prior to the ActivityPub profile being created and sent to the client
*/
\do_action( 'activitypub_outbox_pre' );
$json = new \stdClass();
$json->{'@context'} = \Activitypub\get_context();
$json->id = \home_url( \add_query_arg( null, null ) );
$json->generator = 'http://wordpress.org/?v=' . \get_bloginfo_rss( 'version' );
$json->actor = \get_author_posts_url( $user_id );
$json->type = 'OrderedCollectionPage';
$json->partOf = \get_rest_url( null, "/activitypub/1.0/users/$user_id/followers" ); // phpcs:ignore
$json->totalItems = \Activitypub\count_followers( $user_id ); // phpcs:ignore
$json->orderedItems = \Activitypub\Peer\Followers::get_followers( $user_id ); // phpcs:ignore
$json->first = $json->partOf; // phpcs:ignore
$json->first = \get_rest_url( null, "/activitypub/1.0/users/$user_id/followers" );
$response = new \WP_REST_Response( $json, 200 );
$response->header( 'Content-Type', 'application/activity+json' );
return $response;
}
/**
* The supported parameters
*
* @return array list of parameters
*/
public static function request_parameters() {
$params = array();
$params['page'] = array(
'type' => 'integer',
);
$params['user_id'] = array(
'required' => true,
'type' => 'integer',
'validate_callback' => function( $param, $request, $key ) {
return user_can( $param, 'publish_posts' );
},
);
return $params;
}
}

View File

@ -0,0 +1,109 @@
<?php
namespace Activitypub\Rest;
/**
* ActivityPub Following REST-Class
*
* @author Matthias Pfefferle
*
* @see https://www.w3.org/TR/activitypub/#following
*/
class Following {
/**
* Initialize the class, registering WordPress hooks
*/
public static function init() {
\add_action( 'rest_api_init', array( '\Activitypub\Rest\Following', 'register_routes' ) );
}
/**
* Register routes
*/
public static function register_routes() {
\register_rest_route(
'activitypub/1.0',
'/users/(?P<user_id>\d+)/following',
array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array( '\Activitypub\Rest\Following', 'get' ),
'args' => self::request_parameters(),
'permission_callback' => '__return_true',
),
)
);
}
/**
* Handle GET request
*
* @param WP_REST_Request $request
*
* @return WP_REST_Response
*/
public static function get( $request ) {
$user_id = $request->get_param( 'user_id' );
$user = \get_user_by( 'ID', $user_id );
if ( ! $user ) {
return new \WP_Error(
'rest_invalid_param',
\__( 'User not found', 'activitypub' ),
array(
'status' => 404,
'params' => array(
'user_id' => \__( 'User not found', 'activitypub' ),
),
)
);
}
/*
* Action triggerd prior to the ActivityPub profile being created and sent to the client
*/
\do_action( 'activitypub_outbox_pre' );
$json = new \stdClass();
$json->{'@context'} = \Activitypub\get_context();
$json->id = \home_url( \add_query_arg( null, null ) );
$json->generator = 'http://wordpress.org/?v=' . \get_bloginfo_rss( 'version' );
$json->actor = \get_author_posts_url( $user_id );
$json->type = 'OrderedCollectionPage';
$json->partOf = \get_rest_url( null, "/activitypub/1.0/users/$user_id/following" ); // phpcs:ignore
$json->totalItems = 0; // phpcs:ignore
$json->orderedItems = apply_filters( 'activitypub_following', array(), $user ); // phpcs:ignore
$json->first = $json->partOf; // phpcs:ignore
$response = new \WP_REST_Response( $json, 200 );
$response->header( 'Content-Type', 'application/activity+json' );
return $response;
}
/**
* The supported parameters
*
* @return array list of parameters
*/
public static function request_parameters() {
$params = array();
$params['page'] = array(
'type' => 'integer',
);
$params['user_id'] = array(
'required' => true,
'type' => 'integer',
'validate_callback' => function( $param, $request, $key ) {
return user_can( $param, 'publish_posts' );
},
);
return $params;
}
}

View File

@ -0,0 +1,564 @@
<?php
namespace Activitypub\Rest;
/**
* ActivityPub Inbox REST-Class
*
* @author Matthias Pfefferle
*
* @see https://www.w3.org/TR/activitypub/#inbox
*/
class Inbox {
/**
* Initialize the class, registering WordPress hooks
*/
public static function init() {
\add_action( 'rest_api_init', array( '\Activitypub\Rest\Inbox', 'register_routes' ) );
\add_filter( 'rest_pre_serve_request', array( '\Activitypub\Rest\Inbox', 'serve_request' ), 11, 4 );
\add_action( 'activitypub_inbox_follow', array( '\Activitypub\Rest\Inbox', 'handle_follow' ), 10, 2 );
\add_action( 'activitypub_inbox_undo', array( '\Activitypub\Rest\Inbox', 'handle_unfollow' ), 10, 2 );
//\add_action( 'activitypub_inbox_like', array( '\Activitypub\Rest\Inbox', 'handle_reaction' ), 10, 2 );
//\add_action( 'activitypub_inbox_announce', array( '\Activitypub\Rest\Inbox', 'handle_reaction' ), 10, 2 );
\add_action( 'activitypub_inbox_create', array( '\Activitypub\Rest\Inbox', 'handle_create' ), 10, 2 );
}
/**
* Register routes
*/
public static function register_routes() {
\register_rest_route(
'activitypub/1.0',
'/inbox',
array(
array(
'methods' => \WP_REST_Server::EDITABLE,
'callback' => array( '\Activitypub\Rest\Inbox', 'shared_inbox_post' ),
'args' => self::shared_inbox_post_parameters(),
'permission_callback' => '__return_true',
),
)
);
\register_rest_route(
'activitypub/1.0',
'/users/(?P<user_id>\d+)/inbox',
array(
array(
'methods' => \WP_REST_Server::EDITABLE,
'callback' => array( '\Activitypub\Rest\Inbox', 'user_inbox_post' ),
'args' => self::user_inbox_post_parameters(),
'permission_callback' => '__return_true',
),
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array( '\Activitypub\Rest\Inbox', 'user_inbox_get' ),
'args' => self::user_inbox_get_parameters(),
'permission_callback' => '__return_true',
),
)
);
}
/**
* Hooks into the REST API request to verify the signature.
*
* @param bool $served Whether the request has already been served.
* @param WP_HTTP_ResponseInterface $result Result to send to the client. Usually a WP_REST_Response.
* @param WP_REST_Request $request Request used to generate the response.
* @param WP_REST_Server $server Server instance.
*
* @return true
*/
public static function serve_request( $served, $result, $request, $server ) {
if ( '/activitypub' !== \substr( $request->get_route(), 0, 12 ) ) {
return $served;
}
$signature = $request->get_header( 'signature' );
if ( ! $signature ) {
return $served;
}
$headers = $request->get_headers();
// verify signature
//\Activitypub\Signature::verify_signature( $headers, $key );
return $served;
}
/**
* Renders the user-inbox
*
* @param WP_REST_Request $request
* @return WP_REST_Response
*/
public static function user_inbox_get( $request ) {
$user_id = $request->get_param( 'user_id' );
$page = $request->get_param( 'page', 0 );
/*
* Action triggerd prior to the ActivityPub profile being created and sent to the client
*/
\do_action( 'activitypub_inbox_pre' );
$json = new \stdClass();
$json->{'@context'} = \Activitypub\get_context();
$json->id = \home_url( \add_query_arg( null, null ) );
$json->generator = 'http://wordpress.org/?v=' . \get_bloginfo_rss( 'version' );
$json->type = 'OrderedCollectionPage';
$json->partOf = \get_rest_url( null, "/activitypub/1.0/users/$user_id/inbox" ); // phpcs:ignore
$json->totalItems = 0; // phpcs:ignore
$json->orderedItems = array(); // phpcs:ignore
$json->first = $json->partOf; // phpcs:ignore
// filter output
$json = \apply_filters( 'activitypub_inbox_array', $json );
/*
* Action triggerd after the ActivityPub profile has been created and sent to the client
*/
\do_action( 'activitypub_inbox_post' );
$response = new \WP_REST_Response( $json, 200 );
$response->header( 'Content-Type', 'application/activity+json' );
return $response;
}
/**
* Handles user-inbox requests
*
* @param WP_REST_Request $request
*
* @return WP_REST_Response
*/
public static function user_inbox_post( $request ) {
$user_id = $request->get_param( 'user_id' );
$data = $request->get_params();
$type = $request->get_param( 'type' );
$type = \strtolower( $type );
\do_action( 'activitypub_inbox', $data, $user_id, $type );
\do_action( "activitypub_inbox_{$type}", $data, $user_id );
return new \WP_REST_Response( array(), 202 );
}
/**
* The shared inbox
*
* @param WP_REST_Request $request
*
* @return WP_REST_Response
*/
public static function shared_inbox_post( $request ) {
$data = $request->get_params();
$type = $request->get_param( 'type' );
$users = self::extract_recipients( $data );
if ( ! $users ) {
return new \WP_Error(
'rest_invalid_param',
\__( 'No recipients found', 'activitypub' ),
array(
'status' => 404,
'params' => array(
'to' => \__( 'Please check/validate "to" field', 'activitypub' ),
'bto' => \__( 'Please check/validate "bto" field', 'activitypub' ),
'cc' => \__( 'Please check/validate "cc" field', 'activitypub' ),
'bcc' => \__( 'Please check/validate "bcc" field', 'activitypub' ),
'audience' => \__( 'Please check/validate "audience" field', 'activitypub' ),
),
)
);
}
foreach ( $users as $user ) {
$type = \strtolower( $type );
\do_action( 'activitypub_inbox', $data, $user->ID, $type );
\do_action( "activitypub_inbox_{$type}", $data, $user->ID );
}
return new \WP_REST_Response( array(), 202 );
}
/**
* The supported parameters
*
* @return array list of parameters
*/
public static function user_inbox_get_parameters() {
$params = array();
$params['page'] = array(
'type' => 'integer',
);
$params['user_id'] = array(
'required' => true,
'type' => 'integer',
'validate_callback' => function( $param, $request, $key ) {
return user_can( $param, 'publish_posts' );
},
);
return $params;
}
/**
* The supported parameters
*
* @return array list of parameters
*/
public static function user_inbox_post_parameters() {
$params = array();
$params['page'] = array(
'type' => 'integer',
);
$params['user_id'] = array(
'required' => true,
'type' => 'integer',
'validate_callback' => function( $param, $request, $key ) {
return user_can( $param, 'publish_posts' );
},
);
$params['id'] = array(
'required' => true,
'sanitize_callback' => 'esc_url_raw',
);
$params['actor'] = array(
'required' => true,
'sanitize_callback' => function( $param, $request, $key ) {
if ( ! \is_string( $param ) ) {
$param = $param['id'];
}
return \esc_url_raw( $param );
},
);
$params['type'] = array(
'required' => true,
//'type' => 'enum',
//'enum' => array( 'Create' ),
//'sanitize_callback' => function( $param, $request, $key ) {
// return \strtolower( $param );
//},
);
$params['object'] = array(
'required' => true,
);
return $params;
}
/**
* The supported parameters
*
* @return array list of parameters
*/
public static function shared_inbox_post_parameters() {
$params = array();
$params['page'] = array(
'type' => 'integer',
);
$params['id'] = array(
'required' => true,
'type' => 'string',
'sanitize_callback' => 'esc_url_raw',
);
$params['actor'] = array(
'required' => true,
//'type' => array( 'object', 'string' ),
'sanitize_callback' => function( $param, $request, $key ) {
if ( ! \is_string( $param ) ) {
$param = $param['id'];
}
return \esc_url_raw( $param );
},
);
$params['type'] = array(
'required' => true,
//'type' => 'enum',
//'enum' => array( 'Create' ),
//'sanitize_callback' => function( $param, $request, $key ) {
// return \strtolower( $param );
//},
);
$params['object'] = array(
'required' => true,
//'type' => 'object',
);
$params['to'] = array(
'required' => false,
'sanitize_callback' => function( $param, $request, $key ) {
if ( \is_string( $param ) ) {
$param = array( $param );
}
return $param;
},
);
$params['cc'] = array(
'sanitize_callback' => function( $param, $request, $key ) {
if ( \is_string( $param ) ) {
$param = array( $param );
}
return $param;
},
);
$params['bcc'] = array(
'sanitize_callback' => function( $param, $request, $key ) {
if ( \is_string( $param ) ) {
$param = array( $param );
}
return $param;
},
);
return $params;
}
/**
* Handles "Follow" requests
*
* @param array $object The activity-object
* @param int $user_id The id of the local blog-user
*/
public static function handle_follow( $object, $user_id ) {
// save follower
\Activitypub\Peer\Followers::add_follower( $object['actor'], $user_id );
// get inbox
$inbox = \Activitypub\get_inbox_by_actor( $object['actor'] );
// send "Accept" activity
$activity = new \Activitypub\Model\Activity( 'Accept', \Activitypub\Model\Activity::TYPE_SIMPLE );
$activity->set_object( $object );
$activity->set_actor( \get_author_posts_url( $user_id ) );
$activity->set_to( $object['actor'] );
$activity->set_id( \get_author_posts_url( $user_id ) . '#follow-' . \preg_replace( '~^https?://~', '', $object['actor'] ) );
$activity = $activity->to_simple_json();
$response = \Activitypub\safe_remote_post( $inbox, $activity, $user_id );
}
/**
* Handles "Unfollow" requests
*
* @param array $object The activity-object
* @param int $user_id The id of the local blog-user
*/
public static function handle_unfollow( $object, $user_id ) {
if ( isset( $object['object'] ) && isset( $object['object']['type'] ) && 'Follow' === $object['object']['type'] ) {
\Activitypub\Peer\Followers::remove_follower( $object['actor'], $user_id );
}
}
/**
* Handles "Reaction" requests
*
* @param array $object The activity-object
* @param int $user_id The id of the local blog-user
*/
public static function handle_reaction( $object, $user_id ) {
$meta = \Activitypub\get_remote_metadata_by_actor( $object['actor'] );
$comment_post_id = \url_to_postid( $object['object'] );
// save only replys and reactions
if ( ! $comment_post_id ) {
return false;
}
$commentdata = array(
'comment_post_ID' => $comment_post_id,
'comment_author' => \esc_attr( $meta['name'] ),
'comment_author_email' => '',
'comment_author_url' => \esc_url_raw( $object['actor'] ),
'comment_content' => \esc_url_raw( $object['actor'] ),
'comment_type' => \esc_attr( \strtolower( $object['type'] ) ),
'comment_parent' => 0,
'comment_meta' => array(
'source_url' => \esc_url_raw( $object['id'] ),
'avatar_url' => \esc_url_raw( $meta['icon']['url'] ),
'protocol' => 'activitypub',
),
);
// disable flood control
\remove_action( 'check_comment_flood', 'check_comment_flood_db', 10 );
// do not require email for AP entries
\add_filter( 'pre_option_require_name_email', '__return_false' );
$state = \wp_new_comment( $commentdata, true );
\remove_filter( 'pre_option_require_name_email', '__return_false' );
// re-add flood control
\add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 );
}
/**
* Handles "Create" requests
*
* @param array $object The activity-object
* @param int $user_id The id of the local blog-user
*/
public static function handle_create( $object, $user_id ) {
$meta = \Activitypub\get_remote_metadata_by_actor( $object['actor'] );
if ( ! isset( $object['object']['inReplyTo'] ) ) {
return;
}
// check if Activity is public or not
if ( ! self::is_activity_public( $object ) ) {
// @todo maybe send email
return;
}
$comment_post_id = \url_to_postid( $object['object']['inReplyTo'] );
// save only replys and reactions
if ( ! $comment_post_id ) {
return false;
}
$commentdata = array(
'comment_post_ID' => $comment_post_id,
'comment_author' => \esc_attr( $meta['name'] ),
'comment_author_url' => \esc_url_raw( $object['actor'] ),
'comment_content' => \wp_filter_kses( $object['object']['content'] ),
'comment_type' => '',
'comment_author_email' => '',
'comment_parent' => 0,
'comment_meta' => array(
'source_url' => \esc_url_raw( $object['object']['url'] ),
'avatar_url' => \esc_url_raw( $meta['icon']['url'] ),
'protocol' => 'activitypub',
),
);
// disable flood control
\remove_action( 'check_comment_flood', 'check_comment_flood_db', 10 );
// do not require email for AP entries
\add_filter( 'pre_option_require_name_email', '__return_false' );
$state = \wp_new_comment( $commentdata, true );
\remove_filter( 'pre_option_require_name_email', '__return_false' );
// re-add flood control
\add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 );
}
/**
* Extract recipient URLs from Activity object
*
* @param array $data
*
* @return array The list of user URLs
*/
public static function extract_recipients( $data ) {
$recipient_items = array();
foreach ( array( 'to', 'bto', 'cc', 'bcc', 'audience' ) as $i ) {
if ( array_key_exists( $i, $data ) ) {
if ( is_array( $data[ $i ] ) ) {
$recipient = $data[ $i ];
} else {
$recipient = array( $data[ $i ] );
}
$recipient_items = array_merge( $recipient_items, $recipient );
}
if ( array_key_exists( $i, $data['object'] ) ) {
if ( is_array( $data['object'][ $i ] ) ) {
$recipient = $data['object'][ $i ];
} else {
$recipient = array( $data['object'][ $i ] );
}
$recipient_items = array_merge( $recipient_items, $recipient );
}
}
$recipients = array();
// flatten array
foreach ( $recipient_items as $recipient ) {
if ( is_array( $recipient ) ) {
// check if recipient is an object
if ( array_key_exists( 'id', $recipient ) ) {
$recipients[] = $recipient['id'];
}
} else {
$recipients[] = $recipient;
}
}
return array_unique( $recipients );
}
/**
* Get local user recipients
*
* @param array $data
*
* @return array The list of local users
*/
public static function get_recipients( $data ) {
$recipients = self::extract_recipients( $data );
$users = array();
foreach ( $recipients as $recipient ) {
$user_id = \Activitypub\url_to_authorid( $recipient );
$user = get_user_by( 'id', $user_id );
if ( $user ) {
$users[] = $user;
}
}
return $users;
}
/**
* Check if passed Activity is Public
*
* @param array $data
* @return boolean
*/
public static function is_activity_public( $data ) {
$recipients = self::extract_recipients( $data );
return in_array( 'https://www.w3.org/ns/activitystreams#Public', $recipients, true );
}
}

View File

@ -0,0 +1,203 @@
<?php
namespace Activitypub\Rest;
/**
* ActivityPub NodeInfo REST-Class
*
* @author Matthias Pfefferle
*
* @see http://nodeinfo.diaspora.software/
*/
class Nodeinfo {
/**
* Initialize the class, registering WordPress hooks
*/
public static function init() {
\add_action( 'rest_api_init', array( '\Activitypub\Rest\Nodeinfo', 'register_routes' ) );
\add_filter( 'nodeinfo_data', array( '\Activitypub\Rest\Nodeinfo', 'add_nodeinfo_discovery' ), 10, 2 );
\add_filter( 'nodeinfo2_data', array( '\Activitypub\Rest\Nodeinfo', 'add_nodeinfo2_discovery' ), 10 );
}
/**
* Register routes
*/
public static function register_routes() {
\register_rest_route(
'activitypub/1.0',
'/nodeinfo/discovery',
array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array( '\Activitypub\Rest\Nodeinfo', 'discovery' ),
'permission_callback' => '__return_true',
),
)
);
\register_rest_route(
'activitypub/1.0',
'/nodeinfo',
array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array( '\Activitypub\Rest\Nodeinfo', 'nodeinfo' ),
'permission_callback' => '__return_true',
),
)
);
\register_rest_route(
'activitypub/1.0',
'/nodeinfo2',
array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array( '\Activitypub\Rest\Nodeinfo', 'nodeinfo2' ),
'permission_callback' => '__return_true',
),
)
);
}
/**
* Render NodeInfo file
*
* @param WP_REST_Request $request
*
* @return WP_REST_Response
*/
public static function nodeinfo( $request ) {
$nodeinfo = array();
$nodeinfo['version'] = '2.0';
$nodeinfo['software'] = array(
'name' => 'wordpress',
'version' => \get_bloginfo( 'version' ),
);
$users = \count_users();
$posts = \wp_count_posts();
$comments = \wp_count_comments();
$nodeinfo['usage'] = array(
'users' => array(
'total' => (int) $users['total_users'],
),
'localPosts' => (int) $posts->publish,
'localComments' => (int) $comments->approved,
);
$nodeinfo['openRegistrations'] = false;
$nodeinfo['protocols'] = array( 'activitypub' );
$nodeinfo['services'] = array(
'inbound' => array(),
'outbound' => array(),
);
return new \WP_REST_Response( $nodeinfo, 200 );
}
/**
* Render NodeInfo file
*
* @param WP_REST_Request $request
*
* @return WP_REST_Response
*/
public static function nodeinfo2( $request ) {
$nodeinfo = array();
$nodeinfo['version'] = '1.0';
$nodeinfo['server'] = array(
'baseUrl' => \home_url( '/' ),
'name' => \get_bloginfo( 'name' ),
'software' => 'wordpress',
'version' => \get_bloginfo( 'version' ),
);
$users = \get_users(
array(
'capability__in' => array( 'publish_posts' ),
)
);
if ( is_array( $users ) ) {
$users = count( $users );
} else {
$users = 1;
}
$posts = \wp_count_posts();
$comments = \wp_count_comments();
$nodeinfo['usage'] = array(
'users' => array(
'total' => (int) $users,
),
'localPosts' => (int) $posts->publish,
'localComments' => (int) $comments->approved,
);
$nodeinfo['openRegistrations'] = false;
$nodeinfo['protocols'] = array( 'activitypub' );
$nodeinfo['services'] = array(
'inbound' => array(),
'outbound' => array(),
);
return new \WP_REST_Response( $nodeinfo, 200 );
}
/**
* Render NodeInfo discovery file
*
* @param WP_REST_Request $request
*
* @return WP_REST_Response
*/
public static function discovery( $request ) {
$discovery = array();
$discovery['links'] = array(
array(
'rel' => 'http://nodeinfo.diaspora.software/ns/schema/2.0',
'href' => \get_rest_url( null, 'activitypub/1.0/nodeinfo' ),
),
);
return new \WP_REST_Response( $discovery, 200 );
}
/**
* Extend NodeInfo data
*
* @param array $nodeinfo NodeInfo data
* @param string The NodeInfo Version
*
* @return array The extended array
*/
public static function add_nodeinfo_discovery( $nodeinfo, $version ) {
if ( '2.0' === $version ) {
$nodeinfo['protocols'][] = 'activitypub';
} else {
$nodeinfo['protocols']['inbound'][] = 'activitypub';
$nodeinfo['protocols']['outbound'][] = 'activitypub';
}
return $nodeinfo;
}
/**
* Extend NodeInfo2 data
*
* @param array $nodeinfo NodeInfo2 data
*
* @return array The extended array
*/
public static function add_nodeinfo2_discovery( $nodeinfo ) {
$nodeinfo['protocols'][] = 'activitypub';
return $nodeinfo;
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace Activitypub\Rest;
/**
* ActivityPub OStatus REST-Class
*
* @author Matthias Pfefferle
*
* @see https://www.w3.org/community/ostatus/
*/
class Ostatus {
/**
* Register routes
*/
public static function register_routes() {
\register_rest_route(
'activitypub/1.0',
'/ostatus/remote-follow',
array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array( '\Activitypub\Rest\Ostatus', 'get' ),
// 'args' => self::request_parameters(),
'permission_callback' => '__return_true',
),
)
);
}
public static function get() {
// @todo implement
}
}

View File

@ -0,0 +1,148 @@
<?php
namespace Activitypub\Rest;
/**
* ActivityPub Outbox REST-Class
*
* @author Matthias Pfefferle
*
* @see https://www.w3.org/TR/activitypub/#outbox
*/
class Outbox {
/**
* Initialize the class, registering WordPress hooks
*/
public static function init() {
\add_action( 'rest_api_init', array( '\Activitypub\Rest\Outbox', 'register_routes' ) );
}
/**
* Register routes
*/
public static function register_routes() {
\register_rest_route(
'activitypub/1.0',
'/users/(?P<user_id>\d+)/outbox',
array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array( '\Activitypub\Rest\Outbox', 'user_outbox_get' ),
'args' => self::request_parameters(),
'permission_callback' => '__return_true',
),
)
);
}
/**
* Renders the user-outbox
*
* @param WP_REST_Request $request
* @return WP_REST_Response
*/
public static function user_outbox_get( $request ) {
$user_id = $request->get_param( 'user_id' );
$author = \get_user_by( 'ID', $user_id );
$post_types = \get_option( 'activitypub_support_post_types', array( 'post', 'page' ) );
if ( ! $author ) {
return new \WP_Error(
'rest_invalid_param',
\__( 'User not found', 'activitypub' ),
array(
'status' => 404,
'params' => array(
'user_id' => \__( 'User not found', 'activitypub' ),
),
)
);
}
$page = $request->get_param( 'page', 0 );
/*
* Action triggerd prior to the ActivityPub profile being created and sent to the client
*/
\do_action( 'activitypub_outbox_pre' );
$json = new \stdClass();
$json->{'@context'} = \Activitypub\get_context();
$json->id = \home_url( \add_query_arg( null, null ) );
$json->generator = 'http://wordpress.org/?v=' . \get_bloginfo_rss( 'version' );
$json->actor = \get_author_posts_url( $user_id );
$json->type = 'OrderedCollectionPage';
$json->partOf = \get_rest_url( null, "/activitypub/1.0/users/$user_id/outbox" ); // phpcs:ignore
$json->totalItems = 0; // phpcs:ignore
// phpcs:ignore
$json->totalItems = 0;
foreach ( $post_types as $post_type ) {
$count_posts = \wp_count_posts( $post_type );
$json->totalItems += \intval( $count_posts->publish ); // phpcs:ignore
}
$json->first = \add_query_arg( 'page', 1, $json->partOf ); // phpcs:ignore
$json->last = \add_query_arg( 'page', \ceil ( $json->totalItems / 10 ), $json->partOf ); // phpcs:ignore
if ( $page && ( ( \ceil ( $json->totalItems / 10 ) ) > $page ) ) { // phpcs:ignore
$json->next = \add_query_arg( 'page', $page + 1, $json->partOf ); // phpcs:ignore
}
if ( $page ) {
$posts = \get_posts(
array(
'posts_per_page' => 10,
'author' => $user_id,
'offset' => ( $page - 1 ) * 10,
'post_type' => $post_types,
)
);
foreach ( $posts as $post ) {
$activitypub_post = new \Activitypub\Model\Post( $post );
$activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_NONE );
$activitypub_activity->from_post( $activitypub_post );
$json->orderedItems[] = $activitypub_activity->to_array(); // phpcs:ignore
}
}
// filter output
$json = \apply_filters( 'activitypub_outbox_array', $json );
/*
* Action triggerd after the ActivityPub profile has been created and sent to the client
*/
\do_action( 'activitypub_outbox_post' );
$response = new \WP_REST_Response( $json, 200 );
$response->header( 'Content-Type', 'application/activity+json' );
return $response;
}
/**
* The supported parameters
*
* @return array list of parameters
*/
public static function request_parameters() {
$params = array();
$params['page'] = array(
'type' => 'integer',
);
$params['user_id'] = array(
'required' => true,
'type' => 'integer',
'validate_callback' => function( $param, $request, $key ) {
return user_can( $param, 'publish_posts' );
},
);
return $params;
}
}

View File

@ -0,0 +1,121 @@
<?php
namespace Activitypub\Rest;
/**
* ActivityPub WebFinger REST-Class
*
* @author Matthias Pfefferle
*
* @see https://webfinger.net/
*/
class Webfinger {
/**
* Initialize the class, registering WordPress hooks
*/
public static function init() {
\add_action( 'rest_api_init', array( '\Activitypub\Rest\Webfinger', 'register_routes' ) );
\add_action( 'webfinger_user_data', array( '\Activitypub\Rest\Webfinger', 'add_webfinger_discovery' ), 10, 3 );
}
/**
* Register routes
*/
public static function register_routes() {
\register_rest_route(
'activitypub/1.0',
'/webfinger',
array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array( '\Activitypub\Rest\Webfinger', 'webfinger' ),
'args' => self::request_parameters(),
'permission_callback' => '__return_true',
),
)
);
}
/**
* Render JRD file
*
* @param WP_REST_Request $request
* @return WP_REST_Response
*/
public static function webfinger( $request ) {
$resource = $request->get_param( 'resource' );
if ( \strpos( $resource, '@' ) === false ) {
return new \WP_Error( 'activitypub_unsupported_resource', \__( 'Resource is invalid', 'activitypub' ), array( 'status' => 400 ) );
}
$resource = \str_replace( 'acct:', '', $resource );
$resource_identifier = \substr( $resource, 0, \strrpos( $resource, '@' ) );
$resource_host = \substr( \strrchr( $resource, '@' ), 1 );
if ( \wp_parse_url( \home_url( '/' ), \PHP_URL_HOST ) !== $resource_host ) {
return new \WP_Error( 'activitypub_wrong_host', \__( 'Resource host does not match blog host', 'activitypub' ), array( 'status' => 404 ) );
}
$user = \get_user_by( 'login', \esc_sql( $resource_identifier ) );
if ( ! $user || ! user_can( $user, 'publish_posts' ) ) {
return new \WP_Error( 'activitypub_user_not_found', \__( 'User not found', 'activitypub' ), array( 'status' => 404 ) );
}
$json = array(
'subject' => $resource,
'aliases' => array(
\get_author_posts_url( $user->ID ),
),
'links' => array(
array(
'rel' => 'self',
'type' => 'application/activity+json',
'href' => \get_author_posts_url( $user->ID ),
),
array(
'rel' => 'http://webfinger.net/rel/profile-page',
'type' => 'text/html',
'href' => \get_author_posts_url( $user->ID ),
),
),
);
return new \WP_REST_Response( $json, 200 );
}
/**
* The supported parameters
*
* @return array list of parameters
*/
public static function request_parameters() {
$params = array();
$params['resource'] = array(
'required' => true,
'type' => 'string',
'pattern' => '^acct:(.+)@(.+)$',
);
return $params;
}
/**
* Add WebFinger discovery links
*
* @param array $array the jrd array
* @param string $resource the WebFinger resource
* @param WP_User $user the WordPress user
*/
public static function add_webfinger_discovery( $array, $resource, $user ) {
$array['links'][] = array(
'rel' => 'self',
'type' => 'application/activity+json',
'href' => \get_author_posts_url( $user->ID ),
);
return $array;
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Activitypub\Table;
if ( ! \class_exists( '\WP_List_Table' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}
class Followers_List extends \WP_List_Table {
public function get_columns() {
return array(
'identifier' => \__( 'Identifier', 'activitypub' ),
);
}
public function get_sortable_columns() {
return array();
}
public function prepare_items() {
$columns = $this->get_columns();
$hidden = array();
$this->process_action();
$this->_column_headers = array( $columns, $hidden, $this->get_sortable_columns() );
$this->items = array();
foreach ( \Activitypub\Peer\Followers::get_followers( \get_current_user_id() ) as $follower ) {
$this->items[]['identifier'] = \esc_attr( $follower );
}
}
public function column_default( $item, $column_name ) {
return $item[ $column_name ];
}
}

View File

@ -0,0 +1,58 @@
<?php
namespace Activitypub\Integration;
class Buddypress {
public static function init() {
\add_filter( 'activitypub_json_author_array', array( 'Activitypub\Integration\Buddypress', 'add_user_metadata' ), 11, 2 );
}
public static function add_user_metadata( $object, $author_id ) {
$object->url = bp_core_get_user_domain( $author_id ); //add BP member profile URL as user URL
// add BuddyPress' cover_image instead of WordPress' header_image
$cover_image_url = bp_attachments_get_attachment( 'url', array( 'item_id' => $author_id ) );
if ( $cover_image_url ) {
$object->image = array(
'type' => 'Image',
'url' => $cover_image_url,
);
}
// change profile URL to BuddyPress' profile URL
$object->attachment['profile_url'] = array(
'type' => 'PropertyValue',
'name' => \__( 'Profile', 'activitypub' ),
'value' => \html_entity_decode(
'<a rel="me" title="' . \esc_attr( bp_core_get_user_domain( $author_id ) ) . '" target="_blank" href="' . \bp_core_get_user_domain( $author_id ) . '">' . \wp_parse_url( \bp_core_get_user_domain( $author_id ), \PHP_URL_HOST ) . '</a>',
\ENT_QUOTES,
'UTF-8'
),
);
// replace blog URL on multisite
if ( is_multisite() ) {
$user_blogs = get_blogs_of_user( $author_id ); //get sites of user to send as AP metadata
if ( ! empty( $user_blogs ) ) {
unset( $object->attachment['blog_url'] );
foreach ( $user_blogs as $blog ) {
if ( 1 !== $blog->userblog_id ) {
$object->attachment[] = array(
'type' => 'PropertyValue',
'name' => $blog->blogname,
'value' => \html_entity_decode(
'<a rel="me" title="' . \esc_attr( $blog->siteurl ) . '" target="_blank" href="' . $blog->siteurl . '">' . \wp_parse_url( $blog->siteurl, \PHP_URL_HOST ) . '</a>',
\ENT_QUOTES,
'UTF-8'
),
);
}
}
}
}
return $object;
}
}

View File

@ -0,0 +1,386 @@
=== ActivityPub ===
Contributors: pfefferle, mediaformat, akirk, automattic
Tags: OStatus, fediverse, activitypub, activitystream
Requires at least: 4.7
Tested up to: 6.1
Stable tag: 0.17.0
Requires PHP: 5.6
License: MIT
License URI: http://opensource.org/licenses/MIT
The ActivityPub protocol is a decentralized social networking protocol based upon the ActivityStreams 2.0 data format.
== Description ==
This is **BETA** software, see the FAQ to see the current feature set or rather what is still planned.
The plugin implements the ActivityPub protocol for your blog. Your readers will be able to follow your blogposts on Mastodon and other federated platforms that support ActivityPub.
The plugin works with the following federated platforms:
* [Mastodon](https://joinmastodon.org/)
* [Pleroma](https://pleroma.social/)
* [Friendica](https://friendi.ca/)
* [HubZilla](https://hubzilla.org/)
* [Pixelfed](https://pixelfed.org/)
* [SocialHome](https://socialhome.network/)
* [Misskey](https://join.misskey.page/)
== Frequently Asked Questions ==
= What is the status of this plugin? =
Implemented:
* profile pages (JSON representation)
* custom links
* functional inbox/outbox
* follow (accept follows)
* share posts
* receive comments/reactions
To implement:
* signature verification
* better WordPress integration
* better configuration possibilities
* threaded comments support
= What is "ActivityPub for WordPress" =
*ActivityPub for WordPress* extends WordPress with some Fediverse features, but it does not compete with platforms like Friendica or Mastodon. If you want to run a **decentralized social network**, please use [Mastodon](https://joinmastodon.org/) or [GNU social](https://gnusocial.network/).
= What are the differences between this plugin and Pterotype? =
**Compatibility**
*ActivityPub for WordPress* is compatible with OStatus and IndieWeb plugin suites. *Pterotype* is incompatible with the standalone [WebFinger plugin](https://wordpress.org/plugins/webfinger/), so it can't be run together with OStatus.
**Custom tables**
*Pterotype* creates/uses a bunch of custom tables, *ActivityPub for WordPress* only uses the native tables and adds as little meta data as possible.
= What if you are running your blog in a subdirectory? =
In order for webfinger to work, it must be mapped to the root directory of the URL on which your blog resides.
**Apache**
Add the following to the .htaccess file in the root directory:
RedirectMatch "^\/\.well-known(.*)$" "\/blog\/\.well-known$1"
Where 'blog' is the path to the subdirectory at which your blog resides.
**Nginx**
Add the following to the site.conf in sites-available:
location ~* /.well-known {
allow all;
try_files $uri $uri/ /blog/?$args;
}
Where 'blog' is the path to the subdirectory at which your blog resides.
== Changelog ==
Project maintained on GitHub at [pfefferle/wordpress-activitypub](https://github.com/pfefferle/wordpress-activitypub).
= 0.17.0 =
* Fix type-selector
* Allow more HTML elements in Activity-Objects
= 0.16.5 =
* Return empty content/excerpt on password protected posts/pages
= 0.16.4 =
* Remove scripts later in the queue, to also handle scripts added by blocks
* Add published date to author profiles
= 0.16.3 =
* "cc", "to", ... fields can either be an array or a string
* Remove "style" and "script" HTML elements from content
= 0.16.2 =
* Fix fatal error in outbox
= 0.16.1 =
* Fix "update and create, posts appear blank on Mastodon" issue
= 0.16.0 =
* Add "Outgoing Mentions" ([#213](https://github.com/pfefferle/wordpress-activitypub/pull/213)) props [@akirk](https://github.com/akirk)
* Add configuration item for number of images to attach ([#248](https://github.com/pfefferle/wordpress-activitypub/pull/248)) props [@mexon](https://github.com/mexon)
* Use shortcodes instead of custom templates, to setup the Activity Post-Content ([#250](https://github.com/pfefferle/wordpress-activitypub/pull/250)) props [@toolstack](https://github.com/toolstack)
* Remove custom REST Server, because the needed changes are now merged into Core.
* Fix hashtags ([#261](https://github.com/pfefferle/wordpress-activitypub/pull/261)) props [@akirk](https://github.com/akirk)
* Change priorites, to maybe fix the hashtag issue
= 0.15.0 =
* Enable ActivityPub only for users that can `publish_posts`
* Persist only public Activities
* Fix remote-delete
= 0.14.3 =
* Better error handling. props [@akirk](https://github.com/akirk)
= 0.14.2 =
* Fix Critical error when using Friends Plugin and adding new URL to follow. props [@akirk](https://github.com/akirk)
= 0.14.1 =
* Fix "WebFinger not compatible with PHP < 8.0". props [@mexon](https://github.com/mexon)
= 0.14.0 =
* Friends support: https://wordpress.org/plugins/friends/ props [@akirk](https://github.com/akirk)
* Massive guidance improvements. props [mediaformat](https://github.com/mediaformat) & [@akirk](https://github.com/akirk)
* Add Custom Post Type support to outbox API. props [blueset](https://github.com/blueset)
* Better hash-tag support. props [bocops](https://github.com/bocops)
* Fix user-count (NodeInfo). props [mediaformat](https://github.com/mediaformat)
= 0.13.4 =
* fix webfinger for email identifiers
= 0.13.3 =
* fix: Create and Note should not have the same ActivityPub ID
= 0.13.2 =
* fix Follow issue AGAIN
= 0.13.1 =
* fix Inbox issue
= 0.13.0 =
* add Autor URL and WebFinger health checks
* fix NodeInfo endpoint
= 0.12.0 =
* use "pre_option_require_name_email" filter instead of "check_comment_flood". props [@akirk](https://github.com/akirk)
* save only comments/replies
* check for an explicit "undo -> follow" action. see https://wordpress.org/support/topic/qs-after-latest/
= 0.11.2 =
* fix inconsistent `%tags%` placeholder
= 0.11.1 =
* fix follow/unfollow actions
= 0.11.0 =
* add support for customizable post-content
* first try of a delete activity
* do not require email for AP entries. props [@akirk](https://github.com/akirk)
* fix [timezones](https://github.com/pfefferle/wordpress-activitypub/issues/63) bug. props [@mediaformat](https://github.com/mediaformat)
* fix [digest header](https://github.com/pfefferle/wordpress-activitypub/issues/104) bug. props [@mediaformat](https://github.com/mediaformat)
= 0.10.1 =
* fix inbox activities, like follow
* fix debug
= 0.10.0 =
* add image alt text to the ActivityStreams attachment property in a format that Mastodon can read. props [@BenLubar](https://github.com/BenLubar)
* use the "summary" property for a title as Mastodon does. props [@BenLubar](https://github.com/BenLubar)
* support authorized fetch to avoid having comments from "Anonymous". props [@BenLubar](https://github.com/BenLubar)
* add new post type: "title and link only". props [@bgcarlisle](https://github.com/bgcarlisle)
= 0.9.1 =
* disable shared inbox
* disable delete activity
= 0.9.0 =
* some code refactorings
* fix #73
= 0.8.3 =
* fixed accept header bug
= 0.8.2 =
* add all required accept header
* better/simpler accept-header handling
* add debugging mechanism
* Add setting to enable AP for different (public) Post-Types
* explicit use of global functions
= 0.8.1 =
* fixed PHP warnings
= 0.8.0 =
* Moved followers list to user-menu
= 0.7.4 =
* added admin_email to metadata, to be able to "Manage your instance" on https://fediverse.network/manage/
= 0.7.3 =
* refactorings
* fixed PHP warnings
* better hashtag regex
= 0.7.2 =
* fixed JSON representation of posts https://merveilles.town/@xuv/101907542498716956
= 0.7.1 =
* fixed inbox problems with pleroma
= 0.7.0 =
* finally fixed pleroma compatibility
* added "following" endpoint
* simplified "followers" endpoint
* fixed default value problem
= 0.6.0 =
* add tags as hashtags to the end of each activity
* fixed pleroma following issue
* followers-list improvements
= 0.5.1 =
* fixed name-collision that caused an infinite loop
= 0.5.0 =
* complete refactoring
* fixed bug #30: Password-protected posts are federated
* only send Activites when ActivityPub is enabled for this post-type
= 0.4.4 =
* show avatars
= 0.4.3 =
* finally fixed backlink in excerpt/summary posts
= 0.4.2 =
* fixed backlink in excerpt/summary posts (thanks @depone)
= 0.4.1 =
* finally fixed contact list
= 0.4.0 =
* added settings to enable/disable hashtag support
* fixed follower list
* send activities only for new posts, otherwise send updates
= 0.3.2 =
* added "followers" endpoint
* change activity content from blog 'excerpt' to blog 'content'
= 0.3.1 =
* better json encoding
= 0.3.0 =
* basic hashtag support
* temporarily deactivated likes and boosts
* added support for actor objects
* fixed encoding issue
= 0.2.1 =
* customizable backlink (permalink or shorturl)
* show profile-identifiers also on profile settings
= 0.2.0 =
* added option to switch between content and excerpt
* removed html and duplicate new-lines
= 0.1.1 =
* fixed "excerpt" in AS JSON
* added settings for the activity-summary and for the activity-object-type
= 0.1.0 =
* added basic WebFinger support
* added basic NodeInfo support
* fully functional "follow" activity
* send new posts to your followers
* receive comments from your followers
= 0.0.2 =
* refactoring
* functional inbox
* nicer profile views
= 0.0.1 =
* initial
== Installation ==
Follow the normal instructions for [installing WordPress plugins](https://wordpress.org/support/article/managing-plugins/).
= Automatic Plugin Installation =
To add a WordPress Plugin using the [built-in plugin installer](https://codex.wordpress.org/Administration_Screens#Add_New_Plugins):
1. Go to [Plugins](https://codex.wordpress.org/Administration_Screens#Plugins) > [Add New](https://codex.wordpress.org/Plugins_Add_New_Screen).
1. Type "`activitypub`" into the **Search Plugins** box.
1. Find the WordPress Plugin you wish to install.
1. Click **Details** for more information about the Plugin and instructions you may wish to print or save to help setup the Plugin.
1. Click **Install Now** to install the WordPress Plugin.
1. The resulting installation screen will list the installation as successful or note any problems during the install.
1. If successful, click **Activate Plugin** to activate it, or **Return to Plugin Installer** for further actions.
= Manual Plugin Installation =
There are a few cases when manually installing a WordPress Plugin is appropriate.
* If you wish to control the placement and the process of installing a WordPress Plugin.
* If your server does not permit automatic installation of a WordPress Plugin.
* If you want to try the [latest development version](https://github.com/pfefferle/wordpress-activitypub).
Installation of a WordPress Plugin manually requires FTP familiarity and the awareness that you may put your site at risk if you install a WordPress Plugin incompatible with the current version or from an unreliable source.
Backup your site completely before proceeding.
To install a WordPress Plugin manually:
* Download your WordPress Plugin to your desktop.
* Download from [the WordPress directory](https://wordpress.org/plugins/activitypub/)
* Download from [GitHub](https://github.com/pfefferle/wordpress-activitypub/releases)
* If downloaded as a zip archive, extract the Plugin folder to your desktop.
* With your FTP program, upload the Plugin folder to the `wp-content/plugins` folder in your WordPress directory online.
* Go to [Plugins screen](https://codex.wordpress.org/Administration_Screens#Plugins) and find the newly uploaded Plugin in the list.
* Click **Activate** to activate it.

View File

@ -0,0 +1,16 @@
<div class="activitypub-settings-header">
<div class="activitypub-settings-title-section">
<h1><?php \esc_html_e( 'ActivityPub', 'activitypub' ); ?></h1>
</div>
<nav class="activitypub-settings-tabs-wrapper hide-if-no-js" aria-label="<?php \esc_attr_e( 'Secondary menu', 'activitypub' ); ?>">
<a href="<?php echo \esc_url_raw( admin_url( 'options-general.php?page=activitypub' ) ); ?>" class="activitypub-settings-tab <?php echo \esc_attr( $args['welcome'] ); ?>">
<?php \esc_html_e( 'Welcome', 'activitypub' ); ?>
</a>
<a href="<?php echo \esc_url_raw( admin_url( 'options-general.php?page=activitypub&tab=settings' ) ); ?>" class="activitypub-settings-tab <?php echo \esc_attr( $args['settings'] ); ?>">
<?php \esc_html_e( 'Settings', 'activitypub' ); ?>
</a>
</nav>
</div>
<hr class="wp-header-end">

View File

@ -0,0 +1,112 @@
<?php
$author_id = \get_the_author_meta( 'ID' );
$json = new \stdClass();
$json->{'@context'} = \Activitypub\get_context();
$json->id = \get_author_posts_url( $author_id );
$json->type = 'Person';
$json->name = \get_the_author_meta( 'display_name', $author_id );
$json->summary = \html_entity_decode(
\get_the_author_meta( 'description', $author_id ),
\ENT_QUOTES,
'UTF-8'
);
$json->preferredUsername = \get_the_author_meta( 'login', $author_id ); // phpcs:ignore
$json->url = \get_author_posts_url( $author_id );
$json->icon = array(
'type' => 'Image',
'url' => \get_avatar_url( $author_id, array( 'size' => 120 ) ),
);
$json->published = \gmdate( 'Y-m-d\TH:i:s\Z', \strtotime( \get_the_author_meta( 'registered', $author_id ) ) );
if ( \has_header_image() ) {
$json->image = array(
'type' => 'Image',
'url' => \get_header_image(),
);
}
$json->inbox = \get_rest_url( null, "/activitypub/1.0/users/$author_id/inbox" );
$json->outbox = \get_rest_url( null, "/activitypub/1.0/users/$author_id/outbox" );
$json->followers = \get_rest_url( null, "/activitypub/1.0/users/$author_id/followers" );
$json->following = \get_rest_url( null, "/activitypub/1.0/users/$author_id/following" );
$json->manuallyApprovesFollowers = \apply_filters( 'activitypub_json_manually_approves_followers', \__return_false() ); // phpcs:ignore
// phpcs:ignore
$json->publicKey = array(
'id' => \get_author_posts_url( $author_id ) . '#main-key',
'owner' => \get_author_posts_url( $author_id ),
'publicKeyPem' => \trim( \Activitypub\Signature::get_public_key( $author_id ) ),
);
$json->tag = array();
$json->attachment = array();
$json->attachment['blog_url'] = array(
'type' => 'PropertyValue',
'name' => \__( 'Blog', 'activitypub' ),
'value' => \html_entity_decode(
'<a rel="me" title="' . \esc_attr( \home_url( '/' ) ) . '" target="_blank" href="' . \home_url( '/' ) . '">' . \wp_parse_url( \home_url( '/' ), \PHP_URL_HOST ) . '</a>',
\ENT_QUOTES,
'UTF-8'
),
);
$json->attachment['profile_url'] = array(
'type' => 'PropertyValue',
'name' => \__( 'Profile', 'activitypub' ),
'value' => \html_entity_decode(
'<a rel="me" title="' . \esc_attr( \get_author_posts_url( $author_id ) ) . '" target="_blank" href="' . \get_author_posts_url( $author_id ) . '">' . \wp_parse_url( \get_author_posts_url( $author_id ), \PHP_URL_HOST ) . '</a>',
\ENT_QUOTES,
'UTF-8'
),
);
if ( \get_the_author_meta( 'user_url', $author_id ) ) {
$json->attachment['user_url'] = array(
'type' => 'PropertyValue',
'name' => \__( 'Website', 'activitypub' ),
'value' => \html_entity_decode(
'<a rel="me" title="' . \esc_attr( \get_the_author_meta( 'user_url', $author_id ) ) . '" target="_blank" href="' . \get_the_author_meta( 'user_url', $author_id ) . '">' . \wp_parse_url( \get_the_author_meta( 'user_url', $author_id ), \PHP_URL_HOST ) . '</a>',
\ENT_QUOTES,
'UTF-8'
),
);
}
// filter output
$json = \apply_filters( 'activitypub_json_author_array', $json, $author_id );
// migrate to ActivityPub standard
$json->attachment = array_values( $json->attachment );
/*
* Action triggerd prior to the ActivityPub profile being created and sent to the client
*/
\do_action( 'activitypub_json_author_pre', $author_id );
$options = 0;
// JSON_PRETTY_PRINT added in PHP 5.4
if ( \get_query_var( 'pretty' ) ) {
$options |= \JSON_PRETTY_PRINT; // phpcs:ignore
}
$options |= \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT;
/*
* Options to be passed to json_encode()
*
* @param int $options The current options flags
*/
$options = \apply_filters( 'activitypub_json_author_options', $options, $author_id );
\header( 'Content-Type: application/activity+json' );
echo \wp_json_encode( $json, $options );
/*
* Action triggerd after the ActivityPub profile has been created and sent to the client
*/
\do_action( 'activitypub_json_author_post', $author_id );

View File

@ -0,0 +1,86 @@
<?php
$json = new \stdClass();
$json->{'@context'} = \Activitypub\get_context();
$json->id = \get_home_url( '/' );
$json->type = 'Organization';
$json->name = \get_bloginfo( 'name' );
$json->summary = \html_entity_decode(
\get_bloginfo( 'description' ),
\ENT_QUOTES,
'UTF-8'
);
$json->preferredUsername = \get_bloginfo( 'name' ); // phpcs:ignore
$json->url = \get_home_url( '/' );
if ( \has_site_icon() ) {
$json->icon = array(
'type' => 'Image',
'url' => \get_site_icon_url( 120 ),
);
}
if ( \has_header_image() ) {
$json->image = array(
'type' => 'Image',
'url' => \get_header_image(),
);
}
$json->inbox = \get_rest_url( null, '/activitypub/1.0/blog/inbox' );
$json->outbox = \get_rest_url( null, '/activitypub/1.0/blog/outbox' );
$json->followers = \get_rest_url( null, '/activitypub/1.0/blog/followers' );
$json->following = \get_rest_url( null, '/activitypub/1.0/blog/following' );
$json->manuallyApprovesFollowers = \apply_filters( 'activitypub_json_manually_approves_followers', \__return_false() ); // phpcs:ignore
// phpcs:ignore
$json->publicKey = array(
'id' => \get_home_url( '/' ) . '#main-key',
'owner' => \get_home_url( '/' ),
'publicKeyPem' => '',
);
$json->tag = array();
$json->attachment = array();
$json->attachment[] = array(
'type' => 'PropertyValue',
'name' => \__( 'Blog', 'activitypub' ),
'value' => \html_entity_decode(
'<a rel="me" title="' . \esc_attr( \home_url( '/' ) ) . '" target="_blank" href="' . \home_url( '/' ) . '">' . \wp_parse_url( \home_url( '/' ), \PHP_URL_HOST ) . '</a>',
\ENT_QUOTES,
'UTF-8'
),
);
// filter output
$json = \apply_filters( 'activitypub_json_blog_array', $json );
/*
* Action triggerd prior to the ActivityPub profile being created and sent to the client
*/
\do_action( 'activitypub_json_blog_pre' );
$options = 0;
// JSON_PRETTY_PRINT added in PHP 5.4
if ( \get_query_var( 'pretty' ) ) {
$options |= \JSON_PRETTY_PRINT; // phpcs:ignore
}
$options |= \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT;
/*
* Options to be passed to json_encode()
*
* @param int $options The current options flags
*/
$options = \apply_filters( 'activitypub_json_blog_options', $options );
\header( 'Content-Type: application/activity+json' );
echo \wp_json_encode( $json, $options );
/*
* Action triggerd after the ActivityPub profile has been created and sent to the client
*/
\do_action( 'activitypub_json_blog_post' );

View File

@ -0,0 +1,16 @@
<div class="wrap">
<h1><?php \esc_html_e( 'Followers (Fediverse)', 'activitypub' ); ?></h1>
<?php // translators: ?>
<p><?php \printf( \esc_html__( 'You currently have %s followers.', 'activitypub' ), \esc_attr( \Activitypub\Peer\Followers::count_followers( \get_current_user_id() ) ) ); ?></p>
<?php $token_table = new \Activitypub\Table\Followers_List(); ?>
<form method="get">
<input type="hidden" name="page" value="indieauth_user_token" />
<?php
$token_table->prepare_items();
$token_table->display();
?>
</form>
</div>

View File

@ -0,0 +1,37 @@
<?php
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$post = \get_post();
$activitypub_post = new \Activitypub\Model\Post( $post );
$json = \array_merge( array( '@context' => \Activitypub\get_context() ), $activitypub_post->to_array() );
// filter output
$json = \apply_filters( 'activitypub_json_post_array', $json );
/*
* Action triggerd prior to the ActivityPub profile being created and sent to the client
*/
\do_action( 'activitypub_json_post_pre' );
$options = 0;
// JSON_PRETTY_PRINT added in PHP 5.4
if ( \get_query_var( 'pretty' ) ) {
$options |= \JSON_PRETTY_PRINT; // phpcs:ignore
}
$options |= \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT;
/*
* Options to be passed to json_encode()
*
* @param int $options The current options flags
*/
$options = \apply_filters( 'activitypub_json_post_options', $options );
\header( 'Content-Type: application/activity+json' );
echo \wp_json_encode( $json, $options );
/*
* Action triggerd after the ActivityPub profile has been created and sent to the client
*/
\do_action( 'activitypub_json_post_post' );

View File

@ -0,0 +1,182 @@
<?php
\load_template(
\dirname( __FILE__ ) . '/admin-header.php',
true,
array(
'settings' => 'active',
'welcome' => '',
)
);
?>
<div class="privacy-settings-body hide-if-no-js">
<div class="notice notice-info">
<p>
<?php
echo \wp_kses(
\sprintf(
// translators:
\__( 'If you have problems using this plugin, please check the <a href="%s">Site Health</a> to ensure that your site is compatible and/or use the "Help" tab (in the top right of the settings pages).', 'activitypub' ),
\esc_url_raw( \admin_url( 'site-health.php' ) )
),
'default'
);
?>
</p>
</div>
<p><?php \esc_html_e( 'Customize your ActivityPub settings to suit your needs.', 'activitypub' ); ?></p>
<form method="post" action="options.php">
<?php \settings_fields( 'activitypub' ); ?>
<h3><?php \esc_html_e( 'Activities', 'activitypub' ); ?></h3>
<p><?php \esc_html_e( 'All activity related settings.', 'activitypub' ); ?></p>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<?php \esc_html_e( 'Post-Content', 'activitypub' ); ?>
</th>
<td>
<p>
<label><input type="radio" name="activitypub_post_content_type" id="activitypub_post_content_type_title_link" value="title" <?php echo \checked( 'title', \get_option( 'activitypub_post_content_type', 'content' ) ); ?> /> <?php \esc_html_e( 'Title and link', 'activitypub' ); ?></label> - <span class="description"><?php \esc_html_e( 'Only the title and a link.', 'activitypub' ); ?></span>
</p>
<p>
<label><input type="radio" name="activitypub_post_content_type" id="activitypub_post_content_type_excerpt" value="excerpt" <?php echo \checked( 'excerpt', \get_option( 'activitypub_post_content_type', 'content' ) ); ?> /> <?php \esc_html_e( 'Excerpt', 'activitypub' ); ?></label> - <span class="description"><?php \esc_html_e( 'A content summary, shortened to 400 characters and without markup.', 'activitypub' ); ?></span>
</p>
<p>
<label><input type="radio" name="activitypub_post_content_type" id="activitypub_post_content_type_content" value="content" <?php echo \checked( 'content', \get_option( 'activitypub_post_content_type', 'content' ) ); ?> /> <?php \esc_html_e( 'Content (default)', 'activitypub' ); ?></label> - <span class="description"><?php \esc_html_e( 'The full content.', 'activitypub' ); ?></span>
</p>
<p>
<label><input type="radio" name="activitypub_post_content_type" id="activitypub_post_content_type_custom" value="custom" <?php echo \checked( 'custom', \get_option( 'activitypub_post_content_type', 'content' ) ); ?> /> <?php \esc_html_e( 'Custom', 'activitypub' ); ?></label> - <span class="description"><?php \esc_html_e( 'Use the text-area below, to customize your activities.', 'activitypub' ); ?></span>
</p>
<p>
<textarea name="activitypub_custom_post_content" id="activitypub_custom_post_content" rows="10" cols="50" class="large-text" placeholder="<?php echo wp_kses( ACTIVITYPUB_CUSTOM_POST_CONTENT, 'post' ); ?>"><?php echo wp_kses( \get_option( 'activitypub_custom_post_content', ACTIVITYPUB_CUSTOM_POST_CONTENT ), 'post' ); ?></textarea>
<details>
<summary><?php esc_html_e( 'See a list of ActivityPub Template Tags.', 'activitypub' ); ?></summary>
<div class="description">
<ul>
<li><code>[ap_title]</code> - <?php \esc_html_e( 'The post\'s title.', 'activitypub' ); ?></li>
<li><code>[ap_content]</code> - <?php \esc_html_e( 'The post\'s content.', 'activitypub' ); ?></li>
<li><code>[ap_excerpt]</code> - <?php \esc_html_e( 'The post\'s excerpt (default 400 chars).', 'activitypub' ); ?></li>
<li><code>[ap_permalink]</code> - <?php \esc_html_e( 'The post\'s permalink.', 'activitypub' ); ?></li>
<li><code>[ap_shortlink]</code> - <?php echo \wp_kses( \__( 'The post\'s shortlink. I can recommend <a href="https://wordpress.org/plugins/hum/" target="_blank">Hum</a>.', 'activitypub' ), 'default' ); ?></li>
<li><code>[ap_hashtags]</code> - <?php \esc_html_e( 'The post\'s tags as hashtags.', 'activitypub' ); ?></li>
<li><code>[ap_hashcats]</code> - <?php \esc_html_e( 'The post\'s categories as hashtags.', 'activitypub' ); ?></li>
<li><code>[ap_image]</code> - <?php \esc_html_e( 'The URL for the post\'s featured image.', 'activitypub' ); ?></li>
</ul>
<p><?php \esc_html_e( 'You can find the full list with all possible attributes in the help section on the top-right of the screen.', 'activitypub' ); ?></p>
</div>
</details>
</p>
</td>
</tr>
<tr>
<th scope="row">
<?php \esc_html_e( 'Number of images', 'activitypub' ); ?>
</th>
<td>
<input value="<?php echo esc_attr( \get_option( 'activitypub_max_image_attachments', ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS ) ); ?>" name="activitypub_max_image_attachments" id="activitypub_max_image_attachments" type="number" min="0" />
<p class="description">
<?php
echo \wp_kses(
\sprintf(
// translators:
\__( 'The number of images to attach to posts. Default: <code>%s</code>', 'activitypub' ),
\esc_html( ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS )
),
'default'
);
?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<?php \esc_html_e( 'Activity-Object-Type', 'activitypub' ); ?>
</th>
<td>
<p>
<label><input type="radio" name="activitypub_object_type" id="activitypub_object_type_note" value="note" <?php echo \checked( 'note', \get_option( 'activitypub_object_type', 'note' ) ); ?> /> <?php \esc_html_e( 'Note (default)', 'activitypub' ); ?></label> - <span class="description"><?php \esc_html_e( 'Should work with most platforms.', 'activitypub' ); ?></span>
</p>
<p>
<label><input type="radio" name="activitypub_object_type" id="activitypub_object_type_article" value="article" <?php echo \checked( 'article', \get_option( 'activitypub_object_type', 'note' ) ); ?> /> <?php \esc_html_e( 'Article', 'activitypub' ); ?></label> - <span class="description"><?php \esc_html_e( 'The presentation of the "Article" might change on different platforms. Mastodon for example shows the "Article" type as a simple link.', 'activitypub' ); ?></span>
</p>
<p>
<label><input type="radio" name="activitypub_object_type" id="activitypub_object_type" value="wordpress-post-format" <?php echo \checked( 'wordpress-post-format', \get_option( 'activitypub_object_type', 'note' ) ); ?> /> <?php \esc_html_e( 'WordPress Post-Format', 'activitypub' ); ?></label> - <span class="description"><?php \esc_html_e( 'Maps the WordPress Post-Format to the ActivityPub Object Type.', 'activitypub' ); ?></span>
</p>
</td>
</tr>
<tr>
<th scope="row"><?php \esc_html_e( 'Supported post types', 'activitypub' ); ?></th>
<td>
<fieldset>
<?php \esc_html_e( 'Enable ActivityPub support for the following post types:', 'activitypub' ); ?>
<?php $post_types = \get_post_types( array( 'public' => true ), 'objects' ); ?>
<?php $support_post_types = \get_option( 'activitypub_support_post_types', array( 'post', 'page' ) ) ? \get_option( 'activitypub_support_post_types', array( 'post', 'page' ) ) : array(); ?>
<ul>
<?php // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited ?>
<?php foreach ( $post_types as $post_type ) { ?>
<li>
<input type="checkbox" id="activitypub_support_post_types" name="activitypub_support_post_types[]" value="<?php echo \esc_attr( $post_type->name ); ?>" <?php echo \checked( true, \in_array( $post_type->name, $support_post_types, true ) ); ?> />
<label for="<?php echo \esc_attr( $post_type->name ); ?>"><?php echo \esc_html( $post_type->label ); ?></label>
</li>
<?php } ?>
</ul>
</fieldset>
</td>
</tr>
<tr>
<th scope="row">
<?php \esc_html_e( 'Hashtags (beta)', 'activitypub' ); ?>
</th>
<td>
<p>
<label><input type="checkbox" name="activitypub_use_hashtags" id="activitypub_use_hashtags" value="1" <?php echo \checked( '1', \get_option( 'activitypub_use_hashtags', '1' ) ); ?> /> <?php echo wp_kses( \__( 'Add hashtags in the content as native tags and replace the <code>#tag</code> with the tag-link. <strong>This feature is experimental! Please disable it, if you find any HTML or CSS errors.</strong>', 'activitypub' ), 'default' ); ?></label>
</p>
</td>
</tr>
</tbody>
</table>
<?php \do_settings_fields( 'activitypub', 'activity' ); ?>
<h3><?php \esc_html_e( 'Server', 'activitypub' ); ?></h3>
<p><?php \esc_html_e( 'Server related settings.', 'activitypub' ); ?></p>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<?php \esc_html_e( 'Blocklist', 'activitypub' ); ?>
</th>
<td>
<p class="description">
<?php
echo \wp_kses(
\sprintf(
// translators: %s is a URL.
\__( 'To block servers, add the host of the server to the "<a href="%s">Disallowed Comment Keys</a>" list.', 'activitypub' ),
\esc_attr( \admin_url( 'options-discussion.php#disallowed_keys' ) )
),
'default'
);
?>
</p>
</td>
</tr>
</tbody>
</table>
<?php \do_settings_fields( 'activitypub', 'server' ); ?>
<?php \do_settings_sections( 'activitypub' ); ?>
<?php \submit_button(); ?>
</form>
</div>

View File

@ -0,0 +1,96 @@
<?php
\load_template(
\dirname( __FILE__ ) . '/admin-header.php',
true,
array(
'settings' => '',
'welcome' => 'active',
)
);
?>
<div class="privacy-settings-body hide-if-no-js">
<h2><?php \esc_html_e( 'Welcome', 'activitypub' ); ?></h2>
<p><?php \esc_html_e( 'With ActivityPub your blog becomes part of a federated social network. This means you can share and talk to everyone using the ActivityPub protocol, including users of Friendica, Pleroma and Mastodon.', 'activitypub' ); ?></p>
<p>
<?php
echo wp_kses(
\sprintf(
// translators:
\__(
'People can follow you by using the username <code>%1$s</code> or the URL <code>%2$s</code>. Users who can not access this settings page will find their username on the <a href="%3$s">Edit Profile</a> page.',
'activitypub'
),
\esc_attr( \Activitypub\get_webfinger_resource( wp_get_current_user()->ID ) ),
\esc_url_raw( \get_author_posts_url( wp_get_current_user()->ID ) ),
\esc_url_raw( \admin_url( 'profile.php#activitypub' ) )
),
'default'
);
?>
</p>
<p>
<?php
echo wp_kses(
\sprintf(
// translators:
\__( 'If you have problems using this plugin, please check the <a href="%s">Site Health</a> to ensure that your site is compatible and/or use the "Help" tab (in the top right of the settings pages).', 'activitypub' ),
\esc_url_raw( admin_url( 'site-health.php' ) )
),
'default'
);
?>
</p>
<hr />
<h3><?php \esc_html_e( 'Recommended Plugins', 'activitypub' ); ?></h3>
<p><?php \esc_html_e( 'ActivityPub works as is and there is no need for you to install additional plugins, nevertheless there are some plugins that extends the functionality of ActivityPub.', 'activitypub' ); ?></p>
<div class="activitypub-settings-accordion">
<h4 class="activitypub-settings-accordion-heading">
<button aria-expanded="true" class="activitypub-settings-accordion-trigger" aria-controls="activitypub-settings-accordion-block-friends-plugin" type="button">
<span class="title"><?php \esc_html_e( 'Following Others', 'activitypub' ); ?></span>
<span class="icon"></span>
</button>
</h4>
<div id="activitypub-settings-accordion-block-friends-plugin" class="activitypub-settings-accordion-panel plugin-card-friends">
<p><?php \esc_html_e( 'To follow people on Mastodon or similar platforms using your own WordPress, you can use the Friends Plugin for WordPress which uses this plugin to receive posts and display them on your own WordPress, thus making your own WordPress a Fediverse instance of its own.', 'activitypub' ); ?></p>
<p><a href="<?php echo \esc_url_raw( \admin_url( 'plugin-install.php?tab=plugin-information&plugin=friends&TB_iframe=true' ) ); ?>" class="thickbox open-plugin-details-modal button install-now" target="_blank"><?php \esc_html_e( 'Install the Friends Plugin for WordPress', 'activitypub' ); ?></a></p>
</div>
<h4 class="activitypub-settings-accordion-heading">
<button aria-expanded="false" class="activitypub-settings-accordion-trigger" aria-controls="activitypub-settings-accordion-block-activitypub-hum-plugin" type="button">
<span class="title"><?php \esc_html_e( 'Add a URL Shortener', 'activitypub' ); ?></span>
<span class="icon"></span>
</button>
</h4>
<div id="activitypub-settings-accordion-block-activitypub-hum-plugin" class="activitypub-settings-accordion-panel plugin-card-hum" hidden="hidden">
<p><?php \esc_html_e( 'Hum is a personal URL shortener for WordPress, designed to provide short URLs to your personal content, both hosted on WordPress and elsewhere.', 'activitypub' ); ?></p>
<p><a href="<?php echo \esc_url_raw( \admin_url( 'plugin-install.php?tab=plugin-information&plugin=hum&TB_iframe=true' ) ); ?>" class="thickbox open-plugin-details-modal button install-now" target="_blank"><?php \esc_html_e( 'Install Hum Plugin for WordPress', 'activitypub' ); ?></a></p>
</div>
<h4 class="activitypub-settings-accordion-heading">
<button aria-expanded="false" class="activitypub-settings-accordion-trigger" aria-controls="activitypub-settings-accordion-block-activitypub-webfinger-plugin" type="button">
<span class="title"><?php \esc_html_e( 'Advanced WebFinger Support', 'activitypub' ); ?></span>
<span class="icon"></span>
</button>
</h4>
<div id="activitypub-settings-accordion-block-activitypub-webfinger-plugin" class="activitypub-settings-accordion-panel plugin-card-webfinger" hidden="hidden">
<p><?php \esc_html_e( 'WebFinger is a protocol that allows for discovery of information about people and things identified by a URI. Information about a person might be discovered via an "acct:" URI, for example, which is a URI that looks like an email address.', 'activitypub' ); ?></p>
<p><?php \esc_html_e( 'The ActivityPub plugin comes with basic WebFinger support, if you need more configuration options and compatibility with other Fediverse/IndieWeb plugins, please install the WebFinger plugin.', 'activitypub' ); ?></p>
<p><a href="<?php echo \esc_url_raw( \admin_url( 'plugin-install.php?tab=plugin-information&plugin=webfinger&TB_iframe=true' ) ); ?>" class="thickbox open-plugin-details-modal button install-now" target="_blank"><?php \esc_html_e( 'Install WebFinger Plugin for WordPress', 'activitypub' ); ?></a></p>
</div>
<h4 class="activitypub-settings-accordion-heading">
<button aria-expanded="false" class="activitypub-settings-accordion-trigger" aria-controls="activitypub-settings-accordion-block-activitypub-nodeinfo-plugin" type="button">
<span class="title"><?php \esc_html_e( 'Provide Enhanced Information about Your Blog', 'activitypub' ); ?></span>
<span class="icon"></span>
</button>
</h4>
<div id="activitypub-settings-accordion-block-activitypub-nodeinfo-plugin" class="activitypub-settings-accordion-panel plugin-card-nodeinfo" hidden="hidden">
<p><?php \esc_html_e( 'NodeInfo is an effort to create a standardized way of exposing metadata about a server running one of the distributed social networks. The two key goals are being able to get better insights into the user base of distributed social networking and the ability to build tools that allow users to choose the best fitting software and server for their needs.', 'activitypub' ); ?></p>
<p><?php \esc_html_e( 'The ActivityPub plugin comes with a simple NodeInfo endpoint. If you need more configuration options and compatibility with other Fediverse plugins, please install the NodeInfo plugin.', 'activitypub' ); ?></p>
<p><a href="<?php echo \esc_url_raw( \admin_url( 'plugin-install.php?tab=plugin-information&plugin=nodeinfo&TB_iframe=true' ) ); ?>" class="thickbox open-plugin-details-modal button install-now" target="_blank"><?php \esc_html_e( 'Install NodeInfo Plugin for WordPress', 'activitypub' ); ?></a></p>
</div>
</div>
</div>

View File

@ -0,0 +1,7 @@
Copyright <YEAR> <COPYRIGHT HOLDER>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,95 @@
# authLDAP
[![Join the chat at https://gitter.im/heiglandreas/authLdap](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/heiglandreas/authLdap?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Use your existing LDAP as authentication-backend for your wordpress!
[![Build Status](https://travis-ci.org/heiglandreas/authLdap.svg?branch=master)](https://travis-ci.org/heiglandreas/authLdap)
[![WordPress Stats](https://img.shields.io/wordpress/plugin/dt/authldap.svg)](https://wordpress.org/plugins/authldap/stats/)
[![WordPress Version](https://img.shields.io/wordpress/plugin/v/authldap.svg)](https://wordpress.org/plugins/authldap/)
[![WordPress testet](https://img.shields.io/wordpress/v/authldap.svg)](https://wordpress.org/plugins/authldap/)
[![Code Climate](https://codeclimate.com/github/heiglandreas/authLdap/badges/gpa.svg)](https://codeclimate.com/github/heiglandreas/authLdap)
[![Test Coverage](https://codeclimate.com/github/heiglandreas/authLdap/badges/coverage.svg)](https://codeclimate.com/github/heiglandreas/authLdap)
So what are the differences to other Wordpress-LDAP-Authentication-Plugins?
* **Flexible**: You are totaly free in which LDAP-backend to use. Due to the extensive configuration you can
freely decide how to do the authentication of your users. It simply depends on your
filters
* **Independent**: As soon as a user logs in, it is added/updated to the Wordpress' user-database
to allow wordpress to always use the correct data. You only have to administer your users once.
* **Failsafe**: Due to the users being created in Wordpress' User-database they can
also log in when the LDAP-backend currently is gone.
* **Role-Aware**: You can map Wordpress' roles to values of an existing LDAP-attribute.
## How does the plugin work?
Well, as a matter of fact it is rather simple. The plugin verifies, that the user
seeking authentification can bind to the LDAP using the provided password.
If that is so, the user is either created or updated in the wordpress-user-database.
This update includes the provided password (so the wordpress can authenticate users
even without the LDAP), the users name according to the authLDAP-preferences and
the status of the user depending on the groups-settings of the authLDAP-preferences
Writing this plugin would not have been as easy as it has been, without the
wonderfull plugin of Alistair Young from http://www.weblogs.uhi.ac.uk/sm00ay/?p=45
## Configuration
### Usage Settings
* **Enable Authentication via LDAP** Whether you want to enable authLdap for login or not
* **debug authLdap** When you have problems with authentication via LDAP you can enable a debugging mode here.
* **Save entered Password** Decide whether passwords will be cached in your wordpress-installation. **Attention:** Without the cache your users will not be able to log into your site when your LDAP is down!
### Server Settings
* **LDAP Uri** This is the URI where your ldap-backend can be reached. More information are actually on the Configuration page
* **Filter** This is the real McCoy! The filter you define here specifies how a user will be found. Before applying the filter a %s will be replaced with the given username. This means, when a user logs in using foobar as username the following happens:
* **uid=%1$s** check for any LDAP-Entry that has an attribute uid with value foobar
* **(&(objectclass=posixAccount)(|(uid=%1$s)(mail=%1$s)))** check for any LDAP-Entry that has an attribute objectclass with value posixAccout and either a UID- or a mail-attribute with value foobar
This filter is rather powerfull if used wisely.
### Creating Users
* **Name-Attribute** Which Attribute from the LDAP contains the Full or the First name of the user trying to log in. This defaults to name
* **Second Name Attribute** If the above Name-Attribute only contains the First Name of the user you can here specify an Attribute that contains the second name. This field is empty by default
* **User-ID Attribute** This field will be used as login-name for wordpress. Please give the Attribute, that is used to identify the user. This should be the same as you used in the above Filter-Option. This field defaults to uid
* **Mail Attribute** Which Attribute holds the eMail-Address of the user? If more than one eMail-Address are stored in the LDAP, only the first given is used. This field defaults to mail
* **Web-Attribute** If your users have a personal page (URI) stored in the LDAP, it can be provided here. This field is empty by default
### User-Groups for Roles
* **Group-Attribute** This is the attribute that defines the Group-ID that can be matched against the Groups defined further down This field defaults to gidNumber.
* **Group-Filter** Here you can add the filter for selecting groups for the currentlly logged in user The Filter should contain the string %s which will be replaced by the login-name of the currently logged in
## FAQ
<dl>
<dt>Can I change a users password with this plugin?</dt>
<dd>Short Answer: <strong>No</strong>!<br>Long Answer: As the users credentials are not
only used for a wordpress-site when you authenticate against an LDAP but for
many other services also chances are great that there is a centralized place
where password-changes shall be made. We'll later allow inclusion of a link
to such a place but currently it's not available. And as password-hashing and
where to store it requires deeper insight into the LDAP-Server then most users
have and admins are willing to give, password changes are out of scope of this
plugin. If you know exactyl what you do, you might want to have a look at
<a href="https://github.com/heiglandreas/authLdap/issues/54#issuecomment-125851029">
issue 54</a>
wherer a way of adding it is described!
</dd>
<dt>Can I add a user to the LDAP when she creates a user-account on wordpress?</dt>
<dd>Short Answer: <strong>No</strong>!<br>Long Answer: Even though that is technically possible
it's not in the scope of this plugin. As creating a user in an LDAP often involves
an administrative process that has already been implemented in your departments
administration it doesn't make sense to rebuild that - in most cases highly
individual - process in this plugin. If you know exactly what you do, have a look at
<a href="https://github.com/heiglandreas/authLdap/issues/65">issue 65</a>
where <a href="https://github.com/wtfiwtz">wtfiwtz</a> shows how to implement that feature.
</dd>
</dl>

View File

@ -0,0 +1,13 @@
.row {
overflow: hidden;
padding-top: 10px;
}
.element {
float: right;
text-align: left;
}
.authldap-options input[type=text] {
width: 100%;
}

View File

@ -0,0 +1,886 @@
<?php
/*
Plugin Name: AuthLDAP
Plugin URI: https://github.com/heiglandreas/authLdap
Description: This plugin allows you to use your existing LDAP as authentication base for WordPress
Version: 2.5.2
Author: Andreas Heigl <andreas@heigl.org>
Author URI: http://andreas.heigl.org
License: MIT
License URI: https://opensource.org/licenses/MIT
*/
// phpcs:disable PSR1.Files.SideEffects
use Org_Heigl\AuthLdap\LdapUri;
require_once dirname(__FILE__) . '/ldap.php';
require_once __DIR__ . '/src/LdapUri.php';
require_once __DIR__ . '/src/Exception/Error.php';
require_once __DIR__ . '/src/Exception/InvalidLdapUri.php';
function authLdap_debug($message)
{
if (authLdap_get_option('Debug')) {
error_log('[AuthLDAP] ' . $message, 0);
}
}
function authLdap_addmenu()
{
if (! is_multisite()) {
add_options_page(
'AuthLDAP',
'AuthLDAP',
'manage_options',
basename(__FILE__),
'authLdap_options_panel'
);
} else {
add_submenu_page(
'settings.php',
'AuthLDAP',
'AuthLDAP',
'manage_options',
'authldap',
'authLdap_options_panel'
);
}
}
function authLdap_get_post($name, $default = '')
{
return isset($_POST[$name]) ? $_POST[$name] : $default;
}
function authLdap_options_panel()
{
// inclusde style sheet
wp_enqueue_style('authLdap-style', plugin_dir_url(__FILE__) . 'authLdap.css');
if (($_SERVER['REQUEST_METHOD'] == 'POST') && array_key_exists('ldapOptionsSave', $_POST)) {
$new_options = array(
'Enabled' => authLdap_get_post('authLDAPAuth', false),
'CachePW' => authLdap_get_post('authLDAPCachePW', false),
'URI' => authLdap_get_post('authLDAPURI'),
'URISeparator' => authLdap_get_post('authLDAPURISeparator'),
'StartTLS' => authLdap_get_post('authLDAPStartTLS', false),
'Filter' => authLdap_get_post('authLDAPFilter'),
'NameAttr' => authLdap_get_post('authLDAPNameAttr'),
'SecName' => authLdap_get_post('authLDAPSecName'),
'UidAttr' => authLdap_get_post('authLDAPUidAttr'),
'MailAttr' => authLdap_get_post('authLDAPMailAttr'),
'WebAttr' => authLdap_get_post('authLDAPWebAttr'),
'Groups' => authLdap_get_post('authLDAPGroups', array()),
'GroupSeparator'=> authLdap_get_post('authLDAPGroupSeparator', ','),
'Debug' => authLdap_get_post('authLDAPDebug', false),
'GroupBase' => authLdap_get_post('authLDAPGroupBase'),
'GroupAttr' => authLdap_get_post('authLDAPGroupAttr'),
'GroupFilter' => authLdap_get_post('authLDAPGroupFilter'),
'DefaultRole' => authLdap_get_post('authLDAPDefaultRole'),
'GroupEnable' => authLdap_get_post('authLDAPGroupEnable', false),
'GroupOverUser' => authLdap_get_post('authLDAPGroupOverUser', false),
'DoNotOverwriteNonLdapUsers' => authLdap_get_post('authLDAPDoNotOverwriteNonLdapUsers', false),
'UserRead' => authLdap_get_post('authLDAPUseUserAccount', false),
);
if (authLdap_set_options($new_options)) {
echo "<div class='updated'><p>Saved Options!</p></div>";
} else {
echo "<div class='error'><p>Could not save Options!</p></div>";
}
}
// Do some initialization for the admin-view
$authLDAP = authLdap_get_option('Enabled');
$authLDAPCachePW = authLdap_get_option('CachePW');
$authLDAPURI = authLdap_get_option('URI');
$authLDAPURISeparator = authLdap_get_option('URISeparator');
$authLDAPStartTLS = authLdap_get_option('StartTLS');
$authLDAPFilter = authLdap_get_option('Filter');
$authLDAPNameAttr = authLdap_get_option('NameAttr');
$authLDAPSecName = authLdap_get_option('SecName');
$authLDAPMailAttr = authLdap_get_option('MailAttr');
$authLDAPUidAttr = authLdap_get_option('UidAttr');
$authLDAPWebAttr = authLdap_get_option('WebAttr');
$authLDAPGroups = authLdap_get_option('Groups');
$authLDAPGroupSeparator= authLdap_get_option('GroupSeparator');
$authLDAPDebug = authLdap_get_option('Debug');
$authLDAPGroupBase = authLdap_get_option('GroupBase');
$authLDAPGroupAttr = authLdap_get_option('GroupAttr');
$authLDAPGroupFilter = authLdap_get_option('GroupFilter');
$authLDAPDefaultRole = authLdap_get_option('DefaultRole');
$authLDAPGroupEnable = authLdap_get_option('GroupEnable');
$authLDAPGroupOverUser = authLdap_get_option('GroupOverUser');
$authLDAPDoNotOverwriteNonLdapUsers = authLdap_get_option('DoNotOverwriteNonLdapUsers');
$authLDAPUseUserAccount= authLdap_get_option('UserRead');
$tChecked = ($authLDAP) ? ' checked="checked"' : '';
$tDebugChecked = ($authLDAPDebug) ? ' checked="checked"' : '';
$tPWChecked = ($authLDAPCachePW) ? ' checked="checked"' : '';
$tGroupChecked = ($authLDAPGroupEnable) ? ' checked="checked"' : '';
$tGroupOverUserChecked = ($authLDAPGroupOverUser) ? ' checked="checked"' : '';
$tStartTLSChecked = ($authLDAPStartTLS) ? ' checked="checked"' : '';
$tDoNotOverwriteNonLdapUsers = ($authLDAPDoNotOverwriteNonLdapUsers) ? ' checked="checked"' : '';
$tUserRead = ($authLDAPUseUserAccount) ? ' checked="checked"' : '';
$roles = new WP_Roles();
$action = $_SERVER['REQUEST_URI'];
if (! extension_loaded('ldap')) {
echo '<div class="warning">The LDAP-Extension is not available on your '
. 'WebServer. Therefore Everything you can alter here does not '
. 'make any sense!</div>';
}
include dirname(__FILE__) . '/view/admin.phtml';
}
/**
* get a LDAP server object
*
* throws exception if there is a problem connecting
*
* @conf boolean authLDAPDebug true, if debugging should be turned on
* @conf string authLDAPURI LDAP server URI
*
* @return Org_Heigl\AuthLdap\LdapList LDAP server object
*/
function authLdap_get_server()
{
static $_ldapserver = null;
if (is_null($_ldapserver)) {
$authLDAPDebug = authLdap_get_option('Debug');
$authLDAPURI = explode(
authLdap_get_option('URISeparator', ' '),
authLdap_get_option('URI')
);
$authLDAPStartTLS = authLdap_get_option('StartTLS');
//$authLDAPURI = 'ldap:/foo:bar@server/trallala';
authLdap_debug('connect to LDAP server');
require_once dirname(__FILE__) . '/src/LdapList.php';
$_ldapserver = new \Org_Heigl\AuthLdap\LdapList();
foreach ($authLDAPURI as $uri) {
$_ldapserver->addLdap(new \Org_Heigl\AuthLdap\LDAP(
LdapUri::fromString($uri),
$authLDAPDebug,
$authLDAPStartTLS
));
}
}
return $_ldapserver;
}
/**
* This method authenticates a user using either the LDAP or, if LDAP is not
* available, the local database
*
* For this we store the hashed passwords in the WP_Database to ensure working
* conditions even without an LDAP-Connection
*
* @param null|WP_User|WP_Error
* @param string $username
* @param string $password
* @param boolean $already_md5
* @return boolean true, if login was successfull or false, if it wasn't
* @conf boolean authLDAP true, if authLDAP should be used, false if not. Defaults to false
* @conf string authLDAPFilter LDAP filter to use to find correct user, defaults to '(uid=%s)'
* @conf string authLDAPNameAttr LDAP attribute containing user (display) name, defaults to 'name'
* @conf string authLDAPSecName LDAP attribute containing second name, defaults to ''
* @conf string authLDAPMailAttr LDAP attribute containing user e-mail, defaults to 'mail'
* @conf string authLDAPUidAttr LDAP attribute containing user id (the username we log on with), defaults to 'uid'
* @conf string authLDAPWebAttr LDAP attribute containing user website, defaults to ''
* @conf string authLDAPDefaultRole default role for authenticated user, defaults to ''
* @conf boolean authLDAPGroupEnable true, if we try to map LDAP groups to Wordpress roles
* @conf boolean authLDAPGroupOverUser true, if LDAP Groups have precedence over existing user roles
*/
function authLdap_login($user, $username, $password, $already_md5 = false)
{
// don't do anything when authLDAP is disabled
if (! authLdap_get_option('Enabled')) {
authLdap_debug(
'LDAP disabled in AuthLDAP plugin options (use the first option in the AuthLDAP options to enable it)'
);
return $user;
}
// If the user has already been authenticated (only in that case we get a
// WP_User-Object as $user) we skip LDAP-authentication and simply return
// the existing user-object
if ($user instanceof WP_User) {
authLdap_debug(sprintf(
'User %s has already been authenticated - skipping LDAP-Authentication',
$user->get('nickname')
));
return $user;
}
authLdap_debug("User '$username' logging in");
if ($username == 'admin') {
authLdap_debug('Doing nothing for possible local user admin');
return $user;
}
global $wpdb, $error;
try {
$authLDAP = authLdap_get_option('Enabled');
$authLDAPFilter = authLdap_get_option('Filter');
$authLDAPNameAttr = authLdap_get_option('NameAttr');
$authLDAPSecName = authLdap_get_option('SecName');
$authLDAPMailAttr = authLdap_get_option('MailAttr');
$authLDAPUidAttr = authLdap_get_option('UidAttr');
$authLDAPWebAttr = authLdap_get_option('WebAttr');
$authLDAPDefaultRole = authLdap_get_option('DefaultRole');
$authLDAPGroupEnable = authLdap_get_option('GroupEnable');
$authLDAPGroupOverUser = authLdap_get_option('GroupOverUser');
$authLDAPUseUserAccount = authLdap_get_option('UserRead');
if (! $username) {
authLdap_debug('Username not supplied: return false');
return false;
}
if (! $password) {
authLdap_debug('Password not supplied: return false');
$error = __('<strong>Error</strong>: The password field is empty.');
return false;
}
// First check for valid values and set appropriate defaults
if (! $authLDAPFilter) {
$authLDAPFilter = '(uid=%s)';
}
if (! $authLDAPNameAttr) {
$authLDAPNameAttr = 'name';
}
if (! $authLDAPMailAttr) {
$authLDAPMailAttr = 'mail';
}
if (! $authLDAPUidAttr) {
$authLDAPUidAttr = 'uid';
}
// If already_md5 is TRUE, then we're getting the user/password from the cookie. As we don't want
// to store LDAP passwords in any
// form, we've already replaced the password with the hashed username and LDAP_COOKIE_MARKER
if ($already_md5) {
if ($password == md5($username).md5($ldapCookieMarker)) {
authLdap_debug('cookie authentication');
return true;
}
}
// Remove slashes as noted on https://github.com/heiglandreas/authLdap/issues/108
$password = stripslashes_deep($password);
// No cookie, so have to authenticate them via LDAP
$result = false;
try {
authLdap_debug('about to do LDAP authentication');
$result = authLdap_get_server()->Authenticate($username, $password, $authLDAPFilter);
} catch (Exception $e) {
authLdap_debug('LDAP authentication failed with exception: ' . $e->getMessage());
return false;
}
// Make optional querying from the admin account #213
if (! authLdap_get_option('UserRead')) {
// Rebind with the default credentials after the user has been loged in
// Otherwise the credentials of the user trying to login will be used
// This fixes #55
authLdap_get_server()->bind();
}
if (true !== $result) {
authLdap_debug('LDAP authentication failed');
// TODO what to return? WP_User object, true, false, even an WP_Error object...
// all seem to fall back to normal wp user authentication
return;
}
authLdap_debug('LDAP authentication successful');
$attributes = array_values(
array_filter(
apply_filters(
'authLdap_filter_attributes',
array(
$authLDAPNameAttr,
$authLDAPSecName,
$authLDAPMailAttr,
$authLDAPWebAttr,
$authLDAPUidAttr
)
)
)
);
try {
$attribs = authLdap_get_server()->search(
sprintf($authLDAPFilter, $username),
$attributes
);
// First get all the relevant group informations so we can see if
// whether have been changes in group association of the user
if (! isset($attribs[0]['dn'])) {
authLdap_debug('could not get user attributes from LDAP');
throw new UnexpectedValueException('dn has not been returned');
}
if (! isset($attribs[0][strtolower($authLDAPUidAttr)][0])) {
authLdap_debug('could not get user attributes from LDAP');
throw new UnexpectedValueException('The user-ID attribute has not been returned');
}
$dn = $attribs[0]['dn'];
$realuid = $attribs[0][strtolower($authLDAPUidAttr)][0];
} catch (Exception $e) {
authLdap_debug('Exception getting LDAP user: ' . $e->getMessage());
return false;
}
$uid = authLdap_get_uid($realuid);
// This fixes #172
if (true == authLdap_get_option('DoNotOverwriteNonLdapUsers', false)) {
if (! get_user_meta($uid, 'authLDAP')) {
return null;
}
}
$role = '';
// we only need this if either LDAP groups are disabled or
// if the WordPress role of the user overrides LDAP groups
if (!$authLDAPGroupEnable || !$authLDAPGroupOverUser) {
$role = authLdap_user_role($uid);
}
// do LDAP group mapping if needed
// (if LDAP groups override worpress user role, $role is still empty)
if (empty($role) && $authLDAPGroupEnable) {
$role = authLdap_groupmap($realuid, $dn);
authLdap_debug('role from group mapping: ' . $role);
}
// if we don't have a role yet, use default role
if (empty($role) && !empty($authLDAPDefaultRole)) {
authLdap_debug('no role yet, set default role');
$role = $authLDAPDefaultRole;
}
if (empty($role)) {
// Sorry, but you are not in any group that is allowed access
trigger_error('no group found');
authLdap_debug('user is not in any group that is allowed access');
return false;
} else {
$roles = new WP_Roles();
// not sure if this is needed, but it can't hurt
if (!$roles->is_role($role)) {
trigger_error('no group found');
authLdap_debug('role is invalid');
return false;
}
}
// from here on, the user has access!
// now, lets update some user details
$user_info = array();
$user_info['user_login'] = $realuid;
$user_info['role'] = $role;
$user_info['user_email'] = '';
$user_info['user_nicename'] = '';
// first name
if (isset($attribs[0][strtolower($authLDAPNameAttr)][0])) {
$user_info['first_name'] = $attribs[0][strtolower($authLDAPNameAttr)][0];
}
// last name
if (isset($attribs[0][strtolower($authLDAPSecName)][0])) {
$user_info['last_name'] = $attribs[0][strtolower($authLDAPSecName)][0];
}
// mail address
if (isset($attribs[0][strtolower($authLDAPMailAttr)][0])) {
$user_info['user_email'] = $attribs[0][strtolower($authLDAPMailAttr)][0];
}
// website
if (isset($attribs[0][strtolower($authLDAPWebAttr)][0])) {
$user_info['user_url'] = $attribs[0][strtolower($authLDAPWebAttr)][0];
}
// display name, nickname, nicename
if (array_key_exists('first_name', $user_info)) {
$user_info['display_name'] = $user_info['first_name'];
$user_info['nickname'] = $user_info['first_name'];
$user_info['user_nicename'] = sanitize_title_with_dashes($user_info['first_name']);
if (array_key_exists('last_name', $user_info)) {
$user_info['display_name'] .= ' ' . $user_info['last_name'];
$user_info['nickname'] .= ' ' . $user_info['last_name'];
$user_info['user_nicename'] .= '_' . sanitize_title_with_dashes($user_info['last_name']);
}
}
$user_info['user_nicename'] = substr($user_info['user_nicename'], 0, 50);
// optionally store the password into the wordpress database
if (authLdap_get_option('CachePW')) {
// Password will be hashed inside wp_update_user or wp_insert_user
$user_info['user_pass'] = $password;
} else {
// clear the password
$user_info['user_pass'] = '';
}
// add uid if user exists
if ($uid) {
// found user in the database
authLdap_debug('The LDAP user has an entry in the WP-Database');
$user_info['ID'] = $uid;
unset($user_info['display_name'], $user_info['nickname']);
$userid = wp_update_user($user_info);
} else {
// new wordpress account will be created
authLdap_debug('The LDAP user does not have an entry in the WP-Database, a new WP account will be created');
$userid = wp_insert_user($user_info);
}
// if the user exists, wp_insert_user will update the existing user record
if (is_wp_error($userid)) {
authLdap_debug('Error creating user : ' . $userid->get_error_message());
trigger_error('Error creating user: ' . $userid->get_error_message());
return $userid;
}
/**
* Add hook for custom updates
*
* @param int $userid User ID.
* @param array $attribs[0] Attributes retrieved from LDAP for the user.
*/
do_action('authLdap_login_successful', $userid, $attribs[0]);
authLdap_debug('user id = ' . $userid);
// flag the user as an ldap user so we can hide the password fields in the user profile
update_user_meta($userid, 'authLDAP', true);
// return a user object upon positive authorization
return new WP_User($userid);
} catch (Exception $e) {
authLdap_debug($e->getMessage() . '. Exception thrown in line ' . $e->getLine());
trigger_error($e->getMessage() . '. Exception thrown in line ' . $e->getLine());
}
}
/**
* Get user's user id
*
* Returns null if username not found
*
* @param string $username username
* @param string user id, null if not found
*/
function authLdap_get_uid($username)
{
global $wpdb;
// find out whether the user is already present in the database
$uid = $wpdb->get_var(
$wpdb->prepare(
"SELECT ID FROM {$wpdb->users} WHERE user_login = %s",
$username
)
);
if ($uid) {
authLdap_debug("Existing user, uid = {$uid}");
return $uid;
} else {
return null;
}
}
/**
* Get the user's current role
*
* Returns empty string if not found.
*
* @param int $uid wordpress user id
* @return string role, empty if none found
*/
function authLdap_user_role($uid)
{
global $wpdb, $wp_roles;
if (!$uid) {
return '';
}
/** @var array<string, bool> $usercapabilities */
$usercapabilities = get_user_meta( $uid, "{$wpdb->prefix}capabilities", true);
if ( ! is_array( $usercapabilities ) ) {
return '';
}
/** @var array<string, array{name: string, capabilities: array<mixed>} $editable_roles */
$editable_roles = $wp_roles->roles;
// By using this approach we are now using the order of the roles from the WP_Roles object
// and not from the capabilities any more.
$userroles = array_keys(array_intersect_key($editable_roles, $usercapabilities));
$role = $userroles[0];
authLdap_debug("Existing user's role: {$role}");
return $role;
}
/**
* Get LDAP groups for user and map to role
*
* @param string $username
* @param string $dn
* @return string role, empty string if no mapping found, first found role otherwise
* @conf array authLDAPGroups, associative array, role => ldap_group
* @conf string authLDAPGroupBase, base dn to look up groups
* @conf string authLDAPGroupAttr, ldap attribute that holds name of group
* @conf string authLDAPGroupFilter, LDAP filter to find groups. can contain %s and %dn% placeholders
*/
function authLdap_groupmap($username, $dn)
{
$authLDAPGroups = authLdap_sort_roles_by_capabilities(
authLdap_get_option('Groups')
);
$authLDAPGroupBase = authLdap_get_option('GroupBase');
$authLDAPGroupAttr = authLdap_get_option('GroupAttr');
$authLDAPGroupFilter = authLdap_get_option('GroupFilter');
$authLDAPGroupSeparator = authLdap_get_option('GroupSeparator');
if (! $authLDAPGroupAttr) {
$authLDAPGroupAttr = 'gidNumber';
}
if (! $authLDAPGroupFilter) {
$authLDAPGroupFilter = '(&(objectClass=posixGroup)(memberUid=%s))';
}
if (! $authLDAPGroupSeparator) {
$authLDAPGroupSeparator = ',';
}
if (!is_array($authLDAPGroups) || count(array_filter(array_values($authLDAPGroups))) == 0) {
authLdap_debug('No group names defined');
return '';
}
try {
// To allow searches based on the DN instead of the uid, we replace the
// string %dn% with the users DN.
$authLDAPGroupFilter = str_replace(
'%dn%',
ldap_escape($dn, '', LDAP_ESCAPE_FILTER),
$authLDAPGroupFilter
);
authLdap_debug('Group Filter: ' . json_encode($authLDAPGroupFilter));
authLdap_debug('Group Base: ' . $authLDAPGroupBase);
$groups = authLdap_get_server()->search(
sprintf($authLDAPGroupFilter, ldap_escape($username, '', LDAP_ESCAPE_FILTER)),
array($authLDAPGroupAttr),
$authLDAPGroupBase
);
} catch (Exception $e) {
authLdap_debug('Exception getting LDAP group attributes: ' . $e->getMessage());
return '';
}
$grp = array();
for ($i = 0; $i < $groups ['count']; $i++) {
for ($k = 0; $k < $groups[$i][strtolower($authLDAPGroupAttr)]['count']; $k++) {
$grp[] = $groups[$i][strtolower($authLDAPGroupAttr)][$k];
}
}
authLdap_debug('LDAP groups: ' . json_encode($grp));
// Check whether the user is member of one of the groups that are
// allowed acces to the blog. If the user is not member of one of
// The groups throw her out! ;-)
// If the user is member of more than one group only the first one
// will be taken into account!
$role = '';
foreach ($authLDAPGroups as $key => $val) {
$currentGroup = explode($authLDAPGroupSeparator, $val);
// Remove whitespaces around the group-ID
$currentGroup = array_map('trim', $currentGroup);
if (0 < count(array_intersect($currentGroup, $grp))) {
$role = $key;
break;
}
}
authLdap_debug("Role from LDAP group: {$role}");
return $role;
}
/**
* This function disables the password-change fields in the users preferences.
*
* It does not make sense to authenticate via LDAP and then allow the user to
* change the password only in the wordpress database. And changing the password
* LDAP-wide can not be the scope of Wordpress!
*
* Whether the user is an LDAP-User or not is determined using the authLDAP-Flag
* of the users meta-informations
*
* @return false, if the user whose prefs are viewed is an LDAP-User, true if
* he isn't
* @conf boolean authLDAP
*/
function authLdap_show_password_fields($return, $user)
{
if (! $user) {
return true;
}
if (get_user_meta($user->ID, 'authLDAP')) {
return false;
}
return $return;
}
/**
* This function disables the password reset for a user.
*
* It does not make sense to authenticate via LDAP and then allow the user to
* reset the password only in the wordpress database. And changing the password
* LDAP-wide can not be the scope of Wordpress!
*
* Whether the user is an LDAP-User or not is determined using the authLDAP-Flag
* of the users meta-informations
*
* @author chaplina (https://github.com/chaplina)
* @conf boolean authLDAP
* @return false, if the user is an LDAP-User, true if he isn't
*/
function authLdap_allow_password_reset($return, $userid)
{
if (!(isset($userid))) {
return true;
}
if (get_user_meta($userid, 'authLDAP')) {
return false;
}
return $return;
}
/**
* Sort the given roles by number of capabilities
*
* @param array $roles
*
* @return array
*/
function authLdap_sort_roles_by_capabilities($roles)
{
global $wpdb;
$myRoles = get_option($wpdb->get_blog_prefix() . 'user_roles');
authLdap_debug(print_r($roles, true));
uasort($myRoles, 'authLdap_sortByCapabilitycount');
$return = array();
foreach ($myRoles as $key => $role) {
if (isset($roles[$key])) {
$return[$key] = $roles[$key];
}
}
authLdap_debug(print_r($return, true));
return $return;
}
/**
* Sort according to the number of capabilities
*
* @param $a
* @param $b
*/
function authLdap_sortByCapabilitycount($a, $b)
{
if (count($a['capabilities']) > count($b['capabilities'])) {
return -1;
}
if (count($a['capabilities']) < count($b['capabilities'])) {
return 1;
}
return 0;
}
/**
* Load AuthLDAP Options
*
* Sets and stores defaults if options are not up to date
*/
function authLdap_load_options($reload = false)
{
static $options = null;
// the current version for options
$option_version_plugin = 1;
$optionFunction = 'get_option';
if (is_multisite()) {
$optionFunction = 'get_site_option';
}
if (is_null($options) || $reload) {
$options = $optionFunction('authLDAPOptions', array());
}
// check if option version has changed (or if it's there at all)
if (!isset($options['Version']) || ($options['Version'] != $option_version_plugin)) {
// defaults for all options
$options_default = array(
'Enabled' => false,
'CachePW' => false,
'URI' => '',
'URISeparator' => ' ',
'Filter' => '', // '(uid=%s)'
'NameAttr' => '', // 'name'
'SecName' => '',
'UidAttr' => '', // 'uid'
'MailAttr' => '', // 'mail'
'WebAttr' => '',
'Groups' => array(),
'Debug' => false,
'GroupAttr' => '', // 'gidNumber'
'GroupFilter' => '', // '(&(objectClass=posixGroup)(memberUid=%s))'
'DefaultRole' => '',
'GroupEnable' => true,
'GroupOverUser' => true,
'Version' => $option_version_plugin,
'DoNotOverwriteNonLdapUsers' => false,
);
// check if we got a version
if (!isset($options['Version'])) {
// we just changed to the new option format
// read old options, then delete them
$old_option_new_option = array(
'authLDAP' => 'Enabled',
'authLDAPCachePW' => 'CachePW',
'authLDAPURI' => 'URI',
'authLDAPFilter' => 'Filter',
'authLDAPNameAttr' => 'NameAttr',
'authLDAPSecName' => 'SecName',
'authLDAPUidAttr' => 'UidAttr',
'authLDAPMailAttr' => 'MailAttr',
'authLDAPWebAttr' => 'WebAttr',
'authLDAPGroups' => 'Groups',
'authLDAPDebug' => 'Debug',
'authLDAPGroupAttr' => 'GroupAttr',
'authLDAPGroupFilter' => 'GroupFilter',
'authLDAPDefaultRole' => 'DefaultRole',
'authLDAPGroupEnable' => 'GroupEnable',
'authLDAPGroupOverUser' => 'GroupOverUser',
);
foreach ($old_option_new_option as $old_option => $new_option) {
$value = get_option($old_option, null);
if (!is_null($value)) {
$options[$new_option] = $value;
}
delete_option($old_option);
}
delete_option('authLDAPCookieMarker');
delete_option('authLDAPCookierMarker');
}
// set default for all options that are missing
foreach ($options_default as $key => $default) {
if (!isset($options[$key])) {
$options[$key] = $default;
}
}
// set new version and save
$options['Version'] = $option_version_plugin;
update_option('authLDAPOptions', $options);
}
return $options;
}
/**
* Get an individual option
*/
function authLdap_get_option($optionname, $default = null)
{
$options = authLdap_load_options();
if (isset($options[$optionname]) && $options[$optionname]) {
return $options[$optionname];
}
if (null !== $default) {
return $default;
}
//authLdap_debug('option name invalid: ' . $optionname);
return null;
}
/**
* Set new options
*/
function authLdap_set_options($new_options = array())
{
// initialize the options with what we currently have
$options = authLdap_load_options();
// set the new options supplied
foreach ($new_options as $key => $value) {
$options[$key] = $value;
}
// store options
$optionFunction = 'update_option';
if (is_multisite()) {
$optionFunction = 'update_site_option';
}
if ($optionFunction('authLDAPOptions', $options)) {
// reload the option cache
authLdap_load_options(true);
return true;
}
// could not set options
return false;
}
/**
* Do not send an email after changing the password or the email of the user!
*
* @param boolean $result The initial resturn value
* @param array $user The old userdata
* @param array $newUserData The changed userdata
*
* @return bool
*/
function authLdap_send_change_email($result, $user, $newUserData)
{
if (get_user_meta($user['ID'], 'authLDAP')) {
return false;
}
return $result;
}
$hook = is_multisite() ? 'network_' : '';
add_action($hook . 'admin_menu', 'authLdap_addmenu');
add_filter('show_password_fields', 'authLdap_show_password_fields', 10, 2);
add_filter('allow_password_reset', 'authLdap_allow_password_reset', 10, 2);
add_filter('authenticate', 'authLdap_login', 10, 3);
/** This only works from WP 4.3.0 on */
add_filter('send_password_change_email', 'authLdap_send_change_email', 10, 3);
add_filter('send_email_change_email', 'authLdap_send_change_email', 10, 3);

View File

@ -0,0 +1,275 @@
<?php
/**
* $Id: ldap.php 2676679 2022-02-10 18:26:37Z heiglandreas $
*
* authLdap - Authenticate Wordpress against an LDAP-Backend.
* Copyright (c) 2008 Andreas Heigl<andreas@heigl.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* This file handles the basic LDAP-Tasks
*
* @author Andreas Heigl<andreas@heigl.org>
* @package authLdap
* @category authLdap
* @since 2008
*/
namespace Org_Heigl\AuthLdap;
use Exception;
use Org_Heigl\AuthLdap\Exception\Error;
use function ldap_escape;
class LDAP
{
private $server = '';
private $scheme = 'ldap';
private $port = 389;
private $baseDn = '';
private $debug = false;
/**
* This property contains the connection handle to the ldap-server
*
* @var Ressource|Connection|null
*/
private $ch = null;
private $username = '';
private $password = '';
private $starttls = false;
public function __construct(LdapUri $URI, $debug = false, $starttls = false)
{
$this->debug=$debug;
$array = parse_url($URI->toString());
if (! is_array($array)) {
throw new Exception($URI . ' seems not to be a valid URI');
}
$url = array_map(function ($item) {
return urldecode($item);
}, $array);
if (false === $url) {
throw new Exception($URI . ' is an invalid URL');
}
if (! isset($url['scheme'])) {
throw new Exception($URI . ' does not provide a scheme');
}
if (0 !== strpos($url['scheme'], 'ldap')) {
throw new Exception($URI . ' is an invalid LDAP-URI');
}
if (! isset($url['host'])) {
throw new Exception($URI . ' does not provide a server');
}
if (! isset($url['path'])) {
throw new Exception($URI . ' does not provide a search-base');
}
if (1 == strlen($url['path'])) {
throw new Exception($URI . ' does not provide a valid search-base');
}
$this -> server = $url['host'];
$this -> scheme = $url['scheme'];
$this -> baseDn = substr($url['path'], 1);
if (isset($url['user'])) {
$this -> username = $url['user'];
}
if ('' == trim($this -> username)) {
$this -> username = 'anonymous';
}
if (isset($url['pass'])) {
$this -> password = $url['pass'];
}
if (isset($url['port'])) {
$this -> port = $url['port'];
}
$this->starttls = $starttls;
}
/**
* Connect to the given LDAP-Server
*
* @return LDAP
* @throws Error
*/
public function connect()
{
$this -> disconnect();
if ('ldaps' == $this->scheme && 389 == $this->port) {
$this->port = 636;
}
$this->ch = @ldap_connect($this->scheme . '://' . $this->server . ':' . $this -> port);
if (false === $this->ch) {
$this->ch = null;
throw new Error('Could not connect to the server');
}
ldap_set_option($this->ch, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($this->ch, LDAP_OPT_REFERRALS, 0);
//if configured try to upgrade encryption to tls for ldap connections
if ($this->starttls) {
ldap_start_tls($this->ch);
}
return $this;
}
/**
* Disconnect from a resource if one is available
*
* @return LDAP
*/
public function disconnect()
{
if (null !== $this->ch ) {
@ldap_unbind($this->ch);
}
$this->ch = null;
return $this;
}
/**
* Bind to an LDAP-Server with the given credentials
*
* @return LDAP
* @throw AuthLdap_Exception
*/
public function bind()
{
if (! $this->ch) {
$this->connect();
}
if (null === $this->ch) {
throw new Error('No valid LDAP connection available');
}
$bind = false;
if (( ( $this->username )
&& ( $this->username != 'anonymous') )
&& ( $this->password != '' )) {
$bind = @ldap_bind($this->ch, $this->username, $this->password);
} else {
$bind = @ldap_bind($this->ch);
}
if (! $bind) {
throw new Error('bind was not successfull: ' . ldap_error($this->ch));
}
return $this;
}
public function getErrorNumber()
{
return @ldap_errno($this->ch);
}
public function getErrorText()
{
return @ldap_error($this->ch);
}
/**
* This method does the actual ldap-serch.
*
* This is using the filter <var>$filter</var> for retrieving the attributes
* <var>$attributes</var>
*
*
* @param string $filter
* @param array $attributes
* @param string $base
* @return array
*/
public function search($filter, $attributes = array('uid'), $base = '')
{
if (null === $this->ch) {
throw new Error('No resource handle avbailable');
}
if (! $base) {
$base = $this->baseDn;
}
$result = ldap_search($this->ch, $base, $filter, $attributes);
if ($result === false) {
throw new Error('no result found');
}
$this->_info = @ldap_get_entries($this->ch, $result);
if ($this->_info === false) {
throw new Error('invalid results found');
}
return $this -> _info;
}
/**
* This method sets debugging to ON
*/
public function debugOn()
{
$this->debug = true;
return $this;
}
/**
* This method sets debugging to OFF
*/
public function debugOff()
{
$this->debug = false;
return $this;
}
/**
* This method authenticates the user <var>$username</var> using the
* password <var>$password</var>
*
* @param string $username
* @param string $password
* @param string $filter OPTIONAL This parameter defines the Filter to be used
* when searchin for the username. This MUST contain the string '%s' which
* will be replaced by the vaue given in <var>$username</var>
* @return boolean true or false depending on successfull authentication or not
*/
public function authenticate($username, $password, $filter = '(uid=%s)')
{
//return true;
$this->connect();
$this->bind();
$res = $this->search(sprintf($filter, ldap_escape($username, '', LDAP_ESCAPE_FILTER)));
if (! $res || ! is_array($res) || ( $res ['count'] != 1 )) {
return false;
}
$dn = $res[0]['dn'];
if ($username && $password) {
if (@ldap_bind($this->ch, $dn, $password)) {
return true;
}
}
return false;
}
/**
* $this method loggs errors if debugging is set to ON
*/
public function logError()
{
if ($this->debug) {
$_v = debug_backtrace();
throw new Error(
'[LDAP_ERROR]' . ldap_errno($this->ch) . ':' . ldap_error($this->ch),
$_v[0]['line']
);
}
}
}

View File

@ -0,0 +1,133 @@
=== authLdap ===
Contributors: heiglandreas
Tags: ldap, auth, authentication, active directory, AD, openLDAP, Open Directory
Requires at least: 2.5.0
Tested up to: 5.9.0
Requires PHP: 7.2
Stable tag: trunk
License: MIT
License URI: https://opensource.org/licenses/MIT
Use your existing LDAP flexible as authentication backend for WordPress
== Description ==
Use your existing LDAP as authentication-backend for your wordpress!
So what are the differences to other Wordpress-LDAP-Authentication-Plugins?
* Flexible: You are totaly free in which LDAP-backend to use. Due to the extensive configuration you can freely decide how to do the authentication of your users. It simply depends on your filters
* Independent: As soon as a user logs in, it is added/updated to the Wordpress' user-database to allow wordpress to always use the correct data. You only have to administer your users once.
* Failsafe: Due to the users being created in Wordpress' User-database they can also log in when the LDAP-backend currently is gone.
* Role-Aware: You can map Wordpress' roles to values of an existing LDAP-attribute.
For more Information on the configuration have a look at https://github.com/heiglandreas/authLdap
== Installation ==
1. Upload the extracted folder `authLdap` to the `/wp-content/plugins/` directory
2. Activate the plugin through the 'Plugins' menu in WordPress
3. Configure the Plugin via the 'authLdap'-Configuration-Page.
== Frequently Asked Questions ==
= Where can I find more Informations about the plugin? =
Go to https://github.com/heiglandreas/authLdap
= Where can I report issues with the plugin? =
Please use the issuetracker at https://github.com/heiglandreas/authLdap/issues
== Changelog ==
= 2.5.0 =
* Ignore the order of capabilities to tell the role. In addition the filter `editable_roles` can be used to limit the roles
= 2.4.11 =
* Fix issue with running on PHP8.1
= 2.4.9 =
* Improve group-assignement UI
= 2.4.8 =
* Make textfields in settings-page wider
= 2.4.7 =
* Replace deprecated function
* Fix undefined index
* Add filter for retrieving other params at login (authLdap_filter_attributes)
* Add do_action after successfull login (authLdap_login_successful)
= 2.4.0 =
* Allow to use environment variables for LDAP-URI configuration
= 2.3.0 =
* Allow to not overwrite existing WordPress-Users with LDAP-Users as that can be a security issue.
= 2.1.0 =
* Add search-base for groups. This might come in handy for multisite-instances
= 2.0.0 =
* This new release adds Multi-Site support. It will no longer be possible to use this plugin just in one subsite of a multisite installation!
* Adds a warning screen to the config-section when no LDAPextension could be found
* Fixes an issue with the max-length of the username
= 1.5.1 =
* Fixes an issue with escaped backslashes and quotes
= 1.5.0 =
* Allows parts of the LDAP-URI to be URLEncoded
* Drops support for PHP 5.4
= 1.4.20 =
* Allows multiple LDAP-servers to be queried (given that they use the same attributes)
* Fixes issue with URL-Encoded informations (see https://github.com/heiglandreas/authLdap/issues/108)
= 1.4.19 =
* Adds support for TLS
= 1.4.14 =
* Update to showing password-fields check (thanks to @chaplina)
= 1.4.13 =
* Removed generation of default email-address (thanks to @henryk)
* Fixes password-hashing when caching passwords (thanks to @litinoveweedle)
* Removes the possibility to reset a password for LDAP-based users (thanks to @chaplina)
* Removes the password-change-Email from 4.3 on (thanks to @litinoveweedle)
* Fixes double authentication-attempt (that resulted in failed authentication) (thanks to @litinoveweedle)
= 1.4.10 =
* Cleanup by removing deprecated code
* Fixes issues with undefined variables
* Enables internal option-versioning
* Setting users nickname initially to the realname instead of the uid
* Fixes display of password-change possibility in users profile-page
= 1.4.9 =
* Fixed an issue with changing display name on every login
* Use proper way of looking up user-roles in setups w/o DB-prefix
= 1.4.8 =
* Updated version string
= 1.4.7 =
* Use default user to retrieve group menberships and not logging in user.
* return the UID from the LDAP instead of the value given by the user
* remove unnecessary checkbox
* Adds a testsuite
* Fixes PSR2 violations
[…]
= 1.2.1 =
* Fixed an issue with group-ids
* Moved the code to GitHub (https://github.com/heiglandreas/authLdap)
= 1.1.0 =
* Changed the login-process. Now users that are not allowed to login due to
missing group-memberships are not created within your blog as was the standard
until Version 1.0.3 - Thanks to alex@tayts.com
* Changed the default mail-address that is created when no mail-address can be
retrieved from the LDAP from me@example.com to $username@example.com so that
a new user can be created even though the mail address already exists in your
blog - Also thanks to alex@tayts.com
* Added support for WordPress-Table-prefixes as the capabilities of a user
are interlany stored in a field that is named "$tablePrefix_capabilities" -
again thanks to alex@tayts.com and also to sim0n of silicium.mine.nu

View File

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
/**
* Copyright Andrea Heigl <andreas@heigl.org>
*
* Licenses under the MIT-license. For details see the included file LICENSE.md
*/
namespace Org_Heigl\AuthLdap\Exception;
use Exception;
class Error extends Exception
{
public function __construct($message, $line = null)
{
parent::__construct($message);
if ($line) {
$this -> line = $line;
}
}
}

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace Org_Heigl\AuthLdap\Exception;
use RuntimeException;
class InvalidLdapUri extends RuntimeException
{
public static function fromLdapUriString(string $ldapUri): InvalidLdapUri
{
return new self('"%s" is not a valid LDAP-URI.');
}
}

View File

@ -0,0 +1,90 @@
<?php
/**
* Copyright (c) Andreas Heigl<andreas@heigl.org>
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author Andreas Heigl<andreas@heigl.org>
* @copyright Andreas Heigl
* @license http://www.opensource.org/licenses/mit-license.php MIT-License
* @since 07.07.2016
* @link http://github.com/heiglandreas/authLDAP
*/
namespace Org_Heigl\AuthLdap;
use Org_Heigl\AuthLdap\Exception\Error;
class LdapList
{
/**
* @var \LDAP[]
*/
protected $items = [];
public function addLdap(LDAP $ldap)
{
$this->items[] = $ldap;
}
public function authenticate($username, $password, $filter = '(uid=%s)')
{
/** @var LDAP $item */
foreach ($this->items as $key => $item) {
if (! $item->authenticate($username, $password, $filter)) {
unset($this->items[$key]);
continue;
}
return true;
}
return false;
}
public function bind()
{
$allFailed = true;
foreach ($this->items as $key => $item) {
try {
$item->bind();
} catch (\Exception $e) {
unset($this->items[$key]);
continue;
}
$allFailed = false;
}
if ($allFailed) {
throw new Error('No bind successfull');
}
return true;
}
public function search($filter, $attributes = array('uid'), $base = '')
{
foreach ($this->items as $item) {
try {
$result = $item->search($filter, $attributes, $base);
return $result;
} catch (Exception $e) {
throw $e;
}
}
throw new \AuthLDAP_Exception('No Results found');
}
}

View File

@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
/**
* Copyright (c) Andreas Heigl<andreas@heigl.org>
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author Andreas Heigl<andreas@heigl.org>
* @copyright Andreas Heigl
* @license http://www.opensource.org/licenses/mit-license.php MIT-License
* @since 19.07.2020
* @link http://github.com/heiglandreas/authLDAP
*/
namespace Org_Heigl\AuthLdap;
use Org_Heigl\AuthLdap\Exception\InvalidLdapUri;
use function getenv;
use function preg_replace;
use function urlencode;
final class LdapUri
{
private $uri;
private function __construct(string $uri)
{
if (! preg_match('/^(ldap|ldaps|env)/', $uri)) {
throw InvalidLdapUri::fromLdapUriString($uri);
}
$this->uri = $uri;
}
public static function fromString(string $uri): LdapUri
{
return new LdapUri($uri);
}
public function toString(): string
{
$uri = $this->uri;
if (0 === strpos($uri, 'env:')) {
$uri = getenv(substr($this->uri, 4));
}
$uri = preg_replace_callback('/%env:([^%]+)%/', function (array $matches) {
return rawurlencode(getenv($matches[1]));
}, $uri);
return $uri;
}
public function __toString()
{
return $this->toString();
}
}

View File

@ -0,0 +1,453 @@
<?php
/**
* Copyright (c)2014-2014 heiglandreas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIBILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category
* @author Andreas Heigl<andreas@heigl.org>
* @copyright ©2014-2014 Andreas Heigl
* @license http://www.opesource.org/licenses/mit-license.php MIT-License
* @version 0.0
* @since 19.12.14
* @link https://github.com/heiglandreas/authLdap
*/
?><div class="wrap">
<?php if (! extension_loaded('ldap')) : ?>
<div class="error"><strong>Caveat:</strong> The LDAP-extension is not loaded!
Without that extension it is not possible to query an LDAP-Server! Please have a look
at <a href="http://php.net/manual/install.php">the PHP-Installation page</a>
</div>
<?php endif ?>
<h2>AuthLDAP Options</h2>
<form class="authldap-options" method="post" id="authLDAP_options" action="<?php echo $action;?>">
<h3 class="title">General Usage of authLDAP</h3>
<fieldset class="options">
<table class="form-table">
<tr>
<th>
<label for="authLDAPAuth">Enable Authentication via LDAP?</label>
</th>
<td>
<input type="checkbox" name="authLDAPAuth" id="authLDAPAuth" value="1"<?php echo $tChecked; ?>/>
</td>
</tr>
<tr>
<th>
<label for="authLDAPDebug">Debug AuthLDAP?</label>
</th>
<td>
<input type="checkbox" name="authLDAPDebug" id="authLDAPDebug" value="1"<?php echo $tDebugChecked; ?>/>
</td>
</tr>
<tr>
<th>
<label for="authLDAPDoNotOverwriteNonLdapUsers">Do not authenticate existing WordPress-Users</label>
</th>
<td>
<input type="checkbox" name="authLDAPDoNotOverwriteNonLdapUsers" id="authLDAPDoNotOverwriteNonLdapUsers" value="1"<?php echo $tDoNotOverwriteNonLdapUsers; ?>/>
<p class="description">
Shall we prohibit authenticating already in WordPress created users using LDAP? If you enable this, LDAP-Users with the same user-ID
as existing WordPress-Users can no longer take over the WordPress-Users account. This also means that LDAP-Users with the same User-ID as existing
WordPress-Users will <strong>not</strong> be able to authenticate anymore! Accounts that have been taken over already will not be affected by this setting.
</p>
<p class="description">This should only be checked if you know what you are doing!</p>
</td>
</tr>
<tr>
<th>
<label for="authLDAPCachePW">Save entered passwords in the wordpress user table?</label>
</th>
<td>
<input type="checkbox" name="authLDAPCachePW" id="authLDAPCachePW" value="1"<?php echo $tPWChecked; ?>/>
</td>
</tr>
<tr>
<th>
<label for="authLDAPGroupEnable">Map LDAP Groups to wordpress Roles?</label>
</th>
<td>
<input type="checkbox" name="authLDAPGroupEnable" id="authLDAPGroupEnable" value="1"<?php echo $tGroupChecked; ?>/>
<p class="description">
Search LDAP for user's groups and map to Wordpress Roles.
</p>
</td>
</tr>
</table>
</fieldset>
<h3 class="title">General Server Settings</h3>
<fieldset class="options">
<table class="form-table">
<tr>
<th>
<label for="authLDAPURI">LDAP URI</label>
</th>
<td>
<input type="text" name="authLDAPURI" id="authLDAPURI" placeholder="LDAP-URI"
class="regular-text" value="<?php echo $authLDAPURI; ?>"/>
<p class="description">
The <abbr title="Uniform Ressource Identifier">URI</abbr>
for connecting to the LDAP-Server. This usualy takes the form
<var>&lt;scheme&gt;://&lt;user&gt;:&lt;password&gt;@&lt;server&gt;/&lt;path&gt;</var>
according to RFC 1738.</p>
<p class="description">
In this case it schould be something like
<var>ldap://uid=adminuser,dc=example,c=com:secret@ldap.example.com/dc=basePath,dc=example,c=com</var>.
</p>
<p class="description">
If your LDAP accepts anonymous login, you can ommit the user and
password-Part of the URI
</p>
<p class="description">
You can use the pseudo-schema <em>env</em> to provide your LDAP-URI from an environment-variable. So if you have your
LDAP-URI in a variable called <code>LDAP_URI</code> you can enter <code>env:LDAP_URI</code> in this field and at runtime the
appropriate value will be taken from the Environment-variable <code>LDAP_URI</code>. If the varialbe is not set, then the value will be empty.
</p>
<p class="description">
You can also provide different parts of the LDP-URI from environment variables by providing
<code>%env:[VARIABLENAME]%</code> within your LDAP-URI. So if you want to provide the
password from an Environment-variable <code>LDAP_PASSWORD</code> your LDAP-URI looks like
<code>ldap://uid=adminuser,dc=example,c=com:%env:LDAP_PASSWORD%@ldap.example.com/dc=basePath,dc=example,c=com</code>
</p>
<p class="description">
<strong>Caveat!</strong><br/>
If you are using Environment-variables for parts of the LDAP-URL then those <strong>must not</strong> be URL-Encoded!<br/>
Otherwise the different parts <strong>must</strong> be URL-Encoded!
</p>
</td>
</tr>
<tr>
<th>
<label for="authLDAPURISeparator">LDAP URI-Separator</label>
</th>
<td>
<input type="text" name="authLDAPURISeparator" id="authLDAPURISeparator" placeholder="LDAP-URI Separator"
class="regular-text" value="<?php echo $authLDAPURISeparator; ?>"/>
<p class="description">
A separator that separates multiple LDAP-URIs from one another.
You can use that feature to try to authenticate against multiple LDAP-Servers
as long as they all have the same attribute-settings. The first LDAP-Server the user can
authenticate against will be used to handle the user.
</td>
</tr>
<tr>
<th>
<label for="authLDAPStartTLS" class="description">StartTLS</label>
</th>
<td>
<input type="checkbox" name="authLDAPStartTLS" id="authLDAPStartTLS" value="1"<?php echo $tStartTLSChecked; ?>/>
<p class="description">
Use StartTLS for encryption of ldap connections. This setting is not to be used in combination with ldaps connections (ldap:// only).
</p>
</td>
<tr>
<th scope="row">
<label for="authLDAPFilter" class="description">Filter</label>
</th>
<td>
<input type="text" name="authLDAPFilter" id="authLDAPFilter" placeholder="(uid=%s)"
class="regular-text" value="<?php echo $authLDAPFilter; ?>"/>
<p class="description">
Please provide a valid filter that can be used for querying the
<abbr title="Lightweight Directory Access Protocol">LDAP</abbr>
for the correct user. For more information on this
feature have a look at <a href="http://andreas.heigl.org/cat/dev/wp/authldap">http://andreas.heigl.org/cat/dev/wp/authldap</a>
</p>
<p class="description">
This field <strong>should</strong> include the string <code>%s</code>
that will be replaced with the username provided during log-in
</p>
<p class="description">
If you leave this field empty it defaults to <strong>(uid=%s)</strong>
</p>
</td>
</tr>
</table>
</fieldset>
<h3 class="title">Settings for creating new Users</h3>
<fieldset class="options">
<table class="form-table">
<tr>
<th scope="row">
<label for="authLDAPUseUserAccount">User-Read</label>
</th>
<td>
<input type="checkbox" name="authLDAPUseUserAccount" id="authLDAPUseUserAccount" value="1"<?php echo $tUserRead; ?>/><br />
<p class="description">
If checked the plugin will use the user's account to query their own information. If not it will use the admin account.
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPNameAttr">Name-Attribute</label>
</th>
<td>
<input type="text" name="authLDAPNameAttr" id="authLDAPNameAttr" placeholder="name"
class="regular-text" value="<?php echo $authLDAPNameAttr; ?>"/><br />
<p class="description">
Which Attribute from the LDAP contains the Full or the First name
of the user trying to log in.
</p>
<p class="description">
This defaults to <strong>name</strong>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPSecName">Second Name Attribute</label>
</th>
<td>
<input type="text" name="authLDAPSecName" id="authLDAPSecName" placeholder=""
class="regular-text" value="<?php echo $authLDAPSecName; ?>" />
<p class="description">
If the above Name-Attribute only contains the First Name of the
user you can here specify an Attribute that contains the second name.
</p>
<p class="description">
This field is empty by default
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPUidAttr">User-ID Attribute</label>
</th>
<td>
<input type="text" name="authLDAPUidAttr" id="authLDAPUidAttr" placeholder="uid"
class="regular-text" value="<?php echo $authLDAPUidAttr; ?>" />
<p class="description">
Please give the Attribute, that is used to identify the user. This
should be the same as you used in the above <em>Filter</em>-Option
</p>
<p class="description">
This field defaults to <strong>uid</strong>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPMailAttr">Mail Attribute</label>
</th>
<td>
<input type="text" name="authLDAPMailAttr" id="authLDAPMailAttr" placeholder="mail"
class="regular-text" value="<?php echo $authLDAPMailAttr; ?>" />
<p class="description">
Which Attribute holds the eMail-Address of the user?
</p>
<p class="description">
If more than one eMail-Address are stored in the LDAP, only the first given is used
</p>
<p class="description">
This field defaults to <strong>mail</strong>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPWebAttr">Web-Attribute</label>
</th>
<td>
<input type="text" name="authLDAPWebAttr" id="authLDAPWebAttr" placeholder=""
class="regular-text" value="<?php echo $authLDAPWebAttr; ?>" />
<p class="description">
If your users have a personal page (URI) stored in the LDAP, it can
be provided here.
</p>
<p class="description">
This field is empty by default
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPDefaultRole">Default Role</label>
</th>
<td>
<select name="authLDAPDefaultRole" id="authLDAPDefaultRole">
<option value="" <?php echo ( $authLDAPDefaultRole == '' ? 'selected="selected"' : '' ); ?>>
None (deny access)
</option>
<?php foreach ($roles->get_names() as $group => $vals) : ?>
<option value="<?php echo $group; ?>" <?php echo ( $authLDAPDefaultRole == $group ? 'selected="selected"' : '' ); ?>>
<?php echo $vals; ?>
</option>
<?php endforeach; ?>
</select>
<p class="description">
Here you can select the default role for users.
If you enable LDAP Groups below, they will take precedence over the Default Role.
</p>
<p class="description">
Existing users will retain their roles unless overriden by LDAP Groups below.
</p>
</td>
</tr>
</table>
</fieldset>
<div id="authldaprolemapping">
<h3 class="title">Groups for Roles</h3>
<fieldset class="options">
<table class="form-table">
<tr>
<th>
<label for="authLDAPGroupOverUser">LDAP Groups override role of existing users?</label>
</th>
<td>
<input type="checkbox" name="authLDAPGroupOverUser" id="authLDAPGroupOverUser" value="1"<?php echo $tGroupOverUserChecked; ?>/>
<p class="description">
If role determined by LDAP Group differs from existing Wordpress User's role, use LDAP Group.
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPGroupBase">Group-Base</label>
</th>
<td>
<input type="text" name="authLDAPGroupBase" id="authLDAPGroupBase" placeholder=""
class="regular-text" value="<?php echo $authLDAPGroupBase; ?>" />
<p class="description">
This is the base dn to lookup groups.
</p>
<p class="description">
If empty the base dn of the LDAP URI will be used
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPGroupAttr">Group-Attribute</label>
</th>
<td>
<input type="text" name="authLDAPGroupAttr" id="authLDAPGroupAttr" placeholder="gidNumber"
class="regular-text" value="<?php echo $authLDAPGroupAttr; ?>" />
<p class="description">
This is the attribute that defines the Group-ID that can be matched
against the Groups defined further down
</p>
<p class="description">
This field defaults to <strong>gidNumber</strong>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPGroupSeparator">Group-Separator</label>
</th>
<td>
<input type="text" name="authLDAPGroupSeparator" id="authLDAPGroupSeparator" placeholder=","
class="regular-text" value="<?php echo $authLDAPGroupSeparator; ?>" />
<p class="description">
This attribute defines the separator used for the Group-IDs listed in the
Groups defined further down. This is useful if the value of Group-Attribute
listed above can contain a comma (for example, when using the memberof attribute)
</p>
<p class="description">
This field defaults to <strong>, (comma)</strong>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPGroupFilter">Group-Filter</label>
</th>
<td>
<input type="text" name="authLDAPGroupFilter" id="authLDAPGroupFilter"
placeholder="(&amp;(objectClass=posixGroup)(memberUid=%s))"
class="regular-text" value="<?php echo $authLDAPGroupFilter; ?>" />
<p class="description">
Here you can add the filter for selecting groups for ther
currentlly logged in user
</p>
<p class="description">
The Filter should contain the string <code>%s</code> which will be replaced by
the login-name of the currently logged in user
</p>
<p class="description">
Alternatively the string <code>%dn%</code> will be replaced by the
DN of the currently logged in user. This can be helpfull if
group-memberships are defined with DNs rather than UIDs
</p>
<p class="description">This field defaults to
<strong>(&amp;(objectClass=posixGroup)(memberUid=%s))</strong>
</p>
</td>
</tr>
</table>
</fieldset>
<h3 class="title">Role - group mapping</h3>
<fieldset class="options">
<p class="description">You can set multiple values per role by separating them with a coma</p>
<p class="description">The values are empty by default</p>
<table class="form-table">
<thead>
<th scope="row">Assign this WordPress-Role</th>
<th style="width:auto;">to members of this/these LDAP-Groups</th>
</thead>
<tbody>
<?php
foreach ($roles->get_names() as $group => $vals) :
$aGroup=$authLDAPGroups[$group]; ?>
<tr>
<th scope="row" style="width:auto; min-width: 200px;">
<label for="authLDAPGroups[<?php echo $group; ?>]">
<?php echo $vals; ?>
</label>
</th>
<td>
<input type="text" name="authLDAPGroups[<?php echo $group; ?>]" id="authLDAPGroups[<?php echo $group; ?>]"
value="<?php echo $aGroup; ?>" />
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</fieldset>
</div>
<fieldset class="buttons">
<p class="submit">
<input type="submit" name="ldapOptionsSave" class="button button-primary" value="Save Changes" />
</p>
</fieldset>
</form>
</div>
<script type="text/javascript">
elem = document.getElementById('authLDAPGroupEnable');
if(! elem.checked) {
document.getElementById('authldaprolemapping').setAttribute('style', 'display:none;');
}
elem.addEventListener('change', function(e){
if(! e.target.checked) {
document.getElementById('authldaprolemapping').setAttribute('style', 'display:none;');
} else {
document.getElementById('authldaprolemapping').removeAttribute('style');
}
});
</script>

View File

@ -0,0 +1,134 @@
<?php
/**
* This file creates a class to build our CSS.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
if ( ! class_exists( 'GeneratePress_Backgrounds_CSS' ) ) {
/**
* Generate our background CSS.
*/
class GeneratePress_Backgrounds_CSS {
/**
* The css selector that you're currently adding rules to
*
* @access protected
* @var string
*/
protected $_selector = ''; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
/**
* Stores the final css output with all of its rules for the current selector.
*
* @access protected
* @var string
*/
protected $_selector_output = ''; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
/**
* Stores all of the rules that will be added to the selector
*
* @access protected
* @var string
*/
protected $_css = ''; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
/**
* The string that holds all of the css to output
*
* @access protected
* @var string
*/
protected $_output = ''; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
/**
* Sets a selector to the object and changes the current selector to a new one
*
* @access public
* @since 1.0
*
* @param string $selector - the css identifier of the html that you wish to target.
* @return $this
*/
public function set_selector( $selector = '' ) {
// Render the css in the output string everytime the selector changes.
if ( '' !== $this->_selector ) {
$this->add_selector_rules_to_output();
}
$this->_selector = $selector;
return $this;
}
/**
* Adds a css property with value to the css output
*
* @access public
* @since 1.0
*
* @param string $property - the css property.
* @param string $value - the value to be placed with the property.
* @param string $url Whether we need to generate URL in the string.
* @return $this
*/
public function add_property( $property, $value, $url = '' ) {
// If we don't have a value or our value is the same as our og default, bail.
if ( empty( $value ) ) {
return false;
}
// Set up our background image URL param if needed.
$url_start = ( '' !== $url ) ? "url('" : ""; // phpcs:ignore -- need double quotes.
$url_end = ( '' !== $url ) ? "')" : ""; // phpcs:ignore -- need double quotes.
$this->_css .= $property . ':' . $url_start . $value . $url_end . ';';
return $this;
}
/**
* Adds the current selector rules to the output variable
*
* @access private
* @since 1.0
*
* @return $this
*/
private function add_selector_rules_to_output() {
if ( ! empty( $this->_css ) ) {
$this->_selector_output = $this->_selector;
$selector_output = sprintf( '%1$s{%2$s}', $this->_selector_output, $this->_css );
$this->_output .= $selector_output;
// Reset the css.
$this->_css = '';
}
return $this;
}
/**
* Returns the minified css in the $_output variable
*
* @access public
* @since 1.0
*
* @return string
*/
public function css_output() {
// Add current selector's rules to output.
$this->add_selector_rules_to_output();
// Output minified css.
return $this->_output;
}
}
}

View File

@ -0,0 +1,420 @@
<?php
/**
* This file handles Secondary Nav background images.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
if ( ! function_exists( 'generate_backgrounds_secondary_nav_customizer' ) ) {
add_action( 'customize_register', 'generate_backgrounds_secondary_nav_customizer', 1000 );
/**
* Adds our Secondary Nav background image options
*
* These options are in their own function so we can hook it in late to
* make sure Secondary Nav is activated.
*
* 1000 priority is there to make sure Secondary Nav is registered (999)
* as we check to see if the layout control exists.
*
* Secondary Nav now uses 100 as a priority.
*
* @param object $wp_customize Our Customizer object.
*/
function generate_backgrounds_secondary_nav_customizer( $wp_customize ) {
if ( ! function_exists( 'generate_secondary_nav_get_defaults' ) ) {
return;
}
if ( ! $wp_customize->get_section( 'secondary_nav_section' ) ) {
return;
}
$defaults = generate_secondary_nav_get_defaults();
if ( method_exists( $wp_customize, 'register_control_type' ) ) {
$wp_customize->register_control_type( 'GeneratePress_Section_Shortcut_Control' );
}
require_once GP_LIBRARY_DIRECTORY . 'customizer-helpers.php';
$wp_customize->add_section(
'secondary_bg_images_section',
array(
'title' => __( 'Secondary Navigation', 'gp-premium' ),
'capability' => 'edit_theme_options',
'description' => '',
'panel' => 'generate_backgrounds_panel',
'priority' => 21,
)
);
$wp_customize->add_control(
new GeneratePress_Section_Shortcut_Control(
$wp_customize,
'generate_secondary_navigation_background_image_shortcuts',
array(
'section' => 'secondary_bg_images_section',
'element' => __( 'Secondary Navigation', 'gp-premium' ),
'shortcuts' => array(
'layout' => 'secondary_nav_section',
'colors' => 'secondary_navigation_color_section',
'typography' => 'secondary_font_section',
),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
'priority' => 1,
)
)
);
$wp_customize->add_setting(
'generate_secondary_nav_settings[nav_image]',
array(
'default' => $defaults['nav_image'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'esc_url_raw',
)
);
$wp_customize->add_control(
new WP_Customize_Image_Control(
$wp_customize,
'generate_secondary_backgrounds-nav-image',
array(
'section' => 'secondary_bg_images_section',
'settings' => 'generate_secondary_nav_settings[nav_image]',
'priority' => 750,
'label' => __( 'Navigation', 'gp-premium' ),
)
)
);
$wp_customize->add_setting(
'generate_secondary_nav_settings[nav_repeat]',
array(
'default' => $defaults['nav_repeat'],
'type' => 'option',
'sanitize_callback' => 'generate_premium_sanitize_choices',
)
);
$wp_customize->add_control(
'generate_secondary_nav_settings[nav_repeat]',
array(
'type' => 'select',
'section' => 'secondary_bg_images_section',
'choices' => array(
'' => __( 'Repeat', 'gp-premium' ),
'repeat-x' => __( 'Repeat x', 'gp-premium' ),
'repeat-y' => __( 'Repeat y', 'gp-premium' ),
'no-repeat' => __( 'No Repeat', 'gp-premium' ),
),
'settings' => 'generate_secondary_nav_settings[nav_repeat]',
'priority' => 800,
)
);
$wp_customize->add_setting(
'generate_secondary_nav_settings[nav_item_image]',
array(
'default' => $defaults['nav_item_image'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'esc_url_raw',
)
);
$wp_customize->add_control(
new WP_Customize_Image_Control(
$wp_customize,
'generate_secondary_backgrounds-nav-item-image',
array(
'section' => 'secondary_bg_images_section',
'settings' => 'generate_secondary_nav_settings[nav_item_image]',
'priority' => 950,
'label' => __( 'Navigation Item', 'gp-premium' ),
)
)
);
$wp_customize->add_setting(
'generate_secondary_nav_settings[nav_item_repeat]',
array(
'default' => $defaults['nav_item_repeat'],
'type' => 'option',
'sanitize_callback' => 'generate_premium_sanitize_choices',
)
);
$wp_customize->add_control(
'generate_secondary_nav_settings[nav_item_repeat]',
array(
'type' => 'select',
'section' => 'secondary_bg_images_section',
'choices' => array(
'' => __( 'Repeat', 'gp-premium' ),
'repeat-x' => __( 'Repeat x', 'gp-premium' ),
'repeat-y' => __( 'Repeat y', 'gp-premium' ),
'no-repeat' => __( 'No Repeat', 'gp-premium' ),
),
'settings' => 'generate_secondary_nav_settings[nav_item_repeat]',
'priority' => 1000,
)
);
$wp_customize->add_setting(
'generate_secondary_nav_settings[nav_item_hover_image]',
array(
'default' => $defaults['nav_item_hover_image'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'esc_url_raw',
)
);
$wp_customize->add_control(
new WP_Customize_Image_Control(
$wp_customize,
'generate_secondary_backgrounds-nav-item-hover-image',
array(
'section' => 'secondary_bg_images_section',
'settings' => 'generate_secondary_nav_settings[nav_item_hover_image]',
'priority' => 1150,
'label' => __( 'Navigation Item Hover', 'gp-premium' ),
)
)
);
$wp_customize->add_setting(
'generate_secondary_nav_settings[nav_item_hover_repeat]',
array(
'default' => $defaults['nav_item_hover_repeat'],
'type' => 'option',
'sanitize_callback' => 'generate_premium_sanitize_choices',
)
);
$wp_customize->add_control(
'generate_secondary_nav_settings[nav_item_hover_repeat]',
array(
'type' => 'select',
'section' => 'secondary_bg_images_section',
'choices' => array(
'' => __( 'Repeat', 'gp-premium' ),
'repeat-x' => __( 'Repeat x', 'gp-premium' ),
'repeat-y' => __( 'Repeat y', 'gp-premium' ),
'no-repeat' => __( 'No Repeat', 'gp-premium' ),
),
'settings' => 'generate_secondary_nav_settings[nav_item_hover_repeat]',
'priority' => 1200,
)
);
$wp_customize->add_setting(
'generate_secondary_nav_settings[nav_item_current_image]',
array(
'default' => $defaults['nav_item_current_image'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'esc_url_raw',
)
);
$wp_customize->add_control(
new WP_Customize_Image_Control(
$wp_customize,
'generate_secondary_backgrounds-nav-item-current-image',
array(
'section' => 'secondary_bg_images_section',
'settings' => 'generate_secondary_nav_settings[nav_item_current_image]',
'priority' => 1350,
'label' => __( 'Navigation Item Current', 'gp-premium' ),
)
)
);
$wp_customize->add_setting(
'generate_secondary_nav_settings[nav_item_current_repeat]',
array(
'default' => $defaults['nav_item_current_repeat'],
'type' => 'option',
'sanitize_callback' => 'generate_premium_sanitize_choices',
)
);
$wp_customize->add_control(
'generate_secondary_nav_settings[nav_item_current_repeat]',
array(
'type' => 'select',
'section' => 'secondary_bg_images_section',
'choices' => array(
'' => __( 'Repeat', 'gp-premium' ),
'repeat-x' => __( 'Repeat x', 'gp-premium' ),
'repeat-y' => __( 'Repeat y', 'gp-premium' ),
'no-repeat' => __( 'No Repeat', 'gp-premium' ),
),
'settings' => 'generate_secondary_nav_settings[nav_item_current_repeat]',
'priority' => 1400,
)
);
$wp_customize->add_section(
'secondary_subnav_bg_images_section',
array(
'title' => __( 'Secondary Sub-Navigation', 'gp-premium' ),
'capability' => 'edit_theme_options',
'description' => '',
'panel' => 'generate_backgrounds_panel',
'priority' => 22,
)
);
$wp_customize->add_setting(
'generate_secondary_nav_settings[sub_nav_item_image]',
array(
'default' => $defaults['sub_nav_item_image'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'esc_url_raw',
)
);
$wp_customize->add_control(
new WP_Customize_Image_Control(
$wp_customize,
'generate_secondary_backgrounds-sub-nav-item-image',
array(
'section' => 'secondary_subnav_bg_images_section',
'settings' => 'generate_secondary_nav_settings[sub_nav_item_image]',
'priority' => 1700,
'label' => __( 'Sub-Navigation Item', 'gp-premium' ),
)
)
);
$wp_customize->add_setting(
'generate_secondary_nav_settings[sub_nav_item_repeat]',
array(
'default' => $defaults['sub_nav_item_repeat'],
'type' => 'option',
'sanitize_callback' => 'generate_premium_sanitize_choices',
)
);
$wp_customize->add_control(
'generate_secondary_nav_settings[sub_nav_item_repeat]',
array(
'type' => 'select',
'section' => 'secondary_subnav_bg_images_section',
'choices' => array(
'' => __( 'Repeat', 'gp-premium' ),
'repeat-x' => __( 'Repeat x', 'gp-premium' ),
'repeat-y' => __( 'Repeat y', 'gp-premium' ),
'no-repeat' => __( 'No Repeat', 'gp-premium' ),
),
'settings' => 'generate_secondary_nav_settings[sub_nav_item_repeat]',
'priority' => 1800,
)
);
$wp_customize->add_setting(
'generate_secondary_nav_settings[sub_nav_item_hover_image]',
array(
'default' => $defaults['sub_nav_item_hover_image'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'esc_url_raw',
)
);
$wp_customize->add_control(
new WP_Customize_Image_Control(
$wp_customize,
'generate_secondary_backgrounds-sub-nav-item-hover-image',
array(
'section' => 'secondary_subnav_bg_images_section',
'settings' => 'generate_secondary_nav_settings[sub_nav_item_hover_image]',
'priority' => 2000,
'label' => __( 'Sub-Navigation Item Hover', 'gp-premium' ),
)
)
);
$wp_customize->add_setting(
'generate_secondary_nav_settings[sub_nav_item_hover_repeat]',
array(
'default' => $defaults['sub_nav_item_hover_repeat'],
'type' => 'option',
'sanitize_callback' => 'generate_premium_sanitize_choices',
)
);
$wp_customize->add_control(
'generate_secondary_nav_settings[sub_nav_item_hover_repeat]',
array(
'type' => 'select',
'section' => 'secondary_subnav_bg_images_section',
'choices' => array(
'' => __( 'Repeat', 'gp-premium' ),
'repeat-x' => __( 'Repeat x', 'gp-premium' ),
'repeat-y' => __( 'Repeat y', 'gp-premium' ),
'no-repeat' => __( 'No Repeat', 'gp-premium' ),
),
'settings' => 'generate_secondary_nav_settings[sub_nav_item_hover_repeat]',
'priority' => 2100,
)
);
$wp_customize->add_setting(
'generate_secondary_nav_settings[sub_nav_item_current_image]',
array(
'default' => $defaults['sub_nav_item_current_image'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'esc_url_raw',
)
);
$wp_customize->add_control(
new WP_Customize_Image_Control(
$wp_customize,
'generate_secondary_backgrounds-sub-nav-item-current-image',
array(
'section' => 'secondary_subnav_bg_images_section',
'settings' => 'generate_secondary_nav_settings[sub_nav_item_current_image]',
'priority' => 2300,
'label' => __( 'Sub-Navigation Item Current', 'gp-premium' ),
)
)
);
$wp_customize->add_setting(
'generate_secondary_nav_settings[sub_nav_item_current_repeat]',
array(
'default' => $defaults['sub_nav_item_current_repeat'],
'type' => 'option',
'sanitize_callback' => 'generate_premium_sanitize_choices',
)
);
$wp_customize->add_control(
'generate_secondary_nav_settings[sub_nav_item_current_repeat]',
array(
'type' => 'select',
'section' => 'secondary_subnav_bg_images_section',
'choices' => array(
'' => __( 'Repeat', 'gp-premium' ),
'repeat-x' => __( 'Repeat x', 'gp-premium' ),
'repeat-y' => __( 'Repeat y', 'gp-premium' ),
'no-repeat' => __( 'No Repeat', 'gp-premium' ),
),
'settings' => 'generate_secondary_nav_settings[sub_nav_item_current_repeat]',
'priority' => 2400,
)
);
}
}

View File

@ -0,0 +1,19 @@
<?php
/**
* Backgrounds module.
*
* @since 1.1.0
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
// Define the version. This used to be a standalone plugin, so we need to keep this constant.
if ( ! defined( 'GENERATE_BACKGROUNDS_VERSION' ) ) {
define( 'GENERATE_BACKGROUNDS_VERSION', GP_PREMIUM_VERSION );
}
require plugin_dir_path( __FILE__ ) . 'functions/functions.php';

View File

@ -0,0 +1,169 @@
<?php
/**
* This file handles column-related functionality.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
if ( ! function_exists( 'generate_blog_get_columns' ) ) {
/**
* Initiate columns.
*
* @since 0.1
*/
function generate_blog_get_columns() {
$generate_blog_settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
// If columns are enabled, set to true.
$columns = ( $generate_blog_settings['column_layout'] ) ? true : false;
// If we're not dealing with posts, set it to false.
// Check for is_home() to prevent bug in Yoast that throws off the post type check.
$columns = ( 'post' === get_post_type() || is_search() || is_home() ) ? $columns : false;
// If masonry is enabled via filter, enable columns.
// phpcs:ignore -- Non-strict comparison allowed.
$columns = ( 'true' == apply_filters( 'generate_blog_masonry', 'false' ) ) ? true : $columns;
// If we're on a singular post or page, disable.
$columns = ( is_singular() ) ? false : $columns;
// Turn off columns if we're on a WooCommerce search page.
if ( function_exists( 'is_woocommerce' ) ) {
$columns = ( is_woocommerce() && is_search() ) ? false : $columns;
}
// Bail if there's no search results.
if ( is_search() ) {
global $wp_query;
// phpcs:ignore -- non-strict comparison allowed.
if ( 0 == $wp_query->post_count ) {
$columns = false;
}
}
// Return the result.
return apply_filters( 'generate_blog_columns', $columns );
}
}
if ( ! function_exists( 'generate_blog_get_masonry' ) ) {
/**
* Check if masonry is enabled.
* This function is a mess with strings as bools etc.. Will re-write in a big upate to get lots of testing.
*/
function generate_blog_get_masonry() {
$generate_blog_settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
// If masonry is enabled via option or filter, enable it.
// phpcs:ignore -- non-strict comparison allowed.
if ( $generate_blog_settings['masonry'] || 'true' == apply_filters( 'generate_blog_masonry', 'false' ) ) {
$masonry = 'true';
} else {
$masonry = 'false';
}
// Allow masonry to be turned off using a boolean.
if ( false === apply_filters( 'generate_blog_masonry', 'false' ) ) {
$masonry = 'false';
}
return $masonry;
}
}
if ( ! function_exists( 'generate_blog_add_columns_container' ) ) {
add_action( 'generate_before_main_content', 'generate_blog_add_columns_container' );
/**
* Add columns container
*
* @since 1.0
*/
function generate_blog_add_columns_container() {
if ( ! generate_blog_get_columns() ) {
return;
}
$columns = generate_blog_get_column_count();
printf(
'<div class="generate-columns-container %1$s">%2$s',
'false' !== generate_blog_get_masonry() ? 'masonry-container are-images-unloaded' : '',
'false' !== generate_blog_get_masonry() ? '<div class="grid-sizer grid-' . esc_attr( $columns ) . ' tablet-grid-50 mobile-grid-100"></div>' : '' // phpcs:ignore -- no escaping needed.
);
}
}
if ( ! function_exists( 'generate_blog_add_ending_columns_container' ) ) {
add_action( 'generate_after_main_content', 'generate_blog_add_ending_columns_container' );
/**
* Add closing columns container
*
* @since 1.0
*/
function generate_blog_add_ending_columns_container() {
if ( ! generate_blog_get_columns() ) {
return;
}
echo '</div><!-- .generate-columns-contaier -->';
}
}
if ( ! function_exists( 'generate_blog_columns_css' ) ) {
/**
* Add inline CSS
*/
function generate_blog_columns_css() {
$generate_blog_settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
if ( function_exists( 'generate_spacing_get_defaults' ) ) {
$spacing_settings = wp_parse_args(
get_option( 'generate_spacing_settings', array() ),
generate_spacing_get_defaults()
);
}
$separator = ( function_exists( 'generate_spacing_get_defaults' ) ) ? absint( $spacing_settings['separator'] ) : 20;
$return = '';
if ( generate_blog_get_columns() ) {
$return .= '.generate-columns {margin-bottom: ' . $separator . 'px;padding-left: ' . $separator . 'px;}';
$return .= '.generate-columns-container {margin-left: -' . $separator . 'px;}';
$return .= '.page-header {margin-bottom: ' . $separator . 'px;margin-left: ' . $separator . 'px}';
$return .= '.generate-columns-container > .paging-navigation {margin-left: ' . $separator . 'px;}';
}
return $return;
}
}
if ( ! function_exists( 'generate_blog_get_column_count' ) ) {
/**
* Get our column grid class
*/
function generate_blog_get_column_count() {
$generate_blog_settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
$count = $generate_blog_settings['columns'];
return apply_filters( 'generate_blog_get_column_count', $count );
}
}

View File

@ -0,0 +1,149 @@
.masonry-enabled .page-header {
position: relative !important;
}
.separate-containers .site-main > .generate-columns-container {
margin-bottom: 0;
}
.masonry-container.are-images-unloaded,
.load-more.are-images-unloaded,
.masonry-enabled #nav-below {
opacity: 0;
}
/* columns */
.generate-columns-container:not(.masonry-container) {
display: flex;
flex-wrap: wrap;
align-items: stretch;
}
.generate-columns .inside-article {
height: 100%;
box-sizing: border-box;
}
.generate-columns-activated.post-image-aligned-left .generate-columns-container article:not(.featured-column) .post-image,
.generate-columns-activated.post-image-aligned-right .generate-columns-container article:not(.featured-column) .post-image {
float: none;
text-align: center;
margin-left: 0;
margin-right: 0;
}
.generate-columns-container .paging-navigation,
.generate-columns-container .page-header {
flex: 1 1 100%;
clear: both;
}
.generate-columns-container .paging-navigation {
margin-bottom: 0;
}
.load-more:not(.has-svg-icon) .button.loading:before {
content: "\e900";
display: inline-block;
font-family: "GP Premium";
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
animation: spin 2s infinite linear;
margin-right: 7px;
}
.load-more .button:not(.loading) .gp-icon {
display: none;
}
.load-more .gp-icon svg {
animation: spin 2s infinite linear;
margin-right: 7px;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.generate-columns {
box-sizing: border-box;
}
.generate-columns.grid-20,
.grid-sizer.grid-20 {
width: 20%;
}
.generate-columns.grid-25,
.grid-sizer.grid-25 {
width: 25%;
}
.generate-columns.grid-33,
.grid-sizer.grid-33 {
width: 33.3333%;
}
.generate-columns.grid-50,
.grid-sizer.grid-50 {
width: 50%;
}
.generate-columns.grid-60,
.grid-sizer.grid-60 {
width: 60%;
}
.generate-columns.grid-66,
.grid-sizer.grid-66 {
width: 66.66667%;
}
.generate-columns.grid-100,
.grid-sizer.grid-100 {
width: 100%;
}
@media (min-width: 768px) and (max-width: 1024px) {
.generate-columns.tablet-grid-50,
.grid-sizer.tablet-grid-50 {
width: 50%;
}
}
@media (max-width: 767px) {
.generate-columns-activated .generate-columns-container {
margin-left: 0;
margin-right: 0;
}
.generate-columns-container > *,
.generate-columns-container .generate-columns {
padding-left: 0;
}
.generate-columns-container .page-header {
margin-left: 0;
}
.generate-columns.mobile-grid-100,
.grid-sizer.mobile-grid-100 {
width: 100%;
}
.generate-columns-container > .paging-navigation {
margin-left: 0;
}
}
@media (max-width: 768px) {
.load-more {
display: block;
text-align: center;
margin-bottom: 0;
}
}

View File

@ -0,0 +1 @@
.masonry-enabled .page-header{position:relative!important}.separate-containers .site-main>.generate-columns-container{margin-bottom:0}.load-more.are-images-unloaded,.masonry-container.are-images-unloaded,.masonry-enabled #nav-below{opacity:0}.generate-columns-container:not(.masonry-container){display:flex;flex-wrap:wrap;align-items:stretch}.generate-columns .inside-article{height:100%;box-sizing:border-box}.generate-columns-activated.post-image-aligned-left .generate-columns-container article:not(.featured-column) .post-image,.generate-columns-activated.post-image-aligned-right .generate-columns-container article:not(.featured-column) .post-image{float:none;text-align:center;margin-left:0;margin-right:0}.generate-columns-container .page-header,.generate-columns-container .paging-navigation{flex:1 1 100%;clear:both}.generate-columns-container .paging-navigation{margin-bottom:0}.load-more:not(.has-svg-icon) .button.loading:before{content:"\e900";display:inline-block;font-family:"GP Premium";font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;animation:spin 2s infinite linear;margin-right:7px}.load-more .button:not(.loading) .gp-icon{display:none}.load-more .gp-icon svg{animation:spin 2s infinite linear;margin-right:7px}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.generate-columns{box-sizing:border-box}.generate-columns.grid-20,.grid-sizer.grid-20{width:20%}.generate-columns.grid-25,.grid-sizer.grid-25{width:25%}.generate-columns.grid-33,.grid-sizer.grid-33{width:33.3333%}.generate-columns.grid-50,.grid-sizer.grid-50{width:50%}.generate-columns.grid-60,.grid-sizer.grid-60{width:60%}.generate-columns.grid-66,.grid-sizer.grid-66{width:66.66667%}.generate-columns.grid-100,.grid-sizer.grid-100{width:100%}@media (min-width:768px) and (max-width:1024px){.generate-columns.tablet-grid-50,.grid-sizer.tablet-grid-50{width:50%}}@media (max-width:767px){.generate-columns-activated .generate-columns-container{margin-left:0;margin-right:0}.generate-columns-container .generate-columns,.generate-columns-container>*{padding-left:0}.generate-columns-container .page-header{margin-left:0}.generate-columns.mobile-grid-100,.grid-sizer.mobile-grid-100{width:100%}.generate-columns-container>.paging-navigation{margin-left:0}}@media (max-width:768px){.load-more{display:block;text-align:center;margin-bottom:0}}

View File

@ -0,0 +1,104 @@
.post-image-above-header .inside-article .post-image,
.post-image-above-header .inside-article .featured-image {
margin-top: 0;
margin-bottom: 2em;
}
.post-image-aligned-left .inside-article .post-image,
.post-image-aligned-left .inside-article .featured-image {
margin-top: 0;
margin-right: 2em;
float: left;
text-align: left;
}
.post-image-aligned-center .post-image,
.post-image-aligned-center .featured-image {
text-align: center;
}
.post-image-aligned-right .inside-article .post-image,
.post-image-aligned-right .inside-article .featured-image {
margin-top: 0;
margin-left: 2em;
float: right;
text-align: right;
}
.post-image-below-header.post-image-aligned-right .inside-article .post-image,
.post-image-below-header.post-image-aligned-right .inside-article .featured-image,
.post-image-below-header.post-image-aligned-center .inside-article .featured-image,
.post-image-below-header.post-image-aligned-left .inside-article .post-image,
.post-image-below-header.post-image-aligned-left .inside-article .featured-image {
margin-top: 2em;
}
.post-image-aligned-left > .featured-image,
.post-image-aligned-right > .featured-image {
float: none;
margin-left: auto;
margin-right: auto;
}
.post-image-aligned-left .featured-image {
text-align: left;
}
.post-image-aligned-right .featured-image {
text-align: right;
}
.post-image-aligned-left .inside-article:before,
.post-image-aligned-left .inside-article:after,
.post-image-aligned-right .inside-article:before,
.post-image-aligned-right .inside-article:after {
content: "";
display: table;
}
.post-image-aligned-left .inside-article:after,
.post-image-aligned-right .inside-article:after {
clear: both;
}
.one-container.post-image-above-header .page-header + .no-featured-image-padding .inside-article .post-image,
.one-container.post-image-above-header .no-featured-image-padding.generate-columns .inside-article .post-image {
margin-top: 0;
}
.one-container.right-sidebar.post-image-aligned-center .no-featured-image-padding .post-image,
.one-container.right-sidebar.post-image-aligned-center .no-featured-image-padding .featured-image,
.one-container.both-right.post-image-aligned-center .no-featured-image-padding .post-image,
.one-container.both-right.post-image-aligned-center .no-featured-image-padding .featured-image {
margin-right: 0;
}
.one-container.left-sidebar.post-image-aligned-center .no-featured-image-padding .post-image,
.one-container.left-sidebar.post-image-aligned-center .no-featured-image-padding .featured-image,
.one-container.both-left.post-image-aligned-center .no-featured-image-padding .post-image,
.one-container.both-left.post-image-aligned-center .no-featured-image-padding .featured-image {
margin-left: 0;
}
.one-container.both-sidebars.post-image-aligned-center .no-featured-image-padding .post-image,
.one-container.both-sidebars.post-image-aligned-center .no-featured-image-padding .featured-image {
margin-left: 0;
margin-right: 0;
}
.one-container.post-image-aligned-center .no-featured-image-padding.generate-columns .post-image,
.one-container.post-image-aligned-center .no-featured-image-padding.generate-columns .featured-image {
margin-left: 0;
margin-right: 0;
}
@media (max-width: 768px) {
body:not(.post-image-aligned-center) .inside-article .post-image,
body:not(.post-image-aligned-center) .featured-image,
body:not(.post-image-aligned-center) .inside-article .featured-image {
margin-right: 0;
margin-left: 0;
float: none;
text-align: center;
}
}

View File

@ -0,0 +1 @@
.post-image-above-header .inside-article .featured-image,.post-image-above-header .inside-article .post-image{margin-top:0;margin-bottom:2em}.post-image-aligned-left .inside-article .featured-image,.post-image-aligned-left .inside-article .post-image{margin-top:0;margin-right:2em;float:left;text-align:left}.post-image-aligned-center .featured-image,.post-image-aligned-center .post-image{text-align:center}.post-image-aligned-right .inside-article .featured-image,.post-image-aligned-right .inside-article .post-image{margin-top:0;margin-left:2em;float:right;text-align:right}.post-image-below-header.post-image-aligned-center .inside-article .featured-image,.post-image-below-header.post-image-aligned-left .inside-article .featured-image,.post-image-below-header.post-image-aligned-left .inside-article .post-image,.post-image-below-header.post-image-aligned-right .inside-article .featured-image,.post-image-below-header.post-image-aligned-right .inside-article .post-image{margin-top:2em}.post-image-aligned-left>.featured-image,.post-image-aligned-right>.featured-image{float:none;margin-left:auto;margin-right:auto}.post-image-aligned-left .featured-image{text-align:left}.post-image-aligned-right .featured-image{text-align:right}.post-image-aligned-left .inside-article:after,.post-image-aligned-left .inside-article:before,.post-image-aligned-right .inside-article:after,.post-image-aligned-right .inside-article:before{content:"";display:table}.post-image-aligned-left .inside-article:after,.post-image-aligned-right .inside-article:after{clear:both}.one-container.post-image-above-header .no-featured-image-padding.generate-columns .inside-article .post-image,.one-container.post-image-above-header .page-header+.no-featured-image-padding .inside-article .post-image{margin-top:0}.one-container.both-right.post-image-aligned-center .no-featured-image-padding .featured-image,.one-container.both-right.post-image-aligned-center .no-featured-image-padding .post-image,.one-container.right-sidebar.post-image-aligned-center .no-featured-image-padding .featured-image,.one-container.right-sidebar.post-image-aligned-center .no-featured-image-padding .post-image{margin-right:0}.one-container.both-left.post-image-aligned-center .no-featured-image-padding .featured-image,.one-container.both-left.post-image-aligned-center .no-featured-image-padding .post-image,.one-container.left-sidebar.post-image-aligned-center .no-featured-image-padding .featured-image,.one-container.left-sidebar.post-image-aligned-center .no-featured-image-padding .post-image{margin-left:0}.one-container.both-sidebars.post-image-aligned-center .no-featured-image-padding .featured-image,.one-container.both-sidebars.post-image-aligned-center .no-featured-image-padding .post-image{margin-left:0;margin-right:0}.one-container.post-image-aligned-center .no-featured-image-padding.generate-columns .featured-image,.one-container.post-image-aligned-center .no-featured-image-padding.generate-columns .post-image{margin-left:0;margin-right:0}@media (max-width:768px){body:not(.post-image-aligned-center) .featured-image,body:not(.post-image-aligned-center) .inside-article .featured-image,body:not(.post-image-aligned-center) .inside-article .post-image{margin-right:0;margin-left:0;float:none;text-align:center}}

View File

@ -0,0 +1,254 @@
.post-image-above-header .inside-article .post-image,
.post-image-above-header .inside-article .featured-image {
margin-top: 0;
margin-bottom: 2em;
}
.post-image-aligned-left .inside-article .post-image,
.post-image-aligned-left .inside-article .featured-image {
margin-top: 0;
margin-right: 2em;
float: left;
text-align: left;
}
.post-image-aligned-center .post-image,
.post-image-aligned-center .featured-image {
text-align: center;
}
.post-image-aligned-right .inside-article .post-image,
.post-image-aligned-right .inside-article .featured-image {
margin-top: 0;
margin-left: 2em;
float: right;
text-align: right;
}
.post-image-below-header.post-image-aligned-right .inside-article .post-image,
.post-image-below-header.post-image-aligned-right .inside-article .featured-image,
.post-image-below-header.post-image-aligned-center .inside-article .featured-image,
.post-image-below-header.post-image-aligned-left .inside-article .post-image,
.post-image-below-header.post-image-aligned-left .inside-article .featured-image {
margin-top: 2em;
}
.post-image-aligned-left > .featured-image,
.post-image-aligned-right > .featured-image {
float: none;
margin-left: auto;
margin-right: auto;
}
.post-image-aligned-left .featured-image {
text-align: left;
}
.post-image-aligned-right .featured-image {
text-align: right;
}
.post-image-aligned-left .inside-article:before,
.post-image-aligned-left .inside-article:after,
.post-image-aligned-right .inside-article:before,
.post-image-aligned-right .inside-article:after {
content: "";
display: table;
}
.post-image-aligned-left .inside-article:after,
.post-image-aligned-right .inside-article:after {
clear: both;
}
.one-container.post-image-above-header .page-header + .no-featured-image-padding .inside-article .post-image,
.one-container.post-image-above-header .no-featured-image-padding.generate-columns .inside-article .post-image {
margin-top: 0;
}
.one-container.right-sidebar.post-image-aligned-center .no-featured-image-padding .post-image,
.one-container.right-sidebar.post-image-aligned-center .no-featured-image-padding .featured-image,
.one-container.both-right.post-image-aligned-center .no-featured-image-padding .post-image,
.one-container.both-right.post-image-aligned-center .no-featured-image-padding .featured-image {
margin-right: 0;
}
.one-container.left-sidebar.post-image-aligned-center .no-featured-image-padding .post-image,
.one-container.left-sidebar.post-image-aligned-center .no-featured-image-padding .featured-image,
.one-container.both-left.post-image-aligned-center .no-featured-image-padding .post-image,
.one-container.both-left.post-image-aligned-center .no-featured-image-padding .featured-image {
margin-left: 0;
}
.one-container.both-sidebars.post-image-aligned-center .no-featured-image-padding .post-image,
.one-container.both-sidebars.post-image-aligned-center .no-featured-image-padding .featured-image {
margin-left: 0;
margin-right: 0;
}
.one-container.post-image-aligned-center .no-featured-image-padding.generate-columns .post-image,
.one-container.post-image-aligned-center .no-featured-image-padding.generate-columns .featured-image {
margin-left: 0;
margin-right: 0;
}
@media (max-width: 768px) {
body:not(.post-image-aligned-center) .inside-article .post-image,
body:not(.post-image-aligned-center) .featured-image,
body:not(.post-image-aligned-center) .inside-article .featured-image {
margin-right: 0;
margin-left: 0;
float: none;
text-align: center;
}
}
.masonry-enabled .page-header {
position: relative !important;
}
.separate-containers .site-main > .generate-columns-container {
margin-bottom: 0;
}
.masonry-container.are-images-unloaded,
.load-more.are-images-unloaded,
.masonry-enabled #nav-below {
opacity: 0;
}
/* columns */
.generate-columns-container:not(.masonry-container) {
display: flex;
flex-wrap: wrap;
align-items: stretch;
}
.generate-columns .inside-article {
height: 100%;
box-sizing: border-box;
}
.generate-columns-activated.post-image-aligned-left .generate-columns-container article:not(.featured-column) .post-image,
.generate-columns-activated.post-image-aligned-right .generate-columns-container article:not(.featured-column) .post-image {
float: none;
text-align: center;
margin-left: 0;
margin-right: 0;
}
.generate-columns-container .paging-navigation,
.generate-columns-container .page-header {
flex: 1 1 100%;
clear: both;
}
.generate-columns-container .paging-navigation {
margin-bottom: 0;
}
.load-more:not(.has-svg-icon) .button.loading:before {
content: "\e900";
display: inline-block;
font-family: "GP Premium";
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
animation: spin 2s infinite linear;
margin-right: 7px;
}
.load-more .button:not(.loading) .gp-icon {
display: none;
}
.load-more .gp-icon svg {
animation: spin 2s infinite linear;
margin-right: 7px;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.generate-columns {
box-sizing: border-box;
}
.generate-columns.grid-20,
.grid-sizer.grid-20 {
width: 20%;
}
.generate-columns.grid-25,
.grid-sizer.grid-25 {
width: 25%;
}
.generate-columns.grid-33,
.grid-sizer.grid-33 {
width: 33.3333%;
}
.generate-columns.grid-50,
.grid-sizer.grid-50 {
width: 50%;
}
.generate-columns.grid-60,
.grid-sizer.grid-60 {
width: 60%;
}
.generate-columns.grid-66,
.grid-sizer.grid-66 {
width: 66.66667%;
}
.generate-columns.grid-100,
.grid-sizer.grid-100 {
width: 100%;
}
@media (min-width: 768px) and (max-width: 1024px) {
.generate-columns.tablet-grid-50,
.grid-sizer.tablet-grid-50 {
width: 50%;
}
}
@media (max-width: 767px) {
.generate-columns-activated .generate-columns-container {
margin-left: 0;
margin-right: 0;
}
.generate-columns-container > *,
.generate-columns-container .generate-columns {
padding-left: 0;
}
.generate-columns-container .page-header {
margin-left: 0;
}
.generate-columns.mobile-grid-100,
.grid-sizer.mobile-grid-100 {
width: 100%;
}
.generate-columns-container > .paging-navigation {
margin-left: 0;
}
}
@media (max-width: 768px) {
.load-more {
display: block;
text-align: center;
margin-bottom: 0;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,58 @@
<?php
defined( 'WPINC' ) or die;
if ( ! function_exists( 'generate_blog_get_defaults' ) ) {
/**
* Set our defaults
*
* @since 0.1
*/
function generate_blog_get_defaults() {
$generate_blog_defaults = array(
'excerpt_length' => '55',
'read_more' => __( 'Read more', 'gp-premium' ),
'read_more_button' => false,
'masonry' => false,
'masonry_load_more' => __( '+ More', 'gp-premium' ),
'masonry_loading' => __( 'Loading...', 'gp-premium' ),
'infinite_scroll' => false,
'infinite_scroll_button' => false,
'post_image' => true,
'post_image_position' => '',
'post_image_alignment' => 'post-image-aligned-center',
'post_image_size' => 'full',
'post_image_width' => '',
'post_image_height' => '',
'post_image_padding' => true,
'single_post_image' => true,
'single_post_image_position' => 'inside-content',
'single_post_image_alignment' => 'center',
'single_post_image_size' => 'full',
'single_post_image_width' => '',
'single_post_image_height' => '',
'single_post_image_padding' => true,
'page_post_image' => true,
'page_post_image_position' => 'above-content',
'page_post_image_alignment' => 'center',
'page_post_image_size' => 'full',
'page_post_image_width' => '',
'page_post_image_height' => '',
'page_post_image_padding' => true,
'date' => true,
'author' => true,
'categories' => true,
'tags' => true,
'comments' => true,
'single_date' => true,
'single_author' => true,
'single_categories' => true,
'single_tags' => true,
'single_post_navigation' => true,
'column_layout' => false,
'columns' => '50',
'featured_column' => false,
);
return apply_filters( 'generate_blog_option_defaults', $generate_blog_defaults );
}
}

View File

@ -0,0 +1,714 @@
<?php
defined( 'WPINC' ) or die;
// Pull in our defaults and functions
require plugin_dir_path( __FILE__ ) . 'defaults.php';
require plugin_dir_path( __FILE__ ) . 'images.php';
require plugin_dir_path( __FILE__ ) . 'columns.php';
require plugin_dir_path( __FILE__ ) . 'customizer.php';
require plugin_dir_path( __FILE__ ) . 'migrate.php';
if ( ! function_exists( 'generate_blog_scripts' ) ) {
add_action( 'wp_enqueue_scripts', 'generate_blog_scripts', 50 );
/**
* Enqueue scripts and styles
*/
function generate_blog_scripts() {
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
$settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
wp_add_inline_style( 'generate-style', generate_blog_css() );
wp_add_inline_style( 'generate-style', generate_blog_columns_css() );
$deps = array();
if ( 'true' == generate_blog_get_masonry() && generate_blog_get_columns() ) {
$deps[] = 'masonry';
$deps[] = 'imagesloaded';
}
if ( $settings[ 'infinite_scroll' ] && ! is_singular() && ! is_404() && ! is_post_type_archive( 'product' ) ) {
$deps[] = 'infinite-scroll';
wp_enqueue_script( 'infinite-scroll', plugin_dir_url( __FILE__ ) . 'js/infinite-scroll.pkgd.min.js', array(), '3.0.6', true );
$font_icons = true;
if ( function_exists( 'generate_get_option' ) ) {
if ( 'font' !== generate_get_option( 'icons' ) ) {
$font_icons = false;
}
}
if ( $settings['infinite_scroll_button'] && $font_icons ) {
wp_enqueue_style( 'gp-premium-icons' );
}
}
if ( ( 'true' == generate_blog_get_masonry() && generate_blog_get_columns() ) || ( $settings[ 'infinite_scroll' ] && ! is_singular() && ! is_404() && ! is_post_type_archive( 'product' ) ) ) {
wp_enqueue_script( 'generate-blog', plugin_dir_url( __FILE__ ) . "js/scripts{$suffix}.js", $deps, GENERATE_BLOG_VERSION, true );
wp_localize_script(
'generate-blog',
'generateBlog',
array(
'more' => $settings['masonry_load_more'],
'loading' => $settings['masonry_loading'],
'icon' => function_exists( 'generate_get_svg_icon' ) ? generate_get_svg_icon( 'spinner' ) : '',
'masonryInit' => apply_filters(
'generate_blog_masonry_init',
array(
'columnWidth' => '.grid-sizer',
'itemSelector' => '.masonry-post',
'stamp' => '.page-header',
'percentPosition' => true,
'stagger' => 30,
'visibleStyle' => array(
'transform' => 'translateY(0)',
'opacity' => 1,
),
'hiddenStyle' => array(
'transform' => 'translateY(5px)',
'opacity' => 0,
),
)
),
'infiniteScrollInit' => apply_filters(
'generate_blog_infinite_scroll_init',
array(
'path' => '.infinite-scroll-path a',
'append' => '#main .infinite-scroll-item',
'history' => false,
'loadOnScroll' => $settings['infinite_scroll_button'] ? false : true,
'button' => $settings['infinite_scroll_button'] ? '.load-more a' : null,
'scrollThreshold' => $settings['infinite_scroll_button'] ? false : 600,
)
),
)
);
}
$needs_columns_css = false;
$needs_featured_image_css = false;
if ( generate_blog_get_columns() || $settings['infinite_scroll'] ) {
$needs_columns_css = true;
}
if ( ! is_singular() ) {
if ( $settings['post_image'] ) {
$needs_featured_image_css = true;
}
}
if ( is_page() && has_post_thumbnail() ) {
if ( $settings['page_post_image'] ) {
$needs_featured_image_css = true;
}
}
if ( is_single() && has_post_thumbnail() ) {
if ( $settings['single_post_image'] ) {
$needs_featured_image_css = true;
}
}
if ( $needs_columns_css && $needs_featured_image_css ) {
wp_enqueue_style( 'generate-blog', plugin_dir_url( __FILE__ ) . "css/style{$suffix}.css", array(), GENERATE_BLOG_VERSION );
} elseif ( $needs_columns_css ) {
wp_enqueue_style( 'generate-blog-columns', plugin_dir_url( __FILE__ ) . "css/columns{$suffix}.css", array(), GENERATE_BLOG_VERSION );
} elseif ( $needs_featured_image_css ) {
wp_enqueue_style( 'generate-blog-images', plugin_dir_url( __FILE__ ) . "css/featured-images{$suffix}.css", array(), GENERATE_BLOG_VERSION );
}
}
}
if ( ! function_exists( 'generate_blog_post_classes' ) ) {
add_filter( 'post_class', 'generate_blog_post_classes' );
/**
* Adds custom classes to the content container
*
* @since 0.1
*/
function generate_blog_post_classes( $classes ) {
global $wp_query;
$paged = get_query_var( 'paged' );
$paged = $paged ? $paged : 1;
// Get our options
$settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
if ( $settings['infinite_scroll'] ) {
$classes[] = 'infinite-scroll-item';
}
// Set our masonry class
if ( 'true' == generate_blog_get_masonry() && generate_blog_get_columns() ) {
$classes[] = 'masonry-post';
}
// Set our column classes
if ( generate_blog_get_columns() && ! is_singular() ) {
$classes[] = 'generate-columns';
$classes[] = 'tablet-grid-50';
$classes[] = 'mobile-grid-100';
$classes[] = 'grid-parent';
// Set our featured column class
if ( $wp_query->current_post == 0 && $paged == 1 && $settings['featured_column'] ) {
if ( 50 == generate_blog_get_column_count() ) {
$classes[] = 'grid-100';
}
if ( 33 == generate_blog_get_column_count() ) {
$classes[] = 'grid-66';
}
if ( 25 == generate_blog_get_column_count() ) {
$classes[] = 'grid-50';
}
if ( 20 == generate_blog_get_column_count() ) {
$classes[] = 'grid-60';
}
$classes[] = 'featured-column';
} else {
$classes[] = 'grid-' . generate_blog_get_column_count();
}
}
if ( ! $settings['post_image_padding'] && ! is_singular() ) {
$classes[] = 'no-featured-image-padding';
}
$location = generate_blog_get_singular_template();
if ( ! $settings[$location . '_post_image_padding'] && is_singular() ) {
$classes[] = 'no-featured-image-padding';
}
$atts = generate_get_blog_image_attributes();
if ( ! is_singular() && has_post_thumbnail() && ! empty( $atts ) ) {
$values = array(
$atts['width'],
$atts['height'],
$atts['crop'],
);
$image_src = wp_get_attachment_image_src( get_post_thumbnail_id( get_the_ID(), 'full' ), $values );
if ( $image_src && ( ! $image_src[3] || ! apply_filters( 'generate_use_featured_image_size_match', true ) ) ) {
$classes[] = 'resize-featured-image';
}
}
return $classes;
}
}
if ( ! function_exists( 'generate_blog_body_classes' ) ) {
add_filter( 'body_class', 'generate_blog_body_classes' );
/**
* Adds custom classes to the body
*
* @since 0.1
*/
function generate_blog_body_classes( $classes ) {
// Get theme options
$settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
if ( is_singular() ) {
$location = generate_blog_get_singular_template();
if ( 'below-title' == $settings[$location . '_post_image_position'] ) {
$classes[] = 'post-image-below-header';
}
if ( 'inside-content' == $settings[$location . '_post_image_position'] ) {
$classes[] = 'post-image-above-header';
}
$classes[] = ( ! empty( $settings[$location . '_post_image_alignment'] ) ) ? 'post-image-aligned-' . $settings[$location . '_post_image_alignment'] : 'post-image-aligned-center';
} else {
$classes[] = ( '' == $settings['post_image_position'] ) ? 'post-image-below-header' : 'post-image-above-header';
$classes[] = ( ! empty( $settings['post_image_alignment'] ) ) ? $settings['post_image_alignment'] : 'post-image-aligned-center';
}
if ( 'true' == generate_blog_get_masonry() && generate_blog_get_columns() ) {
$classes[] = 'masonry-enabled';
}
if ( generate_blog_get_columns() && ! is_singular() ) {
$classes[] = 'generate-columns-activated';
}
if ( $settings[ 'infinite_scroll' ] && ! is_singular() ) {
$classes[] = 'infinite-scroll';
}
return $classes;
}
}
if ( ! function_exists( 'generate_excerpt_length' ) ) {
add_filter( 'excerpt_length', 'generate_excerpt_length', 15 );
/**
* Set our excerpt length
*
* @since 0.1
*/
function generate_excerpt_length( $length ) {
$generate_settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
return absint( apply_filters( 'generate_excerpt_length', $generate_settings['excerpt_length'] ) );
}
}
if ( ! function_exists( 'generate_blog_css' ) ) {
/**
* Build our inline CSS
*
* @since 0.1
*/
function generate_blog_css() {
global $post;
$return = '';
$settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
if ( ! defined( 'GENERATE_VERSION' ) ) {
return;
}
if ( version_compare( GENERATE_VERSION, '3.0.0-alpha.1', '<' ) ) {
// Get disable headline meta.
$disable_headline = ( isset( $post ) ) ? get_post_meta( $post->ID, '_generate-disable-headline', true ) : '';
if ( ! $settings['categories'] && ! $settings['comments'] && ! $settings['tags'] && ! is_singular() ) {
$return .= '.blog footer.entry-meta, .archive footer.entry-meta {display:none;}';
}
if ( ! $settings['single_date'] && ! $settings['single_author'] && $disable_headline && is_singular() ) {
$return .= '.single .entry-header{display:none;}.single .entry-content {margin-top:0;}';
}
if ( ! $settings['date'] && ! $settings['author'] && ! is_singular() ) {
$return .= '.entry-header .entry-meta {display:none;}';
}
if ( ! $settings['single_date'] && ! $settings['single_author'] && is_singular() ) {
$return .= '.entry-header .entry-meta {display:none;}';
}
if ( ! $settings['single_post_navigation'] && is_singular() ) {
$return .= '.post-navigation {display:none;}';
}
if ( ! $settings['single_categories'] && ! $settings['single_post_navigation'] && ! $settings['single_tags'] && is_singular() ) {
$return .= '.single footer.entry-meta {display:none;}';
}
}
$separator = 20;
$content_padding_top = 40;
$content_padding_right = 40;
$content_padding_left = 40;
$mobile_content_padding_top = 30;
$mobile_content_padding_right = 30;
$mobile_content_padding_left = 30;
if ( function_exists( 'generate_spacing_get_defaults' ) ) {
$spacing_settings = wp_parse_args(
get_option( 'generate_spacing_settings', array() ),
generate_spacing_get_defaults()
);
$separator = absint( $spacing_settings['separator'] );
$content_padding_top = absint( $spacing_settings['content_top'] );
$content_padding_right = absint( $spacing_settings['content_right'] );
$content_padding_left = absint( $spacing_settings['content_left'] );
$mobile_content_padding_top = absint( $spacing_settings['mobile_content_top'] );
$mobile_content_padding_right = absint( $spacing_settings['mobile_content_right'] );
$mobile_content_padding_left = absint( $spacing_settings['mobile_content_left'] );
}
if ( 'true' == generate_blog_get_masonry() && generate_blog_get_columns() ) {
$return .= '.page-header {margin-bottom: ' . $separator . 'px;margin-left: ' . $separator . 'px}';
}
if ( $settings[ 'infinite_scroll' ] && ! is_singular() ) {
$return .= '#nav-below {display:none;}';
}
if ( ! $settings['post_image_padding'] && 'post-image-aligned-center' == $settings['post_image_alignment'] && ! is_singular() ) {
$return .= '.no-featured-image-padding .post-image {margin-left:-' . $content_padding_left . 'px;margin-right:-' . $content_padding_right . 'px;}';
$return .= '.post-image-above-header .no-featured-image-padding .inside-article .post-image {margin-top:-' . $content_padding_top . 'px;}';
}
$location = generate_blog_get_singular_template();
if ( ! $settings[$location . '_post_image_padding'] && 'center' == $settings[$location . '_post_image_alignment'] && is_singular() ) {
$return .= '.no-featured-image-padding .featured-image {margin-left:-' . $content_padding_left . 'px;margin-right:-' . $content_padding_right . 'px;}';
$return .= '.post-image-above-header .no-featured-image-padding .inside-article .featured-image {margin-top:-' . $content_padding_top . 'px;}';
}
if ( ! $settings['page_post_image_padding'] || ! $settings['single_post_image_padding'] || ! $settings['post_image_padding'] ) {
$return .= '@media ' . generate_premium_get_media_query( 'mobile' ) . '{';
if ( ! $settings['post_image_padding'] && 'post-image-aligned-center' == $settings['post_image_alignment'] && ! is_singular() ) {
$return .= '.no-featured-image-padding .post-image {margin-left:-' . $mobile_content_padding_left . 'px;margin-right:-' . $mobile_content_padding_right . 'px;}';
$return .= '.post-image-above-header .no-featured-image-padding .inside-article .post-image {margin-top:-' . $mobile_content_padding_top . 'px;}';
}
if ( ! $settings[$location . '_post_image_padding'] && 'center' == $settings[$location . '_post_image_alignment'] && is_singular() ) {
$return .= '.no-featured-image-padding .featured-image {margin-left:-' . $mobile_content_padding_left . 'px;margin-right:-' . $mobile_content_padding_right . 'px;}';
$return .= '.post-image-above-header .no-featured-image-padding .inside-article .featured-image {margin-top:-' . $mobile_content_padding_top . 'px;}';
}
$return .= '}';
}
$atts = generate_get_blog_image_attributes();
if ( ! empty( $atts ) ) {
$image_width = $atts['width'] && 9999 !== $atts['width'] ? 'width: ' . $atts['width'] . 'px;' : '';
$image_height = $atts['height'] && 9999 !== $atts['height'] ? 'height: ' . $atts['height'] . 'px;' : '';
$image_crop = $atts['crop'] ? '-o-object-fit: cover;object-fit: cover;' : '';
if ( ! $image_width && $image_height ) {
$image_crop = '-o-object-fit: cover;object-fit: cover;';
}
if ( ! is_singular() ) {
$return .= '.resize-featured-image .post-image img {' . $image_width . $image_height . $image_crop . '}';
}
if ( is_single() || is_page() ) {
$values = array(
$atts['width'],
$atts['height'],
$atts['crop'],
);
$image_src = wp_get_attachment_image_src( get_post_thumbnail_id( get_the_ID(), 'full' ), $values );
if ( $image_src && ( ! $image_src[3] || ! apply_filters( 'generate_use_featured_image_size_match', true ) ) ) {
$return .= '.featured-image img {' . $image_width . $image_height . $image_crop . '}';
}
}
}
return $return;
}
}
if ( ! function_exists( 'generate_blog_excerpt_more' ) ) {
add_filter( 'excerpt_more', 'generate_blog_excerpt_more', 15 );
/**
* Prints the read more HTML
*/
function generate_blog_excerpt_more( $more ) {
$generate_settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
if ( '' == $generate_settings['read_more'] ) {
return '';
}
return apply_filters(
'generate_excerpt_more_output',
sprintf(
' ... <a title="%1$s" class="read-more" href="%2$s" aria-label="%4$s">%3$s</a>',
the_title_attribute( 'echo=0' ),
esc_url( get_permalink( get_the_ID() ) ),
wp_kses_post( $generate_settings['read_more'] ),
sprintf(
/* translators: Aria-label describing the read more button */
_x( 'More on %s', 'more on post title', 'gp-premium' ),
the_title_attribute( 'echo=0' )
)
)
);
}
}
if ( ! function_exists( 'generate_blog_content_more' ) ) {
add_filter( 'the_content_more_link', 'generate_blog_content_more', 15 );
/**
* Prints the read more HTML
*/
function generate_blog_content_more( $more ) {
$generate_settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
if ( '' == $generate_settings['read_more'] ) {
return '';
}
return apply_filters(
'generate_content_more_link_output',
sprintf(
'<p class="read-more-container"><a title="%1$s" class="read-more content-read-more" href="%2$s" aria-label="%4$s">%3$s</a></p>',
the_title_attribute( 'echo=0' ),
esc_url( get_permalink( get_the_ID() ) . apply_filters( 'generate_more_jump', '#more-' . get_the_ID() ) ),
wp_kses_post( $generate_settings['read_more'] ),
sprintf(
/* translators: Aria-label describing the read more button */
_x( 'More on %s', 'more on post title', 'gp-premium' ),
the_title_attribute( 'echo=0' )
)
)
);
}
}
/**
* Checks the setting and returns false if $thing is disabled
*
* @since 1.4
*
* @param String $data The original data, passed through if not disabled
* @param String $thing The name of the thing to check
* @return String|False The original data, or false (if disabled)
*/
function generate_disable_post_thing( $data, $thing ) {
$generate_blog_settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
if ( ! $generate_blog_settings[$thing] ) {
return false;
}
return $data;
}
if ( ! function_exists( 'generate_disable_post_date' ) ) {
add_filter( 'generate_post_date', 'generate_disable_post_date' );
/**
* Remove the post date if set
*
* @since 0.1
*/
function generate_disable_post_date( $date ) {
if ( is_singular() ) {
return generate_disable_post_thing( $date, 'single_date' );
} else {
return generate_disable_post_thing( $date, 'date' );
}
}
}
if ( ! function_exists( 'generate_disable_post_author' ) ) {
add_filter( 'generate_post_author', 'generate_disable_post_author' );
/**
* Set the author if set
*
* @since 0.1
*/
function generate_disable_post_author( $author ) {
if ( is_singular() ) {
return generate_disable_post_thing( $author, 'single_author' );
} else {
return generate_disable_post_thing( $author, 'author' );
}
}
}
if ( ! function_exists( 'generate_disable_post_categories' ) ) {
add_filter( 'generate_show_categories', 'generate_disable_post_categories' );
/**
* Remove the categories if set
*
* @since 0.1
*/
function generate_disable_post_categories( $categories ) {
if ( is_singular() ) {
return generate_disable_post_thing( $categories, 'single_categories' );
} else {
return generate_disable_post_thing( $categories, 'categories' );
}
}
}
if ( ! function_exists( 'generate_disable_post_tags' ) ) {
add_filter( 'generate_show_tags', 'generate_disable_post_tags' );
/**
* Remove the tags if set
*
* @since 0.1
*/
function generate_disable_post_tags( $tags ) {
if ( is_singular() ) {
return generate_disable_post_thing( $tags, 'single_tags' );
} else {
return generate_disable_post_thing( $tags, 'tags' );
}
}
}
if ( ! function_exists( 'generate_disable_post_comments_link' ) ) {
add_filter( 'generate_show_comments', 'generate_disable_post_comments_link' );
/**
* Remove the link to comments if set
*
* @since 0.1
*/
function generate_disable_post_comments_link( $comments_link ) {
return generate_disable_post_thing( $comments_link, 'comments' );
}
}
add_filter( 'generate_show_post_navigation', 'generate_disable_post_navigation' );
/**
* Remove the single post navigation
*
* @since 1.5
*/
function generate_disable_post_navigation( $navigation ) {
if ( is_singular() ) {
return generate_disable_post_thing( $navigation, 'single_post_navigation' );
} else {
return $navigation;
}
}
add_filter( 'generate_excerpt_more_output', 'generate_blog_read_more_button' );
add_filter( 'generate_content_more_link_output', 'generate_blog_read_more_button' );
/**
* Add the button class to our read more link if set.
*
* @since 1.5
*
* @param string $output Our existing read more link.
*/
function generate_blog_read_more_button( $output ) {
$settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
if ( ! $settings['read_more_button'] ) {
return $output;
}
return sprintf(
'%5$s<p class="read-more-container"><a title="%1$s" class="read-more button" href="%2$s" aria-label="%4$s">%3$s</a></p>',
the_title_attribute( 'echo=0' ),
esc_url( get_permalink( get_the_ID() ) . apply_filters( 'generate_more_jump', '#more-' . get_the_ID() ) ),
wp_kses_post( $settings['read_more'] ),
sprintf(
/* translators: Aria-label describing the read more button */
_x( 'More on %s', 'more on post title', 'gp-premium' ),
the_title_attribute( 'echo=0' )
),
'generate_excerpt_more_output' === current_filter() ? ' ... ' : ''
);
}
if ( ! function_exists( 'generate_blog_load_more' ) ) {
add_action( 'generate_after_main_content', 'generate_blog_load_more', 20 );
/**
* Build our load more button
*/
function generate_blog_load_more() {
// Get theme options
$settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
if ( ( ! $settings[ 'infinite_scroll_button' ] || ! $settings[ 'infinite_scroll' ] ) || is_singular() || is_404() ) {
return;
}
global $wp_query;
if ( $wp_query->max_num_pages < 2 ) {
return;
}
if ( is_post_type_archive( 'product' ) ) {
return;
}
if ( is_tax( 'product_cat' ) ) {
return;
}
$icon = '';
if ( function_exists( 'generate_get_svg_icon' ) ) {
$icon = generate_get_svg_icon( 'spinner' );
}
printf(
'<div class="masonry-load-more load-more %1$s %2$s">
<a class="button" href="#">%3$s%4$s</a>
</div>',
$icon ? 'has-svg-icon' : '',
( 'true' == generate_blog_get_masonry() && generate_blog_get_columns() ) ? 'are-images-unloaded' : '',
$icon,
wp_kses_post( $settings['masonry_load_more'] )
);
}
}
/**
* Checks to see whether we're getting page or single post options.
*
* @since 1.5
*
* @return string Name of our singular template
*/
function generate_blog_get_singular_template() {
$template = 'single';
if ( is_page() ) {
$template = 'page';
}
return $template;
}
add_action( 'generate_after_footer', 'generate_blog_do_infinite_scroll_path', 500 );
/**
* Add a next page of posts link for infinite scroll.
*
* @since 2.0.0
*/
function generate_blog_do_infinite_scroll_path() {
if ( function_exists( 'is_woocommerce' ) && is_woocommerce() ) {
return;
}
$settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
if ( $settings['infinite_scroll'] && ! is_singular() && ! is_404() ) {
printf(
'<div class="infinite-scroll-path" aria-hidden="true" style="display: none;">%s</div>',
get_next_posts_link()
);
}
}

View File

@ -0,0 +1,370 @@
<?php
/**
* Functions specific to featured images.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
/**
* Collects all available image sizes which we use in the Customizer.
*
* @since 1.10.0
*
* @return array
*/
function generate_blog_get_image_sizes() {
$sizes = get_intermediate_image_sizes();
$new_sizes = array(
'full' => 'full',
);
foreach ( $sizes as $key => $name ) {
$new_sizes[ $name ] = $name;
}
return $new_sizes;
}
add_filter( 'generate_page_header_default_size', 'generate_blog_set_featured_image_size' );
/**
* Set our featured image sizes.
*
* @since 1.10.0
*
* @param string $size The existing size.
* @return string The new size.
*/
function generate_blog_set_featured_image_size( $size ) {
$settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
if ( ! is_singular() ) {
$size = $settings['post_image_size'];
}
if ( is_single() ) {
$size = $settings['single_post_image_size'];
}
if ( is_page() ) {
$size = $settings['page_post_image_size'];
}
$atts = generate_get_blog_image_attributes();
if ( ! empty( $atts ) ) {
$values = array(
$atts['width'],
$atts['height'],
$atts['crop'],
);
$image_src = wp_get_attachment_image_src( get_post_thumbnail_id( get_the_ID(), 'full' ), $values );
if ( $image_src && $image_src[3] && apply_filters( 'generate_use_featured_image_size_match', true ) ) {
return $values;
} else {
return $size;
}
}
return $size;
}
if ( ! function_exists( 'generate_get_blog_image_attributes' ) ) {
/**
* Build our image attributes
*
* @since 0.1
*/
function generate_get_blog_image_attributes() {
$settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
if ( is_singular() ) {
if ( is_singular( 'page' ) ) {
$single = 'page_';
} else {
$single = 'single_';
}
} else {
$single = '';
}
$ignore_crop = array( '', '0', '9999' );
$atts = array(
'width' => ( in_array( $settings[ "{$single}post_image_width" ], $ignore_crop ) ) ? 9999 : absint( $settings[ "{$single}post_image_width" ] ),
'height' => ( in_array( $settings[ "{$single}post_image_height" ], $ignore_crop ) ) ? 9999 : absint( $settings[ "{$single}post_image_height" ] ),
'crop' => ( in_array( $settings[ "{$single}post_image_width" ], $ignore_crop ) || in_array( $settings[ "{$single}post_image_height" ], $ignore_crop ) ) ? false : true,
);
// If there's no height or width, empty the array.
if ( 9999 == $atts['width'] && 9999 == $atts['height'] ) { // phpcs:ignore
$atts = array();
}
return apply_filters( 'generate_blog_image_attributes', $atts );
}
}
if ( ! function_exists( 'generate_blog_setup' ) ) {
add_action( 'wp', 'generate_blog_setup', 50 );
/**
* Setup our blog functions and actions
*
* @since 0.1
*/
function generate_blog_setup() {
$settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
// Move our featured images to above the title.
if ( 'post-image-above-header' === $settings['post_image_position'] ) {
remove_action( 'generate_after_entry_header', 'generate_post_image' );
add_action( 'generate_before_content', 'generate_post_image' );
// If we're using the Page Header add-on, move those as well.
if ( function_exists( 'generate_page_header_post_image' ) ) {
remove_action( 'generate_after_entry_header', 'generate_page_header_post_image' );
add_action( 'generate_before_content', 'generate_page_header_post_image' );
}
}
$page_header_content = false;
if ( function_exists( 'generate_page_header_get_options' ) ) {
$options = generate_page_header_get_options();
if ( $options && '' !== $options['content'] ) {
$page_header_content = true;
}
// If our Page Header has no content, remove it.
// This will allow the Blog add-on to add an image for us.
if ( ! $page_header_content && is_singular() ) {
remove_action( 'generate_before_content', 'generate_page_header' );
remove_action( 'generate_after_entry_header', 'generate_page_header' );
remove_action( 'generate_after_header', 'generate_page_header' );
}
}
// Remove the core theme featured image.
// I would like to filter instead one day.
remove_action( 'generate_after_header', 'generate_featured_page_header' );
remove_action( 'generate_before_content', 'generate_featured_page_header_inside_single' );
$location = generate_blog_get_singular_template();
if ( $settings[ $location . '_post_image' ] && is_singular() && ! $page_header_content ) {
if ( 'below-title' === $settings[ $location . '_post_image_position' ] ) {
add_action( 'generate_after_entry_header', 'generate_blog_single_featured_image' );
}
if ( 'inside-content' === $settings[ $location . '_post_image_position' ] ) {
add_action( 'generate_before_content', 'generate_blog_single_featured_image' );
}
if ( 'above-content' === $settings[ $location . '_post_image_position' ] ) {
add_action( 'generate_after_header', 'generate_blog_single_featured_image' );
}
}
}
}
add_filter( 'generate_featured_image_output', 'generate_blog_featured_image' );
/**
* Remove featured image if set or using WooCommerce.
*
* @since 1.5
* @param string $output The existing output.
* @return string The image HTML
*/
function generate_blog_featured_image( $output ) {
$settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
if ( ( function_exists( 'is_woocommerce' ) && is_woocommerce() ) || ! $settings['post_image'] ) {
return false;
}
return $output;
}
/**
* Build our featured images for single posts and pages.
*
* This function is way more complicated than it could be so it can
* ensure compatibility with the Page Header add-on.
*
* @since 1.5
*
* @return string The image HTML
*/
function generate_blog_single_featured_image() {
$settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
$image_id = get_post_thumbnail_id( get_the_ID(), 'full' );
if ( function_exists( 'generate_page_header_get_image' ) && generate_page_header_get_image( 'ID' ) ) {
if ( intval( $image_id ) !== generate_page_header_get_image( 'ID' ) ) {
$image_id = generate_page_header_get_image( 'ID' );
}
}
$location = generate_blog_get_singular_template();
if ( ( function_exists( 'is_woocommerce' ) && is_woocommerce() ) || ! $settings[ $location . '_post_image' ] || ! $image_id ) {
return false;
}
$attrs = array(
'itemprop' => 'image',
);
if ( function_exists( 'generate_get_schema_type' ) ) {
if ( 'microdata' !== generate_get_schema_type() ) {
$attrs = array();
}
}
if ( function_exists( 'wp_get_loading_attr_default' ) ) {
$attrs['loading'] = wp_get_loading_attr_default( 'the_post_thumbnail' );
}
$image_html = apply_filters(
'post_thumbnail_html', // phpcs:ignore -- Core filter.
wp_get_attachment_image(
$image_id,
apply_filters( 'generate_page_header_default_size', 'full' ),
'',
$attrs
),
get_the_ID(),
$image_id,
apply_filters( 'generate_page_header_default_size', 'full' ),
''
);
$location = generate_blog_get_singular_template();
$classes = array(
is_page() ? 'page-header-image' : null,
is_singular() && ! is_page() ? 'page-header-image-single' : null,
'above-content' === $settings[ $location . '_post_image_position' ] ? 'grid-container grid-parent' : null,
);
$image_html = apply_filters( 'generate_single_featured_image_html', $image_html );
// phpcs:ignore -- No need to escape here.
echo apply_filters(
'generate_single_featured_image_output',
sprintf(
'<div class="featured-image %2$s">
%1$s
</div>',
$image_html,
implode( ' ', $classes )
),
$image_html
);
}
add_filter( 'generate_blog_image_attributes', 'generate_blog_page_header_image_atts' );
/**
* Filter our image attributes in case we're using differents atts in our Page Header
*
* @since 1.5
*
* @param array $atts Our existing image attributes.
* @return array Image attributes
*/
function generate_blog_page_header_image_atts( $atts ) {
if ( ! function_exists( 'generate_page_header_get_options' ) ) {
return $atts;
}
if ( ! is_singular() ) {
return $atts;
}
$options = generate_page_header_get_options();
if ( $options && 'enable' === $options['image_resize'] ) {
$ignore_crop = array( '', '0', '9999' );
$atts = array(
'width' => ( in_array( $options['image_width'], $ignore_crop ) ) ? 9999 : absint( $options['image_width'] ),
'height' => ( in_array( $options['image_height'], $ignore_crop ) ) ? 9999 : absint( $options['image_height'] ),
'crop' => ( in_array( $options['image_width'], $ignore_crop ) || in_array( $options['image_height'], $ignore_crop ) ) ? false : true,
);
}
return $atts;
}
add_filter( 'generate_single_featured_image_html', 'generate_blog_page_header_link' );
/**
* Add our Page Header link to our featured image if set.
*
* @since 1.5
*
* @param string $image_html Our existing image HTML.
* @return string Our new image HTML.
*/
function generate_blog_page_header_link( $image_html ) {
if ( ! function_exists( 'generate_page_header_get_options' ) ) {
return $image_html;
}
$options = generate_page_header_get_options();
if ( ! empty( $options['image_link'] ) ) {
return '<a href="' . esc_url( $options['image_link'] ) . '"' . apply_filters( 'generate_page_header_link_target', '' ) . '>' . $image_html . '</a>';
} else {
return $image_html;
}
}
add_filter( 'body_class', 'generate_blog_remove_featured_image_class', 20 );
/**
* Remove the featured image classes if they're disabled.
*
* @since 2.1.0
* @param array $classes The body classes.
*/
function generate_blog_remove_featured_image_class( $classes ) {
if ( is_singular() ) {
$settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
generate_blog_get_defaults()
);
if ( is_single() ) {
$disable_single_featured_image = ! $settings['single_post_image'];
$classes = generate_premium_remove_featured_image_class( $classes, $disable_single_featured_image );
}
if ( is_page() && ! $settings['page_post_image'] ) {
$disable_page_featured_image = ! $settings['page_post_image'];
$classes = generate_premium_remove_featured_image_class( $classes, $disable_page_featured_image );
}
}
return $classes;
}

View File

@ -0,0 +1,98 @@
jQuery( function( $ ) {
// Featured image controls
var featuredImageArchiveControls = [
'generate_blog_settings-post_image',
'generate_blog_settings-post_image_padding',
'generate_blog_settings-post_image_position',
'generate_blog_settings-post_image_alignment',
'generate_blog_settings-post_image_size',
'generate_blog_settings-post_image_width',
'generate_blog_settings-post_image_height',
'generate_regenerate_images_notice',
];
$.each( featuredImageArchiveControls, function( index, value ) {
$( '#customize-control-' + value ).attr( 'data-control-section', 'featured-image-archives' );
} );
var featuredImageSingleControls = [
'generate_blog_settings-single_post_image',
'generate_blog_settings-single_post_image_padding',
'generate_blog_settings-single_post_image_position',
'generate_blog_settings-single_post_image_alignment',
'generate_blog_settings-single_post_image_size',
'generate_blog_settings-single_post_image_width',
'generate_blog_settings-single_post_image_height',
'generate_regenerate_single_post_images_notice',
];
$.each( featuredImageSingleControls, function( index, value ) {
$( '#customize-control-' + value ).attr( 'data-control-section', 'featured-image-single' ).css( {
visibility: 'hidden',
height: '0',
width: '0',
margin: '0',
overflow: 'hidden',
} );
} );
var featuredImagePageControls = [
'generate_blog_settings-page_post_image',
'generate_blog_settings-page_post_image_padding',
'generate_blog_settings-page_post_image_position',
'generate_blog_settings-page_post_image_alignment',
'generate_blog_settings-page_post_image_size',
'generate_blog_settings-page_post_image_width',
'generate_blog_settings-page_post_image_height',
'generate_regenerate_page_images_notice',
];
$.each( featuredImagePageControls, function( index, value ) {
$( '#customize-control-' + value ).attr( 'data-control-section', 'featured-image-page' ).css( {
visibility: 'hidden',
height: '0',
width: '0',
margin: '0',
overflow: 'hidden',
} );
} );
// Post meta controls
var postMetaArchiveControls = [
'generate_settings-post_content',
'generate_blog_settings-excerpt_length',
'generate_blog_settings-read_more',
'generate_blog_settings-read_more_button',
'generate_blog_settings-date',
'generate_blog_settings-author',
'generate_blog_settings-categories',
'generate_blog_settings-tags',
'generate_blog_settings-comments',
'generate_blog_settings-infinite_scroll',
'generate_blog_settings-infinite_scroll_button',
'blog_masonry_load_more_control',
'blog_masonry_loading_control',
];
$.each( postMetaArchiveControls, function( index, value ) {
$( '#customize-control-' + value ).attr( 'data-control-section', 'post-meta-archives' );
} );
var postMetaSingleControls = [
'generate_blog_settings-single_date',
'generate_blog_settings-single_author',
'generate_blog_settings-single_categories',
'generate_blog_settings-single_tags',
'generate_blog_settings-single_post_navigation',
];
$.each( postMetaSingleControls, function( index, value ) {
$( '#customize-control-' + value ).attr( 'data-control-section', 'post-meta-single' ).css( {
visibility: 'hidden',
height: '0',
width: '0',
margin: '0',
overflow: 'hidden',
} );
} );
} );

View File

@ -0,0 +1,76 @@
/**
* Theme Customizer enhancements for a better user experience.
*
* Contains handlers to make Theme Customizer preview reload changes asynchronously.
*/
( function( $ ) {
// Container width
wp.customize( 'generate_settings[container_width]', function( value ) {
value.bind( function() {
if ( $( '.masonry-container' )[ 0 ] ) {
jQuery( '.masonry-container' ).imagesLoaded( function() {
$container = jQuery( '.masonry-container' );
if ( jQuery( $container ).length ) {
$container.masonry( {
columnWidth: '.grid-sizer',
itemSelector: '.masonry-post',
stamp: '.page-header',
} );
}
} );
}
} );
} );
$( 'body' ).on( 'generate_spacing_updated', function() {
if ( $( '.masonry-container' )[ 0 ] ) {
jQuery( '.masonry-container' ).imagesLoaded( function() {
$container = jQuery( '.masonry-container' );
if ( jQuery( $container ).length ) {
$container.masonry( {
columnWidth: '.grid-sizer',
itemSelector: '.masonry-post',
stamp: '.page-header',
} );
}
} );
}
} );
/**
* The first infinite scroll load in the Customizer misses article classes if they've been
* added or removed in the previous refresh.
*
* This is totally hacky, but I'm just happy I finally got it working!
*/
var $container = $( '.infinite-scroll-item' ).first().parent();
$container.on( 'load.infiniteScroll', function( event, response ) {
var $posts = $( response ).find( 'article' );
if ( wp.customize.value( 'generate_blog_settings[column_layout]' )() ) {
$posts.addClass( 'generate-columns' );
$posts.addClass( 'grid-parent' );
$posts.addClass( 'grid-' + wp.customize.value( 'generate_blog_settings[columns]' )() );
$posts.addClass( 'tablet-grid-50' );
$posts.addClass( 'mobile-grid-100' );
} else {
$posts.removeClass( 'generate-columns' );
$posts.removeClass( 'grid-parent' );
$posts.removeClass( 'grid-' + wp.customize.value( 'generate_blog_settings[columns]' )() );
$posts.removeClass( 'tablet-grid-50' );
$posts.removeClass( 'mobile-grid-100' );
}
if ( wp.customize.value( 'generate_blog_settings[masonry]' )() ) {
$posts.addClass( 'masonry-post' );
} else {
$posts.removeClass( 'masonry-post' );
}
if ( ! wp.customize.value( 'generate_blog_settings[post_image_padding]' )() ) {
$posts.addClass( 'no-featured-image-padding' );
} else {
$posts.removeClass( 'no-featured-image-padding' );
}
} );
}( jQuery ) );

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,100 @@
document.addEventListener( 'DOMContentLoaded', function() {
var msnryContainer = document.querySelector( '.masonry-container' );
if ( msnryContainer ) {
// eslint-disable-next-line no-undef -- Masonry is a dependency.
var msnry = new Masonry( msnryContainer, generateBlog.masonryInit ),
navBelow = document.querySelector( '#nav-below' ),
loadMore = document.querySelector( '.load-more' );
// eslint-disable-next-line no-undef -- imagesLoaded is a dependency.
imagesLoaded( msnryContainer, function() {
msnry.layout();
msnryContainer.classList.remove( 'are-images-unloaded' );
if ( loadMore ) {
loadMore.classList.remove( 'are-images-unloaded' );
}
if ( navBelow ) {
navBelow.style.opacity = 1;
}
} );
if ( navBelow ) {
msnryContainer.parentNode.insertBefore( navBelow, msnryContainer.nextSibling );
}
window.addEventListener( 'orientationchange', function() {
msnry.layout();
} );
}
var hasInfiniteScroll = document.querySelector( '.infinite-scroll' ),
nextLink = document.querySelector( '.infinite-scroll-path a' );
if ( hasInfiniteScroll && nextLink ) {
var infiniteItems = document.querySelectorAll( '.infinite-scroll-item' ),
container = infiniteItems[ 0 ].parentNode,
button = document.querySelector( '.load-more a' ),
svgIcon = '';
if ( generateBlog.icon ) {
svgIcon = generateBlog.icon;
}
var infiniteScrollInit = generateBlog.infiniteScrollInit;
infiniteScrollInit.outlayer = msnry;
// eslint-disable-next-line no-undef -- InfiniteScroll is a dependency.
var infiniteScroll = new InfiniteScroll( container, infiniteScrollInit );
if ( button ) {
button.addEventListener( 'click', function( e ) {
document.activeElement.blur();
e.target.innerHTML = svgIcon + generateBlog.loading;
e.target.classList.add( 'loading' );
} );
}
infiniteScroll.on( 'append', function( response, path, items ) {
if ( button && ! document.querySelector( '.generate-columns-container' ) ) {
container.appendChild( button.parentNode );
}
items.forEach( function( element ) {
var images = element.querySelectorAll( 'img' );
if ( images ) {
images.forEach( function( image ) {
var imgOuterHTML = image.outerHTML;
image.outerHTML = imgOuterHTML;
} );
}
} );
if ( msnryContainer && msnry ) {
// eslint-disable-next-line no-undef -- ImagesLoaded is a dependency.
imagesLoaded( msnryContainer, function() {
msnry.layout();
} );
}
if ( button ) {
button.innerHTML = svgIcon + generateBlog.more;
button.classList.remove( 'loading' );
}
document.body.dispatchEvent( new Event( 'post-load' ) );
} );
infiniteScroll.on( 'last', function() {
var loadMoreElement = document.querySelector( '.load-more' );
if ( loadMoreElement ) {
loadMoreElement.style.display = 'none';
}
} );
}
} );

View File

@ -0,0 +1 @@
document.addEventListener("DOMContentLoaded",function(){var t,e,n,r,a,i,l=document.querySelector(".masonry-container"),o=(l&&(t=new Masonry(l,generateBlog.masonryInit),e=document.querySelector("#nav-below"),n=document.querySelector(".load-more"),imagesLoaded(l,function(){t.layout(),l.classList.remove("are-images-unloaded"),n&&n.classList.remove("are-images-unloaded"),e&&(e.style.opacity=1)}),e&&l.parentNode.insertBefore(e,l.nextSibling),window.addEventListener("orientationchange",function(){t.layout()})),document.querySelector(".infinite-scroll")),c=document.querySelector(".infinite-scroll-path a");o&&c&&(r=document.querySelectorAll(".infinite-scroll-item")[0].parentNode,a=document.querySelector(".load-more a"),i="",generateBlog.icon&&(i=generateBlog.icon),(o=generateBlog.infiniteScrollInit).outlayer=t,c=new InfiniteScroll(r,o),a&&a.addEventListener("click",function(e){document.activeElement.blur(),e.target.innerHTML=i+generateBlog.loading,e.target.classList.add("loading")}),c.on("append",function(e,n,o){a&&!document.querySelector(".generate-columns-container")&&r.appendChild(a.parentNode),o.forEach(function(e){e=e.querySelectorAll("img");e&&e.forEach(function(e){var n=e.outerHTML;e.outerHTML=n})}),l&&t&&imagesLoaded(l,function(){t.layout()}),a&&(a.innerHTML=i+generateBlog.more,a.classList.remove("loading")),document.body.dispatchEvent(new Event("post-load"))}),c.on("last",function(){var e=document.querySelector(".load-more");e&&(e.style.display="none")}))});

View File

@ -0,0 +1,122 @@
<?php
defined( 'WPINC' ) or die;
add_action( 'admin_init', 'generate_blog_update_visibility_settings' );
/**
* Migrates our old Blog settings so we can use checkboxes instead.
*
* @since 1.5
*/
function generate_blog_update_visibility_settings() {
// Get our migration settings
$settings = get_option( 'generate_migration_settings', array() );
// If we've already ran this function, bail
if ( isset( $settings[ 'blog_visibility_updated' ] ) && 'true' == $settings[ 'blog_visibility_updated' ] ) {
return;
}
// A lot of the defaults changed, so lets put the old defaults here
$defaults = array(
'masonry' => 'false',
'masonry_width' => 'width2',
'masonry_most_recent_width' => 'width4',
'post_image' => 'true',
'date' => 'true',
'author' => 'true',
'categories' => 'true',
'tags' => 'true',
'comments' => 'true',
);
// Get our spacing settings
$blog_settings = wp_parse_args(
get_option( 'generate_blog_settings', array() ),
$defaults
);
$new_settings = array();
// These options use to be a select input with false + true values
// This will make the false values empty so the options can be checkboxes
$keys = array( 'date', 'author', 'categories', 'tags', 'comments', 'masonry', 'post_image' );
foreach ( $keys as $key ) {
if ( is_string( $blog_settings[ $key ] ) ) {
if ( 'false' == $blog_settings[ $key ] ) {
$new_settings[ $key ] = false;
} elseif ( 'true' == $blog_settings[ $key ] ) {
$new_settings[ $key ] = true;
}
}
}
// Set the single post meta options to whatever the blog options are
$new_settings[ 'single_date' ] = isset( $new_settings[ 'date' ] ) ? $new_settings[ 'date' ] : true;
$new_settings[ 'single_author' ] = isset( $new_settings[ 'author' ] ) ? $new_settings[ 'author' ] : true;
$new_settings[ 'single_categories' ] = isset( $new_settings[ 'categories' ] ) ? $new_settings[ 'categories' ] : true;
$new_settings[ 'single_tags' ] = isset( $new_settings[ 'tags' ] ) ? $new_settings[ 'tags' ] : true;
if ( isset( $new_settings[ 'masonry' ] ) && $new_settings[ 'masonry' ] ) {
$new_settings[ 'column_layout' ] = true;
$new_settings[ 'infinite_scroll' ] = true;
$new_settings[ 'infinite_scroll_button' ] = true;
if ( 'width2' == $blog_settings['masonry_width'] ) {
$new_settings[ 'columns' ] = '33';
}
if ( 'width4' == $blog_settings['masonry_width'] ) {
$new_settings[ 'columns' ] = '50';
}
if ( 'width6' == $blog_settings['masonry_width'] ) {
$new_settings[ 'columns' ] = '100';
}
if ( 'width2' == $blog_settings[ 'masonry_width' ] ) {
if ( 'width2' !== $blog_settings[ 'masonry_most_recent_width' ] ) {
$new_settings[ 'featured_column' ] = true;
} else {
$new_settings[ 'featured_column' ] = false;
}
}
if ( 'width4' == $blog_settings[ 'masonry_width' ] ) {
if ( 'width6' == $blog_settings[ 'masonry_most_recent_width' ] ) {
$new_settings[ 'featured_column' ] = true;
} else {
$new_settings[ 'featured_column' ] = false;
}
}
if ( 'width6' == $blog_settings[ 'masonry_width' ] ) {
$new_settings[ 'featured_column' ] = false;
}
}
if ( function_exists( 'generate_page_header_get_defaults' ) ) {
$page_header_settings = wp_parse_args(
get_option( 'generate_page_header_settings', array() ),
generate_page_header_get_defaults()
);
if ( 'hide' == $page_header_settings[ 'post_header_position' ] ) {
$new_settings[ 'single_post_image' ] = false;
} else {
$new_settings[ 'single_post_image_position' ] = $page_header_settings[ 'post_header_position' ];
}
$new_settings[ 'page_post_image_position' ] = $page_header_settings[ 'page_header_position' ];
}
unset( $blog_settings['masonry_width'] );
unset( $blog_settings['masonry_most_recent_width'] );
$update_settings = wp_parse_args( $new_settings, $blog_settings );
update_option( 'generate_blog_settings', $update_settings );
// Update our migration option so we don't need to run this again
$updated[ 'blog_visibility_updated' ] = 'true';
$migration_settings = wp_parse_args( $updated, $settings );
update_option( 'generate_migration_settings', $migration_settings );
}

View File

@ -0,0 +1,20 @@
<?php
/**
* Blog module.
*
* @since 1.1.0
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
// Define the version. This used to be a standalone plugin, so we need to keep this constant.
if ( ! defined( 'GENERATE_BLOG_VERSION' ) ) {
define( 'GENERATE_BLOG_VERSION', GP_PREMIUM_VERSION );
}
// Include functions identical between standalone addon and GP Premium.
require plugin_dir_path( __FILE__ ) . 'functions/generate-blog.php';

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,620 @@
/**
* Theme Customizer enhancements for a better user experience.
*
* Contains handlers to make Theme Customizer preview reload changes asynchronously.
*/
function generate_colors_live_update( id, selector, property, default_value, get_value, settings ) {
default_value = typeof default_value !== 'undefined' ? default_value : 'initial';
get_value = typeof get_value !== 'undefined' ? get_value : '';
settings = typeof settings !== 'undefined' ? settings : 'generate_settings';
wp.customize( settings + '[' + id + ']', function( value ) {
value.bind( function( newval ) {
// Stop the header link color from applying to the site title.
if ( 'header_link_color' === id || 'header_link_color' === id ) {
jQuery( '.site-header a' ).addClass( 'header-link' );
jQuery( '.site-header .main-title a' ).removeClass( 'header-link' );
}
if ( 'content_link_color' === id || 'content_link_color_hover' === id || 'entry_meta_link_color' === id || 'blog_post_title_color' === id ) {
var content_link = jQuery( '.inside-article a' );
var meta = jQuery( '.entry-meta a' );
var title = jQuery( '.entry-title a' );
content_link.attr( 'data-content-link-color', true );
if ( '' !== wp.customize.value('generate_settings[entry_meta_link_color]')() ) {
meta.attr( 'data-content-link-color', '' );
} else {
meta.attr( 'data-content-link-color', true );
}
if ( '' !== wp.customize.value('generate_settings[blog_post_title_color]')() ) {
title.attr( 'data-content-link-color', '' );
} else {
title.attr( 'data-content-link-color', true );
}
}
default_value = ( '' !== get_value ) ? wp.customize.value('generate_settings[' + get_value + ']')() : default_value;
newval = ( '' !== newval ) ? newval : default_value;
var unique_id = ( 'generate_secondary_nav_settings' == settings ) ? 'secondary_' : '';
if ( jQuery( 'style#' + unique_id + id ).length ) {
jQuery( 'style#' + unique_id + id ).html( selector + '{' + property + ':' + newval + ';}' );
} else {
jQuery( 'head' ).append( '<style id="' + unique_id + id + '">' + selector + '{' + property + ':' + newval + '}</style>' );
setTimeout(function() {
jQuery( 'style#' + id ).not( ':last' ).remove();
}, 1000);
}
} );
} );
}
/**
* Header background color
* Empty: transparent
*/
generate_colors_live_update( 'top_bar_background_color', '.top-bar', 'background-color', 'transparent' );
/**
* Header text color
* Empty: text_color
*/
generate_colors_live_update( 'top_bar_text_color', '.top-bar', 'color', '', 'text_color' );
/**
* Header link color
* Empty: link_color
*/
generate_colors_live_update( 'top_bar_link_color', '.top-bar a, .top-bar a:visited', 'color', '', 'link_color' );
/**
* Header link color hover
* Empty: link_color_hover
*/
generate_colors_live_update( 'top_bar_link_color_hover', '.top-bar a:hover', 'color', '', 'link_color_hover' );
/**
* Header background color
* Empty: transparent
*/
generate_colors_live_update( 'header_background_color', '.site-header', 'background-color', 'transparent' );
/**
* Header text color
* Empty: text_color
*/
generate_colors_live_update( 'header_text_color', '.site-header', 'color', '', 'text_color' );
/**
* Header link color
* Empty: link_color
*/
generate_colors_live_update( 'header_link_color', '.site-header a.header-link, .site-header a.header-link:visited', 'color', '', 'link_color' );
/**
* Header link color hover
* Empty: link_color_hover
*/
generate_colors_live_update( 'header_link_hover_color', '.site-header a.header-link:hover', 'color', '', 'link_color_hover' );
/**
* Site title color
* Empty: link_color
*/
generate_colors_live_update( 'site_title_color', '.main-title a,.main-title a:hover,.main-title a:visited,.header-wrap .navigation-stick .main-title a, .header-wrap .navigation-stick .main-title a:hover, .header-wrap .navigation-stick .main-title a:visited', 'color', '', 'link_color' );
/**
* Site tagline color
* Empty: text_color
*/
generate_colors_live_update( 'site_tagline_color', '.site-description', 'color', '', 'text_color' );
/**
* Main navigation background
* Empty: transparent
*/
generate_colors_live_update( 'navigation_background_color', '.main-navigation', 'background-color', 'transparent' );
/**
* Primary navigation text color
* Empty: link_color
*/
generate_colors_live_update( 'navigation_text_color',
'.main-navigation .main-nav ul li a,\
.menu-toggle,button.menu-toggle:hover,\
button.menu-toggle:focus,\
.main-navigation .mobile-bar-items a,\
.main-navigation .mobile-bar-items a:hover,\
.main-navigation .mobile-bar-items a:focus,\
.main-navigation .menu-bar-items',
'color', '', 'link_color'
);
/**
* Primary navigation text color hover
* Empty: link_color_hover
*/
generate_colors_live_update( 'navigation_text_hover_color',
'.navigation-search input[type="search"],\
.navigation-search input[type="search"]:active,\
.navigation-search input[type="search"]:focus,\
.main-navigation .main-nav ul li:hover > a,\
.main-navigation .main-nav ul li:focus > a,\
.main-navigation .main-nav ul li.sfHover > a,\
.main-navigation .menu-bar-item:hover a',
'color', '', 'link_color_hover'
);
/**
* Primary navigation menu item hover
* Empty: link_color_hover
*/
generate_colors_live_update( 'navigation_background_hover_color',
'.navigation-search input[type="search"],\
.navigation-search input[type="search"]:focus,\
.main-navigation .main-nav ul li:hover > a,\
.main-navigation .main-nav ul li:focus > a,\
.main-navigation .main-nav ul li.sfHover > a,\
.main-navigation .menu-bar-item:hover a',
'background-color', 'transparent'
);
/**
* Primary sub-navigation color
* Empty: transparent
*/
generate_colors_live_update( 'subnavigation_background_color', '.main-navigation ul ul', 'background-color', 'transparent' );
/**
* Primary sub-navigation text color
* Empty: link_color
*/
generate_colors_live_update( 'subnavigation_text_color', '.main-navigation .main-nav ul ul li a', 'color', 'link_color' );
/**
* Primary sub-navigation hover
*/
var subnavigation_hover = '.main-navigation .main-nav ul ul li:hover > a, \
.main-navigation .main-nav ul ul li:focus > a, \
.main-navigation .main-nav ul ul li.sfHover > a';
/**
* Primary sub-navigation text hover
* Empty: link_color_hover
*/
generate_colors_live_update( 'subnavigation_text_hover_color', subnavigation_hover, 'color', '', 'link_color_hover' );
/**
* Primary sub-navigation background hover
* Empty: transparent
*/
generate_colors_live_update( 'subnavigation_background_hover_color', subnavigation_hover, 'background-color', 'transparent' );
/**
* Navigation current selectors
*/
var navigation_current = '.main-navigation .main-nav ul li[class*="current-menu-"] > a, \
.main-navigation .main-nav ul li[class*="current-menu-"]:hover > a, \
.main-navigation .main-nav ul li[class*="current-menu-"].sfHover > a';
/**
* Primary navigation current text
* Empty: link_color
*/
generate_colors_live_update( 'navigation_text_current_color', navigation_current, 'color', '', 'link_color' );
/**
* Primary navigation current text
* Empty: transparent
*/
generate_colors_live_update( 'navigation_background_current_color', navigation_current, 'background-color', 'transparent' );
/**
* Primary sub-navigation current selectors
*/
var subnavigation_current = '.main-navigation .main-nav ul ul li[class*="current-menu-"] > a,\
.main-navigation .main-nav ul ul li[class*="current-menu-"]:hover > a, \
.main-navigation .main-nav ul ul li[class*="current-menu-"].sfHover > a';
/**
* Primary sub-navigation current text
* Empty: link_color
*/
generate_colors_live_update( 'subnavigation_text_current_color', subnavigation_current, 'color', '', 'link_color' );
/**
* Primary navigation current item background
* Empty: transparent
*/
generate_colors_live_update( 'subnavigation_background_current_color', subnavigation_current, 'background-color', 'transparent' );
/**
* Secondary navigation background
* Empty: transparent
*/
generate_colors_live_update( 'navigation_background_color', '.secondary-navigation', 'background-color', 'transparent', '', 'generate_secondary_nav_settings' );
/**
* Secondary navigation text color
* Empty: link_color
*/
generate_colors_live_update( 'navigation_text_color',
'.secondary-navigation .main-nav ul li a,\
.secondary-navigation .menu-toggle,\
button.secondary-menu-toggle:hover,\
button.secondary-menu-toggle:focus, \
.secondary-navigation .top-bar, \
.secondary-navigation .top-bar a,\
.secondary-menu-bar-items,\
.secondary-menu-bar-items .menu-bar-item > a',
'color', '', 'link_color', 'generate_secondary_nav_settings'
);
/**
* Navigation search
*/
wp.customize( 'generate_settings[navigation_search_background_color]', function( value ) {
value.bind( function( newval ) {
if ( jQuery( 'style#navigation_search_background_color' ).length ) {
jQuery( 'style#navigation_search_background_color' ).html( '.navigation-search input[type="search"],.navigation-search input[type="search"]:active, .navigation-search input[type="search"]:focus, .main-navigation .main-nav ul li.search-item.active > a, .main-navigation .menu-bar-items .search-item.active > a{background-color:' + newval + ';}' );
} else {
jQuery( 'head' ).append( '<style id="navigation_search_background_color">.navigation-search input[type="search"],.navigation-search input[type="search"]:active, .navigation-search input[type="search"]:focus, .main-navigation .main-nav ul li.search-item.active > a, .main-navigation .menu-bar-items .search-item.active > a{background-color:' + newval + ';}</style>' );
setTimeout(function() {
jQuery( 'style#navigation_search_background_color' ).not( ':last' ).remove();
}, 1000);
}
if ( jQuery( 'style#navigation_search_background_opacity' ).length ) {
if ( newval ) {
jQuery( 'style#navigation_search_background_opacity' ).html( '.navigation-search input{opacity: 1;}' );
} else {
jQuery( 'style#navigation_search_background_opacity' ).html( '.navigation-search input{opacity: 0.9;}' );
}
} else {
if ( newval ) {
jQuery( 'head' ).append( '<style id="navigation_search_background_opacity">.navigation-search input{opacity: 1;}</style>' );
}
setTimeout(function() {
jQuery( 'style#navigation_search_background_opacity' ).not( ':last' ).remove();
}, 1000);
}
} );
} );
generate_colors_live_update( 'navigation_search_text_color', '.navigation-search input[type="search"],.navigation-search input[type="search"]:active, .navigation-search input[type="search"]:focus, .main-navigation .main-nav ul li.search-item.active > a, .main-navigation .menu-bar-items .search-item.active > a', 'color', '' );
/**
* Secondary navigation text color hover
* Empty: link_color_hover
*/
generate_colors_live_update( 'navigation_text_hover_color',
'.secondary-navigation .main-nav ul li:hover > a, \
.secondary-navigation .main-nav ul li:focus > a, \
.secondary-navigation .main-nav ul li.sfHover > a,\
.secondary-menu-bar-items .menu-bar-item:hover > a',
'color', '', 'link_color_hover', 'generate_secondary_nav_settings'
);
/**
* Secondary navigation menu item hover
* Empty: link_color_hover
*/
generate_colors_live_update( 'navigation_background_hover_color',
'.secondary-navigation .main-nav ul li:hover > a, \
.secondary-navigation .main-nav ul li:focus > a, \
.secondary-navigation .main-nav ul li.sfHover > a, \
.secondary-menu-bar-items .menu-bar-item:hover > a',
'background-color', 'transparent', '', 'generate_secondary_nav_settings'
);
/**
* Secondary navigation top bar link hover
*/
wp.customize( 'generate_secondary_nav_settings[navigation_background_hover_color]', function( value ) {
value.bind( function( newval ) {
if ( jQuery( 'style#secondary_nav_top_bar_hover' ).length ) {
jQuery( 'style#secondary_nav_top_bar_hover' ).html( '.secondary-navigation .top-bar a:hover,.secondary-navigation .top-bar a:focus{color:' + newval + ';}' );
} else {
jQuery( 'head' ).append( '<style id="secondary_nav_top_bar_hover">.secondary-navigation .top-bar a:hover,.secondary-navigation .top-bar a:focus{color:' + newval + ';}</style>' );
setTimeout(function() {
jQuery( 'style#secondary_nav_top_bar_hover' ).not( ':last' ).remove();
}, 1000);
}
} );
} );
generate_colors_live_update( 'navigation_top_bar_hover_color',
'.secondary-navigation .top-bar a:hover, \
.secondary-navigation .top-bar a:focus',
'color', 'transparent', '', 'generate_secondary_nav_settings'
);
/**
* Secondary sub-navigation color
* Empty: transparent
*/
generate_colors_live_update( 'subnavigation_background_color', '.secondary-navigation ul ul', 'background-color', 'transparent', '', 'generate_secondary_nav_settings' );
/**
* Secondary sub-navigation text color
* Empty: link_color
*/
generate_colors_live_update( 'subnavigation_text_color', '.secondary-navigation .main-nav ul ul li a', 'color', '', 'link_color', 'generate_secondary_nav_settings' );
/**
* Secondary sub-navigation hover
*/
var secondary_subnavigation_hover = '.secondary-navigation .main-nav ul ul li > a:hover, \
.secondary-navigation .main-nav ul ul li:focus > a, \
.secondary-navigation .main-nav ul ul li.sfHover > a';
/**
* Secondary sub-navigation text hover
* Empty: link_color_hover
*/
generate_colors_live_update( 'subnavigation_text_hover_color', secondary_subnavigation_hover, 'color', '', 'link_color_hover', 'generate_secondary_nav_settings' );
/**
* Secondary sub-navigation background hover
* Empty: transparent
*/
generate_colors_live_update( 'subnavigation_background_hover_color', secondary_subnavigation_hover, 'background-color', 'transparent', '', 'generate_secondary_nav_settings' );
/**
* Secondary navigation current selectors
*/
var secondary_navigation_current = '.secondary-navigation .main-nav ul li[class*="current-menu-"] > a, \
.secondary-navigation .main-nav ul li[class*="current-menu-"]:hover > a, \
.secondary-navigation .main-nav ul li[class*="current-menu-"].sfHover > a';
/**
* Secondary navigation current text
* Empty: link_color
*/
generate_colors_live_update( 'navigation_text_current_color', secondary_navigation_current, 'color', '', 'link_color', 'generate_secondary_nav_settings' );
/**
* Secondary navigation current text
* Empty: transparent
*/
generate_colors_live_update( 'navigation_background_current_color', secondary_navigation_current, 'background-color', 'transparent', '', 'generate_secondary_nav_settings' );
/**
* Secondary sub-navigation current selectors
*/
var secondary_subnavigation_current = '.secondary-navigation .main-nav ul ul li[class*="current-menu-"] > a,\
.secondary-navigation .main-nav ul ul li[class*="current-menu-"]:hover > a, \
.secondary-navigation .main-nav ul ul li[class*="current-menu-"].sfHover > a';
/**
* Secondary sub-navigation current text
* Empty: link_color
*/
generate_colors_live_update( 'subnavigation_text_current_color', secondary_subnavigation_current, 'color', '', 'link_color', 'generate_secondary_nav_settings' );
/**
* Primary navigation current item background
* Empty: transparent
*/
generate_colors_live_update( 'subnavigation_background_current_color', secondary_subnavigation_current, 'background-color', 'transparent', '', 'generate_secondary_nav_settings' );
/**
* Content selectors
*/
var content = '.separate-containers .inside-article,\
.separate-containers .comments-area,\
.separate-containers .page-header,\
.one-container .container,\
.separate-containers .paging-navigation,\
.inside-page-header';
/**
* Content background
* Empty: transparent
*/
generate_colors_live_update( 'content_background_color', content, 'background-color', 'transparent' );
/**
* Content text color
* Empty: text_color
*/
generate_colors_live_update( 'content_text_color', content, 'color', '', 'text_color' );
/**
* Content links
* Empty: link_color
*/
generate_colors_live_update( 'content_link_color',
'.inside-article a:not(.button):not(.wp-block-button__link)[data-content-link-color=true], \
.inside-article a:not(.button):not(.wp-block-button__link)[data-content-link-color=true]:visited,\
.paging-navigation a,\
.paging-navigation a:visited,\
.comments-area a,\
.comments-area a:visited,\
.page-header a,\
.page-header a:visited',
'color', '', 'link_color'
);
/**
* Content links on hover
* Empty: link_color_hover
*/
generate_colors_live_update( 'content_link_hover_color',
'.inside-article a:not(.button):not(.wp-block-button__link)[data-content-link-color=true]:hover,\
.paging-navigation a:hover,\
.comments-area a:hover,\
.page-header a:hover',
'color', '', 'link_color_hover'
);
generate_colors_live_update( 'content_title_color', '.entry-header h1,.page-header h1', 'color', 'inherit', 'text_color' );
generate_colors_live_update( 'blog_post_title_color', '.entry-title a,.entry-title a:visited', 'color', '', 'link_color' );
generate_colors_live_update( 'blog_post_title_hover_color', '.entry-title a:hover', 'color', '', 'link_color_hover' );
generate_colors_live_update( 'entry_meta_text_color', '.entry-meta', 'color', '', 'text_color' );
generate_colors_live_update( 'entry_meta_link_color', '.entry-meta a, .entry-meta a:visited', 'color', '', 'link_color' );
generate_colors_live_update( 'entry_meta_link_color_hover', '.entry-meta a:hover', 'color', '', 'link_color_hover' );
generate_colors_live_update( 'h1_color', 'h1', 'color', '', 'text_color' );
generate_colors_live_update( 'h2_color', 'h2', 'color', '', 'text_color' );
generate_colors_live_update( 'h3_color', 'h3', 'color', '', 'text_color' );
generate_colors_live_update( 'h4_color', 'h4', 'color', '', 'text_color' );
generate_colors_live_update( 'h5_color', 'h5', 'color', '', 'text_color' );
generate_colors_live_update( 'sidebar_widget_background_color', '.sidebar .widget', 'background-color', 'transparent' );
generate_colors_live_update( 'sidebar_widget_text_color', '.sidebar .widget', 'color', '', 'text_color' );
generate_colors_live_update( 'sidebar_widget_link_color', '.sidebar .widget a, .sidebar .widget a:visited', 'color', '', 'link_color' );
generate_colors_live_update( 'sidebar_widget_link_hover_color', '.sidebar .widget a:hover', 'color', '', 'link_color_hover' );
generate_colors_live_update( 'sidebar_widget_title_color', '.sidebar .widget .widget-title', 'color', '', 'text_color' );
generate_colors_live_update( 'footer_widget_background_color', '.footer-widgets', 'background-color', 'transparent' );
generate_colors_live_update( 'footer_widget_text_color', '.footer-widgets', 'color', '', 'text_color' );
generate_colors_live_update( 'footer_widget_link_color', '.footer-widgets a, .footer-widgets a:visited', 'color', '', 'link_color' );
generate_colors_live_update( 'footer_widget_link_hover_color', '.footer-widgets a:hover', 'color', '', 'link_color_hover' );
generate_colors_live_update( 'footer_widget_title_color', '.footer-widgets .widget-title', 'color', '', 'text_color' );
generate_colors_live_update( 'footer_background_color', '.site-info', 'background-color', 'transparent' );
generate_colors_live_update( 'footer_text_color', '.site-info', 'color', '', 'text_color' );
generate_colors_live_update( 'footer_link_color', '.site-info a, .site-info a:visited', 'color', '', 'link_color' );
generate_colors_live_update( 'footer_link_hover_color', '.site-info a:hover', 'color', '', 'link_color_hover' );
/**
* Form selectors
*/
var forms = 'input[type="text"], \
input[type="email"], \
input[type="url"], \
input[type="password"], \
input[type="search"], \
input[type="number"], \
input[type="tel"], \
textarea, \
select';
/**
* Form background
* Empty: inherit
*/
generate_colors_live_update( 'form_background_color', forms, 'background-color', 'inherit' );
/**
* Border color
* Empty: inherit
*/
generate_colors_live_update( 'form_border_color', forms, 'border-color' );
/**
* Form text color
* Empty: text_color
*/
generate_colors_live_update( 'form_text_color', forms, 'color', '', 'text_color' );
/**
* Form background on focus selectors
* Empty: inherit
*/
var forms_focus = 'input[type="text"]:focus, \
input[type="email"]:focus, \
input[type="url"]:focus, \
input[type="password"]:focus, \
input[type="search"]:focus,\
input[type="number"]:focus,\
input[type="tel"]:focus, \
textarea:focus, \
select:focus';
/**
* Form background color on focus
* Empty: initial
*/
generate_colors_live_update( 'form_background_color_focus', forms_focus, 'background-color' );
/**
* Form text color on focus
* Empty: initial
*/
generate_colors_live_update( 'form_text_color_focus', forms_focus, 'color' );
/**
* Form border color on focus
* Empty: initial
*/
generate_colors_live_update( 'form_border_color_focus', forms_focus, 'border-color' );
/**
* Button selectors
*/
var button = 'button, \
html input[type="button"], \
input[type="reset"], \
input[type="submit"],\
a.button,\
a.button:visited,\
a.wp-block-button__link:not(.has-background)';
/**
* Button background
* Empty: initial
*/
generate_colors_live_update( 'form_button_background_color', button, 'background-color' );
/**
* Button text
* Empty: initial
*/
generate_colors_live_update( 'form_button_text_color', button, 'color' );
/**
* Button on hover/focus selectors
* Empty: initial
*/
var button_hover = 'button:hover, \
html input[type="button"]:hover, \
input[type="reset"]:hover, \
input[type="submit"]:hover,\
a.button:hover,\
button:focus, \
html input[type="button"]:focus, \
input[type="reset"]:focus, \
input[type="submit"]:focus,\
a.button:focus,\
a.wp-block-button__link:not(.has-background):active,\
a.wp-block-button__link:not(.has-background):focus,\
a.wp-block-button__link:not(.has-background):hover';
/**
* Button color on hover
* Empty: initial
*/
generate_colors_live_update( 'form_button_background_color_hover', button_hover, 'background-color' );
/**
* Button text color on hover
* Empty: initial
*/
generate_colors_live_update( 'form_button_text_color_hover', button_hover, 'color' );
/**
* Back to top background color
* Empty: transparent
*/
generate_colors_live_update( 'back_to_top_background_color', 'a.generate-back-to-top', 'background-color', 'transparent' );
/**
* Back to top text color
* Empty: text_color
*/
generate_colors_live_update( 'back_to_top_text_color', 'a.generate-back-to-top', 'color', '', 'text_color' );
/**
* Back to top background color hover
* Empty: transparent
*/
generate_colors_live_update( 'back_to_top_background_color_hover', 'a.generate-back-to-top:hover,a.generate-back-to-top:focus', 'background-color', 'transparent' );
/**
* Back to top text color hover
* Empty: text_color
*/
generate_colors_live_update( 'back_to_top_text_color_hover', 'a.generate-back-to-top:hover,a.generate-back-to-top:focus', 'color', '', 'text_color' );

View File

@ -0,0 +1,102 @@
/**
* Main navigation background
* Empty: transparent
*/
generate_colors_live_update( 'slideout_background_color', '.main-navigation.slideout-navigation', 'background-color', '' );
/**
* Primary navigation text color
* Empty: link_color
*/
generate_colors_live_update( 'slideout_text_color', '.slideout-navigation.main-navigation .main-nav ul li a, .slideout-navigation a, .slideout-navigation', 'color', '' );
/**
* Primary navigation text color hover
* Empty: link_color_hover
*/
generate_colors_live_update( 'slideout_text_hover_color',
'.slideout-navigation.main-navigation .main-nav ul li:hover > a,\
.slideout-navigation.main-navigation .main-nav ul li:focus > a,\
.slideout-navigation.main-navigation .main-nav ul li.sfHover > a',
'color', ''
);
/**
* Primary navigation menu item hover
* Empty: link_color_hover
*/
generate_colors_live_update( 'slideout_background_hover_color',
'.slideout-navigation.main-navigation .main-nav ul li:hover > a,\
.slideout-navigation.main-navigation .main-nav ul li:focus > a,\
.slideout-navigation.main-navigation .main-nav ul li.sfHover > a',
'background-color', 'transparent'
);
/**
* Primary sub-navigation color
* Empty: transparent
*/
generate_colors_live_update( 'slideout_submenu_background_color', '.slideout-navigation.main-navigation ul ul', 'background-color', '' );
/**
* Primary sub-navigation text color
* Empty: link_color
*/
generate_colors_live_update( 'slideout_submenu_text_color', '.slideout-navigation.main-navigation .main-nav ul ul li a', 'color', '' );
/**
* Primary sub-navigation hover
*/
var slideout_submenu_hover = '.slideout-navigation.main-navigation .main-nav ul ul li:hover > a,\
.slideout-navigation.main-navigation .main-nav ul ul li:focus > a,\
.slideout-navigation.main-navigation .main-nav ul ul li.sfHover > a';
/**
* Primary sub-navigation text hover
* Empty: link_color_hover
*/
generate_colors_live_update( 'slideout_submenu_text_hover_color', slideout_submenu_hover, 'color', '' );
/**
* Primary sub-navigation background hover
* Empty: transparent
*/
generate_colors_live_update( 'slideout_submenu_background_hover_color', slideout_submenu_hover, 'background-color', '' );
/**
* Navigation current selectors
*/
var slideout_current = '.slideout-navigation.main-navigation .main-nav ul li[class*="current-menu-"] > a,\
.slideout-navigation.main-navigation .main-nav ul li[class*="current-menu-"] > a:hover,\
.slideout-navigation.main-navigation .main-nav ul li[class*="current-menu-"].sfHover > a';
/**
* Primary navigation current text
* Empty: link_color
*/
generate_colors_live_update( 'slideout_text_current_color', slideout_current, 'color', '' );
/**
* Primary navigation current text
* Empty: transparent
*/
generate_colors_live_update( 'slideout_background_current_color', slideout_current, 'background-color' );
/**
* Primary sub-navigation current selectors
*/
var slideout_submenu_current = '.slideout-navigation.main-navigation .main-nav ul ul li[class*="current-menu-"] > a,\
.slideout-navigation.main-navigation .main-nav ul ul li[class*="current-menu-"] > a:hover,\
.slideout-navigation.main-navigation .main-nav ul ul li[class*="current-menu-"].sfHover > a';
/**
* Primary sub-navigation current text
* Empty: link_color
*/
generate_colors_live_update( 'slideout_submenu_text_current_color', slideout_submenu_current, 'color', '' );
/**
* Primary navigation current item background
* Empty: transparent
*/
generate_colors_live_update( 'slideout_submenu_background_current_color', slideout_submenu_current, 'background-color' );

View File

@ -0,0 +1,161 @@
/**
* WooCommerce link color
*/
generate_colors_live_update( 'wc_product_title_color', '.woocommerce ul.products li.product .woocommerce-LoopProduct-link', 'color', '', 'link_color' );
generate_colors_live_update( 'wc_product_title_color_hover', '.woocommerce ul.products li.product .woocommerce-LoopProduct-link:hover', 'color', '', 'link_color_hover' );
/**
* WooCommerce primary button
*/
var wc_button = '.woocommerce #respond input#submit, .woocommerce a.button, .woocommerce button.button, .woocommerce input.button, button, \
html input[type="button"], \
input[type="reset"], \
input[type="submit"],\
.button,\
.button:visited';
generate_colors_live_update( 'form_button_background_color', wc_button, 'background-color' );
generate_colors_live_update( 'form_button_text_color', wc_button, 'color' );
/**
* WooCommerce primary button hover
*/
var wc_button_hover = '.woocommerce #respond input#submit:hover, .woocommerce a.button:hover, .woocommerce button.button:hover, .woocommerce input.button:hover,button:hover, \
html input[type="button"]:hover, \
input[type="reset"]:hover, \
input[type="submit"]:hover,\
.button:hover,\
button:focus, \
html input[type="button"]:focus, \
input[type="reset"]:focus, \
input[type="submit"]:focus,\
.button:focus';
generate_colors_live_update( 'form_button_background_color_hover', wc_button_hover, 'background-color' );
generate_colors_live_update( 'form_button_text_color_hover', wc_button_hover, 'color' );
/**
* WooCommerce alt button
*/
var wc_alt_button = '.woocommerce #respond input#submit.alt, .woocommerce a.button.alt, .woocommerce button.button.alt, .woocommerce input.button.alt';
generate_colors_live_update( 'wc_alt_button_background', wc_alt_button, 'background-color' );
generate_colors_live_update( 'wc_alt_button_text', wc_alt_button, 'color' );
/**
* WooCommerce alt button hover
*/
var wc_alt_button_hover = '.woocommerce #respond input#submit.alt:hover, .woocommerce a.button.alt:hover, .woocommerce button.button.alt:hover, .woocommerce input.button.alt:hover';
generate_colors_live_update( 'wc_alt_button_background_hover', wc_alt_button_hover, 'background-color' );
generate_colors_live_update( 'wc_alt_button_text_hover', wc_alt_button_hover, 'color' );
/**
* WooCommerce star ratings
*/
var wc_stars = '.woocommerce .star-rating span:before, .woocommerce .star-rating:before';
generate_colors_live_update( 'wc_rating_stars', wc_stars, 'color' );
/**
* WooCommerce sale sticker
*/
var wc_sale_sticker = '.woocommerce span.onsale';
generate_colors_live_update( 'wc_sale_sticker_background', wc_sale_sticker, 'background-color' );
generate_colors_live_update( 'wc_sale_sticker_text', wc_sale_sticker, 'color' );
/**
* WooCommerce price
*/
var wc_price = '.woocommerce ul.products li.product .price, .woocommerce div.product p.price';
generate_colors_live_update( 'wc_price_color', wc_price, 'color' );
/**
* WooCommerce product tab text
*/
var wc_product_tab = '.woocommerce div.product .woocommerce-tabs ul.tabs li a';
generate_colors_live_update( 'wc_product_tab', wc_product_tab, 'color' );
/**
* WooCommerce product tab text highlight/active
*/
var wc_product_tab_active = '.woocommerce div.product .woocommerce-tabs ul.tabs li a:hover, .woocommerce div.product .woocommerce-tabs ul.tabs li.active a';
generate_colors_live_update( 'wc_product_tab_highlight', wc_product_tab_active, 'color' );
/**
* WooCommerce success message
*/
var wc_success_message = '.woocommerce-message';
generate_colors_live_update( 'wc_success_message_background', wc_success_message, 'background-color' );
generate_colors_live_update( 'wc_success_message_text', wc_success_message + ', div.woocommerce-message a.button, div.woocommerce-message a.button:focus, div.woocommerce-message a.button:hover, div.woocommerce-message a, div.woocommerce-message a:focus, div.woocommerce-message a:hover', 'color' );
/**
* WooCommerce info message
*/
var wc_info_message = '.woocommerce-info';
generate_colors_live_update( 'wc_info_message_background', wc_info_message, 'background-color' );
generate_colors_live_update( 'wc_info_message_text', wc_info_message + ', div.woocommerce-info a.button, div.woocommerce-info a.button:focus, div.woocommerce-info a.button:hover, div.woocommerce-info a, div.woocommerce-info a:focus, div.woocommerce-info a:hover', 'color' );
/**
* WooCommerce error message
*/
var wc_error_message = '.woocommerce-error';
generate_colors_live_update( 'wc_error_message_background', wc_error_message, 'background-color' );
generate_colors_live_update( 'wc_error_message_text', wc_error_message + ', div.woocommerce-error a.button, div.woocommerce-error a.button:focus, div.woocommerce-error a.button:hover, div.woocommerce-error a, div.woocommerce-error a:focus, div.woocommerce-error a:hover', 'color' );
/**
* Menu Mini Cart
*/
generate_colors_live_update( 'wc_mini_cart_background_color', '#wc-mini-cart', 'background-color' );
generate_colors_live_update( 'wc_mini_cart_text_color', '#wc-mini-cart,#wc-mini-cart a:not(.button), #wc-mini-cart a.remove', 'color' );
generate_colors_live_update( 'wc_mini_cart_button_background', '#wc-mini-cart .button.checkout', 'background-color' );
generate_colors_live_update( 'wc_mini_cart_button_text', '#wc-mini-cart .button.checkout', 'color' );
generate_colors_live_update( 'wc_mini_cart_button_background_hover', '#wc-mini-cart .button.checkout:hover, #wc-mini-cart .button.checkout:focus, #wc-mini-cart .button.checkout:active', 'background-color' );
generate_colors_live_update( 'wc_mini_cart_button_text_hover', '#wc-mini-cart .button.checkout:hover, #wc-mini-cart .button.checkout:focus, #wc-mini-cart .button.checkout:active', 'color' );
/**
* Sticky panel cart button
*/
generate_colors_live_update( 'wc_panel_cart_background_color', '.add-to-cart-panel', 'background-color' );
generate_colors_live_update( 'wc_panel_cart_text_color', '.add-to-cart-panel, .add-to-cart-panel a:not(.button)', 'color' );
generate_colors_live_update( 'wc_panel_cart_button_background', '#wc-sticky-cart-panel .button', 'background-color' );
generate_colors_live_update( 'wc_panel_cart_button_text', '#wc-sticky-cart-panel .button', 'color' );
generate_colors_live_update( 'wc_panel_cart_button_background_hover', '#wc-sticky-cart-panel .button:hover, #wc-sticky-cart-panel .button:focus, #wc-sticky-cart-panel .button:active', 'background-color' );
generate_colors_live_update( 'wc_panel_cart_button_text_hover', '#wc-sticky-cart-panel .button:hover, #wc-sticky-cart-panel .button:focus, #wc-sticky-cart-panel .button:active', 'color' );
/**
* Price slider bar
*/
generate_colors_live_update( 'wc_price_slider_background_color', '.woocommerce .widget_price_filter .price_slider_wrapper .ui-widget-content', 'background-color' );
generate_colors_live_update( 'wc_price_slider_bar_color', '.woocommerce .widget_price_filter .ui-slider .ui-slider-range, .woocommerce .widget_price_filter .ui-slider .ui-slider-handle', 'background-color' );
// Archive product description text
wp.customize( 'generate_settings[text_color]', function( value ) {
value.bind( function( newval ) {
if ( ! wp.customize.value('generate_settings[content_text_color]')() ) {
if ( jQuery( 'style#wc_desc_color' ).length ) {
jQuery( 'style#wc_desc_color' ).html( '.woocommerce-product-details__short-description{color:' + newval + ';}' );
} else {
jQuery( 'head' ).append( '<style id="wc_desc_color">.woocommerce-product-details__short-description{color:' + newval + ';}</style>' );
setTimeout(function() {
jQuery( 'style#wc_desc_color' ).not( ':last' ).remove();
}, 1000);
}
}
} );
} );
wp.customize( 'generate_settings[content_text_color]', function( value ) {
value.bind( function( newval ) {
if ( '' == newval ) {
newval = wp.customize.value('generate_settings[text_color]')();
}
if ( jQuery( 'style#wc_desc_color' ).length ) {
jQuery( 'style#wc_desc_color' ).html( '.woocommerce-product-details__short-description{color:' + newval + ';}' );
} else {
jQuery( 'head' ).append( '<style id="wc_desc_color">.woocommerce-product-details__short-description{color:' + newval + ';}</style>' );
setTimeout(function() {
jQuery( 'style#wc_desc_color' ).not( ':last' ).remove();
}, 1000);
}
} );
} );

View File

@ -0,0 +1,403 @@
<?php
/**
* This file handles the Customizer options for the Secondary Nav module.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
if ( ! function_exists( 'generate_colors_secondary_nav_customizer' ) ) {
add_action( 'customize_register', 'generate_colors_secondary_nav_customizer', 1000 );
/**
* Adds our Secondary Nav color options
*
* These options are in their own function so we can hook it in late to
* make sure Secondary Nav is activated.
*
* 1000 priority is there to make sure Secondary Nav is registered (999)
* as we check to see if the layout control exists.
*
* Secondary Nav now uses 100 as a priority.
*
* @param object $wp_customize The Customizer object.
*/
function generate_colors_secondary_nav_customizer( $wp_customize ) {
// Bail if Secondary Nav isn't activated.
if ( ! $wp_customize->get_section( 'secondary_nav_section' ) ) {
return;
}
// Bail if we don't have our color defaults.
if ( ! function_exists( 'generate_secondary_nav_get_defaults' ) ) {
return;
}
// Add our controls.
require_once GP_LIBRARY_DIRECTORY . 'customizer-helpers.php';
// Get our defaults.
$defaults = generate_secondary_nav_get_defaults();
// Add control types so controls can be built using JS.
if ( method_exists( $wp_customize, 'register_control_type' ) ) {
$wp_customize->register_control_type( 'GeneratePress_Alpha_Color_Customize_Control' );
$wp_customize->register_control_type( 'GeneratePress_Title_Customize_Control' );
$wp_customize->register_control_type( 'GeneratePress_Section_Shortcut_Control' );
}
// Get our palettes.
$palettes = generate_get_default_color_palettes();
// Add Secondary Navigation section.
$wp_customize->add_section(
'secondary_navigation_color_section',
array(
'title' => __( 'Secondary Navigation', 'gp-premium' ),
'capability' => 'edit_theme_options',
'priority' => 71,
'panel' => 'generate_colors_panel',
)
);
$wp_customize->add_control(
new GeneratePress_Section_Shortcut_Control(
$wp_customize,
'generate_secondary_navigation_color_shortcuts',
array(
'section' => 'secondary_navigation_color_section',
'element' => __( 'Secondary Navigation', 'gp-premium' ),
'shortcuts' => array(
'layout' => 'secondary_nav_section',
'typography' => 'secondary_font_section',
'backgrounds' => 'secondary_bg_images_section',
),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
'priority' => 1,
)
)
);
$wp_customize->add_control(
new GeneratePress_Title_Customize_Control(
$wp_customize,
'generate_secondary_navigation_items',
array(
'section' => 'secondary_navigation_color_section',
'type' => 'generatepress-customizer-title',
'title' => __( 'Parent Items', 'gp-premium' ),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
)
)
);
// Background.
$wp_customize->add_setting(
'generate_secondary_nav_settings[navigation_background_color]',
array(
'default' => $defaults['navigation_background_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'secondary_navigation_background_color',
array(
'label' => __( 'Background', 'gp-premium' ),
'section' => 'secondary_navigation_color_section',
'settings' => 'generate_secondary_nav_settings[navigation_background_color]',
'palette' => $palettes,
)
)
);
// Text.
$wp_customize->add_setting(
'generate_secondary_nav_settings[navigation_text_color]',
array(
'default' => $defaults['navigation_text_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'secondary_navigation_text_color',
array(
'label' => __( 'Text', 'gp-premium' ),
'section' => 'secondary_navigation_color_section',
'settings' => 'generate_secondary_nav_settings[navigation_text_color]',
)
)
);
// Background hover.
$wp_customize->add_setting(
'generate_secondary_nav_settings[navigation_background_hover_color]',
array(
'default' => $defaults['navigation_background_hover_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'secondary_navigation_background_hover_color',
array(
'label' => __( 'Background Hover', 'gp-premium' ),
'section' => 'secondary_navigation_color_section',
'settings' => 'generate_secondary_nav_settings[navigation_background_hover_color]',
'palette' => $palettes,
)
)
);
// Text hover.
$wp_customize->add_setting(
'generate_secondary_nav_settings[navigation_text_hover_color]',
array(
'default' => $defaults['navigation_text_hover_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'secondary_navigation_text_hover_color',
array(
'label' => __( 'Text Hover', 'gp-premium' ),
'section' => 'secondary_navigation_color_section',
'settings' => 'generate_secondary_nav_settings[navigation_text_hover_color]',
)
)
);
// Background current.
$wp_customize->add_setting(
'generate_secondary_nav_settings[navigation_background_current_color]',
array(
'default' => $defaults['navigation_background_current_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'secondary_navigation_background_current_color',
array(
'label' => __( 'Background Current', 'gp-premium' ),
'section' => 'secondary_navigation_color_section',
'settings' => 'generate_secondary_nav_settings[navigation_background_current_color]',
'palette' => $palettes,
)
)
);
// Text current.
$wp_customize->add_setting(
'generate_secondary_nav_settings[navigation_text_current_color]',
array(
'default' => $defaults['navigation_text_current_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'secondary_navigation_text_current_color',
array(
'label' => __( 'Text Current', 'gp-premium' ),
'section' => 'secondary_navigation_color_section',
'settings' => 'generate_secondary_nav_settings[navigation_text_current_color]',
)
)
);
$wp_customize->add_control(
new GeneratePress_Title_Customize_Control(
$wp_customize,
'generate_secondary_navigation_sub_menu_items',
array(
'section' => 'secondary_navigation_color_section',
'type' => 'generatepress-customizer-title',
'title' => __( 'Sub-Menu Items', 'gp-premium' ),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
)
)
);
// Background.
$wp_customize->add_setting(
'generate_secondary_nav_settings[subnavigation_background_color]',
array(
'default' => $defaults['subnavigation_background_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'secondary_subnavigation_background_color',
array(
'label' => __( 'Background', 'gp-premium' ),
'section' => 'secondary_navigation_color_section',
'settings' => 'generate_secondary_nav_settings[subnavigation_background_color]',
'palette' => $palettes,
)
)
);
// Text.
$wp_customize->add_setting(
'generate_secondary_nav_settings[subnavigation_text_color]',
array(
'default' => $defaults['subnavigation_text_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'secondary_subnavigation_text_color',
array(
'label' => __( 'Text', 'gp-premium' ),
'section' => 'secondary_navigation_color_section',
'settings' => 'generate_secondary_nav_settings[subnavigation_text_color]',
)
)
);
// Background hover.
$wp_customize->add_setting(
'generate_secondary_nav_settings[subnavigation_background_hover_color]',
array(
'default' => $defaults['subnavigation_background_hover_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'secondary_subnavigation_background_hover_color',
array(
'label' => __( 'Background Hover', 'gp-premium' ),
'section' => 'secondary_navigation_color_section',
'settings' => 'generate_secondary_nav_settings[subnavigation_background_hover_color]',
'palette' => $palettes,
)
)
);
// Text hover.
$wp_customize->add_setting(
'generate_secondary_nav_settings[subnavigation_text_hover_color]',
array(
'default' => $defaults['subnavigation_text_hover_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'secondary_subnavigation_text_hover_color',
array(
'label' => __( 'Text Hover', 'gp-premium' ),
'section' => 'secondary_navigation_color_section',
'settings' => 'generate_secondary_nav_settings[subnavigation_text_hover_color]',
)
)
);
// Background current.
$wp_customize->add_setting(
'generate_secondary_nav_settings[subnavigation_background_current_color]',
array(
'default' => $defaults['subnavigation_background_current_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'secondary_subnavigation_background_current_color',
array(
'label' => __( 'Background Current', 'gp-premium' ),
'section' => 'secondary_navigation_color_section',
'settings' => 'generate_secondary_nav_settings[subnavigation_background_current_color]',
'palette' => $palettes,
)
)
);
// Text current.
$wp_customize->add_setting(
'generate_secondary_nav_settings[subnavigation_text_current_color]',
array(
'default' => $defaults['subnavigation_text_current_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'secondary_subnavigation_text_current_color',
array(
'label' => __( 'Text Current', 'gp-premium' ),
'section' => 'secondary_navigation_color_section',
'settings' => 'generate_secondary_nav_settings[subnavigation_text_current_color]',
)
)
);
}
}

View File

@ -0,0 +1,400 @@
<?php
/**
* This file handles the Customizer options for the Off-Canvas Panel.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
add_action( 'customize_preview_init', 'generate_menu_plus_live_preview_scripts', 20 );
/**
* Add live preview JS to the Customizer.
*/
function generate_menu_plus_live_preview_scripts() {
wp_enqueue_script( 'generate-menu-plus-colors-customizer' );
}
add_action( 'customize_register', 'generate_slideout_navigation_color_controls', 150 );
/**
* Adds our Slideout Nav color options
*
* @since 1.6
* @param object $wp_customize The Customizer object.
*/
function generate_slideout_navigation_color_controls( $wp_customize ) {
// Bail if Secondary Nav isn't activated.
if ( ! $wp_customize->get_section( 'menu_plus_slideout_menu' ) ) {
return;
}
// Bail if we don't have our color defaults.
if ( ! function_exists( 'generate_get_color_defaults' ) ) {
return;
}
// Add our controls.
require_once GP_LIBRARY_DIRECTORY . 'customizer-helpers.php';
// Get our defaults.
$defaults = generate_get_color_defaults();
// Add control types so controls can be built using JS.
if ( method_exists( $wp_customize, 'register_control_type' ) ) {
$wp_customize->register_control_type( 'GeneratePress_Alpha_Color_Customize_Control' );
$wp_customize->register_control_type( 'GeneratePress_Section_Shortcut_Control' );
}
// Get our palettes.
$palettes = generate_get_default_color_palettes();
// Add Secondary Navigation section.
$wp_customize->add_section(
'slideout_color_section',
array(
'title' => __( 'Off Canvas Panel', 'gp-premium' ),
'capability' => 'edit_theme_options',
'priority' => 73,
'panel' => 'generate_colors_panel',
)
);
$wp_customize->add_control(
new GeneratePress_Section_Shortcut_Control(
$wp_customize,
'generate_off_canvas_color_shortcuts',
array(
'section' => 'slideout_color_section',
'element' => __( 'Off Canvas Panel', 'gp-premium' ),
'shortcuts' => array(
'layout' => 'menu_plus_slideout_menu',
'typography' => 'generate_slideout_typography',
),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
'priority' => 1,
)
)
);
$wp_customize->add_control(
new GeneratePress_Title_Customize_Control(
$wp_customize,
'generate_slideout_navigation_items',
array(
'section' => 'slideout_color_section',
'type' => 'generatepress-customizer-title',
'title' => __( 'Parent Menu Items', 'gp-premium' ),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
)
)
);
// Background.
$wp_customize->add_setting(
'generate_settings[slideout_background_color]',
array(
'default' => $defaults['slideout_background_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'generate_settings[slideout_background_color]',
array(
'label' => __( 'Background', 'gp-premium' ),
'section' => 'slideout_color_section',
'settings' => 'generate_settings[slideout_background_color]',
'palette' => $palettes,
)
)
);
// Text.
$wp_customize->add_setting(
'generate_settings[slideout_text_color]',
array(
'default' => $defaults['slideout_text_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[slideout_text_color]',
array(
'label' => __( 'Text', 'gp-premium' ),
'section' => 'slideout_color_section',
'settings' => 'generate_settings[slideout_text_color]',
)
)
);
// Background hover.
$wp_customize->add_setting(
'generate_settings[slideout_background_hover_color]',
array(
'default' => $defaults['slideout_background_hover_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'generate_settings[slideout_background_hover_color]',
array(
'label' => __( 'Background Hover', 'gp-premium' ),
'section' => 'slideout_color_section',
'settings' => 'generate_settings[slideout_background_hover_color]',
'palette' => $palettes,
)
)
);
// Text hover.
$wp_customize->add_setting(
'generate_settings[slideout_text_hover_color]',
array(
'default' => $defaults['slideout_text_hover_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[slideout_text_hover_color]',
array(
'label' => __( 'Text Hover', 'gp-premium' ),
'section' => 'slideout_color_section',
'settings' => 'generate_settings[slideout_text_hover_color]',
)
)
);
// Background current.
$wp_customize->add_setting(
'generate_settings[slideout_background_current_color]',
array(
'default' => $defaults['slideout_background_current_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'generate_settings[slideout_background_current_color]',
array(
'label' => __( 'Background Current', 'gp-premium' ),
'section' => 'slideout_color_section',
'settings' => 'generate_settings[slideout_background_current_color]',
'palette' => $palettes,
)
)
);
// Text current.
$wp_customize->add_setting(
'generate_settings[slideout_text_current_color]',
array(
'default' => $defaults['slideout_text_current_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[slideout_text_current_color]',
array(
'label' => __( 'Text Current', 'gp-premium' ),
'section' => 'slideout_color_section',
'settings' => 'generate_settings[slideout_text_current_color]',
)
)
);
$wp_customize->add_control(
new GeneratePress_Title_Customize_Control(
$wp_customize,
'generate_slideout_navigation_sub_menu_items',
array(
'section' => 'slideout_color_section',
'type' => 'generatepress-customizer-title',
'title' => __( 'Sub-Menu Items', 'gp-premium' ),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
)
)
);
// Background.
$wp_customize->add_setting(
'generate_settings[slideout_submenu_background_color]',
array(
'default' => $defaults['slideout_submenu_background_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'generate_settings[slideout_submenu_background_color]',
array(
'label' => __( 'Background', 'gp-premium' ),
'section' => 'slideout_color_section',
'settings' => 'generate_settings[slideout_submenu_background_color]',
'palette' => $palettes,
)
)
);
// Text.
$wp_customize->add_setting(
'generate_settings[slideout_submenu_text_color]',
array(
'default' => $defaults['slideout_submenu_text_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[slideout_submenu_text_color]',
array(
'label' => __( 'Text', 'gp-premium' ),
'section' => 'slideout_color_section',
'settings' => 'generate_settings[slideout_submenu_text_color]',
)
)
);
// Background hover.
$wp_customize->add_setting(
'generate_settings[slideout_submenu_background_hover_color]',
array(
'default' => $defaults['slideout_submenu_background_hover_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'generate_settings[slideout_submenu_background_hover_color]',
array(
'label' => __( 'Background Hover', 'gp-premium' ),
'section' => 'slideout_color_section',
'settings' => 'generate_settings[slideout_submenu_background_hover_color]',
'palette' => $palettes,
)
)
);
// Text hover.
$wp_customize->add_setting(
'generate_settings[slideout_submenu_text_hover_color]',
array(
'default' => $defaults['slideout_submenu_text_hover_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[slideout_submenu_text_hover_color]',
array(
'label' => __( 'Text Hover', 'gp-premium' ),
'section' => 'slideout_color_section',
'settings' => 'generate_settings[slideout_submenu_text_hover_color]',
)
)
);
// Background current.
$wp_customize->add_setting(
'generate_settings[slideout_submenu_background_current_color]',
array(
'default' => $defaults['slideout_submenu_background_current_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'generate_settings[slideout_submenu_background_current_color]',
array(
'label' => __( 'Background Current', 'gp-premium' ),
'section' => 'slideout_color_section',
'settings' => 'generate_settings[slideout_submenu_background_current_color]',
'palette' => $palettes,
)
)
);
// Text current.
$wp_customize->add_setting(
'generate_settings[slideout_submenu_text_current_color]',
array(
'default' => $defaults['slideout_submenu_text_current_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[slideout_submenu_text_current_color]',
array(
'label' => __( 'Text Current', 'gp-premium' ),
'section' => 'slideout_color_section',
'settings' => 'generate_settings[slideout_submenu_text_current_color]',
)
)
);
}

View File

@ -0,0 +1,911 @@
<?php
/**
* This file handles the Customizer options for the WooCommerce module.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
if ( ! function_exists( 'generate_colors_wc_customizer' ) ) {
add_action( 'customize_register', 'generate_colors_wc_customizer', 100 );
/**
* Adds our WooCommerce color options
*
* @param object $wp_customize The Customizer object.
*/
function generate_colors_wc_customizer( $wp_customize ) {
// Bail if WooCommerce isn't activated.
if ( ! $wp_customize->get_section( 'generate_woocommerce_colors' ) ) {
return;
}
if ( ! function_exists( 'generate_get_color_defaults' ) ) {
return;
}
// Add our controls.
require_once GP_LIBRARY_DIRECTORY . 'customizer-helpers.php';
// Get our defaults.
$defaults = generate_get_color_defaults();
// Add control types so controls can be built using JS.
if ( method_exists( $wp_customize, 'register_control_type' ) ) {
$wp_customize->register_control_type( 'GeneratePress_Alpha_Color_Customize_Control' );
$wp_customize->register_control_type( 'GeneratePress_Title_Customize_Control' );
$wp_customize->register_control_type( 'GeneratePress_Information_Customize_Control' );
$wp_customize->register_control_type( 'GeneratePress_Section_Shortcut_Control' );
}
// Get our palettes.
$palettes = generate_get_default_color_palettes();
$wp_customize->add_control(
new GeneratePress_Section_Shortcut_Control(
$wp_customize,
'generate_woocommerce_color_shortcuts',
array(
'section' => 'generate_woocommerce_colors',
'element' => __( 'WooCommerce', 'gp-premium' ),
'shortcuts' => array(
'layout' => 'generate_woocommerce_layout',
'typography' => 'generate_woocommerce_typography',
),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
'priority' => 0,
)
)
);
$wp_customize->add_control(
new GeneratePress_Title_Customize_Control(
$wp_customize,
'generate_woocommerce_button_title',
array(
'section' => 'generate_woocommerce_colors',
'type' => 'generatepress-customizer-title',
'title' => __( 'Buttons', 'gp-premium' ),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
)
)
);
$wp_customize->add_control(
new GeneratePress_Information_Customize_Control(
$wp_customize,
'generate_woocommerce_primary_button_message',
array(
'section' => 'generate_woocommerce_colors',
'label' => __( 'Primary Button Colors', 'gp-premium' ),
'description' => __( 'Primary button colors can be set <a href="#">here</a>.', 'gp-premium' ),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_alt_button_background]',
array(
'default' => $defaults['wc_alt_button_background'],
'type' => 'option',
'capability' => 'edit_theme_options',
'transport' => 'postMessage',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'generate_settings[wc_alt_button_background]',
array(
'label' => __( 'Alt Button Background', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_alt_button_background]',
'palette' => $palettes,
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_alt_button_background_hover]',
array(
'default' => $defaults['wc_alt_button_background_hover'],
'type' => 'option',
'capability' => 'edit_theme_options',
'transport' => 'postMessage',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'generate_settings[wc_alt_button_background_hover]',
array(
'label' => __( 'Alt Button Background Hover', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_alt_button_background_hover]',
'palette' => $palettes,
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_alt_button_text]',
array(
'default' => $defaults['wc_alt_button_text'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_alt_button_text]',
array(
'label' => __( 'Alt Button Text', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_alt_button_text]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_alt_button_text_hover]',
array(
'default' => $defaults['wc_alt_button_text_hover'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_alt_button_text_hover]',
array(
'label' => __( 'Alt Button Text Hover', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_alt_button_text_hover]',
)
)
);
$wp_customize->add_control(
new GeneratePress_Title_Customize_Control(
$wp_customize,
'generate_woocommerce_product_title',
array(
'section' => 'generate_woocommerce_colors',
'type' => 'generatepress-customizer-title',
'title' => __( 'Products', 'gp-premium' ),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_product_title_color]',
array(
'default' => $defaults['wc_product_title_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_product_title_color]',
array(
'label' => __( 'Product Title', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_product_title_color]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_product_title_color_hover]',
array(
'default' => $defaults['wc_product_title_color_hover'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_product_title_color_hover]',
array(
'label' => __( 'Product Title Hover', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_product_title_color_hover]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_rating_stars]',
array(
'default' => $defaults['wc_rating_stars'],
'type' => 'option',
'capability' => 'edit_theme_options',
'transport' => '',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'generate_settings[wc_rating_stars]',
array(
'label' => __( 'Star Ratings', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_rating_stars]',
'palette' => $palettes,
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_sale_sticker_background]',
array(
'default' => $defaults['wc_sale_sticker_background'],
'type' => 'option',
'capability' => 'edit_theme_options',
'transport' => 'postMessage',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'generate_settings[wc_sale_sticker_background]',
array(
'label' => __( 'Sale Sticker Background', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_sale_sticker_background]',
'palette' => $palettes,
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_sale_sticker_text]',
array(
'default' => $defaults['wc_sale_sticker_text'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_sale_sticker_text]',
array(
'label' => __( 'Sale Sticker Text', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_sale_sticker_text]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_price_color]',
array(
'default' => $defaults['wc_price_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_price_color]',
array(
'label' => __( 'Price', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_price_color]',
)
)
);
$wp_customize->add_control(
new GeneratePress_Title_Customize_Control(
$wp_customize,
'generate_woocommerce_panel_cart_title',
array(
'section' => 'generate_woocommerce_colors',
'type' => 'generatepress-customizer-title',
'title' => __( 'Sticky Panel Cart', 'gp-premium' ),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_panel_cart_background_color]',
array(
'default' => $defaults['wc_panel_cart_background_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'transport' => 'postMessage',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'generate_settings[wc_panel_cart_background_color]',
array(
'label' => __( 'Background Color', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_panel_cart_background_color]',
'palette' => $palettes,
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_panel_cart_text_color]',
array(
'default' => $defaults['wc_panel_cart_text_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_panel_cart_text_color]',
array(
'label' => __( 'Text Color', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_panel_cart_text_color]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_panel_cart_button_background]',
array(
'default' => $defaults['wc_panel_cart_button_background'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_panel_cart_button_background]',
array(
'label' => __( 'Button Background', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_panel_cart_button_background]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_panel_cart_button_background_hover]',
array(
'default' => $defaults['wc_panel_cart_button_background_hover'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_panel_cart_button_background_hover]',
array(
'label' => __( 'Button Background Hover', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_panel_cart_button_background_hover]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_panel_cart_button_text]',
array(
'default' => $defaults['wc_panel_cart_button_text'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_panel_cart_button_text]',
array(
'label' => __( 'Button Text', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_panel_cart_button_text]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_panel_cart_button_text_hover]',
array(
'default' => $defaults['wc_panel_cart_button_text_hover'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_panel_cart_button_text_hover]',
array(
'label' => __( 'Button Text Hover', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_panel_cart_button_text_hover]',
)
)
);
$wp_customize->add_control(
new GeneratePress_Title_Customize_Control(
$wp_customize,
'generate_woocommerce_mini_cart_title',
array(
'section' => 'generate_woocommerce_colors',
'type' => 'generatepress-customizer-title',
'title' => __( 'Menu Mini Cart', 'gp-premium' ),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_mini_cart_background_color]',
array(
'default' => $defaults['wc_mini_cart_background_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'transport' => 'postMessage',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'generate_settings[wc_mini_cart_background_color]',
array(
'label' => __( 'Cart Background Color', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_mini_cart_background_color]',
'palette' => $palettes,
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_mini_cart_text_color]',
array(
'default' => $defaults['wc_mini_cart_text_color'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_mini_cart_text_color]',
array(
'label' => __( 'Cart Text Color', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_mini_cart_text_color]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_mini_cart_button_background]',
array(
'default' => $defaults['wc_mini_cart_button_background'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_mini_cart_button_background]',
array(
'label' => __( 'Button Background', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_mini_cart_button_background]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_mini_cart_button_background_hover]',
array(
'default' => $defaults['wc_mini_cart_button_background_hover'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_mini_cart_button_background_hover]',
array(
'label' => __( 'Button Background Hover', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_mini_cart_button_background_hover]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_mini_cart_button_text]',
array(
'default' => $defaults['wc_mini_cart_button_text'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_mini_cart_button_text]',
array(
'label' => __( 'Button Text', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_mini_cart_button_text]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_mini_cart_button_text_hover]',
array(
'default' => $defaults['wc_mini_cart_button_text_hover'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_mini_cart_button_text_hover]',
array(
'label' => __( 'Button Text Hover', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_mini_cart_button_text_hover]',
)
)
);
$wp_customize->add_control(
new GeneratePress_Title_Customize_Control(
$wp_customize,
'generate_woocommerce_price_slider_title',
array(
'section' => 'generate_woocommerce_colors',
'type' => 'generatepress-customizer-title',
'title' => __( 'Price Slider Widget', 'gp-premium' ),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_price_slider_background_color]',
array(
'default' => $defaults['wc_price_slider_background_color'],
'type' => 'option',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_price_slider_background_color]',
array(
'label' => __( 'Slider Background Color', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_price_slider_background_color]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_price_slider_bar_color]',
array(
'default' => $defaults['wc_price_slider_bar_color'],
'type' => 'option',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_price_slider_bar_color]',
array(
'label' => __( 'Slider Bar Color', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_price_slider_bar_color]',
)
)
);
$wp_customize->add_control(
new GeneratePress_Title_Customize_Control(
$wp_customize,
'generate_woocommerce_product_tabs_title',
array(
'section' => 'generate_woocommerce_colors',
'type' => 'generatepress-customizer-title',
'title' => __( 'Product Tabs', 'gp-premium' ),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_product_tab]',
array(
'default' => $defaults['wc_product_tab'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_product_tab]',
array(
'label' => __( 'Product Tab Text', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_product_tab]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_product_tab_highlight]',
array(
'default' => $defaults['wc_product_tab_highlight'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_product_tab_highlight]',
array(
'label' => __( 'Product Tab Active', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_product_tab_highlight]',
)
)
);
$wp_customize->add_control(
new GeneratePress_Title_Customize_Control(
$wp_customize,
'generate_woocommerce_messages_title',
array(
'section' => 'generate_woocommerce_colors',
'type' => 'generatepress-customizer-title',
'title' => __( 'Messages', 'gp-premium' ),
'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_success_message_background]',
array(
'default' => $defaults['wc_success_message_background'],
'type' => 'option',
'capability' => 'edit_theme_options',
'transport' => 'postMessage',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'generate_settings[wc_success_message_background]',
array(
'label' => __( 'Success Message Background', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_success_message_background]',
'palette' => $palettes,
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_success_message_text]',
array(
'default' => $defaults['wc_success_message_text'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_success_message_text]',
array(
'label' => __( 'Success Message Text', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_success_message_text]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_info_message_background]',
array(
'default' => $defaults['wc_info_message_background'],
'type' => 'option',
'capability' => 'edit_theme_options',
'transport' => 'postMessage',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'generate_settings[wc_info_message_background]',
array(
'label' => __( 'Info Message Background', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_info_message_background]',
'palette' => $palettes,
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_info_message_text]',
array(
'default' => $defaults['wc_info_message_text'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_info_message_text]',
array(
'label' => __( 'Info Message Text', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_info_message_text]',
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_error_message_background]',
array(
'default' => $defaults['wc_error_message_background'],
'type' => 'option',
'capability' => 'edit_theme_options',
'transport' => 'postMessage',
'sanitize_callback' => 'generate_premium_sanitize_rgba',
)
);
$wp_customize->add_control(
new GeneratePress_Alpha_Color_Customize_Control(
$wp_customize,
'generate_settings[wc_error_message_background]',
array(
'label' => __( 'Error Message Background', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_error_message_background]',
'palette' => $palettes,
)
)
);
$wp_customize->add_setting(
'generate_settings[wc_error_message_text]',
array(
'default' => $defaults['wc_error_message_text'],
'type' => 'option',
'capability' => 'edit_theme_options',
'sanitize_callback' => 'generate_premium_sanitize_hex_color',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
'generate_settings[wc_error_message_text]',
array(
'label' => __( 'Error Message Text', 'gp-premium' ),
'section' => 'generate_woocommerce_colors',
'settings' => 'generate_settings[wc_error_message_text]',
)
)
);
}
}

View File

@ -0,0 +1,20 @@
<?php
/**
* The Colors module.
*
* @since 1.1.0
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
// Define the version. This used to be a standalone plugin, so we need to keep this constant.
if ( ! defined( 'GENERATE_COLORS_VERSION' ) ) {
define( 'GENERATE_COLORS_VERSION', GP_PREMIUM_VERSION );
}
// Include functions identical between standalone addon and GP Premium.
require plugin_dir_path( __FILE__ ) . 'functions/functions.php';

View File

@ -0,0 +1,223 @@
<?php
/**
* This file handles the Copyright functionality.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
if ( ! function_exists( 'generate_copyright_customize_register' ) ) {
add_action( 'customize_register', 'generate_copyright_customize_register' );
/**
* Add our copyright options to the Customizer.
*
* @param object $wp_customize The Customizer object.
*/
function generate_copyright_customize_register( $wp_customize ) {
// Get our custom control.
require_once GP_LIBRARY_DIRECTORY . 'customizer-helpers.php';
// Register our custom control.
if ( method_exists( $wp_customize, 'register_control_type' ) ) {
$wp_customize->register_control_type( 'GeneratePress_Copyright_Customize_Control' );
}
$wp_customize->add_setting(
'generate_copyright',
array(
'default' => '',
'type' => 'theme_mod',
'sanitize_callback' => 'wp_kses_post',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new GeneratePress_Copyright_Customize_Control(
$wp_customize,
'generate_copyright',
array(
'label' => __( 'Copyright', 'gp-premium' ),
'section' => 'generate_layout_footer',
'settings' => 'generate_copyright',
'priority' => 500,
)
)
);
// Initiate selective refresh.
if ( isset( $wp_customize->selective_refresh ) ) {
$wp_customize->selective_refresh->add_partial(
'generate_copyright',
array(
'selector' => '.copyright-bar',
'settings' => array( 'generate_copyright' ),
'render_callback' => 'generate_copyright_selective_refresh',
)
);
}
}
}
if ( ! function_exists( 'generate_copyright_selective_refresh' ) ) {
/**
* Return our copyright on selective refresh
*/
function generate_copyright_selective_refresh() {
$options = array(
'%current_year%',
'%copy%',
);
$replace = array(
date( 'Y' ), // phpcs:ignore -- prefer date().
'&copy;',
);
$new_copyright = get_theme_mod( 'generate_copyright' );
$new_copyright = str_replace( $options, $replace, get_theme_mod( 'generate_copyright' ) );
return do_shortcode( $new_copyright );
}
}
if ( ! function_exists( 'generate_copyright_remove_default' ) ) {
add_action( 'wp', 'generate_copyright_remove_default' );
/**
* Remove the default copyright.
*
* @since 0.1
* @deprecated GP 1.3.42
*/
function generate_copyright_remove_default() {
// As of 1.3.42, we no longer need to do this.
// We use a nice little filter instead.
if ( ! function_exists( 'generate_add_login_attribution' ) ) {
return;
}
if ( get_theme_mod( 'generate_copyright' ) && '' !== get_theme_mod( 'generate_copyright' ) ) {
remove_action( 'generate_credits', 'generate_add_footer_info' );
remove_action( 'generate_copyright_line', 'generate_add_login_attribution' );
}
}
}
if ( ! function_exists( 'generate_copyright_add_custom' ) ) {
add_action( 'generate_credits', 'generate_copyright_add_custom' );
/**
* Add the custom copyright.
*
* @since 0.1
* @deprecated GP 1.3.42
*/
function generate_copyright_add_custom() {
// As of 1.3.42, we no longer need to do this.
// We use a nice little filter instead.
if ( ! function_exists( 'generate_add_login_attribution' ) ) {
return;
}
$options = array(
'%current_year%',
'%copy%',
);
$replace = array(
date( 'Y' ), // phpcs:ignore -- prefer date().
'&copy;',
);
$new_copyright = get_theme_mod( 'generate_copyright' );
$new_copyright = str_replace( $options, $replace, get_theme_mod( 'generate_copyright' ) );
if ( get_theme_mod( 'generate_copyright' ) && '' !== get_theme_mod( 'generate_copyright' ) ) {
echo do_shortcode( $new_copyright );
}
}
}
if ( ! function_exists( 'generate_apply_custom_copyright' ) ) {
add_filter( 'generate_copyright', 'generate_apply_custom_copyright' );
/**
* Add the custom copyright
*
* @since 1.2.92
* @param string $copyright The copyright value.
*/
function generate_apply_custom_copyright( $copyright ) {
// This will only work if GP >= 1.3.42 and the below function doesn't exist.
if ( function_exists( 'generate_add_login_attribution' ) ) {
return;
}
$options = array(
'%current_year%',
'%copy%',
);
$replace = array(
date( 'Y' ), // phpcs:ignore -- prefer date().
'&copy;',
);
$new_copyright = get_theme_mod( 'generate_copyright' );
$new_copyright = str_replace( $options, $replace, get_theme_mod( 'generate_copyright' ) );
if ( get_theme_mod( 'generate_copyright' ) && '' !== get_theme_mod( 'generate_copyright' ) ) {
return do_shortcode( $new_copyright );
}
return $copyright;
}
}
if ( ! function_exists( 'generate_copyright_customizer_live_preview' ) ) {
add_action( 'customize_preview_init', 'generate_copyright_customizer_live_preview' );
/**
* Add our live preview
*/
function generate_copyright_customizer_live_preview() {
wp_enqueue_script(
'generate-copyright-customizer',
plugin_dir_url( __FILE__ ) . 'js/customizer.js',
array( 'jquery', 'customize-preview' ),
GENERATE_COPYRIGHT_VERSION,
true
);
}
}
if ( ! function_exists( 'generate_update_copyright' ) ) {
add_action( 'admin_init', 'generate_update_copyright' );
/**
* Our copyright use to have it's own setting
* If we have the old setting, move it into our theme_mod
*/
function generate_update_copyright() {
// If we already have a custom logo, bail.
if ( get_theme_mod( 'generate_copyright' ) ) {
return;
}
// Get the old logo value.
$old_value = get_option( 'gen_custom_copyright' );
// If there's no old value, bail.
if ( empty( $old_value ) ) {
return;
}
// Now let's update the new logo setting with our ID.
set_theme_mod( 'generate_copyright', $old_value );
// Got our custom logo? Time to delete the old value.
if ( get_theme_mod( 'generate_copyright' ) ) {
delete_option( 'gen_custom_copyright' );
}
}
}

View File

@ -0,0 +1,18 @@
/**
* Theme Customizer enhancements for a better user experience.
*
* Contains handlers to make Theme Customizer preview reload changes asynchronously.
*/
( function( $ ) {
// Update the site title in real time...
wp.customize( 'generate_copyright', function( value ) {
value.bind( function( newval ) {
if ( $( '.copyright-bar' ).length ) {
$( '.copyright-bar' ).html( newval );
} else {
$( '.inside-site-info' ).html( newval );
}
} );
} );
}( jQuery ) );

View File

@ -0,0 +1,20 @@
<?php
/**
* The Copyright module.
*
* @since 1.0.0
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
// Define the version.
if ( ! defined( 'GENERATE_COPYRIGHT_VERSION' ) ) {
define( 'GENERATE_COPYRIGHT_VERSION', GP_PREMIUM_VERSION );
}
// Include functions identical between standalone addon and GP Premium.
require plugin_dir_path( __FILE__ ) . 'functions/functions.php';

View File

@ -0,0 +1,422 @@
<?php
/**
* This file handles the Disable Elements functionality.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
define( 'GENERATE_DE_LAYOUT_META_BOX', true );
if ( ! function_exists( 'generate_disable_elements' ) ) {
/**
* Remove the default disable_elements.
*
* @since 0.1
*/
function generate_disable_elements() {
// Don't run the function unless we're on a page it applies to.
if ( ! is_singular() ) {
return '';
}
global $post;
// Prevent PHP notices.
if ( isset( $post ) ) {
$disable_header = get_post_meta( $post->ID, '_generate-disable-header', true );
$disable_nav = get_post_meta( $post->ID, '_generate-disable-nav', true );
$disable_secondary_nav = get_post_meta( $post->ID, '_generate-disable-secondary-nav', true );
$disable_post_image = get_post_meta( $post->ID, '_generate-disable-post-image', true );
$disable_headline = get_post_meta( $post->ID, '_generate-disable-headline', true );
$disable_footer = get_post_meta( $post->ID, '_generate-disable-footer', true );
}
$return = '';
if ( ! empty( $disable_header ) && false !== $disable_header ) {
$return = '.site-header {display:none}';
}
if ( ! empty( $disable_nav ) && false !== $disable_nav ) {
$return .= '#site-navigation,.navigation-clone, #mobile-header {display:none !important}';
}
if ( ! empty( $disable_secondary_nav ) && false !== $disable_secondary_nav ) {
$return .= '#secondary-navigation {display:none}';
}
if ( ! empty( $disable_post_image ) && false !== $disable_post_image ) {
$return .= '.generate-page-header, .page-header-image, .page-header-image-single {display:none}';
}
$need_css_removal = true;
if ( defined( 'GENERATE_VERSION' ) && version_compare( GENERATE_VERSION, '3.0.0-alpha.1', '>=' ) ) {
$need_css_removal = false;
}
if ( $need_css_removal && ! empty( $disable_headline ) && false !== $disable_headline && ! is_single() ) {
$return .= '.entry-header {display:none} .page-content, .entry-content, .entry-summary {margin-top:0}';
}
if ( ! empty( $disable_footer ) && false !== $disable_footer ) {
$return .= '.site-footer {display:none}';
}
return $return;
}
}
if ( ! function_exists( 'generate_de_scripts' ) ) {
add_action( 'wp_enqueue_scripts', 'generate_de_scripts', 50 );
/**
* Enqueue scripts and styles
*/
function generate_de_scripts() {
wp_add_inline_style( 'generate-style', generate_disable_elements() );
}
}
if ( ! function_exists( 'generate_add_de_meta_box' ) ) {
add_action( 'add_meta_boxes', 'generate_add_de_meta_box', 50 );
/**
* Generate the layout metabox.
*
* @since 0.1
*/
function generate_add_de_meta_box() {
// Set user role - make filterable.
$allowed = apply_filters( 'generate_metabox_capability', 'edit_theme_options' );
// If not an administrator, don't show the metabox.
if ( ! current_user_can( $allowed ) ) {
return;
}
if ( defined( 'GENERATE_LAYOUT_META_BOX' ) ) {
return;
}
$args = array( 'public' => true );
$post_types = get_post_types( $args );
foreach ( $post_types as $type ) {
if ( 'attachment' !== $type ) {
add_meta_box(
'generate_de_meta_box',
__( 'Disable Elements', 'gp-premium' ),
'generate_show_de_meta_box',
$type,
'side',
'default'
);
}
}
}
}
if ( ! function_exists( 'generate_show_de_meta_box' ) ) {
/**
* Outputs the content of the metabox.
*
* @param object $post The post object.
*/
function generate_show_de_meta_box( $post ) {
wp_nonce_field( basename( __FILE__ ), 'generate_de_nonce' );
$stored_meta = get_post_meta( $post->ID );
$stored_meta['_generate-disable-header'][0] = ( isset( $stored_meta['_generate-disable-header'][0] ) ) ? $stored_meta['_generate-disable-header'][0] : '';
$stored_meta['_generate-disable-nav'][0] = ( isset( $stored_meta['_generate-disable-nav'][0] ) ) ? $stored_meta['_generate-disable-nav'][0] : '';
$stored_meta['_generate-disable-secondary-nav'][0] = ( isset( $stored_meta['_generate-disable-secondary-nav'][0] ) ) ? $stored_meta['_generate-disable-secondary-nav'][0] : '';
$stored_meta['_generate-disable-post-image'][0] = ( isset( $stored_meta['_generate-disable-post-image'][0] ) ) ? $stored_meta['_generate-disable-post-image'][0] : '';
$stored_meta['_generate-disable-headline'][0] = ( isset( $stored_meta['_generate-disable-headline'][0] ) ) ? $stored_meta['_generate-disable-headline'][0] : '';
$stored_meta['_generate-disable-footer'][0] = ( isset( $stored_meta['_generate-disable-footer'][0] ) ) ? $stored_meta['_generate-disable-footer'][0] : '';
$stored_meta['_generate-disable-top-bar'][0] = ( isset( $stored_meta['_generate-disable-top-bar'][0] ) ) ? $stored_meta['_generate-disable-top-bar'][0] : '';
?>
<p>
<div class="generate_disable_elements">
<?php if ( function_exists( 'generate_top_bar' ) ) : ?>
<label for="meta-generate-disable-top-bar" style="display:block;margin-bottom:3px;" title="<?php _e( 'Top Bar', 'gp-premium' ); ?>">
<input type="checkbox" name="_generate-disable-top-bar" id="meta-generate-disable-top-bar" value="true" <?php checked( $stored_meta['_generate-disable-top-bar'][0], 'true' ); ?>>
<?php _e( 'Top Bar', 'gp-premium' ); ?>
</label>
<?php endif; ?>
<label for="meta-generate-disable-header" style="display:block;margin-bottom:3px;" title="<?php _e( 'Header', 'gp-premium' ); ?>">
<input type="checkbox" name="_generate-disable-header" id="meta-generate-disable-header" value="true" <?php checked( $stored_meta['_generate-disable-header'][0], 'true' ); ?>>
<?php _e( 'Header', 'gp-premium' ); ?>
</label>
<label for="meta-generate-disable-nav" style="display:block;margin-bottom:3px;" title="<?php _e( 'Primary Navigation', 'gp-premium' ); ?>">
<input type="checkbox" name="_generate-disable-nav" id="meta-generate-disable-nav" value="true" <?php checked( $stored_meta['_generate-disable-nav'][0], 'true' ); ?>>
<?php _e( 'Primary Navigation', 'gp-premium' ); ?>
</label>
<?php if ( function_exists( 'generate_secondary_nav_setup' ) ) : ?>
<label for="meta-generate-disable-secondary-nav" style="display:block;margin-bottom:3px;" title="<?php _e( 'Secondary Navigation', 'gp-premium' ); ?>">
<input type="checkbox" name="_generate-disable-secondary-nav" id="meta-generate-disable-secondary-nav" value="true" <?php checked( $stored_meta['_generate-disable-secondary-nav'][0], 'true' ); ?>>
<?php _e( 'Secondary Navigation', 'gp-premium' ); ?>
</label>
<?php endif; ?>
<label for="meta-generate-disable-post-image" style="display:block;margin-bottom:3px;" title="<?php _e( 'Featured Image', 'gp-premium' ); ?>">
<input type="checkbox" name="_generate-disable-post-image" id="meta-generate-disable-post-image" value="true" <?php checked( $stored_meta['_generate-disable-post-image'][0], 'true' ); ?>>
<?php _e( 'Featured Image', 'gp-premium' ); ?>
</label>
<label for="meta-generate-disable-headline" style="display:block;margin-bottom:3px;" title="<?php _e( 'Content Title', 'gp-premium' ); ?>">
<input type="checkbox" name="_generate-disable-headline" id="meta-generate-disable-headline" value="true" <?php checked( $stored_meta['_generate-disable-headline'][0], 'true' ); ?>>
<?php _e( 'Content Title', 'gp-premium' ); ?>
</label>
<label for="meta-generate-disable-footer" style="display:block;margin-bottom:3px;" title="<?php _e( 'Footer', 'gp-premium' ); ?>">
<input type="checkbox" name="_generate-disable-footer" id="meta-generate-disable-footer" value="true" <?php checked( $stored_meta['_generate-disable-footer'][0], 'true' ); ?>>
<?php _e( 'Footer', 'gp-premium' ); ?>
</label>
</div>
</p>
<?php
}
}
if ( ! function_exists( 'generate_save_de_meta' ) ) {
add_action( 'save_post', 'generate_save_de_meta' );
/**
* Save our options.
*
* @param int $post_id The post ID.
*/
function generate_save_de_meta( $post_id ) {
if ( defined( 'GENERATE_LAYOUT_META_BOX' ) ) {
return;
}
// Checks save status.
$is_autosave = wp_is_post_autosave( $post_id );
$is_revision = wp_is_post_revision( $post_id );
$is_valid_nonce = ( isset( $_POST['generate_de_nonce'] ) && wp_verify_nonce( $_POST['generate_de_nonce'], basename( __FILE__ ) ) ) ? true : false;
// Exits script depending on save status.
if ( $is_autosave || $is_revision || ! $is_valid_nonce ) {
return;
}
// Check that the logged in user has permission to edit this post.
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return $post_id;
}
$options = array(
'_generate-disable-top-bar',
'_generate-disable-header',
'_generate-disable-nav',
'_generate-disable-secondary-nav',
'_generate-disable-headline',
'_generate-disable-footer',
'_generate-disable-post-image',
);
foreach ( $options as $key ) {
$value = filter_input( INPUT_POST, $key, FILTER_SANITIZE_STRING );
if ( $value ) {
update_post_meta( $post_id, $key, $value );
} else {
delete_post_meta( $post_id, $key );
}
}
}
}
if ( ! function_exists( 'generate_disable_elements_setup' ) ) {
add_action( 'wp', 'generate_disable_elements_setup', 50 );
/**
* Disable the things.
*/
function generate_disable_elements_setup() {
// Don't run the function unless we're on a page it applies to.
if ( ! is_singular() ) {
return;
}
// Get the current post.
global $post;
// Grab our values.
if ( isset( $post ) ) {
$disable_top_bar = get_post_meta( $post->ID, '_generate-disable-top-bar', true );
$disable_header = get_post_meta( $post->ID, '_generate-disable-header', true );
$disable_mobile_header = get_post_meta( $post->ID, '_generate-disable-mobile-header', true );
$disable_nav = get_post_meta( $post->ID, '_generate-disable-nav', true );
$disable_headline = get_post_meta( $post->ID, '_generate-disable-headline', true );
$disable_footer = get_post_meta( $post->ID, '_generate-disable-footer', true );
}
// Remove the top bar.
if ( ! empty( $disable_top_bar ) && false !== $disable_top_bar && function_exists( 'generate_top_bar' ) ) {
remove_action( 'generate_before_header', 'generate_top_bar', 5 );
remove_action( 'generate_inside_secondary_navigation', 'generate_secondary_nav_top_bar_widget', 5 );
}
// Remove the header.
if ( ! empty( $disable_header ) && false !== $disable_header && function_exists( 'generate_construct_header' ) ) {
remove_action( 'generate_header', 'generate_construct_header' );
}
// Remove the mobile header.
if ( ! empty( $disable_mobile_header ) && false !== $disable_mobile_header && function_exists( 'generate_menu_plus_mobile_header' ) ) {
remove_action( 'generate_after_header', 'generate_menu_plus_mobile_header', 5 );
}
// Remove the navigation.
if ( ! empty( $disable_nav ) && false !== $disable_nav && function_exists( 'generate_get_navigation_location' ) ) {
add_filter( 'generate_navigation_location', '__return_false', 20 );
add_filter( 'generate_disable_mobile_header_menu', '__return_true' );
}
// Remove the title.
if ( ! empty( $disable_headline ) && false !== $disable_headline && function_exists( 'generate_show_title' ) ) {
add_filter( 'generate_show_title', '__return_false' );
}
// Remove the footer.
if ( ! empty( $disable_footer ) && false !== $disable_footer ) {
if ( function_exists( 'generate_construct_footer_widgets' ) ) {
remove_action( 'generate_footer', 'generate_construct_footer_widgets', 5 );
}
if ( function_exists( 'generate_construct_footer' ) ) {
remove_action( 'generate_footer', 'generate_construct_footer' );
}
}
}
}
add_action( 'generate_layout_disable_elements_section', 'generate_premium_disable_elements_options' );
/**
* Add the meta box options to the Layout meta box in the new GP
*
* @since 1.4
* @param array $stored_meta Existing meta data.
*/
function generate_premium_disable_elements_options( $stored_meta ) {
$stored_meta['_generate-disable-header'][0] = ( isset( $stored_meta['_generate-disable-header'][0] ) ) ? $stored_meta['_generate-disable-header'][0] : '';
$stored_meta['_generate-disable-mobile-header'][0] = ( isset( $stored_meta['_generate-disable-mobile-header'][0] ) ) ? $stored_meta['_generate-disable-mobile-header'][0] : '';
$stored_meta['_generate-disable-nav'][0] = ( isset( $stored_meta['_generate-disable-nav'][0] ) ) ? $stored_meta['_generate-disable-nav'][0] : '';
$stored_meta['_generate-disable-secondary-nav'][0] = ( isset( $stored_meta['_generate-disable-secondary-nav'][0] ) ) ? $stored_meta['_generate-disable-secondary-nav'][0] : '';
$stored_meta['_generate-disable-post-image'][0] = ( isset( $stored_meta['_generate-disable-post-image'][0] ) ) ? $stored_meta['_generate-disable-post-image'][0] : '';
$stored_meta['_generate-disable-headline'][0] = ( isset( $stored_meta['_generate-disable-headline'][0] ) ) ? $stored_meta['_generate-disable-headline'][0] : '';
$stored_meta['_generate-disable-footer'][0] = ( isset( $stored_meta['_generate-disable-footer'][0] ) ) ? $stored_meta['_generate-disable-footer'][0] : '';
$stored_meta['_generate-disable-top-bar'][0] = ( isset( $stored_meta['_generate-disable-top-bar'][0] ) ) ? $stored_meta['_generate-disable-top-bar'][0] : '';
?>
<div class="generate_disable_elements">
<?php if ( function_exists( 'generate_top_bar' ) ) : ?>
<label for="meta-generate-disable-top-bar" style="display:block;margin-bottom:3px;" title="<?php _e( 'Top Bar', 'gp-premium' ); ?>">
<input type="checkbox" name="_generate-disable-top-bar" id="meta-generate-disable-top-bar" value="true" <?php checked( $stored_meta['_generate-disable-top-bar'][0], 'true' ); ?>>
<?php _e( 'Top Bar', 'gp-premium' ); ?>
</label>
<?php endif; ?>
<label for="meta-generate-disable-header" style="display:block;margin-bottom:3px;" title="<?php _e( 'Header', 'gp-premium' ); ?>">
<input type="checkbox" name="_generate-disable-header" id="meta-generate-disable-header" value="true" <?php checked( $stored_meta['_generate-disable-header'][0], 'true' ); ?>>
<?php _e( 'Header', 'gp-premium' ); ?>
</label>
<?php
if ( function_exists( 'generate_menu_plus_get_defaults' ) ) :
$menu_plus_settings = wp_parse_args(
get_option( 'generate_menu_plus_settings', array() ),
generate_menu_plus_get_defaults()
);
if ( 'enable' === $menu_plus_settings['mobile_header'] ) :
?>
<label for="meta-generate-disable-mobile-header" style="display:block;margin-bottom:3px;" title="<?php esc_attr_e( 'Mobile Header', 'gp-premium' ); ?>">
<input type="checkbox" name="_generate-disable-mobile-header" id="meta-generate-disable-mobile-header" value="true" <?php checked( $stored_meta['_generate-disable-mobile-header'][0], 'true' ); ?>>
<?php esc_html_e( 'Mobile Header', 'gp-premium' ); ?>
</label>
<?php
endif;
endif;
?>
<label for="meta-generate-disable-nav" style="display:block;margin-bottom:3px;" title="<?php _e( 'Primary Navigation', 'gp-premium' ); ?>">
<input type="checkbox" name="_generate-disable-nav" id="meta-generate-disable-nav" value="true" <?php checked( $stored_meta['_generate-disable-nav'][0], 'true' ); ?>>
<?php _e( 'Primary Navigation', 'gp-premium' ); ?>
</label>
<?php if ( function_exists( 'generate_secondary_nav_setup' ) ) : ?>
<label for="meta-generate-disable-secondary-nav" style="display:block;margin-bottom:3px;" title="<?php _e( 'Secondary Navigation', 'gp-premium' ); ?>">
<input type="checkbox" name="_generate-disable-secondary-nav" id="meta-generate-disable-secondary-nav" value="true" <?php checked( $stored_meta['_generate-disable-secondary-nav'][0], 'true' ); ?>>
<?php _e( 'Secondary Navigation', 'gp-premium' ); ?>
</label>
<?php endif; ?>
<label for="meta-generate-disable-post-image" style="display:block;margin-bottom:3px;" title="<?php _e( 'Featured Image', 'gp-premium' ); ?>">
<input type="checkbox" name="_generate-disable-post-image" id="meta-generate-disable-post-image" value="true" <?php checked( $stored_meta['_generate-disable-post-image'][0], 'true' ); ?>>
<?php _e( 'Featured Image', 'gp-premium' ); ?>
</label>
<label for="meta-generate-disable-headline" style="display:block;margin-bottom:3px;" title="<?php _e( 'Content Title', 'gp-premium' ); ?>">
<input type="checkbox" name="_generate-disable-headline" id="meta-generate-disable-headline" value="true" <?php checked( $stored_meta['_generate-disable-headline'][0], 'true' ); ?>>
<?php _e( 'Content Title', 'gp-premium' ); ?>
</label>
<label for="meta-generate-disable-footer" style="display:block;margin-bottom:3px;" title="<?php _e( 'Footer', 'gp-premium' ); ?>">
<input type="checkbox" name="_generate-disable-footer" id="meta-generate-disable-footer" value="true" <?php checked( $stored_meta['_generate-disable-footer'][0], 'true' ); ?>>
<?php _e( 'Footer', 'gp-premium' ); ?>
</label>
</div>
<?php
}
add_action( 'generate_layout_meta_box_save', 'generate_premium_save_disable_elements_meta' );
/**
* Save the Disable Elements meta box values
*
* @since 1.4
* @param int $post_id The post ID.
*/
function generate_premium_save_disable_elements_meta( $post_id ) {
$options = array(
'_generate-disable-top-bar',
'_generate-disable-header',
'_generate-disable-mobile-header',
'_generate-disable-nav',
'_generate-disable-secondary-nav',
'_generate-disable-headline',
'_generate-disable-footer',
'_generate-disable-post-image',
);
foreach ( $options as $key ) {
$value = filter_input( INPUT_POST, $key, FILTER_SANITIZE_STRING );
if ( $value ) {
update_post_meta( $post_id, $key, $value );
} else {
delete_post_meta( $post_id, $key );
}
}
}
add_filter( 'body_class', 'generate_disable_elements_body_classes', 20 );
/**
* Remove body classes if certain elements are disabled.
*
* @since 2.1.0
* @param array $classes Our body classes.
*/
function generate_disable_elements_body_classes( $classes ) {
if ( is_singular() ) {
$disable_featured_image = get_post_meta( get_the_ID(), '_generate-disable-post-image', true );
$classes = generate_premium_remove_featured_image_class( $classes, $disable_featured_image );
}
return $classes;
}

View File

@ -0,0 +1,20 @@
<?php
/**
* The Disable Elements module.
*
* @since 1.0.0
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
// Define the version.
if ( ! defined( 'GENERATE_DE_VERSION' ) ) {
define( 'GENERATE_DE_VERSION', GP_PREMIUM_VERSION );
}
// Include functions identical between standalone addon and GP Premium.
require plugin_dir_path( __FILE__ ) . 'functions/functions.php';

View File

@ -0,0 +1 @@
<?php return array('dependencies' => array('lodash', 'react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-dom-ready', 'wp-edit-post', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-plugins', 'wp-server-side-render'), 'version' => 'cfd31bf4ecfacfe73c45');

View File

@ -0,0 +1,6 @@
.inline-post-meta-area.block-editor-block-list__layout,.inline-post-meta-area>.gb-inside-container.block-editor-block-list__layout,.inline-post-meta-area>.gb-inside-container>.block-editor-inner-blocks>.block-editor-block-list__layout{align-items:center;display:flex}.inline-post-meta-area.block-editor-block-list__layout>.wp-block.block-list-appender,.inline-post-meta-area>.gb-inside-container.block-editor-block-list__layout>.wp-block.block-list-appender,.inline-post-meta-area>.gb-inside-container>.block-editor-inner-blocks>.block-editor-block-list__layout>.wp-block.block-list-appender{margin-left:20px}.inline-post-meta-area.block-editor-block-list__layout>.wp-block-image,.inline-post-meta-area>.gb-inside-container.block-editor-block-list__layout>.wp-block-image,.inline-post-meta-area>.gb-inside-container>.block-editor-inner-blocks>.block-editor-block-list__layout>.wp-block-image{line-height:0}.inline-post-meta-area.block-editor-block-list__layout>.wp-block-image figcaption,.inline-post-meta-area>.gb-inside-container.block-editor-block-list__layout>.wp-block-image figcaption,.inline-post-meta-area>.gb-inside-container>.block-editor-inner-blocks>.block-editor-block-list__layout>.wp-block-image figcaption{display:none}.inline-post-meta-area .wp-block{margin-left:0;margin-right:0}.gpp-dynamic-container-bg-dropdown .components-popover__content{width:275px}.gpp-dynamic-container-bg-dropdown .components-popover__content .components-base-control:not(:last-child){margin-bottom:20px}.gpp-dynamic-container-bg-dropdown .components-popover__content .components-base-control:last-child .components-base-control__field{margin-bottom:0}.gpp-dynamic-container-bg-dropdown .components-popover__content .components-base-control:last-child .components-base-control__help{margin-top:3px}
.gpp-dynamic-headline-text-dropdown .components-popover__content{width:275px}.gpp-dynamic-headline-text-dropdown .components-popover__content .components-base-control:not(:last-child){margin-bottom:20px}.gpp-dynamic-headline-text-dropdown .components-popover__content .components-base-control:last-child .components-base-control__field{margin-bottom:0}.gpp-dynamic-headline-text-dropdown .components-popover__content .components-base-control:last-child .components-base-control__help{margin-top:3px}.gpp-blocks-dynamic-text-replace-field{display:none}.gpp-block-dynamic-year .components-base-control__help{margin-top:2px}
.wp-block[data-type="generatepress/dynamic-content"]{margin-bottom:0;margin-top:0}
.wp-block[data-type="generatepress/dynamic-image"]{color:#fff;margin-bottom:0;margin-top:0}.wp-block[data-type="generatepress/dynamic-image"] .components-gpp-dynamic-image-placeholder__label{align-items:center;bottom:0;color:#fff;display:flex;font-size:1em;justify-content:center;left:0;position:absolute;right:0;top:0}.wp-block[data-type="generatepress/dynamic-image"] .components-gpp-dynamic-image-placeholder__label>.gpp-dynamic-featured-image__label{margin-left:10px}.wp-block[data-type="generatepress/dynamic-image"] .gpp-dynamic-image-placeholder{background:#000;vertical-align:middle}.wp-block[data-type="generatepress/dynamic-image"] .components-placeholder{width:100%}.wp-block[data-type="generatepress/dynamic-image"] .gpp-dynamic-image-preview{display:inline-block;position:relative}.wp-block[data-type="generatepress/dynamic-image"] .dynamic-author-image-rounded{border-radius:100%}
.components-generatepress-units-control-header__units{align-items:center;display:flex;justify-content:space-between;margin-bottom:5px}.components-generatepress-control__units .components-generatepress-control-buttons__units button.components-button{background:#fff;border:0;border-radius:0!important;box-shadow:none!important;color:#929da7;font-size:10px;height:auto;line-height:20px;padding:0 5px;position:relative;text-align:center;text-shadow:none}.components-generatepress-control__units .components-generatepress-control-buttons__units button.components-button.is-primary{background:#fff!important;color:#000!important;cursor:default;font-weight:700;z-index:1}
.editor-styles-wrapper .is-root-container>.wp-block{margin-left:auto;margin-right:auto;max-width:var(--gp-block-element-width)}.left-sidebar-block-type div:not(.block-editor-inner-blocks)>.block-editor-block-list__layout,.right-sidebar-block-type div:not(.block-editor-inner-blocks)>.block-editor-block-list__layout{padding:10px}.gpp-block-element-panel>.components-base-control{margin-bottom:20px}.gpp-block-element-panel .components-notice,.gpp-block-element-panel .components-notice .components-notice__content{margin:0}.gpp-element-panel-label .components-panel__body-toggle.components-button{display:flex;flex-direction:row-reverse;justify-content:flex-end}.gpp-element-panel-label .components-panel__body-toggle.components-button svg.components-panel__icon{margin:0 10px 0 0}button.gpp-block-elements-template-button{background:#fff;border:1px solid #ddd;border-radius:5px;cursor:pointer;margin:0 0 10px;padding:5px}button.gpp-block-elements-template-button:hover{border-color:var(--wp-admin-theme-color)}button.gpp-block-elements-template-button .gpp-block-template-label{color:#888;font-size:13px;padding:5px}.element-has-parent #generate_premium_elements{display:none}.gpp-block-element-template-panel{background:#fafafa}.gpp-hook-select .gpp-block-element-search-select{position:relative;width:100%}.gpp-hook-select .components-text-control__input{background:#fff url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23555%22%2F%3E%3C%2Fsvg%3E") no-repeat right 5px top 55%;background-size:13px 13px;position:relative;z-index:1}.gpp-hook-select .select-search__select{background:#fff;border:1px solid #ddd}.gpp-hook-select .select-search__options{list-style:none}.gpp-hook-select .select-search__row:not(:first-child){border-top:1px solid #eee}.gpp-hook-select .select-search__row{margin:0}.gpp-hook-select .select-search__not-found,.gpp-hook-select .select-search__option{background:#fff;border:none;cursor:pointer;display:block;height:36px;margin:0;outline:none;padding:0 10px;text-align:left;width:100%}.gpp-hook-select .select-search__option.select-search__is-selected{background:#007cba;color:#fff}.gpp-hook-select .select-search__option.select-search__is-highlighted,.gpp-hook-select .select-search__option:not(.select-search__is-selected):hover{background:#fafafa}.gpp-hook-select .select-search__option.select-search__is-highlighted.select-search__is-selected,.gpp-hook-select .select-search__option.select-search__is-selected:hover{background:#007cba;color:#fff}.gpp-hook-select .select-search__group-header{background:#eee;font-size:10px;padding:8px 10px;text-transform:uppercase}.gpp-hook-select .gpp-block-element-search-select.is-disabled{opacity:.5}.gpp-hook-select .gpp-block-element-search-select.is-loading .select-search__value:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2750%27 height=%2750%27%3E%3Cpath fill=%27%232F2D37%27 d=%27M25 5a20.14 20.14 0 0 1 20 17.88 2.51 2.51 0 0 0 2.49 2.26A2.52 2.52 0 0 0 50 22.33a25.14 25.14 0 0 0-50 0 2.52 2.52 0 0 0 2.5 2.81A2.51 2.51 0 0 0 5 22.88 20.14 20.14 0 0 1 25 5Z%27%3E%3CanimateTransform attributeName=%27transform%27 type=%27rotate%27 from=%270 25 25%27 to=%27360 25 25%27 dur=%270.6s%27 repeatCount=%27indefinite%27/%3E%3C/path%3E%3C/svg%3E");background-size:11px}.gpp-hook-select .gpp-block-element-search-select:not(.is-disabled) .select-search__input{cursor:pointer}.gpp-hook-select .gpp-block-element-search-select:not(.select-search--multiple) .select-search__select{border-radius:3px;left:0;max-height:360px;overflow:auto;position:absolute;right:0;top:35px;z-index:2}.gpp-hook-select .select-search__not-found{color:#888;height:auto;padding:16px;text-align:center}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<?php return array('dependencies' => array('wp-hooks', 'wp-i18n'), 'version' => '71ce575bd9a3b2ae77bd');

View File

@ -0,0 +1 @@
!function(){"use strict";function e(o){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e(o)}function o(o,r,t){return(r=function(o){var r=function(o,r){if("object"!==e(o)||null===o)return o;var t=o[Symbol.toPrimitive];if(void 0!==t){var n=t.call(o,"string");if("object"!==e(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(o)}(o);return"symbol"===e(r)?r:String(r)}(r))in o?Object.defineProperty(o,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):o[r]=t,o}var r=window.wp.hooks,t=window.wp.i18n;function n(e,o){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);o&&(t=t.filter((function(o){return Object.getOwnPropertyDescriptor(e,o).enumerable}))),r.push.apply(r,t)}return r}function a(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?n(Object(t),!0).forEach((function(r){o(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):n(Object(t)).forEach((function(o){Object.defineProperty(e,o,Object.getOwnPropertyDescriptor(t,o))}))}return e}(0,r.addFilter)("generate_typography_element_groups","generatepress-pro/customizer/add-typography-groups",(function(e){var o={};return gpCustomizerControls.hasSecondaryNav&&(o.secondaryNavigation=(0,t.__)("Secondary Navigation","gp-premium")),gpCustomizerControls.hasMenuPlus&&(o.offCanvasPanel=(0,t.__)("Off-Canvas Panel","gp-premium")),gpCustomizerControls.hasWooCommerce&&(o.wooCommerce=(0,t.__)("WooCommerce","gp-premium")),a(a({},e),o)})),(0,r.addFilter)("generate_typography_elements","generatepress-pro/customizer/add-typography-elements",(function(e){var o={};return gpCustomizerControls.hasSecondaryNav&&(o["secondary-nav-menu-items"]={module:"secondary-nav",group:"secondaryNavigation",label:(0,t.__)("Secondary Menu Items","gp-premium"),placeholders:{fontSize:{value:"13",min:6,max:30,step:1}}},o["secondary-nav-sub-menu-items"]={module:"secondary-nav",group:"secondaryNavigation",label:(0,t.__)("Secondary Sub-Menu Items","gp-premium"),placeholders:{fontSize:{value:"12",min:6,max:30,step:1}}},o["secondary-nav-menu-toggle"]={module:"secondary-nav",group:"secondaryNavigation",label:(0,t.__)("Secondary Mobile Menu Toggle","gp-premium"),placeholders:{fontSize:{value:"13",min:6,max:30,step:1}}}),gpCustomizerControls.hasMenuPlus&&(o["off-canvas-panel-menu-items"]={module:"off-canvas-panel",group:"offCanvasPanel",label:(0,t.__)("Off-Canvas Menu Items","gp-premium"),placeholders:{fontSize:{value:"",min:6,max:30,step:1}}},o["off-canvas-panel-sub-menu-items"]={module:"off-canvas-panel",group:"offCanvasPanel",label:(0,t.__)("Off-Canvas Sub-Menu Items","gp-premium"),placeholders:{fontSize:{value:"",min:6,max:30,step:1}}}),gpCustomizerControls.hasWooCommerce&&(o["woocommerce-catalog-product-titles"]={module:"woocommerce",group:"wooCommerce",label:(0,t.__)("Catalog Product Titles","gp-premium"),placeholders:{fontSize:{value:"",min:6,max:50,step:1}}},o["woocommerce-related-product-titles"]={module:"woocommerce",group:"wooCommerce",label:(0,t.__)("Related/Upsell Product Titles","gp-premium"),placeholders:{fontSize:{value:"",min:6,max:50,step:1}}}),a(a({},e),o)}))}();

View File

@ -0,0 +1 @@
<?php return array('dependencies' => array('wp-api-fetch', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => '204b0a224864701c559a');

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<?php return array('dependencies' => array('wp-edit-post', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-plugins'), 'version' => '27f43589f8077aec0cae');

View File

@ -0,0 +1 @@
.gpp-active-element-type{color:#555;font-size:11px;text-transform:uppercase}

View File

@ -0,0 +1 @@
!function(){"use strict";function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e(t)}function t(t,n){for(var r=0;r<n.length;r++){var o=n[r];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,(i=o.key,c=void 0,c=function(t,n){if("object"!==e(t)||null===t)return t;var r=t[Symbol.toPrimitive];if(void 0!==r){var o=r.call(t,"string");if("object"!==e(o))return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(i),"symbol"===e(c)?c:String(c)),o)}var i,c}function n(e,t){return n=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},n(e,t)}function r(e){return r=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(e){return e.__proto__||Object.getPrototypeOf(e)},r(e)}var o=window.wp.element,i=window.wp.i18n,c=window.wp.plugins,l=window.wp.editPost,u=window.wp.htmlEntities;function a(t){var n=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(e){return!1}}();return function(){var o,i=r(t);if(n){var c=r(this).constructor;o=Reflect.construct(i,arguments,c)}else o=i.apply(this,arguments);return function(t,n){if(n&&("object"===e(n)||"function"==typeof n))return n;if(void 0!==n)throw new TypeError("Derived constructors may only return object or undefined");return function(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(t)}(this,o)}}var p=function(e){!function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),Object.defineProperty(e,"prototype",{writable:!1}),t&&n(e,t)}(f,e);var r,c,p=a(f);function f(){return function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,f),p.apply(this,arguments)}return r=f,(c=[{key:"render",value:function(){var e=gpPremiumEditor.activeElements;return!e||e.length<1?null:gpPremiumEditor.postTypeIsPublic?(0,o.createElement)(l.PluginDocumentSettingPanel,{name:"generatepress-elements-info",title:(0,i.__)("Active Elements","gp-premium"),className:"gpp-element-info-panel gpp-element-panel-label"},(0,o.createElement)(o.Fragment,null,(0,o.createElement)("ul",{className:"gpp-active-elements"},Object.keys(e).map((function(t,n){return(0,o.createElement)("li",{key:"gpp-active-block-element-".concat(n)},(0,o.createElement)("a",{href:e[t].url+"&action=edit"},(0,u.decodeEntities)(e[t].name))," ",(0,o.createElement)("span",{className:"gpp-active-element-type"},"- ",e[t].type))}))),(0,o.createElement)("a",{href:gpPremiumEditor.elementsUrl,className:"components-button is-secondary"},(0,i.__)("All Elements","gp-premium")))):null}}])&&t(r.prototype,c),Object.defineProperty(r,"prototype",{writable:!1}),f}(o.Component);(0,c.registerPlugin)("generatepress-elements-info-panel",{icon:null,render:p})}();

View File

@ -0,0 +1 @@
<?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-components', 'wp-element', 'wp-html-entities', 'wp-i18n'), 'version' => 'c153dcc4d45dc270e00f');

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,4 @@
.generatepress-module-action{display:inline-block;font-size:12px;font-weight:400;line-height:1;margin-left:10px;text-decoration:none}.generatepress-dashboard__section-item-settings{align-items:center;display:flex}.generatepress-dashboard__section-item-settings button{font-size:11px;height:30px;justify-content:center!important}.generatepress-dashboard__section-item-settings button .components-spinner{margin-top:0}.generatepress-dashboard__section-item-settings button svg{height:20px;margin:0!important;width:20px}.generatepress-dashboard__section-item-settings button:not(:last-child){margin-right:5px}
.generatepress-license-key-area .generatepress-dashboard__section-item-message{background:#fff}.generatepress-license-key-area .generatepress-dashboard__section-item{flex-wrap:wrap;justify-content:flex-start}.generatepress-license-key-area .generatepress-dashboard__section-license-key{display:flex;flex:1}.generatepress-license-key-area .generatepress-dashboard__section-license-key .components-base-control{flex:1}.generatepress-license-key-area .generatepress-dashboard__section-license-key button{height:31px;margin-left:8px}.generatepress-license-key-area .generatepress-dashboard__section-beta-tester{align-items:center;display:flex;flex-basis:100%;margin-top:30px}.generatepress-license-key-area .generatepress-dashboard__section-license-notice{flex-basis:100%;margin:0 0 20px}.generatepress-license-key-area .components-base-control__field,.generatepress-license-key-area .components-base-control__help{margin-bottom:0}
.generatepress-dashboard__section-item-action input[type=file]{border:1px solid #ddd;padding:5px}.generatepress-dashboard__section-item-export-popover .components-popover__content{padding:20px}
.generatepress-dashboard__section-item-modules{margin-top:20px}

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

Some files were not shown because too many files have changed in this diff Show More