diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/LICENSE b/wp-content/upgrade-temp-backup/plugins/activitypub/LICENSE
new file mode 100644
index 00000000..644800f2
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/activitypub/LICENSE
@@ -0,0 +1,22 @@
+MIT License
+
+Copyright (c) 2019 Matthias Pfefferle
+Copyright (c) 2023 Automattic
+
+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.
diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/activitypub.php b/wp-content/upgrade-temp-backup/plugins/activitypub/activitypub.php
new file mode 100644
index 00000000..a6dca243
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/activitypub/activitypub.php
@@ -0,0 +1,206 @@
+register_routes();
+ ( new Rest\Actors_Inbox_Controller() )->register_routes();
+ ( new Rest\Application_Controller() )->register_routes();
+ ( new Rest\Collections_Controller() )->register_routes();
+ ( new Rest\Comments_Controller() )->register_routes();
+ ( new Rest\Followers_Controller() )->register_routes();
+ ( new Rest\Following_Controller() )->register_routes();
+ ( new Rest\Inbox_Controller() )->register_routes();
+ ( new Rest\Interaction_Controller() )->register_routes();
+ ( new Rest\Moderators_Controller() )->register_routes();
+ ( new Rest\Outbox_Controller() )->register_routes();
+ ( new Rest\Replies_Controller() )->register_routes();
+ ( new Rest\URL_Validator_Controller() )->register_routes();
+ ( new Rest\Webfinger_Controller() )->register_routes();
+
+ // Load NodeInfo endpoints only if blog is public.
+ if ( is_blog_public() ) {
+ ( new Rest\Nodeinfo_Controller() )->register_routes();
+ }
+}
+\add_action( 'rest_api_init', __NAMESPACE__ . '\rest_init' );
+
+/**
+ * Initialize plugin.
+ */
+function plugin_init() {
+ \add_action( 'init', array( __NAMESPACE__ . '\Activitypub', 'init' ) );
+ \add_action( 'init', array( __NAMESPACE__ . '\Comment', 'init' ) );
+ \add_action( 'init', array( __NAMESPACE__ . '\Dispatcher', 'init' ) );
+ \add_action( 'init', array( __NAMESPACE__ . '\Handler', 'init' ) );
+ \add_action( 'init', array( __NAMESPACE__ . '\Hashtag', 'init' ) );
+ \add_action( 'init', array( __NAMESPACE__ . '\Link', 'init' ) );
+ \add_action( 'init', array( __NAMESPACE__ . '\Mailer', 'init' ) );
+ \add_action( 'init', array( __NAMESPACE__ . '\Mention', 'init' ) );
+ \add_action( 'init', array( __NAMESPACE__ . '\Migration', 'init' ), 1 );
+ \add_action( 'init', array( __NAMESPACE__ . '\Move', 'init' ) );
+ \add_action( 'init', array( __NAMESPACE__ . '\Options', 'init' ) );
+ \add_action( 'init', array( __NAMESPACE__ . '\Scheduler', 'init' ) );
+
+ if ( site_supports_blocks() ) {
+ \add_action( 'init', array( __NAMESPACE__ . '\Blocks', 'init' ) );
+ }
+
+ $debug_file = __DIR__ . '/includes/debug.php';
+ if ( \WP_DEBUG && file_exists( $debug_file ) && is_readable( $debug_file ) ) {
+ require_once $debug_file;
+ Debug::init();
+ }
+}
+\add_action( 'plugins_loaded', __NAMESPACE__ . '\plugin_init' );
+
+/**
+ * Initialize plugin admin.
+ */
+function plugin_admin_init() {
+ // Menus are registered before `admin_init`, because of course they are.
+ \add_action( 'admin_menu', array( __NAMESPACE__ . '\WP_Admin\Menu', 'admin_menu' ) );
+ \add_action( 'admin_init', array( __NAMESPACE__ . '\WP_Admin\Admin', 'init' ) );
+ \add_action( 'admin_init', array( __NAMESPACE__ . '\WP_Admin\Health_Check', 'init' ) );
+ \add_action( 'admin_init', array( __NAMESPACE__ . '\WP_Admin\Settings', 'init' ) );
+ \add_action( 'admin_init', array( __NAMESPACE__ . '\WP_Admin\Settings_Fields', 'init' ) );
+ \add_action( 'admin_init', array( __NAMESPACE__ . '\WP_Admin\Welcome_Fields', 'init' ) );
+ \add_action( 'admin_init', array( __NAMESPACE__ . '\WP_Admin\Advanced_Settings_Fields', 'init' ) );
+ \add_action( 'admin_init', array( __NAMESPACE__ . '\WP_Admin\Blog_Settings_Fields', 'init' ) );
+ \add_action( 'admin_init', array( __NAMESPACE__ . '\WP_Admin\User_Settings_Fields', 'init' ) );
+
+ if ( defined( 'WP_LOAD_IMPORTERS' ) && WP_LOAD_IMPORTERS ) {
+ require_once __DIR__ . '/includes/wp-admin/import/load.php';
+ \add_action( 'admin_init', __NAMESPACE__ . '\WP_Admin\Import\load' );
+ }
+}
+\add_action( 'plugins_loaded', __NAMESPACE__ . '\plugin_admin_init' );
+
+\register_activation_hook(
+ __FILE__,
+ array(
+ __NAMESPACE__ . '\Activitypub',
+ 'activate',
+ )
+);
+
+/**
+ * Redirect to the welcome page after plugin activation.
+ *
+ * @param string $plugin The plugin basename.
+ */
+function activation_redirect( $plugin ) {
+ if ( ACTIVITYPUB_PLUGIN_BASENAME === $plugin ) {
+ \wp_safe_redirect( \admin_url( 'options-general.php?page=activitypub' ) );
+ exit;
+ }
+}
+\add_action( 'activated_plugin', __NAMESPACE__ . '\activation_redirect' );
+
+\register_deactivation_hook(
+ __FILE__,
+ array(
+ __NAMESPACE__ . '\Activitypub',
+ 'deactivate',
+ )
+);
+
+\register_uninstall_hook(
+ __FILE__,
+ array(
+ __NAMESPACE__ . '\Activitypub',
+ 'uninstall',
+ )
+);
+
+
+/**
+ * `get_plugin_data` wrapper.
+ *
+ * @deprecated 4.2.0 Use `get_plugin_data` instead.
+ *
+ * @param array $default_headers Optional. The default plugin headers. Default empty array.
+ * @return array The plugin metadata array.
+ */
+function get_plugin_meta( $default_headers = array() ) {
+ _deprecated_function( __FUNCTION__, '4.2.0', 'get_plugin_data' );
+
+ if ( ! $default_headers ) {
+ $default_headers = array(
+ 'Name' => 'Plugin Name',
+ 'PluginURI' => 'Plugin URI',
+ 'Version' => 'Version',
+ 'Description' => 'Description',
+ 'Author' => 'Author',
+ 'AuthorURI' => 'Author URI',
+ 'TextDomain' => 'Text Domain',
+ 'DomainPath' => 'Domain Path',
+ 'Network' => 'Network',
+ 'RequiresWP' => 'Requires at least',
+ 'RequiresPHP' => 'Requires PHP',
+ 'UpdateURI' => 'Update URI',
+ );
+ }
+
+ return \get_file_data( __FILE__, $default_headers, 'plugin' );
+}
+
+/**
+ * Plugin Version Number used for caching.
+ *
+ * @deprecated 4.2.0 Use constant ACTIVITYPUB_PLUGIN_VERSION directly.
+ */
+function get_plugin_version() {
+ _deprecated_function( __FUNCTION__, '4.2.0', 'ACTIVITYPUB_PLUGIN_VERSION' );
+
+ return ACTIVITYPUB_PLUGIN_VERSION;
+}
+
+// Check for CLI env, to add the CLI commands.
+if ( defined( 'WP_CLI' ) && WP_CLI ) {
+ WP_CLI::add_command(
+ 'activitypub',
+ '\Activitypub\Cli',
+ array(
+ 'shortdesc' => 'ActivityPub related commands to manage plugin functionality and the federation of posts and comments.',
+ )
+ );
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/assets/css/activitypub-admin.css b/wp-content/upgrade-temp-backup/plugins/activitypub/assets/css/activitypub-admin.css
new file mode 100644
index 00000000..2e181f2a
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/activitypub/assets/css/activitypub-admin.css
@@ -0,0 +1,272 @@
+.activitypub-settings {
+ max-width: 800px;
+ margin: 0 auto;
+ position: relative;
+}
+
+.settings_page_activitypub .notice {
+ max-width: 800px;
+ margin: 0 auto 30px;
+}
+
+.settings_page_activitypub .update-nag {
+ margin: 25px 20px 15px 22px;
+}
+
+.settings_page_activitypub .wrap {
+ padding-left: 22px;
+}
+
+.activitypub-settings-header {
+ text-align: center;
+ margin: 0 0 1rem;
+ background: #fff;
+ border-bottom: 1px solid #dcdcde;
+}
+
+.activitypub-settings-header h1 {
+ display: inline-block;
+ font-weight: 600;
+ margin: 0 0.8rem 1rem;
+ font-size: 23px;
+ padding: 9px 0 4px;
+ line-height: 1.3;
+}
+
+.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: inline-flex;
+ vertical-align: top;
+ flex-wrap: nowrap;
+ gap: 0;
+}
+
+.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;
+}
+
+.activitypub-settings .row {
+ margin-bottom: 16px;
+}
+
+.activitypub-settings .row > div {
+ max-width: calc(100% - 24px);
+ display: inline-flex;
+ flex-direction: column;
+}
+
+.activitypub-settings .row .description {
+ margin-top: 0;
+}
+
+.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;
+}
+
+.activitypub-settings
+input.blog-user-identifier {
+ text-align: right;
+}
+
+.activitypub-settings
+.header-image {
+ width: 100%;
+ height: 80px;
+ position: relative;
+ display: block;
+ margin-bottom: 40px;
+ background-image: rgb(168,165,175);
+ background-image: linear-gradient(180deg, red, yellow);
+ background-size: cover;
+}
+
+.activitypub-settings .logo {
+ height: 80px;
+ width: 80px;
+ position: relative;
+ top: 40px;
+ left: 40px;
+}
+
+.settings_page_activitypub .plugin-recommendations {
+ border-bottom: none;
+ margin-bottom: 0;
+}
+
+#dashboard_right_now li a.activitypub-followers::before {
+ content: "\f307";
+ font-family: dashicons;
+}
+
+.repost .dashboard-comment-wrap,
+.like .dashboard-comment-wrap {
+ padding-inline-start: 63px;
+}
+
+.repost .dashboard-comment-wrap .comment-author,
+.like .dashboard-comment-wrap .comment-author {
+ margin-block: 0;
+}
+
+.activitypub-settings .welcome-tab-close {
+ position: absolute;
+ top: 0px;
+ right: 0px;
+ font-size: 13px;
+ padding: 0 5px 0 20px;
+ text-decoration: none;
+ z-index: 1;
+}
+
+.activitypub-settings .welcome-tab-close::before {
+ position: absolute;
+ top: 0px;
+ left: 0;
+ transition: all .1s ease-in-out;
+ font: normal 16px/20px dashicons;
+ content: '\f335';
+ font-size: 20px;
+}
+
+.activitypub-notice .count {
+ display: inline-block;
+ vertical-align: top;
+ box-sizing: border-box;
+ margin: 1px 0 -1px 2px;
+ padding: 0 5px;
+ min-width: 18px;
+ height: 18px;
+ border-radius: 9px;
+ background-color: #dba617;
+ color: #fff;
+ font-size: 11px;
+ line-height: 1.6;
+ text-align: center;
+ z-index: 26;
+}
+
+.activitypub-notice .dashicons-warning {
+ color: #dba617;
+}
+
+.extra-fields-nav a + a {
+ margin-left: 8px;
+}
+.rtl .extra-fields-nav a + a {
+ margin-left: auto;
+ margin-right: 8px;
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/assets/css/activitypub-embed.css b/wp-content/upgrade-temp-backup/plugins/activitypub/assets/css/activitypub-embed.css
new file mode 100644
index 00000000..0422fb40
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/activitypub/assets/css/activitypub-embed.css
@@ -0,0 +1,115 @@
+/**
+ * ActivityPub embed styles.
+ */
+
+.activitypub-embed {
+ background: #fff;
+ border: 1px solid #e6e6e6;
+ border-radius: 12px;
+ padding: 0;
+ max-width: 100%;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
+}
+
+.activitypub-reply-block .activitypub-embed {
+ margin: 1em 0;
+}
+
+.activitypub-embed-header {
+ padding: 15px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.activitypub-embed-header img {
+ width: 48px;
+ height: 48px;
+ border-radius: 50%;
+}
+
+.activitypub-embed-header-text {
+ flex-grow: 1;
+}
+
+.activitypub-embed-header-text h2 {
+ color: #000;
+ font-size: 15px;
+ font-weight: 600;
+ margin: 0;
+ padding: 0;
+}
+
+.activitypub-embed-header-text .ap-account {
+ color: #687684;
+ font-size: 14px;
+ text-decoration: none;
+}
+
+.activitypub-embed-content {
+ padding: 0 15px 15px;
+}
+
+.activitypub-embed-content .ap-title {
+ font-size: 23px;
+ font-weight: 600;
+ margin: 0 0 10px;
+ padding: 0;
+ color: #000;
+}
+
+.activitypub-embed-content .ap-subtitle {
+ font-size: 15px;
+ color: #000;
+ margin: 0 0 15px;
+}
+
+.activitypub-embed-content .ap-preview {
+ border: 1px solid #e6e6e6;
+ border-radius: 8px;
+ overflow: hidden;
+}
+
+.activitypub-embed-content .ap-preview img {
+ width: 100%;
+ height: auto;
+ display: block;
+}
+
+.activitypub-embed-content .ap-preview-text {
+ padding: 15px;
+}
+
+.activitypub-embed-meta {
+ padding: 15px;
+ border-top: 1px solid #e6e6e6;
+ color: #687684;
+ font-size: 13px;
+ display: flex;
+ gap: 15px;
+}
+
+.activitypub-embed-meta .ap-stat {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+}
+@media only screen and (max-width: 399px) {
+ .activitypub-embed-meta span.ap-stat {
+ display: none !important;
+ }
+}
+
+.activitypub-embed-meta a.ap-stat {
+ color: inherit;
+ text-decoration: none;
+}
+
+.activitypub-embed-meta strong {
+ font-weight: 600;
+ color: #000;
+}
+
+.activitypub-embed-meta .ap-stat-label {
+ color: #687684;
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/assets/img/mp.jpg b/wp-content/upgrade-temp-backup/plugins/activitypub/assets/img/mp.jpg
new file mode 100644
index 00000000..05964b49
Binary files /dev/null and b/wp-content/upgrade-temp-backup/plugins/activitypub/assets/img/mp.jpg differ
diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/assets/img/wp-logo.png b/wp-content/upgrade-temp-backup/plugins/activitypub/assets/img/wp-logo.png
new file mode 100644
index 00000000..b48f08e8
Binary files /dev/null and b/wp-content/upgrade-temp-backup/plugins/activitypub/assets/img/wp-logo.png differ
diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/assets/js/activitypub-admin.js b/wp-content/upgrade-temp-backup/plugins/activitypub/assets/js/activitypub-admin.js
new file mode 100644
index 00000000..37117cab
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/activitypub/assets/js/activitypub-admin.js
@@ -0,0 +1,21 @@
+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 );
+ } );
+
+} );
diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/assets/js/activitypub-header-image.js b/wp-content/upgrade-temp-backup/plugins/activitypub/assets/js/activitypub-header-image.js
new file mode 100644
index 00000000..d43af9e9
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/activitypub/assets/js/activitypub-header-image.js
@@ -0,0 +1,271 @@
+/**
+ * Handle the header image setting in
+ *
+ * This is based on site-icon.js
+ *
+ * @see wp-admin/js/site-icon.js
+ */
+
+/* global jQuery, wp */
+
+( function ( $ ) {
+ var $chooseButton = $( '#activitypub-choose-from-library-button' ),
+ $headerImagePreviewWrapper = $( '#activitypub-header-image-preview-wrapper' ),
+ $headerImagePreview = $( '#activitypub-header-image-preview' ),
+ $hiddenDataField = $( '#activitypub_header_image' ),
+ $removeButton = $( '#activitypub-remove-header-image' ),
+ frame,
+ ImageCropperNoCustomizer;
+
+ /**
+ * We register our own handler because the Core one invokes the Customizer, which fails the request unnecessarily
+ * for users who don't have the 'customize' capability.
+ * See https://github.com/Automattic/wordpress-activitypub/issues/846
+ */
+ ImageCropperNoCustomizer = wp.media.controller.CustomizeImageCropper.extend( {
+ doCrop: function( attachment ) {
+ var cropDetails = attachment.get( 'cropDetails' ),
+ control = this.get( 'control' ),
+ ratio = cropDetails.width / cropDetails.height;
+
+ // Use crop measurements when flexible in both directions.
+ if ( control.params.flex_width && control.params.flex_height ) {
+ cropDetails.dst_width = cropDetails.width;
+ cropDetails.dst_height = cropDetails.height;
+
+ // Constrain flexible side based on image ratio and size of the fixed side.
+ } else {
+ cropDetails.dst_width = control.params.flex_width ? control.params.height * ratio : control.params.width;
+ cropDetails.dst_height = control.params.flex_height ? control.params.width / ratio : control.params.height;
+ }
+
+ return wp.ajax.post( 'crop-image', {
+ // where wp_customize: 'on' would be in Core, for no good reason I understand.
+ nonce: attachment.get( 'nonces' ).edit,
+ id: attachment.get( 'id' ),
+ context: control.id,
+ cropDetails: cropDetails
+ } );
+ }
+ } );
+
+
+
+ /**
+ * Calculate image selection options based on the attachment dimensions.
+ *
+ * @since 6.5.0
+ *
+ * @param {Object} attachment The attachment object representing the image.
+ * @return {Object} The image selection options.
+ */
+ function calculateImageSelectOptions( attachment ) {
+ var realWidth = attachment.get( 'width' ),
+ realHeight = attachment.get( 'height' ),
+ xInit = 1500,
+ yInit = 500,
+ ratio = xInit / yInit,
+ xImg = xInit,
+ yImg = yInit,
+ x1,
+ y1,
+ imgSelectOptions;
+
+ if ( realWidth / realHeight > ratio ) {
+ yInit = realHeight;
+ xInit = yInit * ratio;
+ } else {
+ xInit = realWidth;
+ yInit = xInit / ratio;
+ }
+
+ x1 = ( realWidth - xInit ) / 2;
+ y1 = ( realHeight - yInit ) / 2;
+
+ imgSelectOptions = {
+ aspectRatio: xInit + ':' + yInit,
+ handles: true,
+ keys: true,
+ instance: true,
+ persistent: true,
+ imageWidth: realWidth,
+ imageHeight: realHeight,
+ minWidth: xImg > xInit ? xInit : xImg,
+ minHeight: yImg > yInit ? yInit : yImg,
+ x1: x1,
+ y1: y1,
+ x2: xInit + x1,
+ y2: yInit + y1,
+ };
+
+ return imgSelectOptions;
+ }
+
+ /**
+ * Initializes the media frame for selecting or cropping an image.
+ *
+ * @since 6.5.0
+ */
+ $chooseButton.on( 'click', function () {
+ var $el = $( this );
+ var userId = $el.data( 'userId' );
+ var mediaQuery = { type: 'image' };
+ if ( userId ) {
+ mediaQuery.author = userId;
+ }
+
+ // Create the media frame.
+ frame = wp.media( {
+ button: {
+ // Set the text of the button.
+ text: $el.data( 'update' ),
+
+ // Don't close, we might need to crop.
+ close: false,
+ },
+ states: [
+ new wp.media.controller.Library( {
+ title: $el.data( 'choose-text' ),
+ library: wp.media.query( mediaQuery ),
+ date: false,
+ suggestedWidth: $el.data( 'width' ),
+ suggestedHeight: $el.data( 'height' ),
+ } ),
+ new ImageCropperNoCustomizer( {
+ control: {
+ id: 'activitypub-header-image',
+ params: {
+ width: $el.data( 'width' ),
+ height: $el.data( 'height' ),
+ },
+ },
+ imgSelectOptions: calculateImageSelectOptions,
+ } ),
+ ],
+ } );
+
+ frame.on( 'cropped', function ( attachment ) {
+ $hiddenDataField.val( attachment.id );
+ switchToUpdate( attachment );
+ frame.close();
+
+ // Start over with a frame that is so fresh and so clean clean.
+ frame = null;
+ } );
+
+ // When an image is selected, run a callback.
+ frame.on( 'select', function () {
+ // Grab the selected attachment.
+ var attachment = frame.state().get( 'selection' ).first(),
+ targetRatio = $el.data( 'width' ) / $el.data( 'height' ),
+ currentRatio = attachment.attributes.width / attachment.attributes.height,
+ alreadyCropped = false;
+
+ // Check if the image already has the correct aspect ratio (with a small tolerance).
+ if ( Math.abs( currentRatio - targetRatio ) < 0.01 ) {
+ // Check if this is the same image that was already selected.
+ if ( attachment.id !== parseInt( $hiddenDataField.val(), 10 ) ) {
+ // This is a new image with the correct aspect ratio.
+ $hiddenDataField.val( attachment.id );
+ }
+
+ alreadyCropped = true;
+ }
+
+ if ( alreadyCropped ) {
+ // Skip cropping for already cropped images.
+ switchToUpdate( attachment.attributes );
+ frame.close();
+ } else {
+ frame.setState( 'cropper' );
+ }
+ } );
+
+ frame.open();
+ } );
+
+ /**
+ * Update the UI when a header is selected.
+ *
+ * @since 6.5.0
+ *
+ * @param {array} attributes The attributes for the attachment.
+ */
+ function switchToUpdate( attributes ) {
+ var i18nAppAlternativeString, i18nBrowserAlternativeString;
+
+ if ( attributes.alt ) {
+ i18nBrowserAlternativeString = wp.i18n.sprintf(
+ /* translators: %s: The selected image alt text. */
+ wp.i18n.__( 'Header Image preview: Current image: %s' ),
+ attributes.alt
+ );
+ } else {
+ i18nAppAlternativeString = wp.i18n.sprintf(
+ /* translators: %s: The selected image filename. */
+ wp.i18n.__(
+ 'Header Image preview: The current image has no alternative text. The file name is: %s'
+ ),
+ attributes.filename
+ );
+ i18nBrowserAlternativeString = wp.i18n.sprintf(
+ /* translators: %s: The selected image filename. */
+ wp.i18n.__(
+ 'Header Image preview: The current image has no alternative text. The file name is: %s'
+ ),
+ attributes.filename
+ );
+ }
+
+ // Set activitypub-header-image-preview src.
+ $headerImagePreview.attr( {
+ src: attributes.url,
+ alt: i18nAppAlternativeString,
+ } );
+
+ // Remove hidden class from header image preview div and remove button.
+ $headerImagePreviewWrapper.removeClass( 'hidden' );
+ $removeButton.removeClass( 'hidden' );
+
+ // If the choose button is not in the update state, swap the classes.
+ if ( $chooseButton.attr( 'data-state' ) !== '1' ) {
+ $chooseButton.attr( {
+ class: $chooseButton.attr( 'data-alt-classes' ),
+ 'data-alt-classes': $chooseButton.attr( 'class' ),
+ 'data-state': '1',
+ } );
+ }
+
+ // Swap the text of the choose button.
+ $chooseButton.text( $chooseButton.attr( 'data-update-text' ) );
+ }
+
+ /**
+ * Handles the click event of the remove button.
+ *
+ * @since 6.5.0
+ */
+ $removeButton.on( 'click', function () {
+ $hiddenDataField.val( 'false' );
+ $( this ).toggleClass( 'hidden' );
+ $headerImagePreviewWrapper.toggleClass( 'hidden' );
+ $headerImagePreview.attr( {
+ src: '',
+ alt: '',
+ } );
+
+ /**
+ * Resets state to the button, for correct visual style and state.
+ * Updates the text of the button.
+ * Sets focus state to the button.
+ */
+ $chooseButton
+ .attr( {
+ class: $chooseButton.attr( 'data-alt-classes' ),
+ 'data-alt-classes': $chooseButton.attr( 'class' ),
+ 'data-state': '',
+ } )
+ .text( $chooseButton.attr( 'data-choose-text' ) )
+ .trigger( 'focus' );
+ } );
+} )( jQuery );
diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/build/editor-plugin/block.json b/wp-content/upgrade-temp-backup/plugins/activitypub/build/editor-plugin/block.json
new file mode 100644
index 00000000..f41effc5
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/activitypub/build/editor-plugin/block.json
@@ -0,0 +1,8 @@
+{
+ "name": "editor-plugin",
+ "title": "Editor Plugin: not a block, but block.json is very useful.",
+ "category": "widgets",
+ "icon": "admin-comments",
+ "keywords": [],
+ "editorScript": "file:./plugin.js"
+}
\ No newline at end of file
diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/build/editor-plugin/plugin.asset.php b/wp-content/upgrade-temp-backup/plugins/activitypub/build/editor-plugin/plugin.asset.php
new file mode 100644
index 00000000..b753ae85
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/activitypub/build/editor-plugin/plugin.asset.php
@@ -0,0 +1 @@
+ array('react', 'wp-components', 'wp-core-data', 'wp-data', 'wp-editor', 'wp-element', 'wp-i18n', 'wp-plugins', 'wp-primitives', 'wp-url'), 'version' => '293b8e75ac7a589c5096');
diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/build/editor-plugin/plugin.js b/wp-content/upgrade-temp-backup/plugins/activitypub/build/editor-plugin/plugin.js
new file mode 100644
index 00000000..cad41787
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/activitypub/build/editor-plugin/plugin.js
@@ -0,0 +1 @@
+(()=>{"use strict";var e={20:(e,t,i)=>{var n=i(609),o=Symbol.for("react.element"),r=(Symbol.for("react.fragment"),Object.prototype.hasOwnProperty),l=n.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,a={key:!0,ref:!0,__self:!0,__source:!0};t.jsx=function(e,t,i){var n,c={},s=null,p=null;for(n in void 0!==i&&(s=""+i),void 0!==t.key&&(s=""+t.key),void 0!==t.ref&&(p=t.ref),t)r.call(t,n)&&!a.hasOwnProperty(n)&&(c[n]=t[n]);if(e&&e.defaultProps)for(n in t=e.defaultProps)void 0===c[n]&&(c[n]=t[n]);return{$$typeof:o,type:e,key:s,ref:p,props:c,_owner:l.current}}},848:(e,t,i)=>{e.exports=i(20)},609:e=>{e.exports=window.React}},t={};function i(n){var o=t[n];if(void 0!==o)return o.exports;var r=t[n]={exports:{}};return e[n](r,r.exports,i),r.exports}var n=i(609);const o=window.wp.editor,r=window.wp.plugins,l=window.wp.components,a=window.wp.element,c=(0,a.forwardRef)((function({icon:e,size:t=24,...i},n){return(0,a.cloneElement)(e,{width:t,height:t,...i,ref:n})})),s=window.wp.primitives;var p=i(848);const u=(0,p.jsx)(s.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",children:(0,p.jsx)(s.Path,{d:"M12 3.3c-4.8 0-8.8 3.9-8.8 8.8 0 4.8 3.9 8.8 8.8 8.8 4.8 0 8.8-3.9 8.8-8.8s-4-8.8-8.8-8.8zm6.5 5.5h-2.6C15.4 7.3 14.8 6 14 5c2 .6 3.6 2 4.5 3.8zm.7 3.2c0 .6-.1 1.2-.2 1.8h-2.9c.1-.6.1-1.2.1-1.8s-.1-1.2-.1-1.8H19c.2.6.2 1.2.2 1.8zM12 18.7c-1-.7-1.8-1.9-2.3-3.5h4.6c-.5 1.6-1.3 2.9-2.3 3.5zm-2.6-4.9c-.1-.6-.1-1.1-.1-1.8 0-.6.1-1.2.1-1.8h5.2c.1.6.1 1.1.1 1.8s-.1 1.2-.1 1.8H9.4zM4.8 12c0-.6.1-1.2.2-1.8h2.9c-.1.6-.1 1.2-.1 1.8 0 .6.1 1.2.1 1.8H5c-.2-.6-.2-1.2-.2-1.8zM12 5.3c1 .7 1.8 1.9 2.3 3.5H9.7c.5-1.6 1.3-2.9 2.3-3.5zM10 5c-.8 1-1.4 2.3-1.8 3.8H5.5C6.4 7 8 5.6 10 5zM5.5 15.3h2.6c.4 1.5 1 2.8 1.8 3.7-1.8-.6-3.5-2-4.4-3.7zM14 19c.8-1 1.4-2.2 1.8-3.7h2.6C17.6 17 16 18.4 14 19z"})}),v=(0,p.jsx)(s.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",children:(0,p.jsx)(s.Path,{d:"M15.5 9.5a1 1 0 100-2 1 1 0 000 2zm0 1.5a2.5 2.5 0 100-5 2.5 2.5 0 000 5zm-2.25 6v-2a2.75 2.75 0 00-2.75-2.75h-4A2.75 2.75 0 003.75 15v2h1.5v-2c0-.69.56-1.25 1.25-1.25h4c.69 0 1.25.56 1.25 1.25v2h1.5zm7-2v2h-1.5v-2c0-.69-.56-1.25-1.25-1.25H15v-1.5h2.5A2.75 2.75 0 0120.25 15zM9.5 8.5a1 1 0 11-2 0 1 1 0 012 0zm1.5 0a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0z",fillRule:"evenodd"})}),w=(0,p.jsx)(s.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",children:(0,p.jsx)(s.Path,{d:"M19.5 4.5h-7V6h4.44l-5.97 5.97 1.06 1.06L18 7.06v4.44h1.5v-7Zm-13 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-3H17v3a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h3V5.5h-3Z"})}),d=window.wp.data,_=window.wp.coreData,b=window.wp.url,h=window.wp.i18n,y=(0,n.createElement)(s.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24"},(0,n.createElement)(s.Path,{fillRule:"evenodd",clipRule:"evenodd",d:"M12 18.5A6.5 6.5 0 0 1 6.93 7.931l9.139 9.138A6.473 6.473 0 0 1 12 18.5Zm5.123-2.498a6.5 6.5 0 0 0-9.124-9.124l9.124 9.124ZM4 12a8 8 0 1 1 16 0 8 8 0 0 1-16 0Z"}));(0,r.registerPlugin)("activitypub-editor-plugin",{render:()=>{const e=(0,d.useSelect)((e=>e("core/editor").getCurrentPostType()),[]),[t,i]=(0,_.useEntityProp)("postType",e,"meta"),r={verticalAlign:"middle",gap:"4px",justifyContent:"start",display:"inline-flex",alignItems:"center"},a=(e,t,i)=>(0,n.createElement)(l.Tooltip,{text:i},(0,n.createElement)(l.__experimentalText,{style:r},(0,n.createElement)(c,{icon:e}),t));return"wp_block"===e?null:(0,n.createElement)(o.PluginDocumentSettingPanel,{name:"activitypub",title:(0,h.__)("Fediverse ⁂","activitypub")},(0,n.createElement)(l.TextControl,{label:(0,h.__)("Content Warning","activitypub"),value:t?.activitypub_content_warning,onChange:e=>{i({...t,activitypub_content_warning:e})},placeholder:(0,h.__)("Optional content warning","activitypub"),help:(0,h.__)("Content warnings do not change the content on your site, only in the fediverse.","activitypub")}),(0,n.createElement)(l.RadioControl,{label:(0,h.__)("Visibility","activitypub"),help:(0,h.__)("This adjusts the visibility of a post in the fediverse, but note that it won't affect how the post appears on the blog.","activitypub"),selected:t?.activitypub_content_visibility||"public",options:[{label:a(u,(0,h.__)("Public","activitypub"),(0,h.__)("Post will be visible to everyone and appear in public timelines.","activitypub")),value:"public"},{label:a(v,(0,h.__)("Quiet public","activitypub"),(0,h.__)("Post will be visible to everyone but will not appear in public timelines.","activitypub")),value:"quiet_public"},{label:a(y,(0,h.__)("Do not federate","activitypub"),(0,h.__)("Post will not be shared to the Fediverse.","activitypub")),value:"local"}],onChange:e=>{i({...t,activitypub_content_visibility:e})},className:"activitypub-visibility"}))}}),(0,r.registerPlugin)("activitypub-editor-preview",{render:()=>{const e=(0,d.useSelect)((e=>e("core/editor").getCurrentPost().status));return(0,n.createElement)(n.Fragment,null,o.PluginPreviewMenuItem?(0,n.createElement)(o.PluginPreviewMenuItem,{onClick:()=>function(){const e=(0,d.select)("core/editor").getEditedPostPreviewLink(),t=(0,b.addQueryArgs)(e,{activitypub:"true"});window.open(t,"_blank")}(),icon:w,disabled:"auto-draft"===e},(0,h.__)("Fediverse preview ⁂","activitypub")):null)}})})();
\ No newline at end of file
diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/build/follow-me/block.json b/wp-content/upgrade-temp-backup/plugins/activitypub/build/follow-me/block.json
new file mode 100644
index 00000000..e799fbb5
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/activitypub/build/follow-me/block.json
@@ -0,0 +1,68 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "name": "activitypub/follow-me",
+ "apiVersion": 3,
+ "version": "1.0.0",
+ "title": "Follow me on the Fediverse",
+ "category": "widgets",
+ "description": "Display your Fediverse profile so that visitors can follow you.",
+ "textdomain": "activitypub",
+ "icon": "groups",
+ "supports": {
+ "html": false,
+ "color": {
+ "gradients": true,
+ "link": true,
+ "__experimentalDefaultControls": {
+ "background": true,
+ "text": true,
+ "link": true
+ }
+ },
+ "__experimentalBorder": {
+ "radius": true,
+ "width": true,
+ "color": true,
+ "style": true
+ },
+ "typography": {
+ "fontSize": true,
+ "__experimentalDefaultControls": {
+ "fontSize": true
+ }
+ }
+ },
+ "attributes": {
+ "selectedUser": {
+ "type": "string",
+ "default": "site"
+ },
+ "buttonOnly": {
+ "type": "boolean",
+ "default": false
+ },
+ "buttonText": {
+ "type": "string",
+ "default": "Follow"
+ },
+ "buttonSize": {
+ "type": "string",
+ "default": "default",
+ "enum": [
+ "small",
+ "default",
+ "compact"
+ ]
+ }
+ },
+ "usesContext": [
+ "postType",
+ "postId"
+ ],
+ "editorScript": "file:./index.js",
+ "viewScript": "file:./view.js",
+ "style": [
+ "file:./style-view.css",
+ "wp-components"
+ ]
+}
\ No newline at end of file
diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/build/follow-me/index.asset.php b/wp-content/upgrade-temp-backup/plugins/activitypub/build/follow-me/index.asset.php
new file mode 100644
index 00000000..48631347
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/activitypub/build/follow-me/index.asset.php
@@ -0,0 +1 @@
+ array('react', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => '8f1a6f7e5f76d58a3204');
diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/build/follow-me/index.js b/wp-content/upgrade-temp-backup/plugins/activitypub/build/follow-me/index.js
new file mode 100644
index 00000000..e6dae559
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/activitypub/build/follow-me/index.js
@@ -0,0 +1,3 @@
+(()=>{"use strict";var e,t={919:(e,t,o)=>{const r=window.wp.blocks,n=window.wp.primitives;var l=o(848);const a=(0,l.jsx)(n.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",children:(0,l.jsx)(n.Path,{d:"M15.5 9.5a1 1 0 100-2 1 1 0 000 2zm0 1.5a2.5 2.5 0 100-5 2.5 2.5 0 000 5zm-2.25 6v-2a2.75 2.75 0 00-2.75-2.75h-4A2.75 2.75 0 003.75 15v2h1.5v-2c0-.69.56-1.25 1.25-1.25h4c.69 0 1.25.56 1.25 1.25v2h1.5zm7-2v2h-1.5v-2c0-.69-.56-1.25-1.25-1.25H15v-1.5h2.5A2.75 2.75 0 0120.25 15zM9.5 8.5a1 1 0 11-2 0 1 1 0 012 0zm1.5 0a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0z",fillRule:"evenodd"})});var i=o(609);const c=window.wp.blockEditor,u=window.wp.i18n,s=window.wp.data,p=window.wp.coreData,d=window.wp.components,m=window.wp.element;function v(){return window._activityPubOptions||{}}const b=window.wp.apiFetch;var f=o.n(b);function y(e){return`var(--wp--preset--color--${e})`}function _(e){if("string"!=typeof e)return null;if(e.match(/^#/))return e.substring(0,7);const[,,t]=e.split("|");return y(t)}function h(e,t,o=null,r=""){return o?`${e}${r} { ${t}: ${o}; }\n`:""}function w(e,t,o,r){return h(e,"background-color",t)+h(e,"color",o)+h(e,"background-color",r,":hover")+h(e,"background-color",r,":focus")}function g({selector:e,style:t,backgroundColor:o}){const r=function(e,t,o){const r=`${e} .components-button`,n=("string"==typeof(l=o)?y(l):l?.color?.background||null)||t?.color?.background;var l;return w(r,_(t?.elements?.link?.color?.text),n,_(t?.elements?.link?.[":hover"]?.color?.text))}(e,t,o);return(0,i.createElement)("style",null,r)}const E=(0,l.jsx)(n.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",children:(0,l.jsx)(n.Path,{fillRule:"evenodd",clipRule:"evenodd",d:"M5 4.5h11a.5.5 0 0 1 .5.5v11a.5.5 0 0 1-.5.5H5a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5ZM3 5a2 2 0 0 1 2-2h11a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5Zm17 3v10.75c0 .69-.56 1.25-1.25 1.25H6v1.5h12.75a2.75 2.75 0 0 0 2.75-2.75V8H20Z"})}),x=(0,l.jsx)(n.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",children:(0,l.jsx)(n.Path,{d:"M16.7 7.1l-6.3 8.5-3.3-2.5-.9 1.2 4.5 3.4L17.9 8z"})}),S=(0,m.forwardRef)((function({icon:e,size:t=24,...o},r){return(0,m.cloneElement)(e,{width:t,height:t,...o,ref:r})})),k=window.wp.compose,C="fediverse-remote-user";function O(e){try{return new URL(e),!0}catch(e){return!1}}function T({actionText:e,copyDescription:t,handle:o,resourceUrl:r,myProfile:n="",rememberProfile:l=!1}){const c=(0,u.__)("Loading...","activitypub"),s=(0,u.__)("Opening...","activitypub"),p=(0,u.__)("Error","activitypub"),v=(0,u.__)("Invalid","activitypub"),b=n||(0,u.__)("My Profile","activitypub"),[y,_]=(0,m.useState)(e),[h,w]=(0,m.useState)(E),g=(0,k.useCopyToClipboard)(o,(()=>{w(x),setTimeout((()=>w(E)),1e3)})),[T,N]=(0,m.useState)(""),[I,R]=(0,m.useState)(!0),{setRemoteUser:U}=function(){const[e,t]=(0,m.useState)(function(){const e=localStorage.getItem(C);return e?JSON.parse(e):{}}()),o=(0,m.useCallback)((e=>{!function(e){localStorage.setItem(C,JSON.stringify(e))}(e),t(e)}),[]),r=(0,m.useCallback)((()=>{localStorage.removeItem(C),t({})}),[]);return{template:e?.template||!1,profileURL:e?.profileURL||!1,setRemoteUser:o,deleteRemoteUser:r}}(),z=(0,m.useCallback)((()=>{let t;if(!O(T)&&!function(e){const t=e.replace(/^@/,"").split("@");return 2===t.length&&O(`https://${t[1]}`)}(T))return _(v),t=setTimeout((()=>_(e)),2e3),()=>clearTimeout(t);const o=r+T;_(c),f()({path:o}).then((({url:t,template:o})=>{I&&U({profileURL:T,template:o}),_(s),setTimeout((()=>{window.open(t,"_blank"),_(e)}),200)})).catch((()=>{_(p),setTimeout((()=>_(e)),2e3)}))}),[T]);return(0,i.createElement)("div",{className:"activitypub__dialog",role:"dialog","aria-labelledby":"dialog-title"},(0,i.createElement)("div",{className:"activitypub-dialog__section"},(0,i.createElement)("h4",{id:"dialog-title"},b),(0,i.createElement)("div",{className:"activitypub-dialog__description",id:"copy-description"},t),(0,i.createElement)("div",{className:"activitypub-dialog__button-group"},(0,i.createElement)("label",{htmlFor:"profile-handle",className:"screen-reader-text"},t),(0,i.createElement)("input",{type:"text",id:"profile-handle",value:o,readOnly:!0}),(0,i.createElement)(d.Button,{ref:g,"aria-label":(0,u.__)("Copy handle to clipboard","activitypub")},(0,i.createElement)(S,{icon:h}),(0,u.__)("Copy","activitypub")))),(0,i.createElement)("div",{className:"activitypub-dialog__section"},(0,i.createElement)("h4",{id:"remote-profile-title"},(0,u.__)("Your Profile","activitypub")),(0,i.createElement)("div",{className:"activitypub-dialog__description",id:"remote-profile-description"},(0,m.createInterpolateElement)((0,u.__)("Or, if you know your own profile, we can start things that way! (eg ',
+ esc_url( $attrs['url'] ),
+ esc_attr__( 'This post is a response to the referenced content.', 'activitypub' ),
+ // translators: %s is the URL of the post being replied to.
+ sprintf( __( '↬%s', 'activitypub' ), \str_replace( array( 'https://', 'http://' ), '', esc_url( $attrs['url'] ) ) )
+ );
+ }
+
+ $html .= ' .*?@yourusername@example.com)","activitypub"),{code:(0,i.createElement)("code",null)})),(0,i.createElement)("div",{className:"activitypub-dialog__button-group"},(0,i.createElement)("label",{htmlFor:"remote-profile",className:"screen-reader-text"},(0,u.__)("Enter your ActivityPub profile","activitypub")),(0,i.createElement)("input",{type:"text",id:"remote-profile",value:T,onKeyDown:e=>{"Enter"===e?.code&&z()},onChange:e=>N(e.target.value),"aria-invalid":y===v}),(0,i.createElement)(d.Button,{onClick:z,"aria-label":(0,u.__)("Submit profile","activitypub")},(0,i.createElement)(S,{icon:a}),y)),l&&(0,i.createElement)("div",{className:"activitypub-dialog__remember"},(0,i.createElement)(d.CheckboxControl,{checked:I,label:(0,u.__)("Remember me for easier comments","activitypub"),onChange:()=>{R(!I)}}))))}const N={avatar:"",webfinger:"@well@hello.dolly",name:(0,u.__)("Hello Dolly Fan Account","activitypub"),url:"#"};function I(e){if(!e)return N;const t={...N,...e};return t.avatar=t?.icon?.url,t}function R({profile:e,popupStyles:t,userId:o,buttonText:r,buttonOnly:n,buttonSize:l}){const{webfinger:a,avatar:c,name:u}=e,s=a.startsWith("@")?a:`@${a}`;return n?(0,i.createElement)("div",{className:"activitypub-profile"},(0,i.createElement)(U,{profile:e,popupStyles:t,userId:o,buttonText:r,buttonSize:l})):(0,i.createElement)("div",{className:"activitypub-profile"},(0,i.createElement)("img",{className:"activitypub-profile__avatar",src:c,alt:u}),(0,i.createElement)("div",{className:"activitypub-profile__content"},(0,i.createElement)("div",{className:"activitypub-profile__name"},u),(0,i.createElement)("div",{className:"activitypub-profile__handle",title:s},s)),(0,i.createElement)(U,{profile:e,popupStyles:t,userId:o,buttonText:r,buttonSize:l}))}function U({profile:e,popupStyles:t,userId:o,buttonText:r,buttonSize:n}){const[l,a]=(0,m.useState)(!1),c=(0,u.sprintf)(/* translators: %s: profile name */ /* translators: %s: profile name */
+(0,u.__)("Follow %s","activitypub"),e?.name);return(0,i.createElement)(i.Fragment,null,(0,i.createElement)(d.Button,{className:"activitypub-profile__follow",onClick:()=>a(!0),"aria-haspopup":"dialog","aria-expanded":l,"aria-label":(0,u.__)("Follow me on the Fediverse","activitypub"),size:n},r),l&&(0,i.createElement)(d.Modal,{className:"activitypub-profile__confirm activitypub__modal",onRequestClose:()=>a(!1),title:c,"aria-label":c,role:"dialog"},(0,i.createElement)(z,{profile:e,userId:o}),(0,i.createElement)("style",null,t)))}function z({profile:e,userId:t}){const{namespace:o}=v(),{webfinger:r}=e,n=(0,u.__)("Follow","activitypub"),l=`/${o}/actors/${t}/remote-follow?resource=`,a=(0,u.__)("Copy and paste my profile into the search field of your favorite fediverse app or server.","activitypub"),c=r.startsWith("@")?r:`@${r}`;return(0,i.createElement)(T,{actionText:n,copyDescription:a,handle:c,resourceUrl:l})}function $({selectedUser:e,style:t,backgroundColor:o,id:r,useId:n=!1,profileData:l=!1,buttonOnly:a=!1,buttonText:c=(0,u.__)("Follow","activitypub"),buttonSize:s="default"}){const[p,d]=(0,m.useState)(I()),b="site"===e?0:e,y=function(e){return w(".apfmd__button-group .components-button",_(e?.elements?.link?.color?.text)||"#111","#fff",_(e?.elements?.link?.[":hover"]?.color?.text)||"#333")}(t),h=n?{id:r}:{};return(0,m.useEffect)((()=>{l?d(I(l)):function(e){const{namespace:t}=v(),o={headers:{Accept:"application/activity+json"},path:`/${t}/actors/${e}`};return f()(o)}(b).then((e=>{d(I(e))}))}),[b,l]),(0,i.createElement)("div",{...h,className:"activitypub-follow-me-block-wrapper"},(0,i.createElement)(g,{selector:`#${r}`,style:t,backgroundColor:o}),(0,i.createElement)(R,{profile:p,userId:b,popupStyles:y,buttonText:c,buttonOnly:a,buttonSize:s}))}function P({name:e}){const{enabled:t}=v(),o=t?.site?"":(0,u.__)("It will be empty in other non-author contexts.","activitypub"),r=(0,u.sprintf)(/* translators: %1$s: block name, %2$s: extra information for non-author context */ /* translators: %1$s: block name, %2$s: extra information for non-author context */
+(0,u.__)("This %1$s block will adapt to the page it is on, displaying the user profile associated with a post author (in a loop) or a user archive. %2$s","activitypub"),e,o).trim();return(0,i.createElement)(d.Card,null,(0,i.createElement)(d.CardBody,null,(0,m.createInterpolateElement)(r,{strong:(0,i.createElement)("strong",null)})))}(0,r.registerBlockType)("activitypub/follow-me",{edit:function({attributes:e,setAttributes:t,context:{postType:o,postId:r}}){const n=(0,c.useBlockProps)({className:"activitypub-follow-me-block-wrapper"}),l=function({withInherit:e=!1}){const{enabled:t}=v(),o=t?.users?(0,s.useSelect)((e=>e("core").getUsers({who:"authors"}))):[];return(0,m.useMemo)((()=>{if(!o)return[];const r=[];return t?.site&&r.push({label:(0,u.__)("Site","activitypub"),value:"site"}),e&&t?.users&&r.push({label:(0,u.__)("Dynamic User","activitypub"),value:"inherit"}),o.reduce(((e,t)=>(e.push({label:t.name,value:`${t.id}`}),e)),r)}),[o])}({withInherit:!0}),{selectedUser:a,buttonOnly:b,buttonText:f,buttonSize:y}=e,_="inherit"===a,h=(0,s.useSelect)((e=>{const{getEditedEntityRecord:t}=e(p.store),n=t("postType",o,r)?.author;return null!=n?n:null}),[o,r]);return(0,m.useEffect)((()=>{l.length&&(l.find((({value:e})=>e===a))||t({selectedUser:l[0].value}))}),[a,l]),(0,i.createElement)("div",{...n},(0,i.createElement)(c.InspectorControls,{key:"activitypub-follow-me"},(0,i.createElement)(d.PanelBody,{title:(0,u.__)("Follow Me Options","activitypub")},l.length>1&&(0,i.createElement)(d.SelectControl,{label:(0,u.__)("Select User","activitypub"),value:e.selectedUser,options:l,onChange:e=>t({selectedUser:e})}),(0,i.createElement)(d.ToggleControl,{label:(0,u.__)("Button Only Mode","activitypub"),checked:b,onChange:e=>t({buttonOnly:e}),help:(0,u.__)("Only show the follow button without profile information","activitypub")}),(0,i.createElement)(d.TextControl,{label:(0,u.__)("Button Text","activitypub"),value:f,onChange:e=>t({buttonText:e})}),(0,i.createElement)(d.SelectControl,{label:(0,u.__)("Button Size","activitypub"),value:y,options:[{label:(0,u.__)("Default","activitypub"),value:"default"},{label:(0,u.__)("Compact","activitypub"),value:"compact"},{label:(0,u.__)("Small","activitypub"),value:"small"}],onChange:e=>t({buttonSize:e}),help:(0,u.__)("Choose the size of the follow button","activitypub")}))),_?h?(0,i.createElement)($,{...e,id:n.id,selectedUser:h}):(0,i.createElement)(P,{name:(0,u.__)("Follow Me","activitypub")}):(0,i.createElement)($,{...e,id:n.id}))},save:()=>null,icon:a})},20:(e,t,o)=>{var r=o(609),n=Symbol.for("react.element"),l=(Symbol.for("react.fragment"),Object.prototype.hasOwnProperty),a=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,i={key:!0,ref:!0,__self:!0,__source:!0};t.jsx=function(e,t,o){var r,c={},u=null,s=null;for(r in void 0!==o&&(u=""+o),void 0!==t.key&&(u=""+t.key),void 0!==t.ref&&(s=t.ref),t)l.call(t,r)&&!i.hasOwnProperty(r)&&(c[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps)void 0===c[r]&&(c[r]=t[r]);return{$$typeof:n,type:e,key:u,ref:s,props:c,_owner:a.current}}},848:(e,t,o)=>{e.exports=o(20)},609:e=>{e.exports=window.React}},o={};function r(e){var n=o[e];if(void 0!==n)return n.exports;var l=o[e]={exports:{}};return t[e](l,l.exports,r),l.exports}r.m=t,e=[],r.O=(t,o,n,l)=>{if(!o){var a=1/0;for(s=0;s@yourusername@example.com)","activitypub"),{code:(0,o.createElement)("code",null)})),(0,o.createElement)("div",{className:"activitypub-dialog__button-group"},(0,o.createElement)("label",{htmlFor:"remote-profile",className:"screen-reader-text"},(0,s.__)("Enter your ActivityPub profile","activitypub")),(0,o.createElement)("input",{type:"text",id:"remote-profile",value:C,onKeyDown:e=>{"Enter"===e?.code&&z()},onChange:e=>R(e.target.value),"aria-invalid":b===v}),(0,o.createElement)(u.Button,{onClick:z,"aria-label":(0,s.__)("Submit profile","activitypub")},(0,o.createElement)(h,{icon:g}),b)),l&&(0,o.createElement)("div",{className:"activitypub-dialog__remember"},(0,o.createElement)(u.CheckboxControl,{checked:I,label:(0,s.__)("Remember me for easier comments","activitypub"),onChange:()=>{T(!I)}}))))}function O(){return window._activityPubOptions||{}}const N={avatar:"",webfinger:"@well@hello.dolly",name:(0,s.__)("Hello Dolly Fan Account","activitypub"),url:"#"};function C(e){if(!e)return N;const t={...N,...e};return t.avatar=t?.icon?.url,t}function R({profile:e,popupStyles:t,userId:r,buttonText:a,buttonOnly:n,buttonSize:i}){const{webfinger:l,avatar:c,name:u}=e,s=l.startsWith("@")?l:`@${l}`;return n?(0,o.createElement)("div",{className:"activitypub-profile"},(0,o.createElement)(I,{profile:e,popupStyles:t,userId:r,buttonText:a,buttonSize:i})):(0,o.createElement)("div",{className:"activitypub-profile"},(0,o.createElement)("img",{className:"activitypub-profile__avatar",src:c,alt:u}),(0,o.createElement)("div",{className:"activitypub-profile__content"},(0,o.createElement)("div",{className:"activitypub-profile__name"},u),(0,o.createElement)("div",{className:"activitypub-profile__handle",title:s},s)),(0,o.createElement)(I,{profile:e,popupStyles:t,userId:r,buttonText:a,buttonSize:i}))}function I({profile:e,popupStyles:t,userId:r,buttonText:n,buttonSize:i}){const[l,c]=(0,a.useState)(!1),p=(0,s.sprintf)(/* translators: %s: profile name */ /* translators: %s: profile name */
+(0,s.__)("Follow %s","activitypub"),e?.name);return(0,o.createElement)(o.Fragment,null,(0,o.createElement)(u.Button,{className:"activitypub-profile__follow",onClick:()=>c(!0),"aria-haspopup":"dialog","aria-expanded":l,"aria-label":(0,s.__)("Follow me on the Fediverse","activitypub"),size:i},n),l&&(0,o.createElement)(u.Modal,{className:"activitypub-profile__confirm activitypub__modal",onRequestClose:()=>c(!1),title:p,"aria-label":p,role:"dialog"},(0,o.createElement)(T,{profile:e,userId:r}),(0,o.createElement)("style",null,t)))}function T({profile:e,userId:t}){const{namespace:r}=O(),{webfinger:a}=e,n=(0,s.__)("Follow","activitypub"),i=`/${r}/actors/${t}/remote-follow?resource=`,l=(0,s.__)("Copy and paste my profile into the search field of your favorite fediverse app or server.","activitypub"),c=a.startsWith("@")?a:`@${a}`;return(0,o.createElement)(k,{actionText:n,copyDescription:l,handle:c,resourceUrl:i})}function $({selectedUser:e,style:t,backgroundColor:r,id:n,useId:i=!1,profileData:l=!1,buttonOnly:u=!1,buttonText:p=(0,s.__)("Follow","activitypub"),buttonSize:d="default"}){const[b,y]=(0,a.useState)(C()),_="site"===e?0:e,w=function(e){return v(".apfmd__button-group .components-button",m(e?.elements?.link?.color?.text)||"#111","#fff",m(e?.elements?.link?.[":hover"]?.color?.text)||"#333")}(t),h=i?{id:n}:{};return(0,a.useEffect)((()=>{l?y(C(l)):function(e){const{namespace:t}=O(),r={headers:{Accept:"application/activity+json"},path:`/${t}/actors/${e}`};return c()(r)}(_).then((e=>{y(C(e))}))}),[_,l]),(0,o.createElement)("div",{...h,className:"activitypub-follow-me-block-wrapper"},(0,o.createElement)(f,{selector:`#${n}`,style:t,backgroundColor:r}),(0,o.createElement)(R,{profile:b,userId:_,popupStyles:w,buttonText:p,buttonOnly:u,buttonSize:d}))}let z=1;i()((()=>{[].forEach.call(document.querySelectorAll(".activitypub-follow-me-block-wrapper"),(e=>{const t=JSON.parse(e.dataset.attrs);(0,a.createRoot)(e).render((0,o.createElement)($,{...t,id:"activitypub-follow-me-block-"+z++,useId:!0}))}))}))},20:(e,t,r)=>{var o=r(609),a=Symbol.for("react.element"),n=(Symbol.for("react.fragment"),Object.prototype.hasOwnProperty),i=o.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,l={key:!0,ref:!0,__self:!0,__source:!0};t.jsx=function(e,t,r){var o,c={},u=null,s=null;for(o in void 0!==r&&(u=""+r),void 0!==t.key&&(u=""+t.key),void 0!==t.ref&&(s=t.ref),t)n.call(t,o)&&!l.hasOwnProperty(o)&&(c[o]=t[o]);if(e&&e.defaultProps)for(o in t=e.defaultProps)void 0===c[o]&&(c[o]=t[o]);return{$$typeof:a,type:e,key:u,ref:s,props:c,_owner:i.current}}},848:(e,t,r)=>{e.exports=r(20)},609:e=>{e.exports=window.React}},r={};function o(e){var a=r[e];if(void 0!==a)return a.exports;var n=r[e]={exports:{}};return t[e](n,n.exports,o),n.exports}o.m=t,e=[],o.O=(t,r,a,n)=>{if(!r){var i=1/0;for(s=0;s@yourusername@example.com)","activitypub"),{code:(0,o.createElement)("code",null)})),(0,o.createElement)("div",{className:"activitypub-dialog__button-group"},(0,o.createElement)("label",{htmlFor:"remote-profile",className:"screen-reader-text"},(0,c.__)("Enter your ActivityPub profile","activitypub")),(0,o.createElement)("input",{type:"text",id:"remote-profile",value:L,onKeyDown:e=>{"Enter"===e?.code&&j()},onChange:e=>S(e.target.value),"aria-invalid":C===w}),(0,o.createElement)(l.Button,{onClick:j,"aria-label":(0,c.__)("Submit profile","activitypub")},(0,o.createElement)(s,{icon:f}),C)),m&&(0,o.createElement)("div",{className:"activitypub-dialog__remember"},(0,o.createElement)(l.CheckboxControl,{checked:U,label:(0,c.__)("Remember me for easier comments","activitypub"),onChange:()=>{N(!U)}}))))}function C({selectedComment:e,commentId:t}){const{namespace:r}=window._activityPubOptions||{},a=(0,c.__)("Reply","activitypub"),i=`/${r}/comments/${t}/remote-reply?resource=`,n=(0,c.__)("Copy and paste the Comment URL into the search field of your favorite fediverse app or server.","activitypub");return(0,o.createElement)(E,{actionText:a,copyDescription:n,handle:e,resourceUrl:i,myProfile:(0,c.__)("Original Comment URL","activitypub"),rememberProfile:!0})}function R({profileURL:e,template:t,commentURL:r,deleteRemoteUser:a}){return(0,o.createElement)(o.Fragment,null,(0,o.createElement)(l.Button,{variant:"link",className:"comment-reply-link activitypub-remote-reply__button",onClick:()=>{const e=t.replace("{uri}",r);window.open(e,"_blank")}},/* translators: %s: profile name */ /* translators: %s: profile name */
+(0,c.sprintf)((0,c.__)("Reply as %s","activitypub"),e)),(0,o.createElement)(l.Button,{className:"activitypub-remote-profile-delete",onClick:a,title:(0,c.__)("Delete Remote Profile","activitypub")},(0,o.createElement)(s,{icon:u,size:18})))}function x({selectedComment:e,commentId:t}){const[r,i]=(0,a.useState)(!1),n=(0,c.__)("Remote Reply","activitypub"),{profileURL:s,template:m,deleteRemoteUser:p}=h(),u=s&&m;return(0,o.createElement)(o.Fragment,null,u?(0,o.createElement)(R,{profileURL:s,template:m,commentURL:e,deleteRemoteUser:p}):(0,o.createElement)(l.Button,{variant:"link",className:"comment-reply-link activitypub-remote-reply__button",onClick:()=>i(!0)},(0,c.__)("Reply on the Fediverse","activitypub")),r&&(0,o.createElement)(l.Modal,{className:"activitypub-remote-reply__modal activitypub__modal",onRequestClose:()=>i(!1),title:n},(0,o.createElement)(C,{selectedComment:e,commentId:t})))}let O=1;n()((()=>{[].forEach.call(document.querySelectorAll(".activitypub-remote-reply"),(e=>{const t=JSON.parse(e.dataset.attrs);(0,a.createRoot)(e).render((0,o.createElement)(x,{...t,id:"activitypub-remote-reply-link-"+O++,useId:!0}))}))}))},20:(e,t,r)=>{var o=r(609),a=Symbol.for("react.element"),i=(Symbol.for("react.fragment"),Object.prototype.hasOwnProperty),n=o.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,l={key:!0,ref:!0,__self:!0,__source:!0};t.jsx=function(e,t,r){var o,c={},s=null,m=null;for(o in void 0!==r&&(s=""+r),void 0!==t.key&&(s=""+t.key),void 0!==t.ref&&(m=t.ref),t)i.call(t,o)&&!l.hasOwnProperty(o)&&(c[o]=t[o]);if(e&&e.defaultProps)for(o in t=e.defaultProps)void 0===c[o]&&(c[o]=t[o]);return{$$typeof:a,type:e,key:s,ref:m,props:c,_owner:n.current}}},848:(e,t,r)=>{e.exports=r(20)},609:e=>{e.exports=window.React}},r={};function o(e){var a=r[e];if(void 0!==a)return a.exports;var i=r[e]={exports:{}};return t[e](i,i.exports,o),i.exports}o.m=t,e=[],o.O=(t,r,a,i)=>{if(!r){var n=1/0;for(m=0;m' . esc_html( $attrs['title'] ) . '
';
+ }
+ $html .= '';
+ foreach ( $follower_data['followers'] as $follower ) {
+ $html .= '
+
+ %s
+ /
+ @%s
+
+ %s
+ ';
+
+ $data = $follower->to_array();
+
+ return sprintf(
+ $template,
+ esc_url( object_to_uri( $data['url'] ) ),
+ esc_attr( $data['name'] ),
+ esc_attr( $data['icon']['url'] ),
+ esc_html( $data['name'] ),
+ esc_html( $data['preferredUsername'] ),
+ $external_svg
+ );
+ }
+
+ /**
+ * Converts content to blocks before saving to the database.
+ *
+ * @param array $data The post data to be inserted.
+ * @param object $post The Mastodon Create activity.
+ *
+ * @return array
+ */
+ public static function filter_import_mastodon_post_data( $data, $post ) {
+ // Convert paragraphs to blocks.
+ \preg_match_all( '#
' . $content . '
'; + } + + /** + * Add the 'me' rel to the link. + * + * @param string $rel The rel attribute. + * @return string The modified rel attribute. + */ + public static function add_rel_me( $rel ) { + return $rel . ' me'; + } + + /** + * Checks if the user is the blog user. + * + * @param int $user_id The user ID. + * @return bool True if the user is the blog user, otherwise false. + */ + private static function is_blog( $user_id ) { + return Actors::BLOG_USER_ID === $user_id; + } +} diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/includes/collection/class-followers.php b/wp-content/upgrade-temp-backup/plugins/activitypub/includes/collection/class-followers.php new file mode 100644 index 00000000..24be3507 --- /dev/null +++ b/wp-content/upgrade-temp-backup/plugins/activitypub/includes/collection/class-followers.php @@ -0,0 +1,482 @@ + 400 ) ); + } + + $follower = new Follower(); + $follower->from_array( $meta ); + + $id = $follower->upsert(); + + if ( is_wp_error( $id ) ) { + return $id; + } + + $post_meta = get_post_meta( $id, '_activitypub_user_id', false ); + + // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict + if ( is_array( $post_meta ) && ! in_array( $user_id, $post_meta ) ) { + add_post_meta( $id, '_activitypub_user_id', $user_id ); + wp_cache_delete( sprintf( self::CACHE_KEY_INBOXES, $user_id ), 'activitypub' ); + } + + return $follower; + } + + /** + * Remove a Follower. + * + * @param int $user_id The ID of the WordPress User. + * @param string $actor The Actor URL. + * + * @return bool True on success, false on failure. + */ + public static function remove_follower( $user_id, $actor ) { + wp_cache_delete( sprintf( self::CACHE_KEY_INBOXES, $user_id ), 'activitypub' ); + + $follower = self::get_follower( $user_id, $actor ); + + if ( ! $follower ) { + return false; + } + + /** + * Fires before a Follower is removed. + * + * @param Follower $follower The Follower object. + * @param int $user_id The ID of the WordPress User. + * @param string $actor The Actor URL. + */ + do_action( 'activitypub_followers_pre_remove_follower', $follower, $user_id, $actor ); + + return delete_post_meta( $follower->get__id(), '_activitypub_user_id', $user_id ); + } + + /** + * Get a Follower. + * + * @param int $user_id The ID of the WordPress User. + * @param string $actor The Actor URL. + * + * @return Follower|false|null The Follower object or null + */ + public static function get_follower( $user_id, $actor ) { + global $wpdb; + + // phpcs:ignore WordPress.DB.DirectDatabaseQuery + $post_id = $wpdb->get_var( + $wpdb->prepare( + "SELECT DISTINCT p.ID FROM $wpdb->posts p INNER JOIN $wpdb->postmeta pm ON p.ID = pm.post_id WHERE p.post_type = %s AND pm.meta_key = '_activitypub_user_id' AND pm.meta_value = %d AND p.guid = %s", + array( + esc_sql( self::POST_TYPE ), + esc_sql( $user_id ), + esc_sql( $actor ), + ) + ) + ); + + if ( $post_id ) { + $post = get_post( $post_id ); + return Follower::init_from_cpt( $post ); + } + + return null; + } + + /** + * Get a Follower by Actor independent of the User. + * + * @param string $actor The Actor URL. + * + * @return Follower|false|null The Follower object or false on failure. + */ + public static function get_follower_by_actor( $actor ) { + global $wpdb; + + // phpcs:ignore WordPress.DB.DirectDatabaseQuery + $post_id = $wpdb->get_var( + $wpdb->prepare( + "SELECT ID FROM $wpdb->posts WHERE guid=%s", + esc_sql( $actor ) + ) + ); + + if ( $post_id ) { + $post = get_post( $post_id ); + return Follower::init_from_cpt( $post ); + } + + return null; + } + + /** + * Get the Followers of a given user. + * + * @param int $user_id The ID of the WordPress User. + * @param int $number Maximum number of results to return. + * @param int $page Page number. + * @param array $args The WP_Query arguments. + * @return Follower[] List of `Follower` objects. + */ + public static function get_followers( $user_id, $number = -1, $page = null, $args = array() ) { + $data = self::get_followers_with_count( $user_id, $number, $page, $args ); + return $data['followers']; + } + + /** + * Get the Followers of a given user, along with a total count for pagination purposes. + * + * @param int $user_id The ID of the WordPress User. + * @param int $number Maximum number of results to return. + * @param int $page Page number. + * @param array $args The WP_Query arguments. + * + * @return array { + * Data about the followers. + * + * @type Follower[] $followers List of `Follower` objects. + * @type int $total Total number of followers. + * } + */ + public static function get_followers_with_count( $user_id, $number = -1, $page = null, $args = array() ) { + $defaults = array( + 'post_type' => self::POST_TYPE, + 'posts_per_page' => $number, + 'paged' => $page, + 'orderby' => 'ID', + 'order' => 'DESC', + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + 'meta_query' => array( + array( + 'key' => '_activitypub_user_id', + 'value' => $user_id, + ), + ), + ); + + $args = wp_parse_args( $args, $defaults ); + $query = new WP_Query( $args ); + $total = $query->found_posts; + $followers = array_map( array( Follower::class, 'init_from_cpt' ), $query->get_posts() ); + $followers = array_filter( $followers ); + + return compact( 'followers', 'total' ); + } + + /** + * Get all Followers. + * + * @return Follower[] The Term list of Followers. + */ + public static function get_all_followers() { + $args = array( + 'nopaging' => true, + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + 'meta_query' => array( + 'relation' => 'AND', + array( + 'key' => '_activitypub_inbox', + 'compare' => 'EXISTS', + ), + array( + 'key' => '_activitypub_actor_json', + 'compare' => 'EXISTS', + ), + ), + ); + return self::get_followers( null, null, null, $args ); + } + + /** + * Count the total number of followers + * + * @param int $user_id The ID of the WordPress User. + * + * @return int The number of Followers + */ + public static function count_followers( $user_id ) { + $query = new WP_Query( + array( + 'post_type' => self::POST_TYPE, + 'fields' => 'ids', + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + 'meta_query' => array( + 'relation' => 'AND', + array( + 'key' => '_activitypub_user_id', + 'value' => $user_id, + ), + array( + 'key' => '_activitypub_inbox', + 'compare' => 'EXISTS', + ), + array( + 'key' => '_activitypub_actor_json', + 'compare' => 'EXISTS', + ), + ), + ) + ); + + return $query->found_posts; + } + + /** + * Returns all Inboxes for an Actor's Followers. + * + * @param int $user_id The ID of the WordPress User. + * + * @return array The list of Inboxes. + */ + public static function get_inboxes( $user_id ) { + $cache_key = sprintf( self::CACHE_KEY_INBOXES, $user_id ); + $inboxes = wp_cache_get( $cache_key, 'activitypub' ); + + if ( $inboxes ) { + return $inboxes; + } + + // Get all Followers of an ID of the WordPress User. + $posts = new WP_Query( + array( + 'nopaging' => true, + 'post_type' => self::POST_TYPE, + 'fields' => 'ids', + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + 'meta_query' => array( + 'relation' => 'AND', + array( + 'key' => '_activitypub_inbox', + 'compare' => 'EXISTS', + ), + array( + 'key' => '_activitypub_user_id', + 'value' => $user_id, + ), + array( + 'key' => '_activitypub_inbox', + 'value' => '', + 'compare' => '!=', + ), + ), + ) + ); + + $posts = $posts->get_posts(); + + if ( ! $posts ) { + return array(); + } + + global $wpdb; + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery + $results = $wpdb->get_col( + $wpdb->prepare( + "SELECT DISTINCT meta_value FROM {$wpdb->postmeta} + WHERE post_id IN (" . implode( ', ', array_fill( 0, count( $posts ), '%d' ) ) . ") + AND meta_key = '_activitypub_inbox' + AND meta_value IS NOT NULL", + $posts + ) + ); + + $inboxes = array_filter( $results ); + wp_cache_set( $cache_key, $inboxes, 'activitypub' ); + + return $inboxes; + } + + /** + * Get all Inboxes for a given Activity. + * + * @param string $json The ActivityPub Activity JSON. + * @param int $actor_id The WordPress Actor ID. + * @param int $batch_size Optional. The batch size. Default 50. + * @param int $offset Optional. The offset. Default 0. + * + * @return array The list of Inboxes. + */ + public static function get_inboxes_for_activity( $json, $actor_id, $batch_size = 50, $offset = 0 ) { + $inboxes = self::get_inboxes( $actor_id ); + + if ( self::maybe_add_inboxes_of_blog_user( $json, $actor_id ) ) { + $inboxes = array_fill_keys( $inboxes, 1 ); + foreach ( self::get_inboxes( Actors::BLOG_USER_ID ) as $inbox ) { + $inboxes[ $inbox ] = 1; + } + $inboxes = array_keys( $inboxes ); + } + + return array_slice( $inboxes, $offset, $batch_size ); + } + + /** + * Maybe add Inboxes of the Blog User. + * + * @param string $json The ActivityPub Activity JSON. + * @param int $actor_id The WordPress Actor ID. + * @return bool True if the Inboxes of the Blog User should be added, false otherwise. + */ + public static function maybe_add_inboxes_of_blog_user( $json, $actor_id ) { + // Only if we're in both Blog and User modes. + if ( ACTIVITYPUB_ACTOR_AND_BLOG_MODE !== \get_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ) ) { + return false; + } + // Only if this isn't the Blog Actor. + if ( Actors::BLOG_USER_ID === $actor_id ) { + return false; + } + + $activity = json_decode( $json, true ); + // Only if this is an Update or Delete. Create handles its own "Announce" in dual user mode. + if ( ! in_array( $activity['type'] ?? null, array( 'Update', 'Delete' ), true ) ) { + return false; + } + + return true; + } + + /** + * Get all Followers that have not been updated for a given time. + * + * @param int $number Optional. Limits the result. Default 50. + * @param int $older_than Optional. The time in seconds. Default 86400 (1 day). + * + * @return Follower[] The Term list of Followers. + */ + public static function get_outdated_followers( $number = 50, $older_than = 86400 ) { + $args = array( + 'post_type' => self::POST_TYPE, + 'posts_per_page' => $number, + 'orderby' => 'modified', + 'order' => 'ASC', + 'post_status' => 'any', // 'any' includes 'trash'. + 'date_query' => array( + array( + 'column' => 'post_modified_gmt', + 'before' => gmdate( 'Y-m-d', \time() - $older_than ), + ), + ), + ); + + $posts = new WP_Query( $args ); + $items = array_map( array( Follower::class, 'init_from_cpt' ), $posts->get_posts() ); + + return array_filter( $items ); + } + + /** + * Get all Followers that had errors. + * + * @param int $number Optional. The number of Followers to return. Default 20. + * + * @return Follower[] The Term list of Followers. + */ + public static function get_faulty_followers( $number = 20 ) { + $args = array( + 'post_type' => self::POST_TYPE, + 'posts_per_page' => $number, + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + 'meta_query' => array( + 'relation' => 'OR', + array( + 'key' => '_activitypub_errors', + 'compare' => 'EXISTS', + ), + array( + 'key' => '_activitypub_inbox', + 'compare' => 'NOT EXISTS', + ), + array( + 'key' => '_activitypub_actor_json', + 'compare' => 'NOT EXISTS', + ), + array( + 'key' => '_activitypub_inbox', + 'value' => '', + 'compare' => '=', + ), + array( + 'key' => '_activitypub_actor_json', + 'value' => '', + 'compare' => '=', + ), + ), + ); + + $posts = new WP_Query( $args ); + $items = array_map( array( Follower::class, 'init_from_cpt' ), $posts->get_posts() ); + + return array_filter( $items ); + } + + /** + * This function is used to store errors that occur when + * sending an ActivityPub message to a Follower. + * + * The error will be stored in post meta. + * + * @param int $post_id The ID of the WordPress Custom-Post-Type. + * @param mixed $error The error message. Can be a string or a WP_Error. + * + * @return int|false The meta ID on success, false on failure. + */ + public static function add_error( $post_id, $error ) { + if ( is_string( $error ) ) { + $error_message = $error; + } elseif ( is_wp_error( $error ) ) { + $error_message = $error->get_error_message(); + } else { + $error_message = __( + 'Unknown Error or misconfigured Error-Message', + 'activitypub' + ); + } + + return add_post_meta( + $post_id, + '_activitypub_errors', + $error_message + ); + } +} diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/includes/collection/class-interactions.php b/wp-content/upgrade-temp-backup/plugins/activitypub/includes/collection/class-interactions.php new file mode 100644 index 00000000..dc1f9417 --- /dev/null +++ b/wp-content/upgrade-temp-backup/plugins/activitypub/includes/collection/class-interactions.php @@ -0,0 +1,349 @@ +comment_post_ID; + } + + if ( is_post_disabled( $comment_post_id ) ) { + return false; + } + + $commentdata['comment_post_ID'] = $comment_post_id; + $commentdata['comment_parent'] = $parent_comment_id ? $parent_comment_id : 0; + + return self::persist( $commentdata, self::INSERT ); + } + + /** + * Update a comment. + * + * @param array $activity The activity object. + * + * @return array|string|int|\WP_Error|false The comment data or false on failure. + */ + public static function update_comment( $activity ) { + $meta = get_remote_metadata_by_actor( $activity['actor'] ); + + // Determine comment_ID. + $comment = object_id_to_comment( \esc_url_raw( $activity['object']['id'] ) ); + $commentdata = \get_comment( $comment, ARRAY_A ); + + if ( ! $commentdata ) { + return false; + } + + // Found a local comment id. + $commentdata['comment_author'] = \esc_attr( $meta['name'] ? $meta['name'] : $meta['preferredUsername'] ); + $commentdata['comment_content'] = \addslashes( $activity['object']['content'] ); + + return self::persist( $commentdata, self::UPDATE ); + } + + /** + * Adds an incoming Like, Announce, ... as a comment to a post. + * + * @param array $activity Activity array. + * + * @return array|false Comment data or `false` on failure. + */ + public static function add_reaction( $activity ) { + $commentdata = self::activity_to_comment( $activity ); + + if ( ! $commentdata ) { + return false; + } + + $url = object_to_uri( $activity['object'] ); + $comment_post_id = \url_to_postid( $url ); + $parent_comment_id = url_to_commentid( $url ); + + if ( ! $comment_post_id && $parent_comment_id ) { + $parent_comment = \get_comment( $parent_comment_id ); + $comment_post_id = $parent_comment->comment_post_ID; + } + + if ( ! $comment_post_id || is_post_disabled( $comment_post_id ) ) { + // Not a reply to a post or comment. + return false; + } + + $comment_type = Comment::get_comment_type_by_activity_type( $activity['type'] ); + + if ( ! $comment_type ) { + // Not a valid comment type. + return false; + } + + $comment_content = $comment_type['excerpt']; + + $commentdata['comment_post_ID'] = $comment_post_id; + $commentdata['comment_content'] = \esc_html( $comment_content ); + $commentdata['comment_type'] = \esc_attr( $comment_type['type'] ); + $commentdata['comment_meta']['source_id'] = \esc_url_raw( $activity['id'] ); + + return self::persist( $commentdata, self::INSERT ); + } + + /** + * Get interaction(s) for a given URL/ID. + * + * @param string $url The URL/ID to get interactions for. + * + * @return array The interactions as WP_Comment objects. + */ + public static function get_interaction_by_id( $url ) { + $args = array( + 'nopaging' => true, + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + 'meta_query' => array( + 'relation' => 'AND', + array( + 'key' => 'protocol', + 'value' => 'activitypub', + ), + array( + 'relation' => 'OR', + array( + 'key' => 'source_url', + 'value' => $url, + ), + array( + 'key' => 'source_id', + 'value' => $url, + ), + ), + ), + ); + + $query = new WP_Comment_Query( $args ); + return $query->comments; + } + + /** + * Get interaction(s) for a given actor. + * + * @param string $actor The Actor-URL. + * + * @return array The interactions as WP_Comment objects. + */ + public static function get_interactions_by_actor( $actor ) { + $meta = get_remote_metadata_by_actor( $actor ); + + // Get URL, because $actor seems to be the ID. + if ( $meta && ! is_wp_error( $meta ) && isset( $meta['url'] ) ) { + $actor = object_to_uri( $meta['url'] ); + } + + $args = array( + 'nopaging' => true, + 'author_url' => $actor, + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + 'meta_query' => array( + array( + 'key' => 'protocol', + 'value' => 'activitypub', + ), + ), + ); + + return get_comments( $args ); + } + + /** + * Adds line breaks to the list of allowed comment tags. + * + * @param array $allowed_tags Allowed HTML tags. + * @param string $context Optional. Context. Default empty. + * + * @return array Filtered tag list. + */ + public static function allowed_comment_html( $allowed_tags, $context = '' ) { + if ( 'pre_comment_content' !== $context ) { + // Do nothing. + return $allowed_tags; + } + + // Add `p` and `br` to the list of allowed tags. + if ( ! array_key_exists( 'br', $allowed_tags ) ) { + $allowed_tags['br'] = array(); + } + + if ( ! array_key_exists( 'p', $allowed_tags ) ) { + $allowed_tags['p'] = array(); + } + + return $allowed_tags; + } + + /** + * Convert an Activity to a WP_Comment + * + * @param array $activity The Activity array. + * + * @return array|false The comment data or false on failure. + */ + public static function activity_to_comment( $activity ) { + $comment_content = null; + $actor = object_to_uri( $activity['actor'] ?? null ); + $actor = get_remote_metadata_by_actor( $actor ); + + // Check Actor-Meta. + if ( ! $actor || is_wp_error( $actor ) ) { + return false; + } + + // Check Actor-Name. + if ( isset( $actor['name'] ) ) { + $comment_author = $actor['name']; + } elseif ( isset( $actor['preferredUsername'] ) ) { + $comment_author = $actor['preferredUsername']; + } else { + return false; + } + + $url = object_to_uri( $actor['url'] ?? $actor['id'] ); + + if ( ! $url ) { + $url = object_to_uri( $actor['id'] ); + } + + if ( isset( $activity['object']['content'] ) ) { + $comment_content = \addslashes( $activity['object']['content'] ); + } + + $webfinger = Webfinger::uri_to_acct( $url ); + if ( is_wp_error( $webfinger ) ) { + $webfinger = ''; + } else { + $webfinger = str_replace( 'acct:', '', $webfinger ); + } + + $commentdata = array( + 'comment_author' => \esc_attr( $comment_author ), + 'comment_author_url' => \esc_url_raw( $url ), + 'comment_content' => $comment_content, + 'comment_type' => 'comment', + 'comment_author_email' => $webfinger, + 'comment_meta' => array( + 'source_id' => \esc_url_raw( object_to_uri( $activity['object'] ) ), + 'protocol' => 'activitypub', + ), + ); + + if ( isset( $actor['icon']['url'] ) ) { + $commentdata['comment_meta']['avatar_url'] = \esc_url_raw( $actor['icon']['url'] ); + } + + if ( isset( $activity['object']['url'] ) ) { + $commentdata['comment_meta']['source_url'] = \esc_url_raw( object_to_uri( $activity['object']['url'] ) ); + } + + return $commentdata; + } + + /** + * Persist a comment. + * + * @param array $commentdata The commentdata array. + * @param string $action Optional. Either 'insert' or 'update'. Default 'insert'. + * + * @return array|string|int|\WP_Error|false The comment data or false on failure + */ + public static function persist( $commentdata, $action = self::INSERT ) { + // Disable flood control. + \remove_action( 'check_comment_flood', 'check_comment_flood_db' ); + // Do not require email for AP entries. + \add_filter( 'pre_option_require_name_email', '__return_false' ); + // No nonce possible for this submission route. + \add_filter( + 'akismet_comment_nonce', + function () { + return 'inactive'; + } + ); + \add_filter( 'wp_kses_allowed_html', array( self::class, 'allowed_comment_html' ), 10, 2 ); + + if ( self::INSERT === $action ) { + $state = \wp_new_comment( $commentdata, true ); + } else { + $state = \wp_update_comment( $commentdata, true ); + } + + \remove_filter( 'wp_kses_allowed_html', array( self::class, 'allowed_comment_html' ) ); + \remove_filter( 'pre_option_require_name_email', '__return_false' ); + // Restore flood control. + \add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 ); + + if ( 1 === $state ) { + return $commentdata; + } else { + return $state; // Either WP_Comment, false, a WP_Error, 0, or 1! + } + } + + /** + * Get the total number of interactions by type for a given ID. + * + * @param int $post_id The post ID. + * @param string $type The type of interaction to count. + * + * @return int The total number of interactions. + */ + public static function count_by_type( $post_id, $type ) { + return \get_comments( + array( + 'post_id' => $post_id, + 'status' => 'approve', + 'type' => $type, + 'count' => true, + 'paging' => false, + 'fields' => 'ids', + ) + ); + } +} diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/includes/collection/class-outbox.php b/wp-content/upgrade-temp-backup/plugins/activitypub/includes/collection/class-outbox.php new file mode 100644 index 00000000..cf1dff89 --- /dev/null +++ b/wp-content/upgrade-temp-backup/plugins/activitypub/includes/collection/class-outbox.php @@ -0,0 +1,351 @@ +get_object() ); + + if ( ! $activity->get_actor() ) { + $activity->set_actor( Actors::get_by_id( $user_id )->get_id() ); + } + + $outbox_item = array( + 'post_type' => self::POST_TYPE, + 'post_title' => sprintf( + /* translators: 1. Activity type, 2. Object Title or Excerpt */ + __( '[%1$s] %2$s', 'activitypub' ), + $activity->get_type(), + \wp_trim_words( $title, 5 ) + ), + 'post_content' => wp_slash( $activity->to_json() ), + // ensure that user ID is not below 0. + 'post_author' => \max( $user_id, 0 ), + 'post_status' => 'pending', + 'meta_input' => array( + '_activitypub_object_id' => $object_id, + '_activitypub_activity_type' => $activity->get_type(), + '_activitypub_activity_actor' => $actor_type, + 'activitypub_content_visibility' => $visibility, + ), + ); + + $has_kses = false !== \has_filter( 'content_save_pre', 'wp_filter_post_kses' ); + if ( $has_kses ) { + // Prevent KSES from corrupting JSON in post_content. + \kses_remove_filters(); + } + + $id = \wp_insert_post( $outbox_item, true ); + + // Update the activity ID if the post was inserted successfully. + if ( $id && ! \is_wp_error( $id ) ) { + $activity->set_id( \get_the_guid( $id ) ); + + \wp_update_post( + array( + 'ID' => $id, + 'post_content' => \wp_slash( $activity->to_json() ), + ) + ); + } + + if ( $has_kses ) { + \kses_init_filters(); + } + + if ( \is_wp_error( $id ) ) { + return $id; + } + + if ( ! $id ) { + return false; + } + + self::invalidate_existing_items( $object_id, $activity->get_type(), $id ); + + return $id; + } + + /** + * Invalidate existing outbox items with the same activity type and object ID + * by setting their status to 'publish'. + * + * @param string $object_id The ID of the activity object. + * @param string $activity_type The type of the activity. + * @param int $current_id The ID of the current outbox item to exclude. + * + * @return void + */ + private static function invalidate_existing_items( $object_id, $activity_type, $current_id ) { + // Do not invalidate items for Announce activities. + if ( 'Announce' === $activity_type ) { + return; + } + + $meta_query = array( + array( + 'key' => '_activitypub_object_id', + 'value' => $object_id, + ), + ); + + // For non-Delete activities, only invalidate items of the same type. + if ( 'Delete' !== $activity_type ) { + $meta_query[] = array( + 'key' => '_activitypub_activity_type', + 'value' => $activity_type, + ); + } + + $existing_items = get_posts( + array( + 'post_type' => self::POST_TYPE, + 'post_status' => 'pending', + 'exclude' => array( $current_id ), + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + 'meta_query' => $meta_query, + 'fields' => 'ids', + ) + ); + + foreach ( $existing_items as $existing_item_id ) { + $event_args = array( + Dispatcher::$callback, + $existing_item_id, + Dispatcher::$batch_size, + \get_post_meta( $existing_item_id, '_activitypub_outbox_offset', true ) ?: 0, // phpcs:ignore + ); + + $timestamp = \wp_next_scheduled( 'activitypub_async_batch', $event_args ); + \wp_unschedule_event( $timestamp, 'activitypub_async_batch', $event_args ); + + $timestamp = \wp_next_scheduled( 'activitypub_process_outbox', array( $existing_item_id ) ); + \wp_unschedule_event( $timestamp, 'activitypub_process_outbox', array( $existing_item_id ) ); + + \wp_publish_post( $existing_item_id ); + \delete_post_meta( $existing_item_id, '_activitypub_outbox_offset' ); + } + } + + /** + * Creates an Undo activity. + * + * @param int|\WP_Post $outbox_item The Outbox post or post ID. + * + * @return int|bool The ID of the outbox item or false on failure. + */ + public static function undo( $outbox_item ) { + $outbox_item = get_post( $outbox_item ); + $activity = self::get_activity( $outbox_item ); + + $type = 'Undo'; + if ( 'Create' === $activity->get_type() ) { + $type = 'Delete'; + } elseif ( 'Add' === $activity->get_type() ) { + $type = 'Remove'; + } + + return add_to_outbox( $activity, $type, $outbox_item->post_author ); + } + + /** + * Reschedule an activity. + * + * @param int|\WP_Post $outbox_item The Outbox post or post ID. + * + * @return bool True if the activity was rescheduled, false otherwise. + */ + public static function reschedule( $outbox_item ) { + $outbox_item = get_post( $outbox_item ); + + $outbox_item->post_status = 'pending'; + $outbox_item->post_date = current_time( 'mysql' ); + + wp_update_post( $outbox_item ); + + Scheduler::schedule_outbox_activity_for_federation( $outbox_item->ID ); + + return true; + } + + /** + * Get the Activity object from the Outbox item. + * + * @param int|\WP_Post $outbox_item The Outbox post or post ID. + * @return Activity|\WP_Error The Activity object or WP_Error. + */ + public static function get_activity( $outbox_item ) { + $outbox_item = get_post( $outbox_item ); + $actor = self::get_actor( $outbox_item ); + if ( is_wp_error( $actor ) ) { + return $actor; + } + + $activity_object = \json_decode( $outbox_item->post_content, true ); + $type = \get_post_meta( $outbox_item->ID, '_activitypub_activity_type', true ); + + if ( $activity_object['type'] === $type ) { + $activity = Activity::init_from_array( $activity_object ); + if ( ! $activity->get_actor() ) { + $activity->set_actor( $actor->get_id() ); + } + } else { + $activity = new Activity(); + $activity->set_type( $type ); + $activity->set_id( $outbox_item->guid ); + $activity->set_actor( $actor->get_id() ); + // Pre-fill the Activity with data (for example cc and to). + $activity->set_object( $activity_object ); + } + + if ( 'Update' === $type ) { + $activity->set_updated( gmdate( ACTIVITYPUB_DATE_TIME_RFC3339, strtotime( $outbox_item->post_modified ) ) ); + } + + /** + * Filters the Activity object before it is returned. + * + * @param Activity $activity The Activity object. + * @param \WP_Post $outbox_item The outbox item post object. + */ + return apply_filters( 'activitypub_get_outbox_activity', $activity, $outbox_item ); + } + + /** + * Get the Actor object from the Outbox item. + * + * @param \WP_Post $outbox_item The Outbox post. + * + * @return \Activitypub\Model\User|\Activitypub\Model\Blog|\WP_Error The Actor object or WP_Error. + */ + public static function get_actor( $outbox_item ) { + $actor_type = \get_post_meta( $outbox_item->ID, '_activitypub_activity_actor', true ); + + switch ( $actor_type ) { + case 'blog': + $actor_id = Actors::BLOG_USER_ID; + break; + case 'application': + $actor_id = Actors::APPLICATION_USER_ID; + break; + case 'user': + default: + $actor_id = $outbox_item->post_author; + break; + } + + return Actors::get_by_id( $actor_id ); + } + + /** + * Get the Activity object from the Outbox item. + * + * @param \WP_Post $outbox_item The Outbox post. + * + * @return Activity|\WP_Error The Activity object or WP_Error. + */ + public static function maybe_get_activity( $outbox_item ) { + if ( ! $outbox_item instanceof \WP_Post ) { + return new \WP_Error( 'invalid_outbox_item', 'Invalid Outbox item.' ); + } + + if ( 'ap_outbox' !== $outbox_item->post_type ) { + return new \WP_Error( 'invalid_outbox_item', 'Invalid Outbox item.' ); + } + + // Check if Outbox Activity is public. + $visibility = \get_post_meta( $outbox_item->ID, 'activitypub_content_visibility', true ); + + if ( ! in_array( $visibility, array( ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC, ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC ), true ) ) { + return new \WP_Error( 'private_outbox_item', 'Not a public Outbox item.' ); + } + + $activity_types = \apply_filters( 'rest_activitypub_outbox_activity_types', array( 'Announce', 'Create', 'Like', 'Update' ) ); + $activity_type = \get_post_meta( $outbox_item->ID, '_activitypub_activity_type', true ); + + if ( ! in_array( $activity_type, $activity_types, true ) ) { + return new \WP_Error( 'private_outbox_item', 'Not public Outbox item type.' ); + } + + return self::get_activity( $outbox_item ); + } + + /** + * Get the object ID of an activity. + * + * @param Activity|Base_Object|string $data The activity object. + * + * @return string The object ID. + */ + private static function get_object_id( $data ) { + $object = $data->get_object(); + + if ( is_object( $object ) ) { + return self::get_object_id( $object ); + } + + if ( is_string( $object ) ) { + return $object; + } + + return $data->get_id() ?? $data->get_actor(); + } + + /** + * Get the title of an activity recursively. + * + * @param Base_Object $activity_object The activity object. + * + * @return string The title. + */ + private static function get_object_title( $activity_object ) { + if ( ! $activity_object ) { + return ''; + } + + if ( is_string( $activity_object ) ) { + $post_id = url_to_postid( $activity_object ); + + return $post_id ? get_the_title( $post_id ) : ''; + } + + $title = $activity_object->get_name() ?? $activity_object->get_content(); + + if ( ! $title && $activity_object->get_object() instanceof Base_Object ) { + $title = $activity_object->get_object()->get_name() ?? $activity_object->get_object()->get_content(); + } + + return $title; + } +} diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/includes/collection/class-replies.php b/wp-content/upgrade-temp-backup/plugins/activitypub/includes/collection/class-replies.php new file mode 100644 index 00000000..25b47d21 --- /dev/null +++ b/wp-content/upgrade-temp-backup/plugins/activitypub/includes/collection/class-replies.php @@ -0,0 +1,226 @@ + 'approve', + 'orderby' => 'comment_date_gmt', + 'order' => 'ASC', + 'type' => 'comment', + ); + + if ( $wp_object instanceof WP_Post ) { + $args['parent'] = 0; // TODO: maybe this is unnecessary. + $args['post_id'] = $wp_object->ID; + } elseif ( $wp_object instanceof WP_Comment ) { + $args['parent'] = $wp_object->comment_ID; + } else { + return new WP_Error(); + } + + return $args; + } + + /** + * Get the replies collections ID. + * + * @param WP_Post|WP_Comment $wp_object The post or comment to fetch replies for. + * + * @return string|WP_Error The rest URL of the replies collection or WP_Error if the object is not a post or comment. + */ + private static function get_id( $wp_object ) { + if ( $wp_object instanceof WP_Post ) { + return get_rest_url_by_path( sprintf( 'posts/%d/replies', $wp_object->ID ) ); + } elseif ( $wp_object instanceof WP_Comment ) { + return get_rest_url_by_path( sprintf( 'comments/%d/replies', $wp_object->comment_ID ) ); + } else { + return new WP_Error( 'unsupported_object', 'The object is not a post or comment.' ); + } + } + + /** + * Get the Replies collection. + * + * @param WP_Post|WP_Comment $wp_object The post or comment to fetch replies for. + * + * @return array|\WP_Error|null An associative array containing the replies collection without JSON-LD context on success. + */ + public static function get_collection( $wp_object ) { + $id = self::get_id( $wp_object ); + + if ( is_wp_error( $id ) ) { + return \wp_is_serving_rest_request() ? $id : null; + } + + $replies = array( + 'id' => $id, + 'type' => 'Collection', + ); + + $replies['first'] = self::get_collection_page( $wp_object, 1, $replies['id'] ); + + return $replies; + } + + /** + * Returns a replies collection page as an associative array. + * + * @link https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collectionpage + * + * @param WP_Post|WP_Comment $wp_object The post of comment the replies are for. + * @param int $page The current pagination page. + * @param string $part_of Optional. The collection id/url the returned CollectionPage belongs to. Default null. + * + * @return array|WP_Error|null A CollectionPage as an associative array on success, WP_Error or null on failure. + */ + public static function get_collection_page( $wp_object, $page, $part_of = null ) { + // Build initial arguments for fetching approved comments. + $args = self::build_args( $wp_object ); + if ( is_wp_error( $args ) ) { + return \wp_is_serving_rest_request() ? $args : null; + } + + // Retrieve the partOf if not already given. + $part_of = $part_of ?? self::get_id( $wp_object ); + + // If the collection page does not exist. + if ( is_wp_error( $part_of ) ) { + return \wp_is_serving_rest_request() ? $part_of : null; + } + + // Get to total replies count. + $total_replies = \get_comments( array_merge( $args, array( 'count' => true ) ) ); + + // If set to zero, we get errors below. You need at least one comment per page, here. + $args['number'] = max( (int) \get_option( 'comments_per_page' ), 1 ); + $args['offset'] = intval( $page - 1 ) * $args['number']; + + // Get the ActivityPub ID's of the comments, without local-only comments. + $comment_ids = self::get_reply_ids( \get_comments( $args ) ); + + // Build the associative CollectionPage array. + $collection_page = array( + 'id' => \add_query_arg( 'page', $page, $part_of ), + 'type' => 'CollectionPage', + 'partOf' => $part_of, + 'items' => $comment_ids, + ); + + if ( ( $total_replies / $args['number'] ) > $page ) { + $collection_page['next'] = \add_query_arg( 'page', $page + 1, $part_of ); + } + + if ( $page > 1 ) { + $collection_page['prev'] = \add_query_arg( 'page', $page - 1, $part_of ); + } + + return $collection_page; + } + + /** + * Get the context collection for a post. + * + * @param int $post_id The post ID. + * + * @return array|false The context for the post or false if the post is not found or disabled. + */ + public static function get_context_collection( $post_id ) { + $post = \get_post( $post_id ); + + if ( ! $post || is_post_disabled( $post_id ) ) { + return false; + } + + $comments = \get_comments( + array( + 'post_id' => $post_id, + 'type' => 'comment', + 'status' => 'approve', + 'orderby' => 'comment_date_gmt', + 'order' => 'ASC', + ) + ); + $ids = self::get_reply_ids( $comments, true ); + $post_uri = ( new PostTransformer( $post ) )->to_id(); + \array_unshift( $ids, $post_uri ); + + $author = Actors::get_by_id( $post->post_author ); + if ( is_wp_error( $author ) ) { + if ( is_user_type_disabled( 'blog' ) ) { + return false; + } + + $author = new Blog(); + } + + return array( + 'type' => 'OrderedCollection', + 'url' => \get_permalink( $post_id ), + 'attributedTo' => $author->get_id(), + 'totalItems' => count( $ids ), + 'items' => $ids, + ); + } + + /** + * Get the ActivityPub ID's from a list of comments. + * + * It takes only federated/non-local comments into account, others also do not have an + * ActivityPub ID available. + * + * @param WP_Comment[] $comments The comments to retrieve the ActivityPub ids from. + * @param boolean $include_blog_comments Optional. Include blog comments in the returned array. Default false. + * + * @return string[] A list of the ActivityPub ID's. + */ + private static function get_reply_ids( $comments, $include_blog_comments = false ) { + $comment_ids = array(); + + foreach ( $comments as $comment ) { + if ( is_local_comment( $comment ) ) { + continue; + } + + $public_comment_id = Comment::get_source_id( $comment->comment_ID ); + if ( $public_comment_id ) { + $comment_ids[] = $public_comment_id; + continue; + } + + if ( $include_blog_comments ) { + $comment_ids[] = ( new CommentTransformer( $comment ) )->to_id(); + } + } + + return \array_unique( $comment_ids ); + } +} diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/includes/collection/class-users.php b/wp-content/upgrade-temp-backup/plugins/activitypub/includes/collection/class-users.php new file mode 100644 index 00000000..12194903 --- /dev/null +++ b/wp-content/upgrade-temp-backup/plugins/activitypub/includes/collection/class-users.php @@ -0,0 +1,78 @@ + $v ) { + if ( ++$next_key !== $k ) { + return false; + } + } + + return true; + } +} + +if ( ! function_exists( 'str_contains' ) ) { + /** + * Polyfill for `str_contains()` function added in PHP 8.0. + * + * Performs a case-sensitive check indicating if needle is + * contained in haystack. + * + * @param string $haystack The string to search in. + * @param string $needle The substring to search for in the `$haystack`. + * + * @return bool True if `$needle` is in `$haystack`, otherwise false. + */ + function str_contains( $haystack, $needle ) { + if ( '' === $needle ) { + return true; + } + + return false !== strpos( $haystack, $needle ); + } +} + +if ( ! function_exists( 'wp_is_serving_rest_request' ) ) { + /** + * Polyfill for `wp_is_serving_rest_request()` function added in WordPress 6.5. + * + * @see https://developer.wordpress.org/reference/functions/wp_is_serving_rest_request/ + * + * @return bool True if it's a WordPress REST API request, false otherwise. + */ + function wp_is_serving_rest_request() { + return defined( 'REST_REQUEST' ) && REST_REQUEST; + } +} diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/includes/constants.php b/wp-content/upgrade-temp-backup/plugins/activitypub/includes/constants.php new file mode 100644 index 00000000..8b6c92d0 --- /dev/null +++ b/wp-content/upgrade-temp-backup/plugins/activitypub/includes/constants.php @@ -0,0 +1,76 @@ +)|(?<=' . $block['attrs']['url'] . '
'; + } + + /** + * Check if the post is a preview. + * + * @return boolean True if the post is a preview, false otherwise. + */ + private function is_preview() { + return defined( 'ACTIVITYPUB_PREVIEW' ) && ACTIVITYPUB_PREVIEW; + } + + /** + * Get enclosures for a post. + * + * @param array $media The media array grouped by type. + * + * @return array The media array extended with enclosures. + */ + protected function get_enclosures( $media ) { + $enclosures = get_enclosures( $this->item->ID ); + + if ( ! $enclosures ) { + return $media; + } + + foreach ( $enclosures as $enclosure ) { + // Check if URL is an attachment. + $attachment_id = \attachment_url_to_postid( $enclosure['url'] ); + + if ( $attachment_id ) { + $enclosure['id'] = $attachment_id; + $enclosure['url'] = \wp_get_attachment_url( $attachment_id ); + $enclosure['mediaType'] = \get_post_mime_type( $attachment_id ); + } + + $mime_type = $enclosure['mediaType']; + $mime_type_parts = \explode( '/', $mime_type ); + $enclosure['type'] = \ucfirst( $mime_type_parts[0] ); + + switch ( $mime_type_parts[0] ) { + case 'image': + $media['image'][] = $enclosure; + break; + case 'audio': + $media['audio'][] = $enclosure; + break; + case 'video': + $media['video'][] = $enclosure; + break; + } + } + + return $media; + } + + /** + * Get media attachments from blocks. They will be formatted as ActivityPub attachments, not as WP attachments. + * + * @param array $media The media array grouped by type. + * @param int $max_media The maximum number of attachments to return. + * + * @return array The attachments. + */ + protected function get_block_attachments( $media, $max_media ) { + // Max media can't be negative or zero. + if ( $max_media <= 0 ) { + return array(); + } + + $blocks = \parse_blocks( $this->item->post_content ); + + return $this->get_media_from_blocks( $blocks, $media ); + } + + /** + * Recursively get media IDs from blocks. + * + * @param array $blocks The blocks to search for media IDs. + * @param array $media The media IDs to append new IDs to. + * + * @return array The image IDs. + */ + protected function get_media_from_blocks( $blocks, $media ) { + foreach ( $blocks as $block ) { + // Recurse into inner blocks. + if ( ! empty( $block['innerBlocks'] ) ) { + $media = $this->get_media_from_blocks( $block['innerBlocks'], $media ); + } + + switch ( $block['blockName'] ) { + case 'core/image': + case 'core/cover': + if ( ! empty( $block['attrs']['id'] ) ) { + $alt = ''; + $check = preg_match( '/%2$s
%2$s
)|(?<=
)|^)#([A-Za-z0-9_]+)(?:(?=\s|[[:punct:]]|$))`.
+* `ACTIVITYPUB_USERNAME_REGEXP` - Change the default regex to detect @-replies in a text. Default: `(?:([A-Za-z0-9\._-]+)@((?:[A-Za-z0-9_-]+\.)+[A-Za-z]+))`.
+* `ACTIVITYPUB_URL_REGEXP` - Change the default regex to detect urls in a text. Default: `(www.|http:|https:)+[^\s]+[\w\/]`.
+* `ACTIVITYPUB_CUSTOM_POST_CONTENT` - Change the default template for Activities. Default: `[ap_title]\n\n[ap_content]\n\n[ap_hashtags]\n\n[ap_shortlink]`.
+* `ACTIVITYPUB_AUTHORIZED_FETCH` - Enable AUTHORIZED_FETCH.
+* `ACTIVITYPUB_DISABLE_REWRITES` - Disable auto generation of `mod_rewrite` rules. Default: `false`.
+* `ACTIVITYPUB_DISABLE_INCOMING_INTERACTIONS` - Block incoming replies/comments/likes. Default: `false`.
+* `ACTIVITYPUB_DISABLE_OUTGOING_INTERACTIONS` - Disable outgoing replies/comments/likes. Default: `false`.
+* `ACTIVITYPUB_SHARED_INBOX_FEATURE` - Enable the shared inbox. Default: `false`.
+* `ACTIVITYPUB_SEND_VARY_HEADER` - Enable to send the `Vary: Accept` header. Default: `false`.
+
+= Where can you manage your followers? =
+
+If you have activated the blog user, you will find the list of his followers in the settings under `/wp-admin/options-general.php?page=activitypub&tab=followers`.
+
+The followers of a user can be found in the menu under "Users" -> "Followers" or under `wp-admin/users.php?page=activitypub-followers-list`.
+
+For reasons of data protection, it is not possible to see the followers of other users.
+
+== Screenshots ==
+
+1. The "Follow me"-Block in the Block-Editor
+2. The "Followers"-Block in the Block-Editor
+3. The "Federated Reply"-Block in the Block-Editor
+4. A "Federated Reply" in a Post
+5. A Blog-Profile on Mastodon
+
+== Changelog ==
+
+### 5.8.0 - 2025-04-24
+#### Added
+- An option to receive notification emails when an Actor was mentioned in the Fediverse.
+- Enable direct linking to Help Tabs.
+- Fallback embed support for Fediverse content that lacks native oEmbed responses.
+- Support for all media types in the Mastodon Importer.
+
+#### Changed
+- Added WordPress disallowed list filtering to block unwanted ActivityPub interactions.
+- Mastodon imports now support blocks, with automatic reply embedding for conversations.
+- Tested and compatible with the latest version of WordPress.
+- Updated design of new follower notification email and added meta information.
+- Update DM email notification to include an embed display of the DM.
+- Updated notification settings to be user-specific for more personalization.
+
+#### Fixed
+- Add support for Multisite Language Switcher
+- Better check for an empty `headers` array key in the Signature class.
+- Include user context in Global-Inbox actions.
+- No more PHP warning when Mastodon Apps run out of posts to process.
+- Reply links and popup modals are now properly translated for logged-out visitors.
+
+### 5.7.0 - 2025-04-11
+#### Added
+- Advanced Settings tab, with special settings for advanced users.
+- Check if pretty permalinks are enabled and recommend to use threaded comments.
+- Reply block: show embeds where available.
+- Support same-server domain migrations.
+- Upgrade routine that removes any erroneously created extra field entries.
+
+#### Changed
+- Add option to enable/disable the "shared inbox" to the "Advanced Settings".
+- Add option to enable/disable the `Vary` Header to the "Advanced Settings".
+- Configure the "Follow Me" button to have a button-only mode.
+- Importers are loaded on admin-specific hook.
+- Improve the troubleshooting UI and show Site-Health stats in ActivityPub settings.
+- Increased compatibility with Mobilizon and other platforms by improving signature verification for different key formats.
+
+#### Fixed
+- Ensure that an `Activity` has an `Actor` before adding it to the Outbox.
+- Fixed some bugs and added additional information on the Debug tab of the Site-Health page.
+- Follow-up to the reply block changes that makes sure Mastodon embeds are displayed in the editor.
+- Outbox endpoint bug where non-numeric usernames caused errors when querying Outbox data.
+- Show Site Health error if site uses old "Almost Pretty Permalinks" structure.
+- Sites with comments from the Fediverse no longer create uncached extra fields posts that flood the Outbox.
+- Transformers allow settings values to false again, a regression from 5.5.0.
+
+### 5.6.1 - 2025-04-02
+#### Fixed
+- "Post Interactions" settings will now be saved to the options table.
+- So not show `movedTo` attribute instead of setting it to `false` if empty.
+- Use specified date format for `updated` field in Outbox-Activites.
+
+### 5.6.0 - 2025-04-01
+#### Added
+- Added a Mastodon importer to move your Mastodon posts to your WordPress site.
+- A default Extra-Field to do a little advertising for WordPress.
+- Move: Differentiate between `internal` and 'external' Move.
+- Redirect user to the welcome page after ActivityPub plugin is activated.
+- The option to show/hide the "Welcome Page".
+- User setting to enable/disable Likes and Reblogs
+
+#### Changed
+- Logged-out remote reply button markup to look closer to logged-in version.
+- No longer federates `Delete` activities for posts that were not federated.
+- OrderedCollection and OrderedCollectionPage behave closer to spec now.
+- Outbox items now contain the full activity, not just activity objects.
+- Standardized mentions to use usernames only in comments and posts.
+
+#### Fixed
+- Changelog entries: allow automating changelog entry generation from forks as well.
+- Comments from Fediverse actors will now be purged as expected.
+- Importing attachments no longer creates Outbox items for them.
+- Improved readability in Mastodon Apps plugin string.
+- No more PHP warnings when previewing posts without attachments.
+- Outbox batch processing adheres to passed batch size.
+- Permanently delete reactions that were `Undo` instead of trashing them.
+- PHP warnings when scheduling post activities for an invalid post.
+- PHP Warning when there's no actor information in comment activities.
+- Prevent self-replies on local comments.
+- Properly set `to` audience of `Activity` instead of changing the `Follow` Object.
+- Run all Site-Health checks with the required headers and a valid signature.
+- Set `updated` field for profile updates, otherwise the `Update`-`Activity` wouldn't be handled by Mastodon.
+- Support multiple layers of nested Outbox activities when searching for the Object ID.
+- The Custom-Avatar getter on WP.com.
+- Use the $from account for the object in Move activity for external Moves
+- Use the `$from` account for the object in Move activity for internal Moves
+- Use `add_to_outbox` instead of the changed scheduler hooks.
+- Use `JSON_UNESCAPED_SLASHES` because Mastodon seems to have problems with encoded URLs.
+- `Scheduler::schedule_announce_activity` to handle Activities instead of Activity-Objects.
+
+### 5.5.0 - 2025-03-19
+#### Added
+- Added "Enable Mastodon Apps" and "Event Bridge for ActivityPub" to the recommended plugins section.
+- Added Constants to the Site-Health debug informations.
+- Development environment: add Changelogger tool to environment dependencies.
+- Development environment: allow contributors to specify a changelog entry directly from their Pull Request description.
+- Documentation for migrating from a Mastodon instance to WordPress.
+- Support for sending Activities to ActivityPub Relays, to improve discoverability of public content.
+
+#### Changed
+- Documentation: expand Pull Request process docs, and mention the new changelog process as well as the updated release process.
+- Don't redirect @-name URLs to trailing slashed versions
+- Improved and simplified Query code.
+- Improved readability for actor mode setting.
+- Improved title case for NodeInfo settings.
+- Introduced utility function to determine actor type based on user ID.
+- Outbox items only get sent to followers when there are any.
+- Restricted modifications to settings if they are predefined as constants.
+- The Welcome page now uses WordPress's Settings API and the classic design of the WP Admin.
+- Uses two-digit version numbers in Outbox and NodeInfo responses.
+
+#### Removed
+- Our version of `sanitize_url()` was unused—use Core's `sanitize_url()` instead.
+
+#### Fixed
+- Ensured that Query::get_object_id() returns an ID instead of an Object.
+- Fix a fatal error in the Preview when a post contains no (hash)tags.
+- Fixed an issue with the Content Carousel and Blog Posts block: https://github.com/Automattic/wp-calypso/issues/101220
+- Fixed default value for `activitypub_authorized_fetch` option.
+- Follow-Me blocks now show the correct avatar on attachment pages.
+- Images with the correct aspect ratio no longer get sent through the crop step again.
+- No more PHP warnings when a header image gets cropped.
+- PHP warnings when trying to process empty tags or image blocks without ID attributes.
+- Properly re-added support for `Update` and `Delete` `Announce`ments.
+- Updates to certain user meta fields did not trigger an Update activity.
+- When viewing Reply Contexts, we'll now attribute the post to the blog user when the post author is disabled.
+
+### 5.4.1 - 2025-03-04
+#### Fixed
+- Fixed transition handling of posts to ensure that `Create` and `Update` activities are properly processed.
+- Show "full content" preview even if post is in still in draft mode.
+
+### 5.4.0 - 2025-03-03
+#### Added
+- Upgrade script to fix Follower json representations with unescaped backslashes.
+- Centralized place for sanitization functions.
+
+#### Changed
+- Bumped minimum required WordPress version to 6.4.
+- Use a later hook for Posts to get published to the Outbox, to get sure all `post_meta`s and `taxonomy`s are set stored properly.
+- Use webfinger as author email for comments from the Fediverse.
+- Remove the special handling of comments from Enable Mastodon Apps.
+
+#### Fixed
+- Do not redirect `/@username` URLs to the API any more, to improve `AUTHORIZED_FETCH` handling.
+
+### 5.3.2 - 2025-02-27
+#### Fixed
+- Remove `activitypub_reply_block` filter after Activity-JSON is rendered, to not affect the HTML representation.
+- Remove `render_block_core/embed` filter after Activity-JSON is rendered, to not affect the HTML representation.
+
+### 5.3.1 - 2025-02-26
+#### Fixed
+- Blog profile settings can be saved again without errors.
+- Followers with backslashes in their descriptions no longer break their actor representation.
+
+### 5.3.0 - 2025-02-25
+#### Added
+- A fallback `Note` for `Article` objects to improve previews on services that don't support Articles yet.
+- A reply `context` for Posts and Comments to allow relying parties to discover the whole conversation of a thread.
+- Setting to adjust the number of days Outbox items are kept before being purged.
+- Failed Follower notifications for Outbox items now get retried for two more times.
+- Undo API for Outbox items.
+- Metadata to New Follower E-Mail.
+- Allow Activities on URLs instead of requiring Activity-Objects. This is useful especially for sending Announces and Likes.
+- Outbox Activity IDs can now be resolved when the ActivityPub `Accept header is used.
+- Support for incoming `Move` activities and ensure that followed persons are updated accordingly.
+- Labels to add context to visibility settings in the block editor.
+- WP CLI command to reschedule Outbox-Activities.
+
+#### Changed
+- Outbox now precesses the first batch of followers right away to avoid delays in processing new Activities.
+- Post bulk edits no longer create Outbox items, unless author or post status change.
+- Properly process `Update` activities on profiles and ensure all properties of a followed person are updated accordingly.
+- Outbox processing accounts for shared inboxes again.
+- Improved check for `?activitypub` query-var.
+- Rewrite rules: be more specific in author rewrite rules to avoid conflicts on sites that use the "@author" pattern in their permalinks.
+- Deprecate the `activitypub_post_locale` filter in favor of the `activitypub_locale` filter.
+
+#### Fixed
+- The Outbox purging routine no longer is limited to deleting 5 items at a time.
+- Ellipses now display correctly in notification emails for Likes and Reposts.
+- Send Update-Activity when "Actor-Mode" is changed.
+- Added delay to `Announce` Activity from the Blog-Actor, to not have race conditions.
+- `Actor` validation in several REST API endpoints.
+- Bring back the `activitypub_post_locale` filter to allow overriding the post's locale.
+
+### 5.2.0 - 2025-02-13
+#### Added
+- Batch Outbox-Processing.
+- Outbox processed events get logged in Stream and show any errors returned from inboxes.
+- Outbox items older than 6 months will be purged to avoid performance issues.
+- REST API endpoints for likes and shares.
+
+#### Changed
+- Increased probability of Outbox items being processed with the correct author.
+- Enabled querying of Outbox posts through the REST API to improve troubleshooting and debugging.
+- Updated terminology to be client-neutral in the Federated Reply block.
+
+#### Fixed
+- Fixed an issue where the outbox could not send object types other than `Base_Object` (introduced in 5.0.0).
+- Enforce 200 status header for valid ActivityPub requests.
+- `object_id_to_comment` returns a commment now, even if there are more than one matching comment in the DB.
+- Integration of content-visibility setup in the block editor.
+- Update CLI commands to the new scheduler refactorings.
+- Do not add an audience to the Actor-Profiles.
+- `Activity::set_object` falsely overwrites the Activity-ID with a default.
+
+### 5.1.0 - 2025-02-06
+#### Added
+- Cleanup of option values when the plugin is uninstalled.
+- Third-party plugins can filter settings tabs to add their own settings pages for ActivityPub.
+- Show ActivityPub preview in row actions when Block Editor is enabled but not used for the post type.
+
+#### Changed
+- Manually granting `activitypub` cap no longer requires the receiving user to have `publish_post`.
+- Allow omitting replies in ActivityPub representations instead of setting them as empty.
+- Allow Base Transformer to handle WP_Term objects for transformation.
+- Improved Query extensibility for third party plugins.
+
+#### Fixed
+- Negotiation of ActivityPub requests for custom post types when queried by the ActivityPub ID.
+- Avoid PHP warnings when using Debug mode and when the `actor` is not set.
+- No longer creates Outbox items when importing content/users.
+- Fix NodeInfo 2.0 URL to be HTTP instead of HTTPS.
+
+### 5.0.0 - 2025-02-03
+#### Changed
+- Improved content negotiation and AUTHORIZED_FETCH support for third-party plugins.
+- Moved password check to `is_post_disabled` function.
+
+#### Fixed
+- Handle deletes from remote servers that leave behind an accessible Tombstone object.
+- No longer parses tags for post types that don't support Activitypub.
+- rel attribute will now contain no more than one "me" value.
+
+See full Changelog on [GitHub](https://github.com/Automattic/wordpress-activitypub/blob/trunk/CHANGELOG.md).
+
+== Upgrade Notice ==
+
+= 5.4.0 =
+
+Note: This update requires WordPress 6.4+. Please ensure your site meets this requirement before upgrading.
+
+== 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.
diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/templates/activitypub-json.php b/wp-content/upgrade-temp-backup/plugins/activitypub/templates/activitypub-json.php
new file mode 100644
index 00000000..036a99b8
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/activitypub/templates/activitypub-json.php
@@ -0,0 +1,25 @@
+get_activitypub_object();
+
+/**
+ * Fires before an ActivityPub object is generated and sent to the client.
+ *
+ * @param object $object The ActivityPub object.
+ */
+\do_action( 'activitypub_json_pre', $object );
+
+\header( 'Content-Type: application/activity+json' );
+echo $object->to_json(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+
+/**
+ * Fires after an ActivityPub object is generated and sent to the client.
+ *
+ * @param object $object The ActivityPub object.
+ */
+\do_action( 'activitypub_json_post', $object );
diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/templates/admin-header.php b/wp-content/upgrade-temp-backup/plugins/activitypub/templates/admin-header.php
new file mode 100644
index 00000000..0c655dca
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/activitypub/templates/admin-header.php
@@ -0,0 +1,34 @@
+
+
+ ' . esc_html( $args['actor']['webfinger'] ) . '
+ ' . esc_html( $args['webfinger'] ) . '' ); + ?> +
+ ++ + + +
+ ++ followers list to see all followers.', 'activitypub' ), array( 'a' => array( 'href' => array() ) ) ), + esc_url( admin_url( $args['admin_url'] ) ) + ); + ?> +
+ + + ++ ' . esc_html( $args['actor']['webfinger'] ) . '' ); + ?> +
+ + + ++ + + +
+ + + + diff --git a/wp-content/upgrade-temp-backup/plugins/activitypub/templates/emails/parts/header.php b/wp-content/upgrade-temp-backup/plugins/activitypub/templates/emails/parts/header.php new file mode 100644 index 00000000..6ea7e471 --- /dev/null +++ b/wp-content/upgrade-temp-backup/plugins/activitypub/templates/emails/parts/header.php @@ -0,0 +1,60 @@ + + + ++ +
+ + + + +| + + | ++ + | +
|---|---|
| in_reply_to | ++ |
| post_type | ++ |
+ +
++ +
++ +
++ +
+e||125[openid-connect-generic-alter-user-claim](#openid-connect-generic-alter-user-claim)
+ - [openid-connect-generic-alter-user-data](#openid-connect-generic-alter-user-data)
+ - [openid-connect-generic-settings-fields](#openid-connect-generic-settings-fields)
+ - [Actions](#actions)
+ - [openid-connect-generic-user-create](#openid-connect-generic-user-create)
+ - [openid-connect-generic-user-update](#openid-connect-generic-user-update)
+ - [openid-connect-generic-update-user-using-current-claim](#openid-connect-generic-update-user-using-current-claim)
+ - [openid-connect-generic-redirect-user-back](#openid-connect-generic-redirect-user-back)
+
+
+## Installation
+
+1. Upload to the `/wp-content/plugins/` directory
+1. Activate the plugin
+1. Visit Settings > OpenID Connect and configure to meet your needs
+
+### Composer
+
+[OpenID Connect Generic on packagist](https://packagist.org/packages/daggerhart/openid-connect-generic)
+
+Installation:
+
+`composer require daggerhart/openid-connect-generic`
+
+
+## Frequently Asked Questions
+
+### What is the client's Redirect URI?
+
+Most OAuth2 servers should require a whitelist of redirect URIs for security purposes. The Redirect URI provided
+by this client is like so: `https://example.com/wp-admin/admin-ajax.php?action=openid-connect-authorize`
+
+Replace `example.com` with your domain name and path to WordPress.
+
+### Can I change the client's Redirect URI?
+
+Some OAuth2 servers do not allow for a client redirect URI to contain a query string. The default URI provided by
+this module leverages WordPress's `admin-ajax.php` endpoint as an easy way to provide a route that does not include
+HTML, but this will naturally involve a query string. Fortunately, this plugin provides a setting that will make use of
+an alternate redirect URI that does not include a query string.
+
+On the settings page for this plugin (Dashboard > Settings > OpenID Connect Generic) there is a checkbox for
+**Alternate Redirect URI**. When checked, the plugin will use the Redirect URI
+`https://example.com/openid-connect-authorize`.
+
+## Configuration Environment Variables/Constants
+
+- Client ID: `OIDC_CLIENT_ID`
+- Client Secret Key: `OIDC_CLIENT_SECRET`
+- Login Endpoint URL: `OIDC_ENDPOINT_LOGIN_URL`
+- Userinfo Endpoint URL: `OIDC_ENDPOINT_USERINFO_URL`
+- Token Validation Endpoint URL: `OIDC_ENDPOINT_TOKEN_URL`
+- End Session Endpoint URL: `OIDC_ENDPOINT_LOGOUT_URL`
+- OpenID scope: `OIDC_CLIENT_SCOPE` (space separated)
+- OpenID login type: `OIDC_LOGIN_TYPE` ('button' or 'auto')
+- Enforce privacy: `OIDC_ENFORCE_PRIVACY` (boolean)
+- Create user if they do not exist: `OIDC_CREATE_IF_DOES_NOT_EXIST` (boolean)
+- Link existing user: `OIDC_LINK_EXISTING_USERS` (boolean)
+- Redirect user back to origin page: `OIDC_REDIRECT_USER_BACK` (boolean)
+- Redirect on logout: `OIDC_REDIRECT_ON_LOGOUT` (boolean)
+
+## Hooks
+
+This plugin provides a number of hooks to allow for a significant amount of customization of the plugin operations from
+elsewhere in the WordPress system.
+
+### Filters
+
+Filters are WordPress hooks that are used to modify data. The first argument in a filter hook is always expected to be
+returned at the end of the hook.
+
+WordPress filters API - [`add_filter()`](https://developer.wordpress.org/reference/functions/add_filter/) and
+[`apply_filters()`](https://developer.wordpress.org/reference/functions/apply_filters/).
+
+Most often you'll only need to use `add_filter()` to hook into this plugin's code.
+
+#### `openid-connect-generic-alter-request`
+
+Hooks directly into client before requests are sent to the OpenID Server.
+
+Provides 2 arguments: the request array being sent to the server, and the operation currently being executed by this
+plugin.
+
+Possible operations:
+
+- get-authentication-token
+- refresh-token
+- get-userinfo
+
+```
+add_filter('openid-connect-generic-alter-request', function( $request, $operation ) {
+ if ( $operation == 'get-authentication-token' ) {
+ $request['some_key'] = 'modified value';
+ }
+
+ return $request;
+}, 10, 2);
+```
+
+#### `openid-connect-generic-login-button-text`
+
+Modify the login button text. Default value is `__( 'Login with OpenID Connect' )`.
+
+Provides 1 argument: the current login button text.
+
+```
+add_filter('openid-connect-generic-login-button-text', function( $text ) {
+ $text = __('Login to my super cool IDP server');
+
+ return $text;
+});
+```
+
+#### `openid-connect-generic-auth-url`
+
+Modify the authentication URL before presented to the user. This is the URL that will send the user to the IDP server
+for login.
+
+Provides 1 argument: the plugin generated URL.
+
+```
+add_filter('openid-connect-generic-auth-url', function( $url ) {
+ // Add some custom data to the url.
+ $url.= '&my_custom_data=123abc';
+ return $url;
+});
+```
+
+#### `openid-connect-generic-user-login-test`
+
+Determine whether or not the user should be logged into WordPress.
+
+Provides 2 arguments: the boolean result of the test (default `TRUE`), and the `$user_claim` array from the server.
+
+```
+add_filter('openid-connect-generic-user-login-test', function( $result, $user_claim ) {
+ // Don't let Terry login.
+ if ( $user_claim['email'] == 'terry@example.com' ) {
+ $result = FALSE;
+ }
+
+ return $result;
+}, 10, 2);
+```
+
+#### `openid-connect-generic-user-creation-test`
+
+Determine whether or not the user should be created. This filter is called when a new user is trying to login and they
+do not currently exist within WordPress.
+
+Provides 2 arguments: the boolean result of the test (default `TRUE`), and the `$user_claim` array from the server.
+
+```
+add_filter('', function( $result, $user_claim ) {
+ // Don't let anyone from example.com create an account.
+ $email_array = explode( '@', $user_claim['email'] );
+ if ( $email_array[1] == 'example.com' ) {
+ $result = FALSE;
+ }
+
+ return $result;
+}, 10, 2)
+```
+
+#### `openid-connect-generic-alter-user-claim`
+
+Modify the `$user_claim` before the plugin builds the `$user_data` array for new user created.
+
+**Deprecated** - This filter is not very useful due to some changes that were added later. Recommend not using this
+filter, and using the `openid-connect-generic-alter-user-data` filter instead. Practically, you can only change the
+user's `first_name` and `last_name` values with this filter, but you could easily do that in
+`openid-connect-generic-alter-user-data` as well.
+
+Provides 1 argument: the `$user_claim` from the server.
+
+```
+// Not a great example because the hook isn't very useful.
+add_filter('openid-connect-generic-alter-user-claim', function( $user_claim ) {
+ // Use the beginning of the user's email address as the user's first name.
+ if ( empty( $user_claim['given_name'] ) ) {
+ $email_array = explode( '@', $user_claim['email'] );
+ $user_claim['given_name'] = $email_array[0];
+ }
+
+ return $user_claim;
+});
+```
+
+#### `openid-connect-generic-alter-user-data`
+
+Modify a new user's data immediately before the user is created.
+
+Provides 2 arguments: the `$user_data` array that will be sent to `wp_insert_user()`, and the `$user_claim` from the
+server.
+
+```
+add_filter('openid-connect-generic-alter-user-data', function( $user_data, $user_claim ) {
+ // Don't register any user with their real email address. Create a fake internal address.
+ if ( !empty( $user_data['user_email'] ) ) {
+ $email_array = explode( '@', $user_data['user_email'] );
+ $email_array[1] = 'my-fake-domain.co';
+ $user_data['user_email'] = implode( '@', $email_array );
+ }
+
+ return $user_data;
+}, 10, 2);
+```
+
+#### `openid-connect-generic-settings-fields`
+
+For extending the plugin with a new setting field (found on Dashboard > Settings > OpenID Connect Generic) that the site
+administrator can modify. Also useful to alter the existing settings fields.
+
+See `/includes/openid-connect-generic-settings-page.php` for how fields are constructed.
+
+New settings fields will be automatically saved into the wp_option for this plugin's settings, and will be available in
+the `\OpenID_Connect_Generic_Option_Settings` object this plugin uses.
+
+**Note:** It can be difficult to get a copy of the settings from within other hooks. The easiest way to make use of
+settings in your custom hooks is to call
+`$settings = get_option('openid_connect_generic_settings', array());`.
+
+Provides 1 argument: the existing fields array.
+
+```
+add_filter('openid-connect-generic-settings-fields', function( $fields ) {
+
+ // Modify an existing field's title.
+ $fields['endpoint_userinfo']['title'] = __('User information endpoint url');
+
+ // Add a new field that is a simple checkbox.
+ $fields['block_terry'] = array(
+ 'title' => __('Block Terry'),
+ 'description' => __('Prevent Terry from logging in'),
+ 'type' => 'checkbox',
+ 'section' => 'authorization_settings',
+ );
+
+ // A select field that provides options.
+
+ $fields['deal_with_terry'] = array(
+ 'title' => __('Manage Terry'),
+ 'description' => __('How to deal with Terry when he tries to log in.'),
+ 'type' => 'select',
+ 'options' => array(
+ 'allow' => __('Allow login'),
+ 'block' => __('Block'),
+ 'redirect' => __('Redirect'),
+ ),
+ 'section' => 'authorization_settings',
+ );
+
+ return $fields;
+});
+```
+"Sections" are where your setting appears on the admin settings page. Keys for settings sections:
+
+- client_settings
+- user_settings
+- authorization_settings
+- log_settings
+
+Field types:
+
+- text
+- checkbox
+- select (requires an array of "options")
+
+### Actions
+
+WordPress actions are generic events that other plugins can react to.
+
+Actions API: [`add_action`](https://developer.wordpress.org/reference/functions/add_action/) and [`do_actions`](https://developer.wordpress.org/reference/functions/do_action/)
+
+You'll probably only ever want to use `add_action` when hooking into this plugin.
+
+#### `openid-connect-generic-user-create`
+
+React to a new user being created by this plugin.
+
+Provides 2 arguments: the `\WP_User` object that was created, and the `$user_claim` from the IDP server.
+
+```
+add_action('openid-connect-generic-user-create', function( $user, $user_claim ) {
+ // Send the user an email when their account is first created.
+ wp_mail(
+ $user->user_email,
+ __('Welcome to my web zone'),
+ "Hi {$user->first_name},\n\nYour account has been created at my cool website.\n\n Enjoy!"
+ );
+}, 10, 2);
+```
+
+#### `openid-connect-generic-user-update`
+
+React to the user being updated after login. This is the event that happens when a user logins and they already exist as
+a user in WordPress, as opposed to a new WordPress user being created.
+
+Provides 1 argument: the user's WordPress user ID.
+
+```
+add_action('openid-connect-generic-user-update', function( $uid ) {
+ // Keep track of the number of times the user has logged into the site.
+ $login_count = get_user_meta( $uid, 'my-user-login-count', TRUE);
+ $login_count += 1;
+ add_user_meta( $uid, 'my-user-login-count', $login_count, TRUE);
+});
+```
+
+#### `openid-connect-generic-update-user-using-current-claim`
+
+React to an existing user logging in (after authentication and authorization).
+
+Provides 2 arguments: the `WP_User` object, and the `$user_claim` provided by the IDP server.
+
+```
+add_action('openid-connect-generic-update-user-using-current-claim', function( $user, $user_claim) {
+ // Based on some data in the user_claim, modify the user.
+ if ( !empty( $user_claim['wp_user_role'] ) ) {
+ if ( $user_claim['wp_user_role'] == 'should-be-editor' ) {
+ $user->set_role( 'editor' );
+ }
+ }
+}, 10, 2);
+```
+
+#### `openid-connect-generic-redirect-user-back`
+
+React to a user being redirected after a successful login. This hook is the last hook that will fire when a user logs
+in. It will only fire if the plugin setting "Redirect Back to Origin Page" is enabled at Dashboard > Settings >
+OpenID Connect Generic. It will fire for both new and existing users.
+
+Provides 2 arguments: the url where the user will be redirected, and the `WP_User` object.
+
+```
+add_action('openid-connect-generic-redirect-user-back', function( $redirect_url, $user ) {
+ // Take over the redirection complete. Send users somewhere special based on their capabilities.
+ if ( $user->has_cap( 'edit_users' ) ) {
+ wp_redirect( admin_url( 'users.php' ) );
+ exit();
+ }
+}, 10, 2);
+```
+
+### User Meta Data
+
+This plugin stores meta data about the user for both practical and debugging purposes.
+
+* `openid-connect-generic-subject-identity` - The identity of the user provided by the IDP server.
+* `openid-connect-generic-last-id-token-claim` - The user's most recent `id_token` claim, decoded and stored as an array.
+* `openid-connect-generic-last-user-claim` - The user's most recent `user_claim`, stored as an array.
+* `openid-connect-generic-last-token-response` - The user's most recent `token_response`, stored as an array.
diff --git a/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/README.md b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/README.md
new file mode 100644
index 00000000..6b8776ef
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/README.md
@@ -0,0 +1,133 @@
+# OpenID Connect Generic Client #
+**Contributors:** [daggerhart](https://profiles.wordpress.org/daggerhart/), [tnolte](https://profiles.wordpress.org/tnolte/)
+**Tags:** security, login, oauth2, openidconnect, apps, authentication, autologin, sso
+**Requires at least:** 5.0
+**Tested up to:** 6.4.3
+**Stable tag:** 3.10.1
+**Requires PHP:** 7.4
+**License:** GPLv2 or later
+**License URI:** http://www.gnu.org/licenses/gpl-2.0.html
+
+A simple client that provides SSO or opt-in authentication against a generic OAuth2 Server implementation.
+
+## Description ##
+
+This plugin allows to authenticate users against OpenID Connect OAuth2 API with Authorization Code Flow.
+Once installed, it can be configured to automatically authenticate users (SSO), or provide a "Login with OpenID Connect"
+button on the login form. After consent has been obtained, an existing user is automatically logged into WordPress, while
+new users are created in WordPress database.
+
+Much of the documentation can be found on the Settings > OpenID Connect Generic dashboard page.
+
+Please submit issues to the Github repo: https://github.com/oidc-wp/openid-connect-generic
+
+## Installation ##
+
+1. Upload to the `/wp-content/plugins/` directory
+1. Activate the plugin
+1. Visit Settings > OpenID Connect and configure to meet your needs
+
+## Frequently Asked Questions ##
+
+### What is the client's Redirect URI? ###
+
+Most OAuth2 servers will require whitelisting a set of redirect URIs for security purposes. The Redirect URI provided
+by this client is like so: https://example.com/wp-admin/admin-ajax.php?action=openid-connect-authorize
+
+Replace `example.com` with your domain name and path to WordPress.
+
+### Can I change the client's Redirect URI? ###
+
+Some OAuth2 servers do not allow for a client redirect URI to contain a query string. The default URI provided by
+this module leverages WordPress's `admin-ajax.php` endpoint as an easy way to provide a route that does not include
+HTML, but this will naturally involve a query string. Fortunately, this plugin provides a setting that will make use of
+an alternate redirect URI that does not include a query string.
+
+On the settings page for this plugin (Dashboard > Settings > OpenID Connect Generic) there is a checkbox for
+**Alternate Redirect URI**. When checked, the plugin will use the Redirect URI
+`https://example.com/openid-connect-authorize`.
+
+
+## Changelog ##
+
+### 3.10.1 ###
+
+* Chore: @daggerhart - Readme updates and clarifications.
+* Chore: @daggerhart - Release workflow updates.
+* Improved error handling for malformed urls.
+* Fix: @JUVOJustin - Change request for userinfo to GET.
+* Feature: @JUVOJustin - New filter for settings values `openid-connect-generic-settings`.
+* Feature: @JUVOJustin - New filter for state values `openid-connect-generic-new-state-value`.
+
+### 3.10.0 ###
+
+* Chore: @timnolte - Dependency updates.
+* Fix: @drzraf - Prevents running the auth url filter twice.
+* Fix: @timnolte - Updates the log cleanup handling to properly retain the configured number of log entries.
+* Fix: @timnolte - Updates the log display output to reflect the log retention policy.
+* Chore: @timnolte - Adds Unit Testing & New Local Development Environment.
+* Feature: @timnolte - Updates logging to allow for tracking processing time.
+* Feature: @menno-ll - Adds a remember me feature via a new filter.
+* Improvement: @menno-ll - Updates WP Cookie Expiration to Same as Session Length.
+
+### 3.9.1 ###
+
+* Improvement: @timnolte - Refactors Composer setup and GitHub Actions.
+* Improvement: @timnolte - Bumps WordPress tested version compatibility.
+
+### 3.9.0 ###
+
+* Feature: @matchaxnb - Added support for additional configuration constants.
+* Feature: @schanzen - Added support for agregated claims.
+* Fix: @rkcreation - Fixed access token not updating user metadata after login.
+* Fix: @danc1248 - Fixed user creation issue on Multisite Networks.
+* Feature: @RobjS - Added plugin singleton to support for more developer customization.
+* Feature: @jkouris - Added action hook to allow custom handling of session expiration.
+* Fix: @tommcc - Fixed admin CSS loading only on the plugin settings screen.
+* Feature: @rkcreation - Added method to refresh the user claim.
+* Feature: @Glowsome - Added acr_values support & verification checks that it when defined in options is honored.
+* Fix: @timnolte - Fixed regression which caused improper fallback on missing claims.
+* Fix: @slykar - Fixed missing query string handling in redirect URL.
+* Fix: @timnolte - Fixed issue with some user linking and user creation handling.
+* Improvement: @timnolte - Fixed plugin settings typos and screen formatting.
+* Security: @timnolte - Updated build tooling security vulnerabilities.
+* Improvement: @timnolte - Changed build tooling scripts.
+
+### 3.8.5 ###
+
+* Fix: @timnolte - Fixed missing URL request validation before use & ensure proper current page URL is setup for Redirect Back.
+* Fix: @timnolte - Fixed Redirect URL Logic to Handle Sub-directory Installs.
+* Fix: @timnolte - Fixed issue with redirecting user back when the openid_connect_generic_auth_url shortcode is used.
+
+### 3.8.4 ###
+
+* Fix: @timnolte - Fixed invalid State object access for redirection handling.
+* Improvement: @timnolte - Fixed local wp-env Docker development environment.
+* Improvement: @timnolte - Fixed Composer scripts for linting and static analysis.
+
+### 3.8.3 ###
+
+* Fix: @timnolte - Fixed problems with proper redirect handling.
+* Improvement: @timnolte - Changes redirect handling to use State instead of cookies.
+* Improvement: @timnolte - Refactored additional code to meet coding standards.
+
+### 3.8.2 ###
+
+* Fix: @timnolte - Fixed reported XSS vulnerability on WordPress login screen.
+
+### 3.8.1 ###
+
+* Fix: @timnolte - Prevent SSO redirect on password protected posts.
+* Fix: @timnolte - CI/CD build issues.
+* Fix: @timnolte - Invalid redirect handling on logout for Auto Login setting.
+
+### 3.8.0 ###
+
+* Feature: @timnolte - Ability to use 6 new constants for setting client configuration instead of storing in the DB.
+* Improvement: @timnolte - Plugin development & contribution updates.
+* Improvement: @timnolte - Refactored to meet WordPress coding standards.
+* Improvement: @timnolte - Refactored to provide localization.
+
+--------
+
+[See the previous changelogs here](https://github.com/oidc-wp/openid-connect-generic/blob/main/CHANGELOG.md#changelog)
diff --git a/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/SECURITY.md b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/SECURITY.md
new file mode 100644
index 00000000..99ee0ea0
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/SECURITY.md
@@ -0,0 +1,17 @@
+# Security Policy
+
+## Supported Versions
+
+We follow the [WordPress Core style of versioning](https://make.wordpress.org/core/handbook/about/release-cycle/version-numbering/) rather than traditional [SemVer](https://semver.org/). This means that a move from version 3.9 to 4.0 is no different from a move from version 3.8 to 3.9. When a **PATCH** version is released it represents a bug fix, or non-code, only change.
+
+The latest version released is the only version that will receive security updates, generally as a **PATCH** release unless a security issue requires a functionality change in which requires a minor/major version bump.
+
+## Reporting a Vulnerability
+
+For security reasons, the following are acceptable options for reporting all security issues.
+
+1. Via Keybase secure message to [timnolte](https://keybase.io/timnolte/chat) or [daggerhart](https://keybase.io/daggerhart/chat).
+2. Send a DM via the [WordPress Slack](https://make.wordpress.org/chat/) to `tnolte`.
+3. Via a private [security advisory](https://github.com/oidc-wp/openid-connect-generic/security/advisories) notice.
+
+Please disclose responsibly and not via public GitHub Issues (which allows for exploiting issues in the wild before the patch is released).
diff --git a/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/codecov.yml b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/codecov.yml
new file mode 100644
index 00000000..2e3090aa
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/codecov.yml
@@ -0,0 +1,10 @@
+coverage:
+ status:
+ project:
+ default:
+ target: auto
+ threshold: 0.5%
+ patch: off
+
+comment:
+ require_changes: true
diff --git a/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/css/styles-admin.css b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/css/styles-admin.css
new file mode 100644
index 00000000..cc4c6f99
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/css/styles-admin.css
@@ -0,0 +1,32 @@
+#logger-table .col-data {
+ width: 85%
+}
+
+#logger-table .col-data pre {
+ margin: 0;
+ white-space: pre; /* CSS 2.0 */
+ white-space: pre-wrap; /* CSS 2.1 */
+ white-space: pre-line; /* CSS 3.0 */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ white-space: -moz-pre-wrap; /* Mozilla */
+ white-space: -hp-pre-wrap; /* HP Printers */
+ word-wrap: break-word; /* IE 5+ */
+}
+
+#logger-table .col-details {
+ width: 200px;
+}
+
+#logger-table .col-details div {
+ padding: 4px 0;
+ border-bottom: 1px solid #bbb;
+}
+
+#logger-table .col-details div:last-child {
+ border-bottom: none;
+}
+
+#logger-table .col-details label {
+ font-weight: bold;
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/docker-compose.yml b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/docker-compose.yml
new file mode 100644
index 00000000..a2778087
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/docker-compose.yml
@@ -0,0 +1,95 @@
+# This is the Compose file for command-line services.
+# Anything that doesn't need to be run as part of the main `docker-compose up'
+# command should reside in here and be invoked by a helper script.
+version: "3.7"
+
+services:
+ app:
+ image: ghcr.io/ndigitals/wp-dev-container:php-8.0-node-16
+ restart: always
+ depends_on:
+ - db
+ - phpmyadmin
+ - web
+ - mailhog
+ working_dir: /workspaces/openid-connect-generic
+ environment: &env
+ WORDPRESS_DB_HOST: db
+ WORDPRESS_DB_NAME: wordpress
+ WORDPRESS_DB_USER: wordpress
+ WORDPRESS_DB_PASSWORD: wordpress
+ WORDPRESS_TEST_DB_NAME: wordpress_test
+ CODESPACES: "${CODESPACES}"
+ CODESPACE_NAME: "${CODESPACE_NAME}"
+ GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN: "${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}"
+ volumes:
+ - .:/workspaces/openid-connect-generic:cached
+ - ./tools/local-env:/app:cached
+ - ./tools/php/php-cli.ini:/usr/local/etc/php/php-cli.ini:ro,cached
+ - .:/app/wp-content/plugins/daggerhart-openid-connect-generic:ro,cached
+ - ~/.composer:/root/.composer:cached
+ - ~/.npm:/root/.npm:cached
+ networks:
+ - oidcwp-net
+
+ web:
+ image: httpd
+ restart: unless-stopped
+ depends_on:
+ - db
+ ports:
+ - 8080:80
+ environment:
+ <<: *env
+ volumes:
+ - ./tools/local-env:/app:cached
+ - .:/app/wp-content/plugins/daggerhart-openid-connect-generic:ro,cached
+ - ./tools/apache/httpd.conf:/usr/local/apache2/conf/httpd.conf:ro,cached
+ networks:
+ - oidcwp-net
+
+ db:
+ image: mariadb
+ restart: unless-stopped
+ ports:
+ - 3306:3306
+ environment:
+ MYSQL_ROOT_PASSWORD: password
+ MYSQL_DATABASE: wordpress
+ MYSQL_USER: wordpress
+ MYSQL_PASSWORD: wordpress
+ volumes:
+ - db:/var/lib/mysql
+ - ./tests/db-wordpress_test.sql:/docker-entrypoint-initdb.d/db-wordpress_test.sql
+ networks:
+ - oidcwp-net
+
+ phpmyadmin:
+ image: phpmyadmin
+ restart: unless-stopped
+ depends_on:
+ - db
+ ports:
+ - 8081:8081
+ environment:
+ PMA_HOST: db
+ APACHE_PORT: 8081
+ networks:
+ - oidcwp-net
+
+ ## SMTP Server + Web Interface for viewing and testing emails during development.
+ mailhog:
+ image: mailhog/mailhog
+ restart: unless-stopped
+ ports:
+ - 1025:1025 # smtp server
+ - 8026:8025 # web ui
+ networks:
+ - oidcwp-net
+
+volumes:
+ db:
+
+networks:
+ oidcwp-net:
+
diff --git a/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/includes/functions.php b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/includes/functions.php
new file mode 100644
index 00000000..832328ff
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/includes/functions.php
@@ -0,0 +1,30 @@
+
+ * @copyright 2015-2020 daggerhart
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+
+ */
+
+/**
+ * Return a single use authentication URL.
+ *
+ * @return string
+ */
+function oidcg_get_authentication_url() {
+ return \OpenID_Connect_Generic::instance()->client_wrapper->get_authentication_url();
+}
+
+/**
+ * Refresh a user claim and update the user metadata.
+ *
+ * @param WP_User $user The user object.
+ * @param array $token_response The token response.
+ *
+ * @return WP_Error|array
+ */
+function oidcg_refresh_user_claim( $user, $token_response ) {
+ return \OpenID_Connect_Generic::instance()->client_wrapper->refresh_user_claim( $user, $token_response );
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/includes/openid-connect-generic-client-wrapper.php b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/includes/openid-connect-generic-client-wrapper.php
new file mode 100644
index 00000000..0b0a97f0
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/includes/openid-connect-generic-client-wrapper.php
@@ -0,0 +1,1131 @@
+
+ * @copyright 2015-2020 daggerhart
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+
+ */
+
+/**
+ * OpenID_Connect_Generic_Client_Wrapper class.
+ *
+ * Plugin OIDC/oAuth client wrapper class.
+ *
+ * @package OpenID_Connect_Generic
+ * @category Authentication
+ */
+class OpenID_Connect_Generic_Client_Wrapper {
+
+ /**
+ * The user redirect cookie key.
+ *
+ * @deprecated Redirection should be done via state transient and not cookies.
+ *
+ * @var string
+ */
+ const COOKIE_REDIRECT_KEY = 'openid-connect-generic-redirect';
+
+ /**
+ * The token refresh info cookie key.
+ *
+ * @var string
+ */
+ const COOKIE_TOKEN_REFRESH_KEY = 'openid-connect-generic-refresh';
+
+ /**
+ * The client object instance.
+ *
+ * @var OpenID_Connect_Generic_Client
+ */
+ private $client;
+
+ /**
+ * The settings object instance.
+ *
+ * @var OpenID_Connect_Generic_Option_Settings
+ */
+ private $settings;
+
+ /**
+ * The logger object instance.
+ *
+ * @var OpenID_Connect_Generic_Option_Logger
+ */
+ private $logger;
+
+ /**
+ * The return error onject.
+ *
+ * @example WP_Error if there was a problem, or false if no error
+ *
+ * @var bool|WP_Error
+ */
+ private $error = false;
+
+ /**
+ * Inject necessary objects and services into the client.
+ *
+ * @param OpenID_Connect_Generic_Client $client A plugin client object instance.
+ * @param OpenID_Connect_Generic_Option_Settings $settings A plugin settings object instance.
+ * @param OpenID_Connect_Generic_Option_Logger $logger A plugin logger object instance.
+ */
+ public function __construct( OpenID_Connect_Generic_Client $client, OpenID_Connect_Generic_Option_Settings $settings, OpenID_Connect_Generic_Option_Logger $logger ) {
+ $this->client = $client;
+ $this->settings = $settings;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Hook the client into WordPress.
+ *
+ * @param \OpenID_Connect_Generic_Client $client The plugin client instance.
+ * @param \OpenID_Connect_Generic_Option_Settings $settings The plugin settings instance.
+ * @param \OpenID_Connect_Generic_Option_Logger $logger The plugin logger instance.
+ *
+ * @return \OpenID_Connect_Generic_Client_Wrapper
+ */
+ public static function register( OpenID_Connect_Generic_Client $client, OpenID_Connect_Generic_Option_Settings $settings, OpenID_Connect_Generic_Option_Logger $logger ) {
+ $client_wrapper = new self( $client, $settings, $logger );
+
+ // Integrated logout.
+ if ( $settings->endpoint_end_session ) {
+ add_filter( 'allowed_redirect_hosts', array( $client_wrapper, 'update_allowed_redirect_hosts' ), 99, 1 );
+ add_filter( 'logout_redirect', array( $client_wrapper, 'get_end_session_logout_redirect_url' ), 99, 3 );
+ }
+
+ // Alter the requests according to settings.
+ add_filter( 'openid-connect-generic-alter-request', array( $client_wrapper, 'alter_request' ), 10, 2 );
+
+ if ( is_admin() ) {
+ /*
+ * Use the ajax url to handle processing authorization without any html output
+ * this callback will occur when then IDP returns with an authenticated value
+ */
+ add_action( 'wp_ajax_openid-connect-authorize', array( $client_wrapper, 'authentication_request_callback' ) );
+ add_action( 'wp_ajax_nopriv_openid-connect-authorize', array( $client_wrapper, 'authentication_request_callback' ) );
+ }
+
+ if ( $settings->alternate_redirect_uri ) {
+ // Provide an alternate route for authentication_request_callback.
+ add_rewrite_rule( '^openid-connect-authorize/?', 'index.php?openid-connect-authorize=1', 'top' );
+ add_rewrite_tag( '%openid-connect-authorize%', '1' );
+ add_action( 'parse_request', array( $client_wrapper, 'alternate_redirect_uri_parse_request' ) );
+ }
+
+ return $client_wrapper;
+ }
+
+ /**
+ * Implements WordPress parse_request action.
+ *
+ * @param WP_Query $query The WordPress query object.
+ *
+ * @return void
+ */
+ public function alternate_redirect_uri_parse_request( $query ) {
+ if ( isset( $query->query_vars['openid-connect-authorize'] ) &&
+ '1' === $query->query_vars['openid-connect-authorize'] ) {
+ $this->authentication_request_callback();
+ exit;
+ }
+ }
+
+ /**
+ * Get the client login redirect.
+ *
+ * @return string
+ */
+ public function get_redirect_to() {
+ /*
+ * @var WP $wp
+ */
+ global $wp;
+
+ if ( isset( $GLOBALS['pagenow'] ) && 'wp-login.php' == $GLOBALS['pagenow'] && isset( $_GET['action'] ) && 'logout' === $_GET['action'] ) {
+ return '';
+ }
+
+ // Default redirect to the homepage.
+ $redirect_url = home_url();
+
+ // If using the login form, default redirect to the admin dashboard.
+ if ( isset( $GLOBALS['pagenow'] ) && 'wp-login.php' == $GLOBALS['pagenow'] ) {
+ $redirect_url = admin_url();
+ }
+
+ // Honor Core WordPress & other plugin redirects.
+ if ( isset( $_REQUEST['redirect_to'] ) ) {
+ $redirect_url = esc_url_raw( wp_unslash( $_REQUEST['redirect_to'] ) );
+ }
+
+ // Capture the current URL if set to redirect back to origin page.
+ if ( $this->settings->redirect_user_back ) {
+ if ( ! empty( $wp->query_string ) ) {
+ $redirect_url = home_url( '?' . $wp->query_string );
+ }
+ if ( ! empty( $wp->request ) ) {
+ $redirect_url = home_url( add_query_arg( null, null ) );
+ // @phpstan-ignore-next-line
+ if ( $wp->did_permalink ) {
+ $redirect_url = home_url( add_query_arg( $_GET, trailingslashit( $wp->request ) ) );
+ }
+ }
+ }
+
+ // This hook is being deprecated with the move away from cookies.
+ $redirect_url = apply_filters_deprecated(
+ 'openid-connect-generic-cookie-redirect-url',
+ array( $redirect_url ),
+ '3.8.2',
+ 'openid-connect-generic-client-redirect-to'
+ );
+
+ // This is the new hook to use with the transients version of redirection.
+ return apply_filters( 'openid-connect-generic-client-redirect-to', $redirect_url );
+ }
+
+ /**
+ * Create a single use authentication url
+ *
+ * @param array
| + | + + + + |
|---|---|
|
+
+
+
+
+
+
+
+
+
+
+ user_login : '0' ); ?>
+
+
+
+
+
+
+
+
+
+ |
+ + |
)
+ */
+ $fields = array(
+ 'login_type' => array(
+ 'title' => __( 'Login Type', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'Select how the client (login form) should provide login options.', 'daggerhart-openid-connect-generic' ),
+ 'type' => 'select',
+ 'options' => array(
+ 'button' => __( 'OpenID Connect button on login form', 'daggerhart-openid-connect-generic' ),
+ 'auto' => __( 'Auto Login - SSO', 'daggerhart-openid-connect-generic' ),
+ ),
+ 'disabled' => defined( 'OIDC_LOGIN_TYPE' ),
+ 'section' => 'client_settings',
+ ),
+ 'client_id' => array(
+ 'title' => __( 'Client ID', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'The ID this client will be recognized as when connecting the to Identity provider server.', 'daggerhart-openid-connect-generic' ),
+ 'example' => 'my-wordpress-client-id',
+ 'type' => 'text',
+ 'disabled' => defined( 'OIDC_CLIENT_ID' ),
+ 'section' => 'client_settings',
+ ),
+ 'client_secret' => array(
+ 'title' => __( 'Client Secret Key', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'Arbitrary secret key the server expects from this client. Can be anything, but should be very unique.', 'daggerhart-openid-connect-generic' ),
+ 'type' => 'text',
+ 'disabled' => defined( 'OIDC_CLIENT_SECRET' ),
+ 'section' => 'client_settings',
+ ),
+ 'scope' => array(
+ 'title' => __( 'OpenID Scope', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'Space separated list of scopes this client should access.', 'daggerhart-openid-connect-generic' ),
+ 'example' => 'email profile openid offline_access',
+ 'type' => 'text',
+ 'disabled' => defined( 'OIDC_CLIENT_SCOPE' ),
+ 'section' => 'client_settings',
+ ),
+ 'endpoint_login' => array(
+ 'title' => __( 'Login Endpoint URL', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'Identify provider authorization endpoint.', 'daggerhart-openid-connect-generic' ),
+ 'example' => 'https://example.com/oauth2/authorize',
+ 'type' => 'text',
+ 'disabled' => defined( 'OIDC_ENDPOINT_LOGIN_URL' ),
+ 'section' => 'client_settings',
+ ),
+ 'endpoint_userinfo' => array(
+ 'title' => __( 'Userinfo Endpoint URL', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'Identify provider User information endpoint.', 'daggerhart-openid-connect-generic' ),
+ 'example' => 'https://example.com/oauth2/UserInfo',
+ 'type' => 'text',
+ 'disabled' => defined( 'OIDC_ENDPOINT_USERINFO_URL' ),
+ 'section' => 'client_settings',
+ ),
+ 'endpoint_token' => array(
+ 'title' => __( 'Token Validation Endpoint URL', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'Identify provider token endpoint.', 'daggerhart-openid-connect-generic' ),
+ 'example' => 'https://example.com/oauth2/token',
+ 'type' => 'text',
+ 'disabled' => defined( 'OIDC_ENDPOINT_TOKEN_URL' ),
+ 'section' => 'client_settings',
+ ),
+ 'endpoint_end_session' => array(
+ 'title' => __( 'End Session Endpoint URL', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'Identify provider logout endpoint.', 'daggerhart-openid-connect-generic' ),
+ 'example' => 'https://example.com/oauth2/logout',
+ 'type' => 'text',
+ 'disabled' => defined( 'OIDC_ENDPOINT_LOGOUT_URL' ),
+ 'section' => 'client_settings',
+ ),
+ 'acr_values' => array(
+ 'title' => __( 'ACR values', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'Use a specific defined authentication contract from the IDP - optional.', 'daggerhart-openid-connect-generic' ),
+ 'type' => 'text',
+ 'disabled' => defined( 'OIDC_ACR_VALUES' ),
+ 'section' => 'client_settings',
+ ),
+ 'identity_key' => array(
+ 'title' => __( 'Identity Key', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'Where in the user claim array to find the user\'s identification data. Possible standard values: preferred_username, name, or sub. If you\'re having trouble, use "sub".', 'daggerhart-openid-connect-generic' ),
+ 'example' => 'preferred_username',
+ 'type' => 'text',
+ 'section' => 'client_settings',
+ ),
+ 'no_sslverify' => array(
+ 'title' => __( 'Disable SSL Verify', 'daggerhart-openid-connect-generic' ),
+ // translators: %1$s HTML tags for layout/styles, %2$s closing HTML tag for styles.
+ 'description' => sprintf( __( 'Do not require SSL verification during authorization. The OAuth extension uses curl to make the request. By default CURL will generally verify the SSL certificate to see if its valid an issued by an accepted CA. This setting disabled that verification.%1$sNot recommended for production sites.%2$s', 'daggerhart-openid-connect-generic' ), '
', '' ),
+ 'type' => 'checkbox',
+ 'section' => 'client_settings',
+ ),
+ 'http_request_timeout' => array(
+ 'title' => __( 'HTTP Request Timeout', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'Set the timeout for requests made to the IDP. Default value is 5.', 'daggerhart-openid-connect-generic' ),
+ 'example' => 30,
+ 'type' => 'text',
+ 'section' => 'client_settings',
+ ),
+ 'enforce_privacy' => array(
+ 'title' => __( 'Enforce Privacy', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'Require users be logged in to see the site.', 'daggerhart-openid-connect-generic' ),
+ 'type' => 'checkbox',
+ 'disabled' => defined( 'OIDC_ENFORCE_PRIVACY' ),
+ 'section' => 'authorization_settings',
+ ),
+ 'alternate_redirect_uri' => array(
+ 'title' => __( 'Alternate Redirect URI', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'Provide an alternative redirect route. Useful if your server is causing issues with the default admin-ajax method. You must flush rewrite rules after changing this setting. This can be done by saving the Permalinks settings page.', 'daggerhart-openid-connect-generic' ),
+ 'type' => 'checkbox',
+ 'section' => 'authorization_settings',
+ ),
+ 'nickname_key' => array(
+ 'title' => __( 'Nickname Key', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'Where in the user claim array to find the user\'s nickname. Possible standard values: preferred_username, name, or sub.', 'daggerhart-openid-connect-generic' ),
+ 'example' => 'preferred_username',
+ 'type' => 'text',
+ 'section' => 'client_settings',
+ ),
+ 'email_format' => array(
+ 'title' => __( 'Email Formatting', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'String from which the user\'s email address is built. Specify "{email}" as long as the user claim contains an email claim.', 'daggerhart-openid-connect-generic' ),
+ 'example' => '{email}',
+ 'type' => 'text',
+ 'section' => 'client_settings',
+ ),
+ 'displayname_format' => array(
+ 'title' => __( 'Display Name Formatting', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'String from which the user\'s display name is built.', 'daggerhart-openid-connect-generic' ),
+ 'example' => '{given_name} {family_name}',
+ 'type' => 'text',
+ 'section' => 'client_settings',
+ ),
+ 'identify_with_username' => array(
+ 'title' => __( 'Identify with User Name', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'If checked, the user\'s identity will be determined by the user name instead of the email address.', 'daggerhart-openid-connect-generic' ),
+ 'type' => 'checkbox',
+ 'section' => 'client_settings',
+ ),
+ 'state_time_limit' => array(
+ 'title' => __( 'State time limit', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'State valid time in seconds. Defaults to 180', 'daggerhart-openid-connect-generic' ),
+ 'type' => 'number',
+ 'section' => 'client_settings',
+ ),
+ 'token_refresh_enable' => array(
+ 'title' => __( 'Enable Refresh Token', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'If checked, support refresh tokens used to obtain access tokens from supported IDPs.', 'daggerhart-openid-connect-generic' ),
+ 'type' => 'checkbox',
+ 'section' => 'client_settings',
+ ),
+ 'link_existing_users' => array(
+ 'title' => __( 'Link Existing Users', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'If a WordPress account already exists with the same identity as a newly-authenticated user over OpenID Connect, login as that user instead of generating an error.', 'daggerhart-openid-connect-generic' ),
+ 'type' => 'checkbox',
+ 'disabled' => defined( 'OIDC_LINK_EXISTING_USERS' ),
+ 'section' => 'user_settings',
+ ),
+ 'create_if_does_not_exist' => array(
+ 'title' => __( 'Create user if does not exist', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'If the user identity is not linked to an existing WordPress user, it is created. If this setting is not enabled, and if the user authenticates with an account which is not linked to an existing WordPress user, then the authentication will fail.', 'daggerhart-openid-connect-generic' ),
+ 'type' => 'checkbox',
+ 'disabled' => defined( 'OIDC_CREATE_IF_DOES_NOT_EXIST' ),
+ 'section' => 'user_settings',
+ ),
+ 'redirect_user_back' => array(
+ 'title' => __( 'Redirect Back to Origin Page', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'After a successful OpenID Connect authentication, this will redirect the user back to the page on which they clicked the OpenID Connect login button. This will cause the login process to proceed in a traditional WordPress fashion. For example, users logging in through the default wp-login.php page would end up on the WordPress Dashboard and users logging in through the WooCommerce "My Account" page would end up on their account page.', 'daggerhart-openid-connect-generic' ),
+ 'type' => 'checkbox',
+ 'disabled' => defined( 'OIDC_REDIRECT_USER_BACK' ),
+ 'section' => 'user_settings',
+ ),
+ 'redirect_on_logout' => array(
+ 'title' => __( 'Redirect to the login screen when session is expired', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'When enabled, this will automatically redirect the user back to the WordPress login page if their access token has expired.', 'daggerhart-openid-connect-generic' ),
+ 'type' => 'checkbox',
+ 'disabled' => defined( 'OIDC_REDIRECT_ON_LOGOUT' ),
+ 'section' => 'user_settings',
+ ),
+ 'enable_logging' => array(
+ 'title' => __( 'Enable Logging', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'Very simple log messages for debugging purposes.', 'daggerhart-openid-connect-generic' ),
+ 'type' => 'checkbox',
+ 'disabled' => defined( 'OIDC_ENABLE_LOGGING' ),
+ 'section' => 'log_settings',
+ ),
+ 'log_limit' => array(
+ 'title' => __( 'Log Limit', 'daggerhart-openid-connect-generic' ),
+ 'description' => __( 'Number of items to keep in the log. These logs are stored as an option in the database, so space is limited.', 'daggerhart-openid-connect-generic' ),
+ 'type' => 'number',
+ 'disabled' => defined( 'OIDC_LOG_LIMIT' ),
+ 'section' => 'log_settings',
+ ),
+ );
+
+ return apply_filters( 'openid-connect-generic-settings-fields', $fields );
+ }
+
+ /**
+ * Sanitization callback for settings/option page.
+ *
+ * @param array $input The submitted settings values.
+ *
+ * @return array
+ */
+ public function sanitize_settings( $input ) {
+ $options = array();
+
+ // Loop through settings fields to control what we're saving.
+ foreach ( $this->settings_fields as $key => $field ) {
+ if ( isset( $input[ $key ] ) ) {
+ $options[ $key ] = sanitize_text_field( trim( $input[ $key ] ) );
+ } else {
+ $options[ $key ] = '';
+ }
+ }
+
+ return $options;
+ }
+
+ /**
+ * Output the options/settings page.
+ *
+ * @return void
+ */
+ public function settings_page() {
+ wp_enqueue_style( 'daggerhart-openid-connect-generic-admin', plugin_dir_url( __DIR__ ) . 'css/styles-admin.css', array(), OpenID_Connect_Generic::VERSION, 'all' );
+
+ $redirect_uri = admin_url( 'admin-ajax.php?action=openid-connect-authorize' );
+
+ if ( $this->settings->alternate_redirect_uri ) {
+ $redirect_uri = site_url( '/openid-connect-authorize' );
+ }
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [openid_connect_generic_login_button]
+
+
+
+ [openid_connect_generic_auth_url]
+
+
+ settings->enable_logging ) { ?>
+
+
+ logger->get_logs_table() ); ?>
+
+
+
+
+
+
+ value="settings->{ $field['key'] } ); ?>">
+ do_field_description( $field );
+ }
+
+ /**
+ * Output a checkbox for a boolean setting.
+ * - hidden field is default value so we don't have to check isset() on save.
+ *
+ * @param array $field The settings field definition array.
+ *
+ * @return void
+ */
+ public function do_checkbox( $field ) {
+ $hidden_value = 0;
+ if ( ! empty( $field['disabled'] ) && boolval( $field['disabled'] ) === true ) {
+ $hidden_value = intval( $this->settings->{ $field['key'] } );
+ }
+ ?>
+
+
+ value="1"
+ settings->{ $field['key'] }, 1 ); ?>>
+ do_field_description( $field );
+ }
+
+ /**
+ * Output a select control.
+ *
+ * @param array $field The settings field definition array.
+ *
+ * @return void
+ */
+ public function do_select( $field ) {
+ $current_value = isset( $this->settings->{ $field['key'] } ) ? $this->settings->{ $field['key'] } : '';
+ ?>
+
+ do_field_description( $field );
+ }
+
+ /**
+ * Output the field description, and example if present.
+ *
+ * @param array $field The settings field definition array.
+ *
+ * @return void
+ */
+ public function do_field_description( $field ) {
+ ?>
+
+
+
+
:
+
+
+
+ \n"
+"Language-Team: LANGUAGE \n"
+"Language: en\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Country: United States\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+"X-Poedit-KeywordsList: "
+"__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
+"attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
+"X-Poedit-Basepath: ../\n"
+"X-Poedit-SearchPath-0: .\n"
+"X-Poedit-Bookmarks: \n"
+"X-Textdomain-Support: yes\n"
+"X-Generator: grunt-wp-i18n 1.0.3\n"
+
+#: includes/openid-connect-generic-client-wrapper.php:293
+msgid "Session expired. Please login again."
+msgstr ""
+
+#: includes/openid-connect-generic-client-wrapper.php:540
+msgid "User identity is not linked to an existing WordPress user."
+msgstr ""
+
+#: includes/openid-connect-generic-client-wrapper.php:598
+msgid "Invalid user."
+msgstr ""
+
+#: includes/openid-connect-generic-client-wrapper.php:816
+msgid "No appropriate username found."
+msgstr ""
+
+#: includes/openid-connect-generic-client-wrapper.php:826
+#. translators: %1$s is the santitized version of the username from the IDP.
+msgid "Username %1$s could not be sanitized."
+msgstr ""
+
+#: includes/openid-connect-generic-client-wrapper.php:848
+#. translators: %1$s is the configured User Claim nickname key.
+msgid "No nickname found in user claim using key: %1$s."
+msgstr ""
+
+#: includes/openid-connect-generic-client-wrapper.php:945
+msgid "User claim incomplete."
+msgstr ""
+
+#: includes/openid-connect-generic-client-wrapper.php:1048
+msgid "Bad user claim result."
+msgstr ""
+
+#: includes/openid-connect-generic-client-wrapper.php:1114
+msgid "Can not authorize."
+msgstr ""
+
+#: includes/openid-connect-generic-client-wrapper.php:1143
+msgid "Failed user creation."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:176
+msgid "Missing state."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:180
+msgid "Invalid state."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:195
+msgid "Missing authentication code."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:240
+msgid "Request for authentication token failed."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:273
+msgid "Refresh token failed."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:288
+msgid "Missing token body."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:296
+msgid "Invalid token."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:349
+msgid "Request for userinfo failed."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:409
+msgid "Missing authentication state."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:446
+msgid "No identity token."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:453
+msgid "Missing identity token."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:480
+msgid "Bad ID token claim."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:485
+msgid "No subject identity."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:491
+msgid "No matching acr values."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:511
+msgid "Bad user claim."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:531
+msgid "Invalid user claim."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:536
+msgid "Error from the IDP."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:545
+msgid "Incorrect user claim."
+msgstr ""
+
+#: includes/openid-connect-generic-client.php:552
+msgid "Unauthorized access."
+msgstr ""
+
+#: includes/openid-connect-generic-login-form.php:122
+#. translators: %1$s is the error code from the IDP.
+msgid "ERROR (%1$s)"
+msgstr ""
+
+#: includes/openid-connect-generic-login-form.php:141
+msgid "Login with OpenID Connect"
+msgstr ""
+
+#: includes/openid-connect-generic-option-logger.php:228
+msgid "Details"
+msgstr ""
+
+#: includes/openid-connect-generic-option-logger.php:229
+msgid "Data"
+msgstr ""
+
+#: includes/openid-connect-generic-option-logger.php:236
+msgid "Date"
+msgstr ""
+
+#: includes/openid-connect-generic-option-logger.php:240
+msgid "Type"
+msgstr ""
+
+#: includes/openid-connect-generic-option-logger.php:244
+msgid "User"
+msgstr ""
+
+#: includes/openid-connect-generic-option-logger.php:248
+msgid "URI "
+msgstr ""
+
+#: includes/openid-connect-generic-option-logger.php:252
+msgid "Response Time (sec)"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:108
+msgid "OpenID Connect - Generic Client"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:109
+msgid "OpenID Connect Client"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:133
+msgid "Client Settings"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:140
+msgid "WordPress User Settings"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:147
+msgid "Authorization Settings"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:154
+msgid "Log Settings"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:212
+msgid "Login Type"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:213
+msgid "Select how the client (login form) should provide login options."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:216
+msgid "OpenID Connect button on login form"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:217
+msgid "Auto Login - SSO"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:223
+msgid "Client ID"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:224
+msgid ""
+"The ID this client will be recognized as when connecting the to Identity "
+"provider server."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:231
+msgid "Client Secret Key"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:232
+msgid ""
+"Arbitrary secret key the server expects from this client. Can be anything, "
+"but should be very unique."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:238
+msgid "OpenID Scope"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:239
+msgid "Space separated list of scopes this client should access."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:246
+msgid "Login Endpoint URL"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:247
+msgid "Identify provider authorization endpoint."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:254
+msgid "Userinfo Endpoint URL"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:255
+msgid "Identify provider User information endpoint."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:262
+msgid "Token Validation Endpoint URL"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:263
+msgid "Identify provider token endpoint."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:270
+msgid "End Session Endpoint URL"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:271
+msgid "Identify provider logout endpoint."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:278
+msgid "ACR values"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:279
+msgid "Use a specific defined authentication contract from the IDP - optional."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:285
+msgid "Identity Key"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:286
+msgid ""
+"Where in the user claim array to find the user's identification data. "
+"Possible standard values: preferred_username, name, or sub. If you're "
+"having trouble, use \"sub\"."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:292
+msgid "Disable SSL Verify"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:294
+#. translators: %1$s HTML tags for layout/styles, %2$s closing HTML tag for
+#. styles.
+msgid ""
+"Do not require SSL verification during authorization. The OAuth extension "
+"uses curl to make the request. By default CURL will generally verify the "
+"SSL certificate to see if its valid an issued by an accepted CA. This "
+"setting disabled that verification.%1$sNot recommended for production "
+"sites.%2$s"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:299
+msgid "HTTP Request Timeout"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:300
+msgid "Set the timeout for requests made to the IDP. Default value is 5."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:306
+msgid "Enforce Privacy"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:307
+msgid "Require users be logged in to see the site."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:313
+msgid "Alternate Redirect URI"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:314
+msgid ""
+"Provide an alternative redirect route. Useful if your server is causing "
+"issues with the default admin-ajax method. You must flush rewrite rules "
+"after changing this setting. This can be done by saving the Permalinks "
+"settings page."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:319
+msgid "Nickname Key"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:320
+msgid ""
+"Where in the user claim array to find the user's nickname. Possible "
+"standard values: preferred_username, name, or sub."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:326
+msgid "Email Formatting"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:327
+msgid ""
+"String from which the user's email address is built. Specify \"{email}\" as "
+"long as the user claim contains an email claim."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:333
+msgid "Display Name Formatting"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:334
+msgid "String from which the user's display name is built."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:340
+msgid "Identify with User Name"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:341
+msgid ""
+"If checked, the user's identity will be determined by the user name instead "
+"of the email address."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:346
+msgid "State time limit"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:347
+msgid "State valid time in seconds. Defaults to 180"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:352
+msgid "Enable Refresh Token"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:353
+msgid ""
+"If checked, support refresh tokens used to obtain access tokens from "
+"supported IDPs."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:358
+msgid "Link Existing Users"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:359
+msgid ""
+"If a WordPress account already exists with the same identity as a "
+"newly-authenticated user over OpenID Connect, login as that user instead of "
+"generating an error."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:365
+msgid "Create user if does not exist"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:366
+msgid ""
+"If the user identity is not linked to an existing WordPress user, it is "
+"created. If this setting is not enabled, and if the user authenticates with "
+"an account which is not linked to an existing WordPress user, then the "
+"authentication will fail."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:372
+msgid "Redirect Back to Origin Page"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:373
+msgid ""
+"After a successful OpenID Connect authentication, this will redirect the "
+"user back to the page on which they clicked the OpenID Connect login "
+"button. This will cause the login process to proceed in a traditional "
+"WordPress fashion. For example, users logging in through the default "
+"wp-login.php page would end up on the WordPress Dashboard and users logging "
+"in through the WooCommerce \"My Account\" page would end up on their "
+"account page."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:379
+msgid "Redirect to the login screen when session is expired"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:380
+msgid ""
+"When enabled, this will automatically redirect the user back to the "
+"WordPress login page if their access token has expired."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:386
+msgid "Enable Logging"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:387
+msgid "Very simple log messages for debugging purposes."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:393
+msgid "Log Limit"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:394
+msgid ""
+"Number of items to keep in the log. These logs are stored as an option in "
+"the database, so space is limited."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:456
+msgid "Notes"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:459
+msgid "Redirect URI"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:463
+msgid "Login Button Shortcode"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:467
+msgid "Authentication URL Shortcode"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:472
+msgid "Logs"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:561
+msgid "Example"
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:574
+msgid "Enter your OpenID Connect identity provider settings."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:583
+msgid "Modify the interaction between OpenID Connect and WordPress users."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:592
+msgid "Control the authorization mechanics of the site."
+msgstr ""
+
+#: includes/openid-connect-generic-settings-page.php:601
+msgid "Log information about login attempts through OpenID Connect Generic."
+msgstr ""
+
+#: openid-connect-generic.php:242
+msgid "Private site"
+msgstr ""
+
+#. Plugin Name of the plugin/theme
+msgid "OpenID Connect Generic"
+msgstr ""
+
+#. Plugin URI of the plugin/theme
+msgid "https://github.com/daggerhart/openid-connect-generic"
+msgstr ""
+
+#. Description of the plugin/theme
+msgid ""
+"Connect to an OpenID Connect identity provider using Authorization Code "
+"Flow."
+msgstr ""
+
+#. Author of the plugin/theme
+msgid "daggerhart"
+msgstr ""
+
+#. Author URI of the plugin/theme
+msgid "http://www.daggerhart.com"
+msgstr ""
diff --git a/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/openid-connect-generic.php b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/openid-connect-generic.php
new file mode 100644
index 00000000..81895e9a
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/openid-connect-generic.php
@@ -0,0 +1,439 @@
+
+ * @copyright 2015-2023 daggerhart
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+
+ * @link https://github.com/oidc-wp
+ *
+ * @wordpress-plugin
+ * Plugin Name: OpenID Connect Generic
+ * Plugin URI: https://github.com/oidc-wp/openid-connect-generic
+ * Description: Connect to an OpenID Connect identity provider using Authorization Code Flow.
+ * Version: 3.10.2
+ * Requires at least: 5.0
+ * Requires PHP: 7.4
+ * Author: daggerhart
+ * Author URI: https://www.daggerhartlab.com
+ * Text Domain: daggerhart-openid-connect-generic
+ * Domain Path: /languages
+ * License: GPL-2.0+
+ * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
+ * GitHub Plugin URI: https://github.com/oidc-wp/openid-connect-generic
+ */
+
+/*
+Notes
+ Spec Doc - http://openid.net/specs/openid-connect-basic-1_0-32.html
+
+ Filters
+ - openid-connect-generic-alter-request - 3 args: request array, plugin settings, specific request op
+ - openid-connect-generic-settings-fields - modify the fields provided on the settings page
+ - openid-connect-generic-settings - modify settings values early in plugin bootstrap.
+ - openid-connect-generic-login-button-text - modify the login button text
+ - openid-connect-generic-cookie-redirect-url - modify the redirect url stored as a cookie
+ - openid-connect-generic-user-login-test - (bool) should the user be logged in based on their claim
+ - openid-connect-generic-user-creation-test - (bool) should the user be created based on their claim
+ - openid-connect-generic-auth-url - modify the authentication url
+ - openid-connect-generic-alter-user-claim - modify the user_claim before a new user is created
+ - openid-connect-generic-alter-user-data - modify user data before a new user is created
+ - openid-connect-modify-token-response-before-validation - modify the token response before validation
+ - openid-connect-modify-id-token-claim-before-validation - modify the token claim before validation
+ - openid-connect-generic-new-state-value - modify the user's state value before it us saved.
+
+ Actions
+ - openid-connect-generic-user-create - 2 args: fires when a new user is created by this plugin
+ - openid-connect-generic-user-update - 1 arg: user ID, fires when user is updated by this plugin
+ - openid-connect-generic-update-user-using-current-claim - 2 args: fires every time an existing user logs in and the claims are updated.
+ - openid-connect-generic-redirect-user-back - 2 args: $redirect_url, $user. Allows interruption of redirect during login.
+ - openid-connect-generic-user-logged-in - 1 arg: $user, fires when user is logged in.
+ - openid-connect-generic-cron-daily - daily cron action
+ - openid-connect-generic-state-not-found - the given state does not exist in the database, regardless of its expiration.
+ - openid-connect-generic-state-expired - the given state exists, but expired before this login attempt.
+
+ Callable actions
+
+ User Meta
+ - openid-connect-generic-subject-identity - the identity of the user provided by the idp
+ - openid-connect-generic-last-id-token-claim - the user's most recent id_token claim, decoded
+ - openid-connect-generic-last-user-claim - the user's most recent user_claim
+ - openid-connect-generic-last-token-response - the user's most recent token response
+
+ Options
+ - openid_connect_generic_settings - plugin settings
+ - openid-connect-generic-valid-states - locally stored generated states
+*/
+
+
+/**
+ * OpenID_Connect_Generic class.
+ *
+ * Defines plugin initialization functionality.
+ *
+ * @package OpenID_Connect_Generic
+ * @category General
+ */
+class OpenID_Connect_Generic {
+
+ /**
+ * Singleton instance of self
+ *
+ * @var OpenID_Connect_Generic
+ */
+ protected static $_instance = null;
+
+ /**
+ * Plugin version.
+ *
+ * @var string
+ */
+ const VERSION = '3.10.2';
+
+ /**
+ * Plugin settings.
+ *
+ * @var OpenID_Connect_Generic_Option_Settings
+ */
+ private $settings;
+
+ /**
+ * Plugin logs.
+ *
+ * @var OpenID_Connect_Generic_Option_Logger
+ */
+ private $logger;
+
+ /**
+ * Openid Connect Generic client
+ *
+ * @var OpenID_Connect_Generic_Client
+ */
+ private $client;
+
+ /**
+ * Client wrapper.
+ *
+ * @var OpenID_Connect_Generic_Client_Wrapper
+ */
+ public $client_wrapper;
+
+ /**
+ * Setup the plugin
+ *
+ * @param OpenID_Connect_Generic_Option_Settings $settings The settings object.
+ * @param OpenID_Connect_Generic_Option_Logger $logger The loggin object.
+ *
+ * @return void
+ */
+ public function __construct( OpenID_Connect_Generic_Option_Settings $settings, OpenID_Connect_Generic_Option_Logger $logger ) {
+ $this->settings = $settings;
+ $this->logger = $logger;
+ self::$_instance = $this;
+ }
+
+ // @codeCoverageIgnoreStart
+
+ /**
+ * WordPress Hook 'init'.
+ *
+ * @return void
+ */
+ public function init() {
+
+ // Allow altering the settings.
+ $this->settings = apply_filters( 'openid-connect-generic-settings', $this->settings );
+
+ $this->client = new OpenID_Connect_Generic_Client(
+ $this->settings->client_id,
+ $this->settings->client_secret,
+ $this->settings->scope,
+ $this->settings->endpoint_login,
+ $this->settings->endpoint_userinfo,
+ $this->settings->endpoint_token,
+ $this->get_redirect_uri( $this->settings ),
+ $this->settings->acr_values,
+ $this->get_state_time_limit( $this->settings ),
+ $this->logger
+ );
+
+ $this->client_wrapper = OpenID_Connect_Generic_Client_Wrapper::register( $this->client, $this->settings, $this->logger );
+ if ( defined( 'WP_CLI' ) && WP_CLI ) {
+ return;
+ }
+
+ OpenID_Connect_Generic_Login_Form::register( $this->settings, $this->client_wrapper );
+
+ // Add a shortcode to get the auth URL.
+ add_shortcode( 'openid_connect_generic_auth_url', array( $this->client_wrapper, 'get_authentication_url' ) );
+
+ // Add actions to our scheduled cron jobs.
+ add_action( 'openid-connect-generic-cron-daily', array( $this, 'cron_states_garbage_collection' ) );
+
+ $this->upgrade();
+
+ if ( is_admin() ) {
+ OpenID_Connect_Generic_Settings_Page::register( $this->settings, $this->logger );
+ }
+ }
+
+ /**
+ * Get the default redirect URI.
+ *
+ * @param OpenID_Connect_Generic_Option_Settings $settings The settings object.
+ *
+ * @return string
+ */
+ public function get_redirect_uri( OpenID_Connect_Generic_Option_Settings $settings ) {
+ $redirect_uri = admin_url( 'admin-ajax.php?action=openid-connect-authorize' );
+
+ if ( $settings->alternate_redirect_uri ) {
+ $redirect_uri = site_url( '/openid-connect-authorize' );
+ }
+
+ return $redirect_uri;
+ }
+
+ /**
+ * Get the default state time limit.
+ *
+ * @param OpenID_Connect_Generic_Option_Settings $settings The settings object.
+ *
+ * @return int
+ */
+ public function get_state_time_limit( OpenID_Connect_Generic_Option_Settings $settings ) {
+ $state_time_limit = 180;
+ // State time limit cannot be zero.
+ if ( $settings->state_time_limit ) {
+ $state_time_limit = intval( $settings->state_time_limit );
+ }
+
+ return $state_time_limit;
+ }
+
+ /**
+ * Check if privacy enforcement is enabled, and redirect users that aren't
+ * logged in.
+ *
+ * @return void
+ */
+ public function enforce_privacy_redirect() {
+ if ( $this->settings->enforce_privacy && ! is_user_logged_in() ) {
+ // The client endpoint relies on the wp-admin ajax endpoint.
+ if (
+ ! defined( 'DOING_AJAX' ) ||
+ ! boolval( constant( 'DOING_AJAX' ) ) ||
+ ! isset( $_GET['action'] ) ||
+ 'openid-connect-authorize' != $_GET['action'] ) {
+ auth_redirect();
+ }
+ }
+ }
+
+ /**
+ * Enforce privacy settings for rss feeds.
+ *
+ * @param string $content The content.
+ *
+ * @return mixed
+ */
+ public function enforce_privacy_feeds( $content ) {
+ if ( $this->settings->enforce_privacy && ! is_user_logged_in() ) {
+ $content = __( 'Private site', 'daggerhart-openid-connect-generic' );
+ }
+ return $content;
+ }
+
+ /**
+ * Handle plugin upgrades
+ *
+ * @return void
+ */
+ public function upgrade() {
+ $last_version = get_option( 'openid-connect-generic-plugin-version', 0 );
+ $settings = $this->settings;
+
+ if ( version_compare( self::VERSION, $last_version, '>' ) ) {
+ // An upgrade is required.
+ self::setup_cron_jobs();
+
+ // @todo move this to another file for upgrade scripts
+ if ( isset( $settings->ep_login ) ) {
+ $settings->endpoint_login = $settings->ep_login;
+ $settings->endpoint_token = $settings->ep_token;
+ $settings->endpoint_userinfo = $settings->ep_userinfo;
+
+ unset( $settings->ep_login, $settings->ep_token, $settings->ep_userinfo );
+ $settings->save();
+ }
+
+ // Update the stored version number.
+ update_option( 'openid-connect-generic-plugin-version', self::VERSION );
+ }
+ }
+
+ /**
+ * Expire state transients by attempting to access them and allowing the
+ * transient's own mechanisms to delete any that have expired.
+ *
+ * @return void
+ */
+ public function cron_states_garbage_collection() {
+ global $wpdb;
+ $states = $wpdb->get_col( "SELECT `option_name` FROM {$wpdb->options} WHERE `option_name` LIKE '_transient_openid-connect-generic-state--%'" );
+
+ if ( ! empty( $states ) ) {
+ foreach ( $states as $state ) {
+ $transient = str_replace( '_transient_', '', $state );
+ get_transient( $transient );
+ }
+ }
+ }
+
+ /**
+ * Ensure cron jobs are added to the schedule.
+ *
+ * @return void
+ */
+ public static function setup_cron_jobs() {
+ if ( ! wp_next_scheduled( 'openid-connect-generic-cron-daily' ) ) {
+ wp_schedule_event( time(), 'daily', 'openid-connect-generic-cron-daily' );
+ }
+ }
+
+ /**
+ * Activation hook.
+ *
+ * @return void
+ */
+ public static function activation() {
+ self::setup_cron_jobs();
+ }
+
+ /**
+ * Deactivation hook.
+ *
+ * @return void
+ */
+ public static function deactivation() {
+ wp_clear_scheduled_hook( 'openid-connect-generic-cron-daily' );
+ }
+
+ /**
+ * Simple autoloader.
+ *
+ * @param string $class The class name.
+ *
+ * @return void
+ */
+ public static function autoload( $class ) {
+ $prefix = 'OpenID_Connect_Generic_';
+
+ if ( stripos( $class, $prefix ) !== 0 ) {
+ return;
+ }
+
+ $filename = $class . '.php';
+
+ // Internal files are all lowercase and use dashes in filenames.
+ if ( false === strpos( $filename, '\\' ) ) {
+ $filename = strtolower( str_replace( '_', '-', $filename ) );
+ } else {
+ $filename = str_replace( '\\', DIRECTORY_SEPARATOR, $filename );
+ }
+
+ $filepath = __DIR__ . '/includes/' . $filename;
+
+ if ( file_exists( $filepath ) ) {
+ require_once $filepath;
+ }
+ }
+
+ /**
+ * Instantiate the plugin and hook into WordPress.
+ *
+ * @return void
+ */
+ public static function bootstrap() {
+ /**
+ * This is a documented valid call for spl_autoload_register.
+ *
+ * @link https://www.php.net/manual/en/function.spl-autoload-register.php#71155
+ */
+ spl_autoload_register( array( 'OpenID_Connect_Generic', 'autoload' ) );
+
+ $settings = new OpenID_Connect_Generic_Option_Settings(
+ // Default settings values.
+ array(
+ // OAuth client settings.
+ 'login_type' => defined( 'OIDC_LOGIN_TYPE' ) ? OIDC_LOGIN_TYPE : 'button',
+ 'client_id' => defined( 'OIDC_CLIENT_ID' ) ? OIDC_CLIENT_ID : '',
+ 'client_secret' => defined( 'OIDC_CLIENT_SECRET' ) ? OIDC_CLIENT_SECRET : '',
+ 'scope' => defined( 'OIDC_CLIENT_SCOPE' ) ? OIDC_CLIENT_SCOPE : '',
+ 'endpoint_login' => defined( 'OIDC_ENDPOINT_LOGIN_URL' ) ? OIDC_ENDPOINT_LOGIN_URL : '',
+ 'endpoint_userinfo' => defined( 'OIDC_ENDPOINT_USERINFO_URL' ) ? OIDC_ENDPOINT_USERINFO_URL : '',
+ 'endpoint_token' => defined( 'OIDC_ENDPOINT_TOKEN_URL' ) ? OIDC_ENDPOINT_TOKEN_URL : '',
+ 'endpoint_end_session' => defined( 'OIDC_ENDPOINT_LOGOUT_URL' ) ? OIDC_ENDPOINT_LOGOUT_URL : '',
+ 'acr_values' => defined( 'OIDC_ACR_VALUES' ) ? OIDC_ACR_VALUES : '',
+
+ // Non-standard settings.
+ 'no_sslverify' => 0,
+ 'http_request_timeout' => 5,
+ 'identity_key' => 'preferred_username',
+ 'nickname_key' => 'preferred_username',
+ 'email_format' => '{email}',
+ 'displayname_format' => '',
+ 'identify_with_username' => false,
+ 'state_time_limit' => 180,
+
+ // Plugin settings.
+ 'enforce_privacy' => defined( 'OIDC_ENFORCE_PRIVACY' ) ? intval( OIDC_ENFORCE_PRIVACY ) : 0,
+ 'alternate_redirect_uri' => 0,
+ 'token_refresh_enable' => 1,
+ 'link_existing_users' => defined( 'OIDC_LINK_EXISTING_USERS' ) ? intval( OIDC_LINK_EXISTING_USERS ) : 0,
+ 'create_if_does_not_exist' => defined( 'OIDC_CREATE_IF_DOES_NOT_EXIST' ) ? intval( OIDC_CREATE_IF_DOES_NOT_EXIST ) : 1,
+ 'redirect_user_back' => defined( 'OIDC_REDIRECT_USER_BACK' ) ? intval( OIDC_REDIRECT_USER_BACK ) : 0,
+ 'redirect_on_logout' => defined( 'OIDC_REDIRECT_ON_LOGOUT' ) ? intval( OIDC_REDIRECT_ON_LOGOUT ) : 1,
+ 'enable_logging' => defined( 'OIDC_ENABLE_LOGGING' ) ? intval( OIDC_ENABLE_LOGGING ) : 0,
+ 'log_limit' => defined( 'OIDC_LOG_LIMIT' ) ? intval( OIDC_LOG_LIMIT ) : 1000,
+ )
+ );
+
+ $logger = new OpenID_Connect_Generic_Option_Logger( 'error', $settings->enable_logging, $settings->log_limit );
+
+ $plugin = new self( $settings, $logger );
+
+ add_action( 'init', array( $plugin, 'init' ) );
+
+ // Privacy hooks.
+ add_action( 'template_redirect', array( $plugin, 'enforce_privacy_redirect' ), 0 );
+ add_filter( 'the_content_feed', array( $plugin, 'enforce_privacy_feeds' ), 999 );
+ add_filter( 'the_excerpt_rss', array( $plugin, 'enforce_privacy_feeds' ), 999 );
+ add_filter( 'comment_text_rss', array( $plugin, 'enforce_privacy_feeds' ), 999 );
+ }
+
+ /**
+ * Create (if needed) and return a singleton of self.
+ *
+ * @return OpenID_Connect_Generic
+ */
+ public static function instance() {
+ if ( null === self::$_instance ) {
+ self::bootstrap();
+ }
+ return self::$_instance;
+ }
+}
+
+OpenID_Connect_Generic::instance();
+
+register_activation_hook( __FILE__, array( 'OpenID_Connect_Generic', 'activation' ) );
+register_deactivation_hook( __FILE__, array( 'OpenID_Connect_Generic', 'deactivation' ) );
+
+// Provide publicly accessible plugin helper functions.
+require_once 'includes/functions.php';
diff --git a/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/readme.txt b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/readme.txt
new file mode 100644
index 00000000..6d9cd567
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/readme.txt
@@ -0,0 +1,137 @@
+=== OpenID Connect Generic Client ===
+Contributors: daggerhart, tnolte
+Tags: security, login, oauth2, openidconnect, apps, authentication, autologin, sso
+Requires at least: 5.0
+Tested up to: 6.9.0
+Stable tag: 3.10.2
+Requires PHP: 7.4
+License: GPLv2 or later
+License URI: http://www.gnu.org/licenses/gpl-2.0.html
+
+A simple client that provides SSO or opt-in authentication against a generic OAuth2 Server implementation.
+
+== Description ==
+
+This plugin allows to authenticate users against OpenID Connect OAuth2 API with Authorization Code Flow.
+Once installed, it can be configured to automatically authenticate users (SSO), or provide a "Login with OpenID Connect"
+button on the login form. After consent has been obtained, an existing user is automatically logged into WordPress, while
+new users are created in WordPress database.
+
+Much of the documentation can be found on the Settings > OpenID Connect Generic dashboard page.
+
+Please submit issues to the Github repo: https://github.com/daggerhart/openid-connect-generic
+
+== Installation ==
+
+1. Upload to the `/wp-content/plugins/` directory
+1. Activate the plugin
+1. Visit Settings > OpenID Connect and configure to meet your needs
+
+== Frequently Asked Questions ==
+
+= What is the client's Redirect URI? =
+
+Most OAuth2 servers will require whitelisting a set of redirect URIs for security purposes. The Redirect URI provided
+by this client is like so: https://example.com/wp-admin/admin-ajax.php?action=openid-connect-authorize
+
+Replace `example.com` with your domain name and path to WordPress.
+
+= Can I change the client's Redirect URI? =
+
+Some OAuth2 servers do not allow for a client redirect URI to contain a query string. The default URI provided by
+this module leverages WordPress's `admin-ajax.php` endpoint as an easy way to provide a route that does not include
+HTML, but this will naturally involve a query string. Fortunately, this plugin provides a setting that will make use of
+an alternate redirect URI that does not include a query string.
+
+On the settings page for this plugin (Dashboard > Settings > OpenID Connect Generic) there is a checkbox for
+**Alternate Redirect URI**. When checked, the plugin will use the Redirect URI
+`https://example.com/openid-connect-authorize`.
+
+
+== Changelog ==
+
+= 3.10.2 =
+
+* Fix: @socialmedialabs - Regression affecting SSO Auto Login with url handling improvement changes.
+
+= 3.10.1 =
+
+* Chore: @daggerhart - Readme updates and clarifications.
+* Chore: @daggerhart - Release workflow updates.
+* Improved error handling for malformed urls.
+* Fix: @JUVOJustin - Change request for userinfo to GET.
+* Feature: @JUVOJustin - New filter for settings values `openid-connect-generic-settings`.
+* Feature: @JUVOJustin - New filter for state values `openid-connect-generic-new-state-value`.
+
+= 3.10.0 =
+
+* Chore: @timnolte - Dependency updates.
+* Fix: @drzraf - Prevents running the auth url filter twice.
+* Fix: @timnolte - Updates the log cleanup handling to properly retain the configured number of log entries.
+* Fix: @timnolte - Updates the log display output to reflect the log retention policy.
+* Chore: @timnolte - Adds Unit Testing & New Local Development Environment.
+* Feature: @timnolte - Updates logging to allow for tracking processing time.
+* Feature: @menno-ll - Adds a remember me feature via a new filter.
+* Improvement: @menno-ll - Updates WP Cookie Expiration to Same as Session Length.
+
+= 3.9.1 =
+
+* Improvement: @timnolte - Refactors Composer setup and GitHub Actions.
+* Improvement: @timnolte - Bumps WordPress tested version compatibility.
+
+= 3.9.0 =
+
+* Feature: @matchaxnb - Added support for additional configuration constants.
+* Feature: @schanzen - Added support for agregated claims.
+* Fix: @rkcreation - Fixed access token not updating user metadata after login.
+* Fix: @danc1248 - Fixed user creation issue on Multisite Networks.
+* Feature: @RobjS - Added plugin singleton to support for more developer customization.
+* Feature: @jkouris - Added action hook to allow custom handling of session expiration.
+* Fix: @tommcc - Fixed admin CSS loading only on the plugin settings screen.
+* Feature: @rkcreation - Added method to refresh the user claim.
+* Feature: @Glowsome - Added acr_values support & verification checks that it when defined in options is honored.
+* Fix: @timnolte - Fixed regression which caused improper fallback on missing claims.
+* Fix: @slykar - Fixed missing query string handling in redirect URL.
+* Fix: @timnolte - Fixed issue with some user linking and user creation handling.
+* Improvement: @timnolte - Fixed plugin settings typos and screen formatting.
+* Security: @timnolte - Updated build tooling security vulnerabilities.
+* Improvement: @timnolte - Changed build tooling scripts.
+
+= 3.8.5 =
+
+* Fix: @timnolte - Fixed missing URL request validation before use & ensure proper current page URL is setup for Redirect Back.
+* Fix: @timnolte - Fixed Redirect URL Logic to Handle Sub-directory Installs.
+* Fix: @timnolte - Fixed issue with redirecting user back when the openid_connect_generic_auth_url shortcode is used.
+
+= 3.8.4 =
+
+* Fix: @timnolte - Fixed invalid State object access for redirection handling.
+* Improvement: @timnolte - Fixed local wp-env Docker development environment.
+* Improvement: @timnolte - Fixed Composer scripts for linting and static analysis.
+
+= 3.8.3 =
+
+* Fix: @timnolte - Fixed problems with proper redirect handling.
+* Improvement: @timnolte - Changes redirect handling to use State instead of cookies.
+* Improvement: @timnolte - Refactored additional code to meet coding standards.
+
+= 3.8.2 =
+
+* Fix: @timnolte - Fixed reported XSS vulnerability on WordPress login screen.
+
+= 3.8.1 =
+
+* Fix: @timnolte - Prevent SSO redirect on password protected posts.
+* Fix: @timnolte - CI/CD build issues.
+* Fix: @timnolte - Invalid redirect handling on logout for Auto Login setting.
+
+= 3.8.0 =
+
+* Feature: @timnolte - Ability to use 6 new constants for setting client configuration instead of storing in the DB.
+* Improvement: @timnolte - Plugin development & contribution updates.
+* Improvement: @timnolte - Refactored to meet WordPress coding standards.
+* Improvement: @timnolte - Refactored to provide localization.
+
+--------
+
+[See the previous changelogs here](https://github.com/oidc-wp/openid-connect-generic/blob/main/CHANGELOG.md#changelog)
diff --git a/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/wp-cli.yml b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/wp-cli.yml
new file mode 100644
index 00000000..3f430d6f
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/daggerhart-openid-connect-generic/wp-cli.yml
@@ -0,0 +1 @@
+path: /app/wp
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/assets.yml b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/assets.yml
new file mode 100644
index 00000000..f32e729c
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/assets.yml
@@ -0,0 +1,24 @@
+name: Plugin asset/readme update on WordPress.org
+
+on: workflow_dispatch
+
+jobs:
+ trunk:
+ name: Push assets to trunk on WordPress.org
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: https://code.forgejo.org/actions/checkout@v4
+
+ - name: Install and cache rsync
+ uses: https://github.com/awalsh128/cache-apt-pkgs-action@latest
+ with:
+ packages: rsync subversion
+ version: 1.0
+
+ - name: WordPress.org plugin asset/readme update
+ uses: https://github.com/10up/action-wordpress-plugin-asset-update@stable
+ env:
+ SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
+ SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
+ SLUG: event-bridge-for-activitypub
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/deploy.yml b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/deploy.yml
new file mode 100644
index 00000000..45fae27a
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/deploy.yml
@@ -0,0 +1,26 @@
+name: Deploy to WordPress.org
+
+on:
+ push:
+ tags: '[0-9]+.[0-9]+.[0-9]+'
+
+jobs:
+ tag:
+ name: Deploy tagged release on WordPress.org
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: https://code.forgejo.org/actions/checkout@v4
+
+ - name: Install and cache rsync and subversion
+ uses: https://github.com/awalsh128/cache-apt-pkgs-action@latest
+ with:
+ packages: rsync subversion
+ version: 1.0
+
+ - name: WordPress Plugin Deploy
+ uses: https://github.com/10up/action-wordpress-plugin-deploy@stable
+ env:
+ SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
+ SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
+ SLUG: event-bridge-for-activitypub
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpcs.yml b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpcs.yml
new file mode 100644
index 00000000..21622e2e
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpcs.yml
@@ -0,0 +1,61 @@
+name: PHP Code Checker
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+
+jobs:
+ phpcs:
+ name: PHP Code Checker
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ php-versions: ['8.1']
+ steps:
+ - name: Checkout
+ uses: https://code.forgejo.org/actions/checkout@v4
+
+ - name: Cache Composer
+ id: cache-composer
+ uses: https://code.forgejo.org/actions/cache@v4
+ with:
+ path: |
+ ./vendor/
+ key: cache-composer-3
+
+ - name: Setup cache environment for PHP Extensions
+ id: php-extensions-cache
+ uses: https://github.com/shivammathur/cache-extensions@v1
+ with:
+ php-version: ${{ matrix.php-versions }}
+ extensions: dom, iconv, json, libxml, zip
+ key: php-extensions-cache-v1
+
+ - name: Cache PHP extensions
+ uses: https://code.forgejo.org/actions/cache@v4
+ with:
+ path: ${{ steps.php-extensions-cache.outputs.dir }}
+ key: ${{ steps.php-extensions-cache.outputs.key }}
+ restore-keys: ${{ steps.php-extensions-cache.outputs.key }}
+
+ - name: Setup PHP
+ uses: https://github.com/shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-versions }}
+ extensions: dom, iconv, json, libxml, zip
+ coverage: none
+ tools: composer, cs2pr
+ env:
+ runner: self-hosted
+ GITHUB_TOKEN: ${{ env.COMPOSER_TOKEN }}
+
+ - name: Install Composer dependencies for PHP
+ if: steps.cache-composer.outputs.cache-hit != 'true'
+ uses: ramsey/composer-install@v3
+ env:
+ COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.COMPOSER_TOKEN }}"}}'
+
+ - name: Run PHP_CodeSniffer
+ run: ./vendor/bin/phpcs
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpstan.yml b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpstan.yml
new file mode 100644
index 00000000..ce87dacc
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpstan.yml
@@ -0,0 +1,87 @@
+name: PHPStan Tests
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+
+env:
+ WP_TESTS_DIR: /workspace/wordpress-test-lib
+ WP_CORE_DIR: /workspace/wordpress
+
+jobs:
+ phpstan:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ php-version: ['7.4','8.1','8.4']
+ name: PHPStan for WordPress ${{ matrix.php-version }}
+ steps:
+ - name: Checkout
+ uses: https://code.forgejo.org/actions/checkout@v4
+
+ - name: Cache WordPress Setup and installed plugins (Event plugins and ActivityPub plugin).
+ id: cache-wordpress
+ uses: https://code.forgejo.org/actions/cache@v4
+ with:
+ path: |
+ ${{ env.WP_CORE_DIR }}
+ ${{ env.WP_TESTS_DIR }}
+ key: cache-phpstan-wordpress-6.7-activitypub-5.1.0-2
+
+ - name: Cache Composer
+ id: cache-composer
+ uses: https://code.forgejo.org/actions/cache@v4
+ with:
+ path: |
+ ./vendor/
+ key: cache-composer-3
+
+ - name: Setup cache environment for PHP Extensions
+ id: php-extensions-cache
+ uses: https://github.com/shivammathur/cache-extensions@v1
+ with:
+ php-version: ${{ matrix.php-version }}
+ extensions: dom, iconv, json, libxml, zip
+ key: php-extensions-cache-v1
+
+ - name: Cache PHP extensions
+ uses: https://code.forgejo.org/actions/cache@v4
+ with:
+ path: ${{ steps.php-extensions-cache.outputs.dir }}
+ key: ${{ steps.php-extensions-cache.outputs.key }}
+ restore-keys: ${{ steps.php-extensions-cache.outputs.key }}
+
+ - name: Setup PHP
+ uses: https://github.com/shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-version }}
+ extensions: dom, iconv, json, libxml, zip
+ coverage: none
+ tools: composer, cs2pr
+ env:
+ runner: self-hosted
+ GITHUB_TOKEN: ${{ env.COMPOSER_TOKEN }}
+
+ - name: Install Composer dependencies for PHP
+ if: steps.cache-composer.outputs.cache-hit != 'true'
+ uses: ramsey/composer-install@v3
+ env:
+ COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.COMPOSER_TOKEN }}"}}'
+
+ - name: Log debug information
+ run: |
+ git --version
+ php --version
+ composer --version
+
+ - name: Install third party plugins, so that PHP Stan finds that functions
+ if: steps.cache-wordpress.outputs.cache-hit != 'true'
+ run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 latest true false false true
+
+ - name: Running PHPStan Analyze
+ if: ${{ success() || failure() }}
+ run: |
+ ./vendor/bin/phpstan --version
+ ./vendor/bin/phpstan analyze -vv --memory-limit=2G --error-format=checkstyle | cs2pr
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpunit.yml b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpunit.yml
new file mode 100644
index 00000000..9c07a0db
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpunit.yml
@@ -0,0 +1,147 @@
+name: PHPUnit
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+
+env:
+ WP_TESTS_DIR: /workspace/wordpress-test-lib
+ WP_CORE_DIR: /workspace/wordpress
+
+jobs:
+ phpunit:
+ runs-on: ubuntu-latest
+ services:
+ mysql:
+ image: mariadb
+ env:
+ MYSQL_ROOT_PASSWORD: root
+ strategy:
+ matrix:
+ php-version: ['7.4', '8.1', '8.3', '8.4']
+ wordpress-version: ['6.7', '6.8-RC3']
+ name: "PHPUnit: PHP ${{ matrix.php-version }} - WordPress ${{ matrix.wordpress-version }}"
+ continue-on-error: true
+ steps:
+ - name: Checkout
+ uses: https://code.forgejo.org/actions/checkout@v4
+
+ - name: Cache WordPress Setup and installed plugins (Event plugins and ActivityPub plugin).
+ id: cache-wordpress
+ uses: https://code.forgejo.org/actions/cache@v4
+ with:
+ path: |
+ ${{ env.WP_CORE_DIR }}
+ ${{ env.WP_TESTS_DIR }}
+ key: cache-phpunit-wordpress-${{ matrix.wordpress-version }}-activitypub-5.7.0
+
+ - name: Cache Composer
+ id: cache-composer
+ uses: https://code.forgejo.org/actions/cache@v4
+ with:
+ path: |
+ ./vendor/
+ key: cache-composer-3
+
+ - name: Setup cache environment for PHP Extensions
+ id: php-extensions-cache
+ uses: https://github.com/shivammathur/cache-extensions@v1
+ with:
+ php-version: ${{ matrix.php-version }}
+ extensions: dom, iconv, json, libxml, zip
+ key: php-extensions-cache-v1
+
+ - name: Cache PHP extensions
+ uses: https://code.forgejo.org/actions/cache@v4
+ with:
+ path: ${{ steps.php-extensions-cache.outputs.dir }}
+ key: ${{ steps.php-extensions-cache.outputs.key }}
+ restore-keys: ${{ steps.php-extensions-cache.outputs.key }}
+
+ - name: Setup PHP
+ uses: https://github.com/shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-version }}
+ extensions: dom, iconv, json, libxml, zip
+ coverage: none
+ tools: composer, cs2pr
+ env:
+ runner: self-hosted
+ GITHUB_TOKEN: ${{ secrets.COMPOSER_TOKEN }}
+
+ - name: Install Composer dependencies for PHP
+ if: steps.cache-composer.outputs.cache-hit != 'true'
+ uses: ramsey/composer-install@v3
+ env:
+ COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.COMPOSER_TOKEN }}"}}'
+
+ - name: Install and cache mysqladmin needed to initialize the test database
+ uses: https://github.com/awalsh128/cache-apt-pkgs-action@latest
+ with:
+ packages: mysql-client
+ version: 1.0
+
+ - name: Setup Test Environment
+ if: steps.cache-wordpress.outputs.cache-hit != 'true'
+ run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 ${{ matrix.wordpress-version }} false false false false
+
+ - name: Initialize WordPress test database
+ if: steps.cache-wordpress.outputs.cache-hit != 'false'
+ run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 ${{ matrix.wordpress-version }} false true true true
+
+ - name: Run General Tests
+ run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit
+ env:
+ PHP_VERSION: ${{ matrix.php-version }}
+
+ - name: Run Integration tests for The Events Calendar
+ run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=the_events_calendar
+ env:
+ PHP_VERSION: ${{ matrix.php-version }}
+
+ - name: Run Integration tests for VS Event List
+ run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=vs_event_list
+ env:
+ PHP_VERSION: ${{ matrix.php-version }}
+
+ - name: Run Integration tests for GatherPress
+ run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=gatherpress
+ env:
+ PHP_VERSION: ${{ matrix.php-version }}
+
+ - name: Run Integration tests for Events Manager
+ run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=events_manager
+ env:
+ PHP_VERSION: ${{ matrix.php-version }}
+
+ - name: Run Integration tests for WP Event Manager
+ run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=wp_event_manager
+ env:
+ PHP_VERSION: ${{ matrix.php-version }}
+
+ - name: Run Integration tests for Eventin (WP Event Solution)
+ run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=eventin
+ env:
+ PHP_VERSION: ${{ matrix.php-version }}
+
+ - name: Run Integration tests for Modern Events Calendar Lite
+ run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=modern_events_calendar_lite
+ env:
+ PHP_VERSION: ${{ matrix.php-version }}
+
+ - name: Run Integration tests for EventPrime
+ run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=eventprime
+ env:
+ PHP_VERSION: ${{ matrix.php-version }}
+
+ - name: Run Integration tests for Event Organiser
+ run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=event_organiser
+ env:
+ PHP_VERSION: ${{ matrix.php-version }}
+
+ - name: Run Integration tests for EventON – Events Calendar
+ run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=eventon
+ env:
+ PHP_VERSION: ${{ matrix.php-version }}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/release.yml b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/release.yml
new file mode 100644
index 00000000..78d84211
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.forgejo/workflows/release.yml
@@ -0,0 +1,17 @@
+on:
+ push:
+ tags:
+ - '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?$'
+
+jobs:
+ upload-release:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: https://code.forgejo.org/actions/checkout@v4
+
+ - uses: https://code.forgejo.org/actions/forgejo-release@v2
+ with:
+ direction: upload
+ url: https://codeberg.org
+ release-notes: ${{ TAG }}
+ token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.gitattributes b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.gitattributes
new file mode 100644
index 00000000..f5aa0a25
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/.gitattributes
@@ -0,0 +1,26 @@
+.distignore export-ignore
+.forgejo export-ignore
+.gitattributes export-ignore
+.gitignore export-ignore
+.wordpress-org export-ignore
+.wp-env.json export-ignore
+bin export-ignore
+CODE_OF_CONDUCT.md export-ignore
+composer.json export-ignore
+composer.lock export-ignore
+docker-compose.yml export-ignore
+Dockerfile export-ignore
+docs export-ignore
+FEDERATION.md export-ignore
+Gruntfile.js export-ignore
+node_modules export-ignore
+package.json export-ignore
+package-lock.json export-ignore
+phpcs.xml export-ignore
+phpstan.neon export-ignore
+phpstan.neon.dist export-ignore
+phpunit.xml export-ignore
+README.md export-ignore
+src export-ignore
+tests export-ignore
+vendor export-ignore
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/CHANGELOG.md b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/CHANGELOG.md
new file mode 100644
index 00000000..d87b1e66
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/CHANGELOG.md
@@ -0,0 +1,48 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [1.1.0] - 2025-04-12
+
+### Added
+
+* Basic support for Starter Kits
+
+### Fixed
+
+* Fixed: Uncatched error in following process (issue #145)
+* Fixed: Compatibility with ActivityPub plugin version 5.7.0
+
+## [1.0.0] - 2025-02-11
+
+### Changed
+
+* This plugin now depends on ActivityPub plugin version greater than 5.1.0
+
+### Added
+
+* Support for the EventPrime event plugin
+* Event self-announce feature at configurable time before event starts
+* Blueprint (Preview via WordPress Playground)
+* Event Sources feature: cache and list events from remote ActivityPub profiles on your site
+* Custom ActivityPub preview
+* Admin setting to enforce sending summary of events as plain text
+
+### Fixed
+
+* The Events Calendar date times when using the Gutenberg editor.
+* Improved admin UI for event-category mapping
+
+## [0.3.5] - 2025-01-03
+
+### Fixed
+
+* Images of Acknowledgements in Admin UI
+
+## [0.3.4] - 2024-12-21
+
+* Initial release on WordPress.org
+
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/CONTRIBUTING.md b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/CONTRIBUTING.md
new file mode 100644
index 00000000..3f790ce3
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/CONTRIBUTING.md
@@ -0,0 +1,44 @@
+# Contributing
+
+Thank you for considering contributing to Event Bridge For ActivityPub WordPress Plugin 💜
+
+You can contribute in the following ways:
+
+- Finding and reporting bugs
+- Translating the plugin into various languages
+- Contributing code by fixing bugs or implementing features
+- Improving the documentation
+- Proposing ideas for new features
+
+## Bug reports
+
+Bug reports and feature suggestions must use descriptive and concise titles and be submitted to [Codeberg Issues](https://codeberg.org/Event-Federation/wordpress-event-bridge-for-activitypub/issues) or the [WordPress.org Support Forum](https://wordpress.org/support/plugin/event-bridge-for-activitypub/). Please use the search function to make sure that you are not submitting duplicates, and that a similar report or request has not already been resolved or rejected.
+
+## Translations
+
+You can submit translations via [translate.WordPress.org](https://translate.wordpress.org/projects/wp-plugins/event-bridge-for-activitypub/). These changes are merged by WordPress itself to each plugin installation.
+
+## Pull requests
+
+**Please use clean, concise titles for your pull requests.** Unless the pull request is about refactoring code or other internal tasks, assume that the person reading the pull request title is not a programmer or WordPress developer, but instead a WordPress user, and **try to describe your change or fix from their perspective**. We use commit squashing, so the final commit in the main branch will carry the title of the pull request, and commits from the main branch are fed into the changelog. The changelog is separated into [keepachangelog.com categories](https://keepachangelog.com/en/1.0.0/), and while that spec does not prescribe how the entries ought to be named, for easier sorting, start your pull request titles using one of the verbs "Add", "Change", "Deprecate", "Remove", or "Fix" (present tense).
+
+Example:
+
+| Not ideal | Better |
+| ------------------------------------ | ------------------------------------------------------------- |
+| Fixed NoMethodError in RemovalWorker | Fix nil error when removing statuses caused by race condition |
+
+It is not always possible to phrase every change in such a manner, but it is desired.
+
+**The smaller the set of changes in the pull request is, the quicker it can be reviewed and merged.** Splitting tasks into multiple smaller pull requests is often preferable.
+
+**Pull requests that do not pass automated checks may not be reviewed**. In particular, you need to keep in mind:
+
+- Unit and integration test (PHPUnit)
+- Code style rules (PHP_CodeSniffer)
+- [WordPress plugin guidelines](https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/)
+
+## Documentation
+
+- Documentation for users is currently in the README.md and readme.txt files and the admin pages of the plugin (see the `.template/` folder), although this can change if it could be advantageous.
+- Documentation for developers is the the projects [Wiki](https://codeberg.org/Event-Federation/wordpress-event-bridge-for-activitypub/wiki).
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/LICENSE b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/LICENSE
new file mode 100644
index 00000000..241d6f31
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/LICENSE
@@ -0,0 +1,235 @@
+GNU AFFERO GENERAL PUBLIC LICENSE
+Version 3, 19 November 2007
+
+Copyright (C) 2007 Free Software Foundation, Inc.
+
+Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
+
+ Preamble
+
+The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software.
+
+The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
+
+Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software.
+
+A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public.
+
+The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version.
+
+An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+ TERMS AND CONDITIONS
+
+0. Definitions.
+
+"This License" refers to version 3 of the GNU Affero General Public License.
+
+"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
+
+"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations.
+
+To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.
+
+A "covered work" means either the unmodified Program or a work based on the Program.
+
+To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
+
+To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
+
+An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
+
+1. Source Code.
+The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work.
+
+A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
+
+The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
+
+The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
+
+The Corresponding Source for a work in source code form is that same work.
+
+2. Basic Permissions.
+All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
+
+You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
+
+Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
+
+3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
+
+When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
+
+4. Conveying Verbatim Copies.
+You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
+
+You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
+
+5. Conveying Modified Source Versions.
+You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
+
+A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
+
+6. Conveying Non-Source Forms.
+You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
+
+ d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
+
+A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
+
+A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
+
+"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
+
+If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
+
+The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
+
+Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
+
+7. Additional Terms.
+"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
+
+Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
+
+All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
+
+8. Termination.
+
+You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
+
+However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
+
+Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
+
+9. Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
+
+10. Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
+
+An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
+
+11. Patents.
+
+A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version".
+
+A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
+
+In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
+
+A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
+
+12. No Surrender of Others' Freedom.
+
+If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
+
+13. Remote Network Interaction; Use with the GNU General Public License.
+
+Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph.
+
+Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License.
+
+14. Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation.
+
+If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
+
+Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
+
+15. Disclaimer of Warranty.
+
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+16. Limitation of Liability.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+17. Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
+
+END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
+
+ test
+ Copyright (C) 2023 linos
+
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements.
+
+You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see .
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/css/event-bridge-for-activitypub-admin.css b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/css/event-bridge-for-activitypub-admin.css
new file mode 100644
index 00000000..da750dba
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/css/event-bridge-for-activitypub-admin.css
@@ -0,0 +1,236 @@
+.settings_page_event-bridge-for-activitypub #wpcontent {
+ padding-left: 0;
+}
+
+.event-bridge-for-activitypub-settings-page .box {
+ border: 1px solid #c3c4c7;
+ background-color: #fff;
+ padding: 1em 1.5em;
+ margin-bottom: 1.5em;
+}
+
+.event-bridge-for-activitypub-settings-page .logo-center {
+ width: 25%;
+ margin: 10px 5% 10px 5%;
+}
+
+.event-bridge-for-activitypub-settings-page .box ul.event-bridge-for-activitypub-list {
+ margin-left: 0.6em;
+}
+
+.event-bridge-for-activitypub-settings-page .box pre {
+ padding: 1rem;
+ min-height: 200px;
+ box-shadow: none;
+ border-radius: 15px;
+ border: 1px solid #dfe0e2;
+ background-color: #f7f7f7;
+}
+
+.event-bridge-for-activitypub-settings td {
+ padding-top: 20px;
+ padding-bottom: 20px;
+}
+
+.event-bridge-for-activitypub-settings-header {
+ text-align: center;
+ margin: 0 0 1rem;
+}
+
+.event-bridge-for-activitypub-settings-title-section {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ clear: both;
+ padding-top: 8px;
+}
+
+.event-bridge-for-activitypub-settings-tabs-wrapper {
+ display: -ms-inline-grid;
+ -ms-grid-columns: auto auto auto auto;
+ vertical-align: top;
+ display: inline-grid;
+ grid-template-columns: auto auto auto auto;
+}
+
+.event-bridge-for-activitypub-settings-tab.active {
+ box-shadow: inset 0 -3px #3582c4;
+ font-weight: 600;
+}
+
+.event-bridge-for-activitypub-settings-tab {
+ display: block;
+ text-decoration: none;
+ color: inherit;
+ padding: .5rem 1rem 1rem;
+ margin: 0 1rem;
+ transition: box-shadow .5s ease-in-out;
+}
+
+.event-bridge-for-activitypub-settings .box h3 {
+ font-size: 1.15em;
+ margin-bottom: 0em;
+}
+
+#event_bridge_for_activitypub_initially_activated {
+ display: hidden;
+}
+
+/* Accordions for admin pages */
+.event-bridge-for-activitypub-settings-accordion {
+ border: 1px solid #c3c4c7;
+}
+
+.event-bridge-for-activitypub-settings-accordion-heading {
+ margin: 0;
+ border-top: 1px solid #c3c4c7;
+ font-size: inherit;
+ line-height: inherit;
+ font-weight: 600;
+ color: inherit;
+}
+
+.event-bridge-for-activitypub-settings-accordion-heading:first-child {
+ border-top: none;
+}
+
+.event-bridge-for-activitypub-settings-accordion-panel {
+ margin: 0;
+ padding: 1em 1.5em;
+ background: #fff;
+}
+
+.event-bridge-for-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;
+}
+
+.event-bridge-for-activitypub-settings-accordion-trigger {
+ color: #2c3338;
+ cursor: pointer;
+ font-weight: 400;
+ text-align: left;
+}
+
+.event-bridge-for-activitypub-settings-accordion-trigger .title {
+ pointer-events: none;
+ font-weight: 600;
+ flex-grow: 1;
+}
+
+.event-bridge-for-activitypub-settings-accordion-trigger .icon,
+.event-bridge-for-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;
+}
+
+.event-bridge-for-activitypub-settings-accordion-trigger[aria-expanded="true"] .icon {
+ transform: translateY(-30%) rotate(-135deg);
+}
+
+.event-bridge-for-activitypub-settings-accordion-trigger:active,
+.event-bridge-for-activitypub-settings-accordion-trigger:hover {
+ background: #f6f7f7;
+}
+
+.event-bridge-for-activitypub-settings-accordion-trigger:focus {
+ color: #1d2327;
+ border: none;
+ box-shadow: none;
+ outline-offset: -1px;
+ outline: 2px solid #2271b1;
+ background-color: #f6f7f7;
+}
+
+.event-bridge-for-activitypub-settings-inline-icon {
+ width: 1.5em;
+ height: 1.5em;
+ vertical-align: middle;
+ margin: 0 0.3em;
+}
+
+code.event-bridge-for-activitypub-settings-example-url {
+ display: block;
+ background: rgb(28, 29, 33);
+ padding: 8px;
+ margin: 10px 0px 10px 0;
+ border-radius: 7px;
+ color: #d5d5d6;
+ overflow-x: auto;
+ word-break: break-all;
+}
+
+#event_bridge_for_activitypub_summary_type_custom-details {
+ display: none;
+}
+
+#event_bridge_for_activitypub_summary_type_custom-details > details {
+ padding: 0.5em;
+}
+
+.event_bridge_for_activitypub-list {
+ list-style: disc;
+ padding-left: 22px;
+}
+
+.event_bridge_for_activitypub-admin-table-container {
+ padding-left: 22px;
+}
+
+.event_bridge_for_activitypub-admin-table-top > h2 {
+ display: inline-block;
+ font-size: 23px;
+ font-weight: 400;
+ margin: 0 10px 0 2px;
+ padding: 9px 0 4px;
+ line-height: 1.3;
+}
+
+.event_bridge_for_activitypub-admin-table-top > a {
+ display: inline-block;
+}
+
+.settings_page_event-bridge-for-activitypub .notice-warning {
+ background: #fff;
+ border: 1px solid #c3c4c7;
+ border-left-width: 4px;
+ box-shadow: 0 1px 1px rgba(0,0,0,.04);
+ margin: 5px 15px 2px;
+ padding: 1px 12px;
+ border-left-color: #dba617;
+}
+
+.event-bridge-for-activitypub-settings .select-cell::before {
+ content: "\21D2";
+ margin-right: 8px;
+ color: inherit;
+}
+
+ul.event-bridge-for-activitypub-syntax-list {
+ list-style: disc;
+}
+
+ul.event-bridge-for-activitypub-syntax-list > li {
+ margin: 6px 6px 6px 20px;
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/acknowledgement-NGI0Entrust.svg b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/acknowledgement-NGI0Entrust.svg
new file mode 100644
index 00000000..0d211b38
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/acknowledgement-NGI0Entrust.svg
@@ -0,0 +1,121 @@
+
+
+
+
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/acknowledgement-NLnet.svg b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/acknowledgement-NLnet.svg
new file mode 100644
index 00000000..7980346a
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/acknowledgement-NLnet.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/activitypub.svg b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/activitypub.svg
new file mode 100644
index 00000000..f56d428f
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/activitypub.svg
@@ -0,0 +1,288 @@
+
+
+
+
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/fediverse.svg b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/fediverse.svg
new file mode 100644
index 00000000..a789df22
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/fediverse.svg
@@ -0,0 +1,17 @@
+
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/gancio.png b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/gancio.png
new file mode 100644
index 00000000..d53e1632
Binary files /dev/null and b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/gancio.png differ
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/mastodon.svg b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/mastodon.svg
new file mode 100644
index 00000000..0f8baebf
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/mastodon.svg
@@ -0,0 +1,10 @@
+
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/mobilizon.svg b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/mobilizon.svg
new file mode 100644
index 00000000..8b5d57e5
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/img/mobilizon.svg
@@ -0,0 +1 @@
+
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/js/event-bridge-for-activitypub-admin.js b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/js/event-bridge-for-activitypub-admin.js
new file mode 100644
index 00000000..3715707b
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/assets/js/event-bridge-for-activitypub-admin.js
@@ -0,0 +1,34 @@
+jQuery( function( $ ) {
+ // Accordion handling in various areas.
+ $( '.event-bridge-for-activitypub-settings-accordion' ).on( 'click', '.event-bridge-for-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 );
+ }
+ } );
+
+ // Function to toggle visibility of custom details based on selected radio button.
+ function toggleCustomDetailsForSummary() {
+ if ($("#event_bridge_for_activitypub_summary_type_custom").is(':checked')) {
+ $("#event_bridge_for_activitypub_summary_type_custom-details").show();
+ } else {
+ $("#event_bridge_for_activitypub_summary_type_custom-details").hide();
+ }
+ }
+
+ // Run the toggle function on page load.
+ $(document).ready(function() {
+ toggleCustomDetailsForSummary(); // Set the correct state on load.
+
+ // Listen for changes on the radio buttons
+ $("input[name=event_bridge_for_activitypub_summary_type]").change(function() {
+ toggleCustomDetailsForSummary(); // Update visibility on change.
+ });
+ });
+
+} );
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/build/reminder/block.json b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/build/reminder/block.json
new file mode 100644
index 00000000..ad2fc046
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/build/reminder/block.json
@@ -0,0 +1,8 @@
+{
+ "name": "reminder",
+ "title": "Reminder Plugin: not a block, but block.json is very useful.",
+ "category": "widgets",
+ "icon": "admin-comments",
+ "keywords": [],
+ "editorScript": "file:./plugin.js"
+}
\ No newline at end of file
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/build/reminder/plugin.asset.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/build/reminder/plugin.asset.php
new file mode 100644
index 00000000..169666b7
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/build/reminder/plugin.asset.php
@@ -0,0 +1 @@
+ array('react-jsx-runtime', 'wp-components', 'wp-core-data', 'wp-data', 'wp-editor', 'wp-i18n', 'wp-plugins'), 'version' => 'd491284dfb7e5078a777');
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/build/reminder/plugin.js b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/build/reminder/plugin.js
new file mode 100644
index 00000000..cd5cfa27
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/build/reminder/plugin.js
@@ -0,0 +1 @@
+(()=>{"use strict";const e=window.wp.editor,t=window.wp.plugins,i=window.wp.components,n=window.wp.data,a=window.wp.coreData,r=window.wp.i18n,d=window.ReactJSXRuntime,p=activityPubEventBridge.reminderTypeGap;(0,t.registerPlugin)("event-bridge-for-activitypub-reminder",{render:()=>{const t=(0,n.useSelect)((e=>e("core/editor").getCurrentPostType()),[]),[_,b]=(0,a.useEntityProp)("postType",t,"meta"),u=_?.event_bridge_for_activitypub_reminder_time_gap?_?.event_bridge_for_activitypub_reminder_time_gap:p;return(0,d.jsx)(e.PluginDocumentSettingPanel,{name:"activitypub",title:(0,r.__)("Send reminder before event's start","activitypub"),children:(0,d.jsx)(i.SelectControl,{label:(0,r.__)("Time gap","activitypub"),value:u,options:[{label:(0,r.__)("Disabled","event-bridge-for-activitypub"),value:0},{label:(0,r.__)("6 hours","event-bridge-for-activitypub"),value:21600},{label:(0,r.__)("1 day","event-bridge-for-activitypub"),value:86400},{label:(0,r.__)("3 days","event-bridge-for-activitypub"),value:259200},{label:(0,r.__)("1 week","event-bridge-for-activitypub"),value:604800}],onChange:e=>{b({..._,event_bridge_for_activitypub_reminder_time_gap:e})},__nextHasNoMarginBottom:!0})})}})})();
\ No newline at end of file
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/event-bridge-for-activitypub.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/event-bridge-for-activitypub.php
new file mode 100644
index 00000000..179cbd7e
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/event-bridge-for-activitypub.php
@@ -0,0 +1,39 @@
+NGI0 Entrust Fund, a fund established by NLnet.
+ * Plugin URI: https://event-federation.eu/
+ * Version: 1.1.0
+ * Author: André Menrath
+ * Author URI: https://graz.social/@linos
+ * Text Domain: event-bridge-for-activitypub
+ * License: AGPL-3.0-or-later
+ * License URI: https://www.gnu.org/licenses/agpl-3.0.html
+ * Requires PHP: 7.4
+ * Requires Plugins: activitypub
+ *
+ * Requires at least ActivityPub plugin with version >= 5.6.1. ActivityPub plugin tested up to: 5.7.0.
+ *
+ * @package Event_Bridge_For_ActivityPub
+ * @license AGPL-3.0-or-later
+ */
+
+// Exit if accessed directly.
+defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
+
+define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
+define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
+define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_FILE', plugin_dir_path( __FILE__ ) . '/' . basename( __FILE__ ) );
+define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
+define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_VERSION', current( get_file_data( __FILE__, array( 'Version' ), 'plugin' ) ) );
+define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_DOMAIN', 'event-bridge-for-activitypub' );
+define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_ACTIVITYPUB_PLUGIN_MIN_VERSION', '5.6.1' );
+define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_SUMMARY_TEMPLATE', "[ap_start_time]\n[ap_end_time]\n[ap_location]\n\n[ap_content]" );
+define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_DEFAULT_SUMMARY_TYPE', 'preset' );
+
+// Include and register the autoloader class for automatic loading of plugin classes.
+require_once EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . '/includes/class-autoloader.php';
+Event_Bridge_For_ActivityPub\Autoloader::register();
+
+// Initialize the plugin.
+Event_Bridge_For_ActivityPub\Setup::get_instance();
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/class-handler.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/class-handler.php
new file mode 100644
index 00000000..3081c01d
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/class-handler.php
@@ -0,0 +1,35 @@
+ array(
+ 'name' => _x( 'Event Sources', 'post_type plural name', 'event-bridge-for-activitypub' ),
+ 'singular_name' => _x( 'Event Source', 'post_type single name', 'event-bridge-for-activitypub' ),
+ ),
+ 'public' => false,
+ 'hierarchical' => false,
+ 'rewrite' => false,
+ 'query_var' => false,
+ 'delete_with_user' => false,
+ 'can_export' => true,
+ 'supports' => array(),
+ )
+ );
+
+ \register_post_meta(
+ self::POST_TYPE,
+ '_activitypub_actor_id',
+ array(
+ 'type' => 'string',
+ 'single' => true,
+ 'sanitize_callback' => 'sanitize_url',
+ )
+ );
+
+ \register_post_meta(
+ self::POST_TYPE,
+ '_activitypub_errors',
+ array(
+ 'type' => 'string',
+ 'single' => false,
+ 'sanitize_callback' => function ( $value ) {
+ if ( ! is_string( $value ) ) {
+ throw new \Exception( 'Error message is no valid string' );
+ }
+
+ return esc_sql( $value );
+ },
+ )
+ );
+
+ \register_post_meta(
+ self::POST_TYPE,
+ '_activitypub_actor_json',
+ array(
+ 'type' => 'string',
+ 'single' => true,
+ 'sanitize_callback' => function ( $value ) {
+ return sanitize_text_field( $value );
+ },
+ )
+ );
+
+ \register_post_meta(
+ self::POST_TYPE,
+ '_activitypub_inbox',
+ array(
+ 'type' => 'string',
+ 'single' => true,
+ 'sanitize_callback' => 'sanitize_url',
+ )
+ );
+
+ \register_post_meta(
+ self::POST_TYPE,
+ '_event_bridge_for_activitypub_utilize_announces',
+ array(
+ 'type' => 'string',
+ 'single' => true,
+ 'sanitize_callback' => function ( $value ) {
+ if ( 'same_origin' === $value ) {
+ return 'same_origin';
+ }
+ return '';
+ },
+ )
+ );
+
+ \register_post_meta(
+ self::POST_TYPE,
+ '_event_bridge_for_activitypub_accept_of_follow',
+ array(
+ 'type' => 'string',
+ 'single' => true,
+ 'sanitize_callback' => 'sanitize_url',
+ )
+ );
+
+ \register_post_meta(
+ self::POST_TYPE,
+ '_event_bridge_for_activitypub_event_count',
+ array(
+ 'type' => 'integer',
+ 'single' => true,
+ 'sanitize_callback' => 'absint',
+ 'default' => '0',
+ )
+ );
+ }
+
+ /**
+ * Add new Event Source.
+ *
+ * @param string $actor The Actor URL/ID.
+ *
+ * @return Event_Source|WP_Error|null The Followed (WP_Post array) or an WP_Error.
+ */
+ public static function add_event_source( $actor ) {
+ $meta = get_remote_metadata_by_actor( $actor );
+
+ if ( is_tombstone( $meta ) ) {
+ return $meta;
+ }
+
+ if ( \is_wp_error( $meta ) ) {
+ return $meta;
+ }
+
+ if ( empty( $meta ) ) {
+ return null;
+ }
+
+ $event_source = new Event_Source();
+ $event_source->from_array( $meta );
+
+ $post_id = $event_source->save();
+
+ if ( \is_wp_error( $post_id ) ) {
+ return $post_id;
+ }
+
+ self::delete_event_source_transients();
+
+ self::queue_follow_actor( $actor );
+
+ return $event_source;
+ }
+
+ /**
+ * Compose the ActivityPub ID of a follow request.
+ *
+ * @param string $follower_id The ActivityPub ID of the actor that followers the other one.
+ * @param string $followed_id The ActivityPub ID of the followed actor.
+ * @return string The `Follow` ID.
+ */
+ public static function compose_follow_id( $follower_id, $followed_id ) {
+ return $follower_id . '#follow-' . \preg_replace( '~^https?://~', '', $followed_id );
+ }
+
+ /**
+ * Delete all transients related to the event sources.
+ *
+ * @return void
+ */
+ public static function delete_event_source_transients(): void {
+ \delete_transient( 'event_bridge_for_activitypub_event_sources' );
+ \delete_transient( 'event_bridge_for_activitypub_event_sources_hosts' );
+ }
+
+ /**
+ * Check whether an attachment is set as a featured image of any post.
+ *
+ * @param string|int $attachment_id The numeric post ID of the attachment.
+ * @return bool
+ */
+ public static function is_attachment_featured_image( $attachment_id ): bool {
+ if ( ! is_numeric( $attachment_id ) ) {
+ return false;
+ }
+
+ // Query posts with the given attachment ID as their featured image.
+ $args = array(
+ 'post_type' => 'any',
+ 'meta_query' => array(
+ array(
+ 'key' => '_thumbnail_id',
+ 'value' => $attachment_id,
+ 'compare' => '=',
+ ),
+ ),
+ 'fields' => 'ids', // Only retrieve post IDs for performance.
+ 'numberposts' => 1, // We only need one match to confirm.
+ );
+
+ $posts = \get_posts( $args );
+
+ return ! empty( $posts );
+ }
+
+ /**
+ * Delete all posts of an event source.
+ *
+ * @param int $event_source_post_id The WordPress Post ID of the event source.
+ * @return void
+ */
+ public static function delete_events_by_event_source( $event_source_post_id ): void {
+ global $wpdb;
+ $results = $wpdb->get_results(
+ $wpdb->prepare(
+ "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %s",
+ '_event_bridge_for_activitypub_event_source',
+ absint( $event_source_post_id )
+ )
+ );
+
+ // If no matching posts are found, return early.
+ if ( empty( $results ) ) {
+ return;
+ }
+
+ // Loop through the posts and delete them permanently.
+ foreach ( $results as $result ) {
+ // Check if the post has a thumbnail.
+ $thumbnail_id = \get_post_thumbnail_id( $result->post_id );
+
+ if ( $thumbnail_id ) {
+ // Remove the thumbnail from the post.
+ \delete_post_thumbnail( $result->post_id );
+
+ // Delete the attachment (and its files) from the media library.
+ if ( self::is_attachment_featured_image( $thumbnail_id ) ) {
+ \wp_delete_attachment( $thumbnail_id, true );
+ }
+ }
+
+ \wp_delete_post( $result->post_id, true );
+ }
+
+ // Clean up the query.
+ \wp_reset_postdata();
+ }
+
+ /**
+ * Remove an Event Source (=Followed ActivityPub actor).
+ *
+ * @param int|string $event_source_post_id The Events Sources Post ID or ActivityPub ID.
+ *
+ * @return void Post data on success, false or null on failure.
+ */
+ public static function remove_event_source( $event_source_post_id ): void {
+ $event_source = Event_Source::get_by_id( $event_source_post_id );
+
+ if ( ! $event_source ) {
+ return;
+ }
+
+ self::delete_events_by_event_source( $event_source->get__id() );
+
+ self::delete_event_source_transients();
+
+ // Temporary hack.
+ $post = \get_post( $event_source->get__id() );
+ $post->post_status = 'draft';
+
+ if ( $post instanceof \WP_Post ) {
+ $post = \get_object_vars( $post );
+ $post = \wp_slash( $post );
+ $post = \wp_update_post( $post );
+ }
+
+ self::queue_unfollow_actor( $event_source->get_id() );
+ }
+
+ /**
+ * Get all Event-Sources.
+ *
+ * It returns associative arrays, where the keys are the WordPress post IDs and the values are the ActivityPub IDs.
+ * For example:
+ * array(
+ * 15 => 'https://remote.example/actors/event_organizer1',
+ * 19 => 'https://remote2.example/users/johnmastodon',
+ * )
+ *
+ * @return array List of `Event Sources`: =>
+ */
+ public static function get_event_sources(): array {
+ $event_sources = get_transient( 'event_bridge_for_activitypub_event_sources' );
+
+ if ( $event_sources && is_array( $event_sources ) ) {
+ return $event_sources;
+ }
+
+ $event_sources = self::get_event_sources_with_count()['actors'];
+
+ set_transient( 'event_bridge_for_activitypub_event_sources', $event_sources );
+
+ return $event_sources;
+ }
+
+ /**
+ * Get the Event Sources along with a total count for pagination purposes.
+ *
+ * @param int $number Maximum number of results to return.
+ * @param int $page Page number.
+ * @param array $args The WP_Query arguments.
+ *
+ * @return array {
+ * Data about the event sources.
+ *
+ * @type array $actors List of `Event Sources`: =>
+ * @type int $total Total number of followers.
+ * }
+ */
+ public static function get_event_sources_with_count( $number = -1, $page = null, $args = array() ): array {
+ $defaults = array(
+ 'post_type' => self::POST_TYPE,
+ 'posts_per_page' => $number,
+ 'paged' => $page,
+ 'orderby' => 'ID',
+ 'order' => 'DESC',
+ 'post_status' => array( 'publish', 'pending', 'draft', 'auto-draft', 'future', 'private', 'inherit' ),
+ );
+
+ $args = wp_parse_args( $args, $defaults );
+ $query = new WP_Query( $args );
+ $total = $query->found_posts;
+ $actors = array();
+
+ foreach ( $query->get_posts() as $post ) {
+ $actors[ $post->ID ] = get_post_meta( $post->ID, '_activitypub_actor_id', true );
+ }
+
+ $event_sources = compact( 'actors', 'total' );
+
+ return $event_sources;
+ }
+
+ /**
+ * Queue a hook to run async.
+ *
+ * @param string $hook The hook name.
+ * @param array $args The arguments to pass to the hook.
+ * @param string $unqueue_hook Optional a hook to unschedule before queuing.
+ * @return void|bool|WP_Error Whether the hook was queued.
+ */
+ public static function queue( $hook, $args, $unqueue_hook = null ) {
+ if ( $unqueue_hook ) {
+ $hook_timestamp = \wp_next_scheduled( $unqueue_hook, $args );
+ if ( $hook_timestamp ) {
+ \wp_unschedule_event( $hook_timestamp, $unqueue_hook, $args );
+ }
+ }
+
+ if ( \wp_next_scheduled( $hook, $args ) ) {
+ return;
+ }
+
+ return \wp_schedule_single_event( \time(), $hook, $args );
+ }
+
+ /**
+ * Prepare to follow an ActivityPub actor via a scheduled event.
+ *
+ * @param string $actor The ActivityPub actor.
+ *
+ * @return bool Whether the event was queued.
+ */
+ public static function queue_follow_actor( $actor ): bool {
+ $queued = self::queue(
+ 'event_bridge_for_activitypub_follow',
+ array( $actor ),
+ 'event_bridge_for_activitypub_unfollow'
+ );
+
+ if ( \is_wp_error( $queued ) ) {
+ return false;
+ }
+
+ // Following this actor has already been queued.
+ if ( null === $queued ) {
+ return true;
+ }
+
+ return $queued;
+ }
+
+ /**
+ * Follow an ActivityPub actor via the Blog user.
+ *
+ * @param string $actor_id The ID/URL of the Actor.
+ */
+ public static function activitypub_follow_actor( $actor_id ) {
+ $actor = Event_Source::get_by_id( $actor_id );
+
+ if ( ! $actor ) {
+ return $actor;
+ }
+
+ $inbox = $actor->get_shared_inbox();
+ $to = $actor->get_id();
+
+ $from_actor = new Blog();
+
+ $activity = new \Activitypub\Activity\Activity();
+ $activity->set_type( 'Follow' );
+ $activity->set_to( null );
+ $activity->set_cc( null );
+ $activity->set_actor( $from_actor->get_id() );
+ $activity->set_object( $to );
+ $activity->set_id( self::compose_follow_id( $from_actor->get_id(), $to ) );
+ $activity = $activity->to_json();
+ \Activitypub\safe_remote_post( $inbox, $activity, \Activitypub\Collection\Actors::BLOG_USER_ID );
+ }
+
+ /**
+ * Prepare to unfollow an actor via a scheduled event.
+ *
+ * @param string $actor The ActivityPub actor ID.
+ *
+ * @return bool|void|WP_Error Whether the event was queued.
+ */
+ public static function queue_unfollow_actor( $actor ) {
+ $queued = self::queue(
+ 'event_bridge_for_activitypub_unfollow',
+ array( $actor ),
+ 'event_bridge_for_activitypub_follow'
+ );
+
+ if ( \is_wp_error( $queued ) ) {
+ return false;
+ }
+
+ // Following this actor has already been queued.
+ if ( null === $queued ) {
+ return true;
+ }
+
+ return $queued;
+ }
+
+ /**
+ * Unfollow an ActivityPub actor.
+ *
+ * @param string $actor The ActivityPub ID of the actor to unfollow.
+ * @return void
+ */
+ public static function activitypub_unfollow_actor( $actor ): void {
+ $actor = Event_Source::get_by_id( $actor );
+
+ if ( ! $actor ) {
+ return;
+ }
+
+ $inbox = $actor->get_shared_inbox();
+ $to = $actor->get_id();
+
+ $from_actor = new Blog();
+
+ if ( ! $inbox ) {
+ return;
+ }
+
+ $activity = new \Activitypub\Activity\Activity();
+ $activity->set_type( 'Undo' );
+ $activity->set_to( null );
+ $activity->set_cc( null );
+ $activity->set_actor( $from_actor->get_id() );
+ $activity->set_object(
+ array(
+ 'type' => 'Follow',
+ 'actor' => $actor,
+ 'object' => $to,
+ 'id' => self::compose_follow_id( $from_actor->get_id(), $to ),
+ )
+ );
+ $activity->set_id( $from_actor->get_id() . '#unfollow-' . \preg_replace( '~^https?://~', '', $to ) );
+ $activity = $activity->to_json();
+ \Activitypub\safe_remote_post( $inbox, $activity, \Activitypub\Collection\Actors::BLOG_USER_ID );
+
+ $actor->delete();
+
+ self::delete_event_source_transients();
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-accept.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-accept.php
new file mode 100644
index 00000000..ab7b63f1
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-accept.php
@@ -0,0 +1,76 @@
+get_id(), $activity['actor'] );
+
+ // Check if the object of the `Accept` is indeed the `Follow` request we sent to that actor.
+ if ( object_to_uri( $activity['object'] ) !== $follow_id ) {
+ return;
+ }
+
+ // Save the accept status of the follow request to the event source post.
+ \update_post_meta( $event_source_post_id, '_event_bridge_for_activitypub_accept_of_follow', $activity['id'] );
+ \wp_update_post(
+ array(
+ 'ID' => $event_source_post_id,
+ 'post_status' => 'publish',
+ )
+ );
+
+ // Trigger the backfilling of events from this actor.
+ \do_action( 'event_bridge_for_activitypub_backfill_events', $event_source_post_id );
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-create.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-create.php
new file mode 100644
index 00000000..74ff5438
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-create.php
@@ -0,0 +1,76 @@
+get_actor_object()->get_id(), // Gets the WordPress user that "owns" the object by ActivityPub means.
+ $activity['id'],
+ Actor::init_from_array( $actor )
+ );
+ }
+
+ /**
+ * Send "Ignore" response.
+ *
+ * @param string $actor The actors ActivityPub ID which sends the response.
+ * @param string $ignored The ID of the Activity that gets ignored.
+ * @param Actor|mixed $to The target actor.
+ */
+ public static function send_ignore_response( $actor, $ignored, $to ) {
+ // Get actor object that owns the object that was targeted by the ignored activity.
+ $actor = Actors::get_by_resource( $actor );
+
+ if ( \is_wp_error( $to ) || \is_wp_error( $actor ) ) {
+ return;
+ }
+
+ // Get inbox.
+ $inbox = $to->get_inbox();
+
+ if ( ! $inbox ) {
+ return;
+ }
+
+ // Send "Ignore" activity.
+ $activity = new Activity();
+ $activity->set_type( 'Ignore' );
+ $activity->set_object( \esc_url_raw( $ignored ) );
+ $activity->set_actor( $actor->get_id() );
+ $activity->set_to( $to->get_id() );
+ $activity->set_id( $actor->get_id() . '#ignore-' . \preg_replace( '~^https?://~', '', $ignored ) );
+ $activity->set_sensitive( null );
+
+ // @phpstan-ignore-next-line
+ Http::post( $inbox, $activity->to_json(), $actor->get__id() );
+ }
+
+ /**
+ * Get the WordPress Post ID by the ActivityPub ID.
+ *
+ * @param string $activitypub_id The ActivityPub objects ID.
+ * @return int The WordPress post ID.
+ */
+ private static function get_post_id_by_activitypub_id( $activitypub_id ) {
+ // Parse the URL and extract its components.
+ $parsed_url = wp_parse_url( $activitypub_id );
+ $home_url = \trailingslashit( \home_url() );
+
+ // Ensure the base URL matches the home URL.
+ if ( \trailingslashit( "{$parsed_url['scheme']}://{$parsed_url['host']}" ) !== $home_url ) {
+ return 0;
+ }
+
+ // Check for a valid query string and parse it.
+ if ( isset( $parsed_url['query'] ) ) {
+ parse_str( $parsed_url['query'], $query_vars );
+
+ // Ensure the only parameter is 'p'.
+ if ( count( $query_vars ) === 1 && isset( $query_vars['p'] ) ) {
+ return intval( $query_vars['p'] ); // Return the post ID.
+ }
+ }
+
+ // Fallback: legacy ActivityPub plugin (before version 3.0.0) used pretty permalinks as `id`.
+ return \url_to_postid( $activitypub_id );
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-undo.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-undo.php
new file mode 100644
index 00000000..c2ad5aaa
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-undo.php
@@ -0,0 +1,73 @@
+get_results(
+ $wpdb->prepare(
+ "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %s",
+ '_event_bridge_for_activitypub_accept_of_follow',
+ $accept_id
+ )
+ );
+
+ // If no event source with that accept ID is found return.
+ if ( empty( $results ) ) {
+ return;
+ }
+
+ $post_id = reset( $results )->post_id;
+
+ \delete_post_meta( $post_id, '_event_bridge_for_activitypub_accept_of_follow' );
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-update.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-update.php
new file mode 100644
index 00000000..1281a95c
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-update.php
@@ -0,0 +1,76 @@
+get_icon();
+
+ if ( is_string( $icon ) ) {
+ return $icon;
+ }
+
+ if ( isset( $icon['url'] ) && is_string( $icon['url'] ) ) {
+ return $icon['url'];
+ }
+
+ return '';
+ }
+
+ /**
+ * Return the Post-IDs of all events cached by this event source.
+ */
+ public static function get_cached_events(): array {
+ return array();
+ }
+
+ /**
+ * Getter for URL attribute.
+ *
+ * @return string The URL.
+ */
+ public function get_url() {
+ if ( $this->url ) {
+ return $this->url;
+ }
+
+ return $this->id;
+ }
+
+ /**
+ * Get the outbox.
+ *
+ * @return ?string The outbox URL.
+ */
+ public function get_outbox() {
+ if ( $this->outbox ) {
+ return $this->outbox;
+ }
+
+ $actor_json = \get_post_meta( $this->get__id(), '_activitypub_actor_json', true );
+
+ if ( ! $actor_json ) {
+ return null;
+ }
+
+ $actor = \json_decode( $actor_json, true );
+
+ if ( ! isset( $actor['outbox'] ) ) {
+ \do_action( 'event_bridge_for_activitypub_write_log', array( "[ACTIVITYPUB] Did not find outbox URL for actor {$actor}" ) );
+ return null;
+ }
+
+ return $actor['outbox'];
+ }
+
+ /**
+ * Get the Event Source Post ID by the ActivityPub ID.
+ *
+ * @param string $activitypub_actor_id The ActivityPub actor ID.
+ * @return int|false The Event Sources Post ID, if a WordPress Post representing it is found, false otherwise.
+ */
+ public static function get_post_id_by_activitypub_id( $activitypub_actor_id ) {
+ $event_sources = Event_Sources::get_event_sources();
+
+ return array_search( $activitypub_actor_id, $event_sources, true );
+ }
+
+ /**
+ * Get the Event Source by the ActivityPub ID or WordPress Post ID.
+ *
+ * @param int|string $event_source_id The ActivityPub actor ID as string or the Post ID as int of the Event Source.
+ * @return ?Event_Source The Event Sources if it exists, false otherwise.
+ */
+ public static function get_by_id( $event_source_id ): ?Event_Source {
+ $post_id = is_integer( $event_source_id ) ? $event_source_id : self::get_post_id_by_activitypub_id( $event_source_id );
+
+ if ( ! $post_id ) {
+ return null;
+ }
+
+ // Get Custom Post.
+ $event_source_post = \get_post( $post_id );
+
+ if ( ! $event_source_post ) {
+ return null;
+ }
+
+ // Init From Custom Post.
+ $event_source = self::init_from_cpt( $event_source_post );
+
+ if ( ! $event_source ) {
+ return null;
+ }
+
+ return $event_source;
+ }
+
+ /**
+ * Convert a Custom-Post-Type input to an \Event_Bridge_For_ActivityPub\ActivityPub\Model\Event_Source.
+ *
+ * @param \WP_Post $post The post object.
+ * @return ?Event_Source
+ */
+ public static function init_from_cpt( $post ): ?Event_Source {
+ if ( Event_Sources::POST_TYPE !== $post->post_type ) {
+ return null;
+ }
+ $actor_json = \get_post_meta( $post->ID, '_activitypub_actor_json', true );
+ $object = static::init_from_json( $actor_json );
+
+ if ( \is_wp_error( $object ) ) {
+ return null;
+ }
+
+ $object->set__id( $post->ID );
+ $object->set_name( $post->post_title );
+ $object->set_summary( $post->post_excerpt );
+ $object->set_published( gmdate( 'Y-m-d H:i:s', strtotime( $post->post_date ) ) );
+ $object->set_updated( gmdate( 'Y-m-d H:i:s', strtotime( $post->post_modified ) ) );
+ $object->set_status( $post->post_status );
+ $thumbnail_id = \get_post_thumbnail_id( $post );
+ if ( $thumbnail_id ) {
+ $object->set_icon(
+ array(
+ 'type' => 'Image',
+ 'url' => \wp_get_attachment_image_url( $thumbnail_id, 'thumbnail', true ),
+ )
+ );
+ }
+
+ if ( ! $object instanceof Event_Source ) { // To make phpstan happy.
+ return null;
+ }
+
+ return $object;
+ }
+
+ /**
+ * Validate the current Event Source ActivityPub actor object.
+ *
+ * @return boolean True if the verification was successful.
+ */
+ public function is_valid(): bool {
+ // The minimum required attributes.
+ $required_attributes = array(
+ 'id',
+ 'preferredUsername',
+ 'inbox',
+ 'publicKey',
+ 'publicKeyPem',
+ );
+
+ foreach ( $required_attributes as $attribute ) {
+ if ( ! $this->get( $attribute ) ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Update the post meta.
+ */
+ protected function get_post_meta_input() {
+ $meta_input = array();
+ $meta_input['_activitypub_inbox'] = \sanitize_url( $this->get_shared_inbox() );
+ $meta_input['_activitypub_actor_json'] = $this->to_json();
+ $meta_input['_activitypub_actor_id'] = $this->get_id();
+
+ return $meta_input;
+ }
+
+ /**
+ * Get the shared inbox, with a fallback to the inbox.
+ *
+ * @return string|null The URL to the shared inbox, the inbox or null.
+ */
+ public function get_shared_inbox() {
+ if ( ! empty( $this->get_endpoints()['sharedInbox'] ) ) {
+ return $this->get_endpoints()['sharedInbox'];
+ } elseif ( ! empty( $this->get_inbox() ) ) {
+ return $this->get_inbox();
+ }
+
+ return null;
+ }
+
+ /**
+ * Save the current Event Source object to Database within custom post type.
+ *
+ * @return int|WP_Error The post ID or an WP_Error.
+ */
+ public function save() {
+ Event_Sources::delete_event_source_transients();
+
+ if ( ! $this->is_valid() ) {
+ return new WP_Error( 'activitypub_invalid_follower', __( 'Invalid Follower', 'event-bridge-for-activitypub' ), array( 'status' => 400 ) );
+ }
+
+ if ( ! $this->get__id() ) {
+ global $wpdb;
+
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery
+ $post_id = $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_activitypub_actor_id' AND meta_value=%s",
+ esc_sql( $this->get_id() )
+ )
+ );
+
+ if ( $post_id ) {
+ $post = get_post( $post_id );
+ $this->set__id( $post->ID );
+ }
+ }
+
+ $post_id = $this->get__id();
+
+ $args = array(
+ 'ID' => $post_id,
+ 'post_title' => wp_strip_all_tags( sanitize_text_field( $this->get_name() ) ),
+ 'post_author' => 0,
+ 'post_type' => Event_Sources::POST_TYPE,
+ 'post_name' => esc_url_raw( $this->get_id() ),
+ 'post_excerpt' => sanitize_text_field( wp_kses( $this->get_summary(), 'user_description' ) ),
+ 'post_status' => 'pending',
+ 'meta_input' => $this->get_post_meta_input(),
+ );
+
+ if ( ! empty( $post_id ) ) {
+ // If this is an update, prevent the "added" date from being overwritten by the current date.
+ $post = get_post( $post_id );
+ $args['post_date'] = $post->post_date;
+ $args['post_date_gmt'] = $post->post_date_gmt;
+ }
+
+ $post_id = \wp_insert_post( $args );
+ $this->_id = $post_id;
+
+ // Abort if inserting or updating the post didn't work.
+
+ // @phpstan-ignore-next-line
+ if ( is_wp_error( $post_id ) || 0 === $post_id ) {
+ return $post_id;
+ }
+
+ // Delete old icon.
+ // Check if the post has a thumbnail.
+ $thumbnail_id = get_post_thumbnail_id( $post_id );
+
+ if ( $thumbnail_id ) {
+ // Remove the thumbnail from the post.
+ delete_post_thumbnail( $post_id );
+
+ // Delete the attachment (and its files) from the media library.
+ wp_delete_attachment( $thumbnail_id, true );
+ }
+
+ // Set new icon.
+ $icon = $this->get_icon();
+
+ if ( isset( $icon['url'] ) ) {
+ $image = media_sideload_image( sanitize_url( $icon['url'] ), $post_id, null, 'id' );
+ }
+ if ( isset( $image ) && ! is_wp_error( $image ) ) {
+ set_post_thumbnail( $post_id, $image );
+ }
+
+ return $post_id;
+ }
+
+ /**
+ * Delete an Event Source and it's profile image.
+ */
+ public function delete() {
+ $post_id = $this->get__id();
+
+ if ( ! $post_id ) {
+ return false;
+ }
+
+ $thumbnail_id = get_post_thumbnail_id( $post_id );
+
+ if ( $thumbnail_id ) {
+ wp_delete_attachment( $thumbnail_id, true );
+ }
+
+ $result = wp_delete_post( $post_id, false ) ?? false;
+
+ if ( $result ) {
+ Event_Sources::delete_event_source_transients();
+ }
+
+ return $result;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/scheduler/class-event.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/scheduler/class-event.php
new file mode 100644
index 00000000..668abc39
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/scheduler/class-event.php
@@ -0,0 +1,107 @@
+is_event_post_type_of_active_event_plugin( $post->post_type ) ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * 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 maybe_schedule_event_post_activity( $new_status, $old_status, $post ): void {
+ if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
+ return;
+ }
+
+ if ( ! Setup::get_instance()->is_event_post_type_of_active_event_plugin( $post->post_type ) ) {
+ return;
+ }
+
+ if ( Setup::is_post_disabled( $post ) ) {
+ return;
+ }
+
+ switch ( $new_status ) {
+ case 'publish':
+ $type = ( 'publish' === $old_status ) ? 'Update' : 'Create';
+ break;
+
+ case 'draft':
+ $type = ( 'publish' === $old_status ) ? 'Update' : false;
+ break;
+
+ case 'trash':
+ $type = 'Delete';
+ break;
+
+ default:
+ $type = false;
+ }
+
+ // Do not send Activities if `$type` is not set or unknown.
+ if ( empty( $type ) ) {
+ return;
+ }
+
+ $hook = 'event_bridge_for_activitypub_add_event_post_to_outbox';
+ $args = array( $post, $type, $post->post_author );
+
+ if ( false === \wp_next_scheduled( $hook, $args ) ) {
+ \wp_schedule_single_event( \time() + 10, $hook, $args );
+ }
+ }
+
+ /**
+ * Add an event post to the outbox.
+ *
+ * @param \WP_Post $post The WP_Post object to add to the outbox.
+ * @param string $activity_type The type of the Activity.
+ * @param integer $user_id The User-ID.
+ */
+ public static function add_event_post_to_outbox( $post, $activity_type, $user_id ): void {
+ $post = get_post( $post->ID );
+ add_to_outbox( $post, $activity_type, $user_id );
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-event-organiser.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-event-organiser.php
new file mode 100644
index 00000000..4407c54f
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-event-organiser.php
@@ -0,0 +1,78 @@
+schedule = \eo_get_event_schedule( $item->ID );
+ }
+
+ /**
+ * Get the end time from the event object.
+ */
+ public function get_end_time(): string {
+ return $this->schedule['end']->format( 'Y-m-d\TH:i:sP' );
+ }
+
+ /**
+ * Get the start time from the event object.
+ */
+ public function get_start_time(): string {
+ return $this->schedule['start']->format( 'Y-m-d\TH:i:sP' );
+ }
+
+ /**
+ * Get location from the event object.
+ */
+ public function get_location(): ?Place {
+ $venue = \get_the_terms( $this->item->ID, 'event-venue' );
+
+ if ( empty( $venue ) || is_wp_error( $venue ) ) {
+ return null;
+ }
+
+ $venue = array_pop( $venue );
+
+ $location_transformer = new Event_Organiser_Location_Transformer( $venue );
+ $location = $location_transformer->to_object();
+
+ return $location;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-event.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-event.php
new file mode 100644
index 00000000..09468e20
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-event.php
@@ -0,0 +1,609 @@
+item );
+ }
+
+ /**
+ * Set a hardcoded template for the content.
+ *
+ * This actually disabled templates for the content.
+ * Maybe this independent templates for events will be added later.
+ */
+ protected function get_post_content_template(): string {
+ return '[ap_content]';
+ }
+
+ /**
+ * Extend the construction of the Post Transformer to also set the according taxonomy of the event post type.
+ *
+ * @param \WP_Post $item The WordPress post object (event).
+ * @param string $wp_taxonomy The taxonomy slug of the event post type.
+ */
+ public function __construct( $item, $wp_taxonomy = 'category' ) {
+ parent::__construct( $item );
+ $this->wp_taxonomy = $wp_taxonomy;
+ }
+
+ /**
+ * Extract the join mode.
+ *
+ * Currently we don't handle joins, we always mark events as external.
+ *
+ * @return string
+ */
+ public function get_join_mode(): ?string {
+ return 'external';
+ }
+
+ /**
+ * Extract the external participation url.
+ *
+ * Currently we don't handle joins, we always mark events as external.
+ * We just link back to the events HTML representation on our WordPress site.
+ *
+ * @return ?string The external participation URL.
+ */
+ public function get_external_participation_url(): ?string {
+ return 'external' === $this->get_join_mode() ? $this->get_url() : null;
+ }
+
+ /**
+ * Set the event category, via the mapping setting.
+ *
+ * @return ?string
+ */
+ public function get_category(): ?string {
+ if ( is_null( $this->wp_taxonomy ) ) {
+ return null;
+ }
+ $current_category_mapping = \get_option( 'event_bridge_for_activitypub_event_category_mappings', array() );
+ $terms = \get_the_terms( $this->item, $this->wp_taxonomy );
+
+ // Check if the event has a category set and if that category has a specific mapping return that one.
+ if ( ! is_wp_error( $terms ) && $terms && array_key_exists( $terms[0]->slug, $current_category_mapping ) ) {
+ return sanitize_text_field( $current_category_mapping[ $terms[0]->slug ] );
+ } else {
+ // Return the default event category.
+ return sanitize_text_field( \get_option( 'event_bridge_for_activitypub_default_event_category', 'MEETING' ) );
+ }
+ }
+
+ /**
+ * Retrieves the excerpt text (may be HTML). Used for constructing the summary.
+ *
+ * @return ?string
+ */
+ protected function retrieve_excerpt(): ?string {
+ if ( $this->item->post_excerpt ) {
+ return $this->item->post_excerpt;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the start time.
+ *
+ * This is mandatory and must be implemented in the final event transformer class.
+ */
+ abstract public function get_start_time(): string;
+
+ /**
+ * Get the end time.
+ *
+ * This is not mandatory and therefore just return null by default.
+ */
+ public function get_end_time(): ?string {
+ return null;
+ }
+
+ /**
+ * Get a default for the location.
+ *
+ * This should be overridden in the actual event transformer.
+ *
+ * @return array|Place|null
+ */
+ public function get_location() {
+ return null;
+ }
+
+ /**
+ * Default value for the event status.
+ */
+ public function get_status(): ?string {
+ return 'CONFIRMED';
+ }
+
+ /**
+ * Compose a human readable formatted start time.
+ */
+ protected function format_start_time(): string {
+ return $this->format_time( $this->get_start_time() );
+ }
+
+ /**
+ * Compose a human readable formatted end time.
+ */
+ protected function format_end_time(): string {
+ return $this->format_time( $this->get_end_time() );
+ }
+
+ /**
+ * Compose a human readable formatted time.
+ *
+ * @param ?string $time The time which needs to be formatted.
+ */
+ protected static function format_time( $time ) {
+ if ( is_null( $time ) ) {
+ return '';
+ }
+ $start_datetime = new DateTime( $time );
+ $start_timestamp = $start_datetime->getTimestamp();
+ $datetime_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
+ return \wp_date( $datetime_format, $start_timestamp );
+ }
+
+ /**
+ * Generates output for the 'ap_start_time' shortcode.
+ *
+ * @param ?array $atts The shortcode's attributes.
+ * @return string The formatted start date and time of the event.
+ */
+ public function shortcode_start_time( $atts ) {
+ $start_timestamp = $this->get_start_time();
+ return $this->generate_time_output( $start_timestamp, $atts, '🗓️', __( 'Start', 'event-bridge-for-activitypub' ) );
+ }
+
+ /**
+ * Generates output for the 'ap_end_time' shortcode.
+ *
+ * @param ?array $atts The shortcode's attributes.
+ * @return string The formatted end date and time of the event.
+ */
+ public function shortcode_end_time( $atts ) {
+ $end_timestamp = $this->get_end_time();
+ return $this->generate_time_output( $end_timestamp, $atts, '⏳', __( 'End', 'event-bridge-for-activitypub' ) );
+ }
+
+ /**
+ * Generates the formatted time output for a shortcode.
+ *
+ * @param string|null $timestamp The timestamp for the event time.
+ * @param array $atts The shortcode attributes.
+ * @param string $icon The icon to display.
+ * @param string $label The label to display (e.g., 'Start', 'End').
+ * @return string The formatted date and time, or an empty string if the timestamp is invalid.
+ */
+ private function generate_time_output( $timestamp, $atts, $icon, $label ): string {
+ if ( ! $timestamp ) {
+ return '';
+ }
+
+ $args = shortcode_atts(
+ array(
+ 'icon' => 'true',
+ 'label' => 'true',
+ ),
+ $atts
+ );
+
+ $args['icon'] = filter_var( $args['icon'], FILTER_VALIDATE_BOOLEAN );
+ $args['label'] = filter_var( $args['label'], FILTER_VALIDATE_BOOLEAN );
+
+ $output = array();
+
+ if ( $args['icon'] ) {
+ $output[] = $icon;
+ }
+
+ if ( $args['label'] ) {
+ $output[] = $label . ':';
+ }
+
+ $output[] = self::format_time( $timestamp );
+
+ return implode( ' ', $output );
+ }
+
+ /**
+ * Generates output for the 'ap_location' shortcode.
+ *
+ * @param ?array $atts The shortcode's attributes.
+ * @return string The formatted location/address of the event.
+ */
+ public function shortcode_location( $atts ) {
+ $args = shortcode_atts(
+ array(
+ 'icon' => 'true',
+ 'label' => 'true',
+ 'country' => 'true',
+ 'zip' => 'true',
+ 'city' => 'true',
+ 'street' => 'true',
+ ),
+ $atts,
+ 'ap_location'
+ );
+
+ // Convert attributes to booleans.
+ $args = array_map(
+ function ( $value ) {
+ return filter_var( $value, FILTER_VALIDATE_BOOLEAN );
+ },
+ $args
+ );
+
+ $location = $this->get_location();
+ if ( ! $location ) {
+ return '';
+ }
+
+ $output = array();
+
+ if ( is_array( $location ) && isset( $location['type'] ) && 'VirtualLocation' === $location['type'] ) {
+ if ( $args['icon'] ) {
+ $output[] = '🔗';
+ }
+ if ( $args['label'] && isset( $location['name'] ) ) {
+ $output[] = $location['name'] . ':';
+ }
+ } else {
+ if ( $args['icon'] ) {
+ $output[] = '📍';
+ }
+
+ if ( $args['label'] ) {
+ $output[] = esc_html__( 'Location', 'event-bridge-for-activitypub' ) . ':';
+ }
+ }
+
+ $output[] = $this->get_formatted_address( true, $args );
+
+ // Join output array into a single string with spaces and return.
+ return implode( ' ', array_filter( $output ) );
+ }
+
+ /**
+ * Formats the address based on provided arguments.
+ *
+ * @param mixed $address The address data, either as a string or an array.
+ * @param array $args The arguments for which components to include.
+ * @return string The formatted address.
+ */
+ protected static function format_address( $address, $args = array() ) {
+ if ( is_string( $address ) ) {
+ return esc_html( $address );
+ }
+
+ if ( empty( $args ) ) {
+ $args = array(
+ 'icon' => 'true',
+ 'title' => 'true',
+ 'country' => 'true',
+ 'zip' => 'true',
+ 'city' => 'true',
+ 'street' => 'true',
+ );
+ }
+
+ if ( is_array( $address ) ) {
+ $address_parts = array();
+
+ $components = array(
+ 'street' => 'streetAddress',
+ 'zip' => 'postalCode',
+ 'city' => 'addressLocality',
+ 'country' => 'addressCountry',
+ );
+
+ foreach ( $components as $arg_key => $address_key ) {
+ if ( $args[ $arg_key ] && ! empty( $address[ $address_key ] ) ) {
+ $address_parts[] = esc_html( $address[ $address_key ] );
+ }
+ }
+
+ return implode( ', ', $address_parts );
+ }
+
+ return '';
+ }
+
+ /**
+ * Format the category using the translation.
+ */
+ protected function format_categories(): string {
+ if ( is_null( $this->wp_taxonomy ) ) {
+ return '';
+ }
+ $categories = array();
+
+ // Add the federated category string.
+ require_once EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . '/includes/event-categories.php';
+ $federated_category = $this->get_category();
+ if ( array_key_exists( $federated_category, EVENT_BRIDGE_FOR_ACTIVITYPUB_EVENT_CATEGORIES ) ) {
+ $categories[] = EVENT_BRIDGE_FOR_ACTIVITYPUB_EVENT_CATEGORIES[ $federated_category ];
+ }
+
+ // Add all category terms.
+ $terms = \get_the_terms( $this->item, $this->wp_taxonomy );
+ if ( $terms && ! is_wp_error( $terms ) ) {
+ foreach ( $terms as $term ) {
+ $categories[] = $term->name;
+ }
+ }
+
+ if ( ! empty( $categories ) ) {
+ return implode( ' · ', array_unique( $categories ) );
+ }
+ return '';
+ }
+
+ /**
+ * Register the shortcodes.
+ */
+ public function register_shortcodes() {
+ Shortcodes::register();
+ foreach ( array( 'location', 'start_time', 'end_time' ) as $shortcode ) {
+ \add_shortcode( 'ap_' . $shortcode, array( $this, 'shortcode_' . $shortcode ) );
+ }
+ }
+
+ /**
+ * Register the shortcodes.
+ */
+ public function unregister_shortcodes() {
+ Shortcodes::unregister();
+ foreach ( array( 'location', 'start_time', 'end_time' ) as $shortcode ) {
+ \remove_shortcode( 'ap_' . $shortcode );
+ }
+ }
+
+ /**
+ * Get the summary.
+ */
+ public function get_summary(): ?string {
+ if ( 'preset' === get_option( 'event_bridge_for_activitypub_summary_type', 'preset' ) ) {
+ $summary = EVENT_BRIDGE_FOR_ACTIVITYPUB_SUMMARY_TEMPLATE;
+ } else {
+ $summary = $this->get_event_summary_template();
+ }
+
+ // It seems that shortcodes are only applied to published posts.
+ if ( is_preview() ) {
+ $this->item->post_status = 'publish';
+ }
+
+ // Register our shortcodes just in time.
+
+ $this->register_shortcodes();
+
+ // Fill in the shortcodes.
+ \setup_postdata( $this->item );
+ Shortcodes::register();
+ $summary = \do_shortcode( $summary );
+ \wp_reset_postdata();
+
+ $summary = \wpautop( $summary );
+ $summary = \preg_replace( '/[\n\r\t]/', '', $summary );
+ $summary = \trim( $summary );
+
+ $summary = \apply_filters( 'event_bridge_for_activitypub_the_summary', $summary, $this->item );
+
+ // Unregister the shortcodes.
+ $this->unregister_shortcodes();
+
+ if ( 'plain' === get_option( 'event_bridge_for_activitypub_summary_format', 'html' ) ) {
+ $summary = self::strip_html_preserve_linebreaks( $summary );
+ }
+
+ return $summary;
+ }
+
+ /**
+ * Strip all HTML but preverse some line breaks.
+ *
+ * @param mixed $content The HTML input.
+ * @return string
+ */
+ private static function strip_html_preserve_linebreaks( $content ): string {
+ // Replace
with newlines.
+ $content = preg_replace( '/
/i', "\n", $content );
+
+ // Replace closing followed by with double newlines (preserve paragraph breaks).
+ $content = preg_replace( '/<\/p>\s*
/', "\n\n", $content );
+
+ // Preserve list structure.
+ $content = preg_replace( '/<\/ul>/i', "\n", $content );
+ $content = preg_replace( '/
/i', '- ', $content );
+ $content = preg_replace( '/<\/li>/i', "\n", $content );
+
+ // Remove all remaining HTML tags.
+ $content = wp_strip_all_tags( $content );
+
+ // Normalize excessive newlines (more than 2 in a row to just 2).
+ $content = preg_replace( "/\n{3,}/", "\n\n", $content );
+
+ // Trim trailing newlines.
+ return trim( $content );
+ }
+
+ /**
+ * Get the address as a string.
+ *
+ * @param bool $include_location_name Whether to include the locations name.
+ * @param array $args The arguments forwarded to format_address.
+ *
+ * @return string
+ */
+ public function get_formatted_address( $include_location_name = false, $args = array() ) {
+ $location = $this->get_location();
+
+ if ( $location instanceof Place ) {
+ $location_name = $location->get_name();
+ $foramted_address = self::format_address( $location->get_address(), $args );
+
+ $loaction_parts = array();
+
+ if ( $location_name ) {
+ $location_parts[] = $location_name;
+ }
+
+ if ( $foramted_address ) {
+ $location_parts[] = $foramted_address;
+ }
+
+ if ( ! empty( $location_parts ) ) {
+ return implode( ', ', $location_parts );
+ }
+ } elseif ( is_array( $location ) && isset( $location['type'] ) && 'VirtualLocation' === $location['type'] ) {
+ if ( isset( $location['url'] ) ) {
+ return $location['url'];
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * Gets the template to use to generate the summary of the ActivityStreams representation of an event post.
+ *
+ * @return string The Template.
+ */
+ protected function get_event_summary_template() {
+ $summary = \get_option( 'event_bridge_for_activitypub_custom_summary', EVENT_BRIDGE_FOR_ACTIVITYPUB_SUMMARY_TEMPLATE );
+ $template = $summary ?? EVENT_BRIDGE_FOR_ACTIVITYPUB_SUMMARY_TEMPLATE;
+
+ return apply_filters( 'event_bridge_for_activitypub_summary_template', $template, $this->item );
+ }
+
+ /**
+ * By default set the timezone of the WordPress site.
+ *
+ * This is likely to be overwritten by the actual transformer.
+ *
+ * @return string The timezone string of the site.
+ */
+ public function get_timezone(): string {
+ return \wp_timezone_string();
+ }
+
+ /**
+ * Remove the permalink shortcode from a WordPress template.
+ *
+ * This used for the summary template, because the summary usually gets,
+ * used when converting a object, where the URL is usually appended anyway.
+ *
+ * @param string $template The template string.
+ * @param WP_Post|WP_Comment $item The item which was used to select the template.
+ */
+ public static function remove_ap_permalink_from_template( $template, $item ) {
+
+ // we could override the template here, to get out custom template from an option.
+
+ if ( 'event' === $item->post_type ) {
+ $template = str_replace( '[ap_permalink]', '', $template );
+ $template = str_replace( '[ap_permalink type="html"]', '', $template );
+ }
+
+ return $template;
+ }
+
+ /**
+ * Generic function that converts an WP-Event object to an ActivityPub-Event object.
+ *
+ * @return Event_object|\WP_Error
+ */
+ public function to_object() {
+ $activitypub_object = new Event_Object();
+ $activitypub_object = $this->transform_object_properties( $activitypub_object );
+
+ // @phpstan-ignore-next-line
+ $activitypub_object->set_comments_enabled( $this->get_comments_enabled() );
+
+ if ( \is_wp_error( $activitypub_object ) ) {
+ return $activitypub_object;
+ }
+
+ // maybe move the following logic (till end of the function) into getter functions.
+
+ $published = \strtotime( $this->item->post_date_gmt );
+
+ $activitypub_object->set_published( \gmdate( 'Y-m-d\TH:i:s\Z', $published ) );
+
+ $updated = \strtotime( $this->item->post_modified_gmt );
+
+ if ( $updated > $published ) {
+ $activitypub_object->set_updated( \gmdate( 'Y-m-d\TH:i:s\Z', $updated ) );
+ }
+
+ $activitypub_object->set_content_map(
+ array(
+ $this->get_locale() => $this->get_content(),
+ )
+ );
+
+ $activitypub_object->set_to(
+ array(
+ 'https://www.w3.org/ns/activitystreams#Public',
+ $this->get_actor_object()->get_followers(),
+ )
+ );
+
+ // @phpstan-ignore-next-line
+ return $activitypub_object;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventin.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventin.php
new file mode 100644
index 00000000..fd518845
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventin.php
@@ -0,0 +1,166 @@
+event_model = new Event_Model( $this->item->ID );
+ }
+
+ /**
+ * Get the end time from the event object.
+ */
+ public function get_start_time(): string {
+ return \gmdate( 'Y-m-d\TH:i:s\Z', strtotime( $this->event_model->get_start_datetime() ) );
+ }
+
+ /**
+ * Get the end time from the event object.
+ */
+ public function get_end_time(): string {
+ return \gmdate( 'Y-m-d\TH:i:s\Z', strtotime( $this->event_model->get_end_datetime() ) );
+ }
+
+ /**
+ * Get the timezone of the event.
+ */
+ public function get_timezone(): string {
+ return $this->event_model->get_timezone();
+ }
+
+ /**
+ * Get whether the event is online.
+ *
+ * @return bool
+ */
+ public function get_is_online(): bool {
+ return 'online' === $this->event_model->__get( 'event_type' ) ? true : false;
+ }
+
+ /**
+ * Maybe add online link to attachments.
+ *
+ * @return array
+ */
+ public function get_attachment(): array {
+ $attachment = parent::get_attachment();
+
+ $location = (array) $this->event_model->__get( 'location' );
+
+ // @phpstan-ignore-next-line
+ if ( array_key_exists( 'integration', $location ) && array_key_exists( $location['integration'], $location ) ) {
+ $online_link = array(
+ 'type' => 'Link',
+ 'mediaType' => 'text/html',
+ 'name' => $location[ $location['integration'] ],
+ 'href' => $location[ $location['integration'] ],
+ );
+ $attachment[] = $online_link;
+ }
+ return $attachment;
+ }
+
+ /**
+ * Compose the events tags.
+ */
+ public function get_tag(): ?array {
+ // The parent tag function also fetches the mentions.
+ $tags = parent::get_tag();
+
+ $post_tags = \wp_get_post_terms( $this->item->ID, 'etn_tags' );
+ $post_categories = \wp_get_post_terms( $this->item->ID, 'etn_category' );
+
+ if ( ! is_wp_error( $post_tags ) && $post_tags ) {
+ foreach ( $post_tags as $term ) {
+ $tag = array(
+ 'type' => 'Hashtag',
+ 'href' => \esc_url( \get_tag_link( $term->term_id ) ),
+ 'name' => esc_hashtag( $term->name ),
+ );
+ $tags[] = $tag;
+ }
+ }
+
+ if ( ! is_wp_error( $post_categories ) && $post_categories ) {
+ foreach ( $post_categories as $term ) {
+ $tag = array(
+ 'type' => 'Hashtag',
+ 'href' => \esc_url( \get_tag_link( $term->term_id ) ),
+ 'name' => esc_hashtag( $term->name ),
+ );
+ $tags[] = $tag;
+ }
+ }
+
+ if ( empty( $tags ) ) {
+ return null;
+ }
+
+ return $tags;
+ }
+
+ /**
+ * Get the location.
+ *
+ * @return ?Place
+ */
+ public function get_location(): ?Place {
+ $location = (array) $this->event_model->__get( 'location' );
+
+ // @phpstan-ignore-next-line
+ if ( ! array_key_exists( 'address', $location ) ) {
+ return null;
+ }
+
+ // @phpstan-ignore-next-line
+ $place = new Place();
+
+ $address = $location['address'];
+
+ $place->set_name( $address );
+ $place->set_address( $address );
+ $place->set_sensitive( null );
+
+ return $place;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventon.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventon.php
new file mode 100644
index 00000000..c005e1aa
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventon.php
@@ -0,0 +1,186 @@
+wp_taxonomy = $wp_taxonomy;
+
+ $this->tax_meta = \get_option( 'evo_tax_meta' );
+ }
+
+
+ /**
+ * Get content.
+ */
+ public function get_content(): string {
+ $subtitle = \get_post_meta( $this->item->ID, 'evcal_subtitle', true );
+
+ $content = $subtitle ? $subtitle . '
' : '';
+ $content = $content . parent::get_content();
+ return $content;
+ }
+
+ /**
+ * Get the event location(s).
+ *
+ * @return array|null The Place.
+ */
+ public function get_location() {
+ $location = array();
+
+ $terms = \get_the_terms( $this->item->ID, 'event_location' );
+
+ // The terms may both contain virtual and physical Locations.
+ if ( ! empty( $terms ) ) {
+ foreach ( $terms as $term ) {
+ $location_transformer = new EventOn_Place_Transformer( $term );
+ $location[] = $location_transformer->to_object()->to_array( false );
+ }
+ }
+
+ // Virtual Locations can also be directly int the post meta, not in terms!
+ $virtual_url = \get_post_meta( $this->item->ID, '_vir_url', true );
+ $virtual_type = \get_post_meta( $this->item->ID, '_vir_type', true );
+
+ if ( $virtual_url ) {
+ $virtual_location = array(
+ 'type' => 'VirtualLocation',
+ 'url' => (string) $virtual_url,
+ );
+ if ( $virtual_type ) {
+ $virtual_location['name'] = (string) $virtual_type;
+ }
+ $location[] = $virtual_location;
+ }
+
+ // If we only have one location, send object directy, not in array.
+ if ( 1 === count( $location ) ) {
+ $location = reset( $location );
+ } elseif ( empty( $location ) ) {
+ return null;
+ }
+
+ return $location;
+ }
+
+ /**
+ * Get the end time from the events metadata.
+ */
+ public function get_end_time(): ?string {
+ $end_time = \get_post_meta( $this->item->ID, '_unix_end_ev', true );
+ $timezone = \get_post_meta( $this->item->ID, '_evo_tz', true );
+ $timezone = $timezone ? new \DateTimeZone( $timezone ) : null;
+
+ if ( is_null( $end_time ) || empty( $end_time ) ) {
+ return null;
+ }
+ return \wp_date( 'Y-m-d\TH:i:sP', (int) $end_time, $timezone );
+ }
+
+ /**
+ * Get timezone
+ *
+ * @return string
+ */
+ public function get_timezone(): string {
+ $timezone = \get_post_meta( $this->item->ID, '_evo_tz', true );
+
+ return $timezone ?? \wp_timezone_string();
+ }
+
+ /**
+ * Get the end time from the events metadata.
+ */
+ public function get_start_time(): string {
+ $start_time = \get_post_meta( $this->item->ID, '_unix_start_ev', true );
+ $timezone = \get_post_meta( $this->item->ID, '_evo_tz', true );
+ $timezone = $timezone ? new \DateTimeZone( $timezone ) : null;
+
+ return \wp_date( 'Y-m-d\TH:i:sP', (int) $start_time, $timezone );
+ }
+
+ /**
+ * Get the event link from the events metadata.
+ *
+ * @return ?array Associated array of an ActivityStreams Link object with the events URL.
+ */
+ private function get_event_link(): ?array {
+ $event_link = \get_post_meta( $this->item->ID, 'event-link', true );
+ $event_link_label = \get_post_meta( $this->item->ID, 'event-link-label', true ) ?? 'Event Link';
+ if ( $event_link ) {
+ return array(
+ 'type' => 'Link',
+ 'name' => $event_link_label,
+ 'href' => \esc_url( $event_link ),
+ 'mediaType' => 'text/html',
+ );
+ }
+ return null;
+ }
+
+ /**
+ * Overrides/extends the get_attachments function to also add the event Link.
+ *
+ * @return array
+ */
+ protected function get_attachment(): array {
+ $attachments = parent::get_attachment();
+ if ( count( $attachments ) ) {
+ $attachments[0]['type'] = 'Document';
+ $attachments[0]['name'] = 'Banner';
+ }
+ $event_link = $this->get_event_link();
+ if ( $event_link ) {
+ $attachments[] = $event_link;
+ }
+ return $attachments;
+ }
+
+ /**
+ * Retrieves the excerpt text (may be HTML). Used for constructing the summary.
+ *
+ * @return ?string
+ */
+ protected function retrieve_excerpt(): ?string {
+ if ( \get_post_meta( $this->item->ID, 'event-summary', true ) ) {
+ return \get_post_meta( $this->item->ID, 'event-summary', true );
+ } else {
+ return parent::retrieve_excerpt();
+ }
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventprime.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventprime.php
new file mode 100644
index 00000000..b3008f69
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventprime.php
@@ -0,0 +1,70 @@
+wp_object->ID, 'em_end_date', true );
+ if ( $timestamp ) {
+ return \gmdate( 'Y-m-d\TH:i:s\Z', $timestamp );
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the end time from the event object.
+ */
+ public function get_start_time(): string {
+ $timestamp = \get_post_meta( $this->wp_object->ID, 'em_start_date', true );
+ if ( $timestamp ) {
+ return \gmdate( 'Y-m-d\TH:i:s\Z', $timestamp );
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * Get location from the event object.
+ */
+ public function get_location(): ?Place {
+ $venue_term_id = \get_post_meta( $this->item->ID, 'em_venue', true );
+ if ( ! $venue_term_id ) {
+ return null;
+ }
+
+ $venue = \get_the_terms( $this->item->ID, 'em_venue' );
+
+ if ( empty( $venue ) || is_wp_error( $venue ) ) {
+ return null;
+ }
+
+ $venue = array_pop( $venue );
+
+ $location_transformer = new EventPrime_Location_Transformer( $venue );
+ $location = $location_transformer->to_object();
+
+ return $location;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-events-manager.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-events-manager.php
new file mode 100644
index 00000000..f61f50a6
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-events-manager.php
@@ -0,0 +1,248 @@
+em_event = new EM_Event( $this->item->ID, 'post_id' );
+ }
+
+ /**
+ * Returns whether the even is online
+ *
+ * @return bool
+ */
+ protected function is_online(): bool {
+ return \EM_Event_Locations\Event_Locations::is_enabled( 'url' ) && 'url' === $this->em_event->event_location_type;
+ }
+
+ /**
+ * Get the event location.
+ *
+ * @return array|Place|null The Place.
+ */
+ public function get_location() {
+ if ( $this->is_online() ) {
+ if ( property_exists( $this->em_event->event_location, 'data' ) ) {
+ $event_location = $this->em_event->event_location->data;
+ } else {
+ $event_location = array();
+ }
+
+ $event_link_url = isset( $event_location['url'] ) ? $event_location['url'] : null;
+ $event_link_text = isset( $event_location['text'] ) ? $event_location['text'] : esc_html__( 'Link', 'event-bridge-for-activitypub' );
+
+ if ( empty( $event_link_url ) ) {
+ return null;
+ }
+
+ return array(
+ 'type' => 'VirtualLocation',
+ 'url' => \esc_url( $event_link_url ),
+ 'name' => \esc_html( $event_link_text ),
+ );
+ }
+
+ if ( ! \EM_Locations::is_enabled() ) {
+ return null;
+ }
+
+ $em_location = $this->em_event->get_location();
+
+ if ( ! isset( $em_location->post_id ) || ! $em_location->post_id ) {
+ return null;
+ }
+
+ $location_transformer = new Events_Manager_Place_Transformer( get_post( $em_location->post_id ) );
+ $full_location_object = false;
+ $location = $location_transformer->to_object( $full_location_object );
+ return $location;
+ }
+
+ /**
+ * Get the end time from the events metadata.
+ */
+ public function get_end_time(): ?string {
+ return null;
+ }
+
+ /**
+ * Get the end time from the events metadata.
+ */
+ public function get_start_time(): string {
+ $date_string = $this->em_event->event_start_date;
+ $time_string = $this->em_event->event_start_time;
+ $timezone_string = $this->em_event->event_timezone;
+
+ // Create a DateTime object with the given date, time, and timezone.
+ $datetime = new DateTime( $date_string . ' ' . $time_string, new DateTimeZone( $timezone_string ) );
+
+ // Set the timezone for proper formatting.
+ $datetime->setTimezone( new DateTimeZone( 'UTC' ) );
+
+ // Format the DateTime object as 'Y-m-d\TH:i:s\Z'.
+ $formatted_date = $datetime->format( 'Y-m-d\TH:i:s\Z' );
+ return $formatted_date;
+ }
+
+ /**
+ * Returns the maximum attendee capacity.
+ *
+ * @return ?int
+ */
+ public function get_maximum_attendee_capacity() {
+ return $this->em_event->event_spaces;
+ }
+
+ /**
+ * Return the remaining attendee capacity
+ *
+ * @return ?int
+ */
+ public function get_remaining_attendee_capacity(): ?int {
+ $em_bookings_count = $this->get_participant_count();
+ $max_bookings = $this->em_event->event_spaces;
+
+ if ( $max_bookings && $em_bookings_count ) {
+ return $this->em_event->event_spaces - $em_bookings_count;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the current participant count.
+ *
+ * @return int
+ */
+ public function get_participant_count(): int {
+ $em_bookings = $this->em_event->get_bookings()->get_bookings();
+ return count( $em_bookings->bookings );
+ }
+
+ /**
+ * Get the event link as an ActivityPub Link object, but as an associative array.
+ *
+ * @return array|null
+ */
+ private function get_event_link_attachment(): ?array {
+ if ( $this->is_online() ) {
+ if ( property_exists( $this->em_event->event_location, 'data' ) ) {
+ $event_location = $this->em_event->event_location->data;
+ } else {
+ $event_location = array();
+ }
+
+ $event_link_url = isset( $event_location['url'] ) ? $event_location['url'] : null;
+ $event_link_text = isset( $event_location['text'] ) ? $event_location['text'] : __( 'Link', 'event-bridge-for-activitypub' );
+
+ if ( empty( $event_link_url ) ) {
+ return null;
+ }
+
+ return array(
+ 'type' => 'Link',
+ 'name' => \esc_html( $event_link_text ),
+ 'href' => \esc_url( $event_link_url ),
+ 'mediaType' => 'text/html',
+ );
+ }
+
+ return null;
+ }
+
+ /**
+ * Overrides/extends the get_attachments function to also add the event Link.
+ */
+ protected function get_attachment(): array {
+ // Get attachments via parent function.
+ $attachments = parent::get_attachment();
+
+ // The first attachment is the featured image, make sure it is compatible with Mobilizon.
+ if ( count( $attachments ) ) {
+ $attachments[0]['type'] = 'Document';
+ $attachments[0]['name'] = 'Banner';
+ }
+
+ $event_link_attachment = $this->get_event_link_attachment();
+
+ if ( $event_link_attachment ) {
+ $attachments[] = $event_link_attachment;
+ }
+ return $attachments;
+ }
+
+ /**
+ * Compose the events tags.
+ */
+ public function get_tag(): array {
+ // The parent tag function also fetches the mentions.
+ $tags = parent::get_tag();
+
+ $post_tags = \wp_get_post_terms( $this->item->ID, 'event-tags' );
+
+ if ( $post_tags ) {
+ foreach ( $post_tags as $post_tag ) {
+ $tag = array(
+ 'type' => 'Hashtag',
+ 'href' => \esc_url( \get_tag_link( $post_tag->term_id ) ),
+ 'name' => esc_hashtag( $post_tag->name ),
+ );
+ $tags[] = $tag;
+ }
+ }
+ return $tags;
+ }
+
+ /**
+ * Get the events title/name.
+ *
+ * @return string
+ */
+ protected function get_name(): string {
+ return $this->em_event->event_name;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-gatherpress.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-gatherpress.php
new file mode 100644
index 00000000..9b4f49f7
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-gatherpress.php
@@ -0,0 +1,156 @@
+gp_event = new GatherPress_Event( $item->ID );
+ $this->gp_venue = $this->gp_event->get_venue_information();
+ }
+
+ /**
+ * Get the event location.
+ *
+ * @return ?Place The place objector null if not place set.
+ */
+ public function get_location(): ?Place {
+ $address = $this->gp_venue['full_address'];
+ if ( $address ) {
+ $place = new Place();
+ $place->set_type( 'Place' );
+ $place->set_name( $address );
+ $place->set_address( $address );
+ return $place;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the end time from the event object.
+ */
+ public function get_end_time(): string {
+ return $this->gp_event->get_datetime_end( 'Y-m-d\TH:i:s\Z' );
+ }
+
+ /**
+ * Get the end time from the event object.
+ */
+ public function get_start_time(): string {
+ return $this->gp_event->get_datetime_start( 'Y-m-d\TH:i:s\Z' );
+ }
+
+ /**
+ * Get the event link from the events metadata.
+ */
+ private function get_event_link(): array {
+
+ $event_link = get_post_meta( $this->item->ID, 'event-link', true );
+ if ( $event_link ) {
+ return array(
+ 'type' => 'Link',
+ 'name' => 'Website',
+ 'href' => \esc_url( $event_link ),
+ 'mediaType' => 'text/html',
+ );
+ }
+
+ return array();
+ }
+
+ /**
+ * Overrides/extends the get_attachments function to also add the event Link.
+ */
+ protected function get_attachment(): array {
+ $attachments = parent::get_attachment();
+ if ( count( $attachments ) ) {
+ $attachments[0]['type'] = 'Document';
+ $attachments[0]['name'] = 'Banner';
+ }
+ $event_link = $this->get_event_link();
+ if ( $event_link ) {
+ $attachments[] = $this->get_event_link();
+ }
+ return $attachments;
+ }
+
+ /**
+ * Prevents gatherpress blocks from being rendered for the content.
+ *
+ * @param mixed $block_content The blocks content.
+ * @param mixed $block The block.
+ */
+ public static function filter_gatherpress_blocks( $block_content, $block ) {
+ // Check if the block name starts with 'gatherpress'.
+ if ( isset( $block['blockName'] ) && 0 === strpos( $block['blockName'], 'gatherpress/' ) ) {
+ return ''; // Skip rendering this block.
+ }
+
+ return $block_content; // Return the content for other blocks.
+ }
+
+ /**
+ * Apply the filter for preventing the rendering off gatherpress blocks just in time.
+ *
+ * @return Event_Object
+ */
+ public function to_object(): Event_Object {
+ add_filter( 'render_block', array( self::class, 'filter_gatherpress_blocks' ), 10, 2 );
+ $activitypub_object = parent::to_object();
+ remove_filter( 'render_block', array( self::class, 'filter_gatherpress_blocks' ) );
+ return $activitypub_object;
+ }
+
+ /**
+ * Determine whether the event is online.
+ *
+ * @return bool
+ */
+ public function get_is_online(): bool {
+ return $this->gp_event->maybe_get_online_event_link() ? true : false;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-modern-events-calendar-lite.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-modern-events-calendar-lite.php
new file mode 100644
index 00000000..48011a65
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-modern-events-calendar-lite.php
@@ -0,0 +1,127 @@
+mec_main = MEC::getInstance( 'app.libraries.main' );
+ $this->mec_event = new MEC_Event( $item );
+ }
+
+ /**
+ * Retrieves the content without the plugins rendered shortcodes.
+ */
+ public function get_content(): string {
+ $content = wpautop( $this->item->post_content );
+ return $content;
+ }
+
+ /**
+ * Get the end time from the event object.
+ *
+ * @return string
+ */
+ public function get_start_time(): string {
+ return \gmdate( 'Y-m-d\TH:i:s\Z', $this->mec_event->get_datetime()['start']['timestamp'] );
+ }
+
+ /**
+ * Get the end time from the event object.
+ *
+ * @return string
+ */
+ public function get_end_time(): string {
+ return \gmdate( 'Y-m-d\TH:i:s\Z', $this->mec_event->get_datetime()['end']['timestamp'] );
+ }
+
+ /**
+ * Get the location.
+ *
+ * @return ?Place
+ */
+ public function get_location(): ?Place {
+ $location_id = $this->mec_main->get_master_location_id( $this->mec_event->ID );
+
+ if ( ! $location_id ) {
+ return null;
+ }
+
+ $data = $this->mec_main->get_location_data( $location_id );
+
+ $location = new Place();
+ $location->set_sensitive( null );
+
+ if ( ! empty( $data['address'] ) ) {
+ $location->set_address( $data['address'] );
+ }
+ if ( ! empty( $data['name'] ) ) {
+ $location->set_name( $data['name'] );
+ }
+ if ( ! empty( $data['longitude'] ) ) {
+ $location->set_longitude( $data['longitude'] );
+ }
+ if ( ! empty( $data['latitude'] ) ) {
+ $location->set_latitude( $data['latitude'] );
+ }
+
+ return $location;
+ }
+
+ /**
+ * Get the location.
+ */
+ public function get_timezone(): string {
+ $timezone = get_post_meta( $this->item->ID, 'mec_timezone', true );
+
+ if ( 'global' === $timezone ) {
+ return parent::get_timezone();
+ }
+
+ return $timezone;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-the-events-calendar.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-the-events-calendar.php
new file mode 100644
index 00000000..61cb979e
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-the-events-calendar.php
@@ -0,0 +1,203 @@
+tribe_event = \tribe_get_event( $item );
+ }
+
+ /**
+ * Get the tags, including also the set categories from The Events Calendar.
+ *
+ * @return array The array if tags,
+ */
+ public function get_tag(): array {
+ $tags = array();
+ $category_ids = tribe_get_event_cat_ids();
+ if ( $category_ids ) {
+ foreach ( $category_ids as $category_id ) {
+ $term = \get_term( $category_id );
+ $tag = array(
+ 'type' => 'Hashtag',
+ 'href' => \esc_url( \get_term_link( $term ) ),
+ 'name' => esc_hashtag( $term->name ),
+ );
+ $tags[] = $tag;
+ }
+ }
+ $tags = array_merge( $tags, parent::get_tag() );
+
+ return $tags;
+ }
+
+ /**
+ * Get the end time from the event object.
+ */
+ public function get_end_time(): string {
+ $utc_time = get_post_meta( $this->tribe_event->ID, '_EventEndDateUTC', true );
+ $timezone = new \DateTimeZone( $this->get_timezone() );
+ $time = new \DateTime( $utc_time );
+ $time->setTimezone( $timezone );
+ return $time->format( 'Y-m-d\TH:i:sP' );
+ }
+
+ /**
+ * Get the end time from the event object.
+ */
+ public function get_start_time(): string {
+ $utc_time = get_post_meta( $this->tribe_event->ID, '_EventStartDateUTC', true );
+ $timezone = new \DateTimeZone( $this->get_timezone() );
+ $time = new \DateTime( $utc_time );
+ $time->setTimezone( $timezone );
+ return $time->format( 'Y-m-d\TH:i:sP' );
+ }
+
+ /**
+ * Get the timezone of the event.
+ *
+ * @return string The timezone string of the site.
+ */
+ public function get_timezone(): string {
+ // @phpstan-ignore-next-line
+ $timezone = $this->tribe_event->timezone;
+
+ if ( ! $timezone || ! is_string( $timezone ) ) {
+ return parent::get_timezone();
+ }
+
+ return $timezone;
+ }
+
+ /**
+ * Get status of the tribe event
+ *
+ * @return string status of the event
+ */
+ public function get_status(): string {
+ // @phpstan-ignore-next-line
+ $event_status = $this->tribe_event->event_status;
+
+ if ( 'canceled' === $event_status ) {
+ return 'CANCELLED';
+ }
+
+ if ( 'postponed' === $event_status ) {
+ return 'CANCELLED'; // This will be reflected in the cancelled reason.
+ }
+
+ return 'CONFIRMED';
+ }
+
+
+ /**
+ * Check if the comments are enabled for the current event.
+ */
+ public function get_comments_enabled(): bool {
+ return ( 'open' === $this->tribe_event->comment_status ) ? true : false;
+ }
+
+ /**
+ * Check if the event is an online event.
+ */
+ public function get_is_online(): bool {
+ return false;
+ }
+
+ /**
+ * Get the event location.
+ *
+ * @return ?Place The place/venue if one is set.
+ */
+ public function get_location(): ?Place {
+ // Get short handle for the venues.
+
+ if ( ! \tribe_has_venue( $this->tribe_event->ID ) ) {
+ return null;
+ }
+
+ $venue_id = \tribe_get_venue_id( $this->tribe_event->ID );
+ $post = \get_post( $venue_id );
+
+ if ( ! $post ) {
+ return null;
+ }
+
+ $location_transformer = new The_Events_Calendar_Location( $post );
+ $full_location_object = false;
+ $location = $location_transformer->to_object( $full_location_object );
+ return $location;
+ }
+
+ /**
+ * Apply the filter for preventing the rendering off The Events Calendar blocks just in time.
+ *
+ * @return Event_Object
+ */
+ public function to_object(): Event_Object {
+ add_filter( 'render_block', array( self::class, 'filter_tribe_blocks' ), 10, 2 );
+ $activitypub_object = parent::to_object();
+ remove_filter( 'render_block', array( self::class, 'filter_tribe_blocks' ) );
+ return $activitypub_object;
+ }
+
+ /**
+ * Prevents The Events Calendar blocks from being rendered for the content.
+ *
+ * @param mixed $block_content The blocks content.
+ * @param mixed $block The block.
+ */
+ public static function filter_tribe_blocks( $block_content, $block ) {
+ // Check if the block name starts with 'tribe' and is not an exception.
+ if ( isset( $block['blockName'] ) && 0 === strpos( $block['blockName'], 'tribe/' ) ) {
+ return ''; // Skip rendering this block.
+ }
+
+ return $block_content; // Return the content for other blocks.
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-vs-event-list.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-vs-event-list.php
new file mode 100644
index 00000000..1ea96415
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-vs-event-list.php
@@ -0,0 +1,115 @@
+item->ID, 'event-location', true );
+ if ( $address ) {
+ $place = new Place();
+ $place->set_type( 'Place' );
+ $place->set_name( $address );
+ $place->set_address( $address );
+ return $place;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the end time from the events metadata.
+ */
+ public function get_end_time(): ?string {
+ if ( 'yes' === \get_post_meta( $this->item->ID, 'event-hide-end-time', true ) ) {
+ return null;
+ }
+ $end_time = \get_post_meta( $this->item->ID, 'event-date', true );
+ if ( is_null( $end_time ) || empty( $end_time ) || 'no' === $end_time ) {
+ return null;
+ }
+ return \gmdate( 'Y-m-d\TH:i:s\Z', (int) $end_time );
+ }
+
+ /**
+ * Get the end time from the events metadata.
+ */
+ public function get_start_time(): string {
+ $start_time = \get_post_meta( $this->item->ID, 'event-start-date', true );
+ return \gmdate( 'Y-m-d\TH:i:s\Z', (int) $start_time );
+ }
+
+ /**
+ * Get the event link from the events metadata.
+ *
+ * @return ?array Associated array of an ActivityStreams Link object with the events URL.
+ */
+ private function get_event_link(): ?array {
+ $event_link = \get_post_meta( $this->item->ID, 'event-link', true );
+ $event_link_label = \get_post_meta( $this->item->ID, 'event-link-label', true ) ?? 'Event Link';
+ if ( $event_link ) {
+ return array(
+ 'type' => 'Link',
+ 'name' => $event_link_label,
+ 'href' => \esc_url( $event_link ),
+ 'mediaType' => 'text/html',
+ );
+ }
+ return null;
+ }
+
+ /**
+ * Overrides/extends the get_attachments function to also add the event Link.
+ *
+ * @return array
+ */
+ protected function get_attachment(): array {
+ $attachments = parent::get_attachment();
+ if ( count( $attachments ) ) {
+ $attachments[0]['type'] = 'Document';
+ $attachments[0]['name'] = 'Banner';
+ }
+ $event_link = $this->get_event_link();
+ if ( $event_link ) {
+ $attachments[] = $event_link;
+ }
+ return $attachments;
+ }
+
+ /**
+ * Retrieves the excerpt text (may be HTML). Used for constructing the summary.
+ *
+ * @return ?string
+ */
+ protected function retrieve_excerpt(): ?string {
+ if ( \get_post_meta( $this->item->ID, 'event-summary', true ) ) {
+ return \get_post_meta( $this->item->ID, 'event-summary', true );
+ } else {
+ return parent::retrieve_excerpt();
+ }
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-wp-event-manager.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-wp-event-manager.php
new file mode 100644
index 00000000..eda001e5
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-wp-event-manager.php
@@ -0,0 +1,162 @@
+item->ID, '_event_online', true );
+ $is_online = false;
+ // Radio buttons.
+ if ( 'yes' === $is_online_text ) {
+ $is_online = true;
+ }
+ // Checkbox.
+ if ( '1' === $is_online_text ) {
+ $is_online = true;
+ }
+ return $is_online;
+ }
+
+ /**
+ * Get the event location.
+ *
+ * @return ?Place The Place.
+ */
+ public function get_location(): ?Place {
+ $location_name = get_post_meta( $this->item->ID, '_event_location', true );
+
+ if ( $location_name ) {
+ $location = new Place();
+ $location->set_name( $location_name );
+ $location->set_sensitive( null );
+ $location->set_address( $location_name );
+
+ return $location;
+ }
+ return null;
+ }
+
+ /**
+ * Get the end time from the events metadata.
+ *
+ * @return ?string The events end-datetime if is set, null otherwise.
+ */
+ public function get_end_time(): ?string {
+ $end_date = get_post_meta( $this->item->ID, '_event_end_date', true );
+ if ( ! $end_date ) {
+ return null;
+ }
+ $timezone = new DateTimeZone( $this->get_timezone() );
+
+ if ( is_numeric( $end_date ) ) {
+ $end_date = '@' . $end_date;
+ }
+
+ $end_datetime = new DateTime( $end_date, $timezone );
+
+ return $end_datetime->format( 'Y-m-d\TH:i:sP' );
+ }
+
+ /**
+ * Get timezone.
+ *
+ * @return string
+ */
+ public function get_timezone(): string {
+ $time_zone = get_post_meta( $this->item->ID, '_event_timezone', true );
+ if ( $time_zone ) {
+ return $time_zone;
+ }
+ return parent::get_timezone();
+ }
+
+ /**
+ * Get the end time from the events metadata.
+ */
+ public function get_start_time(): string {
+ $start_date = get_post_meta( $this->item->ID, '_event_start_date', true );
+ $timezone = new DateTimeZone( $this->get_timezone() );
+
+ if ( is_numeric( $start_date ) ) {
+ $start_date = '@' . $start_date;
+ }
+
+ $start_datetime = new DateTime( $start_date, $timezone );
+
+ return $start_datetime->format( 'Y-m-d\TH:i:sP' );
+ }
+
+ /**
+ * Get the event link as an ActivityPub Link object, but as an associative array.
+ *
+ * @return ?array
+ */
+ private function get_event_link_attachment(): ?array {
+ $event_link_url = get_post_meta( $this->item->ID, '_event_video_url', true );
+
+ if ( str_starts_with( $event_link_url, 'http' ) ) {
+ return array(
+ 'type' => 'Link',
+ 'name' => \esc_html__( 'Video URL', 'event-bridge-for-activitypub' ),
+ 'href' => \esc_url( $event_link_url ),
+ 'mediaType' => 'text/html',
+ );
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Overrides/extends the get_attachments function to also add the event Link.
+ */
+ protected function get_attachment() {
+ // Get attachments via parent function.
+ $attachments = parent::get_attachment();
+
+ // The first attachment is the featured image, make sure it is compatible with Mobilizon.
+ if ( count( $attachments ) ) {
+ $attachments[0]['type'] = 'Document';
+ $attachments[0]['name'] = 'Banner';
+ }
+
+ if ( $this->get_event_link_attachment() ) {
+ $attachments[] = $this->get_event_link_attachment();
+ }
+ return $attachments;
+ }
+
+ /**
+ * Get the events title/name.
+ *
+ * @return string
+ */
+ protected function get_name(): string {
+ return $this->item->post_title;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-base-post-place.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-base-post-place.php
new file mode 100644
index 00000000..355af17f
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-base-post-place.php
@@ -0,0 +1,146 @@
+transform_object_properties( $activitypub_object );
+
+ if ( \is_wp_error( $activitypub_object ) ) {
+ return $activitypub_object;
+ }
+
+ if ( ! empty( $activitypub_object->get_content() ) ) {
+ $activitypub_object->set_content_map(
+ array(
+ $this->get_locale() => $this->get_content(),
+ )
+ );
+ }
+
+ $updated = \strtotime( $this->item->post_modified_gmt );
+
+ $activitypub_object->set_updated( \gmdate( 'Y-m-d\TH:i:s\Z', $updated ) );
+
+ if ( $full_object ) {
+ $published = \strtotime( $this->item->post_date_gmt );
+
+ $activitypub_object->set_published( \gmdate( 'Y-m-d\TH:i:s\Z', $published ) );
+
+ $activitypub_object->set_to(
+ array(
+ 'https://www.w3.org/ns/activitystreams#Public',
+ $this->get_actor_object()->get_followers(),
+ )
+ );
+ }
+
+ $address = $this->get_address();
+
+ if ( $address ) {
+ $activitypub_object->set_address( $address );
+ }
+
+ // @phpstan-ignore-next-line
+ return $activitypub_object;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-base-term-place.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-base-term-place.php
new file mode 100644
index 00000000..2a70b88a
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-base-term-place.php
@@ -0,0 +1,165 @@
+item->term_id;
+ }
+
+ /**
+ * Get the ActivityPub ID of the term.
+ *
+ * @return string
+ */
+ public function get_url() {
+ return \get_term_link( $this->item );
+ }
+
+ /**
+ * Returns the most unique, resolvable "ID" there currently is for a WordPress term.
+ *
+ * @return string The "ID"
+ */
+ public function get_id() {
+ /**
+ * The first approach was to use the normal query from WordPress, but it contains the slug, which might be edited.
+ *
+ * \add_query_arg( $this->item->taxonomy, $this->item->slug, \trailingslashit( \home_url() ) );
+ *
+ * As https://github.com/Automattic/wordpress-activitypub/pull/1272 got merged, now we can definy a real ID.
+ */
+ return \add_query_arg( 'term_id', $this->item->term_id, \trailingslashit( \home_url() ) );
+ }
+
+ /**
+ * Use Term description as ActivityPub content.
+ *
+ * @return mixed|string
+ */
+ public function get_content() {
+ return $this->item->description;
+ }
+
+ /**
+ * Returns the name for the ActivityPub Item which is the title of the term.
+ *
+ * @return string|null The title or null if the object type is `note`.
+ */
+ protected function get_name() {
+ if ( isset( $this->item->name ) && $this->item instanceof \WP_Term ) {
+ return \wp_strip_all_tags(
+ \html_entity_decode(
+ $this->item->name
+ )
+ );
+ }
+
+ return null;
+ }
+
+ /**
+ * Generic function that converts an WordPress location object to an ActivityPub-Place object.
+ *
+ * @return Place_Object|\WP_Error
+ */
+ public function to_object() {
+ $activitypub_object = new Place_Object();
+
+ $activitypub_object->set_type( $this->get_type() );
+ $activitypub_object->set_id( $this->get_id() );
+ $activitypub_object->set_name( $this->get_name() );
+ $activitypub_object->set_url( $this->get_url() );
+ $activitypub_object->set_content( $this->get_content() );
+ $activitypub_object->set_sensitive( $this->get_sensitive() );
+
+ $address = $this->get_address();
+
+ if ( $address ) {
+ $activitypub_object->set_address( $address );
+ }
+
+ return $activitypub_object;
+ }
+
+ /**
+ * Don't set a media type on Place per default.
+ *
+ * @return null
+ * @phpstan-ignore-next-line
+ */
+ public function get_media_type() {
+ return null;
+ }
+
+ /**
+ * Don't set sensitive per default.
+ *
+ * @return null
+ */
+ public function get_sensitive() {
+ return null;
+ }
+
+ /**
+ * Don't support replies for Place per default.
+ *
+ * @return null
+ */
+ public function get_replies() {
+ return null;
+ }
+
+ /**
+ * Don't support tags for Place per default.
+ *
+ * @return null
+ * @phpstan-ignore-next-line
+ */
+ protected function get_tag() {
+ return null;
+ }
+
+ /**
+ * Don't set attrbuted to per default.
+ *
+ * @return null The attributed to.
+ * @phpstan-ignore-next-line
+ */
+ protected function get_attributed_to() {
+ return null;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-event-organiser.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-event-organiser.php
new file mode 100644
index 00000000..f9fa4050
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-event-organiser.php
@@ -0,0 +1,89 @@
+item->ID );
+ return 0.0 !== $longitude ? $longitude : null;
+ }
+
+ /**
+ * Get the latitude.
+ *
+ * @return float|null
+ */
+ public function get_latitude() {
+ $latitude = \eo_get_venue_lat( $this->item->ID );
+ return 0.0 !== $latitude ? $latitude : null;
+ }
+
+ /**
+ * Get the description of the venue as the ActivityPub content.
+ *
+ * @return string|null
+ */
+ public function get_content() {
+ $description = \eo_get_venue_description( $this->item->term_id );
+
+ if ( empty( $description ) ) {
+ return null;
+ }
+
+ return $description;
+ }
+
+ /**
+ * Get the events address.
+ *
+ * @return ?array The place/venue if one is set, or null if no valid address data exists.
+ */
+ public function get_address(): ?array {
+ $address = \eo_get_venue_address( $this->item->term_id );
+
+ // Map the values to a schema.org PostalAddress.
+ $postal_address = array(
+ 'streetAddress' => isset( $address['address'] ) ? $address['address'] : null,
+ 'postalCode' => isset( $address['address'] ) ? $address['postcode'] : null,
+ 'addressRegion' => isset( $address['address'] ) ? $address['state'] : null,
+ 'addressLocality' => isset( $address['address'] ) ? $address['city'] : null,
+ 'addressCountry' => isset( $address['address'] ) ? $address['country'] : null,
+ );
+
+ // Filter out empty values.
+ foreach ( $postal_address as $key => $value ) {
+ if ( empty( $value ) ) {
+ unset( $postal_address[ $key ] );
+ }
+ }
+
+ // If no valid address data remains, return null.
+ if ( empty( $postal_address ) ) {
+ return null;
+ }
+
+ // Add the type.
+ $postal_address['type'] = 'PostalAddress';
+
+ return $postal_address;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-eventon.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-eventon.php
new file mode 100644
index 00000000..e71cc55c
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-eventon.php
@@ -0,0 +1,197 @@
+term_id ] ) ) {
+ $this->tax_meta = $evo_tax_meta['event_location'][ $item->term_id ];
+ }
+ }
+
+ /**
+ * Generic function that converts an WordPress location object to an ActivityPub-Place object.
+ *
+ * @return Place_Object|\WP_Error
+ */
+ public function to_object() {
+ $object = parent::to_object();
+
+ if ( \is_wp_error( $object ) ) {
+ return $object;
+ }
+
+ $object->set_longitude( $this->get_longitude() );
+ $object->set_latitude( $this->get_latitude() );
+
+ return $object;
+ }
+
+ /**
+ * Get the type, either Place or VirtualLocation, both is stored in the same taxonomy.
+ *
+ * @return string
+ */
+ public function get_type(): string {
+ if ( $this->is_virtual_location() ) {
+ return 'VirtualLocation';
+ }
+ return 'Place';
+ }
+
+ /**
+ * Get the longitute.
+ *
+ * @return float|null
+ */
+ public function get_longitude(): ?float {
+ $longitude = null;
+
+ if ( isset( $this->tax_meta['location_lon'] ) ) {
+ $longitude = $this->tax_meta['location_lon'];
+ }
+
+ return $longitude ? (float) $longitude : null;
+ }
+
+ /**
+ * Get the latitude.
+ *
+ * @return float|null
+ */
+ public function get_latitude(): ?float {
+ $latitude = null;
+
+ if ( isset( $this->tax_meta['location_lat'] ) ) {
+ $latitude = $this->tax_meta['location_lat'];
+ }
+
+ return $latitude ? (float) $latitude : null;
+ }
+
+ /**
+ * Get the events address.
+ *
+ * @return ?array The place/venue if one is set, or null if no valid address data exists.
+ */
+ public function get_address(): ?array {
+
+ if ( $this->is_virtual_location() ) {
+ return null;
+ }
+
+ // Map the values to a schema.org PostalAddress.
+ $postal_address = array(
+ 'streetAddress' => isset( $this->tax_meta['location_address'] ) ? (string) $this->tax_meta['location_address'] : null,
+ 'addressRegion' => isset( $this->tax_meta['location_state'] ) ? (string) $this->tax_meta['location_state'] : null,
+ 'addressCountry' => isset( $this->tax_meta['location_country'] ) ? (string) $this->tax_meta['location_country'] : null,
+ );
+
+ if ( isset( $this->tax_meta['location_city'] ) ) {
+ $locality_and_postal_code = $this->parse_city_for_postal_code( $this->tax_meta['location_city'] );
+ $postal_address['addressLocality'] = (string) $locality_and_postal_code['addressLocality'];
+ $postal_address['postalCode'] = (string) $locality_and_postal_code['postalCode'];
+ }
+
+ // Filter out empty values.
+ foreach ( $postal_address as $key => $value ) {
+ if ( empty( $value ) ) {
+ unset( $postal_address[ $key ] );
+ }
+ }
+
+ // If no valid address data remains, return null.
+ if ( empty( $postal_address ) ) {
+ return null;
+ }
+
+ // Add the type.
+ $postal_address = array_merge(
+ array(
+ 'type' => 'PostalAddress',
+ ),
+ $postal_address
+ );
+
+ return $postal_address;
+ }
+
+ /**
+ * Check if this term represents a virtual location.
+ *
+ * @return bool
+ */
+ private function is_virtual_location(): bool {
+ if ( isset( $this->tax_meta['location_type'] ) && 'virtual' === $this->tax_meta['location_type'] ) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Parse a string whether it contains a postal code and seperates both.
+ *
+ * @param string $input The input string of the locality which might contain the postal code too.
+ * @return array{addressLocality: string, postalCode: string}
+ */
+ private function parse_city_for_postal_code( $input ): array {
+ $input = trim( $input );
+
+ if ( empty( $input ) ) {
+ return array(
+ 'addressLocality' => '',
+ 'postalCode' => '',
+ );
+ }
+
+ $parts = explode( ' ', $input );
+ $postal_code = '';
+ $locality = array();
+
+ foreach ( $parts as $part ) {
+ if ( preg_match( '/^\d{4,5}$/', $part ) ) {
+ // Match postal codes (assuming 4-5 digit codes).
+ $postal_code = $part;
+ } else {
+ // Assume everything else is part of the name of the city.
+ $locality[] = $part;
+ }
+ }
+
+ return array(
+ 'addressLocality' => implode( ' ', $locality ),
+ 'postalCode' => $postal_code,
+ );
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-eventprime.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-eventprime.php
new file mode 100644
index 00000000..f78964cd
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-eventprime.php
@@ -0,0 +1,59 @@
+ep_get_custom_page_url( 'venues_page', $this->item->term_id, 'venue', 'term' );
+
+ if ( \is_wp_error( $url ) ) {
+ return null;
+ }
+ return $url;
+ }
+
+ /**
+ * Get the best "ID" we currently have.
+ *
+ * @return string|null
+ */
+ public function get_id() {
+ return $this->get_url();
+ }
+
+ /**
+ * Get the event location.
+ *
+ * @return array|string|null The place/venue if one is set.
+ */
+ public function get_address() {
+ $address = \get_term_meta( $this->item->term_id, 'em_address', true );
+ $display_address = \get_term_meta( $this->item->term_id, 'em_display_address_on_frontend', true );
+
+ if ( $address && $display_address ) {
+ return $address;
+ }
+
+ return null;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-events-manager.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-events-manager.php
new file mode 100644
index 00000000..21b381e2
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-events-manager.php
@@ -0,0 +1,95 @@
+post_type ) {
+ $this->em_location = em_get_location( $post );
+ }
+ }
+
+ /**
+ * Get the name of the location.
+ *
+ * @return ?string
+ */
+ public function get_name(): ?string {
+ if ( isset( $this->em_location->location_name ) ) {
+ return \wp_strip_all_tags(
+ \html_entity_decode(
+ $this->em_location->location_name
+ )
+ );
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the event location.
+ *
+ * @return ?array The place/venue if one is set.
+ */
+ public function get_address(): ?array {
+ $postal_address = array();
+
+ if ( isset( $this->em_location->location_country ) && $this->em_location->location_country ) {
+ $postal_address['addressCountry'] = $this->em_location->location_country;
+ }
+
+ if ( isset( $this->em_location->location_town ) && $this->em_location->location_town ) {
+ $postal_address['addressLocality'] = $this->em_location->location_town;
+ }
+
+ if ( isset( $this->em_location->location_address ) && $this->em_location->location_address ) {
+ $postal_address['streetAddress'] = $this->em_location->location_address;
+ }
+
+ if ( isset( $this->em_location->location_state ) && $this->em_location->location_state ) {
+ $postal_address['addressRegion'] = $this->em_location->location_state;
+ }
+
+ if ( isset( $this->em_location->location_postcode ) && $this->em_location->location_postcode ) {
+ $postal_address['postalCode'] = $this->em_location->location_postcode;
+ }
+
+ if ( ! empty( $postal_address ) ) {
+ return array_merge( array( 'type' => 'PostalAddress' ), $postal_address );
+ }
+
+ return null;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-the-events-calendar.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-the-events-calendar.php
new file mode 100644
index 00000000..5632bcc0
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-the-events-calendar.php
@@ -0,0 +1,63 @@
+item->ID );
+ if ( $country ) {
+ $postal_address['addressCountry'] = $country;
+ }
+
+ $city = \tribe_get_city( $this->item->ID );
+ if ( $city ) {
+ $postal_address['addressLocality'] = $city;
+ }
+
+ $province = \tribe_get_province( $this->item->ID );
+ if ( $province ) {
+ $postal_address['addressRegion'] = $province;
+ }
+
+ $zip = \tribe_get_zip( $this->item->ID );
+ if ( $zip ) {
+ $postal_address['postalCode'] = $zip;
+ }
+
+ $address = \tribe_get_address( $this->item->ID );
+ if ( $city ) {
+ $postal_address['streetAddress'] = $address;
+ }
+
+ if ( empty( $postal_address ) ) {
+ return null;
+ }
+
+ $postal_address = array_merge( array( 'type' => 'PostalAddress' ), $postal_address );
+
+ return $postal_address;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-base.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-base.php
new file mode 100644
index 00000000..00a5c031
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-base.php
@@ -0,0 +1,378 @@
+get_id();
+ $event_source_activitypub_id = \get_the_guid( $event_source_post_id );
+
+ if ( $post_id ) {
+ \do_action(
+ 'event_bridge_for_activitypub_write_log',
+ array( "[ACTIVITYPUB] Processed incoming event {$event_activitypub_id} from {$event_source_activitypub_id}" )
+ );
+ // Use post meta to remember who we received this event from.
+ \update_post_meta( $post_id, '_event_bridge_for_activitypub_event_source', absint( $event_source_post_id ) );
+ \update_post_meta( $post_id, 'activitypub_content_visibility', defined( 'ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL' ) ? constant( 'ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL' ) : '' );
+ } else {
+ \do_action(
+ 'event_bridge_for_activitypub_write_log',
+ array( "[ACTIVITYPUB] Failed processing incoming event {$event_activitypub_id} from {$event_source_activitypub_id}" )
+ );
+ }
+ }
+
+ /**
+ * Delete a local event in WordPress that is a cached remote one.
+ *
+ * @param string $activitypub_event_id The ActivityPub events ID.
+ * @return bool|WP_Post|null|WP_Error
+ */
+ public static function delete( $activitypub_event_id ) {
+ $post_id = static::get_post_id_from_activitypub_id( $activitypub_event_id );
+
+ if ( ! $post_id ) {
+ \do_action(
+ 'event_bridge_for_activitypub_write_log',
+ array( "[ACTIVITYPUB] Received delete for event that is not cached locally {$activitypub_event_id}" )
+ );
+ return new WP_Error(
+ 'event_bridge_for_activitypub_remote_event_not_found',
+ \__( 'Remote event not found in cache', 'event-bridge-for-activitypub' ),
+ array( 'status' => 404 )
+ );
+ }
+
+ $thumbnail_id = get_post_thumbnail_id( $post_id );
+
+ if ( $thumbnail_id && ! Event_Sources::is_attachment_featured_image( $thumbnail_id ) ) {
+ wp_delete_attachment( $thumbnail_id, true );
+ }
+
+ $result = wp_delete_post( $post_id, true );
+
+ if ( $result ) {
+ \do_action( 'event_bridge_for_activitypub_write_log', array( "[ACTIVITYPUB] Deleted cached event {$activitypub_event_id}" ) );
+ } else {
+ \do_action( 'event_bridge_for_activitypub_write_log', array( "[ACTIVITYPUB] Failed deleting cached event {$activitypub_event_id}" ) );
+ }
+
+ return $result;
+ }
+
+ /**
+ * Format an ActivityStreams xds:datetime to WordPress GMT format.
+ *
+ * @param string $time_string The ActivityStreams xds:datetime (may include offset).
+ * @return string The GMT string in format 'Y-m-d H:i:s'.
+ */
+ protected static function format_time_string_to_wordpress_gmt( $time_string ): string {
+ $datetime = new \DateTime( $time_string );
+ $datetime->setTimezone( new \DateTimeZone( 'GMT' ) );
+ return $datetime->format( 'Y-m-d H:i:s' );
+ }
+
+ /**
+ * Get WordPress post by ActivityPub object ID using the guid.
+ *
+ * @param string $activitypub_id The ActivityPub object ID.
+ * @return int The WordPress Post ID, 0 if not post with that ActivityPub object ID (by guid) is found.
+ */
+ protected static function get_post_id_from_activitypub_id( $activitypub_id ): int {
+ global $wpdb;
+ return (int) $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT ID FROM $wpdb->posts WHERE guid=%s",
+ esc_sql( $activitypub_id ),
+ )
+ );
+ }
+
+ /**
+ * Get the image URL and alt-text of an ActivityPub object.
+ *
+ * @param mixed $data The ActivityPub object as ann associative array.
+ * @return array Array containing the images URL and alt-text.
+ */
+ private static function extract_image_alt_and_url( $data ): array {
+ $image = array(
+ 'url' => null,
+ 'alt' => null,
+ );
+
+ // Check whether it is already simple.
+ if ( ! $data || is_string( $data ) ) {
+ $image['url'] = $data;
+ return $image;
+ }
+
+ if ( ! isset( $data['type'] ) ) {
+ return $image;
+ }
+
+ if ( ! in_array( $data['type'], array( 'Document', 'Image' ), true ) ) {
+ return $image;
+ }
+
+ if ( isset( $data['url'] ) ) {
+ $image['url'] = $data['url'];
+ } elseif ( isset( $data['id'] ) ) {
+ $image['id'] = $data['id'];
+ }
+
+ if ( isset( $data['name'] ) ) {
+ $image['alt'] = $data['name'];
+ }
+
+ return $image;
+ }
+
+ /**
+ * Returns the URL of the featured image.
+ *
+ * @param Event $event The ActivityPub event object.
+ *
+ * @return array
+ */
+ protected static function get_featured_image( $event ): array {
+ // Search for the featured image in the image property.
+ $image = $event->get_image();
+
+ if ( $image ) {
+ return self::extract_image_alt_and_url( $image );
+ }
+
+ // Fallback attachment.
+ $attachment = $event->get_attachment();
+
+ // If attachment is an array get the first fitting one.
+ if ( is_array( $attachment ) && ! empty( $attachment ) ) {
+ $supported_types = array( 'Image', 'Document' );
+ $match = null;
+
+ foreach ( $attachment as $item ) {
+ if ( in_array( $item['type'], $supported_types, true ) ) {
+ $match = $item;
+ break;
+ }
+ }
+
+ $attachment = $match;
+ }
+
+ return self::extract_image_alt_and_url( $attachment );
+ }
+
+ /**
+ * Given an image URL return an attachment ID. Image will be side-loaded into the media library if it doesn't exist.
+ *
+ * Forked from https://gist.github.com/kingkool68/a66d2df7835a8869625282faa78b489a.
+ *
+ * @param int $post_id The post ID where the image will be set as featured image.
+ * @param string $url The image URL to maybe sideload.
+ * @uses media_sideload_image
+ * @return string|int|WP_Error
+ */
+ protected static function maybe_sideload_image( $post_id, $url = '' ) {
+ global $wpdb;
+
+ // Include necessary WordPress file for media handling.
+ if ( ! function_exists( 'media_sideload_image' ) ) {
+ // @phpstan-ignore-next-line
+ require_once ABSPATH . 'wp-admin/includes/media.php';
+ // @phpstan-ignore-next-line
+ require_once ABSPATH . 'wp-admin/includes/file.php';
+ // @phpstan-ignore-next-line
+ require_once ABSPATH . 'wp-admin/includes/image.php';
+ }
+
+ // Check to see if the URL has already been fetched, if so return the attachment ID.
+ $attachment_id = $wpdb->get_var(
+ $wpdb->prepare( "SELECT `post_id` FROM {$wpdb->postmeta} WHERE `meta_key` = '_source_url' AND `meta_value` = %s", $url )
+ );
+ if ( ! empty( $attachment_id ) ) {
+ return $attachment_id;
+ }
+
+ $attachment_id = $wpdb->get_var(
+ $wpdb->prepare( "SELECT `ID` FROM {$wpdb->posts} WHERE guid=%s", $url )
+ );
+ if ( ! empty( $attachment_id ) ) {
+ return $attachment_id;
+ }
+
+ // If the URL doesn't exist, sideload it to the media library.
+ return media_sideload_image( $url, $post_id, $url, 'id' );
+ }
+
+ /**
+ * Sideload an image_url set it as featured image and add the alt-text.
+ *
+ * @param int $post_id The post ID where the image will be set as featured image.
+ * @param string $image_url The image URL.
+ * @param string $alt_text The alt-text of the image.
+ * @return int|WP_Error The attachment ID
+ */
+ protected static function set_featured_image_with_alt( $post_id, $image_url, $alt_text = '' ) {
+ // Maybe sideload the image or get the Attachment ID of an existing one.
+ $image_id = self::maybe_sideload_image( $post_id, $image_url );
+
+ if ( \is_wp_error( $image_id ) ) {
+ // Handle the error.
+ return $image_id;
+ }
+
+ // Set the image as the featured image for the post.
+ \set_post_thumbnail( $post_id, $image_id );
+
+ // Update the alt text.
+ if ( ! empty( $alt_text ) ) {
+ \update_post_meta( $image_id, '_wp_attachment_image_alt', $alt_text );
+ }
+
+ return $image_id; // Return the attachment ID for further use if needed.
+ }
+
+ /**
+ * Convert a PostalAddress to a string.
+ *
+ * @link https://schema.org/PostalAddress
+ *
+ * @param array $postal_address The PostalAddress as an associative array.
+ * @return string
+ */
+ private static function postal_address_to_string( $postal_address ): string {
+ if ( ! isset( $postal_address['type'] ) || 'PostalAddress' !== $postal_address['type'] ) {
+ _doing_it_wrong(
+ __METHOD__,
+ 'The parameter postal_address must be an associate array like schema.org/PostalAddress.',
+ esc_html( EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_VERSION )
+ );
+ }
+
+ $address = array();
+ $known_attributes = array(
+ 'streetAddress',
+ 'postalCode',
+ 'addressLocality',
+ 'addressState',
+ 'addressCountry',
+ );
+
+ foreach ( $known_attributes as $attribute ) {
+ if ( isset( $postal_address[ $attribute ] ) && is_string( $postal_address[ $attribute ] ) ) {
+ $address[] = $postal_address[ $attribute ];
+ }
+ }
+
+ $address_string = implode( ' ,', $address );
+
+ return $address_string;
+ }
+
+ /**
+ * Convert an address to a string.
+ *
+ * @param mixed $address The address as an object, string or associative array.
+ * @return string
+ */
+ protected static function address_to_string( $address ): string {
+ if ( is_string( $address ) ) {
+ return $address;
+ }
+
+ if ( is_object( $address ) ) {
+ $address = (array) $address;
+ }
+
+ if ( ! is_array( $address ) || ! isset( $address['type'] ) ) {
+ return '';
+ }
+
+ if ( 'PostalAddress' === $address['type'] ) {
+ return self::postal_address_to_string( $address );
+ }
+ return '';
+ }
+
+ /**
+ * Return the number of revisions to keep.
+ *
+ * @return int The number of revisions to keep.
+ */
+ public static function revisions_to_keep(): int {
+ return 5;
+ }
+
+ /**
+ * Returns the URL of the online event link.
+ *
+ * @param Event $event The ActivityPub event object.
+ *
+ * @return ?string
+ */
+ protected static function get_online_event_link_from_attachments( $event ): ?string {
+ $attachments = $event->get_attachment();
+
+ if ( ! is_array( $attachments ) || empty( $attachments ) ) {
+ return null;
+ }
+
+ foreach ( $attachments as $attachment ) {
+ if ( array_key_exists( 'type', $attachment ) && 'Link' === $attachment['type'] && isset( $attachment['href'] ) ) {
+ return $attachment['href'];
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-gatherpress.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-gatherpress.php
new file mode 100644
index 00000000..47aafe79
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-gatherpress.php
@@ -0,0 +1,207 @@
+get_tag();
+
+ // Ensure the input is valid.
+ if ( empty( $tags_array ) || ! is_array( $tags_array ) || ! $post_id ) {
+ return false;
+ }
+
+ // Extract and process tag names.
+ $tag_names = array();
+ foreach ( $tags_array as $tag ) {
+ if ( isset( $tag['name'] ) && 'Hashtag' === $tag['type'] ) {
+ $tag_names[] = ltrim( $tag['name'], '#' ); // Remove the '#' from the name.
+ }
+ }
+
+ // Add the tags as terms to the post.
+ if ( ! empty( $tag_names ) ) {
+ \wp_set_object_terms( $post_id, $tag_names, IntegrationsGatherPress::get_event_category_taxonomy(), true );
+ }
+
+ return true;
+ }
+
+ /**
+ * Add venue.
+ *
+ * @param Event $activitypub_event The ActivityPub event object.
+ * @param int $post_id The post ID.
+ */
+ private static function add_venue( $activitypub_event, $post_id ) {
+ $location = $activitypub_event->get_location();
+
+ if ( ! $location ) {
+ return;
+ }
+
+ if ( $location instanceof Place ) {
+ $location = $location->to_array();
+ }
+
+ if ( ! is_array( $location ) ) {
+ return;
+ }
+
+ if ( ! isset( $location['name'] ) ) {
+ return;
+ }
+
+ // Fallback for Gancio instances.
+ if ( 'online' === $location['name'] ) {
+ $online_event_link = self::get_online_event_link_from_attachments( $activitypub_event );
+ if ( ! $online_event_link ) {
+ return;
+ }
+ \update_post_meta( $post_id, 'gatherpress_online_event_link', \sanitize_url( $online_event_link ) );
+ \wp_set_object_terms( $post_id, 'online-event', '_gatherpress_venue', false );
+ return;
+ }
+
+ $venue_instance = \GatherPress\Core\Venue::get_instance();
+ $venue_name = \sanitize_title( $location['name'] );
+ $venue_slug = $venue_instance->get_venue_term_slug( $venue_name );
+ $venue_post = $venue_instance->get_venue_post_from_term_slug( $venue_slug );
+
+ if ( ! $venue_post ) {
+ $venue_id = \wp_insert_post(
+ array(
+ 'post_title' => sanitize_text_field( $location['name'] ),
+ 'post_type' => 'gatherpress_venue',
+ 'post_status' => 'publish',
+ )
+ );
+ } else {
+ $venue_id = $venue_post->ID;
+ }
+
+ $venue_information = array();
+
+ $address_string = isset( $location['address'] ) ? self::address_to_string( $location['address'] ) : '';
+
+ $venue_information['fullAddress'] = $address_string;
+ $venue_information['phone_number'] = '';
+ $venue_information['website'] = '';
+ $venue_information['permalink'] = '';
+
+ $venue_json = \wp_json_encode( $venue_information );
+
+ \update_post_meta( $venue_id, 'gatherpress_venue_information', $venue_json );
+
+ \wp_set_object_terms( $post_id, $venue_slug, '_gatherpress_venue', false );
+ }
+
+ /**
+ * Save the ActivityPub event object as GatherPress Event.
+ *
+ * @param Event $activitypub_event The ActivityPub event object.
+ * @param int $event_source_post_id The Post ID of the Event Source that owns the outbox.
+ *
+ * @return false|int
+ */
+ protected static function save_event( $activitypub_event, $event_source_post_id ) {
+ // Limit this as a safety measure.
+ \add_filter( 'wp_revisions_to_keep', array( self::class, 'revisions_to_keep' ) );
+
+ $post_id = self::get_post_id_from_activitypub_id( $activitypub_event->get_id() );
+
+ $args = array(
+ 'post_title' => sanitize_text_field( $activitypub_event->get_name() ),
+ 'post_type' => 'gatherpress_event',
+ 'post_content' => wp_kses_post( $activitypub_event->get_content() ?? '' ) . '',
+ 'post_excerpt' => wp_kses_post( $activitypub_event->get_summary() ?? '' ),
+ 'post_status' => 'publish',
+ 'guid' => sanitize_url( $activitypub_event->get_id() ),
+ );
+
+ if ( $activitypub_event->get_published() ) {
+ $post_date = self::format_time_string_to_wordpress_gmt( $activitypub_event->get_published() );
+ $args['post_date'] = $post_date;
+ $args['post_date_gmt'] = $post_date;
+ }
+
+ if ( $post_id ) {
+ // Update existing GatherPress event post.
+ $args['ID'] = $post_id;
+ \wp_update_post( $args );
+ } else {
+ // Insert new GatherPress event post.
+ $post_id = \wp_insert_post( $args );
+ }
+
+ // @phpstan-ignore-next-line
+ if ( ! $post_id || \is_wp_error( $post_id ) ) {
+ return false;
+ }
+
+ // Insert the dates.
+ $gatherpress_event = new GatherPress_Event( $post_id );
+ $start_time = $activitypub_event->get_start_time();
+ $end_time = $activitypub_event->get_end_time();
+ if ( ! $end_time ) {
+ $end_time = new DateTime( $start_time );
+ $end_time->modify( '+1 hour' );
+ $end_time = $end_time->format( 'Y-m-d H:i:s' );
+ }
+ $params = array(
+ 'datetime_start' => $start_time,
+ 'datetime_end' => $end_time,
+ 'timezone' => $activitypub_event->get_timezone(),
+ );
+ // Sanitization of the params is done in the save_datetimes function just in time.
+ $gatherpress_event->save_datetimes( $params );
+
+ // Insert featured image.
+ $image = self::get_featured_image( $activitypub_event );
+ self::set_featured_image_with_alt( $post_id, $image['url'], $image['alt'] );
+
+ // Add hashtags.
+ self::add_tags_to_post( $activitypub_event, $post_id );
+
+ // Add venue.
+ self::add_venue( $activitypub_event, $post_id );
+
+ // Limit this as a safety measure.
+ \remove_filter( 'wp_revisions_to_keep', array( self::class, 'revisions_to_keep' ) );
+
+ return $post_id;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-the-events-calendar.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-the-events-calendar.php
new file mode 100644
index 00000000..d36f448b
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-the-events-calendar.php
@@ -0,0 +1,371 @@
+get_id() );
+ $duration = self::get_duration( $activitypub_event );
+ $venue_id = self::add_venue( $activitypub_event, $event_source_post_id );
+ $organizer_id = self::add_organizer( $activitypub_event );
+
+ $args = array(
+ 'title' => $activitypub_event->get_name(),
+ 'content' => $activitypub_event->get_content() ?? '',
+ 'start_date' => gmdate( 'Y-m-d H:i:s', strtotime( $activitypub_event->get_start_time() ) ),
+ 'duration' => $duration,
+ 'status' => 'publish',
+ 'guid' => $activitypub_event->get_id(),
+ );
+
+ if ( $venue_id ) {
+ $args['venue'] = $venue_id;
+ $args['VenueID'] = $venue_id;
+ }
+
+ if ( $organizer_id ) {
+ $args['organizer'] = $organizer_id;
+ $args['OrganizerID'] = $organizer_id;
+ }
+
+ if ( $activitypub_event->get_published() ) {
+ $post_date = self::format_time_string_to_wordpress_gmt( $activitypub_event->get_published() );
+ $args['post_date'] = $post_date;
+ $args['post_date_gmt'] = $post_date;
+ }
+
+ $tribe_event = new The_Events_Calendar_Event_Repository();
+
+ if ( $post_id ) {
+ $post = $tribe_event->where( 'id', $post_id )->set_args( $args )->save();
+ } else {
+ $post = $tribe_event->set_args( $args )->create();
+ }
+
+ if ( $post instanceof \WP_Post ) {
+ $post_id = $post->ID;
+ }
+
+ if ( ! $post_id ) {
+ return false;
+ }
+
+ // Insert featured image.
+ $image = self::get_featured_image( $activitypub_event );
+ if ( isset( $image['url'] ) ) {
+ self::set_featured_image_with_alt( $post_id, $image['url'], $image['alt'] );
+ }
+
+ // Add tags.
+ self::add_tags_to_post( $activitypub_event, $post_id );
+
+ // Remove revision limit.
+ remove_filter( 'wp_revisions_to_keep', array( self::class, 'revisions_to_keep' ) );
+
+ return $post_id;
+ }
+
+ /**
+ * Map an ActivityStreams Place to the Events Calendar venue.
+ *
+ * @param array|Place $location An ActivityPub location as an associative array or Place object.
+ * @link https://www.w3.org/TR/activitystreams-vocabulary/#dfn-place
+ * @return array
+ */
+ private static function get_venue_args( $location ): array {
+ $args = array(
+ 'venue' => $location['name'],
+ 'status' => 'publish',
+ );
+
+ if ( $location instanceof Place ) {
+ $location = $location->to_array();
+ }
+
+ if ( ! isset( $location['address'] ) ) {
+ return $args;
+ }
+
+ if ( is_array( $location['address'] ) ) {
+ $mapping = array(
+ 'streetAddress' => 'address',
+ 'postalCode' => 'zip',
+ 'addressLocality' => 'city',
+ 'addressState' => 'state',
+ 'addressCountry' => 'country',
+ 'url' => 'website',
+ );
+
+ foreach ( $mapping as $postal_address_key => $venue_key ) {
+ if ( isset( $location['address'][ $postal_address_key ] ) ) {
+ $args[ $venue_key ] = $location['address'][ $postal_address_key ];
+ }
+ }
+ } elseif ( is_string( $location['address'] ) ) {
+ // Use the address field for a solely text address.
+ $args['address'] = $location['address'];
+ }
+
+ if ( isset( $location['id'] ) ) {
+ $args['guid'] = $location['id'];
+ }
+
+ return $args;
+ }
+
+ /**
+ * Add venue.
+ *
+ * @param Event $activitypub_event The ActivityPub event object.
+ * @param int $event_source_post_id The WordPress Post ID of the event source.
+ *
+ * @return ?int $post_id The venues post ID.
+ */
+ private static function add_venue( $activitypub_event, $event_source_post_id ): ?int {
+ $location = $activitypub_event->get_location();
+
+ // Make sure we have a valid location in the right format.
+ if ( ! $location ) {
+ return null;
+ }
+
+ if ( $location instanceof Place ) {
+ $location = $location->to_array();
+ }
+
+ if ( ! is_array( $location ) ) {
+ return null;
+ }
+
+ if ( ! isset( $location['name'] ) ) {
+ return null;
+ }
+
+ // Fallback for Gancio instances.
+ if ( 'online' === $location['name'] ) {
+ return null;
+ }
+
+ $tribe_venue = new The_Events_Calendar_Venue_Repository();
+
+ // If the venue already exists try to find it's post id.
+ $post_id = null;
+
+ // Search if we already got this venue/place in our database.
+ if ( isset( $location['id'] ) ) {
+ global $wpdb;
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery
+ $post_id = $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT ID FROM $wpdb->posts WHERE guid=%s AND post_type=%s",
+ $location['id'],
+ \Tribe__Events__Venue::POSTTYPE
+ )
+ );
+ if ( $post_id ) {
+ $post_id = (int) $post_id;
+ }
+ }
+
+ if ( ! $post_id ) {
+ // Try to find a match by searching.
+ $results = $tribe_venue->search( $location['name'] )->all();
+
+ foreach ( $results as $potential_matching_post_id ) {
+ // @phpstan-ignore-next-line
+ if ( $potential_matching_post_id instanceof \WP_Post ) {
+ $potential_matching_post_id = $potential_matching_post_id->ID;
+ }
+ // Only accept a match for the venue/location if it was received by the same actor.
+ if ( \get_post_meta( $potential_matching_post_id, '_event_bridge_for_activitypub_event_source', true ) === $event_source_post_id ) {
+ $post_id = $potential_matching_post_id;
+ break;
+ }
+ }
+ }
+
+ if ( $post_id ) {
+ // Update if we found a match.
+ $result = $tribe_venue->where( 'id', $post_id )->set_args( self::get_venue_args( $location ) )->save();
+ if ( array_key_exists( $post_id, $result ) && $result[ $post_id ] ) {
+ return $post_id;
+ }
+ } else {
+ // Create a new venue.
+ $post = $tribe_venue->set_args( self::get_venue_args( $location ) )->create();
+ if ( $post ) {
+ $post_id = $post->ID;
+ update_post_meta( $post_id, '_event_bridge_for_activitypub_event_source', $event_source_post_id );
+ }
+ }
+
+ return $post_id;
+ }
+
+ /**
+ * Add organizer.
+ *
+ * @param Event $activitypub_event The ActivityPub event object.
+ *
+ * @return int|bool $post_id The organizers post ID.
+ */
+ private static function add_organizer( $activitypub_event ) {
+ // This might likely change, because of FEP-8a8e.
+ $actor = $activitypub_event->get_attributed_to();
+
+ if ( is_null( $actor ) ) {
+ return false;
+ }
+
+ $actor_id = object_to_uri( $actor );
+ $event_source = Event_Source::get_by_id( $actor_id );
+
+ // As long as we do not support announces, we expect the attributedTo to be an existing event source.
+ if ( ! $event_source ) {
+ return false;
+ }
+
+ // Prepare arguments for inserting/updating the organizer post.
+ $args = array(
+ 'organizer' => $event_source->get_name(),
+ 'description' => $event_source->get_summary(),
+ 'website' => $event_source->get_url(),
+ 'excerpt' => $event_source->get_summary(),
+ 'post_parent' => $event_source->get__id(), // Maybe just use post meta too here.
+ );
+
+ if ( $event_source->get_published() ) {
+ $post_date = self::format_time_string_to_wordpress_gmt( $event_source->get_published() );
+ $args['post_date'] = $post_date;
+ $args['post_date_gmt'] = $post_date;
+ }
+
+ // Get organizer if it is already present.
+ $children = \get_children(
+ array(
+ 'post_parent' => $event_source->get__id(),
+ 'post_type' => \Tribe__Events__Organizer::POSTTYPE,
+ ),
+ );
+
+ if ( count( $children ) ) {
+ // Update organizer post.
+ $child = array_pop( $children );
+ $tribe_organizer_post_ids = \tribe_organizers()->where( 'id', $child->ID )->set_args( $args )->save();
+
+ // Fallback to delete duplicates.
+ foreach ( $children as $to_delete ) {
+ \wp_delete_post( $to_delete->ID, true );
+ }
+
+ // If updating failed return.
+ if ( 1 !== count( $tribe_organizer_post_ids ) || ! reset( $tribe_organizer_post_ids ) ) {
+ return false;
+ }
+
+ $tribe_organizer_post_id = array_key_first( $tribe_organizer_post_ids );
+ } else {
+ // Create new organizer post.
+ $tribe_organizer_post = \tribe_organizers()->set_args( $args )->create();
+
+ if ( ! $tribe_organizer_post ) {
+ return false;
+ }
+
+ $tribe_organizer_post_id = $tribe_organizer_post->ID;
+
+ // Make a relationship between the event source WP_Post and the organizer WP_Post.
+ \update_post_meta( $tribe_organizer_post_id, '_event_bridge_for_activitypub_event_source', true );
+ }
+
+ // Add the thumbnail of the event source to the organizer.
+ if ( \get_post_thumbnail_id( $event_source->get__id() ) ) {
+ \set_post_thumbnail( $tribe_organizer_post_id, \get_post_thumbnail_id( $event_source->get__id() ) );
+ }
+
+ return $tribe_organizer_post_id;
+ }
+
+ /**
+ * Add tags to post.
+ *
+ * @param Event $activitypub_event The ActivityPub event object.
+ * @param int $post_id The post ID.
+ */
+ private static function add_tags_to_post( $activitypub_event, $post_id ): bool {
+ $tags_array = $activitypub_event->get_tag();
+
+ // Ensure the input is valid.
+ if ( empty( $tags_array ) || ! is_array( $tags_array ) || ! $post_id ) {
+ return false;
+ }
+
+ // Extract and process tag names.
+ $tag_names = array();
+ foreach ( $tags_array as $tag ) {
+ if ( isset( $tag['name'] ) && 'Hashtag' === $tag['type'] ) {
+ $tag_names[] = ltrim( $tag['name'], '#' ); // Remove the '#' from the name.
+ }
+ }
+
+ // Add the tags as terms to the post.
+ if ( ! empty( $tag_names ) ) {
+ \wp_set_object_terms( $post_id, $tag_names, 'post_tag', true );
+ }
+
+ return true;
+ }
+
+ /**
+ * Get the events duration in seconds.
+ *
+ * @param Event $activitypub_event The ActivityPub event object.
+ *
+ * @return int
+ */
+ private static function get_duration( $activitypub_event ): int {
+ $end_time = $activitypub_event->get_end_time();
+ if ( ! $end_time ) {
+ return 2 * HOUR_IN_SECONDS;
+ }
+ return abs( strtotime( $end_time ) - strtotime( $activitypub_event->get_start_time() ) );
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-vs-event-list.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-vs-event-list.php
new file mode 100644
index 00000000..bb738b37
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-vs-event-list.php
@@ -0,0 +1,175 @@
+to_array();
+ }
+
+ // Return empty string when location is not an associative array.
+ if ( ! is_array( $location ) || 0 === count( $location ) ) {
+ return $location_string;
+ }
+
+ if ( ! isset( $location['type'] ) || 'Place' !== $location['type'] ) {
+ return $location_string;
+ }
+
+ // Add name of the location.
+ if ( isset( $location['name'] ) ) {
+ $location_string .= $location['name'];
+ }
+
+ // Add delimiter between name and address if both are set.
+ if ( isset( $location['name'] ) && isset( $location['address'] ) ) {
+ $location_string .= ' – ';
+ }
+
+ // Add address.
+ if ( isset( $location['address'] ) ) {
+ $location_string .= self::address_to_string( $location['address'] );
+ }
+ return $location_string;
+ }
+
+ /**
+ * Add tags to post.
+ *
+ * @param Event $activitypub_event The ActivityPub event object.
+ * @param int $post_id The post ID.
+ */
+ private static function add_tags_to_post( $activitypub_event, $post_id ) {
+ $tags_array = $activitypub_event->get_tag();
+
+ // Ensure the input is valid.
+ if ( empty( $tags_array ) || ! is_array( $tags_array ) || ! $post_id ) {
+ return false;
+ }
+
+ // Extract and process tag names.
+ $tag_names = array();
+ foreach ( $tags_array as $tag ) {
+ if ( isset( $tag['name'] ) && 'Hashtag' === $tag['type'] ) {
+ $tag_names[] = ltrim( $tag['name'], '#' ); // Remove the '#' from the name.
+ }
+ }
+
+ // Add the tags as terms to the post.
+ if ( ! empty( $tag_names ) ) {
+ \wp_set_object_terms( $post_id, $tag_names, IntegrationsVS_Event_List::get_event_category_taxonomy(), true );
+ }
+
+ return true;
+ }
+
+ /**
+ * Save the ActivityPub event object as VS Event List event.
+ *
+ * @param Event $activitypub_event The ActivityPub event object.
+ * @param int $event_source_post_id The Post ID of the Event Source that owns the outbox.
+ *
+ * @return false|int
+ */
+ protected static function save_event( $activitypub_event, $event_source_post_id ) {
+ // Limit this as a safety measure.
+ \add_filter( 'wp_revisions_to_keep', array( self::class, 'revisions_to_keep' ) );
+
+ $post_id = self::get_post_id_from_activitypub_id( $activitypub_event->get_id() );
+
+ $args = array(
+ 'post_title' => $activitypub_event->get_name(),
+ 'post_type' => \Event_Bridge_For_ActivityPub\Integrations\VS_Event_List::get_post_type(),
+ 'post_content' => $activitypub_event->get_content() ?? '',
+ 'post_excerpt' => $activitypub_event->get_summary() ?? '',
+ 'post_status' => 'publish',
+ 'guid' => $activitypub_event->get_id(),
+ 'meta_input' => array(
+ 'event-start-date' => \strtotime( $activitypub_event->get_start_time() ),
+ 'event-link' => $activitypub_event->get_url() ?? $activitypub_event->get_id(),
+ 'event-link-label' => \sanitize_text_field( __( 'Original Website', 'event-bridge-for-activitypub' ) ),
+ 'event-link-target' => 'yes', // Open in new window.
+ 'event-link-title' => 'no', // Whether to redirect event title to original source.
+ 'event-link-image' => 'no', // Whether to redirect events featured image to original source.
+ ),
+ );
+
+ if ( $activitypub_event->get_published() ) {
+ $post_date = self::format_time_string_to_wordpress_gmt( $activitypub_event->get_published() );
+ $args['post_date'] = $post_date;
+ $args['post_date_gmt'] = $post_date;
+ }
+
+ // Add end time.
+ $end_time = $activitypub_event->get_end_time();
+ if ( $end_time ) {
+ $args['meta_input']['event-date'] = \strtotime( $end_time );
+ }
+
+ // Maybe add location.
+ $location = self::get_location_as_string( $activitypub_event->get_location() );
+ if ( $location ) {
+ $args['meta_input']['event-location'] = $location;
+ }
+
+ if ( $post_id ) {
+ // Update existing event post.
+ $args['ID'] = $post_id;
+ $post_id = \wp_update_post( $args );
+ } else {
+ // Insert new event post.
+ $post_id = \wp_insert_post( $args );
+ }
+
+ // @phpstan-ignore-next-line
+ if ( 0 === $post_id || \is_wp_error( $post_id ) ) {
+ return false;
+ }
+
+ // Insert featured image.
+ $image = self::get_featured_image( $activitypub_event );
+ self::set_featured_image_with_alt( $post_id, $image['url'], $image['alt'] );
+
+ // Add hashtags.
+ self::add_tags_to_post( $activitypub_event, $post_id );
+
+ // Limit this as a safety measure.
+ \remove_filter( 'wp_revisions_to_keep', array( self::class, 'revisions_to_keep' ) );
+
+ return $post_id;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-sanitizer.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-sanitizer.php
new file mode 100644
index 00000000..aae19039
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-sanitizer.php
@@ -0,0 +1,241 @@
+ 404 ) );
+ }
+
+ $event = new Event();
+
+ // Straightforward sanitization of all attributes we possible make use of.
+ if ( isset( $data['content'] ) ) {
+ $event->set_content( \wp_kses_post( $data['content'] ) );
+ }
+
+ if ( isset( $data['summary'] ) ) {
+ $event->set_summary( \wp_kses_post( $data['summary'] ) );
+ }
+
+ if ( isset( $data['name'] ) ) {
+ $event->set_name( \sanitize_text_field( $data['name'] ) );
+ }
+
+ if ( isset( $data['startTime'] ) ) {
+ $event->set_start_time( \sanitize_text_field( $data['startTime'] ) );
+ }
+
+ if ( isset( $data['endTime'] ) ) {
+ $event->set_end_time( \sanitize_text_field( $data['endTime'] ) );
+ }
+
+ if ( isset( $data['published'] ) ) {
+ $event->set_published( \sanitize_text_field( $data['published'] ) );
+ }
+
+ if ( isset( $data['id'] ) ) {
+ $event->set_id( \sanitize_url( $data['id'] ) );
+ }
+
+ if ( isset( $data['url'] ) ) {
+ $event->set_url( \sanitize_url( $data['url'] ) );
+ }
+
+ if ( isset( $data['attributedTo'] ) ) {
+ $event->set_attributed_to( self::sanitize_attributed_to( $data['attributedTo'] ) );
+ }
+
+ if ( isset( $data['location'] ) ) {
+ $event->set_location( self::sanitize_place_object_from_array( $data['location'] ) );
+ }
+
+ if ( isset( $data['attachment'] ) ) {
+ $event->set_attachment( self::sanitize_attachment( $data['attachment'] ) );
+ }
+
+ if ( isset( $data['tag'] ) ) {
+ $event->set_tag( self::sanitize_attachment( $data['tag'] ) );
+ }
+
+ return $event;
+ }
+
+ /**
+ * Sanitize attributedTo.
+ *
+ * Currently only multiple attributedTo's are not supported.
+ *
+ * @param mixed $data The object array.
+ *
+ * @return string
+ */
+ private static function sanitize_attributed_to( $data ): string {
+ if ( is_array( $data ) && self::array_is_list( $data ) ) {
+ $data = reset( $data );
+ }
+
+ return object_to_uri( $data );
+ }
+
+ /**
+ * Sanitize attachments.
+ *
+ * @param mixed $data The object array.
+ *
+ * @return ?array
+ */
+ private static function sanitize_attachment( $data ): ?array {
+ if ( ! is_array( $data ) ) {
+ return null;
+ }
+
+ if ( ! self::array_is_list( $data ) ) {
+ $data = array( $data );
+ }
+
+ $attachment = array();
+
+ foreach ( $data as $item ) {
+ $sanitized_item = array();
+
+ // Straightforward sanitization of all attributes we possible make use of.
+ if ( isset( $item['name'] ) ) {
+ $sanitized_item['name'] = \sanitize_text_field( $item['name'] );
+ }
+ if ( isset( $item['url'] ) ) {
+ $sanitized_item['url'] = \sanitize_url( $item['url'] );
+ }
+ if ( isset( $item['id'] ) ) {
+ $sanitized_item['id'] = \sanitize_url( $item['id'] );
+ }
+ if ( isset( $item['type'] ) ) {
+ $sanitized_item['type'] = \sanitize_text_field( $item['type'] );
+ }
+ if ( isset( $item['href'] ) ) {
+ $sanitized_item['href'] = \sanitize_text_field( $item['href'] );
+ }
+
+ if ( isset( $sanitized_item['url'] ) || isset( $sanitized_item['href'] ) || isset( $sanitized_item['name'] ) ) {
+ $attachment[] = $sanitized_item;
+ }
+ }
+
+ return $attachment;
+ }
+
+ /**
+ * Fallback for PHP version prior to 8.1 for array_is_list.
+ *
+ * @param array $arr The array to check.
+ * @return bool
+ */
+ private static function array_is_list( $arr ) {
+ if ( ! function_exists( 'array_is_list' ) ) {
+ if ( array() === $arr ) {
+ return true;
+ }
+ return array_keys( $arr ) === range( 0, count( $arr ) - 1 );
+ }
+ return array_is_list( $arr );
+ }
+
+ /**
+ * Convert input array to an Location.
+ *
+ * @param mixed $data The object array.
+ *
+ * @return ?Place An Object built from the input array or null.
+ */
+ private static function sanitize_place_object_from_array( $data ): ?Place {
+ if ( ! is_array( $data ) ) {
+ return null;
+ }
+
+ // If the array is a list, work with the first item.
+ if ( array_key_exists( 0, $data ) ) {
+ $data = $data[0];
+ }
+
+ $place = new Place();
+
+ if ( isset( $data['name'] ) ) {
+ $place->set_name( \sanitize_text_field( $data['name'] ) );
+ }
+
+ if ( isset( $data['id'] ) ) {
+ $place->set_id( \sanitize_url( $data['id'] ) );
+ }
+
+ if ( isset( $data['url'] ) ) {
+ $place->set_url( \sanitize_url( $data['url'] ) );
+ }
+
+ if ( isset( $data['address'] ) ) {
+ if ( is_string( $data['address'] ) ) {
+ $place->set_address( \sanitize_text_field( $data['address'] ) );
+ }
+ if ( is_array( $data['address'] ) && isset( $data['address']['type'] ) && 'PostalAddress' === $data['address']['type'] ) {
+ $address = array();
+ if ( isset( $data['address']['streetAddress'] ) ) {
+ $address['streetAddress'] = \sanitize_text_field( $data['address']['streetAddress'] );
+ }
+ if ( isset( $data['address']['postalCode'] ) ) {
+ $address['postalCode'] = \sanitize_text_field( $data['address']['postalCode'] );
+ }
+ if ( isset( $data['address']['addressLocality'] ) ) {
+ $address['addressLocality'] = \sanitize_text_field( $data['address']['addressLocality'] );
+ }
+ if ( isset( $data['address']['addressState'] ) ) {
+ $address['addressState'] = \sanitize_text_field( $data['address']['addressState'] );
+ }
+ if ( isset( $data['address']['addressCountry'] ) ) {
+ $address['addressCountry'] = \sanitize_text_field( $data['address']['addressCountry'] );
+ }
+ if ( isset( $data['address']['url'] ) ) {
+ $address['url'] = \sanitize_url( $data['address']['url'] );
+ }
+ $place->set_address( $address );
+ }
+ }
+
+ return $place;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-the-events-calendar-event-repository.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-the-events-calendar-event-repository.php
new file mode 100644
index 00000000..a4f1f846
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-the-events-calendar-event-repository.php
@@ -0,0 +1,43 @@
+event_plugin = $event_plugin;
+ if ( $this->event_post_type_is_not_activitypub_enabled() ) {
+ add_action( 'admin_notices', array( $this, 'admin_notice_activitypub_not_enabled_for_post_type' ), 10, 1 );
+ }
+ }
+
+ /**
+ * Check if ActivityPub is enabled for the custom post type of the event plugin.
+ *
+ * @return bool
+ */
+ private function event_post_type_is_not_activitypub_enabled(): bool {
+ return ! in_array( $this->event_plugin::get_post_type(), get_option( 'activitypub_support_post_types', array() ), true );
+ }
+
+ /**
+ * Display the admin notices for the plugins.
+ *
+ * @return void
+ */
+ public function admin_notice_activitypub_not_enabled_for_post_type(): void {
+ if ( $this->event_plugin::is_plugin_page() ) {
+ $this->do_admin_notice_post_type_not_activitypub_enabled();
+ }
+ }
+
+ /**
+ * Print admin notice that the current post type is not enabled in the ActivityPub plugin.
+ *
+ * @return void
+ */
+ private function do_admin_notice_post_type_not_activitypub_enabled(): void {
+ $all_plugins = get_plugins();
+ $event_plugin_file = $this->event_plugin::get_relative_plugin_file();
+ if ( isset( $all_plugins[ $event_plugin_file ]['Name'] ) ) {
+ $event_plugin_name = $all_plugins[ $event_plugin_file ]['Name'];
+ } elseif ( isset( get_mu_plugins()[ $event_plugin_file ]['Name'] ) ) {
+ $event_plugin_name = get_mu_plugins()[ $event_plugin_file ]['Name'];
+ } else {
+ return;
+ }
+ $activitypub_plugin_data = get_plugin_data( ACTIVITYPUB_PLUGIN_FILE );
+ $notice = sprintf(
+ /* translators: 1: the name of the event plugin a admin notice is shown. 2: The name of the ActivityPub plugin. */
+ _x(
+ 'You have installed the %1$s plugin, but the event post type of the plugin %2$s is not enabled in the %1$s settings.',
+ 'admin notice',
+ 'event-bridge-for-activitypub'
+ ),
+ esc_html( $activitypub_plugin_data['Name'] ),
+ esc_html( $event_plugin_name ),
+ admin_url( 'options-general.php?page=activitypub&tab=settings' )
+ );
+ $allowed_html = array(
+ 'a' => array(
+ 'href' => true,
+ 'title' => true,
+ ),
+ 'b' => array(),
+ 'i' => array(),
+ );
+ echo '' . \wp_kses( $notice, $allowed_html ) . '
';
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/admin/class-general-admin-notices.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/admin/class-general-admin-notices.php
new file mode 100644
index 00000000..6a5302f0
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/admin/class-general-admin-notices.php
@@ -0,0 +1,152 @@
+ array(
+ 'href' => true,
+ 'title' => true,
+ 'target' => true,
+ ),
+ 'br',
+ 'i',
+ );
+
+ /**
+ * Admin notice when the ActivityPub plugin is not enabled.
+ *
+ * @return string
+ */
+ public static function get_admin_notice_activitypub_plugin_not_enabled(): string {
+ return sprintf(
+ /* translators: 1: An URL that points to the ActivityPub plugin. */
+ _x(
+ 'For the Event Bridge for ActivityPub to work, you will need to install and activate the ActivityPub plugin.',
+ 'admin notice',
+ 'event-bridge-for-activitypub'
+ ),
+ esc_html( self::ACTIVITYPUB_PLUGIN_URL )
+ );
+ }
+
+ /**
+ * Admin notice when the ActivityPub plugin version is too old.
+ *
+ * @return string
+ */
+ public static function get_admin_notice_activitypub_plugin_version_too_old(): string {
+ return sprintf(
+ /* translators: 1: The name of the ActivityPub plugin. 2: The minimum required version number of the ActivityPub plugin. */
+ _x(
+ 'Please upgrade your ActivityPub plugin. At least version %2$s is required for the Event Bridge for ActivityPub to work.',
+ 'admin notice',
+ 'event-bridge-for-activitypub'
+ ),
+ esc_html( self::ACTIVITYPUB_PLUGIN_URL ),
+ esc_html( EVENT_BRIDGE_FOR_ACTIVITYPUB_ACTIVITYPUB_PLUGIN_MIN_VERSION )
+ );
+ }
+
+ /**
+ * Warning that no supported event plugin can be found.
+ *
+ * @return string
+ */
+ public static function get_admin_notice_no_supported_event_plugin_active(): string {
+ return sprintf(
+ /* translators: 1: An URL to the list of supported event plugins. */
+ _x(
+ 'The Plugin Event Bridge for ActivityPub is of no use, because you do not have installed and activated a supported Event Plugin.
+
For a list of supported Event Plugins see here.',
+ 'admin notice',
+ 'event-bridge-for-activitypub'
+ ),
+ esc_url( self::EVENT_BRIDGE_FOR_ACTIVITYPUB_SUPPORTED_EVENT_PLUGINS_URL )
+ );
+ }
+
+ /**
+ * Warning to fix status issues first.
+ *
+ * @return string
+ */
+ public static function get_admin_notice_status_not_ok(): string {
+ return sprintf(
+ /* translators: 1: An URL to the list of supported event plugins. */
+ _x(
+ 'The Plugin Event Bridge for ActivityPub is of no use, because you do not have installed and activated a supported Event Plugin.
+
For a list of supported Event Plugins see here.',
+ 'admin notice',
+ 'event-bridge-for-activitypub'
+ ),
+ esc_html( self::EVENT_BRIDGE_FOR_ACTIVITYPUB_SUPPORTED_EVENT_PLUGINS_URL )
+ );
+ }
+
+ /**
+ * Warning if the plugin is Active and the ActivityPub plugin is not.
+ *
+ * @return void
+ */
+ public static function activitypub_plugin_not_enabled(): void {
+ $notice = self::get_admin_notice_activitypub_plugin_not_enabled();
+ // @phpstan-ignore-next-line
+ echo '' . \wp_kses( $notice, self::ALLOWED_HTML ) . '
';
+ }
+
+ /**
+ * Warning if the plugin is Active and the ActivityPub plugins version is too old.
+ *
+ * @return void
+ */
+ public static function activitypub_plugin_version_too_old(): void {
+ $notice = self::get_admin_notice_activitypub_plugin_version_too_old();
+ // @phpstan-ignore-next-line
+ echo '' . \wp_kses( $notice, self::ALLOWED_HTML ) . '
';
+ }
+
+ /**
+ * Warning when no supported Even Plugin is installed and active.
+ *
+ * @return void
+ */
+ public static function no_supported_event_plugin_active(): void {
+ $notice = self::get_admin_notice_no_supported_event_plugin_active();
+ // @phpstan-ignore-next-line
+ echo '' . \wp_kses( $notice, self::ALLOWED_HTML ) . '
';
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/admin/class-health-check.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/admin/class-health-check.php
new file mode 100644
index 00000000..ecf4652d
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/admin/class-health-check.php
@@ -0,0 +1,211 @@
+ __( 'ActivityPub Event Transformer Test', 'event-bridge-for-activitypub' ),
+ 'test' => array( self::class, 'test_event_transformation' ),
+ );
+
+ return $tests;
+ }
+
+ /**
+ * The the transformation of the most recent event posts.
+ *
+ * @return array
+ */
+ public static function test_event_transformation(): array {
+ $result = array(
+ 'label' => \__( 'Transformation of Events to a valid ActivityStreams representation.', 'event-bridge-for-activitypub' ),
+ 'status' => 'good',
+ 'badge' => array(
+ 'label' => \__( 'Event Bridge for ActivityPub', 'event-bridge-for-activitypub' ),
+ 'color' => 'green',
+ ),
+ 'description' => \sprintf(
+ '%s
',
+ \__( 'The transformation to ActivityPub of your most recent events was successful.', 'event-bridge-for-activitypub' )
+ ),
+ 'actions' => '',
+ 'test' => 'test_event_transformation',
+ );
+
+ $check = self::transform_most_recent_event_posts();
+
+ if ( true === $check ) {
+ return $result;
+ }
+
+ $result['status'] = 'critical';
+ $result['label'] = \__( 'One or more of your most recent events failed to transform to ActivityPub', 'event-bridge-for-activitypub' );
+ $result['badge']['color'] = 'red';
+ $result['description'] = \sprintf(
+ '%s
',
+ \__( 'The transformation to ActivityPub of your most recent events was not successful.', 'event-bridge-for-activitypub' )
+ );
+
+ return $result;
+ }
+
+ /**
+ * Test if right transformer gets applied.
+ *
+ * @param Event_Plugin_Integration $event_plugin The event plugin definition.
+ *
+ * @return bool True if the check passed.
+ */
+ public static function test_if_event_transformer_is_used( $event_plugin ): bool {
+ if ( ! Setup::get_instance()->is_activitypub_plugin_active() ) {
+ return false;
+ }
+
+ // Get a (random) event post.
+ $event_posts = self::get_most_recent_event_posts( $event_plugin->get_post_type(), 1 );
+
+ // If no post is found, we can not do this test.
+ if ( isset( $event_posts[0] ) || empty( $event_posts ) ) {
+ return true;
+ }
+
+ // Call the transformer Factory.
+ $transformer = Transformer_Factory::get_transformer( \get_post( $event_posts[0] ) );
+ // Check that we got the right transformer.
+ $desired_transformer_class = $event_plugin::get_activitypub_event_transformer( $event_posts[0] );
+ if ( $transformer instanceof $desired_transformer_class ) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Retrieves the most recently published event posts of a certain event post type.
+ *
+ * @param ?string $event_post_type The post type of the events.
+ * @param ?int $number_of_posts The maximum number of events to return.
+ *
+ * @return \WP_Post[] Array of event posts, or false if none are found.
+ */
+ public static function get_most_recent_event_posts( $event_post_type = null, $number_of_posts = 5 ): array {
+ if ( ! Setup::get_instance()->is_activitypub_plugin_active() ) {
+ return array();
+ }
+
+ if ( ! $event_post_type ) {
+ $active_event_plugins = Setup::get_instance()->get_active_event_plugins();
+ $active_event_plugin = reset( $active_event_plugins );
+ if ( ! $active_event_plugin ) {
+ return array();
+ }
+ $event_post_type = $active_event_plugin->get_post_type();
+ }
+
+ $args = array(
+ 'numberposts' => $number_of_posts,
+ 'category' => 0,
+ 'orderby' => 'date',
+ 'order' => 'DESC',
+ 'include' => array(),
+ 'exclude' => array(),
+ 'meta_query' => array(
+ 'relation' => 'OR',
+ array(
+ 'key' => '_event_bridge_for_activitypub_event_source',
+ 'compare' => 'NOT EXISTS',
+ ),
+ array(
+ 'key' => '_event_bridge_for_activitypub_event_source',
+ 'value' => '',
+ 'compare' => '=',
+ ),
+ ),
+ 'post_type' => $event_post_type,
+ 'suppress_filters' => true,
+ );
+
+ $query = new WP_Query();
+ return $query->query( $args );
+ }
+
+ /**
+ * Transform the most recent event posts.
+ */
+ public static function transform_most_recent_event_posts(): bool {
+ return true;
+ }
+
+ /**
+ * Retrieves information like name and version from active event plugins.
+ */
+ private static function get_info_about_active_event_plugins(): array {
+ $active_event_plugins = Setup::get_instance()->get_active_event_plugins();
+ $info = array();
+ foreach ( $active_event_plugins as $active_event_plugin ) {
+ $event_plugin_file = $active_event_plugin->get_relative_plugin_file();
+ $event_plugin_data = \get_plugin_data( $event_plugin_file );
+
+ $info[] = array(
+ 'event_plugin_name' => $event_plugin_data['Name'],
+ 'event_plugin_version' => $event_plugin_data['Version'],
+ 'event_plugin_file' => $event_plugin_file,
+ );
+ }
+ return $info;
+ }
+
+ /**
+ * 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 extended information.
+ */
+ public static function add_debug_information( $info ): array {
+ $info['event_bridge_for_activitypub'] = array(
+ 'label' => __( 'Event Bridge for ActivityPub', 'event-bridge-for-activitypub' ),
+ 'fields' => array(
+ 'plugin_version' => array(
+ 'label' => __( 'Plugin Version', 'event-bridge-for-activitypub' ),
+ 'value' => EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_VERSION,
+ 'private' => true,
+ ),
+ 'active_event_plugins' => self::get_info_about_active_event_plugins(),
+ ),
+ );
+
+ return $info;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/admin/class-settings-page.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/admin/class-settings-page.php
new file mode 100644
index 00000000..0b58c39b
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/admin/class-settings-page.php
@@ -0,0 +1,280 @@
+ __( 'Event Bridge', 'event-bridge-for-activitypub' ),
+ 'template' => EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . 'templates/settings/tab.php',
+ );
+
+ return $tabs;
+ }
+
+ /**
+ * Checks whether the current request wants to add an event source (ActivityPub follow) and passed on to actual handler.
+ *
+ * @return void
+ */
+ public static function maybe_add_event_source() {
+ if ( ! isset( $_POST['event_bridge_for_activitypub_add_event_source'] ) ) {
+ return;
+ }
+
+ // Check and verify request and check capabilities.
+ if ( ! \wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'event-bridge-for-activitypub_add-event-source-options' ) ) {
+ return;
+ }
+
+ if ( ! \current_user_can( 'manage_options' ) ) {
+ return;
+ }
+
+ $event_source = \sanitize_text_field( $_POST['event_bridge_for_activitypub_add_event_source'] );
+
+ $actor_url = false;
+ $url = \wp_parse_url( $event_source );
+
+ $error_message = \esc_html__( 'Failed to add Event Source', 'event-bridge-for-activitypub' );
+
+ // Check if URL is a Collection or a single Actor.
+ $maybe_collection = \wp_safe_remote_get( $event_source );
+
+ if ( ! \is_wp_error( $maybe_collection ) ) {
+ $maybe_collection = \json_decode( \wp_remote_retrieve_body( $maybe_collection ), true );
+ }
+
+ $event_sources = array();
+
+ if ( isset( $maybe_collection['type'] ) && in_array( $maybe_collection['type'], array( 'Collection', 'OrderedCollection' ), true ) ) {
+ // Return only the IDs of the items in the collection.
+ $event_sources = \wp_list_pluck( $maybe_collection['items'], 'id' );
+ } else {
+ $event_sources[] = $event_source;
+ }
+
+ // Iterate over all event sources and add them to the collection.
+ foreach ( $event_sources as $event_source ) {
+ $url = \wp_parse_url( $event_source );
+
+ if ( isset( $url['path'], $url['host'], $url['scheme'] ) ) {
+ $actor_url = \sanitize_url( $event_source );
+ } elseif ( preg_match( '/^@?' . Event_Source::ACTIVITYPUB_USER_HANDLE_REGEXP . '$/i', $event_source ) ) {
+ $actor_url = Webfinger::resolve( $event_source );
+ if ( \is_wp_error( $actor_url ) ) {
+ \add_settings_error(
+ 'event-bridge-for-activitypub_add-event-source',
+ 'event_bridge_for_activitypub_cannot_follow_actor',
+ $error_message . ': ' . esc_html__( 'Cannot find an ActivityPub actor for this user handle via Webfinger.', 'event-bridge-for-activitypub' ),
+ 'error'
+ );
+ continue;
+ }
+ } else {
+ if ( ! isset( $url['path'] ) && isset( $url['host'] ) ) {
+ $actor_url = Event_Sources::get_application_actor( $url['host'] );
+ } elseif ( self::is_domain( $event_source ) ) {
+ $actor_url = Event_Sources::get_application_actor( $event_source );
+ }
+ if ( ! $actor_url ) {
+ \add_settings_error(
+ 'event-bridge-for-activitypub_add-event-source',
+ 'event_bridge_for_activitypub_cannot_follow_actor',
+ $error_message . ': ' . \esc_html__( 'Unable to identify the ActivityPub relay actor to follow for this domain.', 'event-bridge-for-activitypub' ),
+ 'error'
+ );
+ continue;
+ }
+ }
+
+ if ( ! $actor_url ) {
+ \add_settings_error(
+ 'event-bridge-for-activitypub_add-event-source',
+ 'event_bridge_for_activitypub_cannot_follow_actor',
+ $error_message . ': ' . \esc_html__( 'ActivityPub actor does not exist.', 'event-bridge-for-activitypub' ),
+ 'error'
+ );
+ continue;
+ }
+
+ // Don't proceed if on the same host!
+ if ( \wp_parse_url( \home_url(), PHP_URL_HOST ) === \wp_parse_url( $actor_url, PHP_URL_HOST ) ) {
+ \add_settings_error(
+ 'event-bridge-for-activitypub_add-event-source',
+ 'event_bridge_for_activitypub_cannot_follow_actor',
+ $error_message . ': ' . \esc_html__( 'Cannot follow own actor on own domain.', 'event-bridge-for-activitypub' ),
+ 'error'
+ );
+ continue;
+ }
+
+ Event_Source_Collection::add_event_source( $actor_url );
+ }
+ }
+
+ /**
+ * Check if a string is a valid domain name.
+ *
+ * @param string $domain The input string which might be a domain.
+ * @return bool
+ */
+ private static function is_domain( $domain ): bool {
+ $pattern = '/^(?!\-)(?:(?:[a-zA-Z\d](?:[a-zA-Z\d\-]{0,61}[a-zA-Z\d])?)\.)+(?!\d+$)[a-zA-Z\d]{2,63}$/';
+ return 1 === preg_match( $pattern, $domain );
+ }
+
+ /**
+ * Adds Link to the settings page in the plugin page.
+ * It's called via apply_filter('plugin_action_links_' . PLUGIN_NAME).
+ *
+ * @param array $links Already added links.
+ *
+ * @return array Original links but with link to setting page added.
+ */
+ public static function settings_link( $links ): array {
+ $links[] = \sprintf(
+ '%2s',
+ \add_query_arg( 'tab', 'event-bridge-for-activitypub', \menu_page_url( 'activitypub', false ) ),
+ \__( 'Settings', 'event-bridge-for-activitypub' )
+ );
+
+ return $links;
+ }
+
+ /**
+ * Receive the event categories (terms) used by the event plugin.
+ *
+ * @param Event_Plugin_Integration $event_plugin Contains info about a certain event plugin.
+ *
+ * @return array An array of Terms.
+ */
+ private static function get_event_terms( $event_plugin ): array {
+ $taxonomy = $event_plugin::get_event_category_taxonomy();
+ if ( $taxonomy ) {
+ $event_terms = get_terms(
+ array(
+ 'taxonomy' => $taxonomy,
+ 'hide_empty' => true,
+ )
+ );
+ return ! is_wp_error( $event_terms ) ? $event_terms : array();
+ } else {
+ return array();
+ }
+ }
+
+ /**
+ * Preparing the data and loading the template for the settings page.
+ *
+ * @return void
+ */
+ public static function do_settings_page(): void {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ if ( empty( $_GET['subpage'] ) ) {
+ $tab = 'welcome';
+ } else {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ $tab = \sanitize_key( $_GET['subpage'] );
+ }
+
+ // Fallback to always re-scan active event plugins, when user visits admin area of this plugin.
+ $plugin_setup = Setup::get_instance();
+ $plugin_setup->redetect_active_event_plugins();
+ $event_plugins = $plugin_setup->get_active_event_plugins();
+
+ switch ( $tab ) {
+ case 'settings':
+ $event_terms = array();
+
+ foreach ( $event_plugins as $event_plugin_integration ) {
+ $event_terms = array_merge( $event_terms, self::get_event_terms( $event_plugin_integration ) );
+ }
+
+ $args = array(
+ 'slug' => self::SETTINGS_SLUG,
+ 'event_terms' => $event_terms,
+ );
+
+ \load_template( EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . 'templates/settings/subpages/settings.php', true, $args );
+ break;
+ case 'event-sources':
+ $supports_event_sources = array();
+
+ foreach ( $event_plugins as $event_plugin_integration ) {
+ if ( is_a( $event_plugin_integration, Feature_Event_Sources::class ) ) {
+ $class_name = get_class( $event_plugin_integration );
+ $supports_event_sources[ $class_name ] = $event_plugin_integration::get_plugin_name();
+ }
+ }
+
+ $args = array(
+ 'supports_event_sources' => $supports_event_sources,
+ );
+
+ \wp_enqueue_script( 'thickbox' );
+ \wp_enqueue_style( 'thickbox' );
+ \load_template( EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . 'templates/settings/subpages/event-sources.php', true, $args );
+ break;
+ case 'welcome':
+ default:
+ \wp_enqueue_script( 'plugin-install' );
+ \add_thickbox();
+ \wp_enqueue_script( 'updates' );
+
+ \load_template( EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . 'templates/settings/subpages/welcome.php', true );
+ break;
+ }
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/admin/class-user-interface.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/admin/class-user-interface.php
new file mode 100644
index 00000000..9d673a2e
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/admin/class-user-interface.php
@@ -0,0 +1,100 @@
+guid;
+
+ $parent = get_post_parent();
+
+ if ( $parent && Event_Sources_Collection::POST_TYPE === $parent->post_type ) {
+ $url = \get_post_meta( $parent->ID, '_activitypub_actor_id', true );
+ }
+
+ $actions['view_origin'] = sprintf(
+ '⁂ %s',
+ \esc_url( $url ),
+ \esc_html__( 'Open original page', 'event-bridge-for-activitypub' )
+ );
+
+ return $actions;
+ }
+
+ /**
+ * Modify the user capabilities so that nobody can edit external events.
+ *
+ * @param array $caps Concerned user's capabilities.
+ * @param mixed $cap Required primitive capabilities for the requested capability.
+ * @param array $user_id The WordPress user ID.
+ * @param array $args Additional args.
+ *
+ * @return array
+ */
+ public static function disable_editing_for_external_events( $caps, $cap, $user_id, $args ) {
+ if ( 'edit_post' === $cap && isset( $args[0] ) ) {
+ $post_id = $args[0];
+ $post = get_post( $post_id );
+ if ( $post && Event_Sources::is_cached_external_post( $post ) ) {
+ // Deny editing by returning 'do_not_allow'.
+ return array( 'do_not_allow' );
+ }
+ }
+ return $caps;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-autoloader.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-autoloader.php
new file mode 100644
index 00000000..40f99cdf
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-autoloader.php
@@ -0,0 +1,67 @@
+get_active_event_plugins() as $event_plugin_integration ) {
+ if ( ! is_a( $event_plugin_integration, Feature_Event_Sources::class ) ) {
+ continue;
+ }
+
+ $post_type = $event_plugin_integration::get_post_type();
+ self::register_post_meta_event_bridge_for_activitypub_event_source( $post_type );
+
+ $post_type = $event_plugin_integration::get_place_post_type();
+ if ( $post_type ) {
+ self::register_post_meta_event_bridge_for_activitypub_event_source( $post_type );
+ }
+
+ $post_type = $event_plugin_integration::get_organizer_post_type();
+ if ( $post_type ) {
+ self::register_post_meta_event_bridge_for_activitypub_event_source( $post_type );
+ }
+ }
+ }
+
+ /**
+ * Register post meta _event_bridge_for_activitypub_event_source for a given post type.
+ *
+ * @param string $post_type The post type to register the meta for.
+ * @return void
+ */
+ private static function register_post_meta_event_bridge_for_activitypub_event_source( $post_type ) {
+ \register_post_meta(
+ $post_type,
+ '_event_bridge_for_activitypub_event_source',
+ array(
+ 'type' => 'integer',
+ 'single' => true,
+ 'sanitize_callback' => 'absint',
+ )
+ );
+ }
+
+ /**
+ * Get the Application actor via FEP-2677.
+ *
+ * @param string $domain The domain without scheme.
+ * @return bool|string The URL/ID of the application actor, false if not found.
+ */
+ public static function get_application_actor( $domain ) {
+ $result = wp_remote_get( 'https://' . $domain . '/.well-known/nodeinfo' );
+
+ if ( is_wp_error( $result ) ) {
+ return false;
+ }
+
+ $body = wp_remote_retrieve_body( $result );
+
+ $nodeinfo = json_decode( $body, true );
+
+ // Check if 'links' exists and is an array.
+ if ( isset( $nodeinfo['links'] ) && is_array( $nodeinfo['links'] ) ) {
+ foreach ( $nodeinfo['links'] as $link ) {
+ // Check if this link matches the application actor rel.
+ if ( isset( $link['rel'] ) && 'https://www.w3.org/ns/activitystreams#Application' === $link['rel'] ) {
+ if ( is_string( $link['href'] ) ) {
+ return $link['href'];
+ }
+ break;
+ }
+ }
+ }
+
+ // Return false if no application actor is found.
+ return false;
+ }
+
+ /**
+ * Filter that cached external posts are not scheduled via the ActivityPub plugin.
+ *
+ * Posts that are actually just external events are treated as cache. They are displayed in
+ * the frontend HTML view and redirected via ActivityPub request, but we do not own them.
+ *
+ * @param bool $disabled If it is disabled already by others (the upstream ActivityPub plugin).
+ * @param WP_Post $post The WordPress post object.
+ * @return bool False if the post is not disabled for federation via ActivityPub.
+ */
+ public static function is_post_disabled_for_activitypub( $disabled, $post = null ): bool {
+ if ( $disabled ) {
+ return $disabled;
+ }
+ return self::is_cached_external_post( $post );
+ }
+
+ /**
+ * Determine whether a WP post is a cached external event.
+ *
+ * @param WP_Post|int $post The WordPress post object or post ID.
+ * @return bool
+ */
+ public static function is_cached_external_post( $post ): bool {
+ $post_id = $post instanceof WP_Post ? $post->ID : $post;
+
+ if ( \get_post_meta( $post_id, '_event_bridge_for_activitypub_event_source', true ) ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Add the ActivityPub template for EventPrime.
+ *
+ * @param string $template The path to the template object.
+ * @return string The new path to the JSON template.
+ */
+ public static function redirect_activitypub_requests_for_cached_external_events( $template ) {
+ if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
+ return $template;
+ }
+
+ if ( ! is_activitypub_request() ) {
+ return $template;
+ }
+
+ if ( ! \is_singular() ) {
+ return $template;
+ }
+
+ $post = \get_post( \get_queried_object_id() );
+
+ if ( self::is_cached_external_post( $post ) ) {
+ \wp_safe_redirect( $post->guid, 301 );
+ exit;
+ }
+
+ return $template;
+ }
+
+ /**
+ * Delete old cached events that took place in the past.
+ */
+ public static function clear_cache() {
+ // Get the event plugin integration that is used.
+ $event_plugin_integration = Setup::get_event_plugin_integration_used_for_event_sources_feature();
+
+ if ( ! $event_plugin_integration ) {
+ return;
+ }
+
+ $cache_retention_period = get_option( 'event_bridge_for_activitypub_event_source_cache_retention', WEEK_IN_SECONDS );
+
+ $ended_before_time = gmdate( 'Y-m-d H:i:s', time() - $cache_retention_period );
+
+ $past_event_ids = $event_plugin_integration::get_cached_remote_events( $ended_before_time );
+
+ foreach ( $past_event_ids as $post_id ) {
+ if ( has_post_thumbnail( $post_id ) ) {
+ $attachment_id = get_post_thumbnail_id( $post_id );
+ wp_delete_attachment( $attachment_id, true );
+ }
+ wp_delete_post( $post_id, true );
+ }
+ }
+
+ /**
+ * Add the Blog Authors to the following list of the Blog Actor
+ * if Blog not in single mode.
+ *
+ * @param array $follow_list The array of following urls.
+ * @param mixed $user The user object, a subtype of \Activitypub\Model\User.
+ *
+ * @return array The array of following urls.
+ */
+ public static function add_event_sources_to_follow_collection( $follow_list, $user ): array {
+ if ( ! $user instanceof Blog ) {
+ return $follow_list;
+ }
+
+ $event_sources_activitypub_ids = array_values( Event_Sources_Collection::get_event_sources() );
+
+ return array_merge( $follow_list, $event_sources_activitypub_ids );
+ }
+
+ /**
+ * Get an array will all unique hosts of all Event-Sources.
+ *
+ * @return array A list with all unique hosts of all Event Sources' ActivityPub IDs.
+ */
+ public static function get_event_sources_hosts() {
+ $hosts = get_transient( 'event_bridge_for_activitypub_event_sources_hosts' );
+
+ if ( $hosts ) {
+ return $hosts;
+ }
+
+ $event_sources = Event_Sources_Collection::get_event_sources();
+
+ $hosts = array();
+ foreach ( $event_sources as $actor ) {
+ $url = wp_parse_url( $actor );
+ if ( isset( $url['host'] ) ) {
+ $hosts[] = $url['host'];
+ }
+ }
+
+ $hosts = array_unique( $hosts );
+
+ set_transient( 'event_bridge_for_activitypub_event_sources_hosts', $hosts );
+
+ return $hosts;
+ }
+
+ /**
+ * Add Event Sources hosts to allowed hosts used by safe redirect.
+ *
+ * @param array $hosts The hosts before the filter.
+ * @return array
+ */
+ public static function add_event_sources_hosts_to_allowed_redirect_hosts( $hosts ) {
+ $event_sources_hosts = self::get_event_sources_hosts();
+ return array_merge( $hosts, $event_sources_hosts );
+ }
+
+ /**
+ * Mark incoming accept activities as valid.
+ *
+ * @param bool $valid The validation state.
+ * @param string $param The object parameter.
+ * @param WP_REST_Request $request The request object.
+ *
+ * @return bool|WP_Error The validation state: true if valid, false if not.
+ */
+ public static function validate_activity( $valid, $param, $request ) {
+ if ( $valid ) {
+ return $valid;
+ }
+ $json_params = $request->get_json_params();
+
+ if ( isset( $json_params['object']['type'] ) && in_array( $json_params['object']['type'], array( 'Accept', 'Undo' ), true ) ) {
+ return true;
+ }
+
+ return $valid;
+ }
+
+ /**
+ * Validate the event object.
+ *
+ * @param bool $valid The validation state.
+ * @param string $param The object parameter.
+ * @param WP_REST_Request $request The request object.
+ *
+ * @return bool|WP_Error The validation state: true if valid, false if not.
+ */
+ public static function validate_event_object( $valid, $param, $request ) {
+ $json_params = $request->get_json_params();
+
+ // Check if we should continue with the validation.
+ if ( isset( $json_params['object']['type'] ) && 'Event' === $json_params['object']['type'] ) {
+ $valid = true;
+ } else {
+ return $valid;
+ }
+
+ if ( empty( $json_params['type'] ) ) {
+ return false;
+ }
+
+ if ( empty( $json_params['actor'] ) ) {
+ return false;
+ }
+
+ if ( ! in_array( $json_params['type'], array( 'Create', 'Update', 'Delete', 'Announce' ), true ) ) {
+ return $valid;
+ }
+
+ if ( ! self::is_valid_activitypub_event_object( $json_params['object'] ) ) {
+ return false;
+ }
+
+ if ( ! self::same_host( $json_params['actor'], $json_params['id'], $json_params['object']['id'] ) ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if all provided URLs belong to the same origin (host).
+ *
+ * @param string ...$urls List of URLs to compare.
+ * @return bool True if all URLs have the same host, false otherwise.
+ */
+ public static function same_host( ...$urls ) {
+ if ( empty( $urls ) ) {
+ return false; // No URLs given, can't compare hosts.
+ }
+
+ $first = \wp_parse_url( array_shift( $urls ) );
+ if ( ! isset( $first['host'] ) ) {
+ return false;
+ }
+
+ $first_host = $first['host'];
+
+ foreach ( $urls as $url ) {
+ $result = \wp_parse_url( $url );
+ if ( ! isset( $result['host'] ) ) {
+ return false;
+ }
+
+ if ( $result['host'] !== $first_host ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Check if the object is a valid ActivityPub event.
+ *
+ * @param mixed $event_object The (event) object as an associative array.
+ * @return bool True if the object is an valid ActivityPub Event, false if not.
+ */
+ public static function is_valid_activitypub_event_object( $event_object ): bool {
+ if ( ! is_array( $event_object ) ) {
+ return false;
+ }
+
+ $required = array(
+ 'id',
+ 'startTime',
+ 'name',
+ );
+
+ if ( array_intersect( $required, array_keys( $event_object ) ) !== $required ) {
+ return false;
+ }
+
+ if ( ! self::is_valid_activitypub_time_string( $event_object['startTime'] ) ) {
+ return false;
+ }
+
+ if ( ! self::is_valid_activitypub_id( $event_object['id'] ) ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Validate an ActivityPub ID.
+ *
+ * @link https://www.w3.org/TR/activitypub/#obj-id
+ *
+ * @param string $id The ID to validate.
+ * @return bool
+ */
+ public static function is_valid_activitypub_id( $id ) {
+ return \sanitize_url( $id ) ? true : false;
+ }
+
+ /**
+ * Validate a time string if it is according to the ActivityPub specification.
+ *
+ * @link https://www.w3.org/TR/activitystreams-core/#dates
+ *
+ * @param string $time_string The xsd:datetime string.
+ * @return bool
+ */
+ public static function is_valid_activitypub_time_string( string $time_string ): bool {
+ // Regular expression based on AS2 rules.
+ return 1 === preg_match( '/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2})?(\.\d+)?(Z|[+-]\d{2}:\d{2})$/', $time_string );
+ }
+
+ /**
+ * Check if a given DateTime is already passed.
+ *
+ * @param string|DateTime $time The ActivityPub like time string or DateTime object.
+ * @return bool
+ */
+ public static function is_time_passed( $time ) {
+ if ( ! $time instanceof DateTime ) {
+ // Create a DateTime object from the ActivityPub time string.
+ $time = new DateTime( $time, new DateTimeZone( 'UTC' ) );
+ }
+
+ // Get the current time in UTC.
+ $current_time = new DateTime( 'now', new DateTimeZone( 'UTC' ) );
+
+ // Compare the event time with the current time.
+ return $time < $current_time;
+ }
+
+ /**
+ * Determine whether an Event is an ongoing or future event.
+ *
+ * @param array $event_object The ActivityPub Event as an associative array.
+ * @return bool
+ */
+ public static function is_ongoing_or_future_event( $event_object ) {
+ if ( isset( $event_object['endTime'] ) ) {
+ $time = $event_object['endTime'];
+ } else {
+ $time = new DateTime( $event_object['startTime'], new DateTimeZone( 'UTC' ) );
+ $time->modify( '+3 hours' );
+ }
+ return ! self::is_time_passed( $time );
+ }
+
+ /**
+ * Check that an ActivityPub actor is an event source (i.e. it is followed by the ActivityPub blog actor).
+ *
+ * @param string $actor_id The actor ID.
+ * @return bool True if the ActivityPub actor ID is followed, false otherwise.
+ */
+ public static function actor_is_event_source( $actor_id ) {
+ $event_sources = Event_Sources_Collection::get_event_sources();
+ if ( in_array( $actor_id, $event_sources, true ) ) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-outbox-parser.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-outbox-parser.php
new file mode 100644
index 00000000..f970383e
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-outbox-parser.php
@@ -0,0 +1,282 @@
+get_outbox();
+
+ if ( ! $outbox_url ) {
+ return;
+ }
+
+ // Schedule the import of events via the outbox.
+ self::queue_importing_from_outbox( $outbox_url, $event_source->get__id(), 0 );
+ }
+
+ /**
+ * Import events from an outbox: OrderedCollection or OrderedCollectionPage.
+ *
+ * @param string $url The url of the current page or outbox.
+ * @param int $event_source_post_id The Post ID of the Event Source that owns the outbox.
+ * @return void
+ */
+ public static function import_events_from_outbox( $url, $event_source_post_id ) {
+ $setup = Setup::get_instance();
+ if ( ! $setup->is_activitypub_plugin_active() ) {
+ return;
+ }
+
+ $outbox = self::fetch_outbox( $url );
+
+ if ( ! $outbox ) {
+ return;
+ }
+
+ $current_count = self::get_import_count( $event_source_post_id );
+
+ if ( $current_count >= self::MAX_EVENTS_TO_IMPORT ) {
+ return;
+ }
+
+ // Process orderedItems if they exist (non-paginated outbox).
+ if ( isset( $outbox['orderedItems'] ) && is_array( $outbox['orderedItems'] ) ) {
+ $current_count += self::import_events_from_items(
+ $outbox['orderedItems'],
+ $event_source_post_id,
+ self::MAX_EVENTS_TO_IMPORT - $current_count
+ );
+ }
+
+ self::update_import_count( $event_source_post_id, $current_count );
+
+ // If the count is already exceeded abort here.
+ if ( $current_count >= self::MAX_EVENTS_TO_IMPORT ) {
+ return;
+ }
+
+ // Get next page and if it exists schedule the import of next page.
+ $pagination_url = self::get_pagination_url( $outbox );
+
+ if ( $pagination_url ) {
+ self::queue_importing_from_outbox( $pagination_url, $event_source_post_id );
+ }
+ }
+
+ /**
+ * Check if an Activity is of type Update or Create.
+ *
+ * @param array $activity The Activity as associative array.
+ * @return bool
+ */
+ private static function is_create_or_update_activity( $activity ) {
+ if ( ! isset( $activity['type'] ) ) {
+ return false;
+ }
+ if ( in_array( $activity['type'], array( 'Update', 'Create' ), true ) ) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Parses items from an Collection, OrderedCollection, CollectionPage or OrderedCollectionPage.
+ *
+ * @param array $items The items as an associative array.
+ * @param int $max_items The maximum number of items to parse.
+ * @return array Parsed events from the collection.
+ */
+ private static function parse_outbox_items_for_events( $items, $max_items ) {
+ $parsed_events = array();
+
+ foreach ( $items as $activity ) {
+ // Abort if we have exceeded the maximal events to return.
+ if ( $max_items > 0 && count( $parsed_events ) >= $max_items ) {
+ break;
+ }
+
+ // Check if it is a create or update Activity.
+ if ( ! self::is_create_or_update_activity( $activity ) ) {
+ continue;
+ }
+
+ // If no object is set we cannot process anything.
+ if ( ! isset( $activity['object'] ) ) {
+ continue;
+ }
+
+ // Check if the Event object meets the minimum requirements and is valid.
+ $is_valid_event_object = Event_Sources::is_valid_activitypub_event_object( $activity['object'] );
+ if ( ! $is_valid_event_object ) {
+ continue;
+ }
+
+ // Check if the event is in the future or ongoing.
+ if ( Event_Sources::is_ongoing_or_future_event( $activity['object'] ) ) {
+ $parsed_events[] = $activity['object'];
+ }
+ }
+
+ return $parsed_events;
+ }
+
+ /**
+ * Import events from the items of an outbox.
+ *
+ * @param array $items The items/orderedItems as an associative array.
+ * @param int $event_source_post_id The Post ID of the Event Source that owns the outbox.
+ * @param int $limit The limit of how many events to save locally.
+ * @return int The number of saved events (at least attempted).
+ */
+ private static function import_events_from_items( $items, $event_source_post_id, $limit = -1 ): int {
+ $events = self::parse_outbox_items_for_events( $items, $limit );
+
+ $transmogrifier = Setup::get_transmogrifier();
+
+ if ( ! $transmogrifier ) {
+ return 0;
+ }
+
+ $imported_count = 0;
+
+ foreach ( $events as $event ) {
+ $transmogrifier::save( $event, $event_source_post_id );
+ ++$imported_count;
+ if ( $limit > 0 && $imported_count >= $limit ) {
+ break;
+ }
+ }
+
+ return $imported_count;
+ }
+
+ /**
+ * Schedule the import of events from an outbox OrderedCollection or OrderedCollectionPage.
+ *
+ * @param string $url The url of the current page or outbox.
+ * @param int $event_source_post_id The Post ID of the Event Source that owns the outbox.
+ * @param int $delay The delay of the current time in seconds.
+ * @return bool
+ */
+ private static function queue_importing_from_outbox( $url, $event_source_post_id, $delay = 10 ): bool {
+ $hook = 'event_bridge_for_activitypub_import_events_from_outbox';
+ $args = array( $url, $event_source_post_id );
+
+ if ( \wp_next_scheduled( $hook, $args ) ) {
+ return false;
+ }
+
+ return \wp_schedule_single_event( \time() + $delay, $hook, $args );
+ }
+
+ /**
+ * Get the current import count for the actor.
+ *
+ * @param int $event_source_post_id The Post ID of the Event Source that owns the outbox.
+ * @return int The current count of imported events.
+ */
+ private static function get_import_count( $event_source_post_id ): int {
+ return (int) \get_post_meta( $event_source_post_id, '_event_bridge_for_activitypub_event_count', true );
+ }
+
+ /**
+ * Update the import count for an event source..
+ *
+ * @param int $event_source_post_id The Post ID of the Event Source that owns the outbox.
+ * @param int $count The new count of imported events.
+ * @return void
+ */
+ private static function update_import_count( $event_source_post_id, $count ) {
+ \update_post_meta( $event_source_post_id, '_event_bridge_for_activitypub_event_count', $count );
+ }
+
+ /**
+ * Fetch the outbox from the given URL.
+ *
+ * @param string $url The URL of the outbox.
+ * @return array|null The decoded outbox data, or null if fetching fails.
+ */
+ private static function fetch_outbox( $url ) {
+ $response = Http::get( $url );
+
+ if ( \is_wp_error( $response ) ) {
+ return null;
+ }
+
+ $outbox = \wp_remote_retrieve_body( $response );
+ $outbox = \json_decode( $outbox, true );
+
+ return ( is_array( $outbox ) && isset( $outbox['type'] ) && isset( $outbox['id'] ) ) ? $outbox : null;
+ }
+
+ /**
+ * Get the pagination URL from the outbox.
+ *
+ * @param array $outbox The outbox data.
+ * @return string|null The pagination URL, or null if not found.
+ */
+ private static function get_pagination_url( $outbox ) {
+ // If we are on a collection page simply use the next key.
+ if ( 'OrderedCollectionPage' === $outbox['type'] && ! empty( $outbox['next'] ) && is_string( $outbox['next'] ) ) {
+ return $outbox['next'];
+ }
+
+ // If we still have the ordered collection itself.
+ if ( isset( $outbox['type'] ) && 'OrderedCollection' === $outbox['type'] && isset( $outbox['first'] ) ) {
+ return object_to_uri( $outbox['first'] );
+ }
+
+ return null;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-preview.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-preview.php
new file mode 100644
index 00000000..637947bf
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-preview.php
@@ -0,0 +1,40 @@
+get_active_event_plugins_post_types();
+
+ if ( in_array( \get_post_type(), $event_post_types, true ) ) {
+ return EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . '/templates/event-preview.php';
+ }
+
+ return ACTIVITYPUB_PLUGIN_DIR . '/templates/post-preview.php';
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-reminder.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-reminder.php
new file mode 100644
index 00000000..67153ebe
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-reminder.php
@@ -0,0 +1,192 @@
+ true,
+ 'single' => true,
+ 'type' => 'integer',
+ 'sanitize_callback' => 'absint',
+ )
+ );
+ }
+ }
+
+ /**
+ * Enqueue the block editor assets.
+ */
+ public static function enqueue_editor_assets() {
+ // Check for our supported post types.
+ $current_screen = \get_current_screen();
+ $event_post_types = Setup::get_instance()->get_active_event_plugins_post_types();
+ if ( ! $current_screen || ! in_array( $current_screen->post_type, $event_post_types, true ) ) {
+ return;
+ }
+ $asset_data = include EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . 'build/reminder/plugin.asset.php';
+ $plugin_url = plugins_url( 'build/reminder/plugin.js', EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_FILE );
+ \wp_enqueue_script( 'event-bridge-for-activitypub-reminder', $plugin_url, $asset_data['dependencies'], $asset_data['version'], true );
+
+ // Pass the the default site wide time gap option to the settings block on the events edit page.
+ \wp_localize_script(
+ 'event-bridge-for-activitypub-reminder',
+ 'activityPubEventBridge',
+ array(
+ 'reminderTypeGap' => \get_option( 'event_bridge_for_activitypub_reminder_time_gap', 0 ),
+ )
+ );
+ }
+
+ /**
+ * 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 maybe_schedule_event_reminder( $new_status, $old_status, $post ): void {
+ if ( ! $post instanceof WP_Post ) {
+ return;
+ }
+
+ // At first always unschedule the reminder for this event, it will be added again, in case.
+ self::unschedule_event_reminder( $post->ID );
+
+ // Do not set reminders if post is password protected.
+ if ( \post_password_required( $post ) ) {
+ return;
+ }
+
+ // Only schedule an reminder for event post types.
+ if ( ! Setup::get_instance()->is_event_post_type_of_active_event_plugin( $post->post_type ) ) {
+ return;
+ }
+
+ // Do not schedule a reminder if the event is not published.
+ if ( 'publish' !== $new_status ) {
+ return;
+ }
+
+ // See if a reminder time gap is set for the event individually in the events post-meta.
+ $reminder_time_gap = (int) get_post_meta( $post->ID, 'event_bridge_for_activitypub_reminder_time_gap', true );
+
+ // If not fallback to the global reminder time gap.
+ if ( ! $reminder_time_gap ) {
+ $reminder_time_gap = \get_option( 'event_bridge_for_activitypub_reminder_time_gap', 0 );
+ }
+
+ // Any non positive integer means that this feature is not active for this event post.
+ if ( 0 === $reminder_time_gap || ! is_int( $reminder_time_gap ) ) {
+ return;
+ }
+
+ // Get start time of the event.
+ $event_transformer = Transformer_Factory::get_transformer( $post );
+
+ if ( \is_wp_error( $event_transformer ) || ! $event_transformer instanceof Event_Transformer ) {
+ return;
+ }
+
+ $start_time = $event_transformer->get_start_time();
+ $start_datetime = new DateTime( $start_time );
+ $start_timestamp = $start_datetime->getTimestamp();
+
+ // Get the time when the reminder of the event's start should be sent.
+ $schedule_time = $start_timestamp - $reminder_time_gap;
+
+ // If the reminder time has already passed "now" skip it.
+ if ( $schedule_time < \time() ) {
+ return;
+ }
+
+ // All checks passed: schedule a single event which will trigger the sending of the reminder for this event post.
+ \wp_schedule_single_event( $schedule_time, 'event_bridge_for_activitypub_send_event_reminder', array( $post->ID ) );
+ }
+
+ /**
+ * Unschedule the event reminder.
+ *
+ * @param int $post_id The WordPress post ID of the event post.
+ */
+ public static function unschedule_event_reminder( $post_id ): void {
+ \wp_clear_scheduled_hook( 'event_bridge_for_activitypub_send_event_reminder', array( $post_id ) );
+ }
+
+ /**
+ * Send a reminder for an event post.
+ *
+ * This currently sends an Announce activity.
+ *
+ * @param int $post_id The WordPress post ID of the event post.
+ */
+ public static function send_event_reminder( $post_id ) {
+ $post = \get_post( $post_id );
+
+ $transformer = Transformer_Factory::get_transformer( $post );
+
+ if ( \is_wp_error( $transformer ) || ! $transformer instanceof Event_Transformer ) {
+ return;
+ }
+
+ $actor = $transformer->get_actor_object();
+ $user_id = $actor->get__id();
+
+ if ( $user_id > 0 && is_user_disabled( $user_id ) ) {
+ return;
+ }
+
+ // Add announce of the event to outbox.
+ add_to_outbox( $post, 'Announce', $user_id );
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-settings.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-settings.php
new file mode 100644
index 00000000..e4dca80d
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-settings.php
@@ -0,0 +1,261 @@
+ 'string',
+ 'description' => \__( 'Default standardized federated event category.', 'event-bridge-for-activitypub' ),
+ 'show_in_rest' => true,
+ 'default' => self::DEFAULT_EVENT_CATEGORY,
+ 'sanitize_callback' => array( self::class, 'sanitize_mapped_event_category' ),
+ )
+ );
+
+ \register_setting(
+ 'event-bridge-for-activitypub',
+ 'event_bridge_for_activitypub_event_category_mappings',
+ array(
+ 'type' => 'array',
+ 'description' => \__( 'Define your own custom post template', 'event-bridge-for-activitypub' ),
+ 'default' => array(),
+ 'sanitize_callback' => array( self::class, 'sanitize_event_category_mappings' ),
+ )
+ );
+
+ \register_setting(
+ 'event-bridge-for-activitypub',
+ 'event_bridge_for_activitypub_reminder_time_gap',
+ array(
+ 'type' => 'array',
+ 'description' => \__( 'Time gap in seconds when a reminder is triggered that the event is about to start.', 'event-bridge-for-activitypub' ),
+ 'default' => 0, // Zero leads to this feature being deactivated.
+ 'sanitize_callback' => 'absint',
+ )
+ );
+
+ \register_setting(
+ 'event-bridge-for-activitypub',
+ 'event_bridge_for_activitypub_initially_activated',
+ array(
+ 'type' => 'boolean',
+ 'description' => \__( 'Whether the plugin just got activated for the first time.', 'event-bridge-for-activitypub' ),
+ 'default' => 1,
+ )
+ );
+
+ \register_setting(
+ 'event-bridge-for-activitypub',
+ 'event_bridge_for_activitypub_summary_type',
+ array(
+ 'type' => 'string',
+ 'description' => \__( 'Summary type to use for ActivityStreams', 'event-bridge-for-activitypub' ),
+ 'show_in_rest' => true,
+ 'default' => 'preset',
+ )
+ );
+
+ \register_setting(
+ 'event-bridge-for-activitypub',
+ 'event_bridge_for_activitypub_summary_format',
+ array(
+ 'type' => 'string',
+ 'description' => \__( 'Summary format to use for ActivityStreams', 'event-bridge-for-activitypub' ),
+ 'show_in_rest' => true,
+ 'default' => 'html',
+ )
+ );
+
+ \register_setting(
+ 'event-bridge-for-activitypub',
+ 'event_bridge_for_activitypub_custom_summary',
+ array(
+ 'type' => 'string',
+ 'description' => \__( 'Define your own custom summary template for events', 'event-bridge-for-activitypub' ),
+ 'show_in_rest' => true,
+ 'default' => EVENT_BRIDGE_FOR_ACTIVITYPUB_SUMMARY_TEMPLATE,
+ )
+ );
+
+ \register_setting(
+ 'event-bridge-for-activitypub_event-sources',
+ 'event_bridge_for_activitypub_event_sources_active',
+ array(
+ 'type' => 'boolean',
+ 'show_in_rest' => true,
+ 'description' => \__( 'Whether the event sources feature is activated.', 'event-bridge-for-activitypub' ),
+ 'default' => 0,
+ 'sanitize_callback' => array( self::class, 'sanitize_event_sources_feature_active' ),
+ )
+ );
+
+ \register_setting(
+ 'event-bridge-for-activitypub_event-sources',
+ 'event_bridge_for_activitypub_event_source_cache_retention',
+ array(
+ 'type' => 'integer',
+ 'show_in_rest' => true,
+ 'description' => \__( 'The cache retention period for external event sources.', 'event-bridge-for-activitypub' ),
+ 'default' => WEEK_IN_SECONDS,
+ 'sanitize_callback' => 'absint',
+ )
+ );
+
+ \register_setting(
+ 'event-bridge-for-activitypub_event-sources',
+ 'event_bridge_for_activitypub_integration_used_for_event_sources_feature',
+ array(
+ 'type' => 'string',
+ 'description' => \__( 'Define which plugin/integration is used for the event sources feature', 'event-bridge-for-activitypub' ),
+ 'default' => array(),
+ 'sanitize_callback' => array( self::class, 'sanitize_event_plugin_integration_used_for_event_sources' ),
+ )
+ );
+
+ \register_setting(
+ 'event-bridge-for-activitypub_add-event-source',
+ 'event_bridge_for_activitypub_add_event_source',
+ array(
+ 'type' => 'array',
+ 'description' => \__( 'Dummy setting for adding event sources', 'event-bridge-for-activitypub' ),
+ 'default' => '',
+ 'sanitize_callback' => 'sanitize_text_field',
+ )
+ );
+ }
+
+ /**
+ * Do not allow the event sources feature to get deactivated, when event sources are still followed.
+ *
+ * @param mixed $value The optios value.
+ */
+ public static function sanitize_event_sources_feature_active( $value ) {
+ $count = count( Event_Sources::get_event_sources() );
+
+ $value = (bool) $value;
+
+ if ( 0 === $count ) {
+ return $value;
+ }
+
+ if ( ! $value ) {
+ \add_settings_error(
+ 'event-bridge-for-activitypub_event-sources',
+ 'event_bridge_for_activitypub_cannot_disable_event_sources',
+ __( 'It is not possible to disable the Event Sources feature while you are still having active followed Event Sources.', 'event-bridge-for-activitypub' ),
+ 'error'
+ );
+ }
+
+ return true;
+ }
+
+ /**
+ * Sanitize the option which event plugin.
+ *
+ * @param mixed $event_plugin_integration The setting.
+ * @return string
+ */
+ public static function sanitize_event_plugin_integration_used_for_event_sources( $event_plugin_integration ): string {
+ if ( ! is_string( $event_plugin_integration ) ) {
+ return '';
+ }
+ $setup = Setup::get_instance();
+ $active_event_plugins = $setup->get_active_event_plugins();
+
+ $valid_options = array();
+ foreach ( $active_event_plugins as $active_event_plugin ) {
+ if ( $active_event_plugin instanceof Feature_Event_Sources ) {
+ $valid_options[] = get_class( $active_event_plugin );
+ }
+ }
+ if ( in_array( $event_plugin_integration, $valid_options, true ) ) {
+ return $event_plugin_integration;
+ }
+ return Setup::get_default_integration_class_name_used_for_event_sources_feature();
+ }
+
+ /**
+ * Sanitize the target ActivityPub Event category.
+ *
+ * @param string $event_category The ActivityPUb event category.
+ */
+ public static function sanitize_mapped_event_category( $event_category ): string {
+ return self::is_allowed_event_category( $event_category ) ? $event_category : self::DEFAULT_EVENT_CATEGORY;
+ }
+
+ /**
+ * Sanitization function for the event category mapping setting.
+ *
+ * Currently only the default event categories are allowed to be target of a mapping.
+ *
+ * @param array $event_category_mappings The settings value.
+ *
+ * @return array An array that contains only valid mapping pairs.
+ */
+ public static function sanitize_event_category_mappings( $event_category_mappings ): array {
+ if ( empty( $event_category_mappings ) ) {
+ return array();
+ }
+ foreach ( $event_category_mappings as $taxonomy_slug => $event_category ) {
+ if ( ! self::is_allowed_event_category( $event_category ) ) {
+ unset( $event_category_mappings[ $taxonomy_slug ] );
+ }
+ }
+ return $event_category_mappings;
+ }
+
+ /**
+ * Checks if the given event category is allowed to be target of a mapping.
+ *
+ * @param string $event_category The event category to check.
+ *
+ * @return bool True if allowed, false otherwise.
+ */
+ private static function is_allowed_event_category( $event_category ): bool {
+ require_once EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . '/includes/event-categories.php';
+ $allowed_event_categories = array_keys( EVENT_BRIDGE_FOR_ACTIVITYPUB_EVENT_CATEGORIES );
+ return in_array( $event_category, $allowed_event_categories, true );
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-setup.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-setup.php
new file mode 100644
index 00000000..8f9ffe02
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/class-setup.php
@@ -0,0 +1,692 @@
+activitypub_plugin_is_active = defined( 'ACTIVITYPUB_PLUGIN_VERSION' ) || \is_plugin_active( 'activitypub/activitypub.php' );
+ $this->activitypub_plugin_version = self::get_activitypub_plugin_version();
+
+ // Register main action that load the Event Bridge For ActivityPub.
+ \add_action( 'plugins_loaded', array( $this, 'setup_hooks' ) );
+ }
+
+ /**
+ * The single instance of the class.
+ *
+ * @since 1.0.0
+ * @var ?self The instance of the class.
+ */
+ private static $instance = null;
+
+ /**
+ * Get the instance of the Singleton class.
+ *
+ * If an instance does not exist, it creates one; otherwise, it returns the existing instance.
+ *
+ * @since 1.0.0
+ *
+ * @return self The instance of the class.
+ */
+ public static function get_instance(): self {
+ if ( null === self::$instance ) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Getter function for whether the ActivityPub plugin is active.
+ *
+ * @return bool True when the ActivityPub plugin is active.
+ */
+ public function is_activitypub_plugin_active(): bool {
+ return $this->activitypub_plugin_is_active;
+ }
+
+ /**
+ * Get the current version of the ActivityPub plugin.
+ *
+ * @return string The semantic Version.
+ */
+ private static function get_activitypub_plugin_version(): string {
+ if ( defined( 'ACTIVITYPUB_PLUGIN_VERSION' ) ) {
+ return constant( 'ACTIVITYPUB_PLUGIN_VERSION' );
+ }
+ return '0.0.0';
+ }
+
+ /**
+ * Getter function for the active event plugins.
+ *
+ * @return Event_Plugin_Integration[]
+ */
+ public function get_active_event_plugins(): array {
+ return $this->active_event_plugins;
+ }
+
+ /**
+ * Getter function for the active event plugins event post types.
+ *
+ * @return array List of event post types of the active event plugins.
+ */
+ public function get_active_event_plugins_post_types(): array {
+ $post_types = array();
+ foreach ( $this->active_event_plugins as $event_plugin ) {
+ $post_types[] = $event_plugin->get_post_type();
+ }
+
+ return $post_types;
+ }
+
+ /**
+ * Function to check whether a post type is an event post type of an active event plugin.
+ *
+ * @param string $post_type The post type.
+ *
+ * @return bool True if it is an event post type.
+ */
+ public function is_event_post_type_of_active_event_plugin( $post_type ): bool {
+ foreach ( $this->active_event_plugins as $event_plugin ) {
+ if ( $post_type === $event_plugin->get_post_type() ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Holds all the full class names for the supported event plugins.
+ *
+ * @var string[]
+ */
+ private const EVENT_PLUGIN_INTEGRATIONS = array(
+ \Event_Bridge_For_ActivityPub\Integrations\Events_Manager::class,
+ \Event_Bridge_For_ActivityPub\Integrations\GatherPress::class,
+ \Event_Bridge_For_ActivityPub\Integrations\The_Events_Calendar::class,
+ \Event_Bridge_For_ActivityPub\Integrations\VS_Event_List::class,
+ \Event_Bridge_For_ActivityPub\Integrations\WP_Event_Manager::class,
+ \Event_Bridge_For_ActivityPub\Integrations\Eventin::class,
+ \Event_Bridge_For_ActivityPub\Integrations\Modern_Events_Calendar_Lite::class,
+ \Event_Bridge_For_ActivityPub\Integrations\Event_Organiser::class,
+ \Event_Bridge_For_ActivityPub\Integrations\EventPrime::class,
+ \Event_Bridge_For_ActivityPub\Integrations\EventOn::class,
+ );
+
+ /**
+ * Force the re-scan for active event plugins without using the cached transient.
+ *
+ * @return void
+ */
+ public function redetect_active_event_plugins(): void {
+ if ( ! $this->activitypub_plugin_is_active ) {
+ return;
+ }
+ \delete_transient( 'event_bridge_for_activitypub_active_event_plugins' );
+
+ $this->detect_active_event_plugins();
+ }
+
+ /**
+ * Function that checks for supported activated event plugins.
+ *
+ * @return array List of supported event plugins as keys from the SUPPORTED_EVENT_PLUGINS const.
+ */
+ public function detect_active_event_plugins(): array {
+ // Detection will fail in case the ActivityPub plugin is not active.
+ if ( ! $this->activitypub_plugin_is_active ) {
+ return array();
+ }
+
+ $active_event_plugins = \get_transient( 'event_bridge_for_activitypub_active_event_plugins' );
+
+ if ( $active_event_plugins ) {
+ $this->active_event_plugins = $active_event_plugins;
+ return $active_event_plugins;
+ }
+
+ if ( ! function_exists( 'get_plugins' ) ) {
+ // @phpstan-ignore-next-line
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
+ }
+
+ $all_plugins = array_merge( \get_plugins(), \get_mu_plugins() );
+
+ $active_event_plugins = array();
+ foreach ( self::EVENT_PLUGIN_INTEGRATIONS as $event_plugin_integration ) {
+ // Get the filename of the main plugin file of the event plugin (relative to the plugin dir).
+ $event_plugin_file = $event_plugin_integration::get_relative_plugin_file();
+
+ // Check if plugin is present on disk and is activated.
+ if ( array_key_exists( $event_plugin_file, $all_plugins ) && \is_plugin_active( $event_plugin_file ) ) {
+ $active_event_plugins[ $event_plugin_file ] = new $event_plugin_integration();
+ }
+ }
+ \set_transient( 'event_bridge_for_activitypub_active_event_plugins', $active_event_plugins );
+ $this->active_event_plugins = $active_event_plugins;
+ return $active_event_plugins;
+ }
+
+ /**
+ * Function that checks which event plugins support the event sources feature.
+ *
+ * @return array List of supported event plugins as keys from the SUPPORTED_EVENT_PLUGINS const.
+ */
+ public static function detect_event_plugins_supporting_event_sources(): array {
+ $plugins_supporting_event_sources = array();
+
+ foreach ( self::EVENT_PLUGIN_INTEGRATIONS as $event_plugin_integration ) {
+ if ( is_a( $event_plugin_integration, Feature_Event_Sources::class, true ) ) {
+ $plugins_supporting_event_sources[] = new $event_plugin_integration();
+ }
+ }
+ return $plugins_supporting_event_sources;
+ }
+
+ /**
+ * Main setup function of the plugin "Event Bridge For ActivityPub".
+ *
+ * This method adds hooks for different purposes as needed.
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ public function setup_hooks(): void {
+ // Detect active supported event plugins.
+ $this->detect_active_event_plugins();
+
+ // Register hook that runs when this plugin gets activated.
+ \register_activation_hook( EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_FILE, array( $this, 'activate' ) );
+
+ // Register listeners whenever any plugin gets activated or deactivated to maybe update the transient of active event plugins.
+ \add_action( 'activated_plugin', array( $this, 'redetect_active_event_plugins' ) );
+ \add_action( 'deactivated_plugin', array( $this, 'redetect_active_event_plugins' ) );
+
+ // Add hook that takes care of all notices in the Admin UI.
+ \add_action( 'admin_init', array( $this, 'do_admin_notices' ) );
+
+ // Add hook that registers all settings of this plugin to WordPress.
+ \add_action( 'admin_init', array( Settings::class, 'register_settings' ) );
+
+ // Add hook that loads CSS and JavaScript files for the Admin UI.
+ \add_action( 'admin_enqueue_scripts', array( self::class, 'enqueue_styles' ) );
+
+ // Register the settings page of this plugin as a Tab in the ActivityPub plugins settings.
+ Settings_Page::init();
+
+ // Add settings link in the Plugin overview Page.
+ \add_filter(
+ 'plugin_action_links_' . EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_BASENAME,
+ array( Settings_Page::class, 'settings_link' )
+ );
+
+ // If we don't have any active event plugins, or the ActivityPub plugin is not enabled, abort here.
+ if ( empty( $this->active_event_plugins ) || ! $this->activitypub_plugin_is_active ) {
+ self::shut_down();
+ return;
+ }
+
+ // Register health checks and status reports to the WordPress status report site.
+ \add_action( 'init', array( Health_Check::class, 'init' ) );
+
+ // Check if the minimum required version of the ActivityPub plugin is installed, if not abort.
+
+ if ( ! version_compare( $this->activitypub_plugin_version, EVENT_BRIDGE_FOR_ACTIVITYPUB_ACTIVITYPUB_PLUGIN_MIN_VERSION, '>=' ) ) {
+ return;
+ }
+
+ // Register our own deplayed event scheduler because of upstream race-condition bug.
+ // See https://github.com/Automattic/wordpress-activitypub/issues/1269 for more information.
+ if ( version_compare( $this->activitypub_plugin_version, '7.0.0', '<' ) ) {
+ Event_Scheduler::init();
+ }
+
+ // Register the event reminders.
+ \add_action( 'init', array( Reminder::class, 'init' ) );
+
+ // Initialize the handling of "Join" activities.
+ Join_Handler::init();
+
+ // If the Event-Sources feature is enabled and all requirements are met, initialize it.
+ if ( ! is_user_type_disabled( 'blog' ) && \get_option( 'event_bridge_for_activitypub_event_sources_active' ) ) {
+ Event_Sources::init();
+ }
+
+ // Initialize writing of debug logs.
+ Debug::init();
+
+ $this->register_plugin_specific_hooks();
+
+ // Most importantly: register the ActivityPub transformers for events to the ActivityPub plugin.
+ \add_filter( 'activitypub_transformer', array( $this, 'register_activitypub_transformer' ), 10, 3 );
+
+ // Apply custom ActivityPub previews for events.
+ \add_action( 'init', array( Preview::class, 'init' ) );
+
+ $this->maybe_register_term_activitypub_ids();
+ }
+
+ /**
+ * Temporary hack to register custom actions and hooks, only needed by exceptional event plugins.
+ *
+ * @return void
+ */
+ private function register_plugin_specific_hooks(): void {
+ if ( array_key_exists( \Event_Bridge_For_ActivityPub\Integrations\EventPrime::get_relative_plugin_file(), $this->active_event_plugins ) ) {
+ \Event_Bridge_For_ActivityPub\Integrations\EventPrime::init();
+ }
+ }
+
+ /**
+ * Shut down the plugin.
+ *
+ * @return void
+ */
+ public static function shut_down(): void {
+ // Delete all transients.
+ Event_Sources_Collection::delete_event_source_transients();
+ \delete_transient( 'event_bridge_for_activitypub_active_event_plugins' );
+
+ // Unschedule all crons.
+ \wp_unschedule_hook( 'event_bridge_for_activitypub_event_sources_clear_cache' );
+ }
+
+ /**
+ * Add the CSS for the admin pages.
+ *
+ * @param string $hook_suffix The suffix of the hook.
+ *
+ * @return void
+ */
+ public static function enqueue_styles( $hook_suffix ): void {
+ if ( 'settings_page_activitypub' !== $hook_suffix ) {
+ return;
+ }
+
+ // Check if we're on your custom tab.
+ $current_tab = isset( $_GET['tab'] ) ? \sanitize_key( $_GET['tab'] ) : 'welcome'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ if ( 'event-bridge-for-activitypub' === $current_tab ) {
+ \wp_enqueue_style(
+ 'event-bridge-for-activitypub-admin-styles',
+ plugins_url(
+ 'assets/css/event-bridge-for-activitypub-admin.css',
+ EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_FILE
+ ),
+ array(),
+ EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_VERSION
+ );
+ \wp_enqueue_script(
+ 'event-bridge-for-activitypub-admin-script',
+ plugins_url(
+ 'assets/js/event-bridge-for-activitypub-admin.js',
+ EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_FILE
+ ),
+ array( 'jquery' ),
+ EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_VERSION,
+ false
+ );
+ }
+ }
+
+ /**
+ * Fires the initialization of admin notices.
+ */
+ public function do_admin_notices(): void {
+ foreach ( $this->active_event_plugins as $event_plugin ) {
+ new Event_Plugin_Admin_Notices( $event_plugin );
+ }
+ // Check if any general admin notices are needed and add actions to insert the needed admin notices.
+ if ( ! $this->activitypub_plugin_is_active ) {
+ // The ActivityPub plugin is not active.
+ \add_action( 'admin_notices', array( General_Admin_Notices::class, 'activitypub_plugin_not_enabled' ), 10, 0 );
+ return;
+ }
+ if ( ! version_compare( $this->activitypub_plugin_version, EVENT_BRIDGE_FOR_ACTIVITYPUB_ACTIVITYPUB_PLUGIN_MIN_VERSION, '>=' ) ) {
+ // The ActivityPub plugin is too old.
+ \add_action( 'admin_notices', array( General_Admin_Notices::class, 'activitypub_plugin_version_too_old' ), 10, 0 );
+ return;
+ }
+ if ( empty( $this->active_event_plugins ) ) {
+ // No supported Event Plugin is active.
+ \add_action( 'admin_notices', array( General_Admin_Notices::class, 'no_supported_event_plugin_active' ), 10, 0 );
+ }
+ }
+
+ /**
+ * Add the custom transformers for the events and locations of several WordPress event plugins.
+ *
+ * @param \Activitypub\Transformer\Base $transformer The transformer to use.
+ * @param mixed $data The data to transform.
+ * @param string $object_class The class of the object to transform.
+ *
+ * @return \Activitypub\Transformer\Base|null|\WP_Error
+ */
+ public function register_activitypub_transformer( $transformer, $data, $object_class ) {
+ // If the current WordPress object is not a post (e.g., a WP_Comment), don't change the transformer.
+ if ( 'WP_Post' === $object_class ) {
+ // Get the transformer for a specific event plugins event or location post type.
+ foreach ( $this->active_event_plugins as $event_plugin ) {
+ // Check if we have an event.
+ if ( $data->post_type === $event_plugin->get_post_type() ) {
+ if ( ! self::is_post_disabled( $data ) ) {
+ return $event_plugin::get_activitypub_event_transformer( $data );
+ } else {
+ return new \WP_Error( 'invalid_object', __( 'Invalid object', 'event-bridge-for-activitypub' ) );
+ }
+ }
+
+ // Check if we have a location.
+ if ( $data->post_type === $event_plugin->get_place_post_type() ) {
+ if ( ! self::is_post_disabled( $data ) ) {
+ return $event_plugin::get_activitypub_place_transformer( $data );
+ } else {
+ return new \WP_Error( 'invalid_object', __( 'Invalid object', 'event-bridge-for-activitypub' ) );
+ }
+ }
+ }
+ } elseif ( 'WP_Term' === $object_class ) {
+ foreach ( $this->active_event_plugins as $event_plugin ) {
+ if ( $data->taxonomy === $event_plugin->get_place_taxonomy() ) {
+ return $event_plugin::get_activitypub_place_transformer( $data );
+ }
+ }
+ }
+
+ // Return the default transformer.
+ return $transformer;
+ }
+
+ /**
+ * Check if a post of a post type that is managed by this plugin is disabled for ActivityPub.
+ *
+ * This function checks the visibility of the post and whether it is private or has a password.
+ *
+ * @param mixed $post The post object or ID.
+ *
+ * @return boolean True if the post is disabled, false otherwise.
+ */
+ public static function is_post_disabled( $post ): bool {
+ $post = \get_post( $post );
+ $disabled = false;
+
+ if ( ! $post ) {
+ return true;
+ }
+
+ $visibility = \get_post_meta( $post->ID, 'activitypub_content_visibility', true );
+
+ if (
+ ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL === $visibility ||
+ ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE === $visibility ||
+ 'private' === $post->post_status ||
+ ! empty( $post->post_password )
+ ) {
+ $disabled = true;
+ }
+
+ return $disabled;
+ }
+
+ /**
+ * Activates ActivityPub support for all active event plugins event post-types.
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ public function activate_activitypub_support_for_active_event_plugins(): void {
+ // If someone installs this plugin, we simply enable ActivityPub support for all currently active event post types.
+ $activitypub_supported_post_types = get_option( 'activitypub_support_post_types', array() );
+ foreach ( $this->active_event_plugins as $event_plugin ) {
+ if ( ! in_array( $event_plugin->get_post_type(), $activitypub_supported_post_types, true ) ) {
+ $activitypub_supported_post_types[] = $event_plugin->get_post_type();
+ add_post_type_support( $event_plugin->get_post_type(), 'activitypub' );
+ }
+ }
+ \update_option( 'activitypub_support_post_types', $activitypub_supported_post_types );
+ }
+
+ /**
+ * Activates the Event Bridge for ActivityPub plugin.
+ *
+ * This method handles the activation of the Event Bridge for ActivityPub plugin.
+ *
+ * @since 1.0.0
+ * @see register_activation_hook()
+ * @return void
+ */
+ public function activate(): void {
+ $this->redetect_active_event_plugins();
+ // Don't allow plugin activation, when the ActivityPub plugin is not activated yet.
+ if ( ! $this->activitypub_plugin_is_active ) {
+ \deactivate_plugins( plugin_basename( EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_FILE ) );
+ $notice = General_Admin_Notices::get_admin_notice_activitypub_plugin_not_enabled();
+ \wp_die(
+ // @phpstan-ignore-next-line
+ wp_kses( $notice, General_Admin_Notices::ALLOWED_HTML ),
+ 'Plugin dependency check',
+ array( 'back_link' => true ),
+ );
+ }
+
+ if ( empty( $this->active_event_plugins ) ) {
+ \deactivate_plugins( plugin_basename( EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_FILE ) );
+ $notice = General_Admin_Notices::get_admin_notice_no_supported_event_plugin_active();
+ \wp_die(
+ // @phpstan-ignore-next-line
+ wp_kses( $notice, General_Admin_Notices::ALLOWED_HTML ),
+ 'Plugin dependency check',
+ array( 'back_link' => true ),
+ );
+ }
+
+ self::activate_activitypub_support_for_active_event_plugins();
+ }
+
+ /**
+ * Maybe (depending on active event plugins) make it possible to querly event terms by `?term_id=`.
+ *
+ * @return void
+ */
+ private function maybe_register_term_activitypub_ids(): void {
+ $register_term_query_var = false;
+
+ foreach ( $this->active_event_plugins as $event_plugin ) {
+ if ( $event_plugin::get_place_taxonomy() ) {
+ $register_term_query_var = true;
+ break;
+ }
+ }
+
+ if ( $register_term_query_var ) {
+ \add_filter( 'query_vars', array( self::class, 'add_term_query_var' ) );
+ \add_filter( 'activitypub_queried_object', array( $this, 'maybe_detect_event_plugins_location_term' ) );
+ }
+ }
+
+ /**
+ * Add the 'activitypub' query for term variable so WordPress won't mangle it.
+ *
+ * @param array $vars The query variables.
+ *
+ * @return array The query variables.
+ */
+ public static function add_term_query_var( $vars ) {
+ $vars[] = 'term_id';
+
+ return $vars;
+ }
+
+ /**
+ * Filters the queried object.
+ *
+ * @param \WP_Term|\WP_Post_Type|\WP_Post|\WP_User|\WP_Comment|null $queried_object The queried object.
+ */
+ public function maybe_detect_event_plugins_location_term( $queried_object ) {
+ if ( $queried_object ) {
+ return $queried_object;
+ }
+
+ $term_id = \get_query_var( 'term_id' );
+
+ if ( $term_id ) {
+ $queried_object = \get_term( $term_id );
+ }
+
+ if ( $queried_object instanceof \WP_Term && $this->is_place_taxonomy_of_active_event_plugin( $queried_object->taxonomy ) ) {
+ return $queried_object;
+ }
+
+ return null;
+ }
+
+ /**
+ * Check whether a taxonomy is an active event plugins location taxonomy.
+ *
+ * @param string $taxonomy The taxonomy.
+ * @return boolean
+ */
+ private function is_place_taxonomy_of_active_event_plugin( $taxonomy ): bool {
+ foreach ( $this->active_event_plugins as $event_plugin ) {
+ if ( $event_plugin::get_place_taxonomy() === $taxonomy ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the event plugin integration class name used for the event sources feature.
+ *
+ * @return ?string The class name of the event plugin integration class.
+ */
+ public static function get_event_plugin_integration_used_for_event_sources_feature(): ?string {
+ // Get plugin option.
+ $event_plugin_integration = get_option(
+ 'event_bridge_for_activitypub_integration_used_for_event_sources_feature',
+ self::get_default_integration_class_name_used_for_event_sources_feature()
+ );
+
+ // Exit if event sources are not active or no plugin is specified.
+ if ( empty( $event_plugin_integration ) ) {
+ return null;
+ }
+
+ // Validate if setting is actual existing class.
+ if ( ! class_exists( $event_plugin_integration ) ) {
+ return null;
+ }
+
+ return $event_plugin_integration;
+ }
+
+ /**
+ * Get the transmogrifier class.
+ *
+ * Retrieves the appropriate transmogrifier class based on the active event plugins and settings.
+ *
+ * @return ?string The transmogrifier class name or null if not available.
+ */
+ public static function get_transmogrifier(): ?string {
+ $event_plugin_integration = self::get_event_plugin_integration_used_for_event_sources_feature();
+
+ if ( ! $event_plugin_integration ) {
+ return null;
+ }
+
+ // Validate if get_transformer method exists in event plugin integration.
+ if ( ! method_exists( $event_plugin_integration, 'get_transmogrifier' ) ) {
+ return null;
+ }
+
+ $transmogrifier = $event_plugin_integration::get_transmogrifier();
+
+ return $transmogrifier;
+ }
+
+ /**
+ * Get the full class name of the first event plugin integration that is active and supports the event source feature.
+ *
+ * @return string The full class name of the event plugin integration.
+ */
+ public static function get_default_integration_class_name_used_for_event_sources_feature(): string {
+ $setup = self::get_instance();
+
+ $event_plugin_integrations = $setup->get_active_event_plugins();
+ foreach ( $event_plugin_integrations as $event_plugin_integration ) {
+ if ( $event_plugin_integration instanceof Feature_Event_Sources ) {
+ return get_class( $event_plugin_integration );
+ }
+ }
+ return '';
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/event-categories.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/event-categories.php
new file mode 100644
index 00000000..71232e74
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/event-categories.php
@@ -0,0 +1,50 @@
+ __( 'Arts', 'event-bridge-for-activitypub' ),
+ 'BOOK_CLUBS' => __( 'Book clubs', 'event-bridge-for-activitypub' ),
+ 'BUSINESS' => __( 'Business', 'event-bridge-for-activitypub' ),
+ 'CAUSES' => __( 'Causes', 'event-bridge-for-activitypub' ),
+ 'COMEDY' => __( 'Comedy', 'event-bridge-for-activitypub' ),
+ 'CRAFTS' => __( 'Crafts', 'event-bridge-for-activitypub' ),
+ 'FOOD_DRINK' => __( 'Food & Drink', 'event-bridge-for-activitypub' ),
+ 'HEALTH' => __( 'Health', 'event-bridge-for-activitypub' ),
+ 'MUSIC' => __( 'Music', 'event-bridge-for-activitypub' ),
+ 'AUTO_BOAT_AIR' => __( 'Auto, boat and air', 'event-bridge-for-activitypub' ),
+ 'COMMUNITY' => __( 'Community', 'event-bridge-for-activitypub' ),
+ 'FAMILY_EDUCATION' => __( 'Family & Education', 'event-bridge-for-activitypub' ),
+ 'FASHION_BEAUTY' => __( 'Fashion & Beauty', 'event-bridge-for-activitypub' ),
+ 'FILM_MEDIA' => __( 'Film & Media', 'event-bridge-for-activitypub' ),
+ 'GAMES' => __( 'Games', 'event-bridge-for-activitypub' ),
+ 'LANGUAGE_CULTURE' => __( 'Language & Culture', 'event-bridge-for-activitypub' ),
+ 'LEARNING' => __( 'Learning', 'event-bridge-for-activitypub' ),
+ 'LGBTQ' => __( 'LGBTQ', 'event-bridge-for-activitypub' ),
+ 'MOVEMENTS_POLITICS' => __( 'Movements and politics', 'event-bridge-for-activitypub' ),
+ 'NETWORKING' => __( 'Networking', 'event-bridge-for-activitypub' ),
+ 'PARTY' => __( 'Party', 'event-bridge-for-activitypub' ),
+ 'PERFORMING_VISUAL_ARTS' => __( 'Performing & Visual Arts', 'event-bridge-for-activitypub' ),
+ 'PETS' => __( 'Pets', 'event-bridge-for-activitypub' ),
+ 'PHOTOGRAPHY' => __( 'Photography', 'event-bridge-for-activitypub' ),
+ 'OUTDOORS_ADVENTURE' => __( 'Outdoors & Adventure', 'event-bridge-for-activitypub' ),
+ 'SPIRITUALITY_RELIGION_BELIEFS' => __( 'Spirituality, Religion & Beliefs', 'event-bridge-for-activitypub' ),
+ 'SCIENCE_TECH' => __( 'Science & Tech', 'event-bridge-for-activitypub' ),
+ 'SPORTS' => __( 'Sports', 'event-bridge-for-activitypub' ),
+ 'THEATRE' => __( 'Theatre', 'event-bridge-for-activitypub' ),
+ 'MEETING' => __( 'Meeting', 'event-bridge-for-activitypub' ), // Default value in federation.
+ 'DEFAULT' => __( 'Default', 'event-bridge-for-activitypub' ), // Internal default for overrides.
+ ),
+);
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-event-organiser.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-event-organiser.php
new file mode 100644
index 00000000..7f1b0909
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-event-organiser.php
@@ -0,0 +1,109 @@
+is_activitypub_request() && defined( 'EVENT_ORGANISER_DIR' ) ) {
+ $class_path = constant( EVENT_ORGANISER_DIR ) . 'includes/class-eo-theme-compatability.php';
+
+ if ( file_exists( $class_path ) ) {
+ require_once $class_path;
+
+ // Remove the theme filter which is not needed in ActivityStreams.
+ $eo = \EO_Theme_Compatabilty::get_instance();
+ if ( $eo instanceof \EO_Theme_Compatabilty ) {
+ $eo->remove_filter( 'template_include', PHP_INT_MAX - 1 );
+ }
+ }
+ }
+
+ return new Event_Organiser_Place_Transformer( $term );
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-event-plugin-integration.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-event-plugin-integration.php
new file mode 100644
index 00000000..9f73a67c
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-event-plugin-integration.php
@@ -0,0 +1,132 @@
+base && static::get_post_type() === $screen->post_type;
+ $is_event_plugins_settings_page = in_array( $screen->id, static::get_settings_pages(), true );
+
+ return $is_event_plugins_edit_page || $is_event_plugins_settings_page;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-eventin.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-eventin.php
new file mode 100644
index 00000000..3624ec81
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-eventin.php
@@ -0,0 +1,74 @@
+post_type ) {
+ return new EventPrime_Event_Transformer( $post );
+ }
+ }
+
+ if ( 'venue' === $object_type ) {
+ $term = get_term( self::get_object_id( $object_type ) );
+ if ( $term && self::get_place_taxonomy() === $term->taxonomy ) {
+ return new EventPrime_Place_Transformer( $term );
+ }
+ }
+
+ return $transformer;
+ }
+
+ /**
+ * Determine if the current post is actually just a shortcode Wrapper linking to an EventPrime event.
+ *
+ * @param \WP_Post $post The WordPress post object.
+ * @return string|bool
+ */
+ private static function post_contains_eventprime_object( $post ) {
+ if ( 'page' !== $post->post_type ) {
+ return false;
+ }
+
+ if ( '[em_event]' === $post->post_content || '[em_events]' === $post->post_content ) {
+ return 'event';
+ }
+
+ if ( '[em_sites]' === $post->post_content ) {
+ return 'venue';
+ }
+
+ return false;
+ }
+
+ /**
+ * Extract the post id for events and term id for venues for an EventPrime event query.
+ *
+ * @param string $type 'event' or 'venue'.
+ * @return bool|int The post ID, or term ID if found, false otherwise.
+ */
+ private static function get_object_id( $type = 'event' ) {
+ if ( ! in_array( $type, array( 'venue', 'event' ), true ) ) {
+ return false;
+ }
+
+ $event = get_query_var( $type );
+ if ( ! $event ) {
+ if ( ! empty( filter_input( INPUT_GET, $type, FILTER_SANITIZE_FULL_SPECIAL_CHARS ) ) ) {
+ $event = rtrim( filter_input( INPUT_GET, $type, FILTER_SANITIZE_FULL_SPECIAL_CHARS ), '/\\' );
+ }
+ }
+
+ if ( $event ) {
+ $ep_basic_functions = new Eventprime_Basic_Functions();
+ return $ep_basic_functions->ep_get_id_by_slug( $event, "em_{$type}" );
+ }
+
+ return false;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-events-manager.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-events-manager.php
new file mode 100644
index 00000000..98bb0a76
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-events-manager.php
@@ -0,0 +1,95 @@
+get_results(
+ $wpdb->prepare(
+ "SELECT DISTINCT {$wpdb->prefix}posts.ID
+ FROM {$wpdb->prefix}posts
+ LEFT JOIN {$wpdb->prefix}gatherpress_events
+ ON {$wpdb->prefix}posts.ID = {$wpdb->prefix}gatherpress_events.post_id
+ LEFT JOIN {$wpdb->prefix}postmeta
+ ON {$wpdb->prefix}posts.ID = {$wpdb->prefix}postmeta.post_id
+ WHERE {$wpdb->prefix}posts.post_type = 'gatherpress_event'
+ AND {$wpdb->prefix}posts.post_status = 'publish'
+ AND {$wpdb->prefix}gatherpress_events.datetime_end_gmt <= %s
+ AND {$wpdb->prefix}postmeta.meta_key = '_event_bridge_for_activitypub_event_source'
+ ",
+ $ends_before_time_string
+ ),
+ ARRAY_N
+ );
+
+ $post_ids = array_column( $results, 0 );
+
+ return $post_ids;
+ }
+
+ /**
+ * Init function: force displaying online event link for federated events.
+ */
+ public static function init(): void {
+ \add_filter(
+ 'gatherpress_force_online_event_link',
+ function ( $force_online_event_link ) {
+ // Get the current post object.
+ $post = get_post();
+
+ // Check if we are in a valid context and the post type is 'gatherpress'.
+ if ( $post && 'gatherpress_event' === $post->post_type ) {
+ // Add your custom logic here to decide whether to force the link.
+ // For example, force it only if a specific meta field exists.
+ if ( get_post_meta( $post->ID, '_event_bridge_for_activitypub_event_source', true ) ) {
+ return true; // Force the online event link.
+ }
+ }
+
+ return $force_online_event_link; // Default behavior.
+ },
+ 10,
+ 1
+ );
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-modern-events-calendar-lite.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-modern-events-calendar-lite.php
new file mode 100644
index 00000000..01f1384e
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-modern-events-calendar-lite.php
@@ -0,0 +1,75 @@
+get_main_post_type().
+ return 'mec-events';
+ }
+
+ /**
+ * Returns the IDs of the admin pages of the plugin.
+ *
+ * @return array The settings page urls.
+ */
+ public static function get_settings_pages(): array {
+ return array( 'MEC-settings', 'MEC-support', 'MEC-ix', 'MEC-wizard', 'MEC-addons', 'mec-intro' );
+ }
+
+ /**
+ * Returns the taxonomy used for the plugin's event categories.
+ *
+ * @return string
+ */
+ public static function get_event_category_taxonomy(): string {
+ return 'mec_category';
+ }
+
+ /**
+ * Returns the ActivityPub transformer for a Modern_Events_Calendar_Lite event post.
+ *
+ * @param \WP_Post $post The WordPress post object of the Event.
+ * @return Modern_Events_Calendar_Lite_Transformer
+ */
+ public static function get_activitypub_event_transformer( $post ): Modern_Events_Calendar_Lite_Transformer {
+ return new Modern_Events_Calendar_Lite_Transformer( $post, self::get_event_category_taxonomy() );
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-the-events-calendar.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-the-events-calendar.php
new file mode 100644
index 00000000..6fba3bc7
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-the-events-calendar.php
@@ -0,0 +1,155 @@
+
+ */
+ public static function get_cached_remote_events( $ends_before_time ): array {
+ add_filter(
+ 'tribe_repository_events_apply_modifier_schema_entry',
+ array( self::class, 'add_is_activitypub_remote_cached_to_query' ),
+ 10,
+ 1
+ );
+
+ $events = tribe_events()->where( 'ends_before', $ends_before_time )->get_ids();
+
+ remove_filter(
+ 'tribe_repository_events_apply_modifier_schema_entry',
+ array( self::class, 'add_is_activitypub_remote_cached_to_query' )
+ );
+
+ return $events;
+ }
+
+ /**
+ * Only show remote cached ActivityPub events in Tribe query.
+ *
+ * @param array $schema_entry The current schema entry.
+ * @return array The modified schema entry.
+ */
+ public static function add_is_activitypub_remote_cached_to_query( $schema_entry ) {
+ $schema_entry['meta_query']['is-remote-cached'] = array(
+ 'key' => '_event_bridge_for_activitypub_event_source',
+ 'compare' => 'EXISTS',
+ );
+ return $schema_entry;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-vs-event-list.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-vs-event-list.php
new file mode 100644
index 00000000..443df0e8
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-vs-event-list.php
@@ -0,0 +1,117 @@
+
+ */
+ public static function get_cached_remote_events( $ends_before_time ): array {
+ $args = array(
+ 'post_type' => 'event',
+ 'posts_per_page' => -1,
+ 'fields' => 'ids',
+ 'meta_query' => array(
+ 'relation' => 'AND',
+ array(
+ 'key' => '_event_bridge_for_activitypub_event_source',
+ 'compare' => 'EXISTS',
+ ),
+ array(
+ 'key' => 'event-date',
+ 'value' => $ends_before_time,
+ 'type' => 'NUMERIC',
+ 'compare' => '<',
+ ),
+ ),
+ );
+
+ $query = new WP_Query( $args );
+
+ $post_ids = $query->posts;
+
+ return $post_ids;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-wp-event-manager.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-wp-event-manager.php
new file mode 100644
index 00000000..668e4822
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/includes/integrations/class-wp-event-manager.php
@@ -0,0 +1,73 @@
+ \__( 'Event Source', 'event-bridge-for-activitypub' ),
+ 'plural' => \__( 'Event Sources', 'event-bridge-for-activitypub' ),
+ 'ajax' => true,
+ )
+ );
+ }
+
+ /**
+ * Get columns.
+ *
+ * @return array
+ */
+ public function get_columns(): array {
+ return array(
+ 'cb' => '',
+ 'icon' => \__( 'Icon', 'event-bridge-for-activitypub' ),
+ 'name' => \__( 'Name', 'event-bridge-for-activitypub' ),
+ 'accepted' => \__( 'Follow', 'event-bridge-for-activitypub' ),
+ 'url' => \__( 'URL', 'event-bridge-for-activitypub' ),
+ 'published' => \__( 'Followed', 'event-bridge-for-activitypub' ),
+ 'modified' => \__( 'Last updated', 'event-bridge-for-activitypub' ),
+ );
+ }
+
+ /**
+ * Returns sortable columns.
+ *
+ * @return array
+ */
+ public function get_sortable_columns(): array {
+ return array(
+ 'name' => array( 'name', true ),
+ 'modified' => array( 'modified', false ),
+ 'published' => array( 'published', false ),
+ );
+ }
+
+ /**
+ * Prepare items.
+ */
+ public function prepare_items(): void {
+ $columns = $this->get_columns();
+ $hidden = array();
+
+ $this->process_action();
+ $this->_column_headers = array( $columns, $hidden, $this->get_sortable_columns() );
+
+ $page_num = $this->get_pagenum();
+ $per_page = 20;
+
+ $args = array();
+
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
+ if ( isset( $_GET['orderby'] ) ) {
+ $args['orderby'] = sanitize_text_field( wp_unslash( $_GET['orderby'] ) );
+ }
+
+ if ( isset( $_GET['order'] ) ) {
+ $args['order'] = sanitize_text_field( wp_unslash( $_GET['order'] ) );
+ }
+
+ if ( isset( $_GET['s'] ) && isset( $_REQUEST['_wpnonce'] ) ) {
+ $nonce = sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) );
+ if ( wp_verify_nonce( $nonce, 'bulk-' . $this->_args['plural'] ) ) {
+ $args['s'] = sanitize_text_field( wp_unslash( $_GET['s'] ) );
+ }
+ }
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
+
+ $event_sources = Event_Sources_Collection::get_event_sources_with_count( $per_page, $page_num, $args );
+ $total_count = $event_sources['total'];
+
+ $this->items = array();
+ $this->set_pagination_args(
+ array(
+ 'total_items' => $total_count,
+ 'total_pages' => (int) ceil( $total_count / $per_page ),
+ 'per_page' => $per_page,
+ )
+ );
+
+ foreach ( $event_sources['actors'] as $event_source_post_id => $event_source_activitypub_id ) {
+ $event_source = Event_Source::get_by_id( (int) $event_source_post_id );
+
+ if ( ! $event_source || ! in_array( $event_source->get_status(), array( 'publish', 'pending' ), true ) ) {
+ continue;
+ }
+
+ $item = array(
+ 'icon' => esc_attr( $event_source->get_icon_url() ),
+ 'name' => esc_attr( $event_source->get_name() ),
+ 'url' => esc_attr( $event_source_activitypub_id ),
+ 'accepted' => esc_attr( get_post_meta( $event_source->get__id(), '_event_bridge_for_activitypub_accept_of_follow', true ) ),
+ 'identifier' => esc_attr( $event_source_post_id ),
+ 'published' => esc_attr( $event_source->get_published() ),
+ 'modified' => esc_attr( $event_source->get_updated() ),
+ );
+
+ $this->items[] = $item;
+ }
+ }
+
+ /**
+ * Returns bulk actions.
+ *
+ * @return array
+ */
+ public function get_bulk_actions(): array {
+ return array(
+ 'delete' => __( 'Delete', 'event-bridge-for-activitypub' ),
+ );
+ }
+
+ /**
+ * Column default.
+ *
+ * @param array $item Item.
+ * @param string $column_name Column name.
+ * @return string
+ */
+ public function column_default( $item, $column_name ) {
+ if ( ! array_key_exists( $column_name, $item ) ) {
+ return __( 'None', 'event-bridge-for-activitypub' );
+ }
+ return $item[ $column_name ];
+ }
+
+ /**
+ * Column avatar.
+ *
+ * @param array $item Item.
+ * @return string
+ */
+ public function column_icon( $item ): string {
+ return sprintf(
+ '
',
+ $item['icon']
+ );
+ }
+
+ /**
+ * Column url.
+ *
+ * @param array $item Item.
+ * @return string
+ */
+ public function column_url( $item ): string {
+ return sprintf(
+ '%s',
+ esc_url( $item['url'] ),
+ $item['url']
+ );
+ }
+
+ /**
+ * Column cb.
+ *
+ * @param array $item Item.
+ * @return string
+ */
+ public function column_cb( $item ): string {
+ return sprintf( '', esc_attr( $item['identifier'] ) );
+ }
+
+ /**
+ * Column action.
+ *
+ * @param array $item Item.
+ * @return string
+ */
+ public function column_accepted( $item ): string {
+ if ( $item['accepted'] ) {
+ return esc_html__( 'Accepted', 'event-bridge-for-activitypub' );
+ } else {
+ return esc_html__( 'Pending', 'event-bridge-for-activitypub' );
+ }
+ }
+
+ /**
+ * Process action.
+ */
+ public function process_action(): void {
+ if ( ! isset( $_REQUEST['event_sources'] ) || ! isset( $_REQUEST['_wpnonce'] ) ) {
+ return;
+ }
+ $nonce = sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) );
+ if ( ! wp_verify_nonce( $nonce, 'bulk-' . $this->_args['plural'] ) ) {
+ return;
+ }
+
+ if ( ! current_user_can( 'manage_options' ) ) {
+ return;
+ }
+
+ $event_sources = $_REQUEST['event_sources']; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
+
+ if ( ! is_array( $event_sources ) ) {
+ return;
+ }
+
+ if ( 'delete' === $this->current_action() ) {
+ foreach ( $event_sources as $event_source ) {
+ Event_Sources_Collection::remove_event_source( absint( $event_source ) );
+ }
+ }
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/readme.txt b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/readme.txt
new file mode 100644
index 00000000..1643b052
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/readme.txt
@@ -0,0 +1,157 @@
+=== Event Bridge for ActivityPub ===
+Contributors: andremenrath, pfefferle
+Tags: events, fediverse, activitypub, calendar
+Requires at least: 6.5
+Tested up to: 6.8
+Stable tag: 1.1.0
+Requires PHP: 7.4
+License: AGPL-3.0-or-later
+License URI: https://www.gnu.org/licenses/agpl-3.0.html
+Integrating popular event plugins with the ActivityPub plugin.
+
+== Description ==
+
+Make your events more discoverable, expand your reach effortlessly while being independent of other (commercial) platforms, and be a part of the growing decentralized web (the Fediverse). With the Event Bridge for ActivityPub Plugin for WordPress, your events can be automatically followed, aggregated and displayed across decentralized platforms like [Mastodon](https://joinmastodon.org) or [Gancio](https://gancio.org), without any extra work. Forget the hassle of managing multiple social media accounts just to keep your audience informed.
+
+This plugin is not an event managing plugin but an add-on to popular event plugins. It extends their functionality to fully support the [ActivityPub plugin](https://wordpress.org/plugins/activitypub/). With the ActivityPub plugin people can follow your website directly and engage with your events just as they would on social media: liking, boosting and even commenting if you enable it. You retain full ownership of your content. By integrating into your existing setup, it ensures no extra work is needed while enhancing your events' visibility across the web.
+
+= Supported Event Plugins =
+
+Full support (including importing events from the Fediverse):
+
+* [The Events Calendar](https://de.wordpress.org/plugins/the-events-calendar/)
+* [VS Event List](https://de.wordpress.org/plugins/very-simple-event-list/)
+* [GatherPress](https://gatherpress.org/)
+
+Basic support (outgoing events):
+
+* [Events Manager](https://de.wordpress.org/plugins/events-manager/)
+* [WP Event Manager](https://de.wordpress.org/plugins/wp-event-manager/)
+* [Eventin](https://de.wordpress.org/plugins/wp-event-solution/)
+* [Modern Events Calendar Lite](https://webnus.net/modern-events-calendar/)
+* [Event Organiser](https://wordpress.org/plugins/event-organiser/)
+* [EventPrime – Events Calendar, Bookings and Tickets](https://wordpress.org/plugins/eventprime-event-calendar-management/)
+* [EventON – Events Calendar](https://wordpress.org/plugins/eventon-lite/)
+
+= How It Works =
+
+With the Event Bridge for ActivityPub WordPress plugin, sharing your events is effortless and automatic! Once you create an event on your WordPress site, it is seamlessly shared across the decentralized web using the ActivityPub protocol.
+
+[vimeo https://vimeo.com/1043105544 ]
+
+Your events can be automatically delivered to platforms that fully support events, such as [Mobilizon](https://joinmobilizon.org/), [Gancio](https://gancio.org), [Friendica](https://friendi.ca), [Hubzilla](https://hubzilla.org), and [Pleroma](https://pleroma.social/). These platforms create public event calendars by pulling in events from various sources, including your website. Any updates you make to your events are synced across these platforms—so you only need to manage your events on your own site, with no extra work required.
+
+[vimeo https://vimeo.com/1043104445 ]
+
+Even platforms that don't yet fully support events, like [Mastodon](https://joinmastodon.org), will still receive a detailed, well-composed summary of your event. The Event Federation plugin ensures that users from those platforms are provided with all important information about an event.
+
+= Features for Your WordPress Events and the Fediverse =
+
+**ActivityPub-Enabled Event Sharing:** Your WordPress events are now compatible with the Fediverse, using the ActivityStreams format. This means your events can be easily discovered and followed by users on platforms like Mastodon and other ActivityPub-compatible services.
+
+**Automatic Event Summaries:** When your event is shared on the Fediverse, platforms like Mastodon that don't fully support events will display a brief HTML summary of key details — such as the event's title, start time, and location. This ensures that even if someone can't view the full event on their platform, they still get the important info at a glance, with a link to your WordPress event page. Advanced users can create custom summaries via a set of shortcodes.
+
+**Improved Event Discoverability:** Your custom event categories are mapped to a set of default categories used in the Fediverse, helping your events reach a wider audience. This improves the chances that users searching for similar events on other platforms will find yours.
+
+**Event Reminders for Your Followers:** Often, events are planned well in advance. To keep your followers informed right in time, you can set up reminders that are supposed to trigger the events showing up in their timelines right before the event starts. At the moment this reminder is implemented as a self-boost of your original event post. While this feature may behave differently across various platforms, we are working on a more robust solution that will let you schedule dedicated reminder notes that appear in all followers' timelines.
+
+**External Event Sources:** This functionality is only available for a subset of the supported event plugins. It enables your WordPress site to act as a hub for displaying events from other ActivityPub profiles, aggregating them into a cohesive calendar view.
+
+== Installation ==
+
+This plugin depends on the [ActivityPub plugin](https://wordpress.org/plugins/activitypub/). Additionally, you need to use one of the supported event Plugins.
+
+= Supported Event Plugins =
+
+Full support (including importing events from the Fediverse):
+
+* [The Events Calendar](https://de.wordpress.org/plugins/the-events-calendar/)
+* [VS Event List](https://de.wordpress.org/plugins/very-simple-event-list/)
+* [GatherPress](https://gatherpress.org/)
+
+Basic support (outgoing events):
+
+* [Events Manager](https://de.wordpress.org/plugins/events-manager/)
+* [WP Event Manager](https://de.wordpress.org/plugins/wp-event-manager/)
+* [Eventin](https://de.wordpress.org/plugins/wp-event-solution/)
+* [Modern Events Calendar Lite](https://webnus.net/modern-events-calendar/)
+* [Event Organiser](https://wordpress.org/plugins/event-organiser/)
+* [EventPrime – Events Calendar, Bookings and Tickets](https://wordpress.org/plugins/eventprime-event-calendar-management/)
+
+= Configuration =
+
+If you're new to the [ActivityPub plugin](https://wordpress.org/plugins/activitypub/), it's recommended to spend a few minutes reading through its documentation to familiarize yourself with its setup and functionality.
+
+== Frequently Asked Questions ==
+
+= Do I need to install another event plugin to use the Event Federation Plugin? =
+
+Yes, this plugin works as an add-on and requires both the ActivityPub plugin and a supported event plugin such as The Events Calendar, VS Event List, or Events Manager to manage your events. It just fills the missing gap between event plugins and the [ActivityPub plugin](https://wordpress.org/plugins/activitypub/).
+
+= What platforms can follow my events? =
+
+Your events can be followed on platforms that support ActivityPub like [Mobilizon](https://joinmobilizon.org/), [Gancio](https://gancio.org), [Friendica](https://friendi.ca), [Hubzilla](https://hubzilla.org), and [Pleroma](https://pleroma.social/). Even other applications like [Mastodon](https://joinmastodon.org), which don't fully support events yet, will display all important information about the events.
+
+= Why does Mastodon not show any updates? ==
+
+Mastodon does not yet handle updates of `Event` objects. See the related tracking issue [#31114](https://github.com/mastodon/mastodon/issues/31114).
+
+= How much extra work is required to maintain my events across the decentralized Web? =
+
+None! Once the plugin is set up, your events are automatically sent to all connected platforms or account that follow you (your Website). Any updates you make to your events are synced without additional effort.
+
+= Can I still use social media to promote my events? =
+
+Yes, you can still use traditional social media if you wish. However, this plugin helps reduce reliance on commercial platforms by connecting your events to the decentralized Fediverse.
+
+= Will this plugin work if I don't use the ActivityPub plugin? =
+
+No, the Event Federation Plugin depends on the [ActivityPub plugin](https://wordpress.org/plugins/activitypub/) to deliver your events across decentralized platforms, so it's essential to have it installed and configured.
+
+= My event plugin is not supported, what can I do? =
+
+If you know about coding have a look at the documentation of how to add your plugin or open an [issue](https://codeberg.org/Event-Federation/wordpress-event-bridge-for-activitypub/issues), if we can spare some free hours we might add it.
+
+= What if I experience problems? =
+
+We're always interested in your feedback. Feel free to reach out to us via [E-Mail](https://event-federation.eu/contact/) or create an [issue](https://codeberg.org/Event-Federation/wordpress-event-bridge-for-activitypub/issues).
+
+== Acknowledgement ==
+
+The development of this WordPress plugin was funded through the [NGI0 Entrust](https://NLnet.nl/entrust) Fund, a fund established by [NLnet](https://nlnet.nl) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) programme, under the aegis of [Communications Networks, Content and Technology](https://commission.europa.eu/about-european-commission/departments-and-executive-agencies/communications-networks-content-and-technology_en) under grant agreement number 101069594.
+
+== Changelog ==
+
+= [1.1.0] - 2025-04-12 =
+
+* Added: Basic support for Starter Kits
+* Fixed: Uncatched error in following process (issue #145)
+* Fixed: Compatibility with ActivityPub plugin version 5.7.0
+
+= [1.0.0] - 2025-02-11 =
+
+* Added: Support for the EventPrime event plugin
+* Added: Event self-announce feature at configurable time before event starts
+* Added: Blueprint (Preview via WordPress Playground)
+* Added: Event Sources feature: cache and list events from remote ActivityPub profiles on your site
+* Added: Custom ActivityPub preview
+* Added: Admin setting to enfore sending summary of events as plain text
+* Changed: Now depends on ActivityPub plugin version greater than 5.1.0
+* Fixed: The Events Calendar date times when using the Gutenberg editor
+* Fixed: Improved admin UI for event-category mapping
+
+= [0.3.5] - 2025-01-03 =
+
+* Fixed: Images of Acknowledgements in Admin UI
+
+= [0.3.4] - 2024-12-21 =
+
+* Initial release on https://wordpress.org/
+
+== Contributing ==
+
+This plugin is free software, and contributions of all kinds are welcome! Whether it's reporting issues, submitting improvements, or suggesting new features, your input helps make the plugin better for everyone.
+
+Please review our [Contribution Guidelines](https://codeberg.org/Event-Federation/wordpress-event-bridge-for-activitypub/src/branch/main/CONTRIBUTING.md) to get started. The source code is hosted on [Codeberg](https://codeberg.org/Event-Federation/wordpress-event-bridge-for-activitypub), where you can open issues and submit pull requests.
+
+Thank you for contributing!
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/templates/event-preview.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/templates/event-preview.php
new file mode 100644
index 00000000..001c0f0d
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/templates/event-preview.php
@@ -0,0 +1,1510 @@
+get_error_message() ),
+ 404
+ );
+}
+
+if ( $transformer instanceof Event ) {
+ $object = $transformer->to_object();
+ $user = $transformer->get_actor_object();
+ $address = $transformer->get_formatted_address();
+ $location = $transformer->get_location();
+ if ( $location ) {
+ $location_name = $location->get_name();
+ } else {
+ $location_name = '';
+ }
+} else {
+ \wp_die(
+ 'Wrong ActivityPub preview template.',
+ 404
+ );
+}
+
+$first_image_attachment = null;
+
+?>
+
+
+
+
+ get_name() ); ?>HUU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ get_content(), ACTIVITYPUB_MASTODON_HTML_SANITIZER ); ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/templates/settings/menu.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/templates/settings/menu.php
new file mode 100644
index 00000000..b4e333fd
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/templates/settings/menu.php
@@ -0,0 +1,45 @@
+ '',
+ 'settings' => '',
+ 'event-sources' => '',
+ )
+);
+?>
+
+
+
+
+
+
+
+ 'active',
+ )
+);
+
+if ( ! current_user_can( 'manage_options' ) ) {
+ return;
+}
+
+$activitypub_plugin_is_active = Setup::get_instance()->is_activitypub_plugin_active();
+
+\get_option( 'event_bridge_for_activitypub_event_sources_active', false );
+
+if ( ! isset( $args ) || ! array_key_exists( 'supports_event_sources', $args ) ) {
+ return;
+}
+
+$event_plugins_supporting_event_sources = $args['supports_event_sources'];
+
+$event_sources_active = \get_option( 'event_bridge_for_activitypub_event_sources_active', false );
+$cache_retention_period = \get_option( 'event_bridge_for_activitypub_event_source_cache_retention', DAY_IN_SECONDS );
+
+?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/templates/settings/subpages/settings.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/templates/settings/subpages/settings.php
new file mode 100644
index 00000000..60106358
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/templates/settings/subpages/settings.php
@@ -0,0 +1,229 @@
+ 'active',
+ )
+);
+
+$activitypub_plugin_is_active = Setup::get_instance()->is_activitypub_plugin_active();
+
+if ( ! isset( $args ) || ! array_key_exists( 'event_terms', $args ) ) {
+ return;
+}
+
+if ( ! current_user_can( 'manage_options' ) ) {
+ return;
+}
+
+$event_terms = $args['event_terms'];
+
+require_once EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . '/includes/event-categories.php';
+
+$selected_default_event_category = \get_option( 'event_bridge_for_activitypub_default_event_category', 'MEETING' );
+$current_category_mapping = \get_option( 'event_bridge_for_activitypub_event_category_mappings', array() );
+$reminder_time_gap = \get_option( 'event_bridge_for_activitypub_reminder_time_gap', 0 );
+
+$reminder_time_gap_choices = array(
+ 0 => __( 'Disabled', 'event-bridge-for-activitypub' ),
+ HOUR_IN_SECONDS * 6 => __( '6 hours', 'event-bridge-for-activitypub' ),
+ DAY_IN_SECONDS => __( '1 day', 'event-bridge-for-activitypub' ),
+ DAY_IN_SECONDS * 3 => __( '3 days', 'event-bridge-for-activitypub' ),
+ WEEK_IN_SECONDS => __( '1 week', 'event-bridge-for-activitypub' ),
+);
+
+if ( \get_option( 'event_bridge_for_activitypub_initially_activated' ) ) {
+ \update_option( 'event_bridge_for_activitypub_initially_activated', '' );
+}
+?>
+
+
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/templates/settings/subpages/welcome.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/templates/settings/subpages/welcome.php
new file mode 100644
index 00000000..c5456cec
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/templates/settings/subpages/welcome.php
@@ -0,0 +1,250 @@
+ 'active',
+ )
+);
+
+$active_event_plugins = Setup::get_instance()->get_active_event_plugins();
+$activitypub_plugin_is_active = Setup::get_instance()->is_activitypub_plugin_active();
+$event_bridge_for_activitypub_status_ok = true;
+$example_event_post = Health_Check::get_most_recent_event_posts();
+
+if ( empty( $example_event_post ) ) {
+ $example_event_post = 'https://yoursite.com/events/event-name';
+ $example_event_post_is_dummy = true;
+} else {
+ $example_event_post = \get_permalink( $example_event_post[0] );
+ $example_event_post_is_dummy = false;
+}
+
+global $wp_filesystem;
+WP_Filesystem();
+
+?>
+
+
+
+
+
+
+ The development of this plugin was funded through the NGI0 Entrust Fund, a fund established by NLnet with financial support from the European Commission's Next Generation Internet programme, under the aegis of DG Communications Networks, Content and Technology under grant agreement No 101069594.
+
+
+
+
+
+
+
diff --git a/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/templates/settings/tab.php b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/templates/settings/tab.php
new file mode 100644
index 00000000..753c1b8a
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/event-bridge-for-activitypub/templates/settings/tab.php
@@ -0,0 +1,13 @@
+
+ *
+ * Gitium 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 3 of the License, or
+ * any later version.
+ *
+ * Gitium 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 Gitium. If not, see .
+ *
+ * @package Gitium
+ */
+
+function gitium_error_log( $message ) {
+ if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) { return; }
+ error_log( "gitium_error_log: $message" );
+}
+
+function wp_content_is_versioned() {
+ return file_exists( WP_CONTENT_DIR . '/.git' );
+}
+
+if ( ! function_exists( 'gitium_enable_maintenance_mode' ) ) :
+ function gitium_enable_maintenance_mode() {
+ $file = ABSPATH . '/.maintenance';
+
+ if ( false === file_put_contents( $file, 'set_key( $git_private_key );
+
+ $git->add( $dir );
+ gitium_update_versions();
+ $current_user = wp_get_current_user();
+ return $git->commit( $message, $current_user->display_name, $current_user->user_email );
+}
+
+function _gitium_format_message( $name, $version = false, $prefix = '' ) {
+ $commit_message = "`$name`";
+ if ( $version ) {
+ $commit_message .= " version $version";
+ }
+ if ( $prefix ) {
+ $commit_message = "$prefix $commit_message";
+ }
+ return $commit_message;
+}
+
+/**
+ * This function return the basic info about a path.
+ *
+ * base_path - means the path after wp-content dir (themes/plugins)
+ * type - can be file/theme/plugin
+ * name - the file name of the path, if it is a file, or the theme/plugin name
+ * version - the theme/plugin version, othewise null
+ */
+/* Some examples:
+
+ with 'wp-content/themes/twentyten/style.css' will return:
+ array(
+ 'base_path' => 'wp-content/themes/twentyten'
+ 'type' => 'theme'
+ 'name' => 'TwentyTen'
+ 'version' => '1.12'
+ )
+
+ with 'wp-content/themes/twentyten/img/foo.png' will return:
+ array(
+ 'base_path' => 'wp-content/themes/twentyten'
+ 'type' => 'theme'
+ 'name' => 'TwentyTen'
+ 'version' => '1.12'
+ )
+
+ with 'wp-content/plugins/foo.php' will return:
+ array(
+ 'base_path' => 'wp-content/plugins/foo.php'
+ 'type' => 'plugin'
+ 'name' => 'Foo'
+ 'varsion' => '2.0'
+ )
+
+ with 'wp-content/plugins/autover/autover.php' will return:
+ array(
+ 'base_path' => 'wp-content/plugins/autover'
+ 'type' => 'plugin'
+ 'name' => 'autover'
+ 'version' => '3.12'
+ )
+
+ with 'wp-content/plugins/autover/' will return:
+ array(
+ 'base_path' => 'wp-content/plugins/autover'
+ 'type' => 'plugin'
+ 'name' => 'autover'
+ 'version' => '3.12'
+ )
+*/
+function _gitium_module_by_path( $path ) {
+ $versions = gitium_get_versions();
+
+ // default values
+ $module = array(
+ 'base_path' => $path,
+ 'type' => 'file',
+ 'name' => basename( $path ),
+ 'version' => null,
+ );
+
+ // find the base_path
+ $split_path = explode( '/', $path );
+ if ( 2 < count( $split_path ) ) {
+ $module['base_path'] = "{$split_path[0]}/{$split_path[1]}/{$split_path[2]}";
+ }
+
+ // find other data for theme
+ if ( array_key_exists( 'themes', $versions ) && 0 === strpos( $path, 'wp-content/themes/' ) ) {
+ $module['type'] = 'theme';
+ foreach ( $versions['themes'] as $theme => $data ) {
+ if ( 0 === strpos( $path, "wp-content/themes/$theme" ) ) {
+ $module['name'] = $data['name'];
+ $module['version'] = $data['version'];
+ break;
+ }
+ }
+ }
+
+ // find other data for plugin
+ if ( array_key_exists( 'plugins', $versions ) && 0 === strpos( $path, 'wp-content/plugins/' ) ) {
+ $module['type'] = 'plugin';
+ foreach ( $versions['plugins'] as $plugin => $data ) {
+ if ( '.' === dirname( $plugin ) ) { // single file plugin
+ if ( "wp-content/plugins/$plugin" === $path ) {
+ $module['base_path'] = $path;
+ $module['name'] = $data['name'];
+ $module['version'] = $data['version'];
+ break;
+ }
+ } else if ( 'wp-content/plugins/' . dirname( $plugin ) === $module['base_path'] ) {
+ $module['name'] = $data['name'];
+ $module['version'] = $data['version'];
+ break;
+ }
+ }
+ }
+
+ return $module;
+}
+
+function gitium_group_commit_modified_plugins_and_themes( $msg_append = '' ) {
+ global $git;
+
+ $uncommited_changes = $git->get_local_changes();
+ $commit_groups = array();
+ $commits = array();
+
+ if ( ! empty( $msg_append ) ) {
+ $msg_append = "($msg_append)";
+ }
+ foreach ( $uncommited_changes as $path => $action ) {
+ $change = _gitium_module_by_path( $path );
+ $change['action'] = $action;
+ $commit_groups[ $change['base_path'] ] = $change;
+ }
+
+ foreach ( $commit_groups as $base_path => $change ) {
+ $commit_message = _gitium_format_message( $change['name'], $change['version'], "{$change['action']} {$change['type']}" );
+ $commit = _gitium_commit_changes( "$commit_message $msg_append", $base_path, false );
+ if ( $commit ) {
+ $commits[] = $commit;
+ }
+ }
+
+ return $commits;
+}
+
+function gitium_commit_and_push_gitignore_file( $path = '' ) {
+ global $git;
+
+ $current_user = wp_get_current_user();
+ if ( ! empty( $path ) ) { $git->rm_cached( $path ); }
+ $git->add( '.gitignore' );
+ $commit = $git->commit( 'Update the `.gitignore` file', $current_user->display_name, $current_user->user_email );
+ gitium_merge_and_push( $commit );
+}
+
+if ( ! function_exists( 'gitium_acquire_merge_lock' ) ) :
+ function gitium_acquire_merge_lock() {
+ $gitium_lock_path = apply_filters( 'gitium_lock_path', sys_get_temp_dir().'/.gitium-lock' );
+ $gitium_lock_handle = fopen( $gitium_lock_path, 'w+' );
+
+ $lock_timeout = intval( ini_get( 'max_execution_time' ) ) > 10 ? intval( ini_get( 'max_execution_time' ) ) - 5 : 10;
+ $lock_timeout_ms = 10;
+ $lock_retries = 0;
+ while ( ! flock( $gitium_lock_handle, LOCK_EX | LOCK_NB ) ) {
+ usleep( $lock_timeout_ms * 1000 );
+ $lock_retries++;
+ if ( $lock_retries * $lock_timeout_ms > $lock_timeout * 1000 ) {
+ return false; // timeout
+ }
+ }
+ gitium_error_log( __FUNCTION__ );
+ return array( $gitium_lock_path, $gitium_lock_handle );
+ }
+endif;
+
+if ( ! function_exists( 'gitium_release_merge_lock' ) ) :
+ function gitium_release_merge_lock( $lock ) {
+ list( $gitium_lock_path, $gitium_lock_handle ) = $lock;
+ gitium_error_log( __FUNCTION__ );
+ flock( $gitium_lock_handle, LOCK_UN );
+ fclose( $gitium_lock_handle );
+ }
+endif;
+
+// Merges the commits with remote and pushes them back
+function gitium_merge_and_push( $commits ) {
+ global $git;
+
+ $lock = gitium_acquire_merge_lock()
+ or trigger_error( 'Timeout when gitium lock was acquired', E_USER_WARNING );
+
+ if ( ! $git->fetch_ref() ) {
+ return false;
+ }
+
+ $merge_status = $git->merge_with_accept_mine( $commits );
+
+ gitium_release_merge_lock( $lock );
+
+ return $git->push() && $merge_status;
+}
+
+function gitium_check_after_event( $plugin, $event = 'activation' ) {
+ global $git;
+
+ if ( 'gitium/gitium.php' == $plugin ) { return; } // do not hook on activation of this plugin
+
+ if ( $git->is_dirty() ) {
+ $versions = gitium_update_versions();
+ if ( isset( $versions['plugins'][ $plugin ] ) ) {
+ $name = $versions['plugins'][ $plugin ]['name'];
+ $version = $versions['plugins'][ $plugin ]['version'];
+ } else {
+ $name = $plugin;
+ }
+ gitium_auto_push( _gitium_format_message( $name, $version, "after $event of" ) );
+ }
+}
+
+function gitium_update_remote_tracking_branch() {
+ global $git;
+ $remote_branch = $git->get_remote_tracking_branch();
+ set_transient( 'gitium_remote_tracking_branch', $remote_branch );
+
+ return $remote_branch;
+}
+
+function _gitium_get_remote_tracking_branch( $update_transient = false ) {
+ if ( ! $update_transient && ( false !== ( $remote_branch = get_transient( 'gitium_remote_tracking_branch' ) ) ) ) {
+ return $remote_branch;
+ } else {
+ return gitium_update_remote_tracking_branch();
+ }
+}
+
+function gitium_update_is_status_working() {
+ global $git;
+ $is_status_working = $git->is_status_working();
+ set_transient( 'gitium_is_status_working', $is_status_working );
+ return $is_status_working;
+}
+
+function _gitium_is_status_working( $update_transient = false ) {
+ if ( ! $update_transient && ( false !== ( $is_status_working = get_transient( 'gitium_is_status_working' ) ) ) ) {
+ return $is_status_working;
+ } else {
+ return gitium_update_is_status_working();
+ }
+}
+
+function _gitium_status( $update_transient = false ) {
+ global $git;
+
+ if ( ! $update_transient && ( false !== ( $changes = get_transient( 'gitium_uncommited_changes' ) ) ) ) {
+ return $changes;
+ }
+
+ $git_version = get_transient( 'gitium_git_version' );
+ if ( false === $git_version ) {
+ set_transient( 'gitium_git_version', $git->get_version() );
+ }
+
+ if ( $git->is_status_working() && $git->get_remote_tracking_branch() ) {
+ if ( ! $git->fetch_ref() ) {
+ set_transient( 'gitium_remote_disconnected', $git->get_last_error() );
+ } else {
+ delete_transient( 'gitium_remote_disconnected' );
+ }
+ $changes = $git->status();
+ } else {
+ delete_transient( 'gitium_remote_disconnected' );
+ $changes = array();
+ }
+
+ set_transient( 'gitium_uncommited_changes', $changes, 12 * 60 * 60 ); // cache changes for half-a-day
+ return $changes;
+}
+
+function _gitium_ssh_encode_buffer( $buffer ) {
+ $len = strlen( $buffer );
+ if ( ord( $buffer[0] ) & 0x80 ) {
+ $len++;
+ $buffer = "\x00" . $buffer;
+ }
+ return pack( 'Na*', $len, $buffer );
+}
+
+function _gitium_generate_keypair() {
+ $rsa_key = openssl_pkey_new(
+ array(
+ 'private_key_bits' => 2048,
+ 'private_key_type' => OPENSSL_KEYTYPE_RSA,
+ )
+ );
+
+ try {
+ $private_key = openssl_pkey_get_private( $rsa_key );
+ $try = openssl_pkey_export( $private_key, $pem ); //Private Key
+ if (!$try)
+ return false;
+ } catch (Exception $e) {
+ return false;
+ }
+
+ $key_info = openssl_pkey_get_details( $rsa_key );
+ $buffer = pack( 'N', 7 ) . 'ssh-rsa' .
+ _gitium_ssh_encode_buffer( $key_info['rsa']['e'] ) .
+ _gitium_ssh_encode_buffer( $key_info['rsa']['n'] );
+ $public_key = 'ssh-rsa ' . base64_encode( $buffer ) . ' gitium@' . parse_url( get_home_url(), PHP_URL_HOST );
+
+ return array( $public_key, $pem );
+}
+
+function gitium_get_keypair( $generate_new_keypair = false ) {
+ if ( $generate_new_keypair ) {
+ $keypair = _gitium_generate_keypair();
+ delete_option( 'gitium_keypair' );
+ add_option( 'gitium_keypair', $keypair, '', false );
+ }
+ if ( false === ( $keypair = get_option( 'gitium_keypair', false ) ) ) {
+ $keypair = _gitium_generate_keypair();
+ add_option( 'gitium_keypair', $keypair, '', false );
+ }
+ return $keypair;
+}
+
+function _gitium_generate_webhook_key() {
+ return md5( str_shuffle( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.()[]{}-_=+!@#%^&*~<>:;' ) );
+}
+
+function gitium_get_webhook_key( $generate_new_webhook_key = false ) {
+ if ( $generate_new_webhook_key ) {
+ $key = _gitium_generate_webhook_key();
+ delete_option( 'gitium_webhook_key' );
+ add_option( 'gitium_webhook_key', $key, '', false );
+ return $key;
+ }
+ if ( false === ( $key = get_option( 'gitium_webhook_key', false ) ) ) {
+ $key = _gitium_generate_webhook_key();
+ add_option( 'gitium_webhook_key', $key, '', false );
+ }
+ return $key;
+}
+
+function gitium_get_webhook() {
+ if ( defined( 'GIT_WEBHOOK_URL' ) && GIT_WEBHOOK_URL ) { return GIT_WEBHOOK_URL; }
+ $key = gitium_get_webhook_key();
+ $url = add_query_arg( 'key', $key, plugins_url( 'gitium-webhook.php', __FILE__ ) );
+ return apply_filters( 'gitium_webhook_url', $url, $key );
+}
+
+function gitium_admin_init() {
+ global $git;
+
+ $git_version = get_transient( 'gitium_git_version' );
+ if ( false === $git_version ) {
+ set_transient( 'gitium_git_version', $git->get_version() );
+ }
+}
+add_action( 'admin_init', 'gitium_admin_init' );
+
+add_action('admin_enqueue_scripts', 'enqueue_script_for_gitium_page');
+function enqueue_script_for_gitium_page($hook) {
+ // Check if the current page is your plugin's settings page
+ if ((isset($_GET['page']) && $_GET['page'] === 'gitium/gitium.php') || (isset($_GET['page']) && $_GET['page'] === 'gitium/gitium-settings.php')) {
+ // Enqueue your JavaScript file
+ wp_enqueue_script(
+ 'my-plugin-script', // Handle for the script
+ plugin_dir_url(__FILE__) . 'js/copy-to-clipboard.js', // URL to the script
+ array('jquery'), // Dependencies
+ '1.1', // Version number
+ true // Load in footer
+ );
+ }
+}
\ No newline at end of file
diff --git a/wp-content/upgrade-temp-backup/plugins/gitium/gitium-webhook.php b/wp-content/upgrade-temp-backup/plugins/gitium/gitium-webhook.php
new file mode 100644
index 00000000..47b82b06
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gitium/gitium-webhook.php
@@ -0,0 +1,81 @@
+
+ *
+ * Gitium 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 3 of the License, or
+ * any later version.
+ *
+ * Gitium 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 Gitium. If not, see .
+ *
+ * @package Gitium
+ */
+
+header( 'Content-Type: text/html' );
+define( 'SHORTINIT', true );
+
+$current_dir = __DIR__;
+
+// Define an array of possible WordPress root locations
+$try_wp_roots = [
+ getenv('DOCUMENT_ROOT'),
+ filter_input(INPUT_SERVER, 'DOCUMENT_ROOT', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
+ realpath($current_dir . '/../../../../../'),
+ realpath($current_dir . '/../../../../'),
+ realpath($current_dir . '/../../../'), // Typical WordPress structure
+ realpath($current_dir . '/../../'), // Alternative structure
+ realpath($current_dir . '/../'), // Closer parent directory
+ $current_dir, // Fallback to current directory
+];
+
+$wordpress_loader = null;
+
+foreach ($try_wp_roots as $root) {
+ if ($root && file_exists($root . '/wp-load.php')) {
+ $wordpress_loader = $root . '/wp-load.php';
+ break;
+ }
+}
+
+if ($wordpress_loader) {
+ require_once $wordpress_loader;
+} else {
+ die('Error: Unable to locate wp-load.php. Please verify your WordPress installation.');
+}
+
+require_once __DIR__ . '/functions.php';
+require_once __DIR__ . '/inc/class-git-wrapper.php';
+
+$webhook_key = get_option( 'gitium_webhook_key', '' );
+$get_key = filter_input(INPUT_GET, 'key', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
+if ( ! empty ( $webhook_key ) && isset( $get_key ) && $webhook_key == $get_key ) :
+ ( '1.7' <= substr( $git->get_version(), 0, 3 ) ) or wp_die( 'Gitium plugin require minimum `git version 1.7`!' );
+
+ list( $git_public_key, $git_private_key ) = gitium_get_keypair();
+ if ( ! $git_public_key || ! $git_private_key )
+ wp_die('Not ready.', 'Not ready.', array( 'response' => 403 ));
+ else
+ $git->set_key( $git_private_key );
+
+ $commits = array();
+ $commitmsg = sprintf( 'Merged changes from %s on %s', $_SERVER['SERVER_NAME'], date( 'm.d.Y' ) );
+
+ if ( $git->is_dirty() && $git->add() > 0 ) {
+ $commits[] = $git->commit( $commitmsg ) or trigger_error( 'Could not commit local changes!', E_USER_ERROR );
+ }
+ gitium_merge_and_push( $commits ) or trigger_error( 'Failed merge & push: ' . serialize( $git->get_last_error() ), E_USER_ERROR );
+
+ wp_die( $commitmsg , 'Pull done!', array( 'response' => 200 ) );
+else :
+ wp_die( 'Cheating uh?', 'Cheating uh?', array( 'response' => 403 ) );
+endif;
diff --git a/wp-content/upgrade-temp-backup/plugins/gitium/gitium.php b/wp-content/upgrade-temp-backup/plugins/gitium/gitium.php
new file mode 100644
index 00000000..e253488f
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gitium/gitium.php
@@ -0,0 +1,380 @@
+
+ *
+ * Gitium 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 3 of the License, or
+ * any later version.
+ *
+ * Gitium 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 Gitium. If not, see .
+ *
+ * @package Gitium
+ */
+
+define( 'GITIUM_LAST_COMMITS', 20 );
+define( 'GITIUM_MIN_GIT_VER', '1.7' );
+define( 'GITIUM_MIN_PHP_VER', '5.6' );
+
+if ( is_multisite() ) {
+ define( 'GITIUM_ADMIN_MENU_ACTION', 'network_admin_menu' );
+ define( 'GITIUM_ADMIN_NOTICES_ACTION', 'network_admin_notices' );
+ define( 'GITIUM_MANAGE_OPTIONS_CAPABILITY', 'manage_network_options' );
+} else {
+ define( 'GITIUM_ADMIN_MENU_ACTION', 'admin_menu' );
+ define( 'GITIUM_ADMIN_NOTICES_ACTION', 'admin_notices' );
+ define( 'GITIUM_MANAGE_OPTIONS_CAPABILITY', 'manage_options' );
+}
+
+require_once __DIR__ . '/functions.php';
+require_once __DIR__ . '/inc/class-git-wrapper.php';
+require_once __DIR__ . '/inc/class-gitium-requirements.php';
+require_once __DIR__ . '/inc/class-gitium-admin.php';
+require_once __DIR__ . '/inc/class-gitium-help.php';
+require_once __DIR__ . '/inc/class-gitium-menu.php';
+require_once __DIR__ . '/inc/class-gitium-menu-bubble.php';
+require_once __DIR__ . '/inc/class-gitium-submenu-configure.php';
+require_once __DIR__ . '/inc/class-gitium-submenu-status.php';
+require_once __DIR__ . '/inc/class-gitium-submenu-commits.php';
+require_once __DIR__ . '/inc/class-gitium-submenu-settings.php';
+
+function gitium_load_textdomain() {
+ load_plugin_textdomain( 'gitium', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
+}
+add_action( 'plugins_loaded', 'gitium_load_textdomain' );
+
+function _gitium_make_ssh_git_file_exe() {
+ $ssh_wrapper = dirname( __FILE__ ) . '/inc/ssh-git';
+ $process = proc_open(
+ "chmod -f +x $ssh_wrapper",
+ array(
+ 0 => array( 'pipe', 'r' ), // stdin
+ 1 => array( 'pipe', 'w' ), // stdout
+ ),
+ $pipes
+ );
+ if ( is_resource( $process ) ) {
+ fclose( $pipes[0] );
+ proc_close( $process );
+ }
+}
+register_activation_hook( __FILE__, '_gitium_make_ssh_git_file_exe' );
+
+function gitium_deactivation() {
+ delete_transient( 'gitium_git_version' );
+}
+register_deactivation_hook( __FILE__, 'gitium_deactivation' );
+
+function gitium_uninstall_hook() {
+ delete_transient( 'gitium_remote_tracking_branch' );
+ delete_transient( 'gitium_remote_disconnected' );
+ delete_transient( 'gitium_uncommited_changes' );
+ delete_transient( 'gitium_git_version' );
+ delete_transient( 'gitium_versions' );
+ delete_transient( 'gitium_menu_bubble' );
+ delete_transient( 'gitium_is_status_working' );
+
+ delete_option( 'gitium_keypair' );
+ delete_option( 'gitium_webhook_key' );
+}
+register_uninstall_hook( __FILE__, 'gitium_uninstall_hook' );
+
+/* Array
+(
+ [themes] => Array
+ (
+ [twentytwelve] => `Twenty Twelve` version 1.3
+ )
+ [plugins] => Array
+ (
+ [cron-view/cron-gui.php] => `Cron GUI` version 1.03
+ [hello-dolly/hello.php] => `Hello Dolly` version 1.6
+ )
+
+) */
+function gitium_update_versions() {
+ $new_versions = [];
+
+ // get all themes from WP
+ $all_themes = wp_get_themes( array( 'allowed' => true ) );
+ foreach ( $all_themes as $theme_name => $theme ) :
+ $theme_versions[ $theme_name ] = array(
+ 'name' => $theme->Name,
+ 'version' => null,
+ 'msg' => '',
+ );
+ $theme_versions[ $theme_name ]['msg'] = '`' . $theme->Name . '`';
+ $version = $theme->Version;
+ if ( ! empty( $version ) ) {
+ $theme_versions[ $theme_name ]['msg'] .= " version $version";
+ $theme_versions[ $theme_name ]['version'] .= $version;
+ }
+ endforeach;
+
+ if ( ! empty( $theme_versions ) ) {
+ $new_versions['themes'] = $theme_versions;
+ }
+ // get all plugins from WP
+ if ( ! function_exists( 'get_plugins' ) ) {
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
+ }
+ $all_plugins = get_plugins();
+ foreach ( $all_plugins as $name => $data ) :
+ $plugin_versions[ $name ] = array(
+ 'name' => $data['Name'],
+ 'version' => null,
+ 'msg' => '',
+ );
+ $plugin_versions[ $name ]['msg'] = "`{$data['Name']}`";
+ if ( ! empty( $data['Version'] ) ) {
+ $plugin_versions[ $name ]['msg'] .= ' version ' . $data['Version'];
+ $plugin_versions[ $name ]['version'] .= $data['Version'];
+ }
+ endforeach;
+
+ if ( ! empty( $plugin_versions ) ) {
+ $new_versions['plugins'] = $plugin_versions;
+ }
+
+ set_transient( 'gitium_versions', $new_versions );
+
+ return $new_versions;
+}
+add_action( 'load-plugins.php', 'gitium_update_versions', 999 );
+
+function gitium_upgrader_post_install( $res, $hook_extra, $result ) {
+ _gitium_make_ssh_git_file_exe();
+
+ $action = null;
+ $type = null;
+
+ // install logic
+ if ( isset( $hook_extra['type'] ) && ( 'plugin' === $hook_extra['type'] ) ) {
+ $action = 'installed';
+ $type = 'plugin';
+ } else if ( isset( $hook_extra['type'] ) && ( 'theme' === $hook_extra['type'] ) ) {
+ $action = 'installed';
+ $type = 'theme';
+ }
+
+ // update/upgrade logic
+ if ( isset( $hook_extra['plugin'] ) ) {
+ $action = 'updated';
+ $type = 'plugin';
+ } else if ( isset( $hook_extra['theme'] ) ) {
+ $action = 'updated';
+ $type = 'theme';
+ }
+
+ // get action if missed above
+ if ( isset( $hook_extra['action'] ) ) {
+ $action = $hook_extra['action'];
+ if ( 'install' === $action ) {
+ $action = 'installed';
+ }
+ if ( 'update' === $action ) {
+ $action = 'updated';
+ }
+ }
+
+ if ( WP_DEBUG ) {
+ error_log( __FUNCTION__ . ':hook_extra:' . serialize( $hook_extra ) );
+ error_log( __FUNCTION__ . ':action:type:' . $action . ':' . $type );
+ }
+
+ $git_dir = $result['destination'];
+ $version = '';
+
+ if ( ABSPATH == substr( $git_dir, 0, strlen( ABSPATH ) ) ) {
+ $git_dir = substr( $git_dir, strlen( ABSPATH ) );
+ }
+ switch ( $type ) {
+ case 'theme':
+ wp_clean_themes_cache();
+ $theme_data = wp_get_theme( $result['destination_name'] );
+ $name = $theme_data->get( 'Name' );
+ $version = $theme_data->get( 'Version' );
+ break;
+ case 'plugin':
+ foreach ( $result['source_files'] as $file ) :
+ if ( '.php' != substr( $file, -4 ) ) { continue; }
+ // every .php file is a possible plugin so we check if it's a plugin
+ $filepath = trailingslashit( $result['destination'] ) . $file;
+ $plugin_data = get_plugin_data( $filepath );
+ if ( $plugin_data['Name'] ) :
+ $name = $plugin_data['Name'];
+ $version = $plugin_data['Version'];
+ // We get info from the first plugin in the package
+ break;
+ endif;
+ endforeach;
+ break;
+ }
+ if ( empty( $name ) ) {
+ $name = $result['destination_name'];
+ }
+ $commit_message = _gitium_format_message( $name,$version,"$action $type" );
+ $commit = _gitium_commit_changes( $commit_message, $git_dir, false );
+ gitium_merge_and_push( $commit );
+
+ return $res;
+}
+add_filter( 'upgrader_post_install', 'gitium_upgrader_post_install', 10, 3 );
+
+// Checks for local changes, tries to group them by plugin/theme and pushes the changes
+function gitium_auto_push( $msg_prepend = '' ) {
+ global $git;
+ list( , $git_private_key ) = gitium_get_keypair();
+ if ( ! $git_private_key )
+ return;
+ $git->set_key( $git_private_key );
+
+ $commits = gitium_group_commit_modified_plugins_and_themes( $msg_prepend );
+ gitium_merge_and_push( $commits );
+ gitium_update_versions();
+}
+add_action( 'upgrader_process_complete', 'gitium_auto_push', 11, 0 );
+
+function gitium_check_after_activate_modifications( $plugin ) {
+ gitium_check_after_event( $plugin );
+}
+add_action( 'activated_plugin', 'gitium_check_after_activate_modifications', 999 );
+
+function gitium_check_after_deactivate_modifications( $plugin ) {
+ gitium_check_after_event( $plugin, 'deactivation' );
+}
+add_action( 'deactivated_plugin', 'gitium_check_after_deactivate_modifications', 999 );
+
+function gitium_check_for_plugin_deletions() { // Handle plugin deletion
+ // $_GET['deleted'] used to resemble if a plugin has been deleted (true)
+ // ...meanwhile commit b28dd45f3dad19f0e06c546fdc89ed5b24bacd72 in github.com/WordPress/WordPress...
+ // Now it resembles the number of deleted plugins (a number). Thanks WP
+ if ( isset( $_GET['deleted'] ) && ( 1 <= (int) $_GET['deleted'] || 'true' == $_GET['deleted'] ) ) {
+ gitium_auto_push();
+ }
+}
+add_action( 'load-plugins.php', 'gitium_check_for_plugin_deletions' );
+
+add_action( 'wp_ajax_wp-plugin-delete-success', 'gitium_auto_push' );
+add_action( 'wp_ajax_wp-theme-delete-success', 'gitium_auto_push' );
+
+function gitium_wp_plugin_delete_success() {
+?>
+
+
+
+=' ) )
+ add_action( 'wp_ajax_edit-theme-plugin-file', 'add_filter_for_ajax_save', 1, 0 );
+else
+ add_action( 'admin_enqueue_scripts', 'gitium_hook_plugin_and_theme_editor_page' );
+
+function gitium_options_page_check() {
+ global $git;
+ if ( ! $git->can_exec_git() ) { wp_die( 'Cannot exec git' ); }
+ return true;
+}
+
+function gitium_remote_disconnected_notice() {
+ if ( current_user_can( GITIUM_MANAGE_OPTIONS_CAPABILITY ) && $message = get_transient( 'gitium_remote_disconnected' ) ) : ?>
+
+
+ Could not connect to remote repository.
+
+
+
+
+
\ No newline at end of file
diff --git a/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-git-wrapper.php b/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-git-wrapper.php
new file mode 100644
index 00000000..de78d79e
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-git-wrapper.php
@@ -0,0 +1,680 @@
+
+ *
+ * Gitium 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 3 of the License, or
+ * any later version.
+ *
+ * Gitium 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 Gitium. If not, see .
+ *
+ * @package Gitium
+ */
+
+if (!defined('GITIGNORE'))
+ define('GITIGNORE', <<repo_dir = $repo_dir;
+ }
+
+ function _rrmdir( $dir ) {
+ if ( empty( $dir ) || ! is_dir( $dir ) ) {
+ return false;
+ }
+
+ $files = array_diff( scandir( $dir ), array( '.', '..' ) );
+ foreach ( $files as $file ) {
+ $filepath = realpath("$dir/$file");
+ ( is_dir( $filepath ) ) ? $this->_rrmdir( $filepath ) : unlink( $filepath );
+ }
+ return rmdir( $dir );
+ }
+
+ function _log(...$args) {
+ if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) { return; }
+
+ $output = '';
+ if (isset($args) && $args) foreach ( $args as $arg ) {
+ $output .= var_export($arg, true).'/n/n';
+ }
+
+ if ($output) error_log($output);
+ }
+
+ function _git_temp_key_file() {
+ $key_file = tempnam( sys_get_temp_dir(), 'ssh-git' );
+ return $key_file;
+ }
+
+ function set_key( $private_key ) {
+ $this->private_key = $private_key;
+ }
+
+ private function get_env() {
+ $env = array(
+ 'HOME' => getenv( 'HOME' ),
+ );
+ $key_file = null;
+
+ if ( defined( 'GIT_SSH' ) && GIT_SSH ) {
+ $env['GIT_SSH'] = GIT_SSH;
+ } else {
+ $env['GIT_SSH'] = dirname( __FILE__ ) . '/ssh-git';
+ }
+
+ if ( defined( 'GIT_KEY_FILE' ) && GIT_KEY_FILE ) {
+ $env['GIT_KEY_FILE'] = GIT_KEY_FILE;
+ } elseif ( $this->private_key ) {
+ $key_file = $this->_git_temp_key_file();
+ chmod( $key_file, 0600 );
+ file_put_contents( $key_file, $this->private_key );
+ $env['GIT_KEY_FILE'] = $key_file;
+ }
+
+ return $env;
+ }
+
+ protected function _call(...$args) {
+ $args = join( ' ', array_map( 'escapeshellarg', $args ) );
+ $return = -1;
+ $response = array();
+ $env = $this->get_env();
+
+ $git_bin_path = apply_filters( 'gitium_git_bin_path', '' );
+ $cmd = "{$git_bin_path}git $args 2>&1";
+
+ $proc = proc_open(
+ $cmd,
+ array(
+ 0 => array( 'pipe', 'r' ), // stdin
+ 1 => array( 'pipe', 'w' ), // stdout
+ ),
+ $pipes,
+ $this->repo_dir,
+ $env
+ );
+ if ( is_resource( $proc ) ) {
+ fclose( $pipes[0] );
+ while ( $line = fgets( $pipes[1] ) ) {
+ $response[] = rtrim( $line, "\n\r" );
+ }
+ $return = (int)proc_close( $proc );
+ }
+ $this->_log( "$return $cmd", join( "\n", $response ) );
+ if ( ! defined( 'GIT_KEY_FILE' ) && isset( $env['GIT_KEY_FILE'] ) ) {
+ unlink( $env['GIT_KEY_FILE'] );
+ }
+ if ( 0 != $return ) {
+ $this->last_error = join( "\n", $response );
+ } else {
+ $this->last_error = null;
+ }
+ return array( $return, $response );
+ }
+
+ function get_last_error() {
+ return $this->last_error;
+ }
+
+ function can_exec_git() {
+ list( $return, ) = $this->_call( 'version' );
+ return ( 0 == $return );
+ }
+
+ function is_status_working() {
+ list( $return, ) = $this->_call( 'status', '-s' );
+ return ( 0 == $return );
+ }
+
+ function get_version() {
+ list( $return, $version ) = $this->_call( 'version' );
+ if ( 0 != $return ) { return ''; }
+ if ( ! empty( $version[0] ) ) {
+ return substr( $version[0], 12 );
+ }
+ return '';
+ }
+
+ // git rev-list @{u}..
+ function get_ahead_commits() {
+ list( , $commits ) = $this->_call( 'rev-list', '@{u}..' );
+ return $commits;
+ }
+
+ // git rev-list ..@{u}
+ function get_behind_commits() {
+ list( , $commits ) = $this->_call( 'rev-list', '..@{u}' );
+ return $commits;
+ }
+
+ function init() {
+ file_put_contents( "$this->repo_dir/.gitignore", $this->gitignore );
+ list( $return, ) = $this->_call( 'init' );
+ $this->_call( 'config', 'user.email', 'gitium@presslabs.com' );
+ $this->_call( 'config', 'user.name', 'Gitium' );
+ $this->_call( 'config', 'push.default', 'matching' );
+ return ( 0 == $return );
+ }
+
+ function is_dot_git_dir( $dir ) {
+ $realpath = realpath( $dir );
+ $git_config = realpath( $realpath . '/config' );
+ $git_index = realpath( $realpath . '/index' );
+ if ( ! empty( $realpath ) && is_dir( $realpath ) && file_exists( $git_config ) && file_exists( $git_index ) ) {
+ return True;
+ }
+ return False;
+ }
+
+ function cleanup() {
+ $dot_git_dir = realpath( $this->repo_dir . '/.git' );
+ if ( $this->is_dot_git_dir( $dot_git_dir ) && $this->_rrmdir( $dot_git_dir ) ) {
+ if ( WP_DEBUG ) {
+ error_log( "Gitium cleanup successfull. Removed '$dot_git_dir'." );
+ }
+ return True;
+ }
+ if ( WP_DEBUG ) {
+ error_log( "Gitium cleanup failed. '$dot_git_dir' is not a .git dir." );
+ }
+ return False;
+ }
+
+ function add_remote_url( $url ) {
+ list( $return, ) = $this->_call( 'remote', 'add', 'origin', $url );
+ return ( 0 == $return );
+ }
+
+ function get_remote_url() {
+ list( , $response ) = $this->_call( 'config', '--get', 'remote.origin.url' );
+ if ( isset( $response[0] ) ) {
+ return $response[0];
+ }
+ return '';
+ }
+
+ function remove_remote() {
+ list( $return, ) = $this->_call( 'remote', 'rm', 'origin');
+ return ( 0 == $return );
+ }
+
+ function get_remote_tracking_branch() {
+ list( $return, $response ) = $this->_call( 'rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}' );
+ if ( 0 == $return ) {
+ return $response[0];
+ }
+ return false;
+ }
+
+ function get_local_branch() {
+ list( $return, $response ) = $this->_call( 'rev-parse', '--abbrev-ref', 'HEAD' );
+ if ( 0 == $return ) {
+ return $response[0];
+ }
+ return false;
+ }
+
+ function fetch_ref() {
+ list( $return, ) = $this->_call( 'fetch', 'origin' );
+ return ( 0 == $return );
+ }
+
+ protected function _resolve_merge_conflicts( $message ) {
+ list( , $changes ) = $this->status( true );
+ $this->_log( $changes );
+ foreach ( $changes as $path => $change ) {
+ if ( in_array( $change, array( 'UD', 'DD' ) ) ) {
+ $this->_call( 'rm', $path );
+ $message .= "\n\tConflict: $path [removed]";
+ } elseif ( 'DU' == $change ) {
+ $this->_call( 'add', $path );
+ $message .= "\n\tConflict: $path [added]";
+ } elseif ( in_array( $change, array( 'AA', 'UU', 'AU', 'UA' ) ) ) {
+ $this->_call( 'checkout', '--theirs', $path );
+ $this->_call( 'add', '--all', $path );
+ $message .= "\n\tConflict: $path [local version]";
+ }
+ }
+ $this->commit( $message );
+ }
+
+ function get_commit_message( $commit ) {
+ list( $return, $response ) = $this->_call( 'log', '--format=%B', '-n', '1', $commit );
+ return ( $return !== 0 ? false : join( "\n", $response ) );
+ }
+
+ private function strpos_haystack_array( $haystack, $needle, $offset=0 ) {
+ if ( ! is_array( $haystack ) ) { $haystack = array( $haystack ); }
+
+ foreach ( $haystack as $query ) {
+ if ( strpos( $query, $needle, $offset) !== false ) { return true; }
+ }
+ return false;
+ }
+
+ private function cherry_pick( $commits ) {
+ foreach ( $commits as $commit ) {
+ if ( empty( $commit ) ) { return false; }
+
+ list( $return, $response ) = $this->_call( 'cherry-pick', $commit );
+
+ // abort the cherry-pick if the changes are already pushed
+ if ( false !== $this->strpos_haystack_array( $response, 'previous cherry-pick is now empty' ) ) {
+ $this->_call( 'cherry-pick', '--abort' );
+ continue;
+ }
+
+ if ( $return != 0 ) {
+ $this->_resolve_merge_conflicts( $this->get_commit_message( $commit ) );
+ }
+ }
+ }
+
+ function merge_with_accept_mine(...$commits) {
+ do_action( 'gitium_before_merge_with_accept_mine' );
+
+ if ( 1 == count($commits) && is_array( $commits[0] ) ) {
+ $commits = $commits[0];
+ }
+
+ // get ahead commits
+ $ahead_commits = $this->get_ahead_commits();
+
+ // combine all commits with the ahead commits
+ $commits = array_unique( array_merge( array_reverse( $commits ), $ahead_commits ) );
+ $commits = array_reverse( $commits );
+
+ // get the remote branch
+ $remote_branch = $this->get_remote_tracking_branch();
+
+ // get the local branch
+ $local_branch = $this->get_local_branch();
+
+ // rename the local branch to 'merge_local'
+ $this->_call( 'branch', '-m', 'merge_local' );
+
+ // local branch set up to track remote branch
+ $this->_call( 'branch', $local_branch, $remote_branch );
+
+ // checkout to the $local_branch
+ list( $return, ) = $this->_call( 'checkout', $local_branch );
+ if ( $return != 0 ) {
+ $this->_call( 'branch', '-M', $local_branch );
+ return false;
+ }
+
+ // don't cherry pick if there are no commits
+ if ( count( $commits ) > 0 ) {
+ $this->cherry_pick( $commits );
+ }
+
+ if ( $this->successfully_merged() ) { // git status without states: AA, DD, UA, AU ...
+ // delete the 'merge_local' branch
+ $this->_call( 'branch', '-D', 'merge_local' );
+ return true;
+ } else {
+ $this->_call( 'cherry-pick', '--abort' );
+ $this->_call( 'checkout', '-b', 'merge_local' );
+ $this->_call( 'branch', '-M', $local_branch );
+ return false;
+ }
+ }
+
+ function successfully_merged() {
+ list( , $response ) = $this->status( true );
+ $changes = array_values( $response );
+ return ( 0 == count( array_intersect( $changes, array( 'DD', 'AU', 'UD', 'UA', 'DU', 'AA', 'UU' ) ) ) );
+ }
+
+ function merge_initial_commit( $commit, $branch ) {
+ list( $return, ) = $this->_call( 'branch', '-m', 'initial' );
+ if ( 0 != $return ) {
+ return false;
+ }
+ list( $return, ) = $this->_call( 'checkout', $branch );
+ if ( 0 != $return ) {
+ return false;
+ }
+ list( $return, ) = $this->_call(
+ 'cherry-pick', '--strategy', 'recursive', '--strategy-option', 'theirs', $commit
+ );
+ if ( $return != 0 ) {
+ $this->_resolve_merge_conflicts( $this->get_commit_message( $commit ) );
+ if ( ! $this->successfully_merged() ) {
+ $this->_call( 'cherry-pick', '--abort' );
+ $this->_call( 'checkout', 'initial' );
+ return false;
+ }
+ }
+ $this->_call( 'branch', '-D', 'initial' );
+ return true;
+ }
+
+ function get_remote_branches() {
+ list( , $response ) = $this->_call( 'branch', '-r' );
+ $response = array_map( 'trim', $response );
+ $response = array_map( function( $b ) { return str_replace( "origin/", "", $b ); }, $response );
+ return $response;
+ }
+
+ function add(...$args) {
+ if ( 1 == count($args) && is_array( $args[0] ) ) {
+ $args = $args[0];
+ }
+ $params = array_merge( array( 'add', '-n', '--all' ), $args );
+ list ( , $response ) = call_user_func_array( array( $this, '_call' ), $params );
+ $count = count( $response );
+
+ $params = array_merge( array( 'add', '--all' ), $args );
+ list ( , $response ) = call_user_func_array( array( $this, '_call' ), $params );
+
+ return $count;
+ }
+
+ function commit( $message, $author_name = '', $author_email = '' ) {
+ $author = '';
+ if ( $author_email ) {
+ if ( empty( $author_name ) ) {
+ $author_name = $author_email;
+ }
+ $author = "$author_name <$author_email>";
+ }
+
+ if ( ! empty( $author ) ) {
+ list( $return, $response ) = $this->_call( 'commit', '-m', $message, '--author', $author );
+ } else {
+ list( $return, $response ) = $this->_call( 'commit', '-m', $message );
+ }
+ if ( $return !== 0 ) { return false; }
+
+ list( $return, $response ) = $this->_call( 'rev-parse', 'HEAD' );
+
+ return ( $return === 0 ) ? $response[0] : false;
+ }
+
+ function push( $branch = '' ) {
+ if ( ! empty( $branch ) ) {
+ list( $return, ) = $this->_call( 'push', '--porcelain', '-u', 'origin', $branch );
+ } else {
+ list( $return, ) = $this->_call( 'push', '--porcelain', '-u', 'origin', 'HEAD' );
+ }
+ return ( $return == 0 );
+ }
+
+ /*
+ * Get uncommited changes with status porcelain
+ * git status --porcelain
+ * It returns an array like this:
+ array(
+ file => deleted|modified
+ ...
+ )
+ */
+ function get_local_changes() {
+ list( $return, $response ) = $this->_call( 'status', '--porcelain' );
+
+ if ( 0 !== $return ) {
+ return array();
+ }
+ $new_response = array();
+ if ( ! empty( $response ) ) {
+ foreach ( $response as $line ) :
+ $work_tree_status = substr( $line, 1, 1 );
+ $path = substr( $line, 3 );
+
+ if ( ( '"' == $path[0] ) && ('"' == $path[strlen( $path ) - 1] ) ) {
+ // git status --porcelain will put quotes around paths with whitespaces
+ // we don't want the quotes, let's get rid of them
+ $path = substr( $path, 1, strlen( $path ) - 2 );
+ }
+
+ if ( 'D' == $work_tree_status ) {
+ $action = 'deleted';
+ } else {
+ $action = 'modified';
+ }
+ $new_response[ $path ] = $action;
+ endforeach;
+ }
+ return $new_response;
+ }
+
+ function get_uncommited_changes() {
+ list( , $changes ) = $this->status();
+ return $changes;
+ }
+
+ function local_status() {
+ list( $return, $response ) = $this->_call( 'status', '-s', '-b', '-u' );
+ if ( 0 !== $return ) {
+ return array( '', array() );
+ }
+
+ $new_response = array();
+ if ( ! empty( $response ) ) {
+ $branch_status = array_shift( $response );
+ foreach ( $response as $idx => $line ) :
+ unset( $index_status, $work_tree_status, $path, $new_path, $old_path );
+
+ if ( empty( $line ) ) { continue; } // ignore empty lines like the last item
+ if ( '#' == $line[0] ) { continue; } // ignore branch status
+
+ $index_status = substr( $line, 0, 1 );
+ $work_tree_status = substr( $line, 1, 1 );
+ $path = substr( $line, 3 );
+
+ $old_path = '';
+ $new_path = explode( '->', $path );
+ if ( ( 'R' === $index_status ) && ( ! empty( $new_path[1] ) ) ) {
+ $old_path = trim( $new_path[0] );
+ $path = trim( $new_path[1] );
+ }
+ $new_response[ $path ] = trim( $index_status . $work_tree_status . ' ' . $old_path );
+ endforeach;
+ }
+
+ return array( $branch_status, $new_response );
+ }
+
+ function status( $local_only = false ) {
+ list( $branch_status, $new_response ) = $this->local_status();
+
+ if ( $local_only ) { return array( $branch_status, $new_response ); }
+
+ $behind_count = 0;
+ $ahead_count = 0;
+ if ( preg_match( '/## ([^.]+)\.+([^ ]+)/', $branch_status, $matches ) ) {
+ $local_branch = $matches[1];
+ $remote_branch = $matches[2];
+
+ list( , $response ) = $this->_call( 'rev-list', "$local_branch..$remote_branch", '--count' );
+ $behind_count = (int)$response[0];
+
+ list( , $response ) = $this->_call( 'rev-list', "$remote_branch..$local_branch", '--count' );
+ $ahead_count = (int)$response[0];
+ }
+
+ if ( $behind_count ) {
+ list( , $response ) = $this->_call( 'diff', '-z', '--name-status', "$local_branch~$ahead_count", $remote_branch );
+ $response = explode( chr( 0 ), $response[0] );
+ array_pop( $response );
+ for ( $idx = 0 ; $idx < count( $response ) / 2 ; $idx++ ) {
+ $file = $response[ $idx * 2 + 1 ];
+ $change = $response[ $idx * 2 ];
+ if ( ! isset( $new_response[ $file ] ) ) {
+ $new_response[ $file ] = "r$change";
+ }
+ }
+ }
+ return array( $branch_status, $new_response );
+ }
+
+ /*
+ * Checks if repo has uncommited changes
+ * git status --porcelain
+ */
+ function is_dirty() {
+ $changes = $this->get_uncommited_changes();
+ return ! empty( $changes );
+ }
+
+ /**
+ * Return the last n commits
+ */
+ function get_last_commits( $n = 20 ) {
+ list( $return, $message ) = $this->_call( 'log', '-n', $n, '--pretty=format:%s' );
+ if ( 0 !== $return ) { return false; }
+
+ list( $return, $response ) = $this->_call( 'log', '-n', $n, '--pretty=format:%h|%an|%ae|%ad|%cn|%ce|%cd' );
+ if ( 0 !== $return ) { return false; }
+
+ foreach ( $response as $index => $value ) {
+ $commit_info = explode( '|', $value );
+ $commits[ $commit_info[0] ] = array(
+ 'subject' => $message[ $index ],
+ 'author_name' => $commit_info[1],
+ 'author_email' => $commit_info[2],
+ 'author_date' => $commit_info[3],
+ );
+ if ( $commit_info[1] != $commit_info[4] && $commit_info[2] != $commit_info[5] ) {
+ $commits[ $commit_info[0] ]['committer_name'] = $commit_info[4];
+ $commits[ $commit_info[0] ]['committer_email'] = $commit_info[5];
+ $commits[ $commit_info[0] ]['committer_date'] = $commit_info[6];
+ }
+ }
+ return $commits;
+ }
+
+ public function set_gitignore( $content ) {
+ file_put_contents( $this->repo_dir . '/.gitignore', $content );
+ return true;
+ }
+
+ public function get_gitignore() {
+ return file_get_contents( $this->repo_dir . '/.gitignore' );
+ }
+
+ /**
+ * Remove files in .gitignore from version control
+ */
+ function rm_cached( $path ) {
+ list( $return, ) = $this->_call( 'rm', '--cached', $path );
+ return ( $return == 0 );
+ }
+
+ function remove_wp_content_from_version_control() {
+ $process = proc_open(
+ 'rm -rf ' . ABSPATH . '/wp-content/.git',
+ array(
+ 0 => array( 'pipe', 'r' ), // stdin
+ 1 => array( 'pipe', 'w' ), // stdout
+ ),
+ $pipes
+ );
+ if ( is_resource( $process ) ) {
+ fclose( $pipes[0] );
+ proc_close( $process );
+ return true;
+ }
+ return false;
+ }
+}
+
+if ( ! defined( 'GIT_DIR' ) ) {
+ define( 'GIT_DIR', dirname( WP_CONTENT_DIR ) );
+}
+
+# global is needed here for wp-cli as it includes/exec files inside a function scope
+# this forces the context to really be global :\.
+global $git;
+$git = new Git_Wrapper( GIT_DIR );
diff --git a/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-admin.php b/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-admin.php
new file mode 100644
index 00000000..0c0a3d8e
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-admin.php
@@ -0,0 +1,58 @@
+
+ *
+ * Gitium 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 3 of the License, or
+ * any later version.
+ *
+ * Gitium 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 Gitium. If not, see .
+ *
+ * @package Gitium
+ */
+class Gitium_Admin {
+
+ public function __construct() {
+ global $git;
+
+ list( , $git_private_key ) = gitium_get_keypair();
+ $git->set_key( $git_private_key );
+
+ if ( current_user_can( GITIUM_MANAGE_OPTIONS_CAPABILITY ) ) {
+ $req = new Gitium_Requirements();
+ if ( ! $req->get_status() ) {
+ return false;
+ }
+
+ if ( $this->has_configuration() ) {
+ new Gitium_Submenu_Status();
+ new Gitium_Submenu_Commits();
+ new Gitium_Submenu_Settings();
+ new Gitium_Menu_Bubble();
+ } else {
+ new Gitium_Submenu_Configure();
+ }
+ }
+ }
+
+ public function has_configuration() {
+ return _gitium_is_status_working() && _gitium_get_remote_tracking_branch();
+ }
+}
+
+if ( ( is_admin() && ! is_multisite() ) || ( is_network_admin() && is_multisite() ) ) {
+ add_action( 'init', 'gitium_admin_page' );
+ function gitium_admin_page() {
+ new Gitium_Admin();
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-help.php b/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-help.php
new file mode 100644
index 00000000..57416798
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-help.php
@@ -0,0 +1,113 @@
+
+ *
+ * Gitium 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 3 of the License, or
+ * any later version.
+ *
+ * Gitium 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 Gitium. If not, see .
+ *
+ * @package Gitium
+ */
+
+class Gitium_Help {
+
+ public function __construct( $hook, $help = 'gitium' ) {
+ add_action( "load-{$hook}", array( $this, $help ), 20 );
+ }
+
+ private function general() {
+ $screen = get_current_screen();
+ $screen->add_help_tab( array( 'id' => 'gitium', 'title' => __( 'Gitium', 'gitium' ), 'callback' => array( $this, 'gitium' ) ) );
+ $screen->add_help_tab( array( 'id' => 'faq', 'title' => __( 'F.A.Q.', 'gitium' ), 'callback' => array( $this, 'faq' ) ) );
+ $screen->add_help_tab( array( 'id' => 'requirements', 'title' => __( 'Requirements', 'gitium' ), 'callback' => array( $this, 'requirements_callback' ) ) );
+ $screen->set_help_sidebar( '
' );
+ }
+
+ public function gitium() {
+ echo '' . __( 'Gitium enables continuous deployment for WordPress integrating with tools such as Github, Bitbucket or Travis-CI. Plugin and theme updates, installs and removals are automatically versioned.', 'gitium' ) . '
';
+ echo '' . __( 'Ninja code edits from the WordPress editor are also tracked into version control. Gitium is designed for sane development environments.', 'gitium' ) . '
';
+ echo '' . __( 'Staging and production can follow different branches of the same repository. You can deploy code simply trough git push.', 'gitium' ) . '
';
+ echo '' . __( 'Gitium requires git command line tool minimum version 1.7 installed on the server and proc_open PHP function enabled.', 'gitium' ) . '
';
+ }
+
+ public function faq() {
+ echo '' . __( 'Could not connect to remote repository?', 'gitium' ) . '
'. __( 'If you encounter this kind of error you can try to fix it by setting the proper username of the .git directory.', 'gitium' ) . '
' . __( 'Example', 'gitium' ) .': chown -R www-data:www-data .git
';
+ echo '' . __( 'Is this plugin considered stable?', 'gitium' ) . '
'. __( 'Right now this plugin is considered alpha quality and should be used in production environments only by adventurous kinds.', 'gitium' ) . '
';
+ echo '' . __( 'What happens in case of conflicts?', 'gitium' ) . '
'. __( 'The behavior in case of conflicts is to overwrite the changes on the origin repository with the local changes (ie. local modifications take precedence over remote ones).', 'gitium' ) . '
';
+ echo '' . __( 'How to deploy automatically after a push?', 'gitium' ) . '
'. __( 'You can ping the webhook url after a push to automatically deploy the new code. The webhook url can be found under Code menu. This url plays well with Github or Bitbucket webhooks.', 'gitium' ) . '
';
+ echo '' . __( 'Does it works on multi site setups?', 'gitium' ) . '
'. __( 'Gitium is not supporting multisite setups at the moment.', 'gitium' ) . '
';
+ echo '' . __( 'How does gitium handle submodules?', 'gitium' ) . '
'. __( 'Currently submodules are not supported.', 'gitium' ) . '
';
+ }
+
+ public function requirements_callback() {
+ echo '' . __( 'Gitium requires:', 'gitium' ) . '
';
+ echo '' . __( 'the function proc_open available', 'gitium' ) . '
';
+ echo '' . __( 'can exec the file inc/ssh-git', 'gitium' ) . '
';
+
+ printf( '' . __( 'git version >= %s', 'gitium' ) . '
', GITIUM_MIN_GIT_VER );
+ printf( '' . __( 'PHP version >= %s', 'gitium' ) . '
', GITIUM_MIN_PHP_VER );
+ }
+
+ public function configuration() {
+ $screen = get_current_screen();
+ $screen->add_help_tab( array( 'id' => 'configuration', 'title' => __( 'Configuration', 'gitium' ), 'callback' => array( $this, 'configuration_callback' ) ) );
+ $this->general();
+ }
+
+ public function configuration_callback() {
+ echo '' . __( 'Configuration step 1', 'gitium' ) . '
' . __( 'In this step you must specify the Remote URL. This URL represents the link between the git sistem and your site.', 'gitium' ) . '
';
+ echo '' . __( 'You can get this URL from your Git repository and it looks like this:', 'gitium' ) . '
';
+ echo '' . __( 'github.com -> git@github.com:user/example.git', 'gitium' ) . '
';
+ echo '' . __( 'bitbucket.org -> git@bitbucket.org:user/glowing-happiness.git', 'gitium' ) . '
';
+ echo '' . __( 'To go to the next step, fill the Remote URL and then press the Fetch button.', 'gitium' ) . '
';
+ echo '' . __( 'Configuration step 2', 'gitium' ) . '
' . __( 'In this step you must select the branch you want to follow.', 'gitium' ) . '
';
+ echo '' . __( 'Only this branch will have all of your code modifications.', 'gitium' ) . '
';
+ echo '' . __( 'When you push the button Merge & Push, all code(plugins & themes) will be pushed on the git repository.', 'gitium' ) . '
';
+ }
+
+ public function status() {
+ $screen = get_current_screen();
+ $screen->add_help_tab( array( 'id' => 'status', 'title' => __( 'Status', 'gitium' ), 'callback' => array( $this, 'status_callback' ) ) );
+ $this->general();
+ }
+
+ public function status_callback() {
+ echo '' . __( 'On status page you can see what files are modified, and you can commit the changes to git.', 'gitium' ) . '
';
+ }
+
+ public function commits() {
+ $screen = get_current_screen();
+ $screen->add_help_tab( array( 'id' => 'commits', 'title' => __( 'Commits', 'gitium' ), 'callback' => array( $this, 'commits_callback' ) ) );
+ $this->general();
+ }
+
+ public function commits_callback() {
+ echo '' . __( 'You may be wondering what is the difference between author and committer.', 'gitium' ) . '
';
+ echo '' . __( 'The author is the person who originally wrote the patch, whereas the committer is the person who last applied the patch.', 'gitium' ) . '
';
+ echo '' . __( 'So, if you send in a patch to a project and one of the core members applies the patch, both of you get credit — you as the author and the core member as the committer.', 'gitium' ) . '
';
+ }
+
+ public function settings() {
+ $screen = get_current_screen();
+ $screen->add_help_tab( array( 'id' => 'settings', 'title' => __( 'Settings', 'gitium' ), 'callback' => array( $this, 'settings_callback' ) ) );
+ $this->general();
+ }
+
+ public function settings_callback() {
+ echo '' . __( 'Each line from the gitignore file specifies a pattern.', 'gitium' ) . '
';
+ echo '' . __( 'When deciding whether to ignore a path, Git normally checks gitignore patterns from multiple sources, with the following order of precedence, from highest to lowest (within one level of precedence, the last matching pattern decides the outcome)', 'gitium' ) . '
';
+ echo '' . sprintf( __( 'Read more on %s', 'gitium' ), 'git documentation' ) . '
';
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-menu-bubble.php b/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-menu-bubble.php
new file mode 100644
index 00000000..c1a8a838
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-menu-bubble.php
@@ -0,0 +1,61 @@
+
+ *
+ * Gitium 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 3 of the License, or
+ * any later version.
+ *
+ * Gitium 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 Gitium. If not, see .
+ *
+ * @package Gitium
+ */
+
+class Gitium_Menu_Bubble extends Gitium_Menu {
+
+ public function __construct() {
+ parent::__construct( $this->gitium_menu_slug, $this->gitium_menu_slug );
+ add_action( GITIUM_ADMIN_MENU_ACTION, array( $this, 'add_menu_bubble' ) );
+ }
+
+ public function add_menu_bubble() {
+ global $menu;
+
+ if ( ! _gitium_is_status_working() ) {
+ foreach ( $menu as $key => $value ) {
+ if ( $this->menu_slug == $menu[ $key ][2] ) {
+ $menu_bubble = get_transient( 'gitium_menu_bubble' );
+ if ( false === $menu_bubble ) { $menu_bubble = ''; }
+ $menu[ $key ][0] = str_replace( $menu_bubble, '', $menu[ $key ][0] );
+ delete_transient( 'gitium_menu_bubble' );
+ return;
+ }
+ }
+ }
+
+ list( , $changes ) = _gitium_status();
+
+ if ( ! empty( $changes ) ) :
+ $bubble_count = count( $changes );
+ foreach ( $menu as $key => $value ) {
+ if ( $this->menu_slug == $menu[ $key ][2] ) {
+ $menu_bubble = " "
+ . $bubble_count . '';
+ $menu[ $key ][0] .= $menu_bubble;
+ set_transient( 'gitium_menu_bubble', $menu_bubble );
+ return;
+ }
+ }
+ endif;
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-menu.php b/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-menu.php
new file mode 100644
index 00000000..9adac247
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-menu.php
@@ -0,0 +1,103 @@
+
+ *
+ * Gitium 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 3 of the License, or
+ * any later version.
+ *
+ * Gitium 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 Gitium. If not, see .
+ *
+ * @package Gitium
+ */
+
+class Gitium_Menu {
+
+ public $gitium_menu_slug = 'gitium/gitium.php';
+ public $commits_menu_slug = 'gitium/gitium-commits.php';
+ public $settings_menu_slug = 'gitium/gitium-settings.php';
+
+ public $git = null;
+
+ public $menu_slug;
+ public $submenu_slug;
+
+ public function __construct( $menu_slug, $submenu_slug ) {
+ global $git;
+ $this->git = $git;
+
+ $this->menu_slug = $menu_slug;
+ $this->submenu_slug = $submenu_slug;
+ }
+
+ public function redirect( $message = '', $success = false, $menu_slug = '' ) {
+ $message_id = substr(
+ md5( str_shuffle( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' ) . time() ), 0, 8
+ );
+ if ( $message ) {
+ set_transient( 'message_' . $message_id, $message, 900 );
+ }
+ if ( '' === $menu_slug ) { $menu_slug = $this->menu_slug; }
+ $url = network_admin_url( 'admin.php?page=' . $menu_slug );
+ $url = esc_url_raw( add_query_arg(
+ array(
+ 'message' => $message_id,
+ 'success' => $success,
+ ),
+ $url
+ ) );
+ wp_safe_redirect( $url );
+ exit;
+ }
+
+ public function success_redirect( $message = '', $menu_slug = '' ) {
+ $this->redirect( $message, true, $menu_slug );
+ }
+
+ public function disconnect_repository() {
+ $gitium_disconnect_repo = filter_input(INPUT_POST, 'GitiumSubmitDisconnectRepository', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
+
+ if ( ! isset( $gitium_disconnect_repo ) ) {
+ return;
+ }
+ check_admin_referer( 'gitium-admin' );
+ gitium_uninstall_hook();
+ if ( ! $this->git->remove_remote() ) {
+ $this->redirect( __('Could not remove remote.', 'gitium') );
+ }
+ $this->success_redirect( __('You are now disconnected from the repository. New key pair generated.', 'gitium') );
+ }
+
+ public function show_message() {
+ $get_message = filter_input(INPUT_GET, 'message', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
+ $get_success = filter_input(INPUT_GET, 'success', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
+ if ( isset( $get_message ) && $get_message ) {
+ $type = ( isset( $get_success ) && $get_success == 1 ) ? 'updated' : 'error';
+ $message = get_transient( 'message_'. $get_message );
+ if ( $message ) : ?>
+
+
+
+
+ *
+ * Gitium 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 3 of the License, or
+ * any later version.
+ *
+ * Gitium 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 Gitium. If not, see .
+ *
+ * @package Gitium
+ */
+
+class Gitium_Requirements {
+
+ private $req = array();
+ private $msg = array();
+
+ /**
+ * Gitium requires:
+ * git min version
+ * the function proc_open available
+ * PHP min version
+ * can exec the file inc/ssh-git
+ */
+ public function __construct() {
+ $this->_check_req();
+ add_action( GITIUM_ADMIN_NOTICES_ACTION, array( $this, 'admin_notices' ) );
+ }
+
+ private function _check_req() {
+ list($this->req['is_git_version'], $this->msg['is_git_version'] ) = $this->is_git_version();
+ list($this->req['is_proc_open'], $this->msg['is_proc_open'] ) = $this->is_proc_open();
+ list($this->req['is_php_verion'], $this->msg['is_php_verion'] ) = $this->is_php_version();
+ list($this->req['can_exec_ssh_git_file'],$this->msg['can_exec_ssh_git_file']) = $this->can_exec_ssh_git_file();
+
+ return $this->req;
+ }
+
+ public function admin_notices() {
+ if ( ! current_user_can( GITIUM_MANAGE_OPTIONS_CAPABILITY ) ) {
+ return;
+ }
+
+ foreach ( $this->req as $key => $value ) {
+ if ( false === $value ) {
+ echo "Gitium Requirement: {$this->msg[$key]}
";
+ }
+ }
+ }
+
+ public function get_status() {
+ $requirements = $this->req;
+
+ foreach ( $requirements as $req ) :
+ if ( false === $req ) :
+ return false;
+ endif;
+ endforeach;
+
+ return true;
+ }
+
+ private function is_git_version() {
+ $git_version = get_transient( 'gitium_git_version' );
+
+ if ( GITIUM_MIN_GIT_VER > substr( $git_version, 0, 3 ) ) {
+ global $git;
+ $git_version = $git->get_version();
+ set_transient( 'gitium_git_version', $git_version );
+ if ( empty( $git_version ) ) {
+ return array( false, 'There is no git installed on this server.' );
+ } else if ( GITIUM_MIN_GIT_VER > substr( $git_version, 0, 3 ) ) {
+ return array( false, "The git version is `$git_version` and must be greater than `" . GITIUM_MIN_GIT_VER . "`!" );
+ }
+ }
+
+ return array( true, "The git version is `$git_version`." );
+ }
+
+ private function is_proc_open() {
+ if ( ! function_exists( 'proc_open' ) ) {
+ return array( false, 'The function `proc_open` is disabled!' );
+ } else {
+ return array( true, 'The function `proc_open` is enabled!' );
+ }
+ }
+
+ private function is_php_version() {
+ if ( ! function_exists( 'phpversion' ) ) {
+ return array( false, 'The function `phpversion` is disabled!' );
+ } else {
+ $php_version = phpversion();
+ if ( GITIUM_MIN_PHP_VER <= substr( $php_version, 0, 3 ) ) {
+ return array( true, "The PHP version is `$php_version`." );
+ } else {
+ return array( false, "The PHP version is `$php_version` and is not greater or equal to " . GITIUM_MIN_PHP_VER );
+ }
+ }
+ }
+
+ private function can_exec_ssh_git_file() {
+ $filepath = dirname( __FILE__ ) . '/ssh-git';
+
+ if ( ! function_exists( 'is_executable' ) ) {
+ return array( false, 'The function `is_executable` is disabled!' );
+ } else if ( is_executable( $filepath ) ) {
+ return array( true, "The `$filepath` file can be executed!" );
+ } else {
+ return array( false, "The `$filepath` file is not executable" );
+ }
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-submenu-commits.php b/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-submenu-commits.php
new file mode 100644
index 00000000..e204c487
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-submenu-commits.php
@@ -0,0 +1,100 @@
+
+ *
+ * Gitium 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 3 of the License, or
+ * any later version.
+ *
+ * Gitium 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 Gitium. If not, see .
+ *
+ * @package Gitium
+ */
+
+class Gitium_Submenu_Commits extends Gitium_Menu {
+
+ public function __construct() {
+ parent::__construct( $this->gitium_menu_slug, $this->commits_menu_slug );
+ add_action( GITIUM_ADMIN_MENU_ACTION, array( $this, 'admin_menu' ) );
+ }
+
+ public function admin_menu() {
+ $submenu_hook = add_submenu_page(
+ $this->menu_slug,
+ __( 'Git Commits', 'gitium' ),
+ __( 'Commits', 'gitium' ),
+ GITIUM_MANAGE_OPTIONS_CAPABILITY,
+ $this->submenu_slug,
+ array( $this, 'page' )
+ );
+ new Gitium_Help( $submenu_hook, 'commits' );
+ }
+
+ public function table_head() {
+ ?>
+
+
+
+
+
+
+ ';
+ }
+
+ public function table_start_row() {
+ static $counter = 0;
+ $counter++;
+ echo ( 0 != $counter % 2 ) ? '' : ' ';
+ }
+
+ public function page() {
+ ?>
+
+
+
+ table_head(); ?>
+
+ git->get_last_commits( GITIUM_LAST_COMMITS ) as $commit_id => $data ) {
+ unset( $committer_name );
+ extract( $data );
+ if ( isset( $committer_name ) ) {
+ $committer = " -> $committer_name " . sprintf( __( 'committed %s ago', 'gitium' ), human_time_diff( strtotime( $committer_date ) ) ) . '';
+ $committers_avatar = '' . get_avatar( $committer_email, 16 ) . '';
+ } else {
+ $committer = '';
+ $committers_avatar = '';
+ }
+ $this->table_start_row();
+ ?>
+
+
+
+
+
+
+
+ table_end_row();
+ }
+ ?>
+
+
+
+
+ *
+ * Gitium 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 3 of the License, or
+ * any later version.
+ *
+ * Gitium 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 Gitium. If not, see .
+ *
+ * @package Gitium
+ */
+
+class Gitium_Submenu_Configure extends Gitium_Menu {
+
+ public function __construct() {
+ parent::__construct( $this->gitium_menu_slug, $this->gitium_menu_slug );
+
+ if ( current_user_can( GITIUM_MANAGE_OPTIONS_CAPABILITY ) ) {
+ add_action( GITIUM_ADMIN_MENU_ACTION, array( $this, 'admin_menu' ) );
+ add_action( 'admin_init', array( $this, 'regenerate_keypair' ) );
+ add_action( 'admin_init', array( $this, 'gitium_warning' ) );
+ add_action( 'admin_init', array( $this, 'init_repo' ) );
+ add_action( 'admin_init', array( $this, 'choose_branch' ) );
+ add_action( 'admin_init', array( $this, 'disconnect_repository' ) );
+ }
+ }
+
+ public function admin_menu() {
+ add_menu_page(
+ __( 'Git Configuration', 'gitium' ),
+ 'Gitium',
+ GITIUM_MANAGE_OPTIONS_CAPABILITY,
+ $this->menu_slug,
+ array( $this, 'page' ),
+ plugins_url( 'img/gitium.png', dirname( __FILE__ ) )
+ );
+
+ $submenu_hook = add_submenu_page(
+ $this->menu_slug,
+ __( 'Git Configuration', 'gitium' ),
+ __( 'Configuration', 'gitium' ),
+ GITIUM_MANAGE_OPTIONS_CAPABILITY,
+ $this->menu_slug,
+ array( $this, 'page' )
+ );
+ new Gitium_Help( $submenu_hook, 'configuration' );
+ }
+
+ public function regenerate_keypair() {
+ $submit_keypair = filter_input(INPUT_POST, 'GitiumSubmitRegenerateKeypair', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
+ if ( ! isset( $submit_keypair ) ) {
+ return;
+ }
+ check_admin_referer( 'gitium-admin' );
+ gitium_get_keypair( true );
+ $this->success_redirect( __( 'Keypair successfully regenerated.', 'gitium' ) );
+ }
+
+ public function gitium_warning() {
+ $submit_warning = filter_input(INPUT_POST, 'GitiumSubmitWarning', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
+ if ( ! isset( $submit_warning ) ) {
+ return;
+ }
+ check_admin_referer( 'gitium-admin' );
+ $this->git->remove_wp_content_from_version_control();
+ }
+
+ public function init_process( $remote_url ) {
+ $git = $this->git;
+ $git->init();
+ $git->add_remote_url( $remote_url );
+ $git->fetch_ref();
+ if ( count( $git->get_remote_branches() ) == 0 ) {
+ $git->add( 'wp-content', '.gitignore' );
+ $current_user = wp_get_current_user();
+ $git->commit( __( 'Initial commit', 'gitium' ), $current_user->display_name, $current_user->user_email );
+ if ( ! $git->push( 'master' ) ) {
+ $git->cleanup();
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public function init_repo() {
+ $remote_url = filter_input(INPUT_POST, 'remote_url', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
+ $gitium_submit_fetch = filter_input(INPUT_POST, 'GitiumSubmitFetch', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
+ if ( ! isset( $gitium_submit_fetch ) || ! isset( $remote_url ) ) {
+ return;
+ }
+ check_admin_referer( 'gitium-admin' );
+
+ if ( empty( $remote_url ) ) {
+ $this->redirect( __( 'Please specify a valid repo.', 'gitium' ) );
+ }
+ if ( $this->init_process( $remote_url ) ) {
+ $this->success_redirect( __( 'Repository initialized successfully.', 'gitium' ) );
+ } else {
+ global $git;
+ $this->redirect( __( 'Could not push to remote: ', 'gitium' ) . $remote_url . ' ERROR: ' . serialize( $git->get_last_error() ) );
+ }
+ }
+
+ public function choose_branch() {
+ $gitium_submit_merge_push = filter_input(INPUT_POST, 'GitiumSubmitMergeAndPush', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
+ $tracking_branch = filter_input(INPUT_POST, 'tracking_branch', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
+ if ( ! isset( $gitium_submit_merge_push ) || ! isset( $tracking_branch ) ) {
+ return;
+ }
+ check_admin_referer( 'gitium-admin' );
+ $this->git->add();
+
+ $branch = $tracking_branch;
+ set_transient( 'gitium_remote_tracking_branch', $branch );
+ $current_user = wp_get_current_user();
+
+ $commit = $this->git->commit( __( 'Merged existing code from ', 'gitium' ) . get_home_url(), $current_user->display_name, $current_user->user_email );
+ if ( ! $commit ) {
+ $this->git->cleanup();
+ $this->redirect( __( 'Could not create initial commit -> ', 'gitium' ) . $this->git->get_last_error() );
+ }
+ if ( ! $this->git->merge_initial_commit( $commit, $branch ) ) {
+ $this->git->cleanup();
+ $this->redirect( __( 'Could not merge the initial commit -> ', 'gitium' ) . $this->git->get_last_error() );
+ }
+ $this->git->push( $branch );
+ $this->success_redirect( __( 'Branch selected successfully.', 'gitium' ) );
+ }
+
+ private function setup_step_1_remote_url() {
+ ?>
+
+
+
+
+
+ https://user:pass@github.com/user/example.git', 'gitium' ); ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ github or bitbucket.', 'gitium' ); ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ git; ?>
+
+
+
+
+
+
+ show_disconnect_repository_button();
+ ?>
+
+ show_message();
+
+ if ( wp_content_is_versioned() ) {
+ return $this->setup_warning();
+ }
+
+ if ( ! $this->git->is_status_working() || ! $this->git->get_remote_url() ) {
+ return $this->setup_step_1();
+ }
+
+ if ( ! $this->git->get_remote_tracking_branch() ) {
+ return $this->setup_step_2();
+ }
+
+ _gitium_status( true );
+ gitium_update_is_status_working();
+ gitium_update_remote_tracking_branch();
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-submenu-settings.php b/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-submenu-settings.php
new file mode 100644
index 00000000..7b292471
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gitium/inc/class-gitium-submenu-settings.php
@@ -0,0 +1,150 @@
+
+ *
+ * Gitium 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 3 of the License, or
+ * any later version.
+ *
+ * Gitium 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 Gitium. If not, see .
+ *
+ * @package Gitium
+ */
+
+class Gitium_Submenu_Settings extends Gitium_Menu {
+
+ public function __construct() {
+ parent::__construct( $this->gitium_menu_slug, $this->settings_menu_slug );
+ add_action( GITIUM_ADMIN_MENU_ACTION, array( $this, 'admin_menu' ) );
+ add_action( 'admin_init', array( $this, 'save' ) );
+ add_action( 'admin_init', array( $this, 'regenerate_webhook' ) );
+ add_action( 'admin_init', array( $this, 'regenerate_public_key' ) );
+ }
+
+ public function admin_menu() {
+ $submenu_hook = add_submenu_page(
+ $this->menu_slug,
+ 'Settings',
+ __( 'Settings' ),
+ GITIUM_MANAGE_OPTIONS_CAPABILITY,
+ $this->submenu_slug,
+ array( $this, 'page' )
+ );
+ new Gitium_Help( $submenu_hook, 'settings' );
+ }
+
+ public function regenerate_webhook() {
+ $gitium_regen_webhook = filter_input(INPUT_POST, 'GitiumSubmitRegenerateWebhook', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
+ if ( ! isset( $gitium_regen_webhook ) ) {
+ return;
+ }
+ check_admin_referer( 'gitium-settings' );
+ gitium_get_webhook_key( true );
+ $this->success_redirect( __( 'Webhook URL regenerates. Please make sure you update any external references.', 'gitium' ), $this->settings_menu_slug );
+ }
+
+ public function regenerate_public_key() {
+ $submit_regenerate_pub_key = filter_input(INPUT_POST, 'GitiumSubmitRegeneratePublicKey', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
+ if ( ! isset( $submit_regenerate_pub_key ) ) {
+ return;
+ }
+ check_admin_referer( 'gitium-settings' );
+ gitium_get_keypair( true );
+ $this->success_redirect( __( 'Public key successfully regenerated.', 'gitium' ), $this->settings_menu_slug );
+ }
+
+ private function show_webhook_table_webhook_url() {
+ ?>
+
+
+
+
+
+
+ Merge changes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ github or bitbucket.', 'gitium' ); ?>
+
+
+
+
+
+ show_webhook_table_webhook_url() ?>
+ show_webhook_table_public_key(); ?>
+
+ git->set_gitignore( $gitignore_content ) ) {
+ gitium_commit_and_push_gitignore_file();
+ $this->success_redirect( __( 'The file `.gitignore` is saved!', 'gitium' ), $this->settings_menu_slug );
+ } else {
+ $this->redirect( __( 'The file `.gitignore` could not be saved!', 'gitium' ), false, $this->settings_menu_slug );
+ }
+ }
+
+ public function page() {
+ $this->show_message();
+ ?>
+
+
+
+
+
+
+ *
+ * Gitium 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 3 of the License, or
+ * any later version.
+ *
+ * Gitium 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 Gitium. If not, see .
+ *
+ * @package Gitium
+ */
+
+class Gitium_Submenu_Status extends Gitium_Menu {
+
+ public function __construct() {
+ parent::__construct( $this->gitium_menu_slug, $this->gitium_menu_slug );
+
+ if ( current_user_can( GITIUM_MANAGE_OPTIONS_CAPABILITY ) ) {
+ add_action( GITIUM_ADMIN_MENU_ACTION, array( $this, 'admin_menu' ) );
+ add_action( 'admin_init', array( $this, 'save_changes' ) );
+ add_action( 'admin_init', array( $this, 'save_ignorelist' ) );
+ add_action( 'admin_init', array( $this, 'disconnect_repository' ) );
+ }
+ }
+
+ public function admin_menu() {
+ add_menu_page(
+ __( 'Git Status', 'gitium' ),
+ 'Gitium',
+ GITIUM_MANAGE_OPTIONS_CAPABILITY,
+ $this->menu_slug,
+ array( $this, 'page' ),
+ plugins_url( 'img/gitium.png', dirname( __FILE__ ) )
+ );
+
+ $submenu_hook = add_submenu_page(
+ $this->menu_slug,
+ __( 'Git Status', 'gitium' ),
+ __( 'Status', 'gitium' ),
+ GITIUM_MANAGE_OPTIONS_CAPABILITY,
+ $this->menu_slug,
+ array( $this, 'page' )
+ );
+ new Gitium_Help( $submenu_hook, 'status' );
+ }
+
+ private function get_change_meanings() {
+ return array(
+ '??' => __( 'untracked', 'gitium' ),
+ 'rM' => __( 'modified on remote', 'gitium' ),
+ 'rA' => __( 'added to remote', 'gitium' ),
+ 'rD' => __( 'deleted from remote', 'gitium' ),
+ 'D' => __( 'deleted from work tree', 'gitium' ),
+ 'M' => __( 'updated in work tree', 'gitium' ),
+ 'A' => __( 'added to work tree', 'gitium' ),
+ 'AM' => __( 'added to work tree', 'gitium' ),
+ 'R' => __( 'deleted from work tree', 'gitium' ),
+ );
+ }
+
+ public function humanized_change( $change ) {
+ $meaning = $this->get_change_meanings();
+
+ if ( isset( $meaning[ $change ] ) ) {
+ return $meaning[ $change ];
+ }
+ if ( 0 === strpos( $change, 'R ' ) ) {
+ $old_filename = substr( $change, 2 );
+ $change = sprintf( __( 'renamed from `%s`', 'gitium' ), $old_filename );
+ }
+ return $change;
+ }
+
+ public function save_ignorelist() {
+ $gitium_ignore_path = filter_input(INPUT_POST, 'GitiumIgnorePath', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
+ if ( ! isset( $gitium_ignore_path ) ) {
+ return;
+ } else {
+ $path = $gitium_ignore_path;
+ }
+ check_admin_referer( 'gitium-admin' );
+
+ if ( $this->git->set_gitignore( join( "\n", array_unique( array_merge( explode( "\n", $this->git->get_gitignore() ), array( $path ) ) ) ) ) ) {
+ gitium_commit_and_push_gitignore_file( $path );
+ $this->success_redirect( __( 'The file `.gitignore` is saved!', 'gitium' ), $this->gitium_menu_slug );
+ } else {
+ $this->redirect( __( 'The file `.gitignore` could not be saved!', 'gitium' ), false, $this->gitium_menu_slug );
+ }
+ }
+
+ public function save_changes() {
+ $gitium_save_changes = filter_input(INPUT_POST, 'GitiumSubmitSaveChanges', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
+ $gitium_commit_msg = filter_input(INPUT_POST, 'commitmsg', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
+
+ if ( ! isset( $gitium_save_changes ) ) {
+ return;
+ }
+
+ check_admin_referer( 'gitium-admin' );
+
+ gitium_enable_maintenance_mode() or wp_die( __( 'Could not enable the maintenance mode!', 'gitium' ) );
+
+ $commitmsg = sprintf( __( 'Merged changes from %s on %s', 'gitium' ), get_site_url(), date( 'm.d.Y' ) );
+
+ if ( isset( $gitium_commit_msg ) && ! empty( $gitium_commit_msg ) ) {
+ $commitmsg = $gitium_commit_msg;
+ }
+
+ $commits = array();
+
+ $current_user = wp_get_current_user();
+
+ // Get local status and behind commits
+ $local_status = $this->git->local_status();
+ $behind_commits = count( $this->git->get_behind_commits() );
+
+ if ( $this->git->is_dirty() && $this->git->add() > 0 ) {
+ $commit = $this->git->commit( $commitmsg, $current_user->display_name, $current_user->user_email );
+ if ( ! $commit ) {
+ gitium_disable_maintenance_mode();
+ $this->redirect( __( 'Could not commit!', 'gitium' ) );
+ }
+ $commits[] = $commit;
+ }
+
+ $merge_success = gitium_merge_and_push( $commits );
+
+ gitium_disable_maintenance_mode();
+
+ if ( ! $merge_success ) {
+ $this->redirect( __( 'Merge failed: ', 'gitium' ) . $this->git->get_last_error() );
+ }
+
+ // Determine message based on previous conditions
+ if ( $behind_commits > 0 && empty( $local_status[1] ) ) {
+ $this->success_redirect( sprintf( __( 'Pull done!', 'gitium' ) ) );
+ } else{
+ $this->success_redirect( sprintf( __( 'Pushed commit: `%s`', 'gitium' ), $commitmsg ) );
+ }
+ }
+
+ private function show_ahead_and_behind_info( $changes = '' ) {
+ $branch = $this->git->get_remote_tracking_branch();
+ $ahead = count( $this->git->get_ahead_commits() );
+ $behind = count( $this->git->get_behind_commits() );
+ ?>
+
+ %s
.', 'gitium' ), $branch );
+ ?>
+
+
+
+ $type ) :
+ $counter++;
+ echo ( 0 != $counter % 2 ) ? ''; + _e( 'Nothing to commit, working directory clean.', 'gitium' ); + echo ' | ';
+ else :
+ $this->show_git_changes_table_rows( $changes );
+ endif;
+ ?>
+
+
+ + +
++ /> +
+ + git->get_remote_url() ); ?>https://user:pass@github.com/user/example.git"
+msgstr ""
+"Si necesita autenticar sobre \"https:// en lugar del uso de SSH: "
+"https://user:pass@github.com/user/example.git "
+
+#: ../inc/class-gitium-submenu-configure.php:143
+msgid "Key pair"
+msgstr "Par de claves"
+
+#: ../inc/class-gitium-submenu-configure.php:147
+#: ../inc/class-gitium-submenu-settings.php:80
+msgid "Regenerate Key"
+msgstr "Regenerar clave"
+
+#: ../inc/class-gitium-submenu-configure.php:149
+#: ../inc/class-gitium-submenu-settings.php:81
+msgid ""
+"If your code use ssh keybased authentication for git you need to allow write "
+"access to your repository using this key."
+msgstr ""
+"Si su código usa autenticación ssh keybased para git, usted necesita "
+"permitir el acceso de escritura a su repositorio utilizando esta clave."
+
+#: ../inc/class-gitium-submenu-configure.php:150
+#: ../inc/class-gitium-submenu-settings.php:82
+msgid ""
+"Checkout instructions for github or bitbucket."
+msgstr ""
+"Instrucciones de Pedido para github or %s."
+msgstr "Siguiendo sucursal remota %s."
+
+#: ../inc/class-gitium-submenu-status.php:127
+msgid "Everything is up to date"
+msgstr "Todo está actualizado"
+
+#: ../inc/class-gitium-submenu-status.php:130
+#, php-format
+msgid "You are %s commits ahead and %s behind remote."
+msgstr "Usted está %s Commits por delante y %s por detrás del remoto."
+
+#: ../inc/class-gitium-submenu-status.php:132
+#, php-format
+msgid "You are %s commits ahead remote."
+msgstr "Usted está %s Commits delante del remoto."
+
+#: ../inc/class-gitium-submenu-status.php:134
+#, php-format
+msgid "You are %s commits behind remote."
+msgstr "Usted está %s Commits detrás del remoto."
+
+#: ../inc/class-gitium-submenu-status.php:160
+msgid "Add this file to the `.gitignore` list."
+msgstr "Añadir este archivo a la lista `.gitignore`."
+
+#: ../inc/class-gitium-submenu-status.php:163
+msgid "Submodules are not supported in this version."
+msgstr "Sub-módulos no son compatibles con esta versión."
+
+#: ../inc/class-gitium-submenu-status.php:175
+#: ../inc/class-gitium-submenu-status.php:176
+msgid "Path"
+msgstr "Ruta"
+
+#: ../inc/class-gitium-submenu-status.php:175
+#: ../inc/class-gitium-submenu-status.php:176
+msgid "Change"
+msgstr "Cambiar"
+
+#: ../inc/class-gitium-submenu-status.php:181
+msgid "Nothing to commit, working directory clean."
+msgstr "Nada que comprometer, directorio de trabajo limpio."
+
+#: ../inc/class-gitium-submenu-status.php:195
+msgid "Commit message"
+msgstr "Comprometer mensaje"
+
+#: ../inc/class-gitium-submenu-status.php:199
+msgid "Save changes"
+msgstr "Guardar cambios"
+
+#: ../inc/class-gitium-submenu-status.php:209
+msgid "connected to"
+msgstr "conectados a"
+
+#: ../inc/class-gitium-submenu-settings.php:32 ../inc/class-gitium-help.php:81
+msgid "Settings"
+msgstr "Ajustes"
+
+#: ../inc/class-gitium-submenu-settings.php:46
+msgid ""
+"Webhook URL regenerates. Please make sure you update any external references."
+msgstr ""
+"Webhook URL se regenera. Por favor, asegúrese de actualizar todas las "
+"referencias externas."
+
+#: ../inc/class-gitium-submenu-settings.php:55
+msgid "Public key successfully regenerated."
+msgstr "Clave pública regenera con éxito."
+
+#: ../inc/class-gitium-submenu-settings.php:61
+msgid "Webhook URL"
+msgstr "URL Webhook"
+
+#: ../inc/class-gitium-submenu-settings.php:65
+msgid "Regenerate Webhook"
+msgstr "Regenerar Webhook"
+
+#: ../inc/class-gitium-submenu-settings.php:67
+msgid "Pinging this URL triggers an update from remote repository."
+msgstr ""
+"Hacer ping en esta URL desencadena una actualización del repositorio remoto."
+
+#: ../inc/class-gitium-submenu-settings.php:77
+msgid "Public Key"
+msgstr "Clave Pública"
+
+#: ../inc/class-gitium-submenu-settings.php:116
+msgid "Gitium Settings"
+msgstr "Ajustes Gitium"
+
+#: ../inc/class-gitium-submenu-settings.php:121
+msgid "Be careful when you modify this list!"
+msgstr "¡Tenga cuidado al modificar esta lista!"
+
+#: ../inc/class-gitium-submenu-settings.php:126
+msgid "Save"
+msgstr "Guardar"
+
+#: ../inc/class-gitium-help.php:26
+msgid "Gitium"
+msgstr "Gitium"
+
+#: ../inc/class-gitium-help.php:27
+msgid "F.A.Q."
+msgstr "PF"
+
+#: ../inc/class-gitium-help.php:32
+msgid ""
+"Gitium enables continuous deployment for WordPress integrating with tools "
+"such as Github, Bitbucket or Travis-CI. Plugin and theme updates, installs "
+"and removals are automatically versioned."
+msgstr ""
+"Gitium permite el despliegue continuo para integración de WordPress con "
+"herramientas como Github, Bitbucket o Travis-CI. El plugin y las "
+"actualizaciones de temas, instalaciones y eliminaciones están versionadas "
+"automáticamente."
+
+#: ../inc/class-gitium-help.php:33
+msgid ""
+"Ninja code edits from the WordPress editor are also tracked into version "
+"control. Gitium is designed for sane development environments."
+msgstr ""
+"Las ediciones Código Ninja desde el editor de WordPress también son "
+"rastreadas en el control de versiones. Gitium está diseñado para entornos de "
+"desarrollo sanos."
+
+#: ../inc/class-gitium-help.php:34
+msgid ""
+"Staging and production can follow different branches of the same repository. "
+"You can deploy code simply trough git push."
+msgstr ""
+"Puesta en escena y producción pueden seguir diferentes ramas del mismo "
+"repositorio. Puede implementar código simplemente a través git push."
+
+#: ../inc/class-gitium-help.php:35
+msgid ""
+"Gitium requires git command line tool minimum version 1.7 "
+"installed on the server and proc_open PHP function enabled."
+msgstr ""
+"Gitium requiere la herramienta de línea de comandos git , "
+"mínimo la versión 1.7 instalada en el servidor y proc_open la "
+"función PHP habilitada."
+
+#: ../inc/class-gitium-help.php:39
+msgid "Is this plugin considered stable?"
+msgstr "¿Es este plugin considerado estable?"
+
+#: ../inc/class-gitium-help.php:39
+msgid ""
+"Right now this plugin is considered alpha quality and should be used in "
+"production environments only by adventurous kinds."
+msgstr ""
+"Ahora mismo este plugin se considera de calidad alfa y debe utilizarse en "
+"entornos de producción sólo por tipos aventureros."
+
+#: ../inc/class-gitium-help.php:40
+msgid "What happens in case of conflicts?"
+msgstr "¿Qué sucede en caso de conflictos?"
+
+#: ../inc/class-gitium-help.php:40
+msgid ""
+"The behavior in case of conflicts is to overwrite the changes on the origin "
+"repository with the local changes (ie. local modifications take precedence "
+"over remote ones)."
+msgstr ""
+"El comportamiento en caso de conflictos es sobrescribir los cambios en el "
+"repositorio de origen con los cambios locales (p.ej. las modificaciones "
+"locales toman precedencia sobre las remotas)."
+
+#: ../inc/class-gitium-help.php:41
+msgid "How to deploy automatically after a push?"
+msgstr "¿Cómo implementar automáticamente después de un empujón?"
+
+#: ../inc/class-gitium-help.php:41
+msgid ""
+"You can ping the webhook url after a push to automatically deploy the new "
+"code. The webhook url can be found under Code menu. This url plays well with "
+"Github or Bitbucket webhooks."
+msgstr ""
+"Puede hacer ping en la url webhook después de un empujón para distribuir "
+"automáticamente el nuevo código. La url webhook se puede encontrar en el "
+"menú Código. Esta url juega bien con Github o BitBucket WebHooks."
+
+#: ../inc/class-gitium-help.php:42
+msgid "Does it works on multi site setups?"
+msgstr "¿Trabaja en múltiples configuraciones de sitio?"
+
+#: ../inc/class-gitium-help.php:42
+msgid "Gitium is not supporting multisite setups at the moment."
+msgstr ""
+"Gitium no soporta a las configuraciones de múltiples sitios en este momento."
+
+#: ../inc/class-gitium-help.php:43
+msgid "How does gitium handle submodules?"
+msgstr "¿Cómo manejar gitium los submódulos?"
+
+#: ../inc/class-gitium-help.php:43
+msgid "Currently submodules are not supported."
+msgstr "Actualmente los submódulos no son compatibles."
+
+#: ../inc/class-gitium-help.php:47
+msgid ""
+"In this step you must specify the Remote URL. This URL "
+"represents the link between the git sistem and your site."
+msgstr ""
+"En esta etapa, se debe especificar el URL remoto . Esta URL "
+"representa el enlace entre el sistema git y su sitio."
+
+#: ../inc/class-gitium-help.php:48
+msgid "You can get this URL from your Git repository and it looks like this:"
+msgstr ""
+"Usted puede obtener esta dirección URL de su repositorio Git y se ve así:"
+
+#: ../inc/class-gitium-help.php:49
+msgid "github.com -> git@github.com:user/example.git"
+msgstr "github.com -> git@github.com:user/example.git"
+
+#: ../inc/class-gitium-help.php:50
+msgid "bitbucket.org -> git@bitbucket.org:user/glowing-happiness.git"
+msgstr "bitbucket.org -> git@bitbucket.org:user/glowing-happiness.git"
+
+#: ../inc/class-gitium-help.php:51
+msgid ""
+"To go to the next step, fill the Remote URL and then press the "
+"Fetch button."
+msgstr ""
+"Para ir al siguiente paso, llene la URL remota y pulse el "
+"botón Buscar ."
+
+#: ../inc/class-gitium-help.php:52
+msgid ""
+"In this step you must select the branch you want to follow."
+msgstr ""
+"En este paso deberá seleccionar la rama que desea seguir."
+
+#: ../inc/class-gitium-help.php:53
+msgid "Only this branch will have all of your code modifications."
+msgstr "Sólo esta rama tendrá todas sus modificaciones de código."
+
+#: ../inc/class-gitium-help.php:54
+msgid ""
+"When you push the button Merge & Push, all code(plugins & "
+"themes) will be pushed on the git repository."
+msgstr ""
+"Cuando se presiona el botón Combinar y Empujar , todo el "
+"código (plugins y temas) serán empujados en el repositorio git."
+
+#: ../inc/class-gitium-help.php:64
+msgid ""
+"On status page you can see what files are modified, and you can commit the "
+"changes to git."
+msgstr ""
+"En la página de estado se puede ver qué archivos son modificados, y usted "
+"puede confirmar los cambios a Git."
+
+#: ../inc/class-gitium-help.php:69 ../inc/class-gitium-submenu-commits.php:29
+#: ../inc/class-gitium-submenu-commits.php:41
+msgid "Commits"
+msgstr "Commits"
+
+#: ../inc/class-gitium-help.php:74
+msgid ""
+"You may be wondering what is the difference between author and committer."
+msgstr ""
+"Usted puede preguntarse cuál es la diferencia entre el autor y el comitter."
+
+#: ../inc/class-gitium-help.php:75
+msgid ""
+"The author is the person who originally wrote the patch, "
+"whereas the committer is the person who last applied the patch."
+msgstr ""
+"El autor es la persona que originalmente escribió el parche, "
+"mientras que el committer es la persona que aplicó el parche "
+"al final."
+
+#: ../inc/class-gitium-help.php:76
+msgid ""
+"So, if you send in a patch to a project and one of the core members applies "
+"the patch, both of you get credit — you as the author and the core member as "
+"the committer."
+msgstr ""
+"Por lo tanto, si usted envía en un parche para un proyecto y uno de los "
+"principales miembros aplica el parche, ambos consiguen crédito - usted como "
+"el autor y el miembro de núcleo como el commiter."
+
+#: ../inc/class-gitium-help.php:86
+msgid "Each line from the gitignore file specifies a pattern."
+msgstr "Cada línea del archivo gitignore especifica un patrón."
+
+#: ../inc/class-gitium-help.php:87
+msgid ""
+"When deciding whether to ignore a path, Git normally checks gitignore "
+"patterns from multiple sources, with the following order of precedence, from "
+"highest to lowest (within one level of precedence, the last matching pattern "
+"decides the outcome)"
+msgstr ""
+"A la hora de decidir si se debe pasar por alto una ruta, Git normalmente "
+"comprueba patrones gitignore de múltiples fuentes, con el siguiente orden, "
+"de de mayor a menor (dentro de un nivel de prioridad, la última "
+"coincidencia de patrones decide el resultado)"
+
+#: ../inc/class-gitium-help.php:88
+#, php-format
+msgid "Read more on %s"
+msgstr "Leer más en %s"
+
+#: ../inc/class-gitium-submenu-commits.php:28
+msgid "Git Commits"
+msgstr "Commits Git"
+
+#: ../inc/class-gitium-submenu-commits.php:61
+#, php-format
+msgid "Last %s commits"
+msgstr "Últimos commits %s"
+
+#: ../inc/class-gitium-submenu-commits.php:70
+#, php-format
+msgid "committed %s ago"
+msgstr "cometido hace %s"
+
+#: ../inc/class-gitium-submenu-commits.php:82
+#, php-format
+msgid "authored %s ago"
+msgstr "Creado hace %s"
diff --git a/wp-content/upgrade-temp-backup/plugins/gitium/languages/gitium-sr_RS.mo b/wp-content/upgrade-temp-backup/plugins/gitium/languages/gitium-sr_RS.mo
new file mode 100644
index 00000000..677d3bf3
Binary files /dev/null and b/wp-content/upgrade-temp-backup/plugins/gitium/languages/gitium-sr_RS.mo differ
diff --git a/wp-content/upgrade-temp-backup/plugins/gitium/languages/gitium-sr_RS.po b/wp-content/upgrade-temp-backup/plugins/gitium/languages/gitium-sr_RS.po
new file mode 100644
index 00000000..09cb064a
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gitium/languages/gitium-sr_RS.po
@@ -0,0 +1,538 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: Gitium\n"
+"POT-Creation-Date: 2014-10-20 19:06+0200\n"
+"PO-Revision-Date: 2014-10-24 12:51+0200\n"
+"Last-Translator: Presslabs https://user:pass@github.com/user/example.git"
+msgstr ""
+"Ako treba da proverite preko \"https://\" umesto SSH, koristite: "
+"https://user:pass@github.com/user/example.git"
+
+#: ../inc/class-gitium-submenu-configure.php:143
+msgid "Key pair"
+msgstr "Par ključeva"
+
+#: ../inc/class-gitium-submenu-configure.php:147
+#: ../inc/class-gitium-submenu-settings.php:80
+msgid "Regenerate Key"
+msgstr "Ključ za regenerisanje"
+
+#: ../inc/class-gitium-submenu-configure.php:149
+#: ../inc/class-gitium-submenu-settings.php:81
+msgid ""
+"If your code use ssh keybased authentication for git you need to allow write "
+"access to your repository using this key."
+msgstr ""
+"Ako vaš kod koristi git autentifikaciju na osnovu ssh ključa, morate pismeno "
+"dozvoliti pristup svom spremištu uz pomoć ovog ključa. "
+
+#: ../inc/class-gitium-submenu-configure.php:150
+#: ../inc/class-gitium-submenu-settings.php:82
+msgid ""
+"Checkout instructions for github or bitbucket."
+msgstr ""
+"Pogledajte uputstva na github "
+"ili bitbucket."
+
+#: ../inc/class-gitium-submenu-configure.php:160
+msgid "Warning!"
+msgstr "Upozorenje!"
+
+#: ../inc/class-gitium-submenu-configure.php:174
+#: ../inc/class-gitium-help.php:47
+msgid "Configuration step 1"
+msgstr "Konfiguracija, korak 1"
+
+#: ../inc/class-gitium-submenu-configure.php:175
+#: ../inc/class-gitium-submenu-configure.php:194
+msgid ""
+"If you need help to set this up, please click on the \"Help\" button from "
+"the top right corner of this screen."
+msgstr ""
+"Ako vam treba pomoć za ovo podešavanje, kliknite na taster \"Pomoć\" u "
+"gornjem desnom uglu ekrana."
+
+#: ../inc/class-gitium-submenu-configure.php:183
+msgid "Fetch"
+msgstr "Uzmi"
+
+#: ../inc/class-gitium-submenu-configure.php:193
+#: ../inc/class-gitium-help.php:52
+msgid "Configuration step 2"
+msgstr "Konfiguracija, korak 2"
+
+#: ../inc/class-gitium-submenu-configure.php:202
+msgid "Choose tracking branch"
+msgstr "Odaberite ogranak za praćenje"
+
+#: ../inc/class-gitium-submenu-configure.php:215
+msgid "Merge & Push"
+msgstr "Spoji & Potisni"
+
+#: ../inc/class-gitium-submenu-status.php:32
+#: ../inc/class-gitium-submenu-status.php:42
+msgid "Git Status"
+msgstr "Git Status"
+
+#: ../inc/class-gitium-submenu-status.php:43
+#: ../inc/class-gitium-submenu-status.php:209 ../inc/class-gitium-help.php:59
+msgid "Status"
+msgstr "Status"
+
+#: ../inc/class-gitium-submenu-status.php:53
+msgid "untracked"
+msgstr "nepraćen"
+
+#: ../inc/class-gitium-submenu-status.php:54
+msgid "modified on remote"
+msgstr "modifikovan na udaljenom skladištu"
+
+#: ../inc/class-gitium-submenu-status.php:55
+msgid "added to remote"
+msgstr "dodat udaljenom skladištu"
+
+#: ../inc/class-gitium-submenu-status.php:56
+msgid "deleted from remote"
+msgstr "obrisan sa udaljenog skladišta"
+
+#: ../inc/class-gitium-submenu-status.php:57
+#: ../inc/class-gitium-submenu-status.php:61
+msgid "deleted from work tree"
+msgstr "obrisan sa radnog drveta"
+
+#: ../inc/class-gitium-submenu-status.php:58
+msgid "updated in work tree"
+msgstr "ažuriran u radnom drvetu"
+
+#: ../inc/class-gitium-submenu-status.php:59
+#: ../inc/class-gitium-submenu-status.php:60
+msgid "added to work tree"
+msgstr "dodat radnom drvetu"
+
+#: ../inc/class-gitium-submenu-status.php:73
+#, php-format
+msgid "renamed from `%s`"
+msgstr "ime `%s` promenjeno"
+
+#: ../inc/class-gitium-submenu-status.php:88
+#: ../inc/class-gitium-submenu-settings.php:106
+msgid "The file `.gitignore` is saved!"
+msgstr "Datoteka `.gitignore` je sačuvana!"
+
+#: ../inc/class-gitium-submenu-status.php:90
+#: ../inc/class-gitium-submenu-settings.php:108
+msgid "The file `.gitignore` could not be saved!"
+msgstr "Datoteka `.gitignore` ne može biti sačuvana!"
+
+#: ../inc/class-gitium-submenu-status.php:100
+msgid "Could not enable the maintenance mode!"
+msgstr "Režim održavanja nije mogao biti aktiviran!"
+
+#: ../inc/class-gitium-submenu-status.php:102
+#: ../inc/class-gitium-submenu-status.php:196
+#, php-format
+msgid "Merged changes from %s on %s"
+msgstr "Promene sa %s na %s spojene!"
+
+#: ../inc/class-gitium-submenu-status.php:109
+msgid "Could not commit!"
+msgstr "Neuspelo izvršenje!"
+
+#: ../inc/class-gitium-submenu-status.php:114
+msgid "Merge failed: "
+msgstr "Neuspelo spajanje:"
+
+#: ../inc/class-gitium-submenu-status.php:116
+#, php-format
+msgid "Pushed commit: `%s`"
+msgstr "Preneto izvršenje: `%s`"
+
+#: ../inc/class-gitium-submenu-status.php:125
+#, php-format
+msgid "Following remote branch %s."
+msgstr "Praćenje udaljenog ogrankagit command line tool minimum version 1.7 "
+"installed on the server and proc_open PHP function enabled."
+msgstr ""
+"Gitium zahteva da na serveru bude instaliran git alat komandne "
+"linije, najmanje verzije 1.7 i proc_open aktiviranu PHP "
+"funkciju."
+
+#: ../inc/class-gitium-help.php:39
+msgid "Is this plugin considered stable?"
+msgstr "Da li se ovaj plugin smatra stabilnim?"
+
+#: ../inc/class-gitium-help.php:39
+msgid ""
+"Right now this plugin is considered alpha quality and should be used in "
+"production environments only by adventurous kinds."
+msgstr ""
+"Trenutno se smatra da ovaj plugin ima alfa kvalitet i treba ga koristiti u "
+"okruženjima produkcije isključivo avanturističkog karaktera."
+
+#: ../inc/class-gitium-help.php:40
+msgid "What happens in case of conflicts?"
+msgstr "Šta se dešava u slučaju konflikta?"
+
+#: ../inc/class-gitium-help.php:40
+msgid ""
+"The behavior in case of conflicts is to overwrite the changes on the origin "
+"repository with the local changes (ie. local modifications take precedence "
+"over remote ones)."
+msgstr ""
+"U slučaju konflikta treba poništiti izmene u prvobitnom spremištu, zajedno "
+"sa lokalnim izmenama (tj. Lokalne izmene imaju prednost u odnosu na "
+"udaljene)."
+
+#: ../inc/class-gitium-help.php:41
+msgid "How to deploy automatically after a push?"
+msgstr "Kako izvršiti automatsko razmeštanje posle pritiska?"
+
+#: ../inc/class-gitium-help.php:41
+msgid ""
+"You can ping the webhook url after a push to automatically deploy the new "
+"code. The webhook url can be found under Code menu. This url plays well with "
+"Github or Bitbucket webhooks."
+msgstr ""
+"Možete pingovati url za webhook nakon pritiska za automatsko razmeštanje "
+"novog koda. URL za webhook možete naći u meniju koda. Ovaj url dobro radi uz "
+"Github ili Bitbucket webhooks."
+
+#: ../inc/class-gitium-help.php:42
+msgid "Does it works on multi site setups?"
+msgstr "Da li radi na podešavanjima višestrukih site-ova?"
+
+#: ../inc/class-gitium-help.php:42
+msgid "Gitium is not supporting multisite setups at the moment."
+msgstr "Gitium trenutno ne podržava podešavanje višestrukih site-ova."
+
+#: ../inc/class-gitium-help.php:43
+msgid "How does gitium handle submodules?"
+msgstr "Kako gitium upravlja submodulima?"
+
+#: ../inc/class-gitium-help.php:43
+msgid "Currently submodules are not supported."
+msgstr "Trenutno, submoduli nisu podržani."
+
+#: ../inc/class-gitium-help.php:47
+msgid ""
+"In this step you must specify the Remote URL. This URL "
+"represents the link between the git sistem and your site."
+msgstr ""
+"U ovom koraku morate odrediti Udaljeni URL. Ovaj URL "
+"predstavlja vezu između git sistema i vašeg site-a."
+
+#: ../inc/class-gitium-help.php:48
+msgid "You can get this URL from your Git repository and it looks like this:"
+msgstr "Ovaj URL možete dobiti iz svog Git spremišta i on izgleda ovako:"
+
+#: ../inc/class-gitium-help.php:49
+msgid "github.com -> git@github.com:user/example.git"
+msgstr "github.com -> git@github.com:user/example.git"
+
+#: ../inc/class-gitium-help.php:50
+msgid "bitbucket.org -> git@bitbucket.org:user/glowing-happiness.git"
+msgstr "bitbucket.org -> git@bitbucket.org:user/glowing-happines.git"
+
+#: ../inc/class-gitium-help.php:51
+msgid ""
+"To go to the next step, fill the Remote URL and then press the "
+"Fetch button."
+msgstr ""
+"Da biste prešli na sledeći korak, popunite Udaljeni URL i "
+"pritisnite Dobavi taster."
+
+#: ../inc/class-gitium-help.php:52
+msgid ""
+"In this step you must select the branch you want to follow."
+msgstr ""
+"U ovom koraku morate odabrati ogranak koji želite da pratite. "
+
+#: ../inc/class-gitium-help.php:53
+msgid "Only this branch will have all of your code modifications."
+msgstr "Samo će ovaj ogranak imati sve vaše modifikacije koda."
+
+#: ../inc/class-gitium-help.php:54
+msgid ""
+"When you push the button Merge & Push, all code(plugins & "
+"themes) will be pushed on the git repository."
+msgstr ""
+"Kad kliknete na taster Spoji & Potisni svi (plugin-ovi i teme) "
+"koda biće potisnuti u git spremište."
+
+#: ../inc/class-gitium-help.php:64
+msgid ""
+"On status page you can see what files are modified, and you can commit the "
+"changes to git."
+msgstr ""
+"Na stranici statusa možete videti koje su datoteke izmenjene i možete uneti "
+"izmene u git."
+
+#: ../inc/class-gitium-help.php:69 ../inc/class-gitium-submenu-commits.php:29
+#: ../inc/class-gitium-submenu-commits.php:41
+msgid "Commits"
+msgstr "Izvršenja"
+
+#: ../inc/class-gitium-help.php:74
+msgid ""
+"You may be wondering what is the difference between author and committer."
+msgstr "Možda se pitate u čemu je razlika između autora i izvršioca?"
+
+#: ../inc/class-gitium-help.php:75
+msgid ""
+"The author is the person who originally wrote the patch, "
+"whereas the committer is the person who last applied the patch."
+msgstr ""
+"Autor je osoba koja je originalno napisala zakrpu, dok je "
+"izvršilac osoba koja je poslednja primenila zakrpu."
+
+#: ../inc/class-gitium-help.php:76
+msgid ""
+"So, if you send in a patch to a project and one of the core members applies "
+"the patch, both of you get credit — you as the author and the core member as "
+"the committer."
+msgstr ""
+"Dakle, ako pošaljete zakrpu projektu i jedan od ključnih članova je primeni "
+"- oboje dobijate zasluge - vi kao autor, a ključni član kao izvršilac."
+
+#: ../inc/class-gitium-help.php:86
+msgid "Each line from the gitignore file specifies a pattern."
+msgstr "Svaka linija iz gitignore datoteke označava šablon."
+
+#: ../inc/class-gitium-help.php:87
+msgid ""
+"When deciding whether to ignore a path, Git normally checks gitignore "
+"patterns from multiple sources, with the following order of precedence, from "
+"highest to lowest (within one level of precedence, the last matching pattern "
+"decides the outcome)"
+msgstr ""
+"Kad odlučujete o tome da li ćete ignorisati putanju, Git obično proverava "
+"gitignore šablone iz višestrukih izvora, sa sledećim redosledom - od "
+"najvišeg do najnižeg (u okviru jednog nivoa prednosti, poslednji šablon koji "
+"se poklapa odlučuje o ishodu)."
+
+#: ../inc/class-gitium-help.php:88
+#, php-format
+msgid "Read more on %s"
+msgstr "Pročitajte više o %s"
+
+#: ../inc/class-gitium-submenu-commits.php:28
+msgid "Git Commits"
+msgstr "Git izvršenja"
+
+#: ../inc/class-gitium-submenu-commits.php:61
+#, php-format
+msgid "Last %s commits"
+msgstr "Poslednja %s izvršenja"
+
+#: ../inc/class-gitium-submenu-commits.php:70
+#, php-format
+msgid "committed %s ago"
+msgstr "izvršena pre %s"
+
+#: ../inc/class-gitium-submenu-commits.php:82
+#, php-format
+msgid "authored %s ago"
+msgstr "autorizovana pre %s"
diff --git a/wp-content/upgrade-temp-backup/plugins/gitium/languages/gitium.pot b/wp-content/upgrade-temp-backup/plugins/gitium/languages/gitium.pot
new file mode 100644
index 00000000..807f7dae
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gitium/languages/gitium.pot
@@ -0,0 +1,489 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: Gitium\n"
+"POT-Creation-Date: 2014-10-20 19:06+0200\n"
+"PO-Revision-Date: 2014-10-20 19:06+0200\n"
+"Last-Translator: Presslabs https://user:pass@github.com/user/example.git"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-configure.php:143
+msgid "Key pair"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-configure.php:147
+#: ../inc/class-gitium-submenu-settings.php:80
+msgid "Regenerate Key"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-configure.php:149
+#: ../inc/class-gitium-submenu-settings.php:81
+msgid ""
+"If your code use ssh keybased authentication for git you need to allow write "
+"access to your repository using this key."
+msgstr ""
+
+#: ../inc/class-gitium-submenu-configure.php:150
+#: ../inc/class-gitium-submenu-settings.php:82
+msgid ""
+"Checkout instructions for github or bitbucket."
+msgstr ""
+
+#: ../inc/class-gitium-submenu-configure.php:160
+msgid "Warning!"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-configure.php:174
+#: ../inc/class-gitium-help.php:47
+msgid "Configuration step 1"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-configure.php:175
+#: ../inc/class-gitium-submenu-configure.php:194
+msgid ""
+"If you need help to set this up, please click on the \"Help\" button from "
+"the top right corner of this screen."
+msgstr ""
+
+#: ../inc/class-gitium-submenu-configure.php:183
+msgid "Fetch"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-configure.php:193
+#: ../inc/class-gitium-help.php:52
+msgid "Configuration step 2"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-configure.php:202
+msgid "Choose tracking branch"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-configure.php:215
+msgid "Merge & Push"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:32
+#: ../inc/class-gitium-submenu-status.php:42
+msgid "Git Status"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:43
+#: ../inc/class-gitium-submenu-status.php:209 ../inc/class-gitium-help.php:59
+msgid "Status"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:53
+msgid "untracked"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:54
+msgid "modified on remote"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:55
+msgid "added to remote"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:56
+msgid "deleted from remote"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:57
+#: ../inc/class-gitium-submenu-status.php:61
+msgid "deleted from work tree"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:58
+msgid "updated in work tree"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:59
+#: ../inc/class-gitium-submenu-status.php:60
+msgid "added to work tree"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:73
+#, php-format
+msgid "renamed from `%s`"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:88
+#: ../inc/class-gitium-submenu-settings.php:106
+msgid "The file `.gitignore` is saved!"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:90
+#: ../inc/class-gitium-submenu-settings.php:108
+msgid "The file `.gitignore` could not be saved!"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:100
+msgid "Could not enable the maintenance mode!"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:102
+#: ../inc/class-gitium-submenu-status.php:196
+#, php-format
+msgid "Merged changes from %s on %s"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:109
+msgid "Could not commit!"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:114
+msgid "Merge failed: "
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:116
+#, php-format
+msgid "Pushed commit: `%s`"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:125
+#, php-format
+msgid "Following remote branch %s."
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:127
+msgid "Everything is up to date"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:130
+#, php-format
+msgid "You are %s commits ahead and %s behind remote."
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:132
+#, php-format
+msgid "You are %s commits ahead remote."
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:134
+#, php-format
+msgid "You are %s commits behind remote."
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:160
+msgid "Add this file to the `.gitignore` list."
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:163
+msgid "Submodules are not supported in this version."
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:175
+#: ../inc/class-gitium-submenu-status.php:176
+msgid "Path"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:175
+#: ../inc/class-gitium-submenu-status.php:176
+msgid "Change"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:181
+msgid "Nothing to commit, working directory clean."
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:195
+msgid "Commit message"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:199
+msgid "Save changes"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-status.php:209
+msgid "connected to"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-settings.php:32 ../inc/class-gitium-help.php:81
+msgid "Settings"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-settings.php:46
+msgid ""
+"Webhook URL regenerates. Please make sure you update any external references."
+msgstr ""
+
+#: ../inc/class-gitium-submenu-settings.php:55
+msgid "Public key successfully regenerated."
+msgstr ""
+
+#: ../inc/class-gitium-submenu-settings.php:61
+msgid "Webhook URL"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-settings.php:65
+msgid "Regenerate Webhook"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-settings.php:67
+msgid "Pinging this URL triggers an update from remote repository."
+msgstr ""
+
+#: ../inc/class-gitium-submenu-settings.php:77
+msgid "Public Key"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-settings.php:116
+msgid "Gitium Settings"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-settings.php:121
+msgid "Be careful when you modify this list!"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-settings.php:126
+msgid "Save"
+msgstr ""
+
+#: ../inc/class-gitium-help.php:26
+msgid "Gitium"
+msgstr ""
+
+#: ../inc/class-gitium-help.php:27
+msgid "F.A.Q."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:32
+msgid ""
+"Gitium enables continuous deployment for WordPress integrating with tools "
+"such as Github, Bitbucket or Travis-CI. Plugin and theme updates, installs "
+"and removals are automatically versioned."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:33
+msgid ""
+"Ninja code edits from the WordPress editor are also tracked into version "
+"control. Gitium is designed for sane development environments."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:34
+msgid ""
+"Staging and production can follow different branches of the same repository. "
+"You can deploy code simply trough git push."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:35
+msgid ""
+"Gitium requires git command line tool minimum version 1.7 "
+"installed on the server and proc_open PHP function enabled."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:39
+msgid "Is this plugin considered stable?"
+msgstr ""
+
+#: ../inc/class-gitium-help.php:39
+msgid ""
+"Right now this plugin is considered alpha quality and should be used in "
+"production environments only by adventurous kinds."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:40
+msgid "What happens in case of conflicts?"
+msgstr ""
+
+#: ../inc/class-gitium-help.php:40
+msgid ""
+"The behavior in case of conflicts is to overwrite the changes on the origin "
+"repository with the local changes (ie. local modifications take precedence "
+"over remote ones)."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:41
+msgid "How to deploy automatically after a push?"
+msgstr ""
+
+#: ../inc/class-gitium-help.php:41
+msgid ""
+"You can ping the webhook url after a push to automatically deploy the new "
+"code. The webhook url can be found under Code menu. This url plays well with "
+"Github or Bitbucket webhooks."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:42
+msgid "Does it works on multi site setups?"
+msgstr ""
+
+#: ../inc/class-gitium-help.php:42
+msgid "Gitium is not supporting multisite setups at the moment."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:43
+msgid "How does gitium handle submodules?"
+msgstr ""
+
+#: ../inc/class-gitium-help.php:43
+msgid "Currently submodules are not supported."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:47
+msgid ""
+"In this step you must specify the Remote URL. This URL "
+"represents the link between the git sistem and your site."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:48
+msgid "You can get this URL from your Git repository and it looks like this:"
+msgstr ""
+
+#: ../inc/class-gitium-help.php:49
+msgid "github.com -> git@github.com:user/example.git"
+msgstr ""
+
+#: ../inc/class-gitium-help.php:50
+msgid "bitbucket.org -> git@bitbucket.org:user/glowing-happiness.git"
+msgstr ""
+
+#: ../inc/class-gitium-help.php:51
+msgid ""
+"To go to the next step, fill the Remote URL and then press the "
+"Fetch button."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:52
+msgid ""
+"In this step you must select the branch you want to follow."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:53
+msgid "Only this branch will have all of your code modifications."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:54
+msgid ""
+"When you push the button Merge & Push, all code(plugins & "
+"themes) will be pushed on the git repository."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:64
+msgid ""
+"On status page you can see what files are modified, and you can commit the "
+"changes to git."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:69 ../inc/class-gitium-submenu-commits.php:29
+#: ../inc/class-gitium-submenu-commits.php:41
+msgid "Commits"
+msgstr ""
+
+#: ../inc/class-gitium-help.php:74
+msgid ""
+"You may be wondering what is the difference between author and committer."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:75
+msgid ""
+"The author is the person who originally wrote the patch, "
+"whereas the committer is the person who last applied the patch."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:76
+msgid ""
+"So, if you send in a patch to a project and one of the core members applies "
+"the patch, both of you get credit — you as the author and the core member as "
+"the committer."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:86
+msgid "Each line from the gitignore file specifies a pattern."
+msgstr ""
+
+#: ../inc/class-gitium-help.php:87
+msgid ""
+"When deciding whether to ignore a path, Git normally checks gitignore "
+"patterns from multiple sources, with the following order of precedence, from "
+"highest to lowest (within one level of precedence, the last matching pattern "
+"decides the outcome)"
+msgstr ""
+
+#: ../inc/class-gitium-help.php:88
+#, php-format
+msgid "Read more on %s"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-commits.php:28
+msgid "Git Commits"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-commits.php:61
+#, php-format
+msgid "Last %s commits"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-commits.php:70
+#, php-format
+msgid "committed %s ago"
+msgstr ""
+
+#: ../inc/class-gitium-submenu-commits.php:82
+#, php-format
+msgid "authored %s ago"
+msgstr ""
diff --git a/wp-content/upgrade-temp-backup/plugins/gitium/readme.txt b/wp-content/upgrade-temp-backup/plugins/gitium/readme.txt
new file mode 100644
index 00000000..27fa5c00
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gitium/readme.txt
@@ -0,0 +1,310 @@
+=== Gitium ===
+
+Contributors: PressLabs
+Donate link: https://www.presslabs.com/gitium/
+Tags: git, version control, revision, gitium, presslabs
+Requires at least: 4.7
+Tested up to: 6.8
+Requires PHP: 7.4
+License: GPLv3
+Stable tag: 1.2.1
+License URI: https://www.gnu.org/licenses/gpl-3.0.en.html
+
+Automatic git version control and deployment for your plugins and themes integrated into wp-admin.
+
+== About the makers ==
+This plugin was developed by the crafty people at Presslabs—the Smart Managed WordPress Hosting Platform. Here we bring high-performance hosting and business intelligence for WordPress sites. In our spare time, we contribute to the global open-source community with our code.
+
+We’ve built Gitium back in 2013 to provide our clients a more simple and error-free method to integrate a new git version control into their code management flow.
+
+== What is Gitium? ==
+
+This plugin enables continuous deployment for WordPress, integrating with tools such as Github, Bitbucket or Travis-CI. Theme or plugin updates, installs and removals are all automatically versioned. Ninja code edits from the WordPress editor are also tracked by the version control system.
+
+== Why is Gitium? ==
+
+Gitium is designed with responsible development environments in mind, allowing staging and production to follow different branches of the same repository. You can also deploy code by simply using git push.
+
+Gitium requires git command line tool with a minimum version of 1.7 installed on the server and the proc_open PHP function enabled.
+
+== Gitium features: ==
+-preserves the WordPress behavior
+-accountability for code changes
+-safe code storage—gets all code edits in Git
+
+== Development ==
+For more details about Gitium, head here: http://docs.presslabs.com/gitium/usage/
+
+== Receiving is nicer when giving ==
+We’ve built this to make our lives easier and we’re happy to do that for other developers, too. We’d really appreciate it if you could contribute with code, tests, documentation or just share your experience with Gitium.
+
+Development of Gitium happens at http://github.com/PressLabs/gitium
+Issues are tracked at http://github.com/PressLabs/gitium/issues
+This WordPress plugin can be found at https://wordpress.org/plugins/gitium/
+
+== Screenshots ==
+
+1. Setup step 1: Get SSH Key
+2. Setup step 2: Set SSH Key (Github)
+3. Setup step 3: Add remote repository
+4. Setup step 4: Choose following branch
+5. Commit local changes
+
+
+== Installation ==
+
+= Manual Installation =
+
+1. Go to your WordPress admin dashboard.
+2. Navigate to 'Plugins' → 'Add New'.
+3. Search for "Gitium".
+4. Install and activate the Gitium plugin.
+
+= Usage =
+
+- Connect Your Repository
+After activation, go to the Gitium settings in your WordPress admin area.
+Copy the Public Key that Gitium has generated for you from the Key Pair field.
+In your repository manager of choice (GitHub, GitLab, or Bitbucket), go to the settings page and find the “Deploy keys” (or similar) section. There you will need to add the Public Key you’ve copied from Gitium. This will grant Gitium access to your repository. Make sure to allow write access as well. Also make sure that you copy the entire key from gitium.
+Now go back to your main repository page and copy the SSH URL to your repo. Paste this URL in Gitium and press the “Fetch” button.
+A “Repository initialized successfully” message will show up. This means that your repository has been populated with the current code of your website and it is ready to start working with Gitium.
+
+- Initial Commit
+Once connected, Gitium will automatically commit your existing WordPress theme and plugins to the connected repository.
+This initial commit serves as the baseline for your site’s code.
+
+- Making Changes
+Make changes to your WordPress site’s code (themes, plugins) as needed.
+Gitium will automatically commit these changes to your Git repository.
+Using the webhook provided by Gitium, it will also automatically deploy the changes from the repository to your WordPress site.
+
+- Webook Configuration
+Gitium uses the webhook to automatically deploy remote changes to your server. To configure it follow these steps:
+ 1. Go to your WordPress website and go to your Gitium Settings page;
+ 2. Copy the full Webhook URL that Gitium provides;
+ 3. In your Git Manager settings, go to Webhook section, add a new webhook and paste the webhook URL you have copied from Gitium.
+ 4. Press Add, no settings changes needed. The webook simply needs a ping, nothing more. The security key is already embedded in the final URL Gitium has generated for you.
+
+Now when you push to your repo, this webhook will automatically pull the changes to your remote server and deploy them.
+
+You can see more details about the plugin also in our documentation here: https://www.presslabs.com/docs/code/gitium/install-gitium/
+
+== Frequently Asked Questions ==
+
+= Could not connect to remote repository? =
+
+If you encounter this kind of error you can try to fix it by setting the proper username of the .git directory.
+
+Example: chown -R www-data:www-data .git
+
+= Is this plugin considered stable? =
+
+Yes, we consider the plugin stable after extensive usage in production environments at Presslabs, with hundreds of users and powering sites with hundreds of millions of pageviews per month.
+
+= What will happen in case of conflicts? =
+
+The behavior in case of conflicts is to overwrite the changes on the `origin` repository with the local changes (ie. local modifications take precedence over remote ones).
+
+= How to deploy automatically after a push? =
+
+You can ping the webhook url after a push to automatically deploy the new code. The webhook url can be found under `Gitium` menu, `Settings` section. This url also plays well with Github or Bitbucket webhooks.
+
+= Does it works on multi site setups? =
+
+Gitium does not support multisite setups at the moment.
+
+= How does gitium handle submodules? =
+
+Submodules are currently not supported.
+
+= Where do I report security bugs found in this plugin? =
+
+Please report security bugs found in the source code of the Gitium plugin through the [Patchstack Vulnerability Disclosure Program](https://patchstack.com/database/vdp/gitium). The Patchstack team will assist you with verification, CVE assignment, and notify the developers of this plugin.
+
+== Upgrade Notice ==
+= 1.2.1 =
+Tested up to WP 6.8
+
+== Changelog ==
+
+= 1.2.1 =
+* Tested the compatibility of the plugin with WP 6.8
+
+= 1.2.0 =
+* Changed the license for all files to GPLv3
+* Fix: In some cases, the WP is configured in another folder. We've made some changes on how we check for the wp-load.php file
+
+= 1.1.0 =
+* Fix: In some cases, the website was stuck in maintenance when it was pulling the changes from remote
+* Added: A copy-to-clipboard button was introduced for copying ssh key-pair and webhook url
+
+= 1.0.7 =
+* Fix: HOME env definition;
+* Fix: deprecation warnings in PHP 8.1;
+* Compat: added composer.json package;
+* Compat: add the possibility to use a custom `.gitignore` by defining the `GITIGNORE` constant.
+
+= 1.0.6 =
+* Fixed deprecation warnings for dynamic property in git-wrapper
+
+= 1.0.5 =
+* Various bug fixes
+
+= 1.0.4 =
+* PHP 8 compat. fixes
+
+= 1.0.3 =
+* Fixed wrong redirection for multisite installations during initial setup
+
+= 1.0.2 =
+* Full PHP 7+ compatibility
+* Hotfix - Fixed the blank pages being displayed instead of success of failure messages;
+* Hotfix - Fixed the push process when other remote branches had changes;
+* Hotfix - Fixed the missing ssh / key handling with fatal errors during activation;
+* Added - More success messages in certain cases.
+
+= 1.0.1 =
+* Hotfix - Fix race condition on Code Editor Save
+
+= 1.0 =
+* Fixed WP 4.9 Compatibility
+
+= 1.0-rc12 =
+* Bumped plugin version
+
+= 1.0-rc11 =
+* Hotfixed an error that prevented gitium to error_log properly.
+
+= 1.0-rc10 =
+* Bumped wordpress tested version
+
+= 1.0-rc9 =
+* PHP7 compat and wp-cli
+
+= 1.0-rc8 =
+* Fix some indents
+* Add some more tests
+* Fix the submenu configure logic
+
+= 1.0-rc7 =
+* Test remote url from git wrapper
+* Remove the phpmd package from test environment
+* Set WP_DEBUG to false on tests
+* Refactoring
+* Abort the cherry-pick - changes are already there
+* Fix the race condition
+* Add acquire and release logs for gitium lock
+* Add explanations to merge with accept mine logic
+
+= 1.0-rc6 =
+* Delete all transients and options on uninstall hook
+* Add transients to is_versions and get_remote_tracking_branch functions
+* Update the composer
+* Check requirements before show the admin menu
+* Put the logs off by default(on test env)
+* Fix redirect issue and display errors
+* Create wordpress docker env command
+* PHP Warning: unlink #114
+
+= 1.0-rc5 =
+* Fix delete plugin/theme bug on 4.6
+* Update the readme file
+
+= 1.0-rc4 =
+* Fix merge with accept mine behind commits bug
+
+= 1.0-rc3 =
+* Add support for multisite
+* Fix PHP error on merge & push
+
+= 1.0-rc2 =
+* Change the default lockfile location
+* Fix a PHP Warning
+
+= 1.0-rc1 =
+* Update the logic of merge and push
+* Add lock mechanism for fetch and merge
+* Fix repo stuck on merge_local branch
+* Tested up to 4.5.3
+
+= 0.5.8-beta =
+* Add documentation for 'Could not connect to remote repository?'
+* Fix the update theme from Dashboard commit message & the install plugin commit message
+* Fix install/delete plugin/theme commit message
+* Add a test and rewrite the tests
+* Tested up to 4.5.2
+
+= 0.5.7-beta =
+* Fix bug deleting plugins/themes causes wrong commit message
+* Fix bug wrong commit message
+* Fix bug updated function to stop maintenance mode hang
+* Fix bug undefined variable 'new_versions'
+* Add 'Merge changes' button for gitium webhook
+* Add gitium documentation for docker
+* Add more tests
+
+= 0.5.6-beta =
+* Fix compatibility issues with wp-cli
+
+= 0.5.5-beta =
+* Fix bug plugin deletion from plugins page did not trigger commit
+
+= 0.5.4-beta =
+* Fix bug missing changes on similarly named plugins
+* Add requirements notices
+* Add requirements help section
+
+= 0.5.3-beta =
+* Fix paths with spaces bug
+* Add a Disconnect from repo button
+* Fix POST var `path` conflicts
+* Fix travis tests
+
+= 0.5.2-beta =
+* Add Contextual Help to Configuration page
+* Make the icon path relative
+* The key file is deleted properly
+* Update serbian translation
+* Make the resource type more specific
+* Fix Menu Bubble
+* Remove useless param for get_transient
+* Add Spanish Translation
+* Rename `gitium_version` transient
+* Fix git version notice
+* Delete .vimrc
+* Update .gitignore
+* Fix syntax error
+* Add better git version check
+* Fix add_query_arg vulnerability
+
+= 0.5.1-beta =
+* Update Serbian Translation (by [Ogi Djuraskovic](http://firstsiteguide.com/))
+* Fix Menu Bubble
+
+= 0.5-beta =
+* Add `Last 20 Commits` menu page
+* Add WordPress Contextual Help menu
+* Add `Settings` menu page
+* Move `Webhook URL` and `Public Key` fields to `Settings` page
+* Add menu icon
+* The `.gitignore` file can be edited
+* Fix commit message on theme/plugin update event
+* Refactoring
+
+= 0.4-beta =
+* Add `Bitbucket` documentation link
+* Add the action `gitium_before_merge_with_accept_mine`
+* Moved to `travis-ci.org`
+* Add new tests
+* Added code climate coverage reporting
+* Refactoring
+
+= 0.3.2-alpha =
+* Fix plugin activation issues
+
+= 0.3.1-alpha =
+* Fix issues with ssh repositories
+* Fix maintemance mode when webhook fails
+
+= 0.3-alpha =
+* First alpha release
diff --git a/wp-content/upgrade-temp-backup/plugins/gp-premium/backgrounds/functions/css.php b/wp-content/upgrade-temp-backup/plugins/gp-premium/backgrounds/functions/css.php
new file mode 100644
index 00000000..e46eec65
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gp-premium/backgrounds/functions/css.php
@@ -0,0 +1,134 @@
+_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;
+ }
+
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/gp-premium/backgrounds/functions/functions.php b/wp-content/upgrade-temp-backup/plugins/gp-premium/backgrounds/functions/functions.php
new file mode 100644
index 00000000..fb21ce01
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gp-premium/backgrounds/functions/functions.php
@@ -0,0 +1,1342 @@
+ '',
+ 'body_repeat' => '',
+ 'body_size' => '',
+ 'body_attachment' => '',
+ 'body_position' => '',
+ 'top_bar_image' => '',
+ 'top_bar_repeat' => '',
+ 'top_bar_size' => '',
+ 'top_bar_attachment' => '',
+ 'top_bar_position' => '',
+ 'header_image' => '',
+ 'header_repeat' => '',
+ 'header_size' => '',
+ 'header_attachment' => '',
+ 'header_position' => '',
+ 'nav_image' => '',
+ 'nav_repeat' => '',
+ 'nav_item_image' => '',
+ 'nav_item_repeat' => '',
+ 'nav_item_hover_image' => '',
+ 'nav_item_hover_repeat' => '',
+ 'nav_item_current_image' => '',
+ 'nav_item_current_repeat' => '',
+ 'sub_nav_image' => '',
+ 'sub_nav_repeat' => '',
+ 'sub_nav_item_image' => '',
+ 'sub_nav_item_repeat' => '',
+ 'sub_nav_item_hover_image' => '',
+ 'sub_nav_item_hover_repeat' => '',
+ 'sub_nav_item_current_image' => '',
+ 'sub_nav_item_current_repeat' => '',
+ 'content_image' => '',
+ 'content_repeat' => '',
+ 'content_size' => '',
+ 'content_attachment' => '',
+ 'content_position' => '',
+ 'sidebar_widget_image' => '',
+ 'sidebar_widget_repeat' => '',
+ 'sidebar_widget_size' => '',
+ 'sidebar_widget_attachment' => '',
+ 'sidebar_widget_position' => '',
+ 'footer_widget_image' => '',
+ 'footer_widget_repeat' => '',
+ 'footer_widget_size' => '',
+ 'footer_widget_attachment' => '',
+ 'footer_widget_position' => '',
+ 'footer_image' => '',
+ 'footer_repeat' => '',
+ 'footer_size' => '',
+ 'footer_attachment' => '',
+ 'footer_position' => '',
+ );
+
+ return apply_filters( 'generate_background_option_defaults', $generate_background_defaults );
+ }
+}
+
+if ( ! function_exists( 'generate_backgrounds_customize' ) ) {
+ add_action( 'customize_register', 'generate_backgrounds_customize', 999 );
+ /**
+ * Build our Customizer options
+ *
+ * @since 0.1
+ *
+ * @param object $wp_customize The Customizer object.
+ */
+ function generate_backgrounds_customize( $wp_customize ) {
+ $defaults = generate_get_background_defaults();
+
+ require_once GP_LIBRARY_DIRECTORY . 'customizer-helpers.php';
+
+ if ( method_exists( $wp_customize, 'register_control_type' ) ) {
+ $wp_customize->register_control_type( 'GeneratePress_Background_Images_Customize_Control' );
+ $wp_customize->register_control_type( 'GeneratePress_Section_Shortcut_Control' );
+ }
+
+ if ( class_exists( 'WP_Customize_Panel' ) ) {
+ if ( ! $wp_customize->get_panel( 'generate_backgrounds_panel' ) ) {
+ $wp_customize->add_panel(
+ 'generate_backgrounds_panel',
+ array(
+ 'capability' => 'edit_theme_options',
+ 'theme_supports' => '',
+ 'title' => __( 'Background Images', 'gp-premium' ),
+ 'priority' => 55,
+ )
+ );
+ }
+ }
+
+ $wp_customize->add_section(
+ 'backgrounds_section',
+ array(
+ 'title' => __( 'Background Images', 'gp-premium' ),
+ 'capability' => 'edit_theme_options',
+ 'priority' => 50,
+ )
+ );
+
+ $wp_customize->add_section(
+ 'generate_backgrounds_body',
+ array(
+ 'title' => __( 'Body', 'gp-premium' ),
+ 'capability' => 'edit_theme_options',
+ 'priority' => 5,
+ 'panel' => 'generate_backgrounds_panel',
+ )
+ );
+
+ $wp_customize->add_control(
+ new GeneratePress_Section_Shortcut_Control(
+ $wp_customize,
+ 'generate_body_background_image_shortcuts',
+ array(
+ 'section' => 'generate_backgrounds_body',
+ 'element' => __( 'Body', 'gp-premium' ),
+ 'shortcuts' => array(
+ 'layout' => 'generate_layout_container',
+ 'colors' => 'body_section',
+ 'typography' => 'font_section',
+ ),
+ 'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
+ )
+ )
+ );
+
+ /**
+ * Body background
+ */
+ $wp_customize->add_setting(
+ 'generate_background_settings[body_image]',
+ array(
+ 'default' => $defaults['body_image'],
+ 'type' => 'option',
+ 'capability' => 'edit_theme_options',
+ 'sanitize_callback' => 'esc_url_raw',
+ )
+ );
+
+ $wp_customize->add_control(
+ new WP_Customize_Image_Control(
+ $wp_customize,
+ 'generate_backgrounds-body-image',
+ array(
+ 'section' => 'generate_backgrounds_body',
+ 'settings' => 'generate_background_settings[body_image]',
+ 'label' => __( 'Body', 'gp-premium' ),
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[body_repeat]',
+ array(
+ 'default' => $defaults['body_repeat'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[body_size]',
+ array(
+ 'default' => $defaults['body_size'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[body_attachment]',
+ array(
+ 'default' => $defaults['body_attachment'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[body_position]',
+ array(
+ 'default' => $defaults['body_position'],
+ 'type' => 'option',
+ 'capability' => 'edit_theme_options',
+ 'sanitize_callback' => 'esc_html',
+ )
+ );
+
+ $wp_customize->add_control(
+ new GeneratePress_Background_Images_Customize_Control(
+ $wp_customize,
+ 'body_backgrounds_control',
+ array(
+ 'section' => 'generate_backgrounds_body',
+ 'settings' => array(
+ 'repeat' => 'generate_background_settings[body_repeat]',
+ 'size' => 'generate_background_settings[body_size]',
+ 'attachment' => 'generate_background_settings[body_attachment]',
+ 'position' => 'generate_background_settings[body_position]',
+ ),
+ )
+ )
+ );
+
+ /**
+ * Top bar background
+ */
+ $wp_customize->add_section(
+ 'generate_backgrounds_top_bar',
+ array(
+ 'title' => __( 'Top Bar', 'gp-premium' ),
+ 'capability' => 'edit_theme_options',
+ 'priority' => 5,
+ 'panel' => 'generate_backgrounds_panel',
+ 'active_callback' => 'generate_premium_is_top_bar_active',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[top_bar_image]',
+ array(
+ 'default' => $defaults['top_bar_image'],
+ 'type' => 'option',
+ 'capability' => 'edit_theme_options',
+ 'sanitize_callback' => 'esc_url_raw',
+ )
+ );
+
+ $wp_customize->add_control(
+ new WP_Customize_Image_Control(
+ $wp_customize,
+ 'generate_background_settings[top_bar_image]',
+ array(
+ 'section' => 'generate_backgrounds_top_bar',
+ 'settings' => 'generate_background_settings[top_bar_image]',
+ 'label' => __( 'Top Bar', 'gp-premium' ),
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[top_bar_repeat]',
+ array(
+ 'default' => $defaults['top_bar_repeat'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[top_bar_size]',
+ array(
+ 'default' => $defaults['top_bar_size'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[top_bar_attachment]',
+ array(
+ 'default' => $defaults['top_bar_attachment'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[top_bar_position]',
+ array(
+ 'default' => $defaults['top_bar_position'],
+ 'type' => 'option',
+ 'capability' => 'edit_theme_options',
+ 'sanitize_callback' => 'esc_html',
+ )
+ );
+
+ $wp_customize->add_control(
+ new GeneratePress_Background_Images_Customize_Control(
+ $wp_customize,
+ 'top_bar_backgrounds_control',
+ array(
+ 'section' => 'generate_backgrounds_top_bar',
+ 'settings' => array(
+ 'repeat' => 'generate_background_settings[top_bar_repeat]',
+ 'size' => 'generate_background_settings[top_bar_size]',
+ 'attachment' => 'generate_background_settings[top_bar_attachment]',
+ 'position' => 'generate_background_settings[top_bar_position]',
+ ),
+ )
+ )
+ );
+
+ /**
+ * Header background
+ */
+ $wp_customize->add_section(
+ 'generate_backgrounds_header',
+ array(
+ 'title' => __( 'Header', 'gp-premium' ),
+ 'capability' => 'edit_theme_options',
+ 'priority' => 10,
+ 'panel' => 'generate_backgrounds_panel',
+ )
+ );
+
+ $wp_customize->add_control(
+ new GeneratePress_Section_Shortcut_Control(
+ $wp_customize,
+ 'generate_header_background_image_shortcuts',
+ array(
+ 'section' => 'generate_backgrounds_header',
+ 'element' => __( 'Header', 'gp-premium' ),
+ 'shortcuts' => array(
+ 'layout' => 'generate_layout_header',
+ 'colors' => 'header_color_section',
+ 'typography' => 'font_header_section',
+ ),
+ 'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
+ 'priority' => 1,
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[header_image]',
+ array(
+ 'default' => $defaults['header_image'],
+ 'type' => 'option',
+ 'capability' => 'edit_theme_options',
+ 'sanitize_callback' => 'esc_url_raw',
+ )
+ );
+
+ $wp_customize->add_control(
+ new WP_Customize_Image_Control(
+ $wp_customize,
+ 'generate_backgrounds-header-image',
+ array(
+ 'section' => 'generate_backgrounds_header',
+ 'settings' => 'generate_background_settings[header_image]',
+ 'label' => __( 'Header', 'gp-premium' ),
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[header_repeat]',
+ array(
+ 'default' => $defaults['header_repeat'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[header_size]',
+ array(
+ 'default' => $defaults['header_size'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[header_attachment]',
+ array(
+ 'default' => $defaults['header_attachment'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[header_position]',
+ array(
+ 'default' => $defaults['header_position'],
+ 'type' => 'option',
+ 'capability' => 'edit_theme_options',
+ 'sanitize_callback' => 'esc_html',
+ )
+ );
+
+ $wp_customize->add_control(
+ new GeneratePress_Background_Images_Customize_Control(
+ $wp_customize,
+ 'header_backgrounds_control',
+ array(
+ 'section' => 'generate_backgrounds_header',
+ 'settings' => array(
+ 'repeat' => 'generate_background_settings[header_repeat]',
+ 'size' => 'generate_background_settings[header_size]',
+ 'attachment' => 'generate_background_settings[header_attachment]',
+ 'position' => 'generate_background_settings[header_position]',
+ ),
+ )
+ )
+ );
+
+ $wp_customize->add_section(
+ 'generate_backgrounds_navigation',
+ array(
+ 'title' => __( 'Primary Navigation', 'gp-premium' ),
+ 'capability' => 'edit_theme_options',
+ 'priority' => 15,
+ 'panel' => 'generate_backgrounds_panel',
+ )
+ );
+
+ $wp_customize->add_control(
+ new GeneratePress_Section_Shortcut_Control(
+ $wp_customize,
+ 'generate_primary_navigation_background_image_shortcuts',
+ array(
+ 'section' => 'generate_backgrounds_navigation',
+ 'element' => __( 'Primary Navigation', 'gp-premium' ),
+ 'shortcuts' => array(
+ 'layout' => 'generate_layout_navigation',
+ 'colors' => 'navigation_color_section',
+ 'typography' => 'font_navigation_section',
+ ),
+ 'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
+ 'priority' => 1,
+ )
+ )
+ );
+
+ /**
+ * Navigation background
+ */
+ $wp_customize->add_setting(
+ 'generate_background_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_background_settings[nav_image]',
+ array(
+ 'section' => 'generate_backgrounds_navigation',
+ 'settings' => 'generate_background_settings[nav_image]',
+ 'priority' => 750,
+ 'label' => __( 'Navigation', 'gp-premium' ),
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[nav_repeat]',
+ array(
+ 'default' => $defaults['nav_repeat'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_control(
+ 'generate_background_settings[nav_repeat]',
+ array(
+ 'type' => 'select',
+ 'section' => 'generate_backgrounds_navigation',
+ '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_background_settings[nav_repeat]',
+ 'priority' => 800,
+ )
+ );
+
+ /**
+ * Navigation item background
+ */
+ $wp_customize->add_setting(
+ 'generate_background_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_backgrounds-nav-item-image',
+ array(
+ 'section' => 'generate_backgrounds_navigation',
+ 'settings' => 'generate_background_settings[nav_item_image]',
+ 'priority' => 950,
+ 'label' => __( 'Navigation Item', 'gp-premium' ),
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[nav_item_repeat]',
+ array(
+ 'default' => $defaults['nav_item_repeat'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_control(
+ 'generate_background_settings[nav_item_repeat]',
+ array(
+ 'type' => 'select',
+ 'section' => 'generate_backgrounds_navigation',
+ '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_background_settings[nav_item_repeat]',
+ 'priority' => 1000,
+ )
+ );
+
+ /**
+ * Navigation item hover background
+ */
+ $wp_customize->add_setting(
+ 'generate_background_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_backgrounds-nav-item-hover-image',
+ array(
+ 'section' => 'generate_backgrounds_navigation',
+ 'settings' => 'generate_background_settings[nav_item_hover_image]',
+ 'priority' => 1150,
+ 'label' => __( 'Navigation Item Hover', 'gp-premium' ),
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[nav_item_hover_repeat]',
+ array(
+ 'default' => $defaults['nav_item_hover_repeat'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_control(
+ 'generate_background_settings[nav_item_hover_repeat]',
+ array(
+ 'type' => 'select',
+ 'section' => 'generate_backgrounds_navigation',
+ '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_background_settings[nav_item_hover_repeat]',
+ 'priority' => 1200,
+ )
+ );
+
+ /**
+ * Navigation item current background
+ */
+ $wp_customize->add_setting(
+ 'generate_background_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_backgrounds-nav-item-current-image',
+ array(
+ 'section' => 'generate_backgrounds_navigation',
+ 'settings' => 'generate_background_settings[nav_item_current_image]',
+ 'priority' => 1350,
+ 'label' => __( 'Navigation Item Current', 'gp-premium' ),
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[nav_item_current_repeat]',
+ array(
+ 'default' => $defaults['nav_item_current_repeat'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_control(
+ 'generate_background_settings[nav_item_current_repeat]',
+ array(
+ 'type' => 'select',
+ 'section' => 'generate_backgrounds_navigation',
+ '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_background_settings[nav_item_current_repeat]',
+ 'priority' => 1400,
+ )
+ );
+
+ $wp_customize->add_section(
+ 'generate_backgrounds_subnavigation',
+ array(
+ 'title' => __( 'Primary Sub-Navigation', 'gp-premium' ),
+ 'capability' => 'edit_theme_options',
+ 'priority' => 20,
+ 'panel' => 'generate_backgrounds_panel',
+ )
+ );
+
+ /**
+ * Sub-Navigation item background
+ */
+ $wp_customize->add_setting(
+ 'generate_background_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_background_settings[sub_nav_item_image]',
+ array(
+ 'section' => 'generate_backgrounds_subnavigation',
+ 'settings' => 'generate_background_settings[sub_nav_item_image]',
+ 'priority' => 1700,
+ 'label' => __( 'Sub-Navigation Item', 'gp-premium' ),
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[sub_nav_item_repeat]',
+ array(
+ 'default' => $defaults['sub_nav_item_repeat'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_control(
+ 'generate_background_settings[sub_nav_item_repeat]',
+ array(
+ 'type' => 'select',
+ 'section' => 'generate_backgrounds_subnavigation',
+ '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_background_settings[sub_nav_item_repeat]',
+ 'priority' => 1800,
+ )
+ );
+
+ /**
+ * Sub-Navigation item hover background
+ */
+ $wp_customize->add_setting(
+ 'generate_background_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_background_settings[sub_nav_item_hover_image]',
+ array(
+ 'section' => 'generate_backgrounds_subnavigation',
+ 'settings' => 'generate_background_settings[sub_nav_item_hover_image]',
+ 'priority' => 2000,
+ 'label' => __( 'Sub-Navigation Item Hover', 'gp-premium' ),
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[sub_nav_item_hover_repeat]',
+ array(
+ 'default' => $defaults['sub_nav_item_hover_repeat'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_control(
+ 'generate_background_settings[sub_nav_item_hover_repeat]',
+ array(
+ 'type' => 'select',
+ 'section' => 'generate_backgrounds_subnavigation',
+ '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_background_settings[sub_nav_item_hover_repeat]',
+ 'priority' => 2100,
+ )
+ );
+
+ /**
+ * Sub-Navigation item current background
+ */
+ $wp_customize->add_setting(
+ 'generate_background_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_background_settings[sub_nav_item_current_image]',
+ array(
+ 'section' => 'generate_backgrounds_subnavigation',
+ 'settings' => 'generate_background_settings[sub_nav_item_current_image]',
+ 'priority' => 2300,
+ 'label' => __( 'Sub-Navigation Item Current', 'gp-premium' ),
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[sub_nav_item_current_repeat]',
+ array(
+ 'default' => $defaults['sub_nav_item_current_repeat'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_control(
+ 'generate_background_settings[sub_nav_item_current_repeat]',
+ array(
+ 'type' => 'select',
+ 'section' => 'generate_backgrounds_subnavigation',
+ '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_background_settings[sub_nav_item_current_repeat]',
+ 'priority' => 2400,
+ )
+ );
+
+ $wp_customize->add_section(
+ 'generate_backgrounds_content',
+ array(
+ 'title' => __( 'Content', 'gp-premium' ),
+ 'capability' => 'edit_theme_options',
+ 'priority' => 25,
+ 'panel' => 'generate_backgrounds_panel',
+ )
+ );
+
+ $wp_customize->add_control(
+ new GeneratePress_Section_Shortcut_Control(
+ $wp_customize,
+ 'generate_content_background_image_shortcuts',
+ array(
+ 'section' => 'generate_backgrounds_content',
+ 'element' => __( 'Content', 'gp-premium' ),
+ 'shortcuts' => array(
+ 'colors' => 'content_color_section',
+ 'typography' => 'font_section',
+ ),
+ 'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
+ 'priority' => 1,
+ )
+ )
+ );
+
+ /**
+ * Content background
+ */
+ $wp_customize->add_setting(
+ 'generate_background_settings[content_image]',
+ array(
+ 'default' => $defaults['content_image'],
+ 'type' => 'option',
+ 'capability' => 'edit_theme_options',
+ 'sanitize_callback' => 'esc_url_raw',
+ )
+ );
+
+ $wp_customize->add_control(
+ new WP_Customize_Image_Control(
+ $wp_customize,
+ 'generate_background_settings[content_image]',
+ array(
+ 'section' => 'generate_backgrounds_content',
+ 'settings' => 'generate_background_settings[content_image]',
+ 'label' => __( 'Content', 'gp-premium' ),
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[content_repeat]',
+ array(
+ 'default' => $defaults['content_repeat'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[content_size]',
+ array(
+ 'default' => $defaults['content_size'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[content_attachment]',
+ array(
+ 'default' => $defaults['content_attachment'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[content_position]',
+ array(
+ 'default' => $defaults['content_position'],
+ 'type' => 'option',
+ 'capability' => 'edit_theme_options',
+ 'sanitize_callback' => 'esc_html',
+ )
+ );
+
+ $wp_customize->add_control(
+ new GeneratePress_Background_Images_Customize_Control(
+ $wp_customize,
+ 'content_backgrounds_control',
+ array(
+ 'section' => 'generate_backgrounds_content',
+ 'settings' => array(
+ 'repeat' => 'generate_background_settings[content_repeat]',
+ 'size' => 'generate_background_settings[content_size]',
+ 'attachment' => 'generate_background_settings[content_attachment]',
+ 'position' => 'generate_background_settings[content_position]',
+ ),
+ )
+ )
+ );
+
+ $wp_customize->add_section(
+ 'generate_backgrounds_sidebars',
+ array(
+ 'title' => __( 'Sidebar', 'gp-premium' ),
+ 'capability' => 'edit_theme_options',
+ 'priority' => 25,
+ 'panel' => 'generate_backgrounds_panel',
+ )
+ );
+
+ $wp_customize->add_control(
+ new GeneratePress_Section_Shortcut_Control(
+ $wp_customize,
+ 'generate_sidebar_background_image_shortcuts',
+ array(
+ 'section' => 'generate_backgrounds_sidebars',
+ 'element' => __( 'Sidebar', 'gp-premium' ),
+ 'shortcuts' => array(
+ 'layout' => 'generate_layout_sidebars',
+ 'colors' => 'sidebar_widget_color_section',
+ 'typography' => 'font_widget_section',
+ ),
+ 'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
+ 'priority' => 1,
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[sidebar_widget_image]',
+ array(
+ 'default' => $defaults['sidebar_widget_image'],
+ 'type' => 'option',
+ 'capability' => 'edit_theme_options',
+ 'sanitize_callback' => 'esc_url_raw',
+ )
+ );
+
+ $wp_customize->add_control(
+ new WP_Customize_Image_Control(
+ $wp_customize,
+ 'generate_background_settings[sidebar_widget_image]',
+ array(
+ 'section' => 'generate_backgrounds_sidebars',
+ 'settings' => 'generate_background_settings[sidebar_widget_image]',
+ 'label' => __( 'Sidebar Widgets', 'gp-premium' ),
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[sidebar_widget_repeat]',
+ array(
+ 'default' => $defaults['sidebar_widget_repeat'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[sidebar_widget_size]',
+ array(
+ 'default' => $defaults['sidebar_widget_size'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[sidebar_widget_attachment]',
+ array(
+ 'default' => $defaults['sidebar_widget_attachment'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[sidebar_widget_position]',
+ array(
+ 'default' => $defaults['sidebar_widget_position'],
+ 'type' => 'option',
+ 'capability' => 'edit_theme_options',
+ 'sanitize_callback' => 'esc_html',
+ )
+ );
+
+ $wp_customize->add_control(
+ new GeneratePress_Background_Images_Customize_Control(
+ $wp_customize,
+ 'sidebar_backgrounds_control',
+ array(
+ 'section' => 'generate_backgrounds_sidebars',
+ 'settings' => array(
+ 'repeat' => 'generate_background_settings[sidebar_widget_repeat]',
+ 'size' => 'generate_background_settings[sidebar_widget_size]',
+ 'attachment' => 'generate_background_settings[sidebar_widget_attachment]',
+ 'position' => 'generate_background_settings[sidebar_widget_position]',
+ ),
+ )
+ )
+ );
+
+ $wp_customize->add_section(
+ 'generate_backgrounds_footer',
+ array(
+ 'title' => __( 'Footer', 'gp-premium' ),
+ 'capability' => 'edit_theme_options',
+ 'priority' => 30,
+ 'panel' => 'generate_backgrounds_panel',
+ )
+ );
+
+ $wp_customize->add_control(
+ new GeneratePress_Section_Shortcut_Control(
+ $wp_customize,
+ 'generate_footer_background_image_shortcuts',
+ array(
+ 'section' => 'generate_backgrounds_footer',
+ 'element' => __( 'Footer', 'gp-premium' ),
+ 'shortcuts' => array(
+ 'layout' => 'generate_layout_footer',
+ 'colors' => 'footer_color_section',
+ 'typography' => 'font_footer_section',
+ ),
+ 'settings' => ( isset( $wp_customize->selective_refresh ) ) ? array() : 'blogname',
+ 'priority' => 1,
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[footer_widget_image]',
+ array(
+ 'default' => $defaults['footer_widget_image'],
+ 'type' => 'option',
+ 'capability' => 'edit_theme_options',
+ 'sanitize_callback' => 'esc_url_raw',
+ )
+ );
+
+ $wp_customize->add_control(
+ new WP_Customize_Image_Control(
+ $wp_customize,
+ 'generate_background_settings[footer_widget_image]',
+ array(
+ 'section' => 'generate_backgrounds_footer',
+ 'settings' => 'generate_background_settings[footer_widget_image]',
+ 'label' => __( 'Footer Widget Area', 'gp-premium' ),
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[footer_widget_repeat]',
+ array(
+ 'default' => $defaults['footer_widget_repeat'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[footer_widget_size]',
+ array(
+ 'default' => $defaults['footer_widget_size'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[footer_widget_attachment]',
+ array(
+ 'default' => $defaults['footer_widget_attachment'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[footer_widget_position]',
+ array(
+ 'default' => $defaults['footer_widget_position'],
+ 'type' => 'option',
+ 'capability' => 'edit_theme_options',
+ 'sanitize_callback' => 'esc_html',
+ )
+ );
+
+ $wp_customize->add_control(
+ new GeneratePress_Background_Images_Customize_Control(
+ $wp_customize,
+ 'footer_widgets_backgrounds_control',
+ array(
+ 'section' => 'generate_backgrounds_footer',
+ 'settings' => array(
+ 'repeat' => 'generate_background_settings[footer_widget_repeat]',
+ 'size' => 'generate_background_settings[footer_widget_size]',
+ 'attachment' => 'generate_background_settings[footer_widget_attachment]',
+ 'position' => 'generate_background_settings[footer_widget_position]',
+ ),
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[footer_image]',
+ array(
+ 'default' => $defaults['footer_image'],
+ 'type' => 'option',
+ 'capability' => 'edit_theme_options',
+ 'sanitize_callback' => 'esc_url_raw',
+ )
+ );
+
+ $wp_customize->add_control(
+ new WP_Customize_Image_Control(
+ $wp_customize,
+ 'generate_backgrounds-footer-image',
+ array(
+ 'section' => 'generate_backgrounds_footer',
+ 'settings' => 'generate_background_settings[footer_image]',
+ 'label' => __( 'Footer Area', 'gp-premium' ),
+ )
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[footer_repeat]',
+ array(
+ 'default' => $defaults['footer_repeat'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[footer_size]',
+ array(
+ 'default' => $defaults['footer_size'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[footer_attachment]',
+ array(
+ 'default' => $defaults['footer_attachment'],
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_key',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'generate_background_settings[footer_position]',
+ array(
+ 'default' => $defaults['footer_position'],
+ 'type' => 'option',
+ 'capability' => 'edit_theme_options',
+ 'sanitize_callback' => 'esc_html',
+ )
+ );
+
+ $wp_customize->add_control(
+ new GeneratePress_Background_Images_Customize_Control(
+ $wp_customize,
+ 'footer_backgrounds_control',
+ array(
+ 'section' => 'generate_backgrounds_footer',
+ 'settings' => array(
+ 'repeat' => 'generate_background_settings[footer_repeat]',
+ 'size' => 'generate_background_settings[footer_size]',
+ 'attachment' => 'generate_background_settings[footer_attachment]',
+ 'position' => 'generate_background_settings[footer_position]',
+ ),
+ )
+ )
+ );
+ }
+}
+
+if ( ! function_exists( 'generate_backgrounds_css' ) ) {
+ /**
+ * Generate the CSS in the section using the Theme Customizer
+ *
+ * @since 0.1
+ */
+ function generate_backgrounds_css() {
+ $generate_settings = wp_parse_args(
+ get_option( 'generate_background_settings', array() ),
+ generate_get_background_defaults()
+ );
+
+ // Fix size values.
+ // Spaces and % are stripped by sanitize_key.
+ $generate_settings['body_size'] = ( '100' == $generate_settings['body_size'] ) ? '100% auto' : esc_attr( $generate_settings['body_size'] ); // phpcs:ignore -- Non-strict comparison ok.
+ $generate_settings['top_bar_size'] = ( '100' == $generate_settings['top_bar_size'] ) ? '100% auto' : esc_attr( $generate_settings['top_bar_size'] ); // phpcs:ignore -- Non-strict comparison ok.
+ $generate_settings['header_size'] = ( '100' == $generate_settings['header_size'] ) ? '100% auto' : esc_attr( $generate_settings['header_size'] ); // phpcs:ignore -- Non-strict comparison ok.
+ $generate_settings['content_size'] = ( '100' == $generate_settings['content_size'] ) ? '100% auto' : esc_attr( $generate_settings['content_size'] ); // phpcs:ignore -- Non-strict comparison ok.
+ $generate_settings['sidebar_widget_size'] = ( '100' == $generate_settings['sidebar_widget_size'] ) ? '100% auto' : esc_attr( $generate_settings['sidebar_widget_size'] ); // phpcs:ignore -- Non-strict comparison ok.
+ $generate_settings['footer_widget_size'] = ( '100' == $generate_settings['footer_widget_size'] ) ? '100% auto' : esc_attr( $generate_settings['footer_widget_size'] ); // phpcs:ignore -- Non-strict comparison ok.
+ $generate_settings['footer_size'] = ( '100' == $generate_settings['footer_size'] ) ? '100% auto' : esc_attr( $generate_settings['footer_size'] ); // phpcs:ignore -- Non-strict comparison ok.
+
+ $css = new GeneratePress_Backgrounds_CSS();
+
+ $css->set_selector( 'body' );
+ $css->add_property( 'background-image', esc_url( $generate_settings['body_image'] ), 'url' );
+ $css->add_property( 'background-repeat', esc_attr( $generate_settings['body_repeat'] ) );
+ $css->add_property( 'background-size', esc_attr( $generate_settings['body_size'] ) );
+ $css->add_property( 'background-attachment', esc_attr( $generate_settings['body_attachment'] ) );
+ $css->add_property( 'background-position', esc_attr( $generate_settings['body_position'] ) );
+
+ if ( is_active_sidebar( 'top-bar' ) ) {
+ $css->set_selector( '.top-bar' );
+ $css->add_property( 'background-image', esc_url( $generate_settings['top_bar_image'] ), 'url' );
+ $css->add_property( 'background-repeat', esc_attr( $generate_settings['top_bar_repeat'] ) );
+ $css->add_property( 'background-size', esc_attr( $generate_settings['top_bar_size'] ) );
+ $css->add_property( 'background-attachment', esc_attr( $generate_settings['top_bar_attachment'] ) );
+ $css->add_property( 'background-position', esc_attr( $generate_settings['top_bar_position'] ) );
+ }
+
+ $css->set_selector( '.site-header' );
+ $css->add_property( 'background-image', esc_url( $generate_settings['header_image'] ), 'url' );
+ $css->add_property( 'background-repeat', esc_attr( $generate_settings['header_repeat'] ) );
+ $css->add_property( 'background-size', esc_attr( $generate_settings['header_size'] ) );
+ $css->add_property( 'background-attachment', esc_attr( $generate_settings['header_attachment'] ) );
+ $css->add_property( 'background-position', esc_attr( $generate_settings['header_position'] ) );
+
+ $css->set_selector( '.main-navigation, .main-navigation .menu-toggle' );
+ $css->add_property( 'background-image', esc_url( $generate_settings['nav_image'] ), 'url' );
+ $css->add_property( 'background-repeat', esc_attr( $generate_settings['nav_repeat'] ) );
+
+ $css->set_selector( '.main-navigation .main-nav > ul > li > a' );
+ $css->add_property( 'background-image', esc_url( $generate_settings['nav_item_image'] ), 'url' );
+ $css->add_property( 'background-repeat', esc_attr( $generate_settings['nav_item_repeat'] ) );
+
+ $css->set_selector( '.main-navigation .main-nav > ul > li > a:hover,.main-navigation .main-nav > ul > li.sfHover > a' );
+ $css->add_property( 'background-image', esc_url( $generate_settings['nav_item_hover_image'] ), 'url' );
+ $css->add_property( 'background-repeat', esc_attr( $generate_settings['nav_item_hover_repeat'] ) );
+
+ $css->set_selector( '.main-navigation .main-nav > ul > li[class*="current-menu-"] > a,.main-navigation .main-nav > ul > li[class*="current-menu-"] > a:hover,.main-navigation .main-nav > ul > li[class*="current-menu-"].sfHover > a' );
+ $css->add_property( 'background-image', esc_url( $generate_settings['nav_item_current_image'] ), 'url' );
+ $css->add_property( 'background-repeat', esc_attr( $generate_settings['nav_item_current_repeat'] ) );
+
+ $css->set_selector( '.main-navigation ul ul li a' );
+ $css->add_property( 'background-image', esc_url( $generate_settings['sub_nav_item_image'] ), 'url' );
+ $css->add_property( 'background-repeat', esc_attr( $generate_settings['sub_nav_item_repeat'] ) );
+
+ $css->set_selector( '.main-navigation ul ul li > a:hover,.main-navigation ul ul li.sfHover > a' );
+ $css->add_property( 'background-image', esc_url( $generate_settings['sub_nav_item_hover_image'] ), 'url' );
+ $css->add_property( 'background-repeat', esc_attr( $generate_settings['sub_nav_item_hover_repeat'] ) );
+
+ $css->set_selector( '.main-navigation ul ul li[class*="current-menu-"] > a,.main-navigation ul ul li[class*="current-menu-"] > a:hover,.main-navigation ul ul li[class*="current-menu-"].sfHover > a' );
+ $css->add_property( 'background-image', esc_url( $generate_settings['sub_nav_item_current_image'] ), 'url' );
+ $css->add_property( 'background-repeat', esc_attr( $generate_settings['sub_nav_item_current_repeat'] ) );
+
+ $css->set_selector( '.separate-containers .inside-article,.separate-containers .comments-area,.separate-containers .page-header,.one-container .container,.separate-containers .paging-navigation,.separate-containers .inside-page-header' );
+ $css->add_property( 'background-image', esc_url( $generate_settings['content_image'] ), 'url' );
+ $css->add_property( 'background-repeat', esc_attr( $generate_settings['content_repeat'] ) );
+ $css->add_property( 'background-size', esc_attr( $generate_settings['content_size'] ) );
+ $css->add_property( 'background-attachment', esc_attr( $generate_settings['content_attachment'] ) );
+ $css->add_property( 'background-position', esc_attr( $generate_settings['content_position'] ) );
+
+ $css->set_selector( '.sidebar .widget' );
+ $css->add_property( 'background-image', esc_url( $generate_settings['sidebar_widget_image'] ), 'url' );
+ $css->add_property( 'background-repeat', esc_attr( $generate_settings['sidebar_widget_repeat'] ) );
+ $css->add_property( 'background-size', esc_attr( $generate_settings['sidebar_widget_size'] ) );
+ $css->add_property( 'background-attachment', esc_attr( $generate_settings['sidebar_widget_attachment'] ) );
+ $css->add_property( 'background-position', esc_attr( $generate_settings['sidebar_widget_position'] ) );
+
+ $css->set_selector( '.footer-widgets' );
+ $css->add_property( 'background-image', esc_url( $generate_settings['footer_widget_image'] ), 'url' );
+ $css->add_property( 'background-repeat', esc_attr( $generate_settings['footer_widget_repeat'] ) );
+ $css->add_property( 'background-size', esc_attr( $generate_settings['footer_widget_size'] ) );
+ $css->add_property( 'background-attachment', esc_attr( $generate_settings['footer_widget_attachment'] ) );
+ $css->add_property( 'background-position', esc_attr( $generate_settings['footer_widget_position'] ) );
+
+ $css->set_selector( '.site-info' );
+ $css->add_property( 'background-image', esc_url( $generate_settings['footer_image'] ), 'url' );
+ $css->add_property( 'background-repeat', esc_attr( $generate_settings['footer_repeat'] ) );
+ $css->add_property( 'background-size', esc_attr( $generate_settings['footer_size'] ) );
+ $css->add_property( 'background-attachment', esc_attr( $generate_settings['footer_attachment'] ) );
+ $css->add_property( 'background-position', esc_attr( $generate_settings['footer_position'] ) );
+
+ return apply_filters( 'generate_backgrounds_css_output', $css->css_output() );
+ }
+}
+
+if ( ! function_exists( 'generate_background_scripts' ) ) {
+ add_action( 'wp_enqueue_scripts', 'generate_background_scripts', 70 );
+ /**
+ * Enqueue scripts and styles.
+ *
+ * @since 0.1
+ */
+ function generate_background_scripts() {
+ if ( 'inline' === generate_get_css_print_method() ) {
+ wp_add_inline_style( 'generate-style', generate_backgrounds_css() );
+ }
+ }
+}
+
+add_filter( 'generate_external_dynamic_css_output', 'generate_backgrounds_add_external_css' );
+/**
+ * Add to external stylesheet.
+ *
+ * @since 1.11.0
+ *
+ * @param string $css Existing CSS.
+ */
+function generate_backgrounds_add_external_css( $css ) {
+ if ( 'inline' === generate_get_css_print_method() ) {
+ return $css;
+ }
+
+ $css .= generate_backgrounds_css();
+
+ return $css;
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/gp-premium/backgrounds/functions/secondary-nav-backgrounds.php b/wp-content/upgrade-temp-backup/plugins/gp-premium/backgrounds/functions/secondary-nav-backgrounds.php
new file mode 100644
index 00000000..fdc17f1d
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gp-premium/backgrounds/functions/secondary-nav-backgrounds.php
@@ -0,0 +1,420 @@
+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,
+ )
+ );
+ }
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/gp-premium/backgrounds/generate-backgrounds.php b/wp-content/upgrade-temp-backup/plugins/gp-premium/backgrounds/generate-backgrounds.php
new file mode 100644
index 00000000..d9cd1055
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gp-premium/backgrounds/generate-backgrounds.php
@@ -0,0 +1,19 @@
+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(
+ '+
Previous post title
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"86e1ad46","element":"p","blockVersion":3,"typography":{"fontSize":"14px"},"spacing":{"marginBottom":"0px"},"gpDynamicTextType":"post-author","gpDynamicLinkType":"author-archives","gpDynamicTextReplace":"Author name","gpDynamicSource":"previous-post","gpDynamicTextBefore":"by "} --\x3eAuthor name
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"2540358d","isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"row-reverse","flexDirectionMobile":"row","alignItems":"center","columnGap":"20px","sizing":{"width":"50%","widthMobile":"100%","height":"","maxWidth":""},"typography":{"textAlignMobile":"left"},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"},"gpRemoveContainerCondition":"no-next-post"} --\x3e \x3c!-- wp:generatepress/dynamic-image {"imageType":"featured-image","imageSource":"next-post","imageSize":"thumbnail","linkTo":"single-post","imageWidth":100,"imageHeight":100,"avatarSize":100} /--\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"daa456b5","isDynamic":true,"blockVersion":4,"sizing":{"width":"75%","widthMobile":"75%","height":"","maxWidth":""},"typography":{"textAlign":"right","textAlignMobile":"left"},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"}} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"2883b2a4","element":"p","blockVersion":3,"spacing":{"marginBottom":"5px"},"gpDynamicTextType":"title","gpDynamicLinkType":"single-post","gpDynamicTextReplace":"Next post title","gpDynamicSource":"next-post"} --\x3eNext post title
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"3d2e07c6","element":"p","blockVersion":3,"typography":{"fontSize":"14px"},"spacing":{"marginBottom":"0px"},"gpDynamicTextType":"post-author","gpDynamicLinkType":"author-archives","gpDynamicTextReplace":"Author name","gpDynamicSource":"next-post","gpDynamicTextBefore":"by "} --\x3eAuthor name
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e',meta:[{key:"_generate_hook",value:"generate_after_do_template_part"},{key:"_generate_hook_priority",value:"1"},{key:"_generate_disable_post_navigation",value:!0},{key:"_generate_use_archive_navigation_container",value:!0}]},template_2:{label:(0,i._x)("Two columns with arrows","label","gp-premium"),thumbnail:"post-navigation-arrows-1.jpg",content:'\x3c!-- wp:generateblocks/container {"uniqueId":"d1dd99b1","isDynamic":true,"blockVersion":4,"sizing":{"height":"","maxWidth":""},"spacing":{"paddingTop":"20px","paddingRight":"0px","paddingBottom":"20px","paddingLeft":"0px"}} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"8878e700","isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"row","flexDirectionMobile":"column","alignItems":"center","justifyContent":"space-between","rowGapMobile":"10px","sizing":{"maxWidth":""},"useGlobalMaxWidth":true,"spacing":{"marginRight":"auto","marginLeft":"auto"}} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"9c89f761","isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"row","alignItems":"center","columnGap":"30px","sizing":{"width":"50%","widthMobile":"100%","height":"","maxWidth":""},"spacing":{"paddingTop":"","paddingRight":"","paddingBottom":"","paddingLeft":"","marginBottomMobile":"10px"},"gpRemoveContainerCondition":"no-previous-post"} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"9cf413a8","isDynamic":true,"blockVersion":4,"sizing":{"width":"","widthTablet":"","widthMobile":"","height":"","maxWidth":""},"spacing":{"paddingTop":"","paddingRight":"","paddingBottom":"","paddingLeft":""}} --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"bec8d56e","hasUrl":true,"blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"textAlign":"center"},"spacing":{"paddingTop":"10px","paddingRight":"10px","paddingBottom":"10px","paddingLeft":"10px"},"backgroundColor":"#000000","backgroundColorHover":"#abb8c3","textColor":"#ffffff","hasIcon":true,"removeText":true,"iconStyles":{"width":"1.5em","height":"1.5em","paddingRight":"0.5em"},"gpDynamicLinkType":"single-post","gpDynamicSource":"previous-post"} --\x3e \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"625f3305","isDynamic":true,"blockVersion":4,"sizing":{"width":"","widthTablet":"","widthMobile":"","height":"","maxWidth":""},"spacing":{"paddingTop":"","paddingRight":"","paddingBottom":"","paddingLeft":""}} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"a6f36397","element":"p","blockVersion":3,"spacing":{"marginBottom":"0px"},"gpDynamicTextType":"title","gpDynamicLinkType":"single-post","gpDynamicTextReplace":"Previous post title","gpDynamicSource":"previous-post"} --\x3ePrevious post title
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"3d262c0b","element":"p","blockVersion":3,"typography":{"fontSize":"14px"},"spacing":{"marginBottom":"0px"},"gpDynamicTextType":"post-date","gpDynamicTextReplace":"Date","gpDynamicSource":"previous-post","gpDynamicDateUpdated":true} --\x3eDate
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"5d70717c","isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"row","alignItems":"center","justifyContent":"flex-end","justifyContentMobile":"flex-start","columnGap":"30px","sizing":{"width":"50%","widthMobile":"100%","height":"","maxWidth":""},"typography":{"textAlign":"right","textAlignMobile":"left"},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"},"gpRemoveContainerCondition":"no-next-post"} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"78f3ead4","isDynamic":true,"blockVersion":4,"sizing":{"width":"","widthTablet":"","widthMobile":"","height":"","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"}} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"643cf12f","element":"p","blockVersion":3,"spacing":{"marginBottom":"0px"},"gpDynamicTextType":"title","gpDynamicLinkType":"single-post","gpDynamicTextReplace":"Next post title","gpDynamicSource":"next-post"} --\x3eNext post title
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"8ac35083","element":"p","blockVersion":3,"typography":{"fontSize":"14px"},"spacing":{"marginBottom":"0px"},"gpDynamicTextType":"post-date","gpDynamicTextReplace":"Date","gpDynamicSource":"next-post","gpDynamicDateUpdated":true} --\x3eDate
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"780c810b","isDynamic":true,"blockVersion":4,"orderMobile":-1,"sizing":{"width":"","widthTablet":"","widthMobile":"","height":"","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"}} --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"122d9fa4","hasUrl":true,"blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"textAlign":"center"},"spacing":{"paddingTop":"10px","paddingRight":"10px","paddingBottom":"10px","paddingLeft":"10px"},"backgroundColor":"#000000","backgroundColorHover":"#abb8c3","textColor":"#ffffff","hasIcon":true,"removeText":true,"iconStyles":{"width":"1.5em","height":"1.5em","paddingRight":"0.5em"},"gpDynamicLinkType":"single-post","gpDynamicSource":"next-post"} --\x3e \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e',meta:[{key:"_generate_hook",value:"generate_after_do_template_part"},{key:"_generate_hook_priority",value:"1"},{key:"_generate_disable_post_navigation",value:!0},{key:"_generate_use_archive_navigation_container",value:!0}]},template_3:{label:(0,i._x)("Two columns with background overlays","label","gp-premium"),thumbnail:"post-navigation-overlay.jpg",content:'\x3c!-- wp:generateblocks/container {"uniqueId":"aadd0a6f","isDynamic":true,"blockVersion":4,"sizing":{"height":"","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"},"paddingSyncUnits":true} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"3642451a","isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"row","sizing":{"maxWidth":""},"useGlobalMaxWidth":true,"spacing":{"marginRight":"auto","marginLeft":"auto"}} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"59edc08b","backgroundColor":"#000000","textColor":"#ffffff","linkColor":"#ffffff","linkColorHover":"#e3e3e3","bgImage":{"id":"","image":{"url":"#dynamic-background-image"}},"bgOptions":{"selector":"pseudo-element","opacity":0.4,"overlay":false,"position":"center center","size":"cover","repeat":"no-repeat","attachment":""},"innerZindex":1,"isDynamic":true,"blockVersion":4,"position":"relative","overflowX":"hidden","overflowY":"hidden","sizing":{"width":"50%","widthMobile":"100%","height":"","maxWidth":""},"spacing":{"paddingTop":"40px","paddingRight":"40px","paddingBottom":"40px","paddingLeft":"40px"},"paddingSyncUnits":true,"gpDynamicImageBg":"featured-image","gpDynamicSource":"previous-post","gpRemoveContainerCondition":"no-previous-post"} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"a510c6c2","isDynamic":true,"blockVersion":4,"position":"relative","zindex":1,"sizing":{"maxWidth":""},"useGlobalMaxWidth":true,"spacing":{"marginRight":"auto","marginLeft":"auto"}} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"8d3d4c12","element":"p","blockVersion":3,"display":"inline-block","typography":{"fontSize":"14px","textTransform":"uppercase"},"spacing":{"paddingTop":"5px","paddingRight":"10px","paddingBottom":"5px","paddingLeft":"10px"},"inlineWidth":true,"backgroundColor":"#cf2e2e"} --\x3ePrevious
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"352592d1","element":"h3","blockVersion":3,"typography":{"fontSize":"25px"},"spacing":{"marginBottom":"0px"},"className":"","gpDynamicTextType":"title","gpDynamicLinkType":"single-post","gpDynamicTextReplace":"Hello World","gpDynamicSource":"previous-post"} --\x3eNext
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"6ba8079e","element":"h3","blockVersion":3,"typography":{"fontSize":"25px"},"spacing":{"marginBottom":"0px"},"className":"","gpDynamicTextType":"title","gpDynamicLinkType":"single-post","gpDynamicTextReplace":"Hello World","gpDynamicSource":"next-post"} --\x3eComments number
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"7af8fa61","backgroundColor":"#0366d6","isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"row","flexDirectionMobile":"column","justifyContent":"space-between","sizing":{"width":"50%","widthMobile":"100%","height":"","maxWidth":""},"spacing":{"paddingTop":"30px","paddingRight":"25px","paddingBottom":"25px","paddingLeft":"0px"},"gpRemoveContainerCondition":"no-next-post"} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"045e1698","isDynamic":true,"blockVersion":4,"sizing":{"width":"","widthMobile":"100%","height":"","maxWidth":""},"typography":{},"spacing":{"paddingTop":"","paddingRight":"","paddingBottom":"","paddingLeft":""}} --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"557abb73","hasUrl":true,"blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"textAlign":"center"},"spacing":{"paddingTop":"15px","paddingRight":"20px","paddingBottom":"15px","paddingLeft":"20px"},"backgroundColor":"#ffffff","backgroundColorHover":"#222222","textColor":"#0693e3","textColorHover":"#ffffff","hasIcon":true,"removeText":true,"iconStyles":{"width":"1em","height":"1em","paddingRight":"0.5em"},"gpDynamicLinkType":"single-post","gpDynamicSource":"next-post"} --\x3e \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"9ad09f6f","isDynamic":true,"blockVersion":4,"sizing":{"width":"","widthMobile":"100%","height":"","maxWidth":""},"typography":{},"spacing":{"paddingTop":"","paddingRight":"","paddingBottom":"","paddingLeft":"","paddingLeftMobile":"10px","marginTopMobile":"20px"}} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"9ba9e9d1","element":"h3","blockVersion":3,"typography":{},"spacing":{"marginBottom":"10px"},"textColor":"#ffffff","linkColor":"#ffffff","gpDynamicTextType":"title","gpDynamicLinkType":"single-post","gpDynamicTextReplace":"Hello World","gpDynamicSource":"next-post"} --\x3eComments number
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e',meta:[{key:"_generate_hook",value:"generate_after_do_template_part"},{key:"_generate_hook_priority",value:"1"},{key:"_generate_disable_post_navigation",value:!0},{key:"_generate_use_archive_navigation_container",value:!1}]},template_5:{label:(0,i._x)("Two columns with featured image offset","label","gp-premim"),thumbnail:"post-navigation-offset.jpg",content:'\x3c!-- wp:generateblocks/container {"uniqueId":"52018004","innerContainer":"full","isDynamic":true,"blockVersion":4,"sizing":{"height":"","maxWidth":""},"typography":{"textAlign":"right"},"spacing":{"paddingTop":"","paddingRight":"","paddingBottom":"","paddingLeft":"","marginRight":"30px","marginLeft":"30px","marginLeftTablet":"30px","marginRightMobile":"25px","marginLeftMobile":"25px"}} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"e54982d5","isDynamic":true,"blockVersion":4,"sizing":{"maxWidth":""},"spacing":{"marginRight":"auto","marginLeft":"auto"}} --\x3e \x3c!-- wp:generateblocks/grid {"uniqueId":"7bdd6853","columns":4,"horizontalGap":0,"verticalGapMobile":0,"isDynamic":true,"blockVersion":3,"useLegacyRowGap":true} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"4138dd74","isGrid":true,"gridId":"7bdd6853","bgImage":{"id":"","image":{"url":"#dynamic-background-image"}},"verticalAlignment":"center","isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"column","justifyContent":"center","sizing":{"width":"25%","widthTablet":"50%","widthMobile":"50%","height":"100%","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"},"borders":{"borderBottomLeftRadius":"10px","borderTopLeftRadius":"10px","borderBottomLeftRadiusTablet":"0px","borderBottomLeftRadiusMobile":"0px","borderTopLeftRadiusMobile":"5px"},"gpDynamicImageBg":"featured-image","gpDynamicSource":"previous-post","gpRemoveContainerCondition":"no-previous-post"} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"83fd48c9","isDynamic":true,"blockVersion":4,"typography":{"textAlign":"left"}} --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"a3aaad4c","hasUrl":true,"blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"textAlign":"center"},"spacing":{"paddingTop":"15px","paddingRight":"15px","paddingBottom":"15px","paddingLeft":"15px","marginRight":"1.5em","marginLeft":"-1.5em"},"borders":{"borderTopWidth":"7px","borderTopStyle":"solid","borderTopColor":"#f9f9f9","borderRightWidth":"7px","borderRightStyle":"solid","borderRightColor":"#f9f9f9","borderBottomWidth":"7px","borderBottomStyle":"solid","borderBottomColor":"#f9f9f9","borderLeftWidth":"7px","borderLeftStyle":"solid","borderLeftColor":"#f9f9f9","borderTopRightRadius":"100%","borderBottomRightRadius":"100%","borderBottomLeftRadius":"100%","borderTopLeftRadius":"100%"},"backgroundColor":"#b5b5b5","backgroundColorHover":"#222222","textColor":"#ffffff","textColorHover":"#ffffff","hasIcon":true,"removeText":true,"iconStyles":{"width":"1em","height":"1em","widthMobile":"0.8em","heightMobile":"0.8em","paddingRight":"0.5em"},"gpDynamicLinkType":"single-post","gpDynamicSource":"previous-post"} --\x3e \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"18430adf","isGrid":true,"gridId":"7bdd6853","backgroundColor":"#ffffff","isDynamic":true,"blockVersion":4,"position":"relative","zindex":2,"sizing":{"width":"25%","widthTablet":"50%","widthMobile":"50%","height":"100%","maxWidth":""},"typography":{"textAlign":"center"},"spacing":{"paddingTop":"30px","paddingRight":"30px","paddingBottom":"30px","paddingLeft":"30px","marginRight":"10px","marginRightTablet":"0px","paddingTopMobile":"10px","paddingRightMobile":"10px","paddingBottomMobile":"10px","paddingLeftMobile":"10px","marginRightMobile":"0px"},"paddingSyncUnits":true,"borders":{"borderTopRightRadius":"10px","borderBottomRightRadius":"10px","borderBottomRightRadiusTablet":"0px","borderTopRightRadiusMobile":"5px","borderBottomRightRadiusMobile":"0px"},"gpDynamicImageBg":"featured-image","gpDynamicSource":"previous-post","gpRemoveContainerCondition":"no-previous-post"} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"2acc62a4","element":"h3","blockVersion":3,"typography":{"fontSize":"25px","textAlign":"left","fontSizeMobile":"17px"},"spacing":{"paddingTop":"10px","paddingRight":"10px","paddingBottom":"10px","paddingLeft":"10px","marginBottom":"0em","marginLeft":"-4em","marginLeftMobile":"-3em"},"paddingSyncUnits":true,"borders":{"borderBottomLeftRadius":"10px","borderTopLeftRadius":"10px","borderTopRightRadiusMobile":"5px","borderBottomRightRadiusMobile":"5px","borderBottomLeftRadiusMobile":"5px","borderTopLeftRadiusMobile":"5px"},"backgroundColor":"#ffffff","textColor":"#000000","linkColor":"#000000","gpDynamicTextType":"title","gpDynamicLinkType":"single-post","gpDynamicTextReplace":"Hello World","gpDynamicSource":"previous-post"} --\x3eAuthor Name
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"759ebd2f","element":"p","blockVersion":3,"spacing":{"marginBottom":"0px"},"gpDynamicTextType":"post-date","gpDynamicTextReplace":"Date","gpDynamicDateUpdated":true} --\x3eDate
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e',meta:[{key:"_generate_post_meta_location",value:"after-post-title"},{key:"_generate_disable_primary_post_meta",value:!0}]},basic_3:{label:(0,i._x)("Term buttons","label","gp-premium"),thumbnail:"post-meta-term-buttons.jpg",content:'\x3c!-- wp:generateblocks/container {"uniqueId":"7134d7c2","isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"row","alignItems":"center","columnGap":"10px","sizing":{"height":"","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"},"paddingSyncUnits":true} --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"e378fc0b","hasUrl":true,"blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"fontSize":"13px","textAlign":"center"},"fontSize":"","spacing":{"paddingTop":"10px","paddingRight":"10px","paddingBottom":"10px","paddingLeft":"10px","marginTop":"","marginRight":"","marginBottom":"","marginLeft":""},"borders":{"borderTopRightRadius":"","borderBottomRightRadius":"","borderBottomLeftRadius":"","borderTopLeftRadius":""},"backgroundColor":"#000000","backgroundColorHover":"#222222","textColor":"#ffffff","textColorHover":"#ffffff","className":"dynamic-term-class","gpDynamicTextType":"terms","gpDynamicLinkType":"term-archives","gpDynamicTextReplace":"Terms","gpDynamicTextTaxonomy":"category"} --\x3e Terms \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- /wp:generateblocks/container --\x3e',meta:[{key:"_generate_post_meta_location",value:"before-post-title"},{key:"_generate_disable_primary_post_meta",value:!1}]}},V={template_1:{label:(0,i._x)("Full footer 1","label","gp-premium"),thumbnail:"site-footer-full-1.jpg",content:'\x3c!-- wp:generateblocks/container {"uniqueId":"73cd57e1","backgroundColor":"#1b1b42","shapeDividers":[],"isDynamic":true,"blockVersion":4,"sizing":{"height":"","maxWidth":""},"spacing":{"paddingTop":"140px","paddingRight":"30px","paddingBottom":"60px","paddingLeft":"30px"}} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"7d9550dd","isDynamic":true,"blockVersion":4,"sizing":{"maxWidth":""},"useGlobalMaxWidth":true,"spacing":{"marginRight":"auto","marginLeft":"auto"}} --\x3e \x3c!-- wp:generateblocks/grid {"uniqueId":"b76f312f","columns":3,"horizontalGap":80,"verticalAlignment":"center","verticalGapTablet":40,"isDynamic":true,"blockVersion":3,"useLegacyRowGap":true} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"53cb46e2","isGrid":true,"gridId":"b76f312f","isDynamic":true,"blockVersion":4,"sizing":{"width":"60%","widthTablet":"100%","widthMobile":"100%","height":"100%","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"}} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"aa19f1fb","element":"h3","blockVersion":3,"textColor":"#ffffff"} --\x3eSemper blandit suspendisse faucibus metus lobortis morbi magna vivamus per risus fermentum dapibus imperdiet praesent magnis.
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"529d5dda","hasUrl":true,"blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"fontWeight":"600","textAlign":"center"},"spacing":{"paddingTop":"10px","paddingRight":"20px","paddingBottom":"10px","paddingLeft":"20px","marginRight":"20px","marginBottomMobile":"20px"},"borders":{"borderTopWidth":"3px","borderTopStyle":"solid","borderTopColor":"#ffffff","borderTopColorHover":"rgba(242, 245, 250, 0.8)","borderRightWidth":"3px","borderRightStyle":"solid","borderRightColor":"#ffffff","borderRightColorHover":"rgba(242, 245, 250, 0.8)","borderBottomWidth":"3px","borderBottomStyle":"solid","borderBottomColor":"#ffffff","borderBottomColorHover":"rgba(242, 245, 250, 0.8)","borderLeftWidth":"3px","borderLeftStyle":"solid","borderLeftColor":"#ffffff","borderLeftColorHover":"rgba(242, 245, 250, 0.8)","borderTopRightRadius":"2px","borderBottomRightRadius":"2px","borderBottomLeftRadius":"2px","borderTopLeftRadius":"2px"},"backgroundColorHover":"#6212b3","backgroundColorHoverOpacity":0,"textColor":"#ffffff","textColorHover":"#f2f5fa"} --\x3e Contact Us \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"e1bd60bb","isGrid":true,"gridId":"b76f312f","removeVerticalGapTablet":true,"isDynamic":true,"blockVersion":4,"sizing":{"width":"20%","widthTablet":"50%","widthMobile":"100%","height":"100%","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"}} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"37420255","element":"p","blockVersion":3,"textColor":"#ffffff"} --\x3eCompany Name
Address Here
Address Here
+1 000 000 0000
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"c762d353","isGrid":true,"gridId":"b76f312f","removeVerticalGapTablet":true,"removeVerticalGapMobile":true,"isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"row","columnGap":"10px","sizing":{"width":"20%","widthTablet":"50%","widthMobile":"100%","height":"100%","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"}} --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"13c371f8","hasUrl":true,"ariaLabel":"instagram link","blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"textAlign":"center"},"spacing":{"paddingTop":"6px","paddingRight":"6px","paddingBottom":"6px","paddingLeft":"6px","marginRight":""},"borders":{"borderTopWidth":"2px","borderTopStyle":"solid","borderTopColor":"#ffffff","borderTopColorHover":"#f2f5fa","borderRightWidth":"2px","borderRightStyle":"solid","borderRightColor":"#ffffff","borderRightColorHover":"#f2f5fa","borderBottomWidth":"2px","borderBottomStyle":"solid","borderBottomColor":"#ffffff","borderBottomColorHover":"#f2f5fa","borderLeftWidth":"2px","borderLeftStyle":"solid","borderLeftColor":"#ffffff","borderLeftColorHover":"#f2f5fa","borderTopRightRadius":"50px","borderBottomRightRadius":"50px","borderBottomLeftRadius":"50px","borderTopLeftRadius":"50px"},"backgroundColorHover":"#222222","textColor":"#ffffff","textColorHover":"#f2f5fa","hasIcon":true,"removeText":true,"iconStyles":{"width":"0.8em","height":"0.8em","paddingRight":"0.5em"}} --\x3e \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"926332bd","hasUrl":true,"ariaLabel":"twitter link","blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"textAlign":"center"},"spacing":{"paddingTop":"6px","paddingRight":"6px","paddingBottom":"6px","paddingLeft":"6px","marginRight":""},"borders":{"borderTopWidth":"2px","borderTopStyle":"solid","borderTopColor":"#ffffff","borderTopColorHover":"#f2f5fa","borderRightWidth":"2px","borderRightStyle":"solid","borderRightColor":"#ffffff","borderRightColorHover":"#f2f5fa","borderBottomWidth":"2px","borderBottomStyle":"solid","borderBottomColor":"#ffffff","borderBottomColorHover":"#f2f5fa","borderLeftWidth":"2px","borderLeftStyle":"solid","borderLeftColor":"#ffffff","borderLeftColorHover":"#f2f5fa","borderTopRightRadius":"50px","borderBottomRightRadius":"50px","borderBottomLeftRadius":"50px","borderTopLeftRadius":"50px"},"backgroundColorHover":"#222222","textColor":"#ffffff","textColorHover":"#f2f5fa","hasIcon":true,"removeText":true,"iconStyles":{"width":"0.8em","height":"0.8em","paddingRight":"0.5em"}} --\x3e \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"d957854e","hasUrl":true,"ariaLabel":"facebook link","blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"textAlign":"center"},"spacing":{"paddingTop":"6px","paddingRight":"6px","paddingBottom":"6px","paddingLeft":"6px"},"borders":{"borderTopWidth":"2px","borderTopStyle":"solid","borderTopColor":"#ffffff","borderTopColorHover":"#f2f5fa","borderRightWidth":"2px","borderRightStyle":"solid","borderRightColor":"#ffffff","borderRightColorHover":"#f2f5fa","borderBottomWidth":"2px","borderBottomStyle":"solid","borderBottomColor":"#ffffff","borderBottomColorHover":"#f2f5fa","borderLeftWidth":"2px","borderLeftStyle":"solid","borderLeftColor":"#ffffff","borderLeftColorHover":"#f2f5fa","borderTopRightRadius":"50px","borderBottomRightRadius":"50px","borderBottomLeftRadius":"50px","borderTopLeftRadius":"50px"},"backgroundColorHover":"#222222","textColor":"#ffffff","textColorHover":"#f2f5fa","hasIcon":true,"removeText":true,"iconStyles":{"width":"0.8em","height":"0.8em","paddingRight":"0.5em"}} --\x3e \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/grid --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"0f87c806","isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"row","flexDirectionMobile":"column-reverse","alignItems":"center","justifyContent":"space-between","rowGapMobile":"20px","sizing":{"height":"","maxWidth":""},"spacing":{"paddingTop":"60px","paddingRight":"0px","paddingBottom":"60px","paddingLeft":"0px","marginTop":"60px"},"borders":{"borderTopWidth":"1px","borderTopStyle":"solid","borderTopColor":"#ffffff"}} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"e6861bde","isDynamic":true,"blockVersion":4,"sizing":{"width":"","widthMobile":"100%","height":"","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"}} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"97c10964","element":"p","blockVersion":3,"typography":{"fontSize":"17px"},"spacing":{"marginBottom":"0px"},"textColor":"#ffffff"} --\x3e© Company Name
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"7c528044","isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"row","flexDirectionMobile":"column","alignItems":"center","alignItemsMobile":"flex-start","columnGap":"20px","rowGapMobile":"10px","sizing":{"width":"","widthMobile":"100%","height":"","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"}} --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"907cc664","hasUrl":true,"blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"fontSize":"17px","textAlign":"center"},"fontSize":"","spacing":{"marginRight":""},"textColor":"#ffffff","textColorHover":"#f2f5fa"} --\x3e Privacy Policy \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"a6a340bc","hasUrl":true,"blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"fontSize":"17px","textAlign":"center"},"fontSize":"","textColor":"#ffffff","textColorHover":"#f2f5fa"} --\x3e Terms of Service \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e'},template_2:{label:(0,i._x)("Full footer 2","label","gp-premium"),thumbnail:"site-footer-full-2.jpg",content:'\x3c!-- wp:generateblocks/container {"uniqueId":"e224c1dd","backgroundColor":"#fafbfc","isDynamic":true,"blockVersion":4,"sizing":{"height":"","maxWidth":""},"spacing":{"paddingTop":"80px","paddingRight":"20px","paddingBottom":"80px","paddingLeft":"20px"}} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"0836612c","isDynamic":true,"blockVersion":4,"sizing":{"maxWidth":""},"useGlobalMaxWidth":true,"spacing":{"marginRight":"auto","marginLeft":"auto"}} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"34307d45","element":"p","blockVersion":3,"typography":{"fontSize":"14px","letterSpacing":"0.3em","fontWeight":"bold","textTransform":"uppercase","textAlign":"center"},"spacing":{"marginTop":"10px"},"textColor":"#2e3d4d"} --\x3eYour Company Name
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"4068688a","isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"row","flexDirectionMobile":"column","alignItems":"center","rowGapMobile":"20px","sizing":{"height":"","maxWidth":""},"spacing":{"paddingTop":"60px","paddingRight":"20px","paddingBottom":"60px","paddingLeft":"20px","marginTop":"60px","marginBottom":"60px"},"borders":{"borderTopWidth":"1px","borderTopStyle":"solid","borderTopColor":"#5c7a99","borderBottomWidth":"1px","borderBottomStyle":"solid","borderBottomColor":"#5c7a99"}} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"12d457ad","isDynamic":true,"blockVersion":4,"sizing":{"width":"33.33%","widthMobile":"100%","height":"","maxWidth":""},"typography":{"textAlign":"center"},"spacing":{"paddingTop":"0px","paddingRight":"20px","paddingBottom":"0px","paddingLeft":"20px"}} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"8818b435","element":"p","blockVersion":3,"typography":{"fontSize":"13px","letterSpacing":"0.2em","fontWeight":"bold","textTransform":"uppercase"},"spacing":{"marginBottom":"0px"}} --\x3ePH +1 000 000 0000
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"68ec175a","isDynamic":true,"blockVersion":4,"sizing":{"width":"33.33%","widthMobile":"100%","height":"","maxWidth":""},"typography":{"textAlign":"center"},"spacing":{"paddingTop":"0px","paddingRight":"20px","paddingBottom":"0px","paddingLeft":"20px"},"borders":{"borderRightWidth":"1px","borderRightStyle":"solid","borderRightColor":"#5c7a99","borderLeftWidth":"1px","borderLeftStyle":"solid","borderLeftColor":"#5c7a99","borderTopWidthMobile":"0px","borderTopStyleMobile":"solid","borderTopColorMobile":"#5c7a99","borderRightWidthMobile":"0px","borderRightStyleMobile":"solid","borderRightColorMobile":"#5c7a99","borderBottomWidthMobile":"0px","borderBottomStyleMobile":"solid","borderBottomColorMobile":"#5c7a99","borderLeftWidthMobile":"0px","borderLeftStyleMobile":"solid","borderLeftColorMobile":"#5c7a99"}} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"cf4dcfab","element":"p","blockVersion":3,"typography":{"fontSize":"13px","letterSpacing":"0.2em","fontWeight":"bold","textTransform":"uppercase"},"spacing":{"marginBottom":"0px"}} --\x3e24 M Drive
East Hampton, NY 11937
© Your Copyright Message
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"b706d851","removeVerticalGapMobile":true,"isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"row","alignItems":"center","justifyContent":"flex-end","justifyContentMobile":"center","columnGap":"20px","rowGap":"10px","sizing":{"width":"50%","widthMobile":"100%","height":"","maxWidth":""},"typography":{},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"}} --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"373aae0d","hasUrl":false,"blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"fontSize":"12px","letterSpacing":"0.2em","fontWeight":"bold","textTransform":"uppercase","textAlign":"center"},"fontSize":"","spacing":{"marginRight":""},"textColor":"#2e3d4d","textColorHover":"#5c7a99"} --\x3e \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"3cd1cf71","hasUrl":false,"blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"fontSize":"12px","letterSpacing":"0.2em","fontWeight":"bold","textTransform":"uppercase","textAlign":"center"},"fontSize":"","textColor":"#2e3d4d","textColorHover":"#5c7a99"} --\x3e \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e'}},q={template_1:{label:(0,i._x)("Basic layout with term buttons","label","gp-premium"),thumbnail:"content-template-basic.jpg",content:'\x3c!-- wp:generateblocks/container {"uniqueId":"d2cafe96","isDynamic":true,"blockVersion":4,"sizing":{"height":"","maxWidth":""},"spacing":{"paddingTop":"","paddingRight":"","paddingBottom":"","paddingLeft":""},"paddingSyncUnits":true} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"75c01790","isDynamic":true,"blockVersion":4} --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"38620841","hasUrl":true,"blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"fontSize":"13px","textAlign":"center"},"fontSize":"","spacing":{"paddingTop":"5px","paddingRight":"10px","paddingBottom":"5px","paddingLeft":"10px"},"backgroundColor":"#000000","backgroundColorHover":"#222222","textColor":"#ffffff","textColorHover":"#ffffff","className":"dynamic-term-class","gpDynamicTextType":"terms","gpDynamicLinkType":"term-archives","gpDynamicTextReplace":"Terms","gpDynamicTextTaxonomy":"category"} --\x3e Terms \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"f593ba8c","blockVersion":3,"typography":{"fontWeight":"bold"},"spacing":{"marginBottom":"30px"},"linkColor":"#000000","linkColorHover":"#858585","gpDynamicTextType":"title","gpDynamicLinkType":"single-post","gpDynamicTextReplace":"Post Title"} --\x3eAuthor name
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"ec93a944","isDynamic":true,"blockVersion":4,"sizing":{"width":"50%","widthMobile":"50%","height":"","maxWidth":""},"typography":{"textAlign":"right"},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"}} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"af8af68e","element":"p","blockVersion":3,"spacing":{"marginBottom":"0px"},"gpDynamicTextType":"post-date","gpDynamicTextReplace":"Post date","gpDynamicDateUpdated":true} --\x3ePost date
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"b70b46a6","isDynamic":true,"blockVersion":4,"sizing":{"height":"","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px","marginTop":"30px","marginBottom":"30px"},"paddingSyncUnits":true} --\x3e \x3c!-- wp:generatepress/dynamic-image {"imageType":"featured-image","imageSize":"medium_large","linkTo":"single-post"} /--\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generatepress/dynamic-content {"contentType":"post-excerpt"} /--\x3e \x3c!-- /wp:generateblocks/container --\x3e',meta:[{key:"_generate_block_element_editor_width_unit",value:"px"},{key:"_generate_block_element_editor_width",value:"750"},{key:"_generate_use_theme_post_container",value:!0}]},template_2:{label:(0,i._x)("Layout with offset content","label","gp-premium"),thumbnail:"content-template-offset.jpg",content:'\x3c!-- wp:generatepress/dynamic-image {"imageType":"featured-image","imageSize":"large","linkTo":"single-post"} /--\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"05e7d83e","backgroundColor":"#ffffff","isDynamic":true,"blockVersion":4,"position":"relative","zindex":1,"sizing":{"height":"","maxWidth":""},"spacing":{"paddingTop":"20px","paddingRight":"20px","paddingBottom":"20px","paddingLeft":"20px","marginTop":"-65px","marginRight":"40px","marginBottom":"20px","marginLeft":"0px"},"paddingSyncUnits":true} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"83898f1c","element":"p","blockVersion":3,"typography":{"fontSize":"14px","fontWeight":"700","textTransform":"uppercase"},"spacing":{"marginBottom":"20px"},"linkColor":"#000000","linkColorHover":"#abb8c3","className":"dynamic-term-class","gpDynamicTextType":"terms","gpDynamicLinkType":"term-archives","gpDynamicTextReplace":"Category","gpDynamicTextTaxonomy":"category"} --\x3eCategory
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"98a0e67b","blockVersion":3,"typography":{"fontSize":"28px"},"gpDynamicTextType":"title","gpDynamicLinkType":"single-post","gpDynamicTextReplace":"Title"} --\x3ePost author name
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"dd34513e","element":"p","blockVersion":3,"typography":{"fontSize":"12px"},"spacing":{"marginRight":"10px","marginBottom":"0px"},"borders":{"borderBottomWidth":"0px","borderBottomStyle":"solid"},"gpDynamicTextType":"post-date","gpDynamicTextReplace":"Date","gpDynamicDateUpdated":true} --\x3eDate
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"6d144082","verticalAlignment":"center","isDynamic":true,"blockVersion":4,"sizing":{"width":"33.33%","widthMobile":"33.33%","height":"","maxWidth":""},"typography":{"textAlign":"right"},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px","marginTop":"15px"},"gpInlinePostMetaJustify":"flex-end"} --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"7c89fc64","hasUrl":true,"blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"fontWeight":"700","textTransform":"uppercase","textAlign":"center"},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"},"textColor":"#000000","textColorHover":"#abb8c3","gpDynamicLinkType":"single-post"} --\x3e More \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e',meta:[{key:"_generate_block_element_editor_width_unit",value:"px"},{key:"_generate_block_element_editor_width",value:"500"},{key:"_generate_use_theme_post_container",value:!1}]},template_3:{label:(0,i._x)("Layout with featured image overlay","label","gp-premim"),thumbnail:"content-template-overlay.jpg",content:'\x3c!-- wp:generateblocks/container {"uniqueId":"99e0f8fe","gradient":true,"gradientDirection":180,"gradientColorOne":"#000000","gradientColorOneOpacity":0.62,"gradientColorTwo":"#000000","gradientColorTwoOpacity":0,"gradientSelector":"pseudo-element","textColor":"#ffffff","linkColor":"#ffffff","linkColorHover":"#ffffff","bgImage":{"id":"","image":{"url":"#dynamic-background-image"}},"innerZindex":1,"isDynamic":true,"blockVersion":4,"position":"relative","overflowX":"hidden","overflowY":"hidden","sizing":{"minHeight":"420px","height":"","maxWidth":""},"spacing":{"paddingTop":"20px","paddingRight":"20px","paddingBottom":"20px","paddingLeft":"20px"},"borders":{"borderTopRightRadius":"12px","borderBottomRightRadius":"12px","borderBottomLeftRadius":"12px","borderTopLeftRadius":"12px"},"gpDynamicImageBg":"featured-image"} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"95ce0971","isDynamic":true,"blockVersion":4,"position":"relative","zindex":1,"sizing":{"maxWidth":""},"useGlobalMaxWidth":true,"spacing":{"marginRight":"auto","marginLeft":"auto"}} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"864271b1","isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"row","alignItems":"center","justifyContent":"space-between","columnGap":"5px","rowGap":"5px","sizing":{"height":"","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px","marginBottom":"10px"},"paddingSyncUnits":true} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"bc0ec4fa","element":"p","blockVersion":3,"typography":{"fontSize":"13px","fontWeight":"700","textTransform":"uppercase"},"spacing":{"marginRight":"10px","marginBottom":"0px"},"className":"dynamic-term-class","gpDynamicTextType":"terms","gpDynamicTextReplace":"Category","gpDynamicTextTaxonomy":"category","gpDynamicTextTaxonomySeparator":" / "} --\x3eCategory
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"5e2dac4c","element":"p","blockVersion":3,"display":"flex","alignItems":"center","justifyContent":"flex-end","typography":{"fontSize":"12px","textAlign":"right"},"spacing":{"marginBottom":"0px"},"hasIcon":true,"iconStyles":{"width":"1.4em","height":"1.4em","paddingRight":"0.5em"},"gpDynamicTextType":"comments-number","gpDynamicTextReplace":"COMMENTS","gpDynamicNoCommentsText":"0","gpDynamicSingleCommentText":"1","gpDynamicMultipleCommentsText":"%"} --\x3eCOMMENTS
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"b1e898af","blockVersion":3,"typography":{"fontSize":"24px"},"marginUnit":"%","gpDynamicTextType":"title","gpDynamicLinkType":"single-post","gpDynamicTextReplace":"Title"} --\x3ePost date
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"a8ee15fd","blockVersion":3,"typography":{"fontSize":"30px"},"spacing":{"marginBottom":"15px"},"gpDynamicTextType":"title","gpDynamicLinkType":"single-post","gpDynamicTextReplace":"Hello World"} --\x3eTerms
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"29491daa","blockVersion":3,"typography":{"fontSize":"30px"},"spacing":{"marginBottom":"15px"},"gpDynamicTextType":"title","gpDynamicLinkType":"single-post","gpDynamicTextReplace":"Hello World"} --\x3ePost date
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"9bb8c373","isDynamic":true,"blockVersion":4,"sizing":{"width":"50%","widthMobile":"50%","height":"","maxWidth":""},"typography":{"textAlign":"right"},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"}} --\x3e \x3c!-- wp:generateblocks/button {"uniqueId":"0fcad1cd","hasUrl":true,"blockVersion":4,"display":"inline-flex","alignItems":"center","justifyContent":"center","typography":{"textTransform":"uppercase","textAlign":"center"},"spacing":{"paddingTop":"8px","paddingRight":"12px","paddingBottom":"8px","paddingLeft":"12px"},"borders":{"borderTopWidth":"2px","borderTopStyle":"solid","borderTopColor":"#0693e3","borderTopColorHover":"#222222","borderRightWidth":"2px","borderRightStyle":"solid","borderRightColor":"#0693e3","borderRightColorHover":"#222222","borderBottomWidth":"2px","borderBottomStyle":"solid","borderBottomColor":"#0693e3","borderBottomColorHover":"#222222","borderLeftWidth":"2px","borderLeftStyle":"solid","borderLeftColor":"#0693e3","borderLeftColorHover":"#222222","borderTopRightRadius":"2px","borderBottomRightRadius":"2px","borderBottomLeftRadius":"2px","borderTopLeftRadius":"2px"},"backgroundColorHover":"#222222","textColor":"#0693e3","textColorHover":"#ffffff","gpDynamicLinkType":"single-post"} --\x3e Read more \x3c!-- /wp:generateblocks/button --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e',meta:[{key:"_generate_block_element_editor_width_unit",value:"px"},{key:"_generate_block_element_editor_width",value:"500"},{key:"_generate_use_theme_post_container",value:!1}]},template_7:{label:(0,i._x)("Landscape layout","label","gp-premium"),thumbnail:"content-template-landscape.jpg",content:'\x3c!-- wp:generateblocks/container {"uniqueId":"918d68ce","isDynamic":true,"blockVersion":4,"sizing":{"height":"","maxWidth":""},"spacing":{"paddingTop":"","paddingRight":"","paddingBottom":"","paddingLeft":""},"paddingSyncUnits":true} --\x3e \x3c!-- wp:generateblocks/grid {"uniqueId":"ae18e4a9","columns":2,"horizontalGap":30,"verticalGapMobile":10,"isDynamic":true,"blockVersion":3,"useLegacyRowGap":true} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"ff15641f","isGrid":true,"gridId":"ae18e4a9","isDynamic":true,"blockVersion":4,"sizing":{"width":"40%","widthTablet":"40%","widthMobile":"100%","height":"100%","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"},"gpRemoveContainerCondition":"no-featured-image"} --\x3e \x3c!-- wp:generatepress/dynamic-image {"imageType":"featured-image","imageSize":"medium_large","linkTo":"single-post"} /--\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"64596747","isGrid":true,"gridId":"ae18e4a9","verticalAlignment":"center","isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"column","justifyContent":"center","sizing":{"width":"60%","widthTablet":"60%","widthMobile":"100%","height":"100%","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"20px","paddingBottom":"10px","paddingLeft":"0px","paddingTopMobile":"10px","paddingRightMobile":"10px","paddingBottomMobile":"10px","paddingLeftMobile":"10px"}} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"ce3f6f48","isDynamic":true,"blockVersion":4,"display":"flex","alignItems":"center","sizing":{"height":"","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px","marginBottom":"10px"}} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"fdbba1f9","element":"p","blockVersion":3,"typography":{"fontSize":"14px","fontWeight":"900","textTransform":"uppercase"},"spacing":{"paddingRight":"10px","marginRight":"10px","marginBottom":"0px"},"borders":{"borderRightWidth":"1px","borderRightStyle":"solid"},"className":"dynamic-term-class","gpDynamicTextType":"terms","gpDynamicTextReplace":"Category","gpDynamicTextTaxonomy":"category"} --\x3eCategory
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"6df4d39e","element":"p","blockVersion":3,"typography":{"fontSize":"14px"},"spacing":{"marginRight":"10px","marginBottom":"0px"},"gpDynamicTextType":"post-date","gpDynamicTextReplace":"Date","gpDynamicDateUpdated":true} --\x3eDate
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"84923e14","blockVersion":3,"typography":{"fontSize":"28px"},"spacing":{"marginBottom":"20px"},"gpDynamicTextType":"title","gpDynamicLinkType":"single-post","gpDynamicTextReplace":"Title"} --\x3eAuthor name
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"dedbe2c8","element":"p","blockVersion":3,"spacing":{"paddingLeft":"20px","marginBottom":"0px","marginLeft":"20px"},"borders":{"borderLeftWidth":"1px","borderLeftStyle":"solid"},"gpDynamicTextType":"post-date","gpDynamicTextReplace":"Post date","gpDynamicDateUpdated":true} --\x3ePost date
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- /wp:generateblocks/container --\x3e',meta:[{key:"_generate_hook",value:"generate_after_header"},{key:"_generate_disable_title",value:!0},{key:"_generate_disable_featured_image",value:!0},{key:"_generate_disable_primary_post_meta",value:!0}]},template_2:{label:(0,i._x)("Single post hero with excerpt","label","gp-premium"),thumbnail:"page-hero-excerpt.jpg",content:'\x3c!-- wp:generateblocks/container {"uniqueId":"70385d72","isDynamic":true,"blockVersion":4,"sizing":{"height":"","maxWidth":""},"spacing":{"paddingTop":"80px","paddingRight":"40px","paddingBottom":"80px","paddingLeft":"40px"}} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"01bfa731","isDynamic":true,"blockVersion":4,"sizing":{"maxWidth":""},"useGlobalMaxWidth":true,"spacing":{"marginRight":"auto","marginLeft":"auto"}} --\x3e \x3c!-- wp:generateblocks/grid {"uniqueId":"5dc55b95","columns":2,"horizontalGap":80,"verticalGap":20,"isDynamic":true,"blockVersion":3,"useLegacyRowGap":true} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"579e5b87","isGrid":true,"gridId":"5dc55b95","verticalAlignment":"center","isDynamic":true,"blockVersion":4,"display":"flex","flexDirection":"column","justifyContent":"center","sizing":{"width":"45%","widthTablet":"60%","widthMobile":"100%","height":"100%","maxWidth":""},"typography":{"fontSize":"14px"},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px"}} --\x3e \x3c!-- wp:generateblocks/container {"uniqueId":"d909e043","isDynamic":true,"blockVersion":4,"display":"flex","alignItems":"center","sizing":{"height":"","maxWidth":""},"spacing":{"paddingTop":"0px","paddingRight":"0px","paddingBottom":"0px","paddingLeft":"0px","marginBottom":"10px"},"paddingSyncUnits":true} --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"9fdb86dc","element":"p","blockVersion":3,"typography":{"fontSize":"14px","fontWeight":"900","textTransform":"uppercase"},"spacing":{"paddingRight":"10px","marginRight":"10px","marginBottom":"0px"},"borders":{"borderRightWidth":"1px","borderRightStyle":"solid"},"textColor":"#000000","linkColor":"#000000","className":"dynamic-term-class","gpDynamicTextType":"terms","gpDynamicLinkType":"term-archives","gpDynamicTextReplace":"Category","gpDynamicTextTaxonomy":"category"} --\x3eCategory
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"1ee4cbcf","element":"p","blockVersion":3,"typography":{"fontSize":"14px"},"spacing":{"marginRight":"10px","marginBottom":"0px"},"gpDynamicTextType":"post-date","gpDynamicTextReplace":"Date","gpDynamicDateUpdated":true} --\x3eDate
\x3c!-- /wp:generateblocks/headline --\x3e \x3c!-- /wp:generateblocks/container --\x3e \x3c!-- wp:generateblocks/headline {"uniqueId":"56c7eb13","blockVersion":3,"spacing":{"marginBottom":"10px"},"gpDynamicTextType":"title","gpDynamicTextReplace":"Title"} --\x3e%s
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed pulvinar ligula augue, quis bibendum tellus scelerisque venenatis. Pellentesque porta nisi mi. In hac habitasse platea dictumst. Etiam risus elit, molestie non volutpat ac, pellentesque sed eros. Nunc leo odio, sodales non tortor at, porttitor posuere dui.
| + + | ++ + | +
| + + | ++ + | +
| + + | ++ /> + | +
| + + | ++ /> + | +
| + + | ++ /> + | +
| + + | ++ + DISALLOW_FILE_EDIT' + ); + ?> + + /> + + | +
| + + | ++ + | +
| + + ? + | ++ + | +
| + + | ++ + | +
| + + | ++ + | +
| + + | ++ + | +
| + + | ++ /> + | +
| + + | ++ + | +
| + + | +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
| + + | ++ + | +
| + + | +
+ >
+
+
+
+
+
+ %s',
+ esc_html__( 'Change', 'gp-premium' )
+ );
+
+ printf(
+ ' %s',
+ esc_html__( 'Remove', 'gp-premium' )
+ );
+ ?>
+ >
+ %s',
+ sprintf(
+ /* translators: Upload Custom Image or Fallback image */
+ esc_html__( 'Upload %s', 'gp-premium' ),
+ '' . esc_html( $image_text ) . ''
+ )
+ );
+ ?>
+
+ |
+
| + + | ++ + | +
| + + | ++ /> + | +
| + + ? + | ++ /> + | +
| + + ? + | ++ /> + | +
| + + | ++ + | +
| + + | ++ + | +
| + + | ++ + | +
| + + | ++ + | +
| + + ? + | ++ + | +
| + + ? + | +
+
+
+
+
+
+
+
+
+
+ px
+
+ |
+
| + + | ++ + | +
| + + | ++ + | +
| + + | ++ + | +
| + + | +
+
+
+
+ ';
+ }
+ ?>
+
+
+ />
+
+
+ |
+
| + + | +
+
+
+
+ ';
+ }
+ ?>
+
+
+ />
+
+
+ |
+
| + + | +
+
+
+
+ ';
+ }
+ ?>
+
+
+ />
+
+
+ |
+
| + + | +
+
+
+
+ ';
+ }
+ ?>
+
+
+ />
+
+
+ |
+
| + + | ++ + | +
| + + | ++ /> + | +
| + + | ++ + | +
| + + | ++ + | +
| + + | ++ + | +
| + + | ++ + | +
| + + | ++ + | +
| + + | ++ + | +
| + + | +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
| + + | +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
| + + | ++ /> + | +
| + + | ++ /> + | +
| + + | ++ /> + | +
| + + | ++ /> + | +
| + + | ++ /> + | +
| + + | ++ /> + | +
| + + | ++ /> + | +
| + + | ++ /> + | +
| + + | +
+
+
+
+
+
+
+
+
+
+
+
+ |
+
| + + | ++ + px + | +
+ +
+ + ++ +
+ + ++ +
+ + ++ +
+ + ++ +
+ _x( 'Elements', 'Post Type General Name', 'gp-premium' ), + 'singular_name' => _x( 'Element', 'Post Type Singular Name', 'gp-premium' ), + 'menu_name' => __( 'Elements', 'gp-premium' ), + 'all_items' => __( 'All Elements', 'gp-premium' ), + 'add_new' => __( 'Add New Element', 'gp-premium' ), + 'add_new_item' => __( 'Add New Element', 'gp-premium' ), + 'new_item' => __( 'New Element', 'gp-premium' ), + 'edit_item' => __( 'Edit Element', 'gp-premium' ), + 'update_item' => __( 'Update Element', 'gp-premium' ), + 'search_items' => __( 'Search Element', 'gp-premium' ), + 'featured_image' => __( 'Background Image', 'gp-premium' ), + 'set_featured_image' => __( 'Set background image', 'gp-premium' ), + 'remove_featured_image' => __( 'Remove background image', 'gp-premium' ), + 'item_published' => __( 'Element published.', 'gp-premium' ), + 'item_updated' => __( 'Element updated.', 'gp-premium' ), + 'item_scheduled' => __( 'Element scheduled.', 'gp-premium' ), + 'item_reverted_to_draft' => __( 'Element reverted to draft.', 'gp-premium' ), + ); + + $args = array( + 'labels' => $labels, + 'supports' => array( 'title', 'editor', 'thumbnail', 'custom-fields', 'page-attributes', 'revisions' ), + 'hierarchical' => true, + 'public' => false, + 'show_ui' => true, + 'show_in_menu' => false, + 'can_export' => true, + 'has_archive' => false, + 'exclude_from_search' => true, + 'show_in_rest' => true, + ); + + register_post_type( 'gp_elements', $args ); + } + + /** + * Disable editor and show_in_rest support for non-Block Elements. + * + * @since 1.11.0 + * @param array $args The existing args. + * @param string $post_type The current post type. + */ + public function set_standard_element( $args, $post_type ) { + if ( 'gp_elements' === $post_type ) { + $post_id = false; + $type = false; + + if ( isset( $_GET['post'] ) ) { // phpcs:ignore -- No processing happening. + $post_id = absint( $_GET['post'] ); // phpcs:ignore -- No processing happening. + } + + if ( $post_id ) { + $type = get_post_meta( $post_id, '_generate_element_type', true ); + } elseif ( isset( $_GET['element_type'] ) ) { // phpcs:ignore -- No processing happening. + $type = esc_html( $_GET['element_type'] ); // phpcs:ignore -- No processing happening. + } + + if ( ! $type ) { + return $args; + } + + if ( 'block' !== $type ) { + $args['supports'] = array( 'title', 'thumbnail' ); + $args['show_in_rest'] = false; + $args['hierarchical'] = false; + } + + if ( 'block' === $type ) { + $args['supports'] = array( 'title', 'editor', 'custom-fields', 'page-attributes', 'revisions' ); + } + + if ( 'layout' === $type ) { + $args['labels']['add_new_item'] = __( 'Add New Layout', 'gp-premium' ); + $args['labels']['edit_item'] = __( 'Edit Layout', 'gp-premium' ); + } + + if ( 'hook' === $type ) { + $args['labels']['add_new_item'] = __( 'Add New Hook', 'gp-premium' ); + $args['labels']['edit_item'] = __( 'Edit Hook', 'gp-premium' ); + } + + if ( 'header' === $type ) { + $args['labels']['add_new_item'] = __( 'Add New Header', 'gp-premium' ); + $args['labels']['edit_item'] = __( 'Edit Header', 'gp-premium' ); + } + } + + return $args; + } + + /** + * Register custom post type columns. + * + * @since 1.7 + * + * @param array $columns Existing CPT columns. + * @return array All our CPT columns. + */ + public function register_columns( $columns ) { + $columns['element_type'] = esc_html__( 'Type', 'gp-premium' ); + $columns['location'] = esc_html__( 'Location', 'gp-premium' ); + $columns['exclusions'] = esc_html__( 'Exclusions', 'gp-premium' ); + $columns['users'] = esc_html__( 'Users', 'gp-premium' ); + + $new_columns = array(); + + // Need to do some funky stuff to display these columns before the date. + foreach ( $columns as $key => $value ) { + if ( 'date' === $key ) { + $new_columns['element_type'] = esc_html__( 'Type', 'gp-premium' ); + $new_columns['location'] = esc_html__( 'Location', 'gp-premium' ); + $new_columns['exclusions'] = esc_html__( 'Exclusions', 'gp-premium' ); + $new_columns['users'] = esc_html__( 'Users', 'gp-premium' ); + } + + $new_columns[ $key ] = $value; + } + + return $new_columns; + } + + /** + * Add a filter select input to the admin list. + * + * @since 1.7 + */ + public function build_element_type_filter() { + $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : false; + + if ( ! $screen ) { + return; + } + + if ( ! isset( $screen->post_type ) || 'gp_elements' !== $screen->post_type ) { + return; + } + + $values = array( + 'block' => esc_html__( 'Blocks', 'gp-premium' ), + 'header' => esc_html__( 'Headers', 'gp-premium' ), + 'hook' => esc_html__( 'Hooks', 'gp-premium' ), + 'layout' => esc_html__( 'Layouts', 'gp-premium' ), + ); + + $current_element_type = isset( $_GET['gp_element_type_filter'] ) ? esc_html( $_GET['gp_element_type_filter'] ) : ''; // phpcs:ignore -- No processing happening. + $current_block_type = isset( $_GET['gp_elements_block_type_filter'] ) ? esc_html( $_GET['gp_elements_block_type_filter'] ) : ''; // phpcs:ignore -- No processing happening. + ?> + + + + is_main_query() && '' !== $type ) { + $meta_query[] = array( + 'key' => '_generate_element_type', + 'value' => esc_attr( $type ), + 'compare' => '=', + ); + + $block_type = isset( $_GET['gp_elements_block_type_filter'] ) ? $_GET['gp_elements_block_type_filter'] : ''; // phpcs:ignore -- No processing happening. + + if ( 'block' === $type && '' !== $block_type ) { + $meta_query['relation'] = 'AND'; + + $meta_query[] = array( + 'key' => '_generate_block_type', + 'value' => esc_attr( $block_type ), + 'compare' => '=', + ); + } + + $query->set( 'meta_query', $meta_query ); + } + } + + /** + * Add content to our custom post type columns. + * + * @since 1.7 + * + * @param string $column The name of the column. + * @param int $post_id The ID of the post row. + */ + public function add_columns( $column, $post_id ) { + switch ( $column ) { + case 'element_type': + $type = get_post_meta( $post_id, '_generate_element_type', true ); + $hook_location = get_post_meta( $post_id, '_generate_hook', true ); + + if ( 'block' === $type ) { + echo esc_html__( 'Block', 'gp-premium' ); + + $block_type = get_post_meta( $post_id, '_generate_block_type', true ); + + if ( $block_type ) { + echo ' - ' . esc_html( GeneratePress_Elements_Helper::get_element_type_label( $block_type ) ); + + if ( 'hook' === $block_type && $hook_location ) { + echo 'smooth-scroll class.', 'gp-premium' ),
+ 'section' => 'generate_general_section',
+ )
+ );
+}
diff --git a/wp-content/upgrade-temp-backup/plugins/gp-premium/gp-premium.php b/wp-content/upgrade-temp-backup/plugins/gp-premium/gp-premium.php
new file mode 100644
index 00000000..14974bfa
--- /dev/null
+++ b/wp-content/upgrade-temp-backup/plugins/gp-premium/gp-premium.php
@@ -0,0 +1,309 @@
+=' ) && ! defined( 'GENERATE_DISABLE_SITE_LIBRARY' ) ) {
+ require_once GP_PREMIUM_DIR_PATH . 'site-library/class-site-library-rest.php';
+ require_once GP_PREMIUM_DIR_PATH . 'site-library/class-site-library-helper.php';
+}
+
+if ( is_admin() ) {
+ require_once GP_PREMIUM_DIR_PATH . 'inc/deprecated-admin.php';
+
+ if ( generatepress_is_module_active( 'generate_package_site_library', 'GENERATE_SITE_LIBRARY' ) && version_compare( PHP_VERSION, '5.4', '>=' ) && ! defined( 'GENERATE_DISABLE_SITE_LIBRARY' ) ) {
+ require_once GP_PREMIUM_DIR_PATH . 'site-library/class-site-library.php';
+ }
+}
+
+if ( generatepress_is_module_active( 'generate_package_font_library', 'GENERATE_FONT_LIBRARY' ) ) {
+ require_once GP_PREMIUM_DIR_PATH . 'font-library/class-font-library.php';
+ require_once GP_PREMIUM_DIR_PATH . 'font-library/class-font-library-rest.php';
+ require_once GP_PREMIUM_DIR_PATH . 'font-library/class-font-library-optimize.php';
+ require_once GP_PREMIUM_DIR_PATH . 'font-library/class-font-library-cpt.php';
+}
+
+if ( ! function_exists( 'generate_premium_updater' ) ) {
+ add_action( 'admin_init', 'generate_premium_updater', 0 );
+ /**
+ * Set up the updater
+ **/
+ function generate_premium_updater() {
+ if ( ! class_exists( 'GeneratePress_Premium_Plugin_Updater' ) ) {
+ include GP_PREMIUM_DIR_PATH . 'library/class-plugin-updater.php';
+ }
+
+ $license_key = get_option( 'gen_premium_license_key' );
+
+ $edd_updater = new GeneratePress_Premium_Plugin_Updater(
+ 'https://generatepress.com',
+ __FILE__,
+ array(
+ 'version' => GP_PREMIUM_VERSION,
+ 'license' => trim( $license_key ),
+ 'item_name' => 'GP Premium',
+ 'author' => 'Tom Usborne',
+ 'url' => home_url(),
+ 'beta' => apply_filters( 'generate_premium_beta_tester', false ),
+ )
+ );
+ }
+}
+
+add_filter( 'edd_sl_plugin_updater_api_params', 'generate_premium_set_updater_api_params', 10, 3 );
+/**
+ * Add the GeneratePress version to our updater params.
+ *
+ * @param array $api_params The array of data sent in the request.
+ * @param array $api_data The array of data set up in the class constructor.
+ * @param string $plugin_file The full path and filename of the file.
+ */
+function generate_premium_set_updater_api_params( $api_params, $api_data, $plugin_file ) {
+ /*
+ * Make sure $plugin_file matches your plugin's file path. You should have a constant for this
+ * or can use __FILE__ if this code goes in your plugin's main file.
+ */
+ if ( __FILE__ === $plugin_file ) {
+ // Dynamically retrieve the current version number.
+ $api_params['generatepress_version'] = defined( 'GENERATE_VERSION' ) ? GENERATE_VERSION : '';
+ }
+
+ return $api_params;
+}
+
+if ( ! function_exists( 'generate_premium_setup' ) ) {
+ add_action( 'after_setup_theme', 'generate_premium_setup' );
+ /**
+ * Add useful functions to GP Premium
+ **/
+ function generate_premium_setup() {
+ // This used to be in the theme but the WP.org review team asked for it to be removed.
+ // Not wanting people to have broken shortcodes in their widgets on update, I added it into premium.
+ add_filter( 'widget_text', 'do_shortcode' );
+ }
+}
+
+if ( ! function_exists( 'generate_premium_theme_information' ) ) {
+ add_action( 'admin_notices', 'generate_premium_theme_information' );
+ /**
+ * Checks whether there's a theme update available and lets you know.
+ * Also checks to see if GeneratePress is the active theme. If not, tell them.
+ *
+ * @since 1.2.95
+ **/
+ function generate_premium_theme_information() {
+ $theme = wp_get_theme();
+
+ if ( 'GeneratePress' === $theme->name || 'generatepress' === $theme->template ) {
+
+ // Get our information on updates.
+ // @see https://developer.wordpress.org/reference/functions/wp_prepare_themes_for_js/.
+ $updates = array();
+ if ( current_user_can( 'update_themes' ) ) {
+ $updates_transient = get_site_transient( 'update_themes' );
+ if ( isset( $updates_transient->response ) ) {
+ $updates = $updates_transient->response;
+ }
+ }
+
+ $screen = get_current_screen();
+
+ // If a GeneratePress update exists, and we're not on the themes page.
+ // No need to tell people an update exists on the themes page, WP does that for us.
+ if ( isset( $updates['generatepress'] ) && 'themes' !== $screen->base ) {
+ printf(
+ '%1$s %3$s
+%1$s %2$s
+%1$s %2$s
+ ', + esc_html__( 'DISALLOW_FILE_EDIT is defined. You should also disallow PHP execution in GP Hooks.', 'gp-premium' ), + esc_html__( 'Learn how', 'gp-premium' ) + ); + } + } +} + +if ( ! function_exists( 'generate_hooks_setup' ) ) { + function generate_hooks_setup() { + // Just to verify that we're activated. + } +} + +if ( ! class_exists( 'Generate_Hooks_Settings' ) ) { + class Generate_Hooks_Settings { + private $dir; + private $file; + private $assets_dir; + private $assets_url; + private $settings_base; + private $settings; + + public function __construct( $file ) { + $this->file = $file; + $this->dir = dirname( $this->file ); + $this->assets_dir = trailingslashit( $this->dir ) . 'assets'; + $this->assets_url = esc_url( trailingslashit( plugins_url( '/assets/', $this->file ) ) ); + $this->settings_base = ''; + + // Initialise settings + add_action( 'admin_init', array( $this, 'init' ) ); + + // Register plugin settings + add_action( 'admin_init' , array( $this, 'register_settings' ) ); + + // Add settings page to menu + add_action( 'admin_menu' , array( $this, 'add_menu_item' ) ); + + // Add settings link to plugins page + add_filter( 'plugin_action_links_' . plugin_basename( $this->file ) , array( $this, 'add_settings_link' ) ); + } + + /** + * Initialise settings + * @return void + */ + public function init() { + $this->settings = $this->settings_fields(); + } + + /** + * Add settings page to admin menu + * @return void + */ + public function add_menu_item() { + $page = add_theme_page( __( 'GP Hooks', 'gp-premium' ) , __( 'GP Hooks', 'gp-premium' ) , apply_filters( 'generate_hooks_capability','manage_options' ) , 'gp_hooks_settings' , array( $this, 'settings_page' ) ); + add_action( 'admin_print_styles-' . $page, array( $this, 'settings_assets' ) ); + } + + /** + * Load settings JS & CSS + * @return void + */ + public function settings_assets() { + wp_enqueue_script( 'gp-cookie', $this->assets_url . 'js/jquery.cookie.js', array( 'jquery' ), GENERATE_HOOKS_VERSION ); + wp_enqueue_script( 'gp-hooks', $this->assets_url . 'js/admin.js', array( 'jquery', 'gp-cookie' ), GENERATE_HOOKS_VERSION ); + wp_enqueue_style( 'gp-hooks', $this->assets_url . 'css/hooks.css' ); + } + + /** + * Add settings link to plugin list table + * @param array $links Existing links + * @return array Modified links + */ + public function add_settings_link( $links ) { + $settings_link = '' . __( 'GP Hooks', 'gp-premium' ) . ''; + array_push( $links, $settings_link ); + return $links; + } + + /** + * Build settings fields + * @return array Fields to be displayed on settings page + */ + private function settings_fields() { + + $settings['standard'] = array( + 'title' => '', + 'description' => '', + 'fields' => array( + array( + "name" => __( 'wp_head', 'gp-premium' ), + "id" => 'generate_wp_head', + "type" => 'textarea' + ), + + array( + "name" => __( 'Before Header', 'gp-premium' ), + "id" => 'generate_before_header', + "type" => 'textarea' + ), + + array( + "name" => __( 'Before Header Content', 'gp-premium' ), + "id" => 'generate_before_header_content', + "type" => 'textarea' + ), + + array( + "name" => __( 'After Header Content', 'gp-premium' ), + "id" => 'generate_after_header_content', + "type" => 'textarea' + ), + + array( + "name" => __( 'After Header', 'gp-premium' ), + "id" => 'generate_after_header', + "type" => 'textarea' + ), + + array( + "name" => __( 'Inside Content Container', 'gp-premium' ), + "id" => 'generate_before_main_content', + "type" => 'textarea' + ), + + array( + "name" => __( 'Before Content', 'gp-premium' ), + "id" => 'generate_before_content', + "type" => 'textarea' + ), + + array( + "name" => __( 'After Entry Title', 'gp-premium' ), + "id" => 'generate_after_entry_header', + "type" => 'textarea' + ), + + array( + "name" => __( 'After Content', 'gp-premium' ), + "id" => 'generate_after_content', + "type" => 'textarea' + ), + + array( + "name" => __( 'Before Right Sidebar Content', 'gp-premium' ), + "id" => 'generate_before_right_sidebar_content', + "type" => 'textarea' + ), + + array( + "name" => __( 'After Right Sidebar Content', 'gp-premium' ), + "id" => 'generate_after_right_sidebar_content', + "type" => 'textarea' + ), + + array( + "name" => __( 'Before Left Sidebar Content', 'gp-premium' ), + "id" => 'generate_before_left_sidebar_content', + "type" => 'textarea' + ), + + array( + "name" => __( 'After Left Sidebar Content', 'gp-premium' ), + "id" => 'generate_after_left_sidebar_content', + "type" => 'textarea' + ), + + array( + "name" => __( 'Before Footer', 'gp-premium' ), + "id" => 'generate_before_footer', + "type" => 'textarea' + ), + + array( + "name" => __( 'After Footer Widgets', 'gp-premium' ), + "id" => 'generate_after_footer_widgets', + "type" => 'textarea' + ), + + array( + "name" => __( 'Before Footer Content', 'gp-premium' ), + "id" => 'generate_before_footer_content', + "type" => 'textarea' + ), + + array( + "name" => __( 'After Footer Content', 'gp-premium' ), + "id" => 'generate_after_footer_content', + "type" => 'textarea' + ), + + array( + "name" => __( 'wp_footer', 'gp-premium' ), + "id" => 'generate_wp_footer', + "type" => 'textarea' + ) + ) + ); + + $settings = apply_filters( 'gp_hooks_settings_fields', $settings ); + + return $settings; + } + + /** + * Register plugin settings + * @return void + */ + public function register_settings() { + if ( is_array( $this->settings ) ) { + foreach( $this->settings as $section => $data ) { + + // Add section to page + add_settings_section( $section, $data['title'], array( $this, 'settings_section' ), 'gp_hooks_settings' ); + + foreach( $data['fields'] as $field ) { + + // Sanitizing isn't possible, as hooks allow any HTML, JS or PHP to be added. + // Allowing PHP can be a security issue if you have admin users who you don't trust. + // In that case, you can disable the ability to add PHP in hooks like this: define( 'GENERATE_HOOKS_DISALLOW_PHP', true ); + $validation = ''; + if( isset( $field['callback'] ) ) { + $validation = $field['callback']; + } + + // Register field + $option_name = $this->settings_base . $field['id']; + register_setting( 'gp_hooks_settings', 'generate_hooks', $validation ); + + // Add field to page + add_settings_field( 'generate_hooks[' . $field['id'] . ']', $field['name'], array( $this, 'display_field' ), 'gp_hooks_settings', $section, array( 'field' => $field ) ); + } + } + } + } + + public function settings_section( $section ) { + $html = ''; + echo $html; + } + + /** + * Generate HTML for displaying fields + * @param array $args Field data + * @return void + */ + public function display_field( $args ) { + + $field = $args['field']; + + $html = ''; + + $option_name = $this->settings_base . $field['id']; + $option = get_option( 'generate_hooks' ); + + $data = ''; + if( isset( $option[$option_name] ) ) { + $data = $option[$option_name]; + } elseif( isset( $field['default'] ) ) { + $data = $field['default']; + } + + + switch( $field['type'] ) { + + case 'textarea': + $checked = ''; + $checked2 = ''; + if( isset( $option[$field['id'] . '_php'] ) && 'true' == $option[$field['id'] . '_php'] ){ + $checked = 'checked="checked"'; + } + if( isset( $option[$field['id'] . '_disable'] ) && 'true' == $option[$field['id'] . '_disable'] ){ + $checked2 = 'checked="checked"'; + } + $html .= ''; + + if ( ! defined( 'GENERATE_HOOKS_DISALLOW_PHP' ) ) { + $html .= '
+
+
+
{{{ data.description }}}
+ + <# } #> + json['palette'] = $this->palette; + $this->json['defaultValue'] = $this->setting->default; + $this->json[ 'link' ] = $this->get_link(); + $this->json[ 'show_opacity' ] = $this->show_opacity; + + if ( is_array( $this->json['palette'] ) ) { + $this->json['palette'] = implode( '|', $this->json['palette'] ); + } else { + // Default to true. + $this->json['palette'] = ( false === $this->json['palette'] || 'false' === $this->json['palette'] ) ? 'false' : 'true'; + } + + // Support passing show_opacity as string or boolean. Default to true. + $this->json[ 'show_opacity' ] = ( false === $this->json[ 'show_opacity' ] || 'false' === $this->json[ 'show_opacity' ] ) ? 'false' : 'true'; + } + + /** + * Render the control. + */ + public function render_content() {} + + public function content_template() { + ?> + <# if ( data.label && '' !== data.label ) { #> + {{ data.label }} + <# } #> + + json[ 'position_title' ] = esc_html__( 'left top, x% y%, xpos ypos (px)', 'gp-premium' ); + $this->json[ 'position_placeholder' ] = esc_html__( 'Position', 'gp-premium' ); + + foreach ( $this->settings as $setting_key => $setting_id ) { + $this->json[ $setting_key ] = array( + 'link' => $this->get_link( $setting_key ), + 'value' => $this->value( $setting_key ), + 'default' => isset( $setting_id->default ) ? $setting_id->default : '', + 'id' => isset( $setting_id->id ) ? $setting_id->id : '' + ); + + if ( 'repeat' === $setting_key ) { + $this->json[ $setting_key ]['choices'] = $this->get_repeat_choices(); + } + + if ( 'size' === $setting_key ) { + $this->json[ $setting_key ]['choices'] = $this->get_size_choices(); + } + + if ( 'attachment' === $setting_key ) { + $this->json[ $setting_key ]['choices'] = $this->get_attachment_choices(); + } + } + } + + public function content_template() { + ?> + <# if ( '' !== data.label ) { #> + {{ data.label }} + <# } #> + + <# if ( 'undefined' !== typeof ( data.repeat ) ) { #> +%current_year% to update year automatically.', 'gp-premium' );
+ $this->json[ 'copyright' ] = __( '%copy% to include the copyright symbol.', 'gp-premium' );
+ $this->json[ 'html' ] = __( 'HTML is allowed.', 'gp-premium' );
+ $this->json[ 'shortcodes' ] = __( 'Shortcodes are allowed.', 'gp-premium' );
+ }
+ /**
+ * Render the control's content.
+ *
+ * Allows the content to be overriden without having to rewrite the wrapper.
+ *
+ * @since 10/16/2012
+ * @return void
+ */
+ public function content_template() {
+ ?>
+
+ json[ 'link' ] = $this->get_link();
+ $this->json[ 'value' ] = $this->value();
+ $this->json[ 'id' ] = $this->id;
+ $this->json[ 'default_value' ] = $this->default_value;
+ $this->json[ 'reset_title' ] = esc_attr__( 'Reset','generate-spacing' );
+ $this->json[ 'unit' ] = $this->unit;
+ $this->json[ 'edit_field' ] = $this->edit_field;
+ }
+
+ public function content_template() {
+ ?>
+
+
+ <# if ( '' !== data.default_value ) { #><# } #>
+ json[ 'link' ] = $this->get_link();
+ $this->json[ 'value' ] = absint( $this->value() );
+ $this->json[ 'description' ] = esc_html( $this->description );
+ }
+
+ public function content_template() {
+ ?>
+
+ type ) {
+ default:
+ case 'text' : ?>
+
+ label ) ) echo '' . esc_html( $this->label ) . '';
+ if ( ! empty( $this->description ) ) echo '' . esc_html( $this->description ) . '';
+ if ( ! empty( $this->areas ) ) :
+ echo '';
+ foreach ( $this->areas as $value => $label ) :
+ echo '' . esc_html( $label ) . '';
+ endforeach;
+ endif;
+ break;
+
+ case 'line' :
+ echo '{{{ data.description }}}
+ <# } #> + + <# if ( data.notice ) { #> +