Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a theme selector #393

Merged
merged 3 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions THEMES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Friends Themes

Here you can find themes that have been created for the Friends plugin.

- [Mastodon-like interface](https://github.com/akirk/friends-mastodon-like-interface)

If you want to create your own theme, take a look at the [wiki page on Writing Themes](https://github.com/akirk/friends/wiki/Writing-Themes).
2 changes: 1 addition & 1 deletion friends.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion friends.css.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion friends.scss
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ h2#page-title a.dashicons {
bottom: 1.5rem;
-webkit-overflow-scrolling: touch;
overflow-y: auto;
padding: .5rem 1.5rem;
padding: .5rem;
position: fixed;
top: 5.5rem;
width: 12rem;
Expand Down
28 changes: 25 additions & 3 deletions includes/class-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -595,9 +595,25 @@ public function process_admin_settings() {
'collapsed',
)
) ) {
update_option( 'friends_frontend_default_view', wp_unslash( $_POST['frontend_default_view'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
update_user_option( get_current_user_id(), 'friends_frontend_default_view', wp_unslash( $_POST['frontend_default_view'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
} else {
delete_option( 'friends_frontend_default_view' );
delete_option( get_current_user_id(), 'friends_frontend_default_view' );
}

foreach ( array_merge( array( '' ), get_post_format_slugs() ) as $post_type ) {
$name = 'friends_frontend_theme';
if ( $post_type ) {
$name = 'friends_frontend_theme_' . $post_type;
}
$theme = 'default';
if ( isset( $_POST[ $name ] ) && in_array( $theme, array_keys( Frontend::get_themes() ) ) ) {
$theme = wp_unslash( $_POST[ $name ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
}
if ( 'default' === $theme ) {
delete_user_option( get_current_user_id(), $name );
} else {
update_user_option( get_current_user_id(), $name, $theme );
}
}

if ( isset( $_GET['_wp_http_referer'] ) ) {
Expand Down Expand Up @@ -667,12 +683,17 @@ public function render_admin_settings() {
}

$post_stats = Friends::get_post_stats();
$post_type_themes = array();
foreach ( get_post_format_slugs() as $slug ) {
$post_type_themes[ 'frontend_theme_' . $slug ] = get_user_option( 'friends_frontend_theme_' . $slug );
}

Friends::template_loader()->get_template_part(
'admin/settings',
null,
array_merge(
Friends::get_post_stats(),
$post_type_themes,
array(
'force_enable_post_formats' => get_option( 'friends_force_enable_post_formats' ),
'post_format_strings' => get_post_format_strings(),
Expand All @@ -683,7 +704,8 @@ public function render_admin_settings() {
'retention_number' => Friends::get_retention_number(),
'retention_days_enabled' => get_option( 'friends_enable_retention_days' ),
'retention_number_enabled' => get_option( 'friends_enable_retention_number' ),
'frontend_default_view' => get_option( 'friends_frontend_default_view', 'expanded' ),
'frontend_default_view' => get_user_option( 'friends_frontend_default_view', 'expanded' ),
'frontend_theme' => get_user_option( 'friends_frontend_theme' ),
'blocks_everywhere' => get_user_option( 'friends_blocks_everywhere' ),
)
)
Expand Down
57 changes: 57 additions & 0 deletions includes/class-friends.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,54 @@ public function __construct() {
new Automatic_Status( $this );
$this->register_hooks();
load_plugin_textdomain( 'friends', false, FRIENDS_PLUGIN_FILE . '/languages/' );

/**
* Friends has loaded.
*
* @param Friends $friends The friends object.
*
* You can now assume that all the Friends hooks and objects are available.
*
* Example:
* ```php
* add_action( 'friends_loaded', function( Friends $friends ) {
* add_action( 'init', 'initialize_my_plugin' );
* } );
* ```
*/
do_action( 'friends_loaded', $this );

/**
* Time to register your parser.
*
* @param Feed $feed The feed object.
*
* You'll receive the feed object on which you need to call `register_parser()`.
*
* Example:
* ```php
* add_action( 'friends_load_parsers', function( Friends\Feed $friends_feed ) {
* $friends_feed->register_parser( 'simplepie', new Feed_Parser_SimplePie( $friends_feed ) );
* } );
* ```
*/
do_action( 'friends_load_parsers', $this->feed );

/**
* Time to register your theme.
*
* @param Frontend $frontend The frontend object.
*
* You'll receive the frontend object on which you need to call `register_theme()`.
*
* Example:
* ```php
* add_action( 'friends_load_themes', function( Friends\Frontend $friends_frontend ) {
* $friends_frontend->register_theme( 'Mastodon', 'mastodon' );
* } );
* ```
*/
do_action( 'friends_load_themes', $this->frontend );
}

/**
Expand Down Expand Up @@ -515,6 +561,17 @@ public static function upgrade_plugin() {
}
}

if ( version_compare( $previous_version, '3.1.5', '<' ) ) {
// Migrate the option friends_frontend_default_view to a user option.
$users = User_Query::all_admin_users();
foreach ( $users->get_results() as $user ) {
$default_view = get_option( 'friends_frontend_default_view' );
if ( $default_view ) {
$user->update_user_option( 'friends_frontend_default_view', $default_view );
}
}
}

update_option( 'friends_plugin_version', Friends::VERSION );
}

Expand Down
146 changes: 109 additions & 37 deletions includes/class-frontend.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,25 @@ class Frontend {
public $template = false;

/**
* Whether a reaciton is being displayed
* Whether a reaction is being displayed.
*
* @var string|false
*/
public $reaction = false;

/**
* The current theme.
*
* @var string
*/
private $theme = 'default';
/**
* Available themes.
*
* @var array
*/
private static $themes = array();

/**
* Constructor
*
Expand Down Expand Up @@ -96,6 +109,10 @@ private function register_hooks() {
add_filter( 'friends_unreblog', array( get_called_class(), 'unreblog' ), 10, 2 );
add_action( 'wp_untrash_post_status', array( $this, 'untrash_post_status' ), 10, 2 );
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
add_action( 'template_redirect', array( $this, 'load_theme' ) );
add_action( 'customize_loaded_components', array( $this, 'ensure_widget_editing' ) );
add_action( 'friends_load_theme_default', array( $this, 'default_theme' ) );
add_action( 'friends_template_paths', array( $this, 'friends_template_paths' ) );
add_action( 'wp_enqueue_scripts', array( $this, 'dequeue_scripts' ), 99999 );
add_action( 'wp_footer', array( $this, 'dequeue_scripts' ) );
add_action( 'the_post', array( $this, 'the_post' ), 10, 2 );
Expand Down Expand Up @@ -217,49 +234,90 @@ public function register_friends_sidebar() {
}
}

public function ensure_widget_editing( $components ) {
if ( ! is_array( $components ) ) {
$components = array();
}
$components[] = 'widgets';
return $components;
}

public function load_theme() {
if ( ! is_user_logged_in() || ! Friends::on_frontend() ) {
return;
}
$theme = get_user_option( 'friends_frontend_theme', 'default' );
if ( $this->post_format ) {
$post_type_theme = get_user_option( 'friends_frontend_theme_' . $this->post_format, get_current_user_id() );
if ( $post_type_theme ) {
$theme = $post_type_theme;
}
}
if ( ! has_action( 'friends_load_theme_' . $theme ) ) {
$theme = 'default';
}
$this->theme = $theme;
do_action( 'friends_load_theme_' . $theme );
}

public function friends_template_paths( $file_paths ) {
$backup_file_paths = $file_paths;
if ( has_filter( 'friends_template_paths_theme_' . $this->theme ) ) {
$file_paths = apply_filters( 'friends_template_paths_theme_' . $this->theme, $file_paths );
}
if ( empty( $file_paths ) ) {
return $backup_file_paths;
}

return $file_paths;
}

public function default_theme() {
$handle = 'friends';
$file = 'friends.css';
$version = Friends::VERSION;
wp_enqueue_style( $handle, plugins_url( $file, FRIENDS_PLUGIN_FILE ), array(), apply_filters( 'friends_debug_enqueue', $version, $handle, dirname( FRIENDS_PLUGIN_FILE ) . '/' . $file ) );
}

/**
* Reference our script for the /friends page
*/
public function enqueue_scripts() {
if ( ! is_user_logged_in() || Friends::on_frontend() ) {
return;
}
global $wp_query;

if ( is_user_logged_in() && Friends::on_frontend() ) {
$handle = 'friends';
$file = 'friends.js';
$version = Friends::VERSION;
wp_enqueue_script( $handle, plugins_url( $file, FRIENDS_PLUGIN_FILE ), array( 'common', 'jquery', 'wp-util' ), apply_filters( 'friends_debug_enqueue', $version, $handle, dirname( FRIENDS_PLUGIN_FILE ) . '/' . $file ), true );

$query_vars = serialize( $this->get_minimal_query_vars( $wp_query->query_vars ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize

$variables = array(
'emojis_json' => plugins_url( 'emojis.json', FRIENDS_PLUGIN_FILE ),
'ajax_url' => admin_url( 'admin-ajax.php' ),
'rest_base' => rest_url( 'friends/v1/' ),
'rest_nonce' => wp_create_nonce( 'wp_rest' ),
'text_link_expired' => __( 'The link has expired. A new link has been generated, please click it again.', 'friends' ),
'text_undo' => __( 'Undo' ), // phpcs:ignore WordPress.WP.I18n.MissingArgDomain
'text_trash_post' => __( 'Trash this post', 'friends' ),
'text_del_convers' => __( 'Do you really want to delete this conversation?', 'friends' ),
'text_no_more_posts' => __( 'No more posts available.', 'friends' ),
'text_checking_url' => __( 'Checking URL.', 'friends' ),
'text_refreshed' => __( 'Refreshed', 'friends' ),
'text_refreshing' => __( 'Refreshing', 'friends' ),
'refresh_now' => isset( $_GET['refresh'] ) ? 'true' : 'false', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
'query_vars' => $query_vars,
'qv_sign' => sha1( wp_salt( 'nonce' ) . $query_vars ),
'current_page' => get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1,
'max_page' => $wp_query->max_num_pages,
);

// translators: %s is a user handle.
$variables['text_confirm_delete_follower'] = __( 'Do you really want to delete the follower %s?', 'friends' );
wp_localize_script( 'friends', 'friends', $variables );
$handle = 'friends';
$file = 'friends.js';
$version = Friends::VERSION;
wp_enqueue_script( $handle, plugins_url( $file, FRIENDS_PLUGIN_FILE ), array( 'common', 'jquery', 'wp-util' ), apply_filters( 'friends_debug_enqueue', $version, $handle, dirname( FRIENDS_PLUGIN_FILE ) . '/' . $file ), true );

$query_vars = serialize( $this->get_minimal_query_vars( $wp_query->query_vars ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize

$variables = array(
'emojis_json' => plugins_url( 'emojis.json', FRIENDS_PLUGIN_FILE ),
'ajax_url' => admin_url( 'admin-ajax.php' ),
'rest_base' => rest_url( 'friends/v1/' ),
'rest_nonce' => wp_create_nonce( 'wp_rest' ),
'text_link_expired' => __( 'The link has expired. A new link has been generated, please click it again.', 'friends' ),
'text_undo' => __( 'Undo' ), // phpcs:ignore WordPress.WP.I18n.MissingArgDomain
'text_trash_post' => __( 'Trash this post', 'friends' ),
'text_del_convers' => __( 'Do you really want to delete this conversation?', 'friends' ),
'text_no_more_posts' => __( 'No more posts available.', 'friends' ),
'text_checking_url' => __( 'Checking URL.', 'friends' ),
'text_refreshed' => __( 'Refreshed', 'friends' ),
'text_refreshing' => __( 'Refreshing', 'friends' ),
'refresh_now' => isset( $_GET['refresh'] ) ? 'true' : 'false', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
'query_vars' => $query_vars,
'qv_sign' => sha1( wp_salt( 'nonce' ) . $query_vars ),
'current_page' => get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1,
'max_page' => $wp_query->max_num_pages,
);

$handle = 'friends';
$file = 'friends.css';
$version = Friends::VERSION;
wp_enqueue_style( $handle, plugins_url( $file, FRIENDS_PLUGIN_FILE ), array(), apply_filters( 'friends_debug_enqueue', $version, $handle, dirname( FRIENDS_PLUGIN_FILE ) . '/' . $file ) );
}
// translators: %s is a user handle.
$variables['text_confirm_delete_follower'] = __( 'Do you really want to delete the follower %s?', 'friends' );
wp_localize_script( 'friends', 'friends', $variables );
}

public function dequeue_scripts() {
Expand Down Expand Up @@ -567,6 +625,20 @@ private static function calculate_read_time( $original_text ) {
return count( $words_array ) / $words_per_minute * 60 + $additional_time;
}

public function register_theme( $name, $slug ) {
self::$themes[ $slug ] = $name;
}

public static function get_themes() {
$themes = array_merge(
array(
'default' => __( 'Friends Default Theme', 'friends' ),
),
self::$themes
);

return $themes;
}
/**
* Handles the post loop on the Friends page.
*/
Expand Down
45 changes: 44 additions & 1 deletion templates/admin/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@
</td>
</tr>
<tr>
<th scope="row" rowspan="2"><?php esc_html_e( 'Frontend', 'friends' ); ?></th>
<th scope="row" rowspan="3"><?php esc_html_e( 'Frontend', 'friends' ); ?></th>
<td>
<fieldset>
<label for="frontend-default-view">
Expand All @@ -243,6 +243,49 @@
</fieldset>
</td>
</tr>
<tr>
<td>
<fieldset>
<label for="frontend-theme">
<span><?php esc_html_e( 'Main Theme:', 'friends' ); ?></span>
<select name="friends_frontend_theme" id="frontend-theme">
<?php foreach ( Friends\Frontend::get_themes() as $theme => $theme_name ) : ?>
<option value="<?php echo esc_attr( $theme ); ?>"<?php selected( $args['frontend_theme'], $theme ); ?>><?php echo esc_html( $theme_name ); ?></option>
<?php endforeach; ?>
</select>
</label>
<details><summary>Post Type Themes</summary>
<table>
<?php foreach ( $args['post_format_strings'] as $post_type_slug => $post_type_title ) : ?>
<tr>
<td><label for="frontend-theme-<?php echo esc_attr( $post_type_slug ); ?>"><?php echo esc_html( $post_type_title ); ?></label></td>
<td>
<select name="friends_frontend_theme_<?php echo esc_attr( $post_type_slug ); ?>" id="frontend-theme-<?php echo esc_attr( $post_type_slug ); ?>">
<option value=""><?php esc_html_e( 'Main Theme', 'friends' ); ?></option>
<?php foreach ( Friends\Frontend::get_themes() as $theme => $theme_name ) : ?>
<option value="<?php echo esc_attr( $theme ); ?>"<?php selected( $args[ 'frontend_theme_' . $post_type_slug ], $theme ); ?>><?php echo esc_html( $theme_name ); ?></option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php endforeach; ?>
</table>
</details>
</fieldset>
<p>
<?php
echo wp_kses_post(
sprintf(
// translators: %1$s is a link, %2$s is a link.
__( 'Check out the <a href=%1$s>available themes</a>, or <a href=%2$s>write your own</a>.', 'friends' ),
'"https://github.com/akirk/friends/blob/main/THEMES.md"',
'"https://github.com/akirk/friends/wiki/Writing-Themes"'
)
);
?>
</p>
</td>
</tr>
<?php if ( ! function_exists( 'classicpress_version' ) ) : ?>
<tr>
<td>
Expand Down
Loading