Initial commit

This commit is contained in:
Django Doucet 2019-12-26 16:11:20 -05:00
commit 3a3f1810f6
12 changed files with 1713 additions and 0 deletions

234
fediembedi-client.php Normal file
View File

@ -0,0 +1,234 @@
<?php
class Client
{
private $instance_url;
private $access_token;
private $app;
private static $acct_id;
public function __construct($instance_url, $access_token = '') {
$this->instance_url = $instance_url;
$this->access_token = $access_token;
}
public function setStatic($param){
self::$acct_id = $param;
}
public function getStatic(){
return self::$acct_id;
}
public function register_app($redirect_uri) {
$response = $this->_post('/api/v1/apps', array(
'client_name' => 'FediEmbedi for WordPress',
'redirect_uris' => $redirect_uri,
'scopes' => 'read',
'website' => get_site_url()
));
if (!isset($response->client_id)){
return "ERROR";
}
$this->app = $response;
$params = http_build_query(array(
'response_type' => 'code',
'redirect_uri' => $redirect_uri,
'scope' => 'read',
'client_id' =>$this->app->client_id
));
return $this->instance_url.'/oauth/authorize?'.$params;
}
public function verify_credentials($access_token){
$headers = array(
'Authorization'=>'Bearer '.$access_token
);
$response = $this->_get('/api/v1/accounts/verify_credentials', null, $headers);
if(property_exists($response, 'id')){
$this->setStatic($response->id);
}
return $response;
}
public function get_bearer_token($client_id, $client_secret, $code, $redirect_uri) {
$response = $this->_post('/oauth/token',array(
'grant_type' => 'authorization_code',
'redirect_uri' => $redirect_uri,
'client_id' => $client_id,
'client_secret' => $client_secret,
'code' => $code
));
return $response;
}
public function get_client_id() {
return $this->app->client_id;
}
public function get_client_secret() {
return $this->app->client_secret;
}
public function getStatus($media = 'false', $pinned = 'false', $replies = 'false', $max_id = null, $since_id = null, $min_id = null, $limit = 10, $reblogs = 'false') {
$headers = array(
'Authorization'=> 'Bearer '.$this->access_token
);
$account_id = self::$acct_id;
$query = http_build_query(array(
'only_media' => $media,
'pinned' => $pinned,
'exclude_replies' => $replies,
'max_id' => $max_id,
'since_id' => $since_id,
'min_id' => $min_id,
'limit' => $limit,
'exclude_reblogs' => $reblogs
));
$response = $this->_get("/api/v1/accounts/{$account_id}/statuses?{$query}", null, $headers);
return $response;
}
public function getAccount() {
$headers = array(
'Authorization'=> 'Bearer '.$this->access_token
);
$account_id = self::$acct_id;
$response = $this->_get("/api/v1/accounts/{$account_id}", null, $headers);
return $response;
}
public function getInstance() {
$headers = array(
'Authorization'=> 'Bearer '.$this->access_token
);
$account_id = self::$acct_id;
$response = $this->_get("/api/v1/instance", null, $headers);
return $response;
}
public function postStatus($status, $mode, $media = '', $spoiler_text = '') {
$headers = array(
'Authorization'=> 'Bearer '.$this->access_token
);
$response = $this->_post('/api/v1/statuses', array(
'status' => $status,
'visibility' => $mode,
'spoiler_text' => $spoiler_text,
'media_ids[]' => $media
), $headers);
return $response;
}
public function create_attachment($media_path) {
$filename =basename($media_path);
$mime_type = mime_content_type($media_path);
$boundary ='hlx'.time();
$headers = array (
'Authorization'=> 'Bearer '.$this->access_token,
'Content-Type' => 'multipart/form-data; boundary='. $boundary,
);
$nl = "\r\n";
$data = '--'.$boundary.$nl;
$data .= 'Content-Disposition: form-data; name="file"; filename="'.$filename.'"'.$nl;
$data .= 'Content-Type: '. $mime_type .$nl.$nl;
$data .= file_get_contents($media_path) .$nl;
$data .= '--'.$boundary.'--';
$response = $this->_post('/api/v1/media', $data, $headers);
return $response;
}
private function _post($url, $data = array(), $headers = array()) {
return $this->post($this->instance_url.$url, $data, $headers);
}
public function _get($url, $data = array(), $headers = array()) {
return $this->get($this->instance_url.$url, $data, $headers);
}
private function post($url, $data = array(), $headers = array()) {
$args = array(
'headers' => $headers,
'body'=> $data,
'redirection' => 5
);
$response = wp_remote_post( $this->getValidURL($url), $args );
if ( is_wp_error( $response ) ) {
$error_message = $response->get_error_message();
} else {
$responseBody = wp_remote_retrieve_body($response);
return json_decode($responseBody);
}
return $response;
}
public function get($url, $data = array(), $headers = array()) {
$args = array(
'headers' => $headers,
'redirection' => 5
);
$response = wp_remote_get( $this->getValidURL($url), $args );
if ( is_wp_error( $response ) ) {
$error_message = $response->get_error_message();
} else {
$responseBody = wp_remote_retrieve_body($response);
return json_decode($responseBody);
}
return $response;
}
public function dump($value){
echo '<pre>';
print_r($value);
echo '</pre>';
}
private function getValidURL($url){
if ( $ret = parse_url($url) ) {
if ( !isset($ret["scheme"]) ){
$url = "http://{$url}";
}
}
return $url;
}
}

View File

@ -0,0 +1,132 @@
<?php
//fedi instance
$fedi_instance = get_option('fediembedi-instance');
$access_token = get_option('fediembedi-token');
$client = new \Client($fedi_instance, $access_token);
$cred = $client->verify_credentials($access_token);
//$profile = $client->getAccount();
//widget options
$show_header = (!empty($instance['show_header'])) ? $instance['show_header'] : '';
$only_media = (!empty($instance['only_media'])) ? $instance['only_media'] : '';
$pinned = (!empty($instance['pinned'])) ? $instance['pinned'] : '';
$exclude_replies = (!empty($instance['exclude_replies'])) ? $instance['exclude_replies'] : '';
$exclude_reblogs = (!empty($instance['exclude_reblogs'])) ? $instance['exclude_reblogs'] : '';
$query = http_build_query(array(
'only_media' => $only_media,
'pinned' => $pinned,
'exclude_replies' => $exclude_replies,
'limit' => 5,
'exclude_reblogs' => $exclude_reblogs
));
$status = $client->getStatus($only_media, $pinned, $exclude_replies, null, null, null, 10, $exclude_reblogs);
$instance_info = $client->getInstance();
if(WP_DEBUG_DISPLAY === true): echo '<details><summary>Debug</summary><pre>'; var_dump($instance_info); echo '</pre></details>'; endif;
?>
<div class="scrollable">
<div role="feed">
<?php if($show_header): ?>
<div class="account-timeline__header">
<div class="account__header">
<div class="account__header__image">
<div class="account__header__info"></div>
<?php if ($status[0]->account->header): echo "<img src=" . $status[0]->account->header . " loading='lazy'>"; endif; ?>
</div>
<div class="account__header__bar">
<div class="account__header__tabs">
<a href="<?php echo $status[0]->account->url; ?>" class="avatar" rel="noreferrer noopener" target="_blank">
<div class="account__avatar" style="width:90px; height: 90px; background-image: url('<?php echo $status[0]->account->avatar; ?>'); background-size: cover;"></div>
</a>
<div class="spacer"></div>
<div class="account__header__tabs__buttons">
<a href="<?php echo $status[0]->account->url; ?>" rel="noreferrer noopener" class="button logo-button" style="padding: 0px 16px; height: 36px; line-height: 36px;">Follow</a>
</div>
</div>
<div class="account__header__tabs__name">
<h1>
<span><?php echo $status[0]->account->display_name; ?></span>
<small><a href="" target="_blank" rel="noreferrer noopener"><?php echo $status[0]->account->url; ?></small>
</h1>
</div>
<div class="account__header__extra">
<div class="account__header__bio">
<div class="account__header__content">
<?php echo $status[0]->account->note; ?>
</div>
</div>
</div>
</div>
</div>
</div>
<?php endif; ?>
<?php foreach ($status as $statut) { ?>
<article>
<div tabindex="-1">
<div class="status__wrapper status__wrapper-public focusable" tabindex="0">
<div class="status__prepend">
<?php
if(!is_null($statut->reblog)): ?>
<div class="status__prepend-icon-wrapper"><i role="img" class="fa fa-retweet status__prepend-icon fa-fw"></i></div>
</div><?php
else: echo '</div>';
endif; ?>
<div class="status status-public">
<div class="status__info">
<a href="<?php if(is_null($statut->reblog)): echo $statut->url; else: echo $statut->reblog->url; endif; ?>" class="status__relative-time" target="_blank" rel="noopener">
<time datetime="<?php echo $statut->created_at; ?>"><?php
printf( _x( '%1$s ago', '%2$s = human-readable time difference', 'fediembedi' ),
human_time_diff(
wp_date("U", strtotime($statut->created_at))
)
);
?></time>
</a>
<a href="<?php if(is_null($statut->reblog)): echo $statut->account->url; else: echo $statut->reblog->account->url; endif; ?>" class="status__display-name" rel="noopener noreferrer" target="_blank">
<div class="status__avatar">
<div class="account__avatar" style="background-image: url(<?php if(is_null($statut->reblog)): echo $statut->account->avatar; else: echo $statut->reblog->account->avatar; endif; ?>); background-size: 40px; width: 40px; height: 40px;"></div>
</div>
<span class="display-name"><?php if(is_null($statut->reblog)): echo $statut->account->display_name; else: echo $statut->reblog->account->display_name; endif; ?></span>
</a>
</div>
<div class="status__content"><?php
if(!is_null($statut->reblog)):
$statut = $statut->reblog;
endif;
if(empty($statut->spoiler_text)):
echo $statut->content;
if(!is_null($statut->card)): ?>
<a href="<?php echo $statut->card->url; ?>" class="status-card compact" target="_blank" rel="noopener noreferrer">
<div class="status-card__image"><div class="status-card__image-image" style="background-image: url(<?php echo $statut->card->image; ?>);"></div></div>
<div class="status-card__content">
<strong class="status-card__title" title="<?php echo $statut->card->title; ?>"><?php echo htmlentities($statut->card->title); ?></strong>
<p class="status-card__description"><?php echo wp_trim_words(htmlentities($statut->card->description)); ?></p>
<span class="status-card__host"><?php echo $statut->card->url; ?></span>
</div>
</a>
<?php
endif;
else: echo '<details><summary>' . $statut->spoiler_text . '</summary>'. $statut->content . '</details>';
endif;
if(!empty($statut->media_attachments)):
foreach ($statut->media_attachments as $attachment) {
if (!empty($attachment->preview_url) && $attachment->type === 'image'):
echo "<img src='" . $attachment->preview_url . "' class='media-gallery__item' alt='" . $attachment->description . "' loading='lazy'>";
elseif($attachment->type === 'video'):
echo "<video src=" . $attachment->url . " controls poster='" . $attachment->preview_url . "' class='media-gallery__item' alt=" . $attachment->description . ">";
elseif($attachment->type === 'audio'):
echo "<audio src=" . $attachment->url . " controls poster='" . $attachment->preview_url . "' class='media-gallery__item' alt=" . $attachment->description . ">";
endif;
}
endif;
?></div>
</div>
</div>
</div>
</article>
<?php }
if(WP_DEBUG_DISPLAY === true): echo '<details><summary>Debug</summary><pre>'; var_dump($status); echo '</pre></details>'; endif; ?>
</div>
</div>

137
fediembedi-widget.php Normal file
View File

@ -0,0 +1,137 @@
<?php
class WP_Widget_fediembedi extends WP_Widget {
/**
* Sets up a new Search widget instance.
*
* @since 2.8.0
*/
public function __construct() {
$widget_ops = array(
'classname' => 'widget_fediembedi',
'description' => __( 'Display a profile timeline', 'fediembedi' ),
'customize_selective_refresh' => true,
);
parent::__construct( 'fediembedi', _x( 'FediEmbedi', 'fediembedi' ), $widget_ops );
}
/**
* Outputs the content for the current Search widget instance.
*
* @since 2.8.0
*
* @param array $args Display arguments including 'before_title', 'after_title',
* 'before_widget', and 'after_widget'.
* @param array $instance Settings for the current Search widget instance.
*/
public function widget( $args, $instance ) {
include(plugin_dir_path(__FILE__) . 'fediembedi-widget-template.php' );//fediembedi_widget_template
}
/**
* Outputs the settings form for the Search widget.
*
* @since 2.8.0
*
* @param array $instance Current settings.
*/
public function form( $instance ) {
$instance = wp_parse_args( (array) $instance, array( 'title' => '') );
//Radio inputs : https://wordpress.stackexchange.com/a/276659/87622
$show_header = (!empty( $instance['show_header'])) ? $instance['show_header'] : NULL;
$only_media = (!empty( $instance['only_media'])) ? $instance['only_media'] : NULL;
$pinned = (!empty($instance['pinned'])) ? $instance['pinned'] : NULL;
$exclude_replies = (!empty($instance['exclude_replies'])) ? $instance['exclude_replies'] : NULL;
$exclude_reblogs = (!empty($instance['exclude_reblogs'])) ? $instance['exclude_reblogs'] : NULL;
$remote_instance = get_option('fediembedi-instance');
$client = new \Client($remote_instance);
$instance_info = $client->getInstance();
$pixelfed = '';
if (strpos($instance_info->version, 'Pixelfed') !== false) {
$pixelfed = true;
}
?>
<p>
<label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:', 'fediembedi'); ?>
<input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($instance['title']); ?>" />
</label>
</p>
<p>
<label>
<input
type="checkbox"
<?php checked( $instance[ 'show_header' ], '1' ); ?>
id="<?php echo $this->get_field_id( '1' ); ?>"
name="<?php echo $this->get_field_name('show_header'); ?>"
value="1"
/><?php _e( 'Show header', 'fediembedi' ); ?>
</label>
<br>
<label>
<input
type="checkbox"
<?php checked( $instance[ 'only_media' ], '1' ); ?>
id="<?php echo $this->get_field_id( '1' ); ?>"
name="<?php echo $this->get_field_name('only_media'); ?>"
value="1"
/><?php _e( 'Only media', 'fediembedi' ); ?>
</label>
<br>
<label>
<input
type="checkbox"
<?php checked( $instance[ 'pinned' ], '1' ); ?>
id="<?php echo $this->get_field_id( '1' ); ?>"
name="<?php echo $this->get_field_name('pinned'); ?>"
value="1"
/><?php _e( 'Show pinned statuses', 'fediembedi' ); ?>
</label>
<br>
<label>
<input
type="checkbox"
<?php checked( $instance[ 'exclude_replies' ], '1' ); ?>
id="<?php echo $this->get_field_id( '1' ); ?>"
name="<?php echo $this->get_field_name('exclude_replies'); ?>"
value="1"
/><?php _e( 'Hide replies', 'fediembedi' ); ?>
</label>
<br>
<label>
<input
type="checkbox"
<?php checked( $instance[ 'exclude_reblogs' ], '1' ); ?>
id="<?php echo $this->get_field_id( '1' ); ?>"
name="<?php echo $this->get_field_name('exclude_reblogs'); ?>"
value="1"
/><?php _e( 'Hide reblogs', 'fediembedi' ); ?>
</label>
</p>
<?php
}
/**
* Handles updating settings for the current Search widget instance.
*
* @since 2.8.0
*
* @param array $new_instance New settings for this instance as input by the user via
* WP_Widget::form().
* @param array $old_instance Old settings for this instance.
* @return array Updated settings.
*/
public function update( $new_instance, $old_instance ) {
$instance = $old_instance;
$new_instance = wp_parse_args( (array) $new_instance, array( 'title' => '' ) );
$instance['title'] = sanitize_text_field( $new_instance['title'] );
$instance['show_header'] = $new_instance['show_header'];
$instance['only_media'] = $new_instance['only_media'];
$instance['pinned'] = $new_instance['pinned'];
$instance['exclude_replies'] = $new_instance['exclude_replies'];
$instance['exclude_reblogs'] = $new_instance['exclude_reblogs'];
return $instance;
}
}

275
fediembedi.php Normal file
View File

@ -0,0 +1,275 @@
<?php
/**
* Plugin Name: FediEmbedi
* Plugin URI: https://git.feneas.org/mediaformat/fediembedi
* GitHub Plugin URI: https://git.feneas.org/mediaformat/fediembedi
* Description: A widget to show your Mastodon profile timeline
* Version: 0.1.0
* Author: mediaformat
* Author URI: https://mediaformat.org
* License: GPL2
* Text Domain: fediembedi
* Domain Path: /languages
*/
namespace FediEmbedi;
require_once 'fediembedi-client.php';
class FediConfig
{
public function __construct()
{
add_action('plugins_loaded', array($this, 'init'));
add_action('widgets_init', array($this, 'fediembedi_widget'));
//add_action('admin_enqueue_scripts', array($this, 'enqueue_scripts'));
add_action('wp_enqueue_scripts', array($this, 'enqueue_styles'));
add_action('admin_menu', array($this, 'configuration_page'));
//add_action('save_post', array($this, 'toot_post'));
add_action('admin_notices', array($this, 'admin_notices'));
add_filter('plugin_action_links_'.plugin_basename(__FILE__), array($this, 'fediembedi_add_plugin_page_settings_link'));
//add_action('add_meta_boxes', array($this, 'add_metabox'));
//add_action('publish_future_post', array($this, 'toot_scheduled_post'));
//add_action('wp_ajax_get_toot_preview', array($this, 'get_toot_preview_ajax_handler'));
}
/**
* Init
*
* Plugin initialization
*
* @return void
*/
public function init()
{
$plugin_dir = basename(dirname(__FILE__));
//load_plugin_textdomain('fediembedi', false, $plugin_dir . '/languages');
if (isset($_GET['code'])) {
$code = $_GET['code'];
$client_id = get_option('fediembedi-client-id');
$client_secret = get_option('fediembedi-client-secret');
if (!empty($code) && !empty($client_id) && !empty($client_secret)) {
//echo __('Authentification, please wait', 'fediembedi') . '...';
update_option('fediembedi-token', 'nada');
$instance = get_option('fediembedi-instance');
$client = new \Client($instance);
$token = $client->get_bearer_token($client_id, $client_secret, $code, get_admin_url());
$instance_info = $client->getInstance();
if (isset($token->error)) {
//print_r($token);
//TODO: Propper error message
update_option(
'fediembedi-notice',
serialize(
array(
'message' => '<strong>FediEmbedi</strong> : ' . __("Can't log you in.", 'fediembedi') .
'<p><strong>' . __('Instance message', 'fediembedi') . '</strong> : ' . $token->error_description . '</p>',
'class' => 'error',
)
)
);
unset($token);
update_option('fediembedi-token', '');
} else {
update_option('fediembedi-client-id', '');
update_option('fediembedi-client-secret', '');
update_option('fediembedi-token', $token->access_token);
update_option('fediembedi-instance-info', $instance_info);
}
$redirect_url = get_admin_url() . 'options-general.php?page=fediembedi';
} else {
//Probably hack or bad refresh, redirect to homepage
$redirect_url = home_url();
}
wp_redirect($redirect_url);
exit;
}
$token = get_option('fediembedi-token');
// if (empty($token)) {
// update_option(
// 'fediembedi-notice',
// serialize(
// array(
// 'message' => '<strong>FediEmbedi</strong> : ' . __('Please login to your account!', 'fediembedi') . '<a href="' . get_admin_url() . 'options-general.php?page=fediembedi"> ' . __('Go to FediEmbedi configuration', 'fediembedi') . '</a>',
// 'class' => 'error',
// )
// )
// );
// }
}
/*
* Widget
*/
public function fediembedi_widget() {
include(plugin_dir_path(__FILE__) . 'fediembedi-widget.php' );//
register_widget( 'WP_Widget_fediembedi' );
}
public function enqueue_styles($hook)
{
if( is_active_widget( false, false, 'fediembedi') ) {
$instance = get_option('fediembedi-instance');
$client = new \Client($instance);
$instance_info = $client->getInstance();
if (strpos($instance_info->version, 'Pixelfed') === false) {
wp_enqueue_style( 'fediembedi', plugin_dir_url( __FILE__ ) . 'mastodon-light.css', array(), filemtime(plugin_dir_path( __FILE__ ) . 'mastodon-light.css') );
} else {
//https://css-tricks.com/lozad-js-performant-lazy-loading-images/ lazyloading for background images
wp_enqueue_style( 'fediembedi', plugin_dir_url( __FILE__ ) . 'pixelfed-light.css', array(), filemtime(plugin_dir_path( __FILE__ ) . 'pixelfed-light.css') );
}
}
}
/**
* Configuration_page
*
* Add the configuration page menu
*
* @return void
*/
public function configuration_page()
{
add_options_page(
'FediEmbedi',
'FediEmbedi',
'manage_options',
'fediembedi',
array($this, 'show_configuration_page')
);
}
/**
* Show_configuration_page
*
* Content of the configuration page
*
* @throws Exception The exception.
* @return void
*/
public function show_configuration_page()
{
wp_enqueue_style('fediembedi-configuration', plugin_dir_url(__FILE__) . 'style.css');
if (isset($_GET['disconnect'])) {
update_option('fediembedi-token', '');
}
$token = get_option('fediembedi-token');
if (isset($_POST['save'])) {
$is_valid_nonce = wp_verify_nonce($_POST['_wpnonce'], 'fediembedi-configuration');
if ($is_valid_nonce) {
$instance = esc_url($_POST['instance']);
$client = new \Client($instance);
$redirect_url = get_admin_url();
$auth_url = $client->register_app($redirect_url);
if ($auth_url == "ERROR") {
//var_dump('$auth_url = ERROR'); //die;
update_option(
'fediembedi-notice',
serialize(
array(
'message' => '<strong>FediEmbedi</strong> : ' . __('The given instance url belongs to an unrecognized service!', 'fediembedi'),
'class' => 'error',
)
)
);
} else {
//var_dump($auth_url); //die;
if (empty($instance)) {
//var_dump($instance); //die;
update_option(
'fediembedi-notice',
serialize(
array(
'message' => '<strong>FediEmbedi</strong> : ' . __('Please set your instance before you connect !', 'fediembedi'),
'class' => 'error',
)
)
);
} else {
update_option('fediembedi-client-id', $client->get_client_id());
update_option('fediembedi-client-secret', $client->get_client_secret());
update_option('fediembedi-instance', $instance);
$account = $client->verify_credentials($token);
if (is_null($account) || isset($account->error)) {
echo '<meta http-equiv="refresh" content="0; url=' . $auth_url . '" />';
echo __('Redirect to ', 'fediembedi') . $instance;
exit;
}
//Inform user that save was successfull
update_option(
'fediembedi-notice',
serialize(
array(
'message' => '<strong>FediEmbedi</strong> : ' . __('Configuration successfully saved!', 'fediembedi'),
'class' => 'success',
)
)
);
}
}
$this->admin_notices();
}
}
$instance = get_option('fediembedi-instance');
if (!empty($token)) {
$client = new \Client($instance);
$account = $client->verify_credentials($token);
}
include 'form.tpl.php';
}
/**
* Admin_notices
* Show the notice (error or info)
*
* @return void
*/
public function admin_notices()
{
$notice = unserialize(get_option('fediembedi-notice'));
if (is_array($notice)) {
echo '<div class="notice notice-' . sanitize_html_class($notice['class']) . ' is-dismissible"><p>' . $notice['message'] . '</p></div>';
update_option('fediembedi-notice', null);
}
}
/**
* @param $links
*
* @return array
*/
function fediembedi_add_plugin_page_settings_link( $links ) {
$links[] = '<a href="' . admin_url( 'options-general.php?page=fediembedi' ) . '">' . __('Configuration', 'fediembedi') . '</a>';
return $links;
}
}
$fediconfig = new FediConfig();

55
form.tpl.php Normal file
View File

@ -0,0 +1,55 @@
<?php
define("ACCOUNT_CONNECTED",isset($account) && $account !== null);
define("ADVANCED_VIEW",false);
?>
<div class="wrap">
<h1><?php esc_html_e( 'FediEmbedi Configuration', 'fediembedi' ); ?></h1>
<br>
<!-- <a href="" target="_blank" class="github-icon" target="_blank">
<svg aria-hidden="true" class="octicon octicon-mark-github" height="32" version="1.1" viewBox="0 0 16 16" width="32"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path></svg>
</a>
<a href="" target="_blank"><img src="<?php echo plugins_url( 'img/paypal.png', __FILE__ );?>" style="height:30px;"></a>
<a href="" target="_blank"><img src="<?php echo plugins_url( 'img/patron.png', __FILE__ );?>" style="height:30px;"></a>
<a href="" target="_blank"><img src="<?php echo plugins_url( 'img/donate.svg', __FILE__ );?>"></a> -->
<br>
<br>
<form method="POST">
<?php wp_nonce_field( 'fediembedi-configuration' ); ?>
<div style="display:<?php echo !ACCOUNT_CONNECTED ? "block":"none"?>">
<input type="text" id="instance" name="instance" size="80" value="<?php esc_attr_e( $instance ); ?>" list="mInstances">
<input class="button button-primary" type="submit" value="<?php esc_attr_e( 'Connect to your Mastodon instance', 'fediembedi' ); ?>" name="save" id="save">
</div>
<div style="display:<?php echo ACCOUNT_CONNECTED ? "block" : "none"?>">
<div class="account">
<?php if(ACCOUNT_CONNECTED): ?>
<a href="<?php echo $account->url ?>" target="_blank"><img class="m-avatar" src="<?php echo $account->avatar ?>"></a>
<?php endif ?>
<div class="details">
<?php if(ACCOUNT_CONNECTED): ?>
<div class="connected"><?php esc_html_e( 'Connected as', 'fediembedi' ); ?>&nbsp;<?php echo $account->username ?></div>
<a class="link" href="<?php echo $account->url ?>" target="_blank"><?php echo $account->url ?></a>
<p><a href="<?php echo $_SERVER['REQUEST_URI'] . '&disconnect' ?>" class="button"><?php esc_html_e( 'Disconnect', 'fediembedi' ); ?></a>
<?php else: ?>
<div class="disconnected"><?php esc_html_e( 'Disconnected', 'fediembedi' ); ?></div>
<?php endif ?>
</div>
<div class="separator"></div>
</div>
</div>
<?php if(ACCOUNT_CONNECTED): ?>
<div class="clear">
<input class="button button-primary" type="submit" value="<?php esc_attr_e( 'Save configuration', 'fediembedi' ); ?>" name="save" id="save">
</div>
<?php endif ?>
</form>
<?php
//require("instanceList.php")
?>
</div>

1
img/retoot.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.4 KiB

9
instanceList.php Normal file

File diff suppressed because one or more lines are too long

298
mastodon-light.css Normal file
View File

@ -0,0 +1,298 @@
/* .scrollable {
contain: strict;
} */
.scrollable {
overflow-y: scroll;
overflow-x: hidden;
flex: 1 1 auto;
-webkit-overflow-scrolling: touch;
will-change: transform;
}
.status {
padding: 8px 10px 8px 68px;
position: relative;
min-height: 54px;
border-bottom: 1px solid #c0cdd9;
cursor: default;
opacity: 1;
-webkit-animation: fade .15s linear;
animation: fade .15s linear;
}
.status__prepend {
margin-left: 68px;
color: #444b5d;
padding: 8px 0 2px;
font-size: 14px;
position: relative;
}
.status__prepend-icon-wrapper {
left: -26px;
position: absolute;
}
.fa-fw {
width: 1.28571429em;
text-align: center;
}
.fa {
display: inline-block;
}
.account__header {
overflow: hidden;
}
.account__header__image {
overflow: hidden;
height: 145px;
position: relative;
background: #e6ebf0;
}
.account__header__info {
position: absolute;
top: 10px;
left: 10px;
}
.account__header__image img {
object-fit: cover;
display: block;
width: 100%;
height: 100%;
margin: 0;
}
.account__header__bar {
position: relative;
background: #fff;
padding: 5px;
border-bottom: 1px solid #b3c3d1;
}
.account__header__tabs {
display: flex;
align-items: flex-start;
padding: 7px 5px;
margin-top: -55px;
}
.account__header__bar .avatar {
display: block;
flex: 0 0 auto;
width: 94px;
margin-left: -2px;
}
.account__header__tabs .spacer {
flex: 1 1 auto;
}
.account__header__tabs__buttons .button {
margin: 0 8px;
color: #fff;
border-radius: 4px;
}
.account__header__tabs__name {
padding: 5px;
}
.account__header__tabs__name h1 {
font-size: 16px;
line-height: 24px;
color: #000;
font-weight: 500;
margin: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.account__header__tabs__name h1 small {
display: block;
font-size: 14px;
color: #282c37;
font-weight: 400;
overflow: hidden;
text-overflow: ellipsis;
}
.account__header__extra {
margin-top: 4px;
}
.account__header__bio {
overflow: hidden;
margin: 0 -5px;
}
.account__header__bio .account__header__content {
padding: 20px 15px 5px;
color: #000;
}
.account__header__content {
color: #282c37;
font-size: 14px;
font-weight: 400;
overflow: hidden;
word-break: normal;
word-wrap: break-word;
}
.account__display-name,
.detailed-status__application,
.detailed-status__datetime,
.detailed-status__display-name,
.status__display-name,
.status__relative-time {
text-decoration: none;
}
.status__display-name {
color: #444b5d;
}
.status__expand {
width: 68px;
position: absolute;
left: 0;
top: 0;
height: 100%;
cursor: pointer;
}
.status__info {
font-size: 15px;
}
.status__info .status__display-name {
display: block;
max-width: 100%;
padding-right: 25px;
}
.status__avatar {
height: 48px;
left: 10px;
position: absolute;
top: 10px;
width: 48px;
}
.account__avatar {
border-radius: 4px;
background: transparent no-repeat;
background-position: 50%;
background-clip: padding-box;
position: relative;
}
.account__avatar-overlay {
width: 48px;
height: 48px;
background-size: 48px 48px;
}
.account__avatar-overlay-base {
border-radius: 4px;
background: transparent no-repeat;
background-position: 50%;
background-clip: padding-box;
width: 36px;
height: 36px;
background-size: 36px 36px;
}
.account__avatar-overlay-overlay {
border-radius: 4px;
background: transparent no-repeat;
background-position: 50%;
background-clip: padding-box;
width: 24px;
height: 24px;
background-size: 24px 24px;
position: absolute;
bottom: 0;
right: 0;
z-index: 1;
}
.display-name {
display: block;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.display-name__account {
font-size: 14px;
}
.account__display-name strong, .status__display-name strong {
color: #000;
}
.display-name__html {
font-weight: 500;
}
.notification__relative_time, .status__relative-time {
color: #444b5d;
float: right;
font-size: 14px;
}
.status-card.compact {
border-color: #ccd7e0;
}
.status-card {
display: flex;
font-size: 14px;
border: 1px solid #c0cdd9;
border-radius: 4px;
color: #444b5d;
margin-top: 14px;
text-decoration: none;
overflow: hidden;
cursor: pointer;
}
.status-card.compact .status-card__image {
flex: 0 0 60px;
}
.status-card__image {
flex: 0 0 100px;
background: #c0cdd9;
position: relative;
}
.status-card__image-image {
border-radius: 4px 0 0 4px;
display: block;
margin: 0;
width: 100%;
height: 100%;
object-fit: cover;
background-size: cover;
background-position: 50%;
}
.status-card.compact .status-card__content {
padding: 10px 8px 8px;
}
.status-card__content {
flex: 1 1 auto;
overflow: hidden;
padding: 14px 14px 14px 8px;
}
.status-card__title {
display: block;
font-weight: 500;
margin-bottom: 5px;
color: #282c37;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-decoration: none;
}
.status-card__description {
color: #282c37;
}
.status-card__host {
display: block;
margin-top: 5px;
font-size: 13px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.status__content summary {
background: #eee;
border-radius: 5px;
padding: 2px 8px;
cursor: pointer;
display: inline-block;
}
.status__content .media-gallery__item{
margin: 1em 0;
}
i.fa-retweet {
background-image: url('img/retoot.svg');
background-position: 0 0;
height: 19px;
vertical-align: middle;
width: 22px;
color: #ccc;
opacity: .75;
z-index: 10;
position: relative;
}

300
pixelfed-light.css Normal file
View File

@ -0,0 +1,300 @@
/* .scrollable {
contain: strict;
} */
.scrollable {
overflow-y: scroll;
overflow-x: hidden;
flex: 1 1 auto;
-webkit-overflow-scrolling: touch;
will-change: transform;
}
.status {
padding: 8px 10px 8px 68px;
position: relative;
min-height: 54px;
border-bottom: 1px solid #c0cdd9;
cursor: default;
opacity: 1;
-webkit-animation: fade .15s linear;
animation: fade .15s linear;
}
.status__prepend {
margin-left: 68px;
color: #444b5d;
padding: 8px 0 2px;
font-size: 14px;
position: relative;
}
.status__prepend-icon-wrapper {
left: -26px;
position: absolute;
}
.fa-fw {
width: 1.28571429em;
text-align: center;
}
.fa {
display: inline-block;
}
.account__header {
overflow: hidden;
}
.account__header__image {
overflow: hidden;
height: 145px;
position: relative;
background: #e6ebf0;
}
.account__header__info {
position: absolute;
top: 10px;
left: 10px;
}
.account__header__image img {
object-fit: cover;
display: block;
width: 100%;
height: 100%;
margin: 0;
;
}
.account__header__bar {
position: relative;
background: #fff;
padding: 5px;
border-bottom: 1px solid #b3c3d1;
}
.account__header__tabs {
display: flex;
align-items: flex-start;
padding: 7px 5px;
margin-top: -55px;
}
.account__header__bar .avatar {
display: block;
flex: 0 0 auto;
width: 94px;
margin-left: -2px;
border-radius: 50%
}
.account__header__tabs .spacer {
flex: 1 1 auto;
}
.account__header__tabs__buttons .button {
margin: 0 8px;
color: #fff;
}
.account__header__tabs__name {
padding: 5px;
}
.account__header__tabs__name h1 {
font-size: 16px;
line-height: 24px;
color: #000;
font-weight: 500;
margin: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.account__header__tabs__name h1 small {
display: block;
font-size: 14px;
color: #282c37;
font-weight: 400;
overflow: hidden;
text-overflow: ellipsis;
}
.account__header__extra {
margin-top: 4px;
}
.account__header__bio {
overflow: hidden;
margin: 0 -5px;
}
.account__header__bio .account__header__content {
padding: 20px 15px 5px;
color: #000;
}
.account__header__content {
color: #282c37;
font-size: 14px;
font-weight: 400;
overflow: hidden;
word-break: normal;
word-wrap: break-word;
}
.account__display-name,
.detailed-status__application,
.detailed-status__datetime,
.detailed-status__display-name,
.status__display-name,
.status__relative-time {
text-decoration: none;
}
.status__display-name {
color: #444b5d;
}
.status__expand {
width: 68px;
position: absolute;
left: 0;
top: 0;
height: 100%;
cursor: pointer;
}
.status__info {
font-size: 15px;
}
.status__info .status__display-name {
display: block;
max-width: 100%;
padding-right: 25px;
}
.status__avatar {
height: 48px;
left: 10px;
position: absolute;
top: 10px;
width: 48px;
}
.account__avatar {
border-radius: 4px;
background: transparent no-repeat;
background-position: 50%;
background-clip: padding-box;
position: relative;
border-radius: 50%
}
.account__avatar-overlay {
width: 48px;
height: 48px;
background-size: 48px 48px;
}
.account__avatar-overlay-base {
border-radius: 4px;
background: transparent no-repeat;
background-position: 50%;
background-clip: padding-box;
width: 36px;
height: 36px;
background-size: 36px 36px;
}
.account__avatar-overlay-overlay {
border-radius: 4px;
background: transparent no-repeat;
background-position: 50%;
background-clip: padding-box;
width: 24px;
height: 24px;
background-size: 24px 24px;
position: absolute;
bottom: 0;
right: 0;
z-index: 1;
}
.display-name {
display: block;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.display-name__account {
font-size: 14px;
}
.account__display-name strong, .status__display-name strong {
color: #000;
}
.display-name__html {
font-weight: 500;
}
.notification__relative_time, .status__relative-time {
color: #444b5d;
float: right;
font-size: 14px;
}
.status-card.compact {
border-color: #ccd7e0;
}
.status-card {
display: flex;
font-size: 14px;
border: 1px solid #c0cdd9;
border-radius: 4px;
color: #444b5d;
margin-top: 14px;
text-decoration: none;
overflow: hidden;
cursor: pointer;
}
.status-card.compact .status-card__image {
flex: 0 0 60px;
}
.status-card__image {
flex: 0 0 100px;
background: #c0cdd9;
position: relative;
}
.status-card__image-image {
border-radius: 4px 0 0 4px;
display: block;
margin: 0;
width: 100%;
height: 100%;
object-fit: cover;
background-size: cover;
background-position: 50%;
}
.status-card.compact .status-card__content {
padding: 10px 8px 8px;
}
.status-card__content {
flex: 1 1 auto;
overflow: hidden;
padding: 14px 14px 14px 8px;
}
.status-card__title {
display: block;
font-weight: 500;
margin-bottom: 5px;
color: #282c37;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-decoration: none;
}
.status-card__description {
color: #282c37;
}
.status-card__host {
display: block;
margin-top: 5px;
font-size: 13px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.status__content summary {
background: #eee;
border-radius: 5px;
padding: 2px 8px;
cursor: pointer;
display: inline-block;
}
.status__content .media-gallery__item{
margin: 1em 0;
}
i.fa-retweet {
background-image: url('img/retoot.svg');
background-position: 0 0;
height: 19px;
vertical-align: middle;
width: 22px;
color: #ccc;
opacity: .75;
z-index: 10;
position: relative;
}

65
readme.txt Normal file
View File

@ -0,0 +1,65 @@
=== Plugin Name ===
Contributors: dj_angola
Donate link: https://paypal.me/MediaFormat
Tags: mastodon, pixelfed, fediverse
Requires at least: 5.1
Tested up to: 5.3.2
Requires PHP: 7.2
Stable tag: 4.3
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Display your Fediverse timeline in a widget
== Description ==
> FediEmbedi is beta software.
= Currently supported software =
* Mastodon
* Pleroma
* Pixelfed
= Planned supported software =
* PeerTube
* *Suggestions?*
= Development =
For the time being development will happen on [git.feneas.org](https://git.feneas.org/mediaformat/fediembedi "FediEmbedi").
= Updates =
I will be making frequent updates in the coming days, weeks, and won't be tagging releases,
so if you want to benefit from easy updates, I suggest installing [Github Updater](https://github.com/afragen/github-updater)
as a companion plugin.
== Installation ==
Typical installation procedure
e.g.
1. Upload `fediembedi` to the `/wp-content/plugins/` directory
1. Activate the plugin through the 'Plugins' menu in WordPress
1. Connect to your fediverse instance by visiting the configuration page in Settings -> FediEmbedi
== Frequently Asked Questions ==
= Does this plugin store my login info? =
No, this plugin uses oAuth 2.0. You will be sent to login to your Instance
and redirected to your site with a secure token. Similar to how apps connect to your account
== Changelog ==
= 0.1.0 =
* Initial commit.
== Credits ==
= Mastodon Autopost =
The App registration, oAuth connection and portions of the Mastodon API code is based on [Mastodon Autopost](https://wordpress.org/plugins/autopost-to-mastodon/).
= Mastodon =
The CSS and SVG icon come from the Mastodon project

196
style.css Normal file
View File

@ -0,0 +1,196 @@
/* .wrap{
padding:10px;
border-radius:10px;
min-height:100%;
}
.wrap h1, .wrap label, .wrap form p{
color: #000;
}
.wrap .button{
color:#2b90d9 !important;
border-color:#2b90d9 !important;
box-shadow:none !important;
text-shadow:none !important;
font-weight:bold;
}
.wrap .button:hover{
background-color:transparent;
}
.wrap input, .wrap textarea{
background-color:transparent !important;
color:#000 !important;
border-color:#000;
border-radius:4px;
}
.wrap > form{
border:solid 1px #2b90d9;
padding:1%;
background-color:#FFF;
} */
.spacer{
margin-top: 20px;
}
.account{
border: 1px solid #000;
padding: 15px;
border-radius:4px;
float:left;
}
.m-avatar{
float:left;
border-radius: 100px;
margin-right: 20px;
width: 60px;
}
.details{
float:left;
}
.details .link{
color:#000;
text-decoration: none;
}
.connected{
color: #2b90d9;
font-size: 16px;
font-weight:bold;
margin-bottom: 10px;
}
.disconnected{
color: #FF0000;
font-size: 16px;
text-align: center;
width: 100%;
}
.advanced_setting{
display:none;
}
/* .wrap .button:hover{
background-color:transparent;
}
.wrap input, .wrap textarea{
background-color:transparent !important;
color:#000 !important;
border-color:#000;
border-radius:4px;
} */
.spacer{
margin-top: 20px;
}
.account{
border: 1px solid #000;
padding: 15px;
border-radius:4px;
float:left;
margin: 0 0 1em;
}
.m-avatar{
float:left;
border-radius: 100px;
margin-right: 20px;
width: 60px;
}
.details{
float:left;
}
.details .link{
color:#000;
text-decoration: none;
}
.connected{
color: #2b90d9;
font-size: 16px;
font-weight:bold;
margin-bottom: 10px;
}
.disconnected{
color: #FF0000;
font-size: 16px;
text-align: center;
width: 100%;
}
.advanced_setting{
display:none;
}
label{
display:inline-block;
vertical-align: bottom;
text-align:center;
}
.messageRadioButtons label{
padding:10px;
border:dashed 2px #000;
opacity:0.5;
}
.scopeRadioButtons label{
opacity:0.5;
margin-right:1em;
}
input[type="radio"]{
display:none;
}
.github-icon{
margin-right: 10px;
text-decoration: none;
position: relative;
}
html > body .liberapay-btn{
margin-top: 3px;
position: absolute;
}
.github-icon{
margin-right: 10px;
text-decoration: none;
position: relative;
}
.modeIcon{
height:1em;
}
html > body .liberapay-btn{
margin-top: 3px;
position: absolute;
}
.tab-button{
text-align:center;
margin-bottom:-1px !important;
border-bottom:none !important;
border-radius:0 !important;
}
.tab-button.active{
background-color:#FFF !important;
margin-bottom:-0px !important;
}

11
uninstall.php Normal file
View File

@ -0,0 +1,11 @@
<?php
if (!defined('WP_UNINSTALL_PLUGIN')) {
die;
}
delete_option( 'fediembedi-client-id' );
delete_option( 'fediembedi-client-secret' );
delete_option( 'fediembedi-token' );
delete_option( 'fediembedi-instance' );
delete_option( 'fediembedi-instance-info' );
delete_option( 'fediembedi-notice' );