2
0
Fork 0
mirror of https://github.com/discourse/wp-discourse.git synced 2025-10-03 08:59:21 +08:00

Two Five Seven (#541)

* Don't try to add url to <head> if it's not present

* Update js config and formatting for comment block and sidebar

* PHP Linting

* FIX: Don't auto-publish updates to existing posts.

See: https://meta.discourse.org/t/disable-posting-wordpress-articles-to-discourse-when-theyre-updated/204488

* Bump version and release notes.

* Fix remote-post.php linting

* Update tests.yml to install svn

* Re-generate comments js build
This commit is contained in:
Angus McLeod 2025-04-16 01:53:23 +02:00 committed by GitHub
parent b20e8fa0f0
commit 22ee91dfb5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
54 changed files with 15762 additions and 14867 deletions

View file

@ -22,6 +22,11 @@ jobs:
with:
php-version: ${{ matrix.php }}

- name: Install Subversion
run: |
sudo apt-get update
sudo apt-get install -y subversion

- name: Install Composer
uses: ramsey/composer-install@v2
with:

View file

@ -466,8 +466,8 @@ class CommentSettings {
'custom-datetime-format',
'discourse_comment',
__( 'The datetime format used for displaying the comment date/time. (default: "', 'wp-discourse' ) .
get_option( 'date_format' ) . '").' .
__( ' See ', 'wp-discourse' ) . '<a href="https://codex.wordpress.org/Formatting_Date_and_Time" target="_blank" rel="noreferrer noopener">' .
get_option( 'date_format' ) . '").' .
__( ' See ', 'wp-discourse' ) . '<a href="https://codex.wordpress.org/Formatting_Date_and_Time" target="_blank" rel="noreferrer noopener">' .
__( 'this page', 'wp-discourse' ) . '</a>' . __( ' for more information.', 'wp-discourse' )
);
}
@ -494,10 +494,10 @@ class CommentSettings {
<em>
<?php esc_html_e( 'For detailed instructions, see the ', 'wp-discourse' ); ?>
<a href="<?php echo esc_url( $setup_howto_url ); ?>"
target="_blank" rel="noreferrer noopener"><?php esc_html_e( 'WP Discourse plugin installation and setup', 'wp-discourse' ); ?></a>
target="_blank" rel="noreferrer noopener"><?php esc_html_e( 'WP Discourse plugin installation and setup', 'wp-discourse' ); ?></a>
<?php esc_html_e( 'and', 'wp-discourse' ); ?>
<a href="<?php echo esc_url( $template_customization_url ); ?>"
target="_blank" rel="noreferrer noopener"><?php esc_html_e( 'WP Discourse template customization', 'wp-discourse' ); ?></a>
target="_blank" rel="noreferrer noopener"><?php esc_html_e( 'WP Discourse template customization', 'wp-discourse' ); ?></a>
<?php esc_html_e( 'topics on the ', 'wp-discourse' ); ?>
<a href="<?php echo esc_url( $discourse_meta_url ); ?>" target="_blank" rel="noreferrer noopener">Discourse Meta</a>
<?php esc_html_e( 'forum.', 'wp-discourse' ); ?>

View file

@ -478,7 +478,7 @@ class ConfigurableTextSettings {
if ( 'text_content_options' === $tab ) {
?>
<form action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
method="post">
method="post">
<?php wp_nonce_field( 'text_options_reset', 'text_options_reset_nonce' ); ?>

<input type="hidden" name="action" value="text_options_reset">
@ -493,7 +493,7 @@ class ConfigurableTextSettings {
*/
public function process_text_options_reset() {
if ( ! isset( $_POST['text_options_reset_nonce'] ) || // Input var okay.
! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['text_options_reset_nonce'] ) ), 'text_options_reset' ) // Input var okay.
! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['text_options_reset_nonce'] ) ), 'text_options_reset' ) // Input var okay.
) {

exit;

View file

@ -140,7 +140,7 @@ class ConnectionSettings {
'api-key',
'discourse_connect',
__( 'Found on your forum at ', 'wp-discourse' ) . '<a href="' . esc_url( $discourse_options['url'] ) .
'/admin/api/keys" target="_blank" rel="norefferer noopener">' . esc_url( $discourse_options['url'] ) . '/admin/api/keys</a>. ' .
'/admin/api/keys" target="_blank" rel="norefferer noopener">' . esc_url( $discourse_options['url'] ) . '/admin/api/keys</a>. ' .
"If you haven't yet created an API key, Click 'New API Key', set User Level to 'All Users', set 'User' to an admin account, select 'Global Key' and click 'Save'. Copy and paste the API key here.",
'wp-discourse'
);
@ -228,7 +228,7 @@ class ConnectionSettings {
<em>
<?php esc_html_e( 'For detailed instructions on setting up the plugin, please see the ', 'wp-discourse' ); ?>
<a href="<?php echo esc_url( $setup_howto_url ); ?>"
target="_blank" rel="noreferrer noopener"><?php esc_html_e( 'WP Discourse plugin installation and setup', 'wp-discourse' ); ?></a>
target="_blank" rel="noreferrer noopener"><?php esc_html_e( 'WP Discourse plugin installation and setup', 'wp-discourse' ); ?></a>
<?php esc_html_e( 'topic on the ', 'wp-discourse' ); ?>
<a href="<?php echo esc_url( $discourse_meta_url ); ?>" target="_blank" rel="noreferrer noopener">Discourse Meta</a>
<?php esc_html_e( 'forum.', 'wp-discourse' ); ?>

View file

@ -1 +1 @@
<?php return array('dependencies' => array('wp-element', 'wp-polyfill'), 'version' => 'c8ae5787daa4412c6d4d288426b7b6cd');
<?php return array('dependencies' => array('react-jsx-runtime'), 'version' => 'a53994925f492a194cb4');

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -4,12 +4,18 @@
"description": "Adds a Discourse Sidebar to the Block Editor",
"main": "build/index.js",
"scripts": {
"start": "wp-scripts start",
"build": "wp-scripts build"
"dev": "nodemon --watch src --exec 'wp-scripts start'",
"build": "wp-scripts build",
"format:css": "wp-scripts lint-style --fix",
"format:js": "wp-scripts format",
"lint:css": "wp-scripts lint-style",
"lint:js": "wp-scripts lint-js",
"start": "wp-scripts start"
},
"author": "Discourse",
"license": "GPL",
"devDependencies": {
"@wordpress/scripts": "^29.0.0"
"@wordpress/scripts": "^30.12.0",
"nodemon": "3.1.9"
}
}

File diff suppressed because it is too large Load diff

View file

@ -5,6 +5,7 @@
.wpdc-permalink {
margin-bottom: 16px;
}

a.wpdc-permalink-link {
text-decoration: none;
}
@ -12,7 +13,7 @@ a.wpdc-permalink-link {
button.components-button.is-button.is-default.is-primary.is-large.active {
color: #fff;
background-size: 100px 100%;
background-image: linear-gradient(-45deg,#0085ba 28%,#005d82 28%,#005d82 72%,#0085ba 72%);
background-image: linear-gradient(-45deg, #0085ba 28%, #005d82 28%, #005d82 72%, #0085ba 72%);
border-color: #00435d;
animation: components-button__busy-animation 2.5s infinite linear;
animation-name: components-button__busy-animation;
@ -27,11 +28,11 @@ button.components-button.is-button.is-default.is-primary.is-large.active {
}

.wpdc-button {
margin-bottom: 16px;
margin-bottom: 16px;
}

input.wpdc-topic-url-input {
margin-bottom: 16px;
margin-bottom: 16px;
}

.wpdc-publishing-options {
@ -79,20 +80,20 @@ input.wpdc-topic-url-input {
}

h2.wpdc-panel-section-title {
color: #555d66;
display: block;
padding: 0;
font-size: inherit;
margin-top: 0;
margin-bottom: 0;
margin-left: -15px;
margin-right: -15px;
transition: .1s background ease-in-out;
border-top: 1px solid #e2e4e7;
color: #555d66;
display: block;
padding: 0;
font-size: inherit;
margin-top: 0;
margin-bottom: 0;
margin-left: -15px;
margin-right: -15px;
transition: 0.1s background ease-in-out;
border-top: 1px solid #e2e4e7;
}

h2.wpdc-panel-section-title:hover {
background: #f8f9f9;
background: #f8f9f9;
}

hr.wpdc-sidebar-hr {
@ -102,7 +103,7 @@ hr.wpdc-sidebar-hr {
}

/* tags */
.wpdc-sidebar .components-form-token-field__input-container input[type=text].components-form-token-field__input {
.wpdc-sidebar .components-form-token-field__input-container input[type="text"].components-form-token-field__input {
width: auto;
}


View file

@ -97,8 +97,8 @@ class FormHelper {

?>
<input id='discourse-<?php echo esc_attr( $option ); ?>'
name='<?php echo esc_attr( $this->option_name( $option, $option_group ) ); ?>'
type="<?php echo isset( $type ) ? esc_attr( $type ) : 'text'; ?>"
name='<?php echo esc_attr( $this->option_name( $option, $option_group ) ); ?>'
type="<?php echo isset( $type ) ? esc_attr( $type ) : 'text'; ?>"
<?php
if ( isset( $min ) ) {
echo 'min="' . esc_attr( $min ) . '"';
@ -109,7 +109,7 @@ class FormHelper {
echo 'max="' . esc_attr( $max ) . '"';
}
?>
value='<?php echo esc_attr( $value ); ?>' class="regular-text ltr"/>
value='<?php echo esc_attr( $value ); ?>' class="regular-text ltr"/>
<p class="description"><?php echo wp_kses( $description, $allowed ); ?></p>
<?php
}
@ -143,12 +143,12 @@ class FormHelper {
?>
<label>
<input name='<?php echo esc_attr( $this->option_name( $option, $option_group ) ); ?>'
type='hidden'
value='0'/>
type='hidden'
value='0'/>
<input id='discourse-<?php echo esc_attr( $option ); ?>'
name='<?php echo esc_attr( $this->option_name( $option, $option_group ) ); ?>'
type='checkbox'
value='1' <?php echo esc_attr( $checked ); ?> />
name='<?php echo esc_attr( $this->option_name( $option, $option_group ) ); ?>'
type='checkbox'
value='1' <?php echo esc_attr( $checked ); ?> />
<?php echo wp_kses( $label, $allowed ); ?>
</label>
<p class="description"><?php echo wp_kses( $description, $allowed ); ?></p>
@ -265,7 +265,7 @@ class FormHelper {

?>
<textarea cols=100 rows=6 id='discourse_<?php echo esc_attr( $option ); ?>'
name='<?php echo esc_attr( $option ); ?>'><?php echo esc_textarea( $value ); ?></textarea>
name='<?php echo esc_attr( $option ); ?>'><?php echo esc_textarea( $value ); ?></textarea>
<p class="description"><?php echo esc_html( $description ); ?></p>
<?php
}

View file

@ -62,7 +62,7 @@ class MetaBox {
return null;
}
if ( isset( $this->options['allowed_post_types'] ) &&
in_array( $post_type, $this->options['allowed_post_types'], true )
in_array( $post_type, $this->options['allowed_post_types'], true )
) {
add_meta_box(
'discourse-publish-meta-box',
@ -108,10 +108,10 @@ class MetaBox {
$published = get_post_meta( $post_id, 'discourse_post_id', true );
$publishing_error = get_post_meta( $post_id, 'wpdc_publishing_error', true );
$saved = 'publish' === get_post_status( $post_id ) ||
'future' === get_post_status( $post_id ) ||
'draft' === get_post_status( $post_id ) ||
'private' === get_post_status( $post_id ) ||
'pending' === get_post_status( $post_id );
'future' === get_post_status( $post_id ) ||
'draft' === get_post_status( $post_id ) ||
'private' === get_post_status( $post_id ) ||
'pending' === get_post_status( $post_id );
// Todo: these values are incorrect if a draft was saved when the plugin wasn't enabled.
$publish_to_discourse = $saved ? get_post_meta( $post_id, 'publish_to_discourse', true ) : $this->options['auto-publish'];
$publish_category_id = $saved ? get_post_meta( $post_id, 'publish_post_category', true ) : $this->options['publish-category'];
@ -194,7 +194,7 @@ class MetaBox {
*/
public function save_meta_box( $post_id ) {
if ( ! isset( $_POST['publish_to_discourse_nonce'] ) || // Input var okay.
! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['publish_to_discourse_nonce'] ) ), 'publish_to_discourse' ) // Input var okay.
! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['publish_to_discourse_nonce'] ) ), 'publish_to_discourse' ) // Input var okay.
) {

return 0;

View file

@ -76,29 +76,29 @@ class OptionsPage {

<h2 class="nav-tab-wrapper nav-tab-first-level">
<a href="?page=wp_discourse_options&tab=connection_options"
class="nav-tab <?php echo 'connection_options' === $tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Connection', 'wp-discourse' ); ?>
class="nav-tab <?php echo 'connection_options' === $tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Connection', 'wp-discourse' ); ?>
</a>
<a href="?page=wp_discourse_options&tab=publishing_options"
class="nav-tab <?php echo 'publishing_options' === $tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Publishing', 'wp-discourse' ); ?>
class="nav-tab <?php echo 'publishing_options' === $tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Publishing', 'wp-discourse' ); ?>
</a>
<a href="?page=wp_discourse_options&tab=commenting_options"
class="nav-tab <?php echo 'commenting_options' === $tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Commenting', 'wp-discourse' ); ?>
class="nav-tab <?php echo 'commenting_options' === $tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Commenting', 'wp-discourse' ); ?>
</a>
<a href="?page=wp_discourse_options&tab=text_content_options"
class="nav-tab <?php echo 'text_content_options' === $tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Text Content', 'wp-discourse' ); ?>
class="nav-tab <?php echo 'text_content_options' === $tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Text Content', 'wp-discourse' ); ?>
</a>
<a href="?page=wp_discourse_options&tab=webhook_options"
class="nav-tab <?php echo 'webhook_options' === $tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Webhooks', 'wp-discourse' ); ?>
class="nav-tab <?php echo 'webhook_options' === $tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Webhooks', 'wp-discourse' ); ?>
</a>

<?php $sso_active = 'sso_options' === $tab || 'sso_options' === $parent; ?>

<a href="?page=wp_discourse_options&tab=sso_options"
class="nav-tab <?php echo $sso_active ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'DiscourseConnect', 'wp-discourse' ); ?>
class="nav-tab <?php echo $sso_active ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'DiscourseConnect', 'wp-discourse' ); ?>
</a>

<a href="?page=wp_discourse_options&tab=log_viewer"
class="nav-tab <?php echo 'log_viewer' === $tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Logs', 'wp-discourse' ); ?>
class="nav-tab <?php echo 'log_viewer' === $tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Logs', 'wp-discourse' ); ?>
</a>

<?php
@ -161,8 +161,8 @@ class OptionsPage {

$multisite_configuration = get_site_option( 'wpdc_multisite_configuration' );
$hide_submit_button = ( is_multisite() &&
( 'connection_options' === $tab || 'webhook_options' === $tab || 'sso_options' === $tab || 'sso_common' === $tab ) &&
! empty( $multisite_configuration ) );
( 'connection_options' === $tab || 'webhook_options' === $tab || 'sso_options' === $tab || 'sso_common' === $tab ) &&
! empty( $multisite_configuration ) );

if ( ! $hide_submit_button ) {
submit_button( 'Save Options', 'primary', 'discourse_save_options', false );

View file

@ -648,7 +648,7 @@ class PublishSettings {
<em>
<?php esc_html_e( 'For detailed instructions, see the ', 'wp-discourse' ); ?>
<a href="<?php echo esc_url( $setup_howto_url ); ?>"
target="_blank" rel="noreferrer noopener"><?php esc_html_e( 'WP Discourse plugin installation and setup', 'wp-discourse' ); ?></a>
target="_blank" rel="noreferrer noopener"><?php esc_html_e( 'WP Discourse plugin installation and setup', 'wp-discourse' ); ?></a>
<?php esc_html_e( 'topic on the ', 'wp-discourse' ); ?>
<a href="<?php echo esc_url( $discourse_meta_url ); ?>" target="_blank" rel="noreferrer noopener">Discourse Meta</a>
<?php esc_html_e( 'forum.', 'wp-discourse' ); ?>

View file

@ -308,7 +308,7 @@ class SettingsValidator {
$output = array();

if ( is_string( $input ) ) {
$input = explode( ',', $input );
$input = explode( ',', $input );
}

foreach ( $input as $tag_slug ) {

View file

@ -262,14 +262,14 @@ class SSOSettings {
);

add_settings_field(
'discourse_sso_disable_create_user',
__( 'Disable user creation', 'wp-discourse' ),
'discourse_sso_disable_create_user',
__( 'Disable user creation', 'wp-discourse' ),
array(
$this,
'sso_client_disable_create_user_checkbox',
),
'discourse_sso_client',
'discourse_sso_client_settings_section'
'discourse_sso_client',
'discourse_sso_client_settings_section'
);

add_settings_field(
@ -338,16 +338,16 @@ class SSOSettings {
?>
<h3 class="nav-tab-wrapper nav-tab-second-level">
<a href="?page=wp_discourse_options&tab=sso_common&parent_tab=sso_options"
class="nav-tab <?php echo 'sso_common' === $tab || 'sso_options' === $tab ? 'nav-tab-active' : ''; ?>">
class="nav-tab <?php echo 'sso_common' === $tab || 'sso_options' === $tab ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e( 'DiscourseConnect Secret Key', 'wpdc' ); ?>
</a>
<a href="?page=wp_discourse_options&tab=sso_provider&parent_tab=sso_options"
class="nav-tab <?php echo 'sso_provider' === $tab ? 'nav-tab-active' : ''; ?>">
class="nav-tab <?php echo 'sso_provider' === $tab ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e( 'DiscourseConnect Provider', 'wpdc' ); ?>
</a>
<?php if ( ! $this->remove_sso_client_settings ) : ?>
<a href="?page=wp_discourse_options&tab=sso_client&parent_tab=sso_options"
class="nav-tab <?php echo 'sso_client' === $tab ? 'nav-tab-active' : ''; ?>">
class="nav-tab <?php echo 'sso_client' === $tab ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e( 'DiscourseConnect Client', 'wpdc' ); ?>
</a>
<?php endif; ?>
@ -672,7 +672,7 @@ class SSOSettings {
<em>
<?php esc_html_e( "You can find your forum's DiscourseConnect settings ", 'wp-discourse' ); ?>
<a href="<?php echo esc_url( $this->discourse_sso_settings_url ); ?>"
target="_blank" rel="noreferrer noopener"><?php esc_html_e( 'here', 'wp-discourse' ); ?></a><?php echo esc_html( '.' ); ?>
target="_blank" rel="noreferrer noopener"><?php esc_html_e( 'here', 'wp-discourse' ); ?></a><?php echo esc_html( '.' ); ?>
</em>
</p>
<?php endif; ?>
@ -725,7 +725,7 @@ class SSOSettings {
<em>
<?php esc_html_e( "Your forum's DiscourseConnect settings are ", 'wp-discourse' ); ?>
<a href="<?php echo esc_url( $this->discourse_sso_settings_url ); ?>"
target="_blank" rel="noreferrer noopener"><?php esc_html_e( 'here', 'wp-discourse' ); ?></a><?php echo esc_html( '.' ); ?>
target="_blank" rel="noreferrer noopener"><?php esc_html_e( 'here', 'wp-discourse' ); ?></a><?php echo esc_html( '.' ); ?>
</em>
</p>
<?php endif; ?>
@ -817,7 +817,7 @@ class SSOSettings {
<em>
<?php esc_html_e( "Your forum's DiscourseConnect settings are ", 'wp-discourse' ); ?>
<a href="<?php echo esc_url( $this->discourse_sso_settings_url ); ?>"
target="_blank" rel="noreferrer noopener"><?php esc_html_e( 'here', 'wp-discourse' ); ?></a><?php echo esc_html( '.' ); ?>
target="_blank" rel="noreferrer noopener"><?php esc_html_e( 'here', 'wp-discourse' ); ?></a><?php echo esc_html( '.' ); ?>
</em>
</p>
<?php endif; ?>

View file

@ -70,7 +70,7 @@ class UserProfile {
</th>
<td>
<input type="text" name="discourse_username"
value="<?php echo esc_attr( $discourse_username ); ?>" <?php echo disabled( $username_editable, false, false ); ?>>
value="<?php echo esc_attr( $discourse_username ); ?>" <?php echo disabled( $username_editable, false, false ); ?>>
<em><?php echo esc_html( $discourse_username_description ); ?></em>
</td>
</tr>
@ -80,7 +80,7 @@ class UserProfile {
$sso_enabled = ! empty( $this->options['enable-sso'] );
if ( $is_admin && $sso_enabled ) :
$email_verified_meta = get_user_meta( $profile_user->ID, 'discourse_email_not_verified', true );
$email_verified = empty( $email_verified_meta );
$email_verified = empty( $email_verified_meta );
?>
<tr>
<th>
@ -105,19 +105,19 @@ class UserProfile {
*/
public function update_discourse_user_metadata( $user_id ) {
if ( ! isset( $_POST['update_discourse_usermeta_nonce'] ) || // Input var okay.
! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['update_discourse_usermeta_nonce'] ) ), 'update_discourse_usermeta' ) // Input var okay.
! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['update_discourse_usermeta_nonce'] ) ), 'update_discourse_usermeta' ) // Input var okay.
) {

return 0;
}
$is_admin = current_user_can( 'manage_options' );
$is_admin = current_user_can( 'manage_options' );
$sso_enabled = ! empty( $this->options['enable-sso'] );
if ( $is_admin && $sso_enabled ) {
// This gets ugly because of support for php 5.4.
$email_verified = false;
if ( isset( $_POST['email_verified'] ) ) {
$email_verified_value = intval( wp_unslash( $_POST['email_verified'] ) );
$email_verified = ! empty( $email_verified_value );
$email_verified = ! empty( $email_verified_value );
}
if ( $email_verified ) {
delete_user_meta( $user_id, 'discourse_email_not_verified' );

View file

@ -1 +1 @@
<?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-blocks', 'wp-element', 'wp-i18n'), 'version' => '9fbf6b41a5767e63fe81');
<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-i18n'), 'version' => '857b20870324aa144770');

File diff suppressed because one or more lines are too long

View file

@ -5,36 +5,36 @@
* @package WPDiscourse
*/

use WPDiscourse\DiscourseCommentFormatter\DiscourseCommentFormatter;
use WPDiscourse\DiscourseComment\DiscourseComment;
use WPDiscourse\DiscourseCommentFormatter\DiscourseCommentFormatter;
use WPDiscourse\DiscourseComment\DiscourseComment;

/**
* Renders the `wp-discourse/comments` block on the server.
*
* @param array $attributes Block attributes.
* @param string $content Block default content.
* @param WP_Block $block Block instance.
* @return string Returns the filtered post comments for the current post wrapped inside "p" tags.
*/
/**
* Renders the `wp-discourse/comments` block on the server.
*
* @param array $attributes Block attributes.
* @param string $content Block default content.
* @param WP_Block $block Block instance.
* @return string Returns the filtered post comments for the current post wrapped inside "p" tags.
*/
function render_block_wpdc_comments( $attributes, $content, $block ) {
$post_id = $block->context['postId'];
if ( ! isset( $post_id ) ) {
if ( ! isset( $post_id ) ) {
return '';
}

$comment_formatter = new DiscourseCommentFormatter();
$comment = new DiscourseComment( $comment_formatter );
$default = '';
$default = '';

$comment->setup_options();
$comment_formatter->setup_options();
$comment->setup_options();
$comment_formatter->setup_options();

ob_start();
ob_start();

$comment->comments_template( $default );
$result = ob_get_contents();
$comment->comments_template( $default );
$result = ob_get_contents();

ob_end_clean();
ob_end_clean();

return $result;
}
@ -43,13 +43,13 @@ function render_block_wpdc_comments( $attributes, $content, $block ) {
* Registers the `wp-discourse/comments` block on the server.
*/
function register_wpdc_blocks() {
if ( version_compare( get_bloginfo( 'version' ), '5.5', '>=' ) ) {
if ( version_compare( get_bloginfo( 'version' ), '5.5', '>=' ) ) {
register_block_type_from_metadata(
WPDISCOURSE_PATH . 'blocks/comments/build/block.json',
array(
'render_callback' => 'render_block_wpdc_comments',
)
);
}
);
}
}
add_action( 'init', 'register_wpdc_blocks' );

File diff suppressed because it is too large Load diff

View file

@ -4,6 +4,7 @@
"description": "WP Discourse Comments",
"main": "build/index.js",
"scripts": {
"dev": "nodemon --watch src --exec 'wp-scripts start'",
"build": "wp-scripts build",
"format": "wp-scripts format",
"lint:css": "wp-scripts lint-style",
@ -13,7 +14,8 @@
"author": "Discourse",
"license": "GPL",
"devDependencies": {
"@wordpress/scripts": "*"
"@wordpress/scripts": "^30.12.0",
"nodemon": "3.1.9"
},
"dependencies": {
"date-fns": "^2.29.3",

View file

@ -11,13 +11,13 @@
"supports": {
"align": true,
"__experimentalLayout": {
"allowSwitching": false,
"default": {
"inherit": true
}
}
"allowSwitching": false,
"default": {
"inherit": true
}
}
},
"usesContext": [ "postId", "postType" ],
"usesContext": [ "postId", "postType" ],
"editorScript": "file:./index.js",
"editorStyle": "comment_styles"
}

View file

@ -1,47 +1,49 @@
export default {
"id": 11,
"category_id": 1,
"posts_count": 3,
"filtered_posts_count": 3,
"posts": [
{
"id": 15,
"name": "Andrew Jones",
"username": "andrew",
"created_at": "2021-10-17T11:34:18.156Z",
"cooked": "<p>Thanks for posting this, I'm interested to hear what other folks think.</p>",
"post_number": 2
},{
"id": 16,
"name": "Beth Smith",
"username": "beth",
"created_at": "2021-10-17T11:34:53.978Z",
"cooked": "<p>Great post Cathy! I'll let you know how I go.</p>",
"post_number": 3
},{
"id": 17,
"name": "Cathy Roberts",
"username": "cathy",
"created_at": "2021-10-17T11:34:53.978Z",
"cooked": "<p>Thanks guys! Positive feedback is always appreciated.</p>",
"post_number": 4
}
],
"participants": [
{
"id": 1,
"username": "andrew",
"name": "Andrew Jones",
},
{
"id": 2,
"username": "beth",
"name": "Beth Smith",
},
id: 11,
category_id: 1,
posts_count: 3,
filtered_posts_count: 3,
posts: [
{
"id": 3,
"username": "cathy",
"name": "Cathy Roberts",
},
]
};
id: 15,
name: 'Andrew Jones',
username: 'andrew',
created_at: '2021-10-17T11:34:18.156Z',
cooked: "<p>Thanks for posting this, I'm interested to hear what other folks think.</p>",
post_number: 2,
},
{
id: 16,
name: 'Beth Smith',
username: 'beth',
created_at: '2021-10-17T11:34:53.978Z',
cooked: "<p>Great post Cathy! I'll let you know how I go.</p>",
post_number: 3,
},
{
id: 17,
name: 'Cathy Roberts',
username: 'cathy',
created_at: '2021-10-17T11:34:53.978Z',
cooked: '<p>Thanks guys! Positive feedback is always appreciated.</p>',
post_number: 4,
},
],
participants: [
{
id: 1,
username: 'andrew',
name: 'Andrew Jones',
},
{
id: 2,
username: 'beth',
name: 'Beth Smith',
},
{
id: 3,
username: 'cathy',
name: 'Cathy Roberts',
},
],
};

View file

@ -1,7 +1,7 @@
/**
* WordPress dependencies
*/
import { useBlockProps, useSetting } from '@wordpress/block-editor';
import { useBlockProps, useSettings } from '@wordpress/block-editor';

/**
* Internal dependencies
@ -9,18 +9,21 @@ import { useBlockProps, useSetting } from '@wordpress/block-editor';
import WPDiscourseCommentsPlaceholder from './placeholder';

export default function WPDiscourseCommentsEdit( props ) {
const blockProps = useBlockProps();
const defaultLayout = useSetting( 'layout' ) || {};
const blockProps = useBlockProps();
const defaultLayout = useSettings( 'layout' ) || {};

// TODO: Workaround for permissions issue described here https://github.com/WordPress/gutenberg/issues/20731
const urlMeta = document.head.querySelector("[name~=wpdc-url][content]");
if (urlMeta) {
props.discourse_url = urlMeta.content;
}
// TODO: Workaround for permissions issue described here https://github.com/WordPress/gutenberg/issues/20731
const urlMeta = document.head.querySelector( '[name~=wpdc-url][content]' );
if ( urlMeta ) {
props.discourse_url = urlMeta.content;
}

return (
<div { ...blockProps }>
<WPDiscourseCommentsPlaceholder __experimentalLayout={ defaultLayout } { ...props } />
</div>
);
}
return (
<div { ...blockProps }>
<WPDiscourseCommentsPlaceholder
__experimentalLayout={ defaultLayout }
{ ...props }
/>
</div>
);
}

View file

@ -2,103 +2,111 @@
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import comments from "./comments.js";
import aAvatarUrl from "./avatars/a_240.png";
import bAvatarUrl from "./avatars/b_240.png";
import cAvatarUrl from "./avatars/c_240.png";
import comments from './comments.js';
import aAvatarUrl from './avatars/a_240.png';
import bAvatarUrl from './avatars/b_240.png';
import cAvatarUrl from './avatars/c_240.png';
import parse from 'html-react-parser';
import { format } from "date-fns";
import { format } from 'date-fns';

/**
* WP Discourse Comments Placeholder
*/

export default function WPDiscourseCommentsPlaceholder( props ) {
const avatarUrls = [
aAvatarUrl,
bAvatarUrl,
cAvatarUrl
];
const avatarUrls = [ aAvatarUrl, bAvatarUrl, cAvatarUrl ];

const mapAvatarUrls = (objects) => {
return objects.map((obj, i) => {
obj.avatar_url = avatarUrls[i];
return obj;
});
}
const mapAvatarUrls = ( objects ) => {
return objects.map( ( obj, i ) => {
obj.avatar_url = avatarUrls[ i ];
return obj;
} );
};

const commentList = () => {
return mapAvatarUrls(comments.posts)
.map((comment) => (commentTemplate(comment)));
}
const commentList = () => {
return mapAvatarUrls( comments.posts ).map( ( comment ) =>
commentTemplate( comment )
);
};

const participantList = () => {
return mapAvatarUrls(comments.participants)
.map((participant) => (avatarTemplate(participant, '25')));
}
const participantList = () => {
return mapAvatarUrls( comments.participants ).map( ( participant ) =>
avatarTemplate( participant, '25' )
);
};

const commentTemplate = (comment) => {
let date = new Date(comment.created_at);
let createdAt = format(date, "MMMM do, yyyy");
const commentTemplate = ( comment ) => {
const date = new Date( comment.created_at );
const createdAt = format( date, 'MMMM do, yyyy' );

return (
<li class='comment'>
<article class="comment-body">
<footer class="comment-meta">
<div class="comment-author vcard">
{ avatarTemplate(comment, '64' ) }
<b class="fn">
<a href="https://discourse.mysite.com/t/1"
rel="external"
class="url">
{comment.username}
</a>
</b>
<span class="says screen-reader-text">
{ __( 'says:', 'wp-discourse' ) }
</span>
</div>
<div class="comment-metadata">
<time datetime={createdAt}>{createdAt}</time>
</div>
</footer>
<div class="comment-content">{parse(comment.cooked)}</div>
</article>
</li>
);
}
return (
<li className="comment">
<article className="comment-body">
<footer className="comment-meta">
<div className="comment-author vcard">
{ avatarTemplate( comment, '64' ) }
<b className="fn">
<a
href="https://discourse.mysite.com/t/1"
rel="external"
className="url"
>
{ comment.username }
</a>
</b>
<span className="says screen-reader-text">
{ __( 'says:', 'wp-discourse' ) }
</span>
</div>
<div className="comment-metadata">
<time dateTime={ createdAt }>{ createdAt }</time>
</div>
</footer>
<div className="comment-content">
{ parse( comment.cooked ) }
</div>
</article>
</li>
);
};

const avatarTemplate = (obj, size) => {
const avatarClass = `avatar avatar-${size} photo avatar-default`;
return (
<img
alt={obj.username}
src={obj.avatar_url}
class={avatarClass}
height={size}
width={size} />
);
}
const avatarTemplate = ( obj, size ) => {
const avatarClass = `avatar avatar-${ size } photo avatar-default`;
return (
<img
alt={ obj.username }
src={ obj.avatar_url }
className={ avatarClass }
height={ size }
width={ size }
/>
);
};

return (
<div id="comments" class="comments-area discourse-comments-area">
<div class="comments-title-wrap">
<h2 class="comments-title discourse-comments-title">{ __( 'Notable Replies', 'wp-discourse' ) }</h2>
<div id="comments" className="comments-area discourse-comments-area">
<div className="comments-title-wrap">
<h2 className="comments-title discourse-comments-title">
{ __( 'Notable Replies', 'wp-discourse' ) }
</h2>
</div>
<ol class="comment-list">{ commentList() }</ol>
<div class="respond comment-respond">
<h3 id="reply-title" class="comment-reply-title">
{ __( 'Continue the discussion at ', 'wp-discourse' ) }
<ol className="comment-list">{ commentList() }</ol>
<div className="respond comment-respond">
<h3 id="reply-title" className="comment-reply-title">
{ __( 'Continue the discussion at', 'wp-discourse' ) }
<a
class="wpdc-discourse-topic-link"
target="_blank"
rel="noreferrer noopener"
href={ props.discourse_url }>
{ props.discourse_url }
</a>
className="wpdc-discourse-topic-link"
target="_blank"
rel="noreferrer noopener"
href={ props.discourse_url }
>
{ props.discourse_url }
</a>
</h3>
<div class="comment-reply-title">
<h4 class="discourse-participants">{ __( 'Participants', 'wp-discourse' ) }</h4>
<div className="comment-reply-title">
<h4 className="discourse-participants">
{ __( 'Participants', 'wp-discourse' ) }
</h4>
<p>{ participantList() }</p>
</div>
</div>

View file

@ -2,17 +2,19 @@ import { registerBlockType } from '@wordpress/blocks';
import SVG from 'react-inlinesvg';
import edit from './edit';

document.addEventListener("DOMContentLoaded", function() {
let attrs = {
example: {},
edit
};
document.addEventListener( 'DOMContentLoaded', function () {
const attrs = {
example: {},
edit,
};

const iconMeta = document.head.querySelector("[name~=wpdc-icon][content]");
if (iconMeta) {
const htmlString = atob(iconMeta.content.split(',')[1]);
attrs.icon = (<SVG src={htmlString} />);
}
const iconMeta = document.head.querySelector(
'[name~=wpdc-icon][content]'
);
if ( iconMeta ) {
const htmlString = atob( iconMeta.content.split( ',' )[ 1 ] );
attrs.icon = <SVG src={ htmlString } />;
}

registerBlockType('wp-discourse/comments', attrs);
});
registerBlockType( 'wp-discourse/comments', attrs );
} );

View file

@ -159,6 +159,10 @@ span.badge-category-bg {
text-align: left;
}

.discourse-comments-area .comment-reply-title .wpdc-discourse-topic-link {
margin-left: 0.25em;
}

.discourse-comments-area .comment-respond p:not(.comment-notes) {
max-width: none;
}

View file

@ -16,49 +16,49 @@ use WPDiscourse\Logs\Logger;
class DiscourseBase {
use PluginUtilities;

/**
* Gives access to the plugin options.
*
* @access protected
* @var mixed|void
*/
/**
* Gives access to the plugin options.
*
* @access protected
* @var mixed|void
*/
protected $options;

/**
* Instance of Logger
*
* @access protected
* @var \WPDiscourse\Logs\Logger
*/
protected $logger;
/**
* Instance of Logger
*
* @access protected
* @var \WPDiscourse\Logs\Logger
*/
protected $logger;

/**
* Logger context
*
* @access protected
* @var string
*/
protected $logger_context = 'base';
/**
* Logger context
*
* @access protected
* @var string
*/
protected $logger_context = 'base';

/**
* Setup options.
*
* @param object $extra_options Extra options used for testing.
*/
public function setup_options( $extra_options = null ) {
/**
* Setup options.
*
* @param object $extra_options Extra options used for testing.
*/
public function setup_options( $extra_options = null ) {
$this->options = $this->get_options();

if ( ! empty( $extra_options ) ) {
foreach ( $extra_options as $key => $value ) {
foreach ( $extra_options as $key => $value ) {
$this->options[ $key ] = $value;
}
}
}
}
}
}

/**
* Setup Logger for the context.
*/
public function setup_logger() {
/**
* Setup Logger for the context.
*/
public function setup_logger() {
$this->logger = Logger::create( $this->logger_context, $this->options );
}
}
}

View file

@ -298,6 +298,9 @@ class Discourse {
* Adds the WP Discourse URL to the <head> for use in the client.
*/
public function wpdc_url() {
if ( empty( $this->options['url'] ) ) {
return;
}
echo '<meta name="wpdc-url" content="' . esc_html( $this->options['url'] ) . '" />';
}


View file

@ -159,7 +159,7 @@ class FileHandler extends StreamHandler {

// Ensure the log file is not too large.
if ( file_exists( $this->url ) && ! $this->validate_size() ) {
$this->file_number++;
++$this->file_number;
$this->must_rotate = true;
$this->close();
}

View file

@ -10,4 +10,4 @@ namespace WPDiscourse\Logs;
/**
* Class NullHandler
*/
class NullHandler extends \WPDiscourse\Monolog\Handler\NullHandler {};
class NullHandler extends \WPDiscourse\Monolog\Handler\NullHandler {}

View file

@ -60,4 +60,4 @@ class Logger extends \WPDiscourse\Monolog\Logger {

return $logger;
}
};
}

View file

@ -114,7 +114,7 @@ class FileManager {
protected function create_files( $files ) {
foreach ( $files as $file ) {
if ( ! $file['base'] ) {
continue;
continue;
}

$file_path = trailingslashit( $file['base'] ) . $file['file'];
@ -130,7 +130,7 @@ class FileManager {
if ( $file_handle ) {
fwrite( $file_handle, $file['content'] );
fclose( $file_handle );
}
}
}
// phpcs:enable Wordpress.WP.AlternativeFunctions
}
@ -145,7 +145,7 @@ class FileManager {
protected function files_are_ready( $files ) {
foreach ( $files as $file ) {
if ( ! $file['base'] ) {
return false;
return false;
}

$directory_path = trailingslashit( $file['base'] );

View file

@ -130,7 +130,7 @@ class Client extends SSOClientBase {
} else {

echo wp_kses_data( $this->get_discourse_sso_link_markup() ) .
' <em>' . esc_html__( 'To link accounts, your Discourse email address needs to match your WordPress email address', 'wp-discourse' ) . '</em>';
' <em>' . esc_html__( 'To link accounts, your Discourse email address needs to match your WordPress email address', 'wp-discourse' ) . '</em>';
}
?>
</td>
@ -231,17 +231,17 @@ class Client extends SSOClientBase {
}
}

if ( empty( $user_query_results ) && ! empty( $this->options['sso-client-disable-create-user'] ) ) {
if ( empty( $user_query_results ) && ! empty( $this->options['sso-client-disable-create-user'] ) ) {
return new \WP_Error( 'no_matching_user' );
}
}

if ( empty( $user_query_results ) ) {
$user_password = wp_generate_password( 12, true );

$user_id = wp_create_user(
$this->get_sso_response( 'username' ),
$user_password,
$this->get_sso_response( 'email' )
$this->get_sso_response( 'username' ),
$user_password,
$this->get_sso_response( 'email' )
);

do_action( 'wpdc_sso_client_after_create_user', $user_id );
@ -482,10 +482,10 @@ class Client extends SSOClientBase {

$path = "/admin/users/$discourse_user_id/log_out";
$response = $this->discourse_request(
$path, array(
'method' => 'POST',
'raw' => true,
)
$path, array(
'method' => 'POST',
'raw' => true,
)
);

if ( ! $this->validate( $response ) ) {

View file

@ -141,7 +141,7 @@ trait TemplateFunctions {
$poll->parentNode->removeChild( $poll );
}

$poll_number++;
++$poll_number;
}

$parsed = $doc->saveHTML( $doc->documentElement );

View file

@ -269,7 +269,7 @@ class WordPressEmailVerification {
public function is_verified( $user_id ) {

if ( 1 === intval( $this->get_email_flag_status( $user_id ) ) ||
1 === intval( $this->get_email_changed_status( $user_id ) ) ) {
1 === intval( $this->get_email_changed_status( $user_id ) ) ) {

return apply_filters( 'wpdc_email_verification_not_verified', false, $user_id );
} else {

View file

@ -2,9 +2,9 @@
Contributors: scossar, cdck, angusmcleod, samsaffron, techapj
Tags: discourse, forum, comments, sso
Requires at least: 5.1
Tested up to: 6.7.1
Tested up to: 6.7.2
Requires PHP: 5.6
Stable tag: 2.5.6
Stable tag: 2.5.7
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html

@ -123,6 +123,12 @@ To create a coherent top menu, see our tutorial on how to make a [Custom nav hea

== Changelog ==

#### 2.5.7 28/03/2025

- Sidebar and comment block JS upgrades.
- Handle various deprecations.
- Don't auto-publish when existing non-published posts are edited.

#### 2.5.6 11/12/2024

- Security updates.

View file

@ -147,10 +147,10 @@ class HTMLTemplates {
<footer class="comment-meta">
<div class="comment-author vcard">
<img alt="Avatar for {username}" src="{avatar_url}" class="avatar avatar-64 photo avatar-default"
height="64"
width="64">
height="64"
width="64">
<b class="fn"><a href="{topic_url}" rel="external"
class="url">{username}</a></b>
class="url">{username}</a></b>
<span class="says screen-reader-text"><?php echo esc_html( 'says:', 'wp-discourse' ); ?></span><!-- screen reader text -->
</div>
<div class="comment-metadata">

View file

@ -13,23 +13,23 @@ use WPDiscourse\Logs\FileManager;
* Logging methods for WPDiscourse unit tests
*/
trait Logging {
/**
* Get last line in latest log file.
*/
protected function get_last_log() {
/**
* Get last line in latest log file.
*/
protected function get_last_log() {
$manager = new FileManager();
$log_files = glob( $manager->logs_dir . '/*.log' );
if ( empty( $log_files ) ) {
return '';
return '';
}
$log_file = $log_files[0];
return shell_exec( "tail -n 1 $log_file" );
}
}

/**
* Clear all logs.
*/
protected function clear_logs() {
/**
* Clear all logs.
*/
protected function clear_logs() {
$manager = new FileManager();
$log_files = glob( $manager->logs_dir . '/*.log' );

@ -38,5 +38,5 @@ trait Logging {
unlink( $file );
}
}
}
}
}

View file

@ -12,60 +12,60 @@ namespace WPDiscourse\Test;
*/
trait Multisite {

/**
* Setup multisite tests
*/
public function setUp(): void {
/**
* Setup multisite tests
*/
public function setUp(): void {
parent::setUp();
$this->create_topic_blog_table();
}
}

/**
* Teardown multisite tests
*/
public function tearDown(): void {
/**
* Teardown multisite tests
*/
public function tearDown(): void {
parent::tearDown();
$this->clear_topic_blog_table();
}
}

/**
* Create topic_blog_table if it doesn't exist.
*/
protected function create_topic_blog_table() {
/**
* Create topic_blog_table if it doesn't exist.
*/
protected function create_topic_blog_table() {
global $wpdb;

$table = $wpdb->base_prefix . 'wpdc_topic_blog';
$sql = sprintf(
'CREATE TABLE %s (
'CREATE TABLE %s (
topic_id mediumint(9) NOT NULL,
blog_id mediumint(9) NOT NULL,
PRIMARY KEY (topic_id)
) %s;',
$table,
$wpdb->get_charset_collate()
$table,
$wpdb->get_charset_collate()
);

require_once ABSPATH . 'wp-admin/includes/upgrade.php';
maybe_create_table( $table, $sql );
}
}

/**
* Clear topic_blog_table.
*/
protected function clear_topic_blog_table() {
/**
* Clear topic_blog_table.
*/
protected function clear_topic_blog_table() {
global $wpdb;
$table = $wpdb->base_prefix . 'wpdc_topic_blog';
$result = $wpdb->query( "TRUNCATE TABLE $table" );
}
}

/**
* Switch to blog for discourse topic.
*/
protected function switch_to_blog_for_topic( $topic_id ) {
/**
* Switch to blog for discourse topic.
*/
protected function switch_to_blog_for_topic( $topic_id ) {
global $wpdb;
$table_name = $wpdb->base_prefix . 'wpdc_topic_blog';
$query = "SELECT blog_id FROM $table_name WHERE topic_id = %d";
$blog_id = $wpdb->get_var( $wpdb->prepare( $query, $topic_id ) );
switch_to_blog( $blog_id );
}
}
}

View file

@ -11,13 +11,13 @@ namespace WPDiscourse\Test;
* Remote posting methods for WPDiscourse unit tests
*/
trait RemotePost {
/**
* Build remote post response.
*
* @param string $type Type of response.
* @param string $sub_type Sub-type of response.
*/
protected function build_response( $type, $sub_type = null ) {
/**
* Build remote post response.
*
* @param string $type Type of response.
* @param string $sub_type Sub-type of response.
*/
protected function build_response( $type, $sub_type = null ) {
$codes = array(
'success' => 200,
'invalid_parameters' => 400,
@ -48,16 +48,16 @@ trait RemotePost {
'message' => $messages[ $type ],
),
);
}
}

/**
* Build JSON of response body.
*
* @param string $type Type of response.
* @param string $sub_type Sub-type of response.
* @param string $action_type Action type of test.
*/
protected function response_body_json( $type, $sub_type = null, $action_type = 'create_post' ) {
/**
* Build JSON of response body.
*
* @param string $type Type of response.
* @param string $sub_type Sub-type of response.
* @param string $action_type Action type of test.
*/
protected function response_body_json( $type, $sub_type = null, $action_type = 'create_post' ) {
if ( in_array( $type, array( 'post_create', 'post_update', 'user', 'comments', 'site', 'users', 'sync_sso', 'groups', 'user_create', 'scopes' ), true ) ) {
return $this->response_body_file( $type );
}
@ -76,62 +76,62 @@ trait RemotePost {
$message_type = $type;
}
return wp_json_encode(
array(
'action' => $action_type,
'errors' => array( $messages[ $message_type ] ),
'error_type' => $type,
)
array(
'action' => $action_type,
'errors' => array( $messages[ $message_type ] ),
'error_type' => $type,
)
);
}
}

/**
* Get fixture with response body.
*
* @param string $file Name of response body file.
*/
protected function response_body_file( $file ) {
/**
* Get fixture with response body.
*
* @param string $file Name of response body file.
*/
protected function response_body_file( $file ) {
return file_get_contents( __DIR__ . "/../../fixtures/response_body/$file.json" );
}
}

/**
* Mock remote post response.
*
* @param object $first_request First request in tested method.
* @param object $second_request Second request in tested method.
*/
protected function mock_remote_post( $first_request, $second_request = null ) {
/**
* Mock remote post response.
*
* @param object $first_request First request in tested method.
* @param object $second_request Second request in tested method.
*/
protected function mock_remote_post( $first_request, $second_request = null ) {
add_filter(
'pre_http_request',
function ( $prempt, $args, $url ) use ( $first_request, $second_request ) {
'pre_http_request',
function ( $prempt, $args, $url ) use ( $first_request, $second_request ) {
$is_sr = ! empty( $second_request ) && ( strpos( $url, $second_request['url'] ) !== false );
$request = $is_sr ? $second_request : $first_request;

if ( $request['method'] != $args['method'] ) {
return new \WP_Error( 'http_request_failed', 'Incorrect method' );
if ( $request['method'] !== $args['method'] ) {
return new \WP_Error( 'http_request_failed', 'Incorrect method' );
}

if ( isset( $request['headers'] ) && $request['headers'] != $args['headers'] ) {
return new \WP_Error( 'http_request_failed', 'Incorrect headers' );
if ( isset( $request['headers'] ) && $request['headers'] !== $args['headers'] ) {
return new \WP_Error( 'http_request_failed', 'Incorrect headers' );
}

if ( isset( $request['body'] ) && $request['body'] != $args['body'] ) {
return new \WP_Error( 'http_request_failed', 'Incorrect body' );
if ( isset( $request['body'] ) && $request['body'] !== $args['body'] ) {
return new \WP_Error( 'http_request_failed', 'Incorrect body' );
}

return $request['response'];
},
10,
3
10,
3
);
}
}

/**
* Mock remote post success.
*
* @param string $type Type of response.
* @param object $second_request Second request response of second request in tested method.
*/
protected function mock_remote_post_success( $type, $method = 'GET', $second_request = null ) {
/**
* Mock remote post success.
*
* @param string $type Type of response.
* @param object $second_request Second request response of second request in tested method.
*/
protected function mock_remote_post_success( $type, $method = 'GET', $second_request = null ) {
$raw_body = $this->response_body_json( $type );
$response = $this->build_response( 'success' );
$response['body'] = $raw_body;
@ -141,5 +141,5 @@ trait RemotePost {
);
$this->mock_remote_post( $first_request, $second_request );
return json_decode( $raw_body );
}
}
}

View file

@ -12,7 +12,7 @@ use WPDiscourse\Test\DiscoursePublishTest;
* DiscoursePublishMultisite test case.
*/
class DiscoursePublishMultisiteTest extends DiscoursePublishTest {
use Multisite;
use Multisite;

/**
* Sync_to_discourse handles new posts correctly in multisite

View file

@ -13,12 +13,12 @@ use WPDiscourse\DiscoursePublish\DiscoursePublish;
* SyncDiscourseTopicMultisiteTest test case.
*/
class SyncDiscourseTopicMultisiteTest extends SyncDiscourseTopicTest {
use Multisite;
use Multisite;

/**
* update_topic_content handles webhook results correctly in multisite.
*/
public function test_update_topic_content() {
/**
* update_topic_content handles webhook results correctly in multisite.
*/
public function test_update_topic_content() {
// Set as multisite.
self::$plugin_options['multisite-configuration-enabled'] = 1;
$this->sync_topic->setup_options( self::$plugin_options );
@ -46,5 +46,5 @@ class SyncDiscourseTopicMultisiteTest extends SyncDiscourseTopicTest {
// Cleanup
wp_delete_post( $post_id );
restore_current_blog();
}
}
}

View file

@ -32,7 +32,7 @@ class DiscourseCommentFormatterTest extends UnitTest {
protected $discourse_post;

/**
* Wordpress post id
* WordPress post id
*
* @access protected
* @var int

View file

@ -30,8 +30,8 @@ class DiscourseCommentTest extends UnitTest {
public function setUp(): void {
parent::setUp();

$comment_formatter = new DiscourseCommentFormatter();
$this->comment = new DiscourseComment( $comment_formatter );
$comment_formatter = new DiscourseCommentFormatter();
$this->comment = new DiscourseComment( $comment_formatter );
self::$plugin_options['enable-discourse-comments'] = true;
$this->comment->setup_options( self::$plugin_options );
$this->comment->setup_logger();
@ -145,12 +145,12 @@ class DiscourseCommentTest extends UnitTest {
$private_category_id = null;

foreach ( $categories as $category ) {
if ( false === $category->read_restricted ) {
if ( false === $category->read_restricted ) {
$public_category_id = $category->id;
}
if ( true === $category->read_restricted ) {
}
if ( true === $category->read_restricted ) {
$private_category_id = $category->id;
}
}
}

// Add the posts.
@ -202,12 +202,12 @@ class DiscourseCommentTest extends UnitTest {
$private_category_id = null;

foreach ( $categories as $category ) {
if ( false === $category->read_restricted ) {
if ( false === $category->read_restricted ) {
$public_category_id = $category->id;
}
if ( true === $category->read_restricted ) {
}
if ( true === $category->read_restricted ) {
$private_category_id = $category->id;
}
}
}

// Add the posts.

View file

@ -15,66 +15,66 @@ use WPDiscourse\Test\UnitTest;
*/
class DiscourseSSOTest extends UnitTest {

/**
* User id
*
* @access protected
* @var int
*/
protected $user_id;
/**
* User id
*
* @access protected
* @var int
*/
protected $user_id;

/**
* Secret
*
* @access protected
* @var string
*/
protected $secret;
/**
* Secret
*
* @access protected
* @var string
*/
protected $secret;

/**
* Nonce
*
* @access protected
* @var string
*/
protected $nonce;
/**
* Nonce
*
* @access protected
* @var string
*/
protected $nonce;

/**
* Query vars
*
* @access protected
* @var array
*/
protected $query_vars;
/**
* Query vars
*
* @access protected
* @var array
*/
protected $query_vars;

/**
* Client
*
* @access protected
* @var \WPDiscourse\DiscourseSSO\DiscourseSSO
*/
protected $discourse_sso;
/**
* Client
*
* @access protected
* @var \WPDiscourse\DiscourseSSO\DiscourseSSO
*/
protected $discourse_sso;

/**
* Signaure
*
* @access protected
* @var string
*/
protected $signature;
/**
* Signaure
*
* @access protected
* @var string
*/
protected $signature;

/**
* Payload
*
* @access protected
* @var string
*/
protected $payload;
/**
* Payload
*
* @access protected
* @var string
*/
protected $payload;

public function setUp(): void {
$this->secret = 'secret';
$this->nonce = 'abcd';
$this->payload = base64_encode( "nonce={$this->nonce}" );
public function setUp(): void {
$this->secret = 'secret';
$this->nonce = 'abcd';
$this->payload = base64_encode( "nonce={$this->nonce}" );
$this->signature = hash_hmac( 'sha256', $this->payload, $this->secret );

self::$plugin_options['sso-secret'] = $this->secret;
@ -88,69 +88,69 @@ class DiscourseSSOTest extends UnitTest {
'sso' => $this->payload,
'sig' => rawurlencode( $this->signature ),
);
$this->user_id = self::factory()->user->create();
}
$this->user_id = self::factory()->user->create();
}

public function tearDown(): void {
public function tearDown(): void {
parent::tearDown();

$_GET['request'] = null;
delete_user_meta( $this->user_id, 'discourse_sso_user_id', true );
}
}

/**
* sso_parse_request without a user redirects to login with correct redirect_to url.
*
*/
public function test_sso_parse_request_no_user() {
$parse_result = $this->discourse_sso->sso_parse_request( (object) array( 'query_vars' => $this->query_vars ) );
/**
* sso_parse_request without a user redirects to login with correct redirect_to url.
*
*/
public function test_sso_parse_request_no_user() {
$parse_result = $this->discourse_sso->sso_parse_request( (object) array( 'query_vars' => $this->query_vars ) );
$wp_redirect_url = add_query_arg( $this->payload, rawurlencode( $this->signature ) );
$wp_login_url = wp_login_url( esc_url_raw( $wp_redirect_url ) );
$wp_login_url = wp_login_url( esc_url_raw( $wp_redirect_url ) );

$this->assertEquals( $parse_result, $wp_login_url );
}
}

/**
* sso_parse_request with a user validates payload and redirects to Discourse.
*
*/
public function test_sso_parse_request_user() {
$user = wp_set_current_user( $this->user_id );
/**
* sso_parse_request with a user validates payload and redirects to Discourse.
*
*/
public function test_sso_parse_request_user() {
$user = wp_set_current_user( $this->user_id );
$parse_result = $this->discourse_sso->sso_parse_request( (object) array( 'query_vars' => $this->query_vars ) );

$params = array_merge( $this->discourse_sso->get_sso_params( $user ), array( 'nonce' => $this->nonce ) );
$payload = base64_encode( http_build_query( $params ) );
$signature = hash_hmac( 'sha256', $payload, $this->secret );
$query_vars = array(
$params = array_merge( $this->discourse_sso->get_sso_params( $user ), array( 'nonce' => $this->nonce ) );
$payload = base64_encode( http_build_query( $params ) );
$signature = hash_hmac( 'sha256', $payload, $this->secret );
$query_vars = array(
'sso' => $payload,
'sig' => $signature,
);
$discourse_url = self::$plugin_options['url'] . '/session/sso_login?' . http_build_query( $query_vars );

$this->assertEquals( $parse_result, $discourse_url );
}
}

/**
* sso_parse_request handles logout requests from Discourse
*
*/
public function test_sso_parse_request_logout() {
/**
* sso_parse_request handles logout requests from Discourse
*
*/
public function test_sso_parse_request_logout() {
$user = wp_set_current_user( $this->user_id );

$_GET['request'] = 'logout';
$this->discourse_sso->sso_parse_request( (object) array( 'query_vars' => array() ) );

$this->assertEquals( is_user_logged_in(), false );
}
}

/**
* sso_parse_request handles invalid signature
*
*/
public function test_sso_parse_request_invalid_signature() {
/**
* sso_parse_request handles invalid signature
*
*/
public function test_sso_parse_request_invalid_signature() {
$user = wp_set_current_user( $this->user_id );

$query_vars = array(
$query_vars = array(
'sso' => $this->query_vars['sso'],
'sig' => 'i2v0a8l9i6d',
);
@ -161,17 +161,17 @@ class DiscourseSSOTest extends UnitTest {

$log = $this->get_last_log();
$this->assertMatchesRegularExpression( '/sso_provider.ERROR: parse_request.invalid_sso/', $log );
}
}

/**
* sso_parse_request handles invalid nonce
*
*/
public function test_sso_parse_request_invalid_nonce() {
/**
* sso_parse_request handles invalid nonce
*
*/
public function test_sso_parse_request_invalid_nonce() {
$user = wp_set_current_user( $this->user_id );

$payload = base64_encode( "not_nonce={$this->nonce}" );
$query_vars = array(
$payload = base64_encode( "not_nonce={$this->nonce}" );
$query_vars = array(
'sso' => $payload,
'sig' => hash_hmac( 'sha256', $payload, $this->secret ),
);
@ -184,13 +184,13 @@ class DiscourseSSOTest extends UnitTest {
$log = $this->get_last_log();
$this->assertMatchesRegularExpression( '/sso_provider.ERROR: parse_request.invalid_sso/', $log );
$this->assertMatchesRegularExpression( '/"message":"' . $error_message . '"/', $log );
}
}

/**
* logout_from_discourse logs out user from Discourse
*
*/
public function test_logout_from_discourse() {
/**
* logout_from_discourse logs out user from Discourse
*
*/
public function test_logout_from_discourse() {
$user = wp_set_current_user( $this->user_id );

$second_request = array(
@ -205,13 +205,13 @@ class DiscourseSSOTest extends UnitTest {

$discourse_user_id = get_user_meta( $user->ID, 'discourse_sso_user_id', true );
$this->assertEquals( $discourse_user_id, $discourse_user->user->id );
}
}

/**
* logout_from_discourse handles failure to get Discourse user
*
*/
public function test_logout_from_discourse_failed_to_get_discourse_user() {
/**
* logout_from_discourse handles failure to get Discourse user
*
*/
public function test_logout_from_discourse_failed_to_get_discourse_user() {
$user = wp_set_current_user( $this->user_id );

$request = array(
@ -229,15 +229,15 @@ class DiscourseSSOTest extends UnitTest {
$log = $this->get_last_log();
$this->assertMatchesRegularExpression( '/sso_provider.ERROR: logout.discourse_user/', $log );
$this->assertMatchesRegularExpression( '/"message":"' . $error_message . '"/', $log );
}
}

/**
* logout_from_discourse handles failure to logout
*
*/
public function test_logout_from_discourse_failed_to_logout() {
$user = wp_set_current_user( $this->user_id );
$response = $this->build_response( 'not_found' );
/**
* logout_from_discourse handles failure to logout
*
*/
public function test_logout_from_discourse_failed_to_logout() {
$user = wp_set_current_user( $this->user_id );
$response = $this->build_response( 'not_found' );
$second_request = array(
'url' => 'log_out',
'method' => 'POST',
@ -254,5 +254,5 @@ class DiscourseSSOTest extends UnitTest {
$log = $this->get_last_log();
$this->assertMatchesRegularExpression( '/sso_provider.ERROR: logout.response_error/', $log );
$this->assertMatchesRegularExpression( '/"message":"' . $error_message . '"/', $log );
}
}
}

View file

@ -71,8 +71,8 @@ class FileHandlerTest extends UnitTest {
$log_files = glob( $manager->logs_dir . '/*.log' );
$this->assertCount( 1, $log_files );

$log_file = $log_files[0];
$last_entry = shell_exec( "tail -n 1 $log_file" );
$log_file = $log_files[0];
$last_entry = shell_exec( "tail -n 1 $log_file" );
$this->assertMatchesRegularExpression( '/New Log/', $last_entry );
}

@ -97,7 +97,7 @@ class FileHandlerTest extends UnitTest {
$line = fgets( $handle );

if ( strpos( $line, 'Multi Log' ) !== false ) {
$matching_line_count++;
++$matching_line_count;
}
}
fclose( $handle );

View file

@ -43,10 +43,10 @@ class LogViewerTest extends UnitTest {
* Teardown each test.
*/
public function tearDown(): void {
parent::tearDown();
parent::tearDown();

self::$plugin_options['logs-enabled'] = 1;
$this->viewer->setup_options( self::$plugin_options );
self::$plugin_options['logs-enabled'] = 1;
$this->viewer->setup_options( self::$plugin_options );
}

/**

View file

@ -82,8 +82,8 @@ class LoggerTest extends UnitTest {
*/
public function test_create_logs_not_enabled() {
self::$plugin_options['logs-enabled'] = 0;
$logger = Logger::create( 'test', self::$plugin_options );
$handlers = $logger->getHandlers();
$logger = Logger::create( 'test', self::$plugin_options );
$handlers = $logger->getHandlers();

$this->assertCount( 1, $handlers );
$this->assertContainsOnlyInstancesOf( NullHandler::class, $handlers );

View file

@ -16,71 +16,71 @@ use WPDiscourse\Test\UnitTest;
*/
class SSOClientTest extends UnitTest {

/**
* Discourse user id
*
* @access protected
* @var int
*/
protected $discourse_user_id;
/**
* Discourse user id
*
* @access protected
* @var int
*/
protected $discourse_user_id;

/**
* User id
*
* @access protected
* @var int
*/
protected $user_id;
/**
* User id
*
* @access protected
* @var int
*/
protected $user_id;

/**
* Secret
*
* @access protected
* @var string
*/
protected $secret;
/**
* Secret
*
* @access protected
* @var string
*/
protected $secret;

/**
* Nonce
*
* @access protected
* @var string
*/
protected $nonce;
/**
* Nonce
*
* @access protected
* @var string
*/
protected $nonce;

/**
* Query args
*
* @access protected
* @var array
*/
protected $query_args;
/**
* Query args
*
* @access protected
* @var array
*/
protected $query_args;

/**
* Client
*
* @access protected
* @var \WPDiscourse\SSOClient\Client
*/
protected $sso_client;
/**
* Client
*
* @access protected
* @var \WPDiscourse\SSOClient\Client
*/
protected $sso_client;

/**
* Signaure
*
* @access protected
* @var string
*/
protected $signature;
/**
* Signaure
*
* @access protected
* @var string
*/
protected $signature;

/**
* Payload
*
* @access protected
* @var array
*/
protected $payload;
/**
* Payload
*
* @access protected
* @var array
*/
protected $payload;

public static function setUpBeforeClass(): void {
public static function setUpBeforeClass(): void {
parent::initialize_shared_variables();
wp_logout();

@ -88,9 +88,9 @@ class SSOClientTest extends UnitTest {
// See https://core.trac.wordpress.org/ticket/35488
wp_set_current_user( 0 );
}
}
}

public function setUp(): void {
public function setUp(): void {
parent::setUp();

$this->discourse_user_id = 5;
@ -122,9 +122,9 @@ class SSOClientTest extends UnitTest {

$_GET['sso'] = $this->payload;
$_GET['sig'] = rawurlencode( $this->signature );
}
}

public function tearDown(): void {
public function tearDown(): void {
parent::tearDown();

$_GET['sso'] = null;
@ -137,12 +137,12 @@ class SSOClientTest extends UnitTest {
// See https://core.trac.wordpress.org/ticket/35488
wp_set_current_user( 0 );
}
}
}

/**
* parse_request authenticates a user and updates their metadata correctly.
*/
public function test_parse_request() {
/**
* parse_request authenticates a user and updates their metadata correctly.
*/
public function test_parse_request() {
add_user_meta( $this->user_id, 'discourse_sso_user_id', $this->discourse_user_id );

$parse_result = $this->sso_client->parse_request();
@ -152,12 +152,12 @@ class SSOClientTest extends UnitTest {
$this->assertEquals( get_user_meta( $user->ID, 'discourse_username', true ), $this->query_args['username'] );
$this->assertEquals( get_user_meta( $user->ID, 'discourse_sso_user_id', true ), $this->query_args['external_id'] );
$this->assertEquals( $parse_result, $this->query_args['return_sso_url'] );
}
}

/**
* parse_request handles invalid signatures correctly.
*/
public function test_parse_request_invalid_signature() {
/**
* parse_request handles invalid signatures correctly.
*/
public function test_parse_request_invalid_signature() {
$_GET['sig'] = rawurlencode( hash_hmac( 'sha256', $this->payload, 'wrong-secret' ) );
$parse_result = $this->sso_client->parse_request();

@ -166,12 +166,12 @@ class SSOClientTest extends UnitTest {

$log = $this->get_last_log();
$this->assertMatchesRegularExpression( '/sso_client.ERROR: parse_request.invalid_signature/', $log );
}
}

/**
* parse_request handles failure to get_user_id correctly
*/
public function test_parse_request_get_user_failed() {
/**
* parse_request handles failure to get_user_id correctly
*/
public function test_parse_request_get_user_failed() {
$this->query_args['username'] = '';
$this->query_args['email'] = '';
$this->payload = base64_encode( http_build_query( $this->query_args ) );
@ -185,12 +185,12 @@ class SSOClientTest extends UnitTest {

$log = $this->get_last_log();
$this->assertMatchesRegularExpression( '/sso_client.ERROR: parse_request.get_user_id/', $log );
}
}

/**
* parse_request handles failure to update_user correctly
*/
public function test_parse_request_update_user_failed() {
/**
* parse_request handles failure to update_user correctly
*/
public function test_parse_request_update_user_failed() {
add_filter( 'wpdc_sso_client_updated_user', array( $this, 'invalid_update_user_filter' ), 10, 2 );

$parse_result = $this->sso_client->parse_request();
@ -202,12 +202,12 @@ class SSOClientTest extends UnitTest {
$this->assertMatchesRegularExpression( '/sso_client.ERROR: parse_request.update_user/', $log );

remove_filter( 'wpdc_sso_client_updated_user', array( $this, 'invalid_update_user_filter' ), 10 );
}
}

/**
* parse_request does not create new users if user creation is disabled.
*/
public function test_parse_request_disable_create_user() {
/**
* parse_request does not create new users if user creation is disabled.
*/
public function test_parse_request_disable_create_user() {
self::$plugin_options['sso-client-disable-create-user'] = 1;
$this->sso_client->setup_options( self::$plugin_options );

@ -216,10 +216,10 @@ class SSOClientTest extends UnitTest {
$log = $this->get_last_log();
$this->assertMatchesRegularExpression( '/sso_client.ERROR: parse_request.get_user_id/', $log );
$this->assertMatchesRegularExpression( '/"code":"no_matching_user"/', $log );
}
}

public function invalid_update_user_filter( $updated_user, $query ) {
public function invalid_update_user_filter( $updated_user, $query ) {
$updated_user['ID'] = 23;
return $updated_user;
}
}
}

View file

@ -14,91 +14,91 @@ use WPDiscourse\Test\RemotePost;
* Base class for WPDiscourse unit tests
*/
class UnitTest extends \WP_UnitTestCase {
use Logging;
use RemotePost;
use Logging;
use RemotePost;

/**
* Connection options.
*
* @access public
* @var object
*/
public static $connection_options;
/**
* Connection options.
*
* @access public
* @var object
*/
public static $connection_options;

/**
* Publish options.
*
* @access public
* @var object
*/
public static $publish_options;
/**
* Publish options.
*
* @access public
* @var object
*/
public static $publish_options;

/**
* Log options.
*
* @access public
* @var object
*/
public static $log_options;
/**
* Log options.
*
* @access public
* @var object
*/
public static $log_options;

/**
* Plugin options.
*
* @access public
* @var object
*/
public static $plugin_options;
/**
* Plugin options.
*
* @access public
* @var object
*/
public static $plugin_options;

/**
* WP_Post attributes.
*
* @access public
* @var object
*/
public static $post_atts;
/**
* WP_Post attributes.
*
* @access public
* @var object
*/
public static $post_atts;

/**
* Params used in remote posts.
*
* @access public
* @var object
*/
public static $remote_post_params;
/**
* Params used in remote posts.
*
* @access public
* @var object
*/
public static $remote_post_params;

/**
* URL of mock discourse instance.
*
* @access public
* @var string
*/
public static $discourse_url;
/**
* URL of mock discourse instance.
*
* @access public
* @var string
*/
public static $discourse_url;

/**
* Setup test class
*/
public static function setUpBeforeClass(): void {
/**
* Setup test class
*/
public static function setUpBeforeClass(): void {
self::initialize_shared_variables();
}
}

/**
* Setup each test.
*/
public function setUp(): void {
/**
* Setup each test.
*/
public function setUp(): void {
}

/**
* Teardown each test.
*/
public function tearDown(): void {
/**
* Teardown each test.
*/
public function tearDown(): void {
$this->clear_logs();
remove_all_filters( 'pre_http_request' );
\Mockery::close();
}
}

/**
* Initialize shared tests.
*/
public static function initialize_shared_variables() {
/**
* Initialize shared tests.
*/
public static function initialize_shared_variables() {
self::$discourse_url = 'http://meta.discourse.org';
self::$connection_options = array(
'url' => self::$discourse_url,
@ -124,5 +124,5 @@ class UnitTest extends \WP_UnitTestCase {
),
'post_status' => 'publish',
);
}
}
}

View file

@ -2,7 +2,7 @@
/**
* Plugin Name: WP-Discourse
* Description: Use Discourse as a community engine for your WordPress blog
* Version: 2.5.6
* Version: 2.5.7
* Requires at least: 5.1
* Requires PHP: 5.6
* Author: Discourse
@ -36,7 +36,7 @@ define( 'WPDISCOURSE_PATH', plugin_dir_path( __FILE__ ) );
define( 'WPDISCOURSE_URL', plugins_url( '', __FILE__ ) );
define( 'MIN_WP_VERSION', '4.7' );
define( 'MIN_PHP_VERSION', '5.6.0' );
define( 'WPDISCOURSE_VERSION', '2.5.6' );
define( 'WPDISCOURSE_VERSION', '2.5.7' );
define( 'WPDISCOURSE_LOGO_URL', WPDISCOURSE_PATH . 'assets/icon.svg' );
$base64 = base64_encode( file_get_contents( WPDISCOURSE_LOGO_URL ) );
define( 'WPDISCOURSE_LOGO', "data:image/svg+xml;base64,$base64" );