diff --git a/wp-content/plugins/the-events-calendar/common/vendor/composer/installed.php b/wp-content/plugins/the-events-calendar/common/vendor/composer/installed.php
index f3ea21ca..db9321e3 100644
--- a/wp-content/plugins/the-events-calendar/common/vendor/composer/installed.php
+++ b/wp-content/plugins/the-events-calendar/common/vendor/composer/installed.php
@@ -1,9 +1,9 @@
array(
'name' => 'the-events-calendar/tribe-common',
- 'pretty_version' => 'dev-master',
- 'version' => 'dev-master',
- 'reference' => '63dd7e9664696331ab95215b8c6d5bf0b39b77d0',
+ 'pretty_version' => '6.3.2',
+ 'version' => '6.3.2.0',
+ 'reference' => 'f37e825d0d7d07207fba1eae8ab8c4a47ec4ea78',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -154,9 +154,9 @@
'dev_requirement' => false,
),
'the-events-calendar/tribe-common' => array(
- 'pretty_version' => 'dev-master',
- 'version' => 'dev-master',
- 'reference' => '63dd7e9664696331ab95215b8c6d5bf0b39b77d0',
+ 'pretty_version' => '6.3.2',
+ 'version' => '6.3.2.0',
+ 'reference' => 'f37e825d0d7d07207fba1eae8ab8c4a47ec4ea78',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
diff --git a/wp-content/plugins/the-events-calendar/lang/the-events-calendar-ar.mo b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-ar.mo
new file mode 100644
index 00000000..f3294c40
Binary files /dev/null and b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-ar.mo differ
diff --git a/wp-content/plugins/the-events-calendar/lang/the-events-calendar-bg_BG.mo b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-bg_BG.mo
new file mode 100644
index 00000000..1e66cc40
Binary files /dev/null and b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-bg_BG.mo differ
diff --git a/wp-content/plugins/the-events-calendar/lang/the-events-calendar-cs_CZ.mo b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-cs_CZ.mo
new file mode 100644
index 00000000..5af2a240
Binary files /dev/null and b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-cs_CZ.mo differ
diff --git a/wp-content/plugins/the-events-calendar/lang/the-events-calendar-el.mo b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-el.mo
new file mode 100644
index 00000000..2d123b69
Binary files /dev/null and b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-el.mo differ
diff --git a/wp-content/plugins/the-events-calendar/lang/the-events-calendar-et.mo b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-et.mo
new file mode 100644
index 00000000..5f3d4b1d
Binary files /dev/null and b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-et.mo differ
diff --git a/wp-content/plugins/the-events-calendar/lang/the-events-calendar-eu.mo b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-eu.mo
new file mode 100644
index 00000000..b7edffc6
Binary files /dev/null and b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-eu.mo differ
diff --git a/wp-content/plugins/the-events-calendar/lang/the-events-calendar-fr_CA.mo b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-fr_CA.mo
new file mode 100644
index 00000000..66dcb126
Binary files /dev/null and b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-fr_CA.mo differ
diff --git a/wp-content/plugins/the-events-calendar/lang/the-events-calendar-he_IL.mo b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-he_IL.mo
new file mode 100644
index 00000000..472448c5
Binary files /dev/null and b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-he_IL.mo differ
diff --git a/wp-content/plugins/the-events-calendar/lang/the-events-calendar-hr.mo b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-hr.mo
new file mode 100644
index 00000000..553a0ee0
Binary files /dev/null and b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-hr.mo differ
diff --git a/wp-content/plugins/the-events-calendar/lang/the-events-calendar-ro_RO.mo b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-ro_RO.mo
new file mode 100644
index 00000000..778675ee
Binary files /dev/null and b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-ro_RO.mo differ
diff --git a/wp-content/plugins/the-events-calendar/lang/the-events-calendar-sk_SK.mo b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-sk_SK.mo
new file mode 100644
index 00000000..a3d8f2a8
Binary files /dev/null and b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-sk_SK.mo differ
diff --git a/wp-content/plugins/the-events-calendar/lang/the-events-calendar-sq.mo b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-sq.mo
new file mode 100644
index 00000000..feecfc66
Binary files /dev/null and b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-sq.mo differ
diff --git a/wp-content/plugins/the-events-calendar/lang/the-events-calendar-sv_SE.mo b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-sv_SE.mo
index 7600ad2b..c24b52ba 100644
Binary files a/wp-content/plugins/the-events-calendar/lang/the-events-calendar-sv_SE.mo and b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-sv_SE.mo differ
diff --git a/wp-content/plugins/the-events-calendar/lang/the-events-calendar-zh_HK.mo b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-zh_HK.mo
new file mode 100644
index 00000000..5b92d02f
Binary files /dev/null and b/wp-content/plugins/the-events-calendar/lang/the-events-calendar-zh_HK.mo differ
diff --git a/wp-content/plugins/the-events-calendar/readme.txt b/wp-content/plugins/the-events-calendar/readme.txt
index e84f2dd9..f2b4a1d9 100644
--- a/wp-content/plugins/the-events-calendar/readme.txt
+++ b/wp-content/plugins/the-events-calendar/readme.txt
@@ -1,11 +1,11 @@
=== The Events Calendar ===
-Contributors: theeventscalendar, borkweb, bordoni, brianjessee, aguseo, camwynsp, GeoffBel, jentheo, leahkoerper, lucatume, neillmcshea, vicskf, zbtirrell, juanfra
+Contributors: theeventscalendar, stellarwp, borkweb, bordoni, brianjessee, aguseo, camwynsp, jentheo, leahkoerper, lucatume, neillmcshea, vicskf, zbtirrell
Tags: events, calendar, event, schedule, organizer
Donate link: https://evnt.is/29
-Stable tag: 6.8.2
+Stable tag: 6.8.2.1
Requires at least: 6.3
-Tested up to: 6.7
+Tested up to: 6.7.1
Requires PHP: 7.4
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -90,14 +90,10 @@ Our Premium Plugins and Services:
⚡ [Events Calendar PRO](https://evnt.is/18wi)
↪️ [Event Aggregator](https://evnt.is/197u) (service)
🎟️ [Event Tickets Plus](https://evnt.is/18wk)
-📱 [Event Tickets Wallet Plus](https://evnt.is/etwp)
✉️ [Promoter](https://evnt.is/1ajt)
👥 [Community Events](https://evnt.is/2g)
-🎟️ [Community Tickets](https://evnt.is/18wl)
✏️ [Filter Bar](https://evnt.is/fa)
🗓️ [Eventbrite Tickets](https://evnt.is/2e)
-📡 [Virtual Events](https://evnt.is/1aky)
-🔄 [Event Automator](https://evnt.is/1bdk)
== Help ==
@@ -178,13 +174,10 @@ The following add-ons are available for The Events Calendar:
* [Events Calendar Pro](https://evnt.is/18wi), for adding premium calendar features like recurring events, advanced views, cool widgets, [shortcodes](https://evnt.is/1ajw), additional fields, and more!
* [Event Aggregator](https://evnt.is/197u), a service that effortlessly fills your calendar with events from Meetup, Google Calendar, iCalendar, Eventbrite, CSV, and ICS.
-* [Virtual Events](https://evnt.is/1aky), which optimizes your calendar for virtual events including Zoom integration, video and livestream embeds, SEO optimization for online events and more.
* [Event Tickets](https://wordpress.org/plugins/event-tickets/) (free), which allows you to sell tickets and collect RSVPs to events. It can run alongside The Events Calendar or as a standalone plugin that adds ticket and RSVP functionality to WordPress posts and pages.
* [Event Tickets Plus](https://evnt.is/18wk), which allows you to sell tickets for your events using your favorite e-commerce platform.
-* [Event Tickets Wallet Plus](https://evnt.is/etwp), for adding digital tickets like Apple Wallet passes and PDF tickets.
* [Promoter](https://evnt.is/1ajt), automated email communication made just for The Events Calendar and Event Tickets. Stay in touch with your attendees every step of the way.
* [Community Events](https://evnt.is/2g), for allowing frontend event submission from your readers.
-* [Community Tickets](https://evnt.is/18wl), which allows event organizers to sell tickets to the events they submit via Community Events.
* [Filter Bar](https://evnt.is/fa), for adding advanced frontend filtering capabilities to your events calendar.
* [Eventbrite Tickets](https://evnt.is/2e), for selling tickets to your event directly through Eventbrite.
@@ -239,6 +232,11 @@ Remember to always make a backup of your database and files before updating!
== Changelog ==
+= [6.8.2.1] 2024-11-21 =
+
+* Tweak - Introduced filter `tec_events_rest_api_password_protected_fields` which can be used to control which event fields should be hidden in the REST API for password protected events. [SVUL-8]
+* Security - Hide content fields from the archive REST endpoint for password protected events. [SVUL-8]
+
= [6.8.2] 2024-11-19 =
* Feature - Introduced Help Hub, a centralized support and resource interface for enhanced user guidance and plugin assistance.
diff --git a/wp-content/plugins/the-events-calendar/src/Tribe/Aggregator/Service.php b/wp-content/plugins/the-events-calendar/src/Tribe/Aggregator/Service.php
index becb53a7..701af969 100644
--- a/wp-content/plugins/the-events-calendar/src/Tribe/Aggregator/Service.php
+++ b/wp-content/plugins/the-events-calendar/src/Tribe/Aggregator/Service.php
@@ -75,7 +75,7 @@ public static function instance() {
* Constructor!
*/
public function __construct( Tribe__Events__Aggregator__API__Requests $requests ) {
- $this->register_messages();
+ add_action( 'after_setup_theme', [ $this, 'register_messages' ] );
$this->requests = $requests;
}
@@ -759,7 +759,7 @@ public function get_limit_remaining( $ignore_cache = false ) {
* These messages are delivered by the EA service and don't need to be registered. They just need to exist
* here so that they can be translated.
*/
- protected function register_messages() {
+ public function register_messages() {
$ical_uid_specification_link = sprintf(
'%s',
esc_html__( 'the UID part of the iCalendar Specification', 'the-events-calendar' )
diff --git a/wp-content/plugins/the-events-calendar/src/Tribe/Main.php b/wp-content/plugins/the-events-calendar/src/Tribe/Main.php
index 852fedd9..f9bf925d 100644
--- a/wp-content/plugins/the-events-calendar/src/Tribe/Main.php
+++ b/wp-content/plugins/the-events-calendar/src/Tribe/Main.php
@@ -39,7 +39,7 @@ class Tribe__Events__Main {
const POSTTYPE = 'tribe_events';
const VENUE_POST_TYPE = 'tribe_venue';
const ORGANIZER_POST_TYPE = 'tribe_organizer';
- const VERSION = '6.8.2';
+ const VERSION = '6.8.2.1';
/**
* Min Pro Addon.
diff --git a/wp-content/plugins/the-events-calendar/src/Tribe/REST/V1/Main.php b/wp-content/plugins/the-events-calendar/src/Tribe/REST/V1/Main.php
index ee02acb4..324bc07b 100644
--- a/wp-content/plugins/the-events-calendar/src/Tribe/REST/V1/Main.php
+++ b/wp-content/plugins/the-events-calendar/src/Tribe/REST/V1/Main.php
@@ -61,6 +61,45 @@ public function hook() {
add_action( 'rest_api_init', [ $this, 'register_endpoints' ] );
add_filter( 'tribe_events_register_event_cat_type_args', [ $this, 'filter_taxonomy_args' ] );
+ add_filter( 'tribe_rest_events_archive_data', [ $this, 'filter_out_password_protected_events' ], 100, 2 );
+ }
+
+ /**
+ * Filters out content from password protected events from the REST API response.
+ *
+ * @since 6.8.2.1
+ *
+ * @param array $data The events to be filtered.
+ * @param WP_REST_Request $request The request object.
+ *
+ * @return array The filtered events.
+ */
+ public function filter_out_password_protected_events( array $data, WP_REST_Request $request ): array {
+ foreach( $data['events'] as &$event ) {
+ if ( ! post_password_required( $event['id'] ) ) {
+ // No password required or password has been provided or requirement has been removed through filters.
+ continue;
+ }
+
+ $event_post = get_post( $event['id'] );
+
+ if ( ! ( $event_post instanceof WP_Post && $event_post->ID ) ) {
+ // No post object, weird but let's skip it.
+ continue;
+ }
+
+ $validator = tribe( 'tec.rest-v1.validator' );
+
+ if ( $validator->can_access_password_content( $event_post, $request ) ) {
+ // User has provided password and can see password protected content.
+ continue;
+ }
+
+ // User should not be able to see password protected content.
+ $event = $validator->remove_password_protected_content( $event );
+ }
+
+ return $data;
}
/**
diff --git a/wp-content/plugins/the-events-calendar/src/Tribe/REST/V1/Validator/Base.php b/wp-content/plugins/the-events-calendar/src/Tribe/REST/V1/Validator/Base.php
index ade73d60..c71ca837 100644
--- a/wp-content/plugins/the-events-calendar/src/Tribe/REST/V1/Validator/Base.php
+++ b/wp-content/plugins/the-events-calendar/src/Tribe/REST/V1/Validator/Base.php
@@ -5,6 +5,46 @@ class Tribe__Events__REST__V1__Validator__Base
extends Tribe__Events__Validator__Base
implements Tribe__Events__REST__V1__Validator__Interface {
+ /**
+ * The event fields that are password protected when a password is required.
+ *
+ * @since 6.8.2.1
+ *
+ * @var array
+ */
+ protected const PASSWORD_PROTECTED_FIELDS = [
+ 'description' => '',
+ 'excerpt' => '',
+ 'image' => false,
+ 'all_day' => 'null',
+ 'cost' => '',
+ 'cost_details' => [
+ 'currency_symbol' => '',
+ 'currency_position' => '',
+ 'currency_code' => '',
+ 'values' => [],
+ ],
+ 'website' => '',
+ 'show_map' => 'null',
+ 'show_map_link' => 'null',
+ 'hide_from_listings' => 'null',
+ 'sticky' => 'null',
+ 'featured' => 'null',
+ 'categories' => [],
+ 'tags' => [],
+ 'venue' => [],
+ 'organizer' => [],
+ 'ticketed' => 'null',
+ 'is_virtual' => 'null',
+ 'virtual_url' => '',
+ 'virtual_video_source' => '',
+ 'attendance' => [
+ 'total_attendees' => 'null',
+ 'checked_in' => 'null',
+ 'not_checked_in' => 'null',
+ ],
+ ];
+
/**
* Determine if a value is a Venue ID, entry, or empty.
*
@@ -167,4 +207,35 @@ public function can_access_password_content( WP_Post $post, WP_REST_Request $req
// Double-check the request password.
return hash_equals( $post->post_password, $request['password'] );
}
+
+ /**
+ * Removes password-protected content from the response.
+ *
+ * @since 6.8.2.1
+ *
+ * @return array
+ */
+ public function remove_password_protected_content( array $data ): array {
+ /**
+ * Filters the password-protected fields that should be removed from the response.
+ *
+ * @since 6.8.2.1
+ *
+ * @param array $password_protected_fields The password-protected fields to remove.
+ */
+ $password_protected_fields = (array) apply_filters( 'tec_events_rest_api_password_protected_fields', self::PASSWORD_PROTECTED_FIELDS );
+
+ foreach ( $data as $key => $value ) {
+ if ( isset( $password_protected_fields[ $key ] ) ) {
+ $data[ $key ] = 'null' === $password_protected_fields[ $key ] ? null : $password_protected_fields[ $key ];
+ continue;
+ }
+
+ if ( is_array( $value ) || is_object( $value ) ) {
+ $data[ $key ] = $this->remove_password_protected_content( (array) $value );
+ }
+ }
+
+ return $data;
+ }
}
diff --git a/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Google_Calendar.php b/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Google_Calendar.php
index d394a08d..780a2991 100644
--- a/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Google_Calendar.php
+++ b/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Google_Calendar.php
@@ -45,8 +45,21 @@ class Google_Calendar extends Link_Abstract {
* {@inheritDoc}
*/
public function register() {
- $this->label = __( 'Google Calendar', 'the-events-calendar' );
- $this->single_label = __( 'Add to Google Calendar', 'the-events-calendar' );
+ // intentionally left blank.
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function label(): string {
+ return __( 'Google Calendar', 'the-events-calendar' );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function single_label(): string {
+ return __( 'Add to Google Calendar', 'the-events-calendar' );
}
/**
diff --git a/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Link_Abstract.php b/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Link_Abstract.php
index de15a0e7..9d2e8981 100644
--- a/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Link_Abstract.php
+++ b/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Link_Abstract.php
@@ -8,6 +8,7 @@
namespace Tribe\Events\Views\V2\iCalendar\Links;
+use JsonSerializable;
use Tribe__Date_Utils as Dates;
use \Tribe\Events\Views\V2\View;
@@ -17,7 +18,7 @@
* @since 5.12.0
* @package Tribe\Events\Views\V2\iCalendar
*/
-abstract class Link_Abstract implements Link_Interface {
+abstract class Link_Abstract implements Link_Interface, JsonSerializable {
/**
* The (translated) text/label for the link.
@@ -131,15 +132,15 @@ public function filter_tec_views_v2_single_subscribe_links( $links ) {
return $links;
}
- $label = $this->get_single_label( null );
- $uri = $this->get_uri( null );
+ $label = $this->get_single_label( null );
+ $uri = $this->get_uri( null );
// Don't add invalid or "invisible" links.
if ( empty( $label ) || empty( $uri ) ) {
return $links;
}
- $class = sanitize_html_class( 'tribe-events-' . self::get_slug() );
+ $class = sanitize_html_class( 'tribe-events-' . self::get_slug() );
$links[ self::get_slug() ] = sprintf(
'%4$s',
$class,
@@ -197,11 +198,34 @@ public function is_visible() {
/**
* {@inheritDoc}
*/
- public function get_label( View $view = null ) {
+ public function get_label( View $view = null ): string {
+ return $this->filter_get_label( $this->label(), $view );
+ }
+
+ /**
+ * Returns the label for the link.
+ *
+ * @since 6.8.2.1
+ *
+ * @return string
+ */
+ abstract protected function label(): string;
+
+ /**
+ * Filters the label for the link.
+ *
+ * @since 6.8.2.1
+ *
+ * @param string $value The label to filter.
+ * @param View|null $view The current View object.
+ *
+ * @return string
+ */
+ protected function filter_get_label( string $value, View $view = null ): string {
$slug = self::get_slug();
/**
- * Allows filtering of the labels for the Calendar view labels.
+ * Allows filtering of the labels for the Single Event view labels.
*
* @since 5.12.0
*
@@ -211,13 +235,36 @@ public function get_label( View $view = null ) {
*
* @return string $label The label that will be displayed.
*/
- return apply_filters( "tec_views_v2_subscribe_links_{$slug}_label", $this->label, $this, $view );
+ return (string) apply_filters( "tec_views_v2_single_subscribe_links_{$slug}_label", $value, $this, $view );
}
/**
* {@inheritDoc}
*/
- public function get_single_label( View $view = null ) {
+ public function get_single_label( View $view = null ): string {
+ return $this->filter_get_single_label( $this->single_label(), $view );
+ }
+
+ /**
+ * Returns the label for the single event view.
+ *
+ * @since 6.8.2.1
+ *
+ * @return string
+ */
+ abstract protected function single_label(): string;
+
+ /**
+ * Filters the single label for the link.
+ *
+ * @since 6.8.2.1
+ *
+ * @param string $value The label to filter.
+ * @param View|null $view The current View object.
+ *
+ * @return string
+ */
+ protected function filter_get_single_label( string $value, View $view = null ): string {
$slug = self::get_slug();
/**
@@ -225,13 +272,13 @@ public function get_single_label( View $view = null ) {
*
* @since 5.12.0
*
- * @param string $label The label that will be displayed.
- * @param Link_Abstract $link_obj The link object the label is for.
- * @param View $view The current View object.
+ * @param string $single_label The label that will be displayed.
+ * @param Link_Abstract $link_obj The link object the label is for.
+ * @param View $view The current View object.
*
* @return string $label The label that will be displayed.
*/
- return apply_filters( "tec_views_v2_single_subscribe_links_{$slug}_label", $this->single_label, $this, $view );
+ return (string) apply_filters( "tec_views_v2_single_subscribe_links_{$slug}_label", $value, $this, $view );
}
/**
@@ -312,7 +359,6 @@ protected function get_canonical_ics_feed_url( View $view = null ) {
$view_url_args['tribe-bar-date'] = $view_url_args['eventDate'];
}
-
// Clean query params to only contain canonical arguments.
$canonical_args = [ 'post_type', 'tribe-bar-date', 'tribe_events_cat', 'post_tag' ];
@@ -362,4 +408,45 @@ protected function get_canonical_ics_feed_url( View $view = null ) {
return add_query_arg( urlencode_deep( $passthrough_args ), home_url( '/' ) );
}
+
+ /**
+ * Magic method to allow getting the label and single_label properties.
+ * These two params are deprecated and will be removed in a future release.
+ *
+ * @since 6.8.2.1
+ *
+ * @param string $name The property name.
+ *
+ * @return string|null
+ */
+ public function __get( $name ) {
+ if ( 'label' === $name ) {
+ _doing_it_wrong( __METHOD__, 'The `label` property is deprecated and will be removed in a future release.', '6.8.2.1' );
+ return $this->get_label();
+ }
+
+ if ( 'single_label' === $name ) {
+ _doing_it_wrong( __METHOD__, 'The `single_label` property is deprecated and will be removed in a future release.', '6.8.2.1' );
+ return $this->get_single_label();
+ }
+
+ return null;
+ }
+
+ /**
+ * Magic method surrounding the JSON serialization to enable the object to be serialized with all props.
+ *
+ * @since 6.8.2.1
+ *
+ * @return array
+ */
+ #[\ReturnTypeWillChange]
+ public function jsonSerialize() {
+ return [
+ 'label' => $this->get_label(),
+ 'single_label' => $this->get_single_label(),
+ 'visible' => $this->is_visible(),
+ 'block_slug' => $this->block_slug,
+ ];
+ }
}
diff --git a/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Outlook_365.php b/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Outlook_365.php
index b5faf3e4..46ddbcb0 100644
--- a/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Outlook_365.php
+++ b/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Outlook_365.php
@@ -41,7 +41,20 @@ class Outlook_365 extends Link_Abstract {
* {@inheritDoc}
*/
public function register() {
- $this->label = __( 'Outlook 365', 'the-events-calendar' );
- $this->single_label = $this->label;
+ // intentionally left blank.
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function label(): string {
+ return __( 'Outlook 365', 'the-events-calendar' );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function single_label(): string {
+ return $this->label();
}
}
diff --git a/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Outlook_Export.php b/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Outlook_Export.php
index 1b80d162..da3e7b45 100644
--- a/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Outlook_Export.php
+++ b/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Outlook_Export.php
@@ -28,12 +28,24 @@ class Outlook_Export extends Link_Abstract {
* {@inheritDoc}
*/
public function register() {
- $this->label = __( 'Export Outlook .ics file', 'the-events-calendar' );
- $this->single_label = $this->label;
-
add_filter( 'tec_views_v2_subscribe_link_outlook-ics_visibility', [ $this, 'filter_tec_views_v2_subscribe_link_outlook_ics_visibility'], 10, 2 );
}
+ /**
+ * {@inheritDoc}
+ */
+ protected function label(): string {
+ return __( 'Export Outlook .ics file', 'the-events-calendar' );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function single_label(): string {
+ return $this->label();
+ }
+
+
/**
* Filters the is_visible() function to not display on single events.
*
diff --git a/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Outlook_Live.php b/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Outlook_Live.php
index 17188004..d755ee4a 100644
--- a/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Outlook_Live.php
+++ b/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/Outlook_Live.php
@@ -41,7 +41,21 @@ class Outlook_Live extends Link_Abstract {
* {@inheritDoc}
*/
public function register() {
- $this->label = __( 'Outlook Live', 'the-events-calendar' );
- $this->single_label = $this->label;
+ // intentionally left blank.
}
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function label(): string {
+ return __( 'Outlook Live', 'the-events-calendar' );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function single_label(): string {
+ return $this->label();
+ }
+
}
diff --git a/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/iCal.php b/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/iCal.php
index 48a3d48c..ceae725a 100644
--- a/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/iCal.php
+++ b/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/iCal.php
@@ -31,7 +31,20 @@ class iCal extends Link_Abstract {
* {@inheritDoc}
*/
public function register() {
- $this->label = __( 'iCalendar', 'the-events-calendar' );
- $this->single_label = __( 'Add to iCalendar', 'the-events-calendar' );
+ // intentionally left blank.
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function label(): string {
+ return __( 'iCalendar', 'the-events-calendar' );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function single_label(): string {
+ return __( 'Add to iCalendar', 'the-events-calendar' );
}
}
diff --git a/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/iCalendar_Export.php b/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/iCalendar_Export.php
index d1e66ad6..7c593e6e 100644
--- a/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/iCalendar_Export.php
+++ b/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/Links/iCalendar_Export.php
@@ -28,12 +28,23 @@ class iCalendar_Export extends Link_Abstract {
* {@inheritDoc}
*/
public function register() {
- $this->label = __( 'Export .ics file', 'the-events-calendar' );
- $this->single_label = $this->label;
-
add_filter( 'tec_views_v2_subscribe_link_ics_visibility', [ $this, 'filter_tec_views_v2_subscribe_link_ics_visibility'], 10, 2 );
}
+ /**
+ * {@inheritDoc}
+ */
+ protected function label(): string {
+ return __( 'Export .ics file', 'the-events-calendar' );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function single_label(): string {
+ return $this->label();
+ }
+
/**
* Filters the is_visible() function to not display on single events.
*
diff --git a/wp-content/plugins/the-events-calendar/the-events-calendar.php b/wp-content/plugins/the-events-calendar/the-events-calendar.php
index 96477f41..319ef6ea 100644
--- a/wp-content/plugins/the-events-calendar/the-events-calendar.php
+++ b/wp-content/plugins/the-events-calendar/the-events-calendar.php
@@ -2,7 +2,7 @@
/**
* Plugin Name: The Events Calendar
* Description: The Events Calendar is a carefully crafted, extensible plugin that lets you easily share your events. Beautiful. Solid. Awesome.
- * Version: 6.8.2
+ * Version: 6.8.2.1
* Requires at least: 6.3
* Requires PHP: 7.4
* Author: The Events Calendar
diff --git a/wp-content/plugins/the-events-calendar/vendor/autoload.php b/wp-content/plugins/the-events-calendar/vendor/autoload.php
index 67b5e6b1..1fbd8b6f 100644
--- a/wp-content/plugins/the-events-calendar/vendor/autoload.php
+++ b/wp-content/plugins/the-events-calendar/vendor/autoload.php
@@ -22,4 +22,4 @@
require_once __DIR__ . '/composer/autoload_real.php';
-return ComposerAutoloaderInitaf65b88dc513654448dc0c9e151257f0::getLoader();
+return ComposerAutoloaderInit9341b32032f5c2c14ff1f117a6964efc::getLoader();
diff --git a/wp-content/plugins/the-events-calendar/vendor/composer/autoload_real.php b/wp-content/plugins/the-events-calendar/vendor/composer/autoload_real.php
index 7a528e72..862414b3 100644
--- a/wp-content/plugins/the-events-calendar/vendor/composer/autoload_real.php
+++ b/wp-content/plugins/the-events-calendar/vendor/composer/autoload_real.php
@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
-class ComposerAutoloaderInitaf65b88dc513654448dc0c9e151257f0
+class ComposerAutoloaderInit9341b32032f5c2c14ff1f117a6964efc
{
private static $loader;
@@ -24,12 +24,12 @@ public static function getLoader()
require __DIR__ . '/platform_check.php';
- spl_autoload_register(array('ComposerAutoloaderInitaf65b88dc513654448dc0c9e151257f0', 'loadClassLoader'), true, true);
+ spl_autoload_register(array('ComposerAutoloaderInit9341b32032f5c2c14ff1f117a6964efc', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
- spl_autoload_unregister(array('ComposerAutoloaderInitaf65b88dc513654448dc0c9e151257f0', 'loadClassLoader'));
+ spl_autoload_unregister(array('ComposerAutoloaderInit9341b32032f5c2c14ff1f117a6964efc', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
- call_user_func(\Composer\Autoload\ComposerStaticInitaf65b88dc513654448dc0c9e151257f0::getInitializer($loader));
+ call_user_func(\Composer\Autoload\ComposerStaticInit9341b32032f5c2c14ff1f117a6964efc::getInitializer($loader));
$loader->register(true);
diff --git a/wp-content/plugins/the-events-calendar/vendor/composer/autoload_static.php b/wp-content/plugins/the-events-calendar/vendor/composer/autoload_static.php
index ef88d910..d9c37823 100644
--- a/wp-content/plugins/the-events-calendar/vendor/composer/autoload_static.php
+++ b/wp-content/plugins/the-events-calendar/vendor/composer/autoload_static.php
@@ -4,7 +4,7 @@
namespace Composer\Autoload;
-class ComposerStaticInitaf65b88dc513654448dc0c9e151257f0
+class ComposerStaticInit9341b32032f5c2c14ff1f117a6964efc
{
public static $prefixLengthsPsr4 = array (
'T' =>
@@ -355,9 +355,9 @@ class ComposerStaticInitaf65b88dc513654448dc0c9e151257f0
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
- $loader->prefixLengthsPsr4 = ComposerStaticInitaf65b88dc513654448dc0c9e151257f0::$prefixLengthsPsr4;
- $loader->prefixDirsPsr4 = ComposerStaticInitaf65b88dc513654448dc0c9e151257f0::$prefixDirsPsr4;
- $loader->classMap = ComposerStaticInitaf65b88dc513654448dc0c9e151257f0::$classMap;
+ $loader->prefixLengthsPsr4 = ComposerStaticInit9341b32032f5c2c14ff1f117a6964efc::$prefixLengthsPsr4;
+ $loader->prefixDirsPsr4 = ComposerStaticInit9341b32032f5c2c14ff1f117a6964efc::$prefixDirsPsr4;
+ $loader->classMap = ComposerStaticInit9341b32032f5c2c14ff1f117a6964efc::$classMap;
}, null, ClassLoader::class);
}
diff --git a/wp-content/plugins/the-events-calendar/vendor/composer/installed.php b/wp-content/plugins/the-events-calendar/vendor/composer/installed.php
index 30076a2f..51e46302 100644
--- a/wp-content/plugins/the-events-calendar/vendor/composer/installed.php
+++ b/wp-content/plugins/the-events-calendar/vendor/composer/installed.php
@@ -3,7 +3,7 @@
'name' => 'the-events-calendar/the-events-calendar',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
- 'reference' => '9d58b5a0333918c61b69c3e752881e0f87f7cbc8',
+ 'reference' => 'bba0f923fe379fd6e9d67492bc3a2037df612fc4',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -13,7 +13,7 @@
'the-events-calendar/the-events-calendar' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
- 'reference' => '9d58b5a0333918c61b69c3e752881e0f87f7cbc8',
+ 'reference' => 'bba0f923fe379fd6e9d67492bc3a2037df612fc4',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
diff --git a/wp-content/plugins/user-switching/composer.json b/wp-content/plugins/user-switching/composer.json
index 3530e89a..24e3c1ae 100644
--- a/wp-content/plugins/user-switching/composer.json
+++ b/wp-content/plugins/user-switching/composer.json
@@ -13,7 +13,8 @@
"support": {
"issues": "https://github.com/johnbillion/user-switching/issues",
"forum": "https://wordpress.org/support/plugin/user-switching",
- "source": "https://github.com/johnbillion/user-switching"
+ "source": "https://github.com/johnbillion/user-switching",
+ "security": "https://patchstack.com/database/vdp/user-switching"
},
"funding": [
{
@@ -31,14 +32,15 @@
"codeception/module-webdriver": "^1.0",
"codeception/util-universalframework": "^1.0",
"johnbillion/plugin-infrastructure": "dev-trunk",
+ "johnbillion/wp-compat": "0.3.0",
"lucatume/wp-browser": "3.2.3",
- "phpcompatibility/phpcompatibility-wp": "2.1.4",
- "phpstan/phpstan": "1.10.59",
- "phpstan/phpstan-phpunit": "1.3.16",
- "roots/wordpress-core-installer": "^1.0.0",
- "roots/wordpress-full": "*",
- "szepeviktor/phpstan-wordpress": "1.3.3",
- "wp-coding-standards/wpcs": "3.0.1"
+ "phpcompatibility/phpcompatibility-wp": "2.1.5",
+ "phpstan/phpstan": "1.12.11",
+ "phpstan/phpstan-phpunit": "1.4.1",
+ "roots/wordpress-core-installer": "1.100.0",
+ "roots/wordpress-full": "6.7.0",
+ "szepeviktor/phpstan-wordpress": "1.3.5",
+ "wp-coding-standards/wpcs": "3.1.0"
},
"autoload-dev": {
"psr-4": {
@@ -83,7 +85,7 @@
],
"test:phpstan": [
"codecept build",
- "phpstan analyze --memory-limit=1024M"
+ "phpstan analyze -v --memory-limit=1024M"
],
"test:start": [
"tests-start"
diff --git a/wp-content/plugins/user-switching/readme.md b/wp-content/plugins/user-switching/readme.md
index 35efb1bd..d408c22f 100644
--- a/wp-content/plugins/user-switching/readme.md
+++ b/wp-content/plugins/user-switching/readme.md
@@ -1,7 +1,7 @@
# User Switching
-Stable tag: 1.8.0
-Tested up to: 6.6
+Stable tag: 1.9.0
+Tested up to: 6.7
License: GPL v2 or later
Tags: users, user switching, fast user switching, multisite, woocommerce
Contributors: johnbillion
@@ -250,6 +250,12 @@ One or more of the above should allow you to correlate an action with the origin
Bear in mind that even without the User Switching plugin in use, any user who has the ability to edit another user can still frame another user for an action by, for example, changing their password and manually logging into that account. If you are concerned about users abusing others, you should take great care when granting users administrative rights.
+### Does this plugin warn me if I attempt to switch into an account which somebody else is already switched into?
+
+Yes. When this happens you'll be shown a prompt asking you to confirm that you would like to continue switching to the affected account.
+
+This feature is useful if you have multiple users on your site who may be switching into other user accounts at the same time, for example a team of support agents.
+
### Can I switch users directly from the admin toolbar?
Yes, there's a third party add-on plugin for this: [Admin Bar User Switching](https://wordpress.org/plugins/admin-bar-user-switching/).
@@ -339,6 +345,11 @@ In addition, User Switching respects the following filters from WordPress core w
## Changelog ##
+### 1.9.0 (21 November 2024) ###
+
+* Introduces a confirmation message when a user attempts to switch into an account which somebody else is already switched into. Helpful for teams of support engineers who switch into customer accounts.
+* Various code quality improvements.
+
### 1.8.0 (22 July 2024) ###
* Adds a 'Switch back' link to some access denied messages within the admin area.
@@ -390,38 +401,6 @@ In addition, User Switching respects the following filters from WordPress core w
* Add a class to the table row on the user edit screen.
* Updated docs.
-### 1.5.5 (22 June 2020) ###
-
-* Added the `user_switching_in_footer` filter to disable output in footer on front end.
-* Documentation additions and improvements.
-
-### 1.5.4 (7 February 2020) ###
-
-* Fix a cookie issue caused by Jetpack 8.1.1 which prevented switching back to the original user.
-
-### 1.5.3 (5 November 2019) ###
-
-* Remove usage of a method that's been deprecated in WordPress 5.3
-
-### 1.5.2 (16 August 2019) ###
-
-* Set the correct `lang` attribute on User Switching's admin notice.
-* Move the WooCommerce session forgetting to an action callback so it can be unhooked if necessary.
-
-
-### 1.5.1 (16 June 2019) ###
-
- * Add appropriate HTTP response codes to the error states.
- * Display User Switching's messages in the original user's locale.
- * Increase the priority of the hook that sets up the cookie constants. See #40.
- * Don't attempt to output the 'Switch To' link on author archives when the queried object isn't a user. See #39.
-
-
-### 1.5.0 (23 March 2019) ###
-
-* Add support for forgetting WooCommerce sessions when switching between users. Requires WooCommerce 3.6+.
-
-
### Earlier versions ###
For the changelog of earlier versions, please refer to the releases page on GitHub.
\ No newline at end of file
diff --git a/wp-content/plugins/user-switching/user-switching.php b/wp-content/plugins/user-switching/user-switching.php
index 35bfeea6..2e7bee0e 100644
--- a/wp-content/plugins/user-switching/user-switching.php
+++ b/wp-content/plugins/user-switching/user-switching.php
@@ -10,14 +10,14 @@
*
* Plugin Name: User Switching
* Description: Instant switching between user accounts in WordPress
- * Version: 1.8.0
+ * Version: 1.9.0
* Plugin URI: https://wordpress.org/plugins/user-switching/
* Author: John Blackbourn
- * Author URI: https://github.com/johnbillion/user-switching
+ * Author URI: https://johnblackbourn.com
* Text Domain: user-switching
* Domain Path: /languages/
* Network: true
- * Requires at least: 5.8
+ * Requires at least: 5.9
* Requires PHP: 7.4
* License URI: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
@@ -39,13 +39,13 @@
/**
* Main singleton class for the User Switching plugin.
*/
-class user_switching {
+final class user_switching {
/**
* The name used to identify the application during a WordPress redirect.
*
* @var string
*/
- public static $application = 'WordPress/User Switching';
+ public static string $application = 'WordPress/User Switching';
const REDIRECT_TYPE_NONE = null;
const REDIRECT_TYPE_URL = 'url';
@@ -56,10 +56,8 @@ class user_switching {
/**
* Sets up all the filters and actions.
- *
- * @return void
*/
- public function init_hooks() {
+ public function init_hooks(): void {
// Required functionality:
add_filter( 'user_has_cap', [ $this, 'filter_user_has_cap' ], 10, 4 );
add_filter( 'map_meta_cap', [ $this, 'filter_map_meta_cap' ], 10, 4 );
@@ -99,10 +97,8 @@ public function init_hooks() {
/**
* Defines the names of the cookies used by User Switching.
- *
- * @return void
*/
- public function action_plugins_loaded() {
+ public function action_plugins_loaded(): void {
// User Switching's auth_cookie
if ( ! defined( 'USER_SWITCHING_COOKIE' ) ) {
define( 'USER_SWITCHING_COOKIE', 'wordpress_user_sw_' . COOKIEHASH );
@@ -123,9 +119,8 @@ public function action_plugins_loaded() {
* Outputs the 'Switch To' link on the user editing screen if the current user has permission to switch to them.
*
* @param WP_User $user User object for this screen.
- * @return void
*/
- public function action_personal_options( WP_User $user ) {
+ public function action_personal_options( WP_User $user ): void {
$link = self::maybe_switch_url( $user );
if ( ! $link ) {
@@ -153,7 +148,7 @@ public function action_personal_options( WP_User $user ) {
*
* @return bool Whether the current user is being 'remembered'.
*/
- public static function remember() {
+ public static function remember(): bool {
/** This filter is documented in wp-includes/pluggable.php */
$cookie_life = apply_filters( 'auth_cookie_expiration', 172800, get_current_user_id(), false );
$current = wp_parse_auth_cookie( '', 'logged_in' );
@@ -169,18 +164,14 @@ public static function remember() {
/**
* Loads localisation files and routes actions depending on the 'action' query var.
- *
- * @return void
*/
- public function action_init() {
+ public function action_init(): void {
load_plugin_textdomain( 'user-switching', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
if ( ! isset( $_REQUEST['action'] ) ) {
return;
}
- $current_user = ( is_user_logged_in() ) ? wp_get_current_user() : null;
-
switch ( $_REQUEST['action'] ) {
// We're attempting to switch to another user:
@@ -195,8 +186,53 @@ public function action_init() {
// Check intent:
check_admin_referer( "switch_to_user_{$user_id}" );
+ $current_user = wp_get_current_user();
+ $target = get_userdata( $user_id );
+
+ if ( ! $target ) {
+ wp_die( esc_html__( 'Could not switch users.', 'user-switching' ), 404 );
+ }
+
+ $duplicate = self::get_duplicated_switch( $target, $current_user );
+
+ if ( $duplicate && ! isset( $_GET['force_switch_user'] ) ) {
+ // Prevent Query Monitor from showing a stack trace for the wp_die() call:
+ // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
+ do_action( 'qm/cease' );
+
+ $message = sprintf(
+ /* Translators: 1: The name of the user who is currently switched to the target user, 2: The name of the target user, 3: Period of time (for example "5 minutes") */
+ __( '%1$s is currently switched to %2$s. They switched %3$s ago. Do you want to continue switching?', 'user-switching' ),
+ $duplicate['user']->display_name,
+ $target->display_name,
+ human_time_diff( $duplicate['login'] ),
+ );
+ $yes = sprintf(
+ /* Translators: %s is the name of the target user */
+ __( 'Yes, switch to %s', 'user-switching' ),
+ $target->display_name,
+ );
+ $no = __( 'No, go back', 'user-switching' );
+
+ wp_die(
+ sprintf(
+ '%1$s
%3$s %5$s',
+ esc_html( $message ),
+ esc_url( add_query_arg( 'force_switch_user', '1' ) ),
+ esc_html( $yes ),
+ 'javascript:history.back()',
+ esc_html( $no ),
+ ),
+ '',
+ [
+ 'response' => 409,
+ 'back_link' => false,
+ ],
+ );
+ }
+
// Switch user:
- $user = switch_to_user( $user_id, self::remember() );
+ $user = switch_to_user( $target->ID, self::remember() );
if ( $user ) {
$redirect_to = self::get_redirect( $user, $current_user );
@@ -234,11 +270,14 @@ public function action_init() {
// Check intent:
check_admin_referer( "switch_to_olduser_{$old_user->ID}" );
+ $current_user = wp_get_current_user();
+
// Switch user:
if ( switch_to_user( $old_user->ID, self::remember(), false ) ) {
if ( ! empty( $_REQUEST['interim-login'] ) && function_exists( 'login_header' ) ) {
- $GLOBALS['interim_login'] = 'success'; // @codingStandardsIgnoreLine
+ // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+ $GLOBALS['interim_login'] = 'success';
login_header( '', '' );
exit;
}
@@ -263,13 +302,15 @@ public function action_init() {
// We're attempting to switch off the current user:
case 'switch_off':
// Check authentication:
- if ( ! $current_user || ! current_user_can( 'switch_off' ) ) {
+ if ( ! current_user_can( 'switch_off' ) ) {
/* Translators: "switch off" means to temporarily log out */
wp_die( esc_html__( 'Could not switch off.', 'user-switching' ), 403 );
}
+ $current_user = wp_get_current_user();
+
// Check intent:
- check_admin_referer( "switch_off_{$current_user->ID}" );
+ check_admin_referer( 'switch_off' );
// Switch off:
if ( switch_off_user() ) {
@@ -293,14 +334,61 @@ public function action_init() {
}
}
+ /**
+ * Detects if the target user has any sessions that originated from another user switching into their account.
+ *
+ * Returns information about the first such session, if any.
+ *
+ * @param WP_User $target Target user.
+ * @param WP_User $ignore User to ignore when checking for duplicate switches.
+ * @return array|null {
+ * Information about the duplicate, or null if there is none.
+ *
+ * @type int $login The login time of the session that originated from another user.
+ * @type WP_User $user The user who switched into the target user's account.
+ * }
+ * @phpstan-return array{
+ * login: int,
+ * user: WP_User,
+ * }|null
+ */
+ public static function get_duplicated_switch( WP_User $target, WP_User $ignore ): ?array {
+ // Fetch the user sessions for the target user:
+ $sessions = WP_Session_Tokens::get_instance( $target->ID );
+
+ // Determine if any of the target user's sessions originated from another user:
+ $other_user_sessions = array_filter(
+ $sessions->get_all(),
+ static fn ( array $session ): bool => (
+ isset( $session['switched_from_id'] ) && $session['switched_from_id'] !== $ignore->ID
+ )
+ );
+
+ if ( empty( $other_user_sessions ) ) {
+ return null;
+ }
+
+ $session = reset( $other_user_sessions );
+ $switched_from_user = get_userdata( $session['switched_from_id'] );
+
+ if ( ! $switched_from_user ) {
+ return null;
+ }
+
+ return [
+ 'login' => $session['login'],
+ 'user' => $switched_from_user,
+ ];
+ }
+
/**
* Fetches the URL to redirect to for a given user (used after switching).
*
- * @param WP_User $new_user Optional. The new user's WP_User object.
- * @param WP_User $old_user Optional. The old user's WP_User object.
+ * @param WP_User $new_user Optional. The new user's WP_User object.
+ * @param WP_User $old_user Optional. The old user's WP_User object.
* @return string The URL to redirect to.
*/
- protected static function get_redirect( ?WP_User $new_user = null, ?WP_User $old_user = null ) {
+ protected static function get_redirect( ?WP_User $new_user = null, ?WP_User $old_user = null ): string {
$redirect_to = '';
$requested_redirect_to = '';
$redirect_type = self::REDIRECT_TYPE_NONE;
@@ -396,10 +484,8 @@ protected static function get_redirect( ?WP_User $new_user = null, ?WP_User $old
/**
* Displays the 'Switched to {user}' and 'Switch back to {user}' messages in the admin area.
- *
- * @return void
*/
- public function action_admin_notices() {
+ public function action_admin_notices(): void {
$user = wp_get_current_user();
$old_user = self::get_old_user();
@@ -504,7 +590,7 @@ public static function get_old_user() {
* @param WP_User $user A WP_User object (usually from the logged_in cookie).
* @return bool Whether verification with the auth cookie passed.
*/
- public static function authenticate_old_user( WP_User $user ) {
+ public static function authenticate_old_user( WP_User $user ): bool {
$cookie = user_switching_get_auth_cookie();
if ( ! empty( $cookie ) ) {
if ( self::secure_auth_cookie() ) {
@@ -526,9 +612,8 @@ public static function authenticate_old_user( WP_User $user ) {
* Adds a 'Switch back to {user}' link to the account menu, and a `Switch To` link to the user edit menu.
*
* @param WP_Admin_Bar $wp_admin_bar The admin bar object.
- * @return void
*/
- public function action_admin_bar_menu( WP_Admin_Bar $wp_admin_bar ) {
+ public function action_admin_bar_menu( WP_Admin_Bar $wp_admin_bar ): void {
if ( ! is_admin_bar_showing() ) {
return;
}
@@ -553,7 +638,7 @@ public function action_admin_bar_menu( WP_Admin_Bar $wp_admin_bar ) {
}
if ( current_user_can( 'switch_off' ) ) {
- $url = self::switch_off_url( wp_get_current_user() );
+ $url = self::switch_off_url();
$redirect_to = is_admin() ? self::get_admin_redirect_to() : [
'redirect_to' => rawurlencode( self::current_url() ),
];
@@ -641,7 +726,7 @@ public function action_shutdown_for_wp_die(): void {
*
* @return ?array
*/
- public static function get_admin_redirect_to() {
+ public static function get_admin_redirect_to(): ?array {
if ( ! empty( $_GET['post'] ) ) {
// Post
return [
@@ -669,10 +754,8 @@ public static function get_admin_redirect_to() {
/**
* Adds a 'Switch back to {user}' link to the Meta sidebar widget.
- *
- * @return void
*/
- public function action_wp_meta() {
+ public function action_wp_meta(): void {
$old_user = self::get_old_user();
if ( $old_user instanceof WP_User ) {
@@ -689,10 +772,8 @@ public function action_wp_meta() {
/**
* Adds a 'Switch back to {user}' link to the WordPress footer if the admin toolbar isn't showing.
- *
- * @return void
*/
- public function action_wp_footer() {
+ public function action_wp_footer(): void {
if ( is_admin_bar_showing() || did_action( 'wp_meta' ) ) {
return;
}
@@ -715,8 +796,10 @@ public function action_wp_footer() {
'redirect_to' => rawurlencode( self::current_url() ),
], self::switch_back_url( $old_user ) );
printf(
- '%s
',
+ '%s
',
+ 'position: fixed; bottom: 40px; padding: 0; margin: 0; left: 10px; font-size: 13px; z-index:99999;',
esc_url( $url ),
+ 'padding: 8px 10px; background: #fff; color: #3858e9;',
esc_html( self::switch_back_message( $old_user ) )
);
}
@@ -728,7 +811,7 @@ public function action_wp_footer() {
* @param string $message The login screen message.
* @return string The login screen message.
*/
- public function filter_login_message( $message ) {
+ public function filter_login_message( string $message ): string {
$old_user = self::get_old_user();
if ( $old_user instanceof WP_User ) {
@@ -764,7 +847,7 @@ public function filter_login_message( $message ) {
* @param WP_User $user The user object displayed in this row.
* @return array Array of actions to display for this user row.
*/
- public function filter_user_row_actions( array $actions, WP_User $user ) {
+ public function filter_user_row_actions( array $actions, WP_User $user ): array {
$link = self::maybe_switch_url( $user );
if ( ! $link ) {
@@ -782,10 +865,8 @@ public function filter_user_row_actions( array $actions, WP_User $user ) {
/**
* Adds a 'Switch To' link to each member's profile page and profile listings in BuddyPress.
- *
- * @return void
*/
- public function action_bp_button() {
+ public function action_bp_button(): void {
$user = null;
if ( bp_is_user() ) {
@@ -829,10 +910,8 @@ public function action_bp_button() {
/**
* Adds a 'Switch To' link to each member's profile page in bbPress.
- *
- * @return void
*/
- public function action_bbpress_button() {
+ public function action_bbpress_button(): void {
$user = get_userdata( bbp_get_user_id() );
if ( ! $user ) {
@@ -865,7 +944,7 @@ public function action_bbpress_button() {
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
* @return array An array of the plugin row's meta data.
*/
- public function filter_plugin_row_meta( array $plugin_meta, $plugin_file ) {
+ public function filter_plugin_row_meta( array $plugin_meta, $plugin_file ): array {
if ( 'user-switching/user-switching.php' !== $plugin_file ) {
return $plugin_meta;
}
@@ -887,7 +966,7 @@ public function filter_plugin_row_meta( array $plugin_meta, $plugin_file ) {
* @param array $args Array of removable query arguments.
* @return array Updated array of removable query arguments.
*/
- public function filter_removable_query_args( array $args ) {
+ public function filter_removable_query_args( array $args ): array {
return array_merge( $args, [
'user_switched',
'switched_off',
@@ -898,7 +977,7 @@ public function filter_removable_query_args( array $args ) {
/**
* Returns the switch to or switch back URL for a given user.
*
- * @param WP_User $user The user to be switched to.
+ * @param WP_User $user The user to be switched to.
* @return string|false The required URL, or false if there's no old user or the user doesn't have the required capability.
*/
public static function maybe_switch_url( WP_User $user ) {
@@ -916,10 +995,10 @@ public static function maybe_switch_url( WP_User $user ) {
/**
* Returns the nonce-secured URL needed to switch to a given user ID.
*
- * @param WP_User $user The user to be switched to.
+ * @param WP_User $user The user to be switched to.
* @return string The required URL.
*/
- public static function switch_to_url( WP_User $user ) {
+ public static function switch_to_url( WP_User $user ): string {
return wp_nonce_url( add_query_arg( [
'action' => 'switch_to_user',
'user_id' => $user->ID,
@@ -930,10 +1009,10 @@ public static function switch_to_url( WP_User $user ) {
/**
* Returns the nonce-secured URL needed to switch back to the originating user.
*
- * @param WP_User $user The old user.
- * @return string The required URL.
+ * @param WP_User $user The old user.
+ * @return string The required URL.
*/
- public static function switch_back_url( WP_User $user ) {
+ public static function switch_back_url( WP_User $user ): string {
return wp_nonce_url( add_query_arg( [
'action' => 'switch_to_olduser',
'nr' => 1,
@@ -943,14 +1022,15 @@ public static function switch_back_url( WP_User $user ) {
/**
* Returns the nonce-secured URL needed to switch off the current user.
*
- * @param WP_User $user The user to be switched off.
- * @return string The required URL.
+ * @since 1.9.0 The `$user` parameter has been removed as it's no longer needed.
+ *
+ * @return string The required URL.
*/
- public static function switch_off_url( WP_User $user ) {
+ public static function switch_off_url(): string {
return wp_nonce_url( add_query_arg( [
'action' => 'switch_off',
'nr' => 1,
- ], wp_login_url() ), "switch_off_{$user->ID}" );
+ ], wp_login_url() ), 'switch_off' );
}
/**
@@ -959,7 +1039,7 @@ public static function switch_off_url( WP_User $user ) {
* @param WP_User $user The concerned user.
* @return string The message.
*/
- public static function switched_to_message( WP_User $user ) {
+ public static function switched_to_message( WP_User $user ): string {
$message = sprintf(
/* Translators: 1: user display name; 2: username; */
__( 'Switched to %1$s (%2$s).', 'user-switching' ),
@@ -980,7 +1060,7 @@ public static function switched_to_message( WP_User $user ) {
* @param WP_User $user The concerned user.
* @return string The message.
*/
- public static function switch_back_message( WP_User $user ) {
+ public static function switch_back_message( WP_User $user ): string {
$message = sprintf(
/* Translators: 1: user display name; 2: username; */
__( 'Switch back to %1$s (%2$s)', 'user-switching' ),
@@ -1001,7 +1081,7 @@ public static function switch_back_message( WP_User $user ) {
* @param WP_User $user The concerned user.
* @return string The message.
*/
- public static function switched_back_message( WP_User $user ) {
+ public static function switched_back_message( WP_User $user ): string {
$message = sprintf(
/* Translators: 1: user display name; 2: username; */
__( 'Switched back to %1$s (%2$s).', 'user-switching' ),
@@ -1021,7 +1101,7 @@ public static function switched_back_message( WP_User $user ) {
*
* @return string The current URL.
*/
- public static function current_url() {
+ public static function current_url(): string {
return ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
}
@@ -1031,7 +1111,7 @@ public static function current_url() {
* @param string $url A URL.
* @return string The URL with query args removed.
*/
- public static function remove_query_args( $url ) {
+ public static function remove_query_args( $url ): string {
return remove_query_arg( wp_removable_query_args(), $url );
}
@@ -1044,7 +1124,7 @@ public static function remove_query_args( $url ) {
*
* @return bool Should the old user cookie be secure?
*/
- public static function secure_olduser_cookie() {
+ public static function secure_olduser_cookie(): bool {
return ( is_ssl() && ( 'https' === wp_parse_url( home_url(), PHP_URL_SCHEME ) ) );
}
@@ -1055,16 +1135,14 @@ public static function secure_olduser_cookie() {
*
* @return bool Whether the auth cookie should be secure.
*/
- public static function secure_auth_cookie() {
+ public static function secure_auth_cookie(): bool {
return ( is_ssl() && ( 'https' === wp_parse_url( wp_login_url(), PHP_URL_SCHEME ) ) );
}
/**
* Adds a 'Switch back to {user}' link to the WooCommerce login screen.
- *
- * @return void
*/
- public function action_woocommerce_login_form_start() {
+ public function action_woocommerce_login_form_start(): void {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $this->filter_login_message( '' );
}
@@ -1073,9 +1151,8 @@ public function action_woocommerce_login_form_start() {
* Adds a 'Switch To' link to the WooCommerce order screen.
*
* @param WC_Order $order The WooCommerce order object.
- * @return void
*/
- public function action_woocommerce_order_details( WC_Order $order ) {
+ public function action_woocommerce_order_details( WC_Order $order ): void {
$user = $order->get_user();
if ( ! $user || ! current_user_can( 'switch_to_user', $user->ID ) ) {
@@ -1099,7 +1176,7 @@ public function action_woocommerce_order_details( WC_Order $order ) {
* @param array $items Menu items.
* @return array Menu items.
*/
- public function filter_woocommerce_account_menu_items( array $items ) {
+ public function filter_woocommerce_account_menu_items( array $items ): array {
$old_user = self::get_old_user();
if ( ! $old_user ) {
@@ -1118,7 +1195,7 @@ public function filter_woocommerce_account_menu_items( array $items ) {
* @param string $endpoint The endpoint slug for the menu item.
* @return string The URL for the menu item.
*/
- public function filter_woocommerce_get_endpoint_url( $url, $endpoint ) {
+ public function filter_woocommerce_get_endpoint_url( string $url, string $endpoint ): string {
if ( 'user-switching-switch-back' !== $endpoint ) {
return $url;
}
@@ -1134,10 +1211,8 @@ public function filter_woocommerce_get_endpoint_url( $url, $endpoint ) {
/**
* Instructs WooCommerce to forget the session for the current user, without deleting it.
- *
- * @return void
*/
- public function forget_woocommerce_session() {
+ public function forget_woocommerce_session(): void {
if ( ! function_exists( 'WC' ) ) {
return;
}
@@ -1179,7 +1254,7 @@ public function forget_woocommerce_session() {
* @param WP_User $user Concerned user object.
* @return array Array of concerned user's capabilities.
*/
- public function filter_user_has_cap( array $user_caps, array $required_caps, array $args, WP_User $user ) {
+ public function filter_user_has_cap( array $user_caps, array $required_caps, array $args, WP_User $user ): array {
if ( 'switch_to_user' === $args[0] ) {
if ( empty( $args[2] ) ) {
$user_caps['switch_to_user'] = false;
@@ -1223,7 +1298,7 @@ public function filter_user_has_cap( array $user_caps, array $required_caps, arr
* }
* @return array Array of required capabilities for the requested action.
*/
- public function filter_map_meta_cap( array $required_caps, $cap, $user_id, array $args ) {
+ public function filter_map_meta_cap( array $required_caps, $cap, $user_id, array $args ): array {
if ( 'switch_to_user' === $cap ) {
if ( empty( $args[0] ) || $args[0] === $user_id ) {
$required_caps[] = 'do_not_allow';
@@ -1237,7 +1312,7 @@ public function filter_map_meta_cap( array $required_caps, $cap, $user_id, array
*
* @return user_switching User Switching instance.
*/
- public static function get_instance() {
+ public static function get_instance(): user_switching {
static $instance;
if ( ! isset( $instance ) ) {
@@ -1262,9 +1337,8 @@ private function __construct() {}
* @param int $old_user_id The ID of the originating user, usually the current logged in user.
* @param bool $pop Optional. Pop the latest user off the auth cookie, instead of appending the new one. Default false.
* @param string $token Optional. The old user's session token to store for later reuse. Default empty string.
- * @return void
*/
- function user_switching_set_olduser_cookie( $old_user_id, $pop = false, $token = '' ) {
+ function user_switching_set_olduser_cookie( $old_user_id, bool $pop = false, string $token = '' ): void {
$secure_auth_cookie = user_switching::secure_auth_cookie();
$secure_olduser_cookie = user_switching::secure_olduser_cookie();
$expiration = time() + 172800; // 48 hours
@@ -1340,9 +1414,8 @@ function user_switching_set_olduser_cookie( $old_user_id, $pop = false, $token =
* Clears the cookies containing the originating user, or pops the latest item off the end if there's more than one.
*
* @param bool $clear_all Optional. Whether to clear the cookies (as opposed to just popping the last user off the end). Default true.
- * @return void
*/
- function user_switching_clear_olduser_cookie( $clear_all = true ) {
+ function user_switching_clear_olduser_cookie( bool $clear_all = true ): void {
$auth_cookie = user_switching_get_auth_cookie();
if ( ! empty( $auth_cookie ) ) {
array_pop( $auth_cookie );
@@ -1361,8 +1434,8 @@ function user_switching_clear_olduser_cookie( $clear_all = true ) {
}
$expire = time() - 31536000;
- setcookie( USER_SWITCHING_COOKIE, ' ', $expire, SITECOOKIEPATH, COOKIE_DOMAIN );
- setcookie( USER_SWITCHING_SECURE_COOKIE, ' ', $expire, SITECOOKIEPATH, COOKIE_DOMAIN );
+ setcookie( USER_SWITCHING_COOKIE, ' ', $expire, SITECOOKIEPATH, COOKIE_DOMAIN );
+ setcookie( USER_SWITCHING_SECURE_COOKIE, ' ', $expire, SITECOOKIEPATH, COOKIE_DOMAIN );
setcookie( USER_SWITCHING_OLDUSER_COOKIE, ' ', $expire, COOKIEPATH, COOKIE_DOMAIN );
} else {
if ( user_switching::secure_auth_cookie() ) {
@@ -1406,7 +1479,7 @@ function user_switching_get_olduser_cookie() {
*
* @return array Array of originating user authentication cookie values. Empty array if there are none.
*/
- function user_switching_get_auth_cookie() {
+ function user_switching_get_auth_cookie(): array {
if ( user_switching::secure_auth_cookie() ) {
$auth_cookie_name = USER_SWITCHING_SECURE_COOKIE;
} else {
@@ -1432,7 +1505,7 @@ function user_switching_get_auth_cookie() {
* @param bool $set_old_user Optional. Whether to set the old user cookie. Default true.
* @return false|WP_User WP_User object on success, false on failure.
*/
- function switch_to_user( $user_id, $remember = false, $set_old_user = true ) {
+ function switch_to_user( $user_id, bool $remember = false, bool $set_old_user = true ) {
$user = get_userdata( $user_id );
if ( ! $user ) {
@@ -1461,7 +1534,7 @@ function switch_to_user( $user_id, $remember = false, $set_old_user = true ) {
* @param array $session Array of extra data.
* @return array Array of extra data.
*/
- $session_filter = function ( array $session ) use ( $old_user_id, $old_token ) {
+ $session_filter = static function ( array $session ) use ( $old_user_id, $old_token ): array {
$session['switched_from_id'] = $old_user_id;
$session['switched_from_session'] = $old_token;
return $session;
@@ -1523,7 +1596,7 @@ function switch_to_user( $user_id, $remember = false, $set_old_user = true ) {
*
* @return bool True on success, false on failure.
*/
- function switch_off_user() {
+ function switch_off_user(): bool {
$old_user_id = get_current_user_id();
if ( ! $old_user_id ) {