Major cleanup: Image handling fixes and plugin updates
- Fixed featured image upload and handling - Added detailed debug logging - Cleaned up fallback image functionality - Updated README.md with new MIT license - Added .gitignore file - Fixed image reposting functionality - Improved error handling and logging - Added proper WordPress coding standards
This commit is contained in:
parent
038d32386d
commit
3bb8217690
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"direnv.path.executable": "/usr/bin/direnv"
|
||||
}
|
132
README.md
132
README.md
@ -1,66 +1,98 @@
|
||||
# Bluesky Publisher for WordPress
|
||||
=== Share On Bluesky ===
|
||||
Contributors: eugenewebdoctor
|
||||
Tags: bluesky, social media, cross-posting, atproto
|
||||
Requires at least: 5.0
|
||||
Tested up to: 6.7
|
||||
Requires PHP: 7.4
|
||||
Stable tag: 1.0.0
|
||||
License: MIT
|
||||
License URI: https://opensource.org/licenses/MIT
|
||||
|
||||
Automatically share your WordPress posts to Bluesky with customizable formatting, image handling, and queue management.
|
||||
A simple WordPress plugin for automatically sharing your posts to Bluesky with support for featured images and customizable formatting.
|
||||
|
||||
## Description
|
||||
== Description ==
|
||||
|
||||
Bluesky Publisher for WordPress enables automatic cross-posting of your WordPress content to Bluesky. With customizable post formatting, image support, and reliable queue management, you can ensure your content looks great on Bluesky.
|
||||
Share On Bluesky is a lightweight WordPress plugin that enables automatic cross-posting to Bluesky. When you publish a post, it automatically shares it to your Bluesky account with proper formatting and image support.
|
||||
|
||||
### Features
|
||||
= Key Features =
|
||||
|
||||
* Automatic post sharing to Bluesky
|
||||
* Customizable post formatting
|
||||
* Featured image support with automatic resizing
|
||||
* Queue management for reliable posting
|
||||
* Post meta box for post status and manual controls
|
||||
* Support for post titles, excerpts, and links
|
||||
* Proper spacing and formatting of posts
|
||||
* Automatic token refresh
|
||||
* One-click connection to Bluesky using your handle and app password
|
||||
* Automatic post sharing when you publish
|
||||
* Featured image support with auto-resizing
|
||||
* Customizable post format with title and excerpt options
|
||||
* Manual post/repost controls from post editor
|
||||
* Secure token management with automatic refresh
|
||||
|
||||
## Requirements
|
||||
== Installation ==
|
||||
|
||||
- WordPress 5.0 or higher
|
||||
- PHP 7.4 or higher
|
||||
- Bluesky account
|
||||
There are two ways to install the Share On Bluesky plugin:
|
||||
|
||||
## Installation
|
||||
= From WordPress Dashboard (Recommended) =
|
||||
|
||||
1. Upload 'bluesky-connector' folder to the '/wp-content/plugins/' directory
|
||||
2. Activate the plugin through the 'Plugins' menu in WordPress
|
||||
3. Go to Settings > Bluesky Publisher to configure your connection
|
||||
1. Go to your WordPress Dashboard > Plugins > Add New
|
||||
2. Search for "Share On Bluesky"
|
||||
3. Click "Install Now" next to the Share On Bluesky plugin
|
||||
4. After installation completes, click "Activate"
|
||||
5. Go to Settings > Bluesky to configure your connection
|
||||
|
||||
## Configuration
|
||||
= Manual Installation =
|
||||
|
||||
1. Get your Bluesky app password
|
||||
2. Enter your Bluesky handle and app password in the settings
|
||||
3. Choose your preferred post format
|
||||
4. Start publishing!
|
||||
1. Download the 'share-on-bluesky' plugin from WordPress.org
|
||||
2. Go to your WordPress Dashboard > Plugins > Add New > Upload Plugin
|
||||
3. Choose the downloaded zip file and click "Install Now"
|
||||
4. After installation completes, click "Activate"
|
||||
5. Go to Settings > Bluesky to configure your connection
|
||||
|
||||
## Frequently Asked Questions
|
||||
= After Installation =
|
||||
|
||||
### Where do I find my Bluesky app password?
|
||||
1. Enter your Bluesky handle (username.bsky.social)
|
||||
2. Generate and enter an app password from your Bluesky account settings
|
||||
3. Choose your preferred post format options
|
||||
4. Test by publishing a new post
|
||||
|
||||
You can generate an app password in your Bluesky account settings under "App Passwords".
|
||||
== Frequently Asked Questions ==
|
||||
|
||||
### What happens if an error occurs during posting?
|
||||
= Where do I find my Bluesky app password? =
|
||||
|
||||
Posts are added to a queue and the plugin will automatically retry failed posts. You can also manually retry posts from the post editor.
|
||||
You can generate an app password in your Bluesky account settings under "App Passwords". Never use your main account password.
|
||||
|
||||
## Changelog
|
||||
= How are images handled? =
|
||||
|
||||
### 1.0.0
|
||||
The plugin automatically uploads your post's featured image to Bluesky when sharing. Images are resized if needed to meet Bluesky's size limits.
|
||||
|
||||
= Can I manually control what gets posted? =
|
||||
|
||||
Yes! Each post has a Bluesky status box where you can manually share, retry, or repost content.
|
||||
|
||||
== Screenshots ==
|
||||
|
||||
1. Settings page showing connection and format options
|
||||
2. Post editor integration with Bluesky status and controls
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 1.0.0 =
|
||||
* Initial release
|
||||
* Automatic post sharing with featured images
|
||||
* Customizable post formatting
|
||||
* Image support with automatic resizing
|
||||
* Queue management system
|
||||
* Post meta box controls
|
||||
* Token refresh functionality
|
||||
* Manual post controls
|
||||
* Secure token management
|
||||
|
||||
## License
|
||||
== Privacy Policy ==
|
||||
|
||||
This project is licensed under the MIT License - see below for details:
|
||||
This plugin connects to Bluesky's servers (bsky.social) to share your posts. It stores:
|
||||
* Your Bluesky handle
|
||||
* Authentication tokens (securely encrypted)
|
||||
* Post sharing status metadata
|
||||
|
||||
No other personal data is collected or shared.
|
||||
|
||||
== Credits ==
|
||||
|
||||
Developed by [Eugene Web Doctor](https://eugenewebdoctor.com)
|
||||
|
||||
== License ==
|
||||
|
||||
```
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Eugene Web Doctor
|
||||
@ -82,23 +114,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
## Credits
|
||||
|
||||
Developed by [Eugene Web Doctor](https://eugenewebdoctor.com)
|
||||
|
||||
## Support Development
|
||||
== Support Development ==
|
||||
|
||||
If you find this plugin useful, consider supporting its development:
|
||||
|
||||
### Lightning Network
|
||||
```
|
||||
enki@zap.sovbit.host
|
||||
```
|
||||
Lightning Network:
|
||||
`enki@zap.sovbit.host`
|
||||
|
||||
### On-Chain Bitcoin
|
||||
```
|
||||
bc1pe60ykxhl6h8j6w7dpwrn7qzcyay6l52dkfeulkgg72eezgmms3wss3ul42
|
||||
|
||||
```
|
||||
On-Chain Bitcoin:
|
||||
`bc1pe60ykxhl6h8j6w7dpwrn7qzcyay6l52dkfeulkgg72eezgmms3wss3ul42`
|
@ -1,4 +1,3 @@
|
||||
|
||||
.bluesky-post-status {
|
||||
padding: 10px;
|
||||
}
|
||||
@ -36,4 +35,22 @@
|
||||
.bluesky-share-post {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Button States */
|
||||
.updating-message {
|
||||
position: relative;
|
||||
padding-left: 24px !important;
|
||||
}
|
||||
|
||||
.updating-message:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 8px;
|
||||
margin-top: -8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: url(../images/spinner.gif) no-repeat center;
|
||||
background-size: 16px 16px;
|
||||
}
|
@ -1,63 +1,146 @@
|
||||
jQuery(document).ready(function($) {
|
||||
// Retry posting to Bluesky
|
||||
$('.bluesky-retry-post').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var button = $(this);
|
||||
var postId = button.data('post-id');
|
||||
|
||||
button.prop('disabled', true);
|
||||
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'bluesky_retry_post',
|
||||
post_id: postId,
|
||||
nonce: blueskyAdmin.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert(response.data.message || 'Error retrying post');
|
||||
button.prop('disabled', false);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert('Network error. Please try again.');
|
||||
button.prop('disabled', false);
|
||||
}
|
||||
});
|
||||
});
|
||||
// Post status container element
|
||||
const $statusContainer = $('.bluesky-post-status');
|
||||
|
||||
// Share post to Bluesky
|
||||
// Helper function to display status messages
|
||||
function updateStatus(message, type = 'info') {
|
||||
const $status = $(`<div class="notice notice-${type} is-dismissible"><p>${message}</p></div>`);
|
||||
$statusContainer.prepend($status);
|
||||
|
||||
// Add dismiss button functionality
|
||||
$status.find('.notice-dismiss').on('click', function() {
|
||||
$status.fadeOut(300, function() { $(this).remove(); });
|
||||
});
|
||||
|
||||
// Auto dismiss after 5 seconds for success messages
|
||||
if (type === 'success') {
|
||||
setTimeout(() => {
|
||||
$status.fadeOut(300, function() { $(this).remove(); });
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle immediate posting
|
||||
$('.bluesky-share-post').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var button = $(this);
|
||||
var postId = button.data('post-id');
|
||||
const $button = $(this);
|
||||
const postId = $button.data('post-id');
|
||||
const nonce = $button.data('nonce');
|
||||
|
||||
button.prop('disabled', true);
|
||||
// Disable button and show loading state
|
||||
$button.prop('disabled', true)
|
||||
.addClass('updating-message')
|
||||
.text(blueskyAdmin.strings.publishing);
|
||||
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
url: blueskyAdmin.ajaxUrl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'bluesky_share_post',
|
||||
action: 'bluesky_post_now',
|
||||
post_id: postId,
|
||||
nonce: blueskyAdmin.nonce
|
||||
nonce: nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
updateStatus(response.data.message, 'success');
|
||||
location.reload();
|
||||
} else {
|
||||
alert(response.data.message || 'Error sharing post');
|
||||
button.prop('disabled', false);
|
||||
updateStatus(response.data.message, 'error');
|
||||
$button.prop('disabled', false)
|
||||
.removeClass('updating-message')
|
||||
.text(blueskyAdmin.strings.retry);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert('Network error. Please try again.');
|
||||
button.prop('disabled', false);
|
||||
error: function(xhr, status, error) {
|
||||
updateStatus(blueskyAdmin.strings.error, 'error');
|
||||
$button.prop('disabled', false)
|
||||
.removeClass('updating-message')
|
||||
.text(blueskyAdmin.strings.retry);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Handle retry posting
|
||||
$('.bluesky-retry-post').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
const $button = $(this);
|
||||
const postId = $button.data('post-id');
|
||||
const nonce = $button.data('nonce');
|
||||
|
||||
// Disable button and show loading state
|
||||
$button.prop('disabled', true)
|
||||
.addClass('updating-message')
|
||||
.text(blueskyAdmin.strings.retrying);
|
||||
|
||||
$.ajax({
|
||||
url: blueskyAdmin.ajaxUrl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'bluesky_post_now',
|
||||
post_id: postId,
|
||||
nonce: nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
updateStatus(response.data.message, 'success');
|
||||
location.reload();
|
||||
} else {
|
||||
updateStatus(response.data.message, 'error');
|
||||
$button.prop('disabled', false)
|
||||
.removeClass('updating-message')
|
||||
.text(blueskyAdmin.strings.retry);
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
updateStatus(blueskyAdmin.strings.error, 'error');
|
||||
$button.prop('disabled', false)
|
||||
.removeClass('updating-message')
|
||||
.text(blueskyAdmin.strings.retry);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Handle reposting
|
||||
$('.bluesky-repost').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
const $button = $(this);
|
||||
const postId = $button.data('post-id');
|
||||
const nonce = $button.data('nonce');
|
||||
|
||||
if (!confirm(blueskyAdmin.strings.confirmRepost)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$button.prop('disabled', true)
|
||||
.addClass('updating-message')
|
||||
.text(blueskyAdmin.strings.reposting);
|
||||
|
||||
$.ajax({
|
||||
url: blueskyAdmin.ajaxUrl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'bluesky_post_now',
|
||||
post_id: postId,
|
||||
nonce: nonce,
|
||||
repost: true
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
updateStatus(response.data.message, 'success');
|
||||
location.reload();
|
||||
} else {
|
||||
updateStatus(response.data.message, 'error');
|
||||
$button.prop('disabled', false)
|
||||
.removeClass('updating-message')
|
||||
.text(blueskyAdmin.strings.repost);
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
updateStatus(blueskyAdmin.strings.error, 'error');
|
||||
$button.prop('disabled', false)
|
||||
.removeClass('updating-message')
|
||||
.text(blueskyAdmin.strings.repost);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,18 @@
|
||||
<?php
|
||||
class Bluesky_API {
|
||||
private $api_url = 'https://bsky.social/xrpc'; // Replace with the actual API endpoint
|
||||
private $api_url = 'https://bsky.social/xrpc';
|
||||
private $api_key;
|
||||
private $did;
|
||||
|
||||
public function __construct($api_key, $did) {
|
||||
$this->api_key = $api_key;
|
||||
$this->did = $did;
|
||||
error_log('[Bluesky Connector] Initializing API with DID: ' . $did);
|
||||
}
|
||||
|
||||
public function create_post($post_data) {
|
||||
error_log('[Bluesky Connector] Creating post with data: ' . wp_json_encode($post_data));
|
||||
|
||||
$headers = array(
|
||||
'Authorization' => 'Bearer ' . $this->api_key,
|
||||
'Content-Type' => 'application/json',
|
||||
@ -17,54 +20,96 @@ class Bluesky_API {
|
||||
|
||||
$response = wp_remote_post($this->api_url . '/com.atproto.repo.createRecord', array(
|
||||
'headers' => $headers,
|
||||
'body' => json_encode(array(
|
||||
'body' => wp_json_encode(array(
|
||||
'repo' => $this->did,
|
||||
'collection' => 'app.bsky.feed.post',
|
||||
'record' => $post_data,
|
||||
)),
|
||||
'timeout' => 30,
|
||||
));
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
error_log('[Bluesky Connector] Create post error: ' . $response->get_error_message());
|
||||
return array('error' => $response->get_error_message());
|
||||
}
|
||||
|
||||
return json_decode(wp_remote_retrieve_body($response), true);
|
||||
$response_code = wp_remote_retrieve_response_code($response);
|
||||
$response_body = wp_remote_retrieve_body($response);
|
||||
error_log('[Bluesky Connector] Create post response code: ' . $response_code);
|
||||
error_log('[Bluesky Connector] Create post response: ' . $response_body);
|
||||
|
||||
return json_decode($response_body, true);
|
||||
}
|
||||
|
||||
public function resolve_handle($handle) {
|
||||
error_log('[Bluesky Connector] Resolving handle: ' . $handle);
|
||||
|
||||
$response = wp_remote_get($this->api_url . '/com.atproto.identity.resolveHandle', array(
|
||||
'query' => array(
|
||||
'handle' => $handle,
|
||||
),
|
||||
'timeout' => 30,
|
||||
));
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
error_log('[Bluesky Connector] Resolve handle error: ' . $response->get_error_message());
|
||||
return array('error' => $response->get_error_message());
|
||||
}
|
||||
|
||||
return json_decode(wp_remote_retrieve_body($response), true);
|
||||
}
|
||||
|
||||
public function upload_blob($file_path, $mime_type) {
|
||||
public function upload_blob($file_path_or_data, $mime_type) {
|
||||
error_log('[Bluesky Connector] Starting blob upload');
|
||||
error_log('[Bluesky Connector] Mime type: ' . $mime_type);
|
||||
|
||||
$headers = array(
|
||||
'Authorization' => 'Bearer ' . $this->api_key,
|
||||
'Content-Type' => $mime_type,
|
||||
);
|
||||
|
||||
$file_contents = file_get_contents($file_path);
|
||||
if ($file_contents === false) {
|
||||
return array('error' => 'Failed to read file.');
|
||||
// Determine if input is a file path or raw data
|
||||
if (is_string($file_path_or_data) && file_exists($file_path_or_data)) {
|
||||
error_log('[Bluesky Connector] Reading from file path: ' . $file_path_or_data);
|
||||
$file_contents = file_get_contents($file_path_or_data);
|
||||
if ($file_contents === false) {
|
||||
error_log('[Bluesky Connector] Failed to read file');
|
||||
return array('error' => 'Failed to read file');
|
||||
}
|
||||
} else {
|
||||
error_log('[Bluesky Connector] Using provided data directly');
|
||||
$file_contents = $file_path_or_data;
|
||||
}
|
||||
|
||||
// Check content size
|
||||
$content_size = strlen($file_contents);
|
||||
error_log('[Bluesky Connector] Content size: ' . $content_size . ' bytes');
|
||||
|
||||
if ($content_size > 1000000) {
|
||||
error_log('[Bluesky Connector] Content size exceeds 1MB limit');
|
||||
return array('error' => 'File size exceeds 1MB limit');
|
||||
}
|
||||
|
||||
$response = wp_remote_post($this->api_url . '/com.atproto.repo.uploadBlob', array(
|
||||
'headers' => $headers,
|
||||
'body' => $file_contents,
|
||||
'timeout' => 30,
|
||||
));
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
error_log('[Bluesky Connector] Upload blob error: ' . $response->get_error_message());
|
||||
return array('error' => $response->get_error_message());
|
||||
}
|
||||
|
||||
return json_decode(wp_remote_retrieve_body($response), true);
|
||||
$response_code = wp_remote_retrieve_response_code($response);
|
||||
$response_body = wp_remote_retrieve_body($response);
|
||||
error_log('[Bluesky Connector] Upload blob response code: ' . $response_code);
|
||||
error_log('[Bluesky Connector] Upload blob response: ' . $response_body);
|
||||
|
||||
if ($response_code !== 200) {
|
||||
return array('error' => 'Upload failed with status ' . $response_code);
|
||||
}
|
||||
|
||||
return json_decode($response_body, true);
|
||||
}
|
||||
}
|
@ -20,33 +20,74 @@ class Bluesky_Auth {
|
||||
// Ensure proper URL format
|
||||
$this->api_domain = rtrim($domain, '/') . '/';
|
||||
|
||||
// Debug logs
|
||||
error_log('Bluesky Auth - Using domain setting: ' . get_option('bluesky_domain'));
|
||||
error_log('Bluesky Auth - Processed domain: ' . $this->api_domain);
|
||||
error_log('Bluesky Auth - Identifier: ' . $this->identifier);
|
||||
// Log configuration details if debugging is enabled
|
||||
$this->log_debug('Auth Configuration', array(
|
||||
'domain_setting' => get_option('bluesky_domain'),
|
||||
'processed_domain' => $this->api_domain,
|
||||
'identifier' => $this->identifier
|
||||
));
|
||||
}
|
||||
|
||||
public function get_access_token() {
|
||||
// First check if we have a valid access token
|
||||
$access_token = get_option('bluesky_access_jwt');
|
||||
$token_created = get_option('bluesky_token_created');
|
||||
|
||||
if (!empty($access_token) && $token_created > (time() - 7200)) {
|
||||
$this->log_debug('Using existing valid token');
|
||||
return $access_token;
|
||||
}
|
||||
|
||||
// If we have a refresh token, try to use it
|
||||
if ($this->should_refresh_token()) {
|
||||
return $this->refresh_access_token();
|
||||
$refresh_result = $this->refresh_access_token();
|
||||
if (!isset($refresh_result['error'])) {
|
||||
return $refresh_result;
|
||||
}
|
||||
}
|
||||
|
||||
// If we got here, we need to create a new session
|
||||
if (empty($this->identifier) || empty($this->password)) {
|
||||
// Try to get credentials from settings if not provided
|
||||
$settings = get_option('bluesky_connector_settings', array());
|
||||
if (!empty($settings['identifier'])) {
|
||||
$this->identifier = $settings['identifier'];
|
||||
}
|
||||
if (!empty($settings['password'])) {
|
||||
$this->password = $settings['password'];
|
||||
}
|
||||
|
||||
// If still empty, try individual options
|
||||
if (empty($this->identifier)) {
|
||||
$this->identifier = get_option('bluesky_identifier');
|
||||
}
|
||||
if (empty($this->password)) {
|
||||
$this->password = get_option('bluesky_password');
|
||||
}
|
||||
|
||||
if (empty($this->identifier) || empty($this->password)) {
|
||||
$this->log_debug('Missing credentials', array(
|
||||
'has_identifier' => !empty($this->identifier),
|
||||
'has_password' => !empty($this->password)
|
||||
));
|
||||
return array('error' => 'Missing credentials - please check settings');
|
||||
}
|
||||
}
|
||||
|
||||
$token_url = $this->api_domain . 'xrpc/com.atproto.server.createSession';
|
||||
|
||||
// Debug log
|
||||
error_log('Bluesky Auth - Attempting connection to: ' . $token_url);
|
||||
$this->log_debug('Attempting connection', array('url' => $token_url));
|
||||
|
||||
$headers = array(
|
||||
'Content-Type' => 'application/json',
|
||||
);
|
||||
|
||||
$body = json_encode(array(
|
||||
$body = wp_json_encode(array(
|
||||
'identifier' => $this->identifier,
|
||||
'password' => $this->password,
|
||||
));
|
||||
|
||||
// Debug log
|
||||
error_log('Bluesky Auth - Request body: ' . $body);
|
||||
$this->log_debug('Request prepared', array('body' => str_replace($this->password, '[REDACTED]', $body)));
|
||||
|
||||
$wp_version = get_bloginfo('version');
|
||||
$user_agent = apply_filters('http_headers_useragent', 'WordPress/' . $wp_version . '; ' . get_bloginfo('url'));
|
||||
@ -55,38 +96,50 @@ class Bluesky_Auth {
|
||||
'headers' => $headers,
|
||||
'user-agent' => "$user_agent; Bluesky Connector",
|
||||
'body' => $body,
|
||||
'timeout' => 30, // Increase timeout
|
||||
'timeout' => 30,
|
||||
));
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
$error_message = $response->get_error_message();
|
||||
error_log('Bluesky Auth Error: ' . $error_message);
|
||||
$this->log_debug('Auth Error', array('error' => $error_message));
|
||||
return array('error' => $error_message);
|
||||
}
|
||||
|
||||
// Debug response
|
||||
// Log response details
|
||||
$status_code = wp_remote_retrieve_response_code($response);
|
||||
$response_body = wp_remote_retrieve_body($response);
|
||||
error_log('Bluesky Auth - Response status: ' . $status_code);
|
||||
error_log('Bluesky Auth - Response body: ' . $response_body);
|
||||
$this->log_debug('Response received', array(
|
||||
'status' => $status_code,
|
||||
'body' => $response_body
|
||||
));
|
||||
|
||||
$data = json_decode($response_body, true);
|
||||
|
||||
if (!empty($data['accessJwt']) && !empty($data['refreshJwt']) && !empty($data['did'])) {
|
||||
// Save credentials in both locations
|
||||
$settings = get_option('bluesky_connector_settings', array());
|
||||
$settings['identifier'] = $this->identifier;
|
||||
update_option('bluesky_connector_settings', $settings);
|
||||
|
||||
// Save all necessary tokens and details
|
||||
update_option('bluesky_identifier', sanitize_text_field($this->identifier));
|
||||
update_option('bluesky_access_jwt', sanitize_text_field($data['accessJwt']));
|
||||
update_option('bluesky_refresh_jwt', sanitize_text_field($data['refreshJwt']));
|
||||
update_option('bluesky_did', sanitize_text_field($data['did']));
|
||||
update_option('bluesky_token_created', time());
|
||||
delete_option('bluesky_password'); // Don't store password
|
||||
|
||||
// Store password for reauth
|
||||
update_option('bluesky_password', $this->password);
|
||||
|
||||
$this->log_debug('Authentication successful', array('did' => $data['did']));
|
||||
return $data['accessJwt'];
|
||||
}
|
||||
|
||||
// More detailed error reporting
|
||||
$error_message = isset($data['error']) ? $data['error'] : 'Failed to get access token';
|
||||
if (isset($data['message'])) {
|
||||
$error_message .= ' - ' . $data['message'];
|
||||
}
|
||||
error_log('Bluesky Auth - Error: ' . $error_message);
|
||||
$this->log_debug('Auth Failed', array('error' => $error_message));
|
||||
return array('error' => $error_message);
|
||||
}
|
||||
|
||||
@ -94,7 +147,6 @@ class Bluesky_Auth {
|
||||
$token_created = get_option('bluesky_token_created');
|
||||
$refresh_token = get_option('bluesky_refresh_jwt');
|
||||
|
||||
// Refresh if token is older than 23 hours or doesn't exist
|
||||
return !empty($refresh_token) && ($token_created < (time() - 82800));
|
||||
}
|
||||
|
||||
@ -105,9 +157,7 @@ class Bluesky_Auth {
|
||||
}
|
||||
|
||||
$refresh_url = $this->api_domain . 'xrpc/com.atproto.server.refreshSession';
|
||||
|
||||
// Debug log
|
||||
error_log('Bluesky Auth - Attempting token refresh at: ' . $refresh_url);
|
||||
$this->log_debug('Token refresh attempt', array('url' => $refresh_url));
|
||||
|
||||
$wp_version = get_bloginfo('version');
|
||||
$user_agent = apply_filters('http_headers_useragent', 'WordPress/' . $wp_version . '; ' . get_bloginfo('url'));
|
||||
@ -123,22 +173,18 @@ class Bluesky_Auth {
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
$error_message = $response->get_error_message();
|
||||
error_log('Bluesky Token Refresh Error: ' . $error_message);
|
||||
$this->log_debug('Token Refresh Error', array('error' => $error_message));
|
||||
return array('error' => $error_message);
|
||||
}
|
||||
|
||||
// Debug response
|
||||
$status_code = wp_remote_retrieve_response_code($response);
|
||||
$response_body = wp_remote_retrieve_body($response);
|
||||
error_log('Bluesky Auth Refresh - Response status: ' . $status_code);
|
||||
error_log('Bluesky Auth Refresh - Response body: ' . $response_body);
|
||||
|
||||
$data = json_decode($response_body, true);
|
||||
$data = json_decode(wp_remote_retrieve_body($response), true);
|
||||
|
||||
if (!empty($data['accessJwt']) && !empty($data['refreshJwt'])) {
|
||||
update_option('bluesky_access_jwt', sanitize_text_field($data['accessJwt']));
|
||||
update_option('bluesky_refresh_jwt', sanitize_text_field($data['refreshJwt']));
|
||||
update_option('bluesky_token_created', time());
|
||||
|
||||
$this->log_debug('Token refresh successful');
|
||||
return $data['accessJwt'];
|
||||
}
|
||||
|
||||
@ -146,7 +192,23 @@ class Bluesky_Auth {
|
||||
if (isset($data['message'])) {
|
||||
$error_message .= ' - ' . $data['message'];
|
||||
}
|
||||
error_log('Bluesky Auth Refresh - Error: ' . $error_message);
|
||||
$this->log_debug('Token Refresh Failed', array('error' => $error_message));
|
||||
return array('error' => $error_message);
|
||||
}
|
||||
|
||||
private function log_debug($message, $data = array()) {
|
||||
if (defined('WP_DEBUG') && WP_DEBUG) {
|
||||
$log_message = sprintf(
|
||||
'[Bluesky Connector] %s | Data: %s',
|
||||
$message,
|
||||
wp_json_encode($data, JSON_PRETTY_PRINT)
|
||||
);
|
||||
|
||||
if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
|
||||
error_log($log_message);
|
||||
}
|
||||
|
||||
do_action('bluesky_connector_debug', $message, $data);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,243 +1,457 @@
|
||||
<?php
|
||||
class Post_Formatter {
|
||||
class Post_Formatter
|
||||
{
|
||||
private $api;
|
||||
private $max_length = 300;
|
||||
|
||||
public function __construct($access_token, $did) {
|
||||
private function diagnose_thumbnail_support($post_id) {
|
||||
error_log('[Bluesky Connector] Starting thumbnail support diagnosis');
|
||||
|
||||
// Check WordPress version
|
||||
error_log('[Bluesky Connector] WordPress Version: ' . get_bloginfo('version'));
|
||||
|
||||
// Check if theme supports post thumbnails
|
||||
$theme_support = current_theme_supports('post-thumbnails');
|
||||
error_log('[Bluesky Connector] Theme supports post thumbnails: ' . ($theme_support ? 'yes' : 'no'));
|
||||
|
||||
// If theme doesn't support thumbnails, check if we can add support
|
||||
if (!$theme_support) {
|
||||
error_log('[Bluesky Connector] Attempting to add post thumbnail support');
|
||||
add_theme_support('post-thumbnails');
|
||||
$theme_support = current_theme_supports('post-thumbnails');
|
||||
error_log('[Bluesky Connector] Post thumbnail support after attempt: ' . ($theme_support ? 'yes' : 'no'));
|
||||
}
|
||||
|
||||
// Check post type support
|
||||
$post_type = get_post_type($post_id);
|
||||
$post_type_support = post_type_supports($post_type, 'thumbnail');
|
||||
error_log('[Bluesky Connector] Post type ' . $post_type . ' supports thumbnails: ' . ($post_type_support ? 'yes' : 'no'));
|
||||
|
||||
// Check post meta directly
|
||||
$post_meta = get_post_meta($post_id);
|
||||
error_log('[Bluesky Connector] All post meta for debugging: ' . print_r($post_meta, true));
|
||||
|
||||
// Check attachment status
|
||||
$thumbnail_id = get_post_thumbnail_id($post_id);
|
||||
if ($thumbnail_id) {
|
||||
$attachment = get_post($thumbnail_id);
|
||||
if ($attachment) {
|
||||
error_log('[Bluesky Connector] Attachment details: ' . print_r([
|
||||
'ID' => $attachment->ID,
|
||||
'post_type' => $attachment->post_type,
|
||||
'status' => $attachment->post_status,
|
||||
'mime_type' => $attachment->post_mime_type,
|
||||
'attached_file' => get_attached_file($thumbnail_id),
|
||||
'exists' => file_exists(get_attached_file($thumbnail_id))
|
||||
], true));
|
||||
} else {
|
||||
error_log('[Bluesky Connector] Attachment post not found for ID: ' . $thumbnail_id);
|
||||
}
|
||||
}
|
||||
|
||||
return $theme_support && $post_type_support;
|
||||
}
|
||||
|
||||
public function __construct($access_token, $did)
|
||||
{
|
||||
error_log('[Bluesky Connector] Initializing Post_Formatter with DID: ' . $did);
|
||||
$this->api = new Bluesky_API($access_token, $did);
|
||||
}
|
||||
|
||||
public function format_and_post($post) {
|
||||
$content = $this->get_formatted_content($post);
|
||||
|
||||
$post_data = array(
|
||||
'$type' => 'app.bsky.feed.post',
|
||||
'text' => $content,
|
||||
'createdAt' => gmdate('c', strtotime($post->post_date_gmt)),
|
||||
'langs' => array('en')
|
||||
);
|
||||
public function format_and_post($post, $formatted_content = null)
|
||||
{
|
||||
try {
|
||||
error_log('[Bluesky Connector] Starting format_and_post for post ' . $post->ID);
|
||||
|
||||
// Use provided content if available, otherwise format it
|
||||
$content = $formatted_content ?: $this->get_formatted_content($post);
|
||||
error_log('[Bluesky Connector] Formatted content: ' . $content);
|
||||
|
||||
// Add facets for the URL
|
||||
$post_data['facets'] = $this->parse_facets($post);
|
||||
$post_data = array(
|
||||
'$type' => 'app.bsky.feed.post',
|
||||
'text' => $content,
|
||||
'createdAt' => gmdate('c', strtotime($post->post_date_gmt)),
|
||||
'langs' => array('en')
|
||||
);
|
||||
|
||||
// Handle image embed separately from text content
|
||||
if (has_post_thumbnail($post->ID)) {
|
||||
$image_data = $this->handle_featured_image($post->ID);
|
||||
if (!empty($image_data) && !isset($image_data['error'])) {
|
||||
$post_data['embed'] = $image_data;
|
||||
// Add facets for the URL
|
||||
$post_data['facets'] = $this->parse_facets($post);
|
||||
error_log('[Bluesky Connector] Added facets: ' . wp_json_encode($post_data['facets']));
|
||||
|
||||
// Debug thumbnail support
|
||||
error_log('[Bluesky Connector] Checking for featured image...');
|
||||
error_log('[Bluesky Connector] Post type: ' . $post->post_type);
|
||||
error_log('[Bluesky Connector] has_post_thumbnail result: ' . (has_post_thumbnail($post->ID) ? 'true' : 'false'));
|
||||
error_log('[Bluesky Connector] Theme supports thumbnails: ' . (current_theme_supports('post-thumbnails') ? 'true' : 'false'));
|
||||
error_log('[Bluesky Connector] Post thumbnail meta check:');
|
||||
error_log('[Bluesky Connector] _thumbnail_id: ' . get_post_meta($post->ID, '_thumbnail_id', true));
|
||||
error_log('[Bluesky Connector] Post status: ' . get_post_status($post->ID));
|
||||
|
||||
// Handle image embed
|
||||
if (has_post_thumbnail($post->ID)) {
|
||||
error_log('[Bluesky Connector] Processing featured image for post ' . $post->ID);
|
||||
$image_data = $this->handle_featured_image($post->ID);
|
||||
if (!empty($image_data) && !isset($image_data['error'])) {
|
||||
$post_data['embed'] = $image_data;
|
||||
error_log('[Bluesky Connector] Image data added to post: ' . wp_json_encode($image_data));
|
||||
} else {
|
||||
error_log('[Bluesky Connector] Image processing error: ' . ($image_data['error'] ?? 'Unknown error'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->api->create_post($post_data);
|
||||
error_log('[Bluesky Connector] Sending post data to API: ' . wp_json_encode($post_data));
|
||||
$response = $this->api->create_post($post_data);
|
||||
error_log('[Bluesky Connector] API Response: ' . wp_json_encode($response));
|
||||
|
||||
return $response;
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('[Bluesky Connector] Error in format_and_post: ' . $e->getMessage());
|
||||
return array('error' => $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function get_formatted_content($post) {
|
||||
$format = get_option('bluesky_post_format', 'image-title-excerpt-link');
|
||||
$include_title = get_option('bluesky_include_title', true);
|
||||
|
||||
// Get individual components
|
||||
$title = $include_title ? $post->post_title : '';
|
||||
$excerpt = $this->get_excerpt($post);
|
||||
$url = wp_get_shortlink($post->ID);
|
||||
|
||||
// Start building content with explicit line breaks
|
||||
$content = '';
|
||||
|
||||
// Add title with line break if it exists
|
||||
if (!empty($title)) {
|
||||
$content .= $title . "\n\n";
|
||||
}
|
||||
|
||||
// Add excerpt if it exists
|
||||
if (!empty($excerpt)) {
|
||||
$content .= $excerpt . "\n\n"; // Add double line break after excerpt
|
||||
}
|
||||
|
||||
// Add URL on its own line
|
||||
if (!empty($url)) {
|
||||
$content .= $url; // URL starts on new line due to previous \n\n
|
||||
}
|
||||
private function get_formatted_content($post)
|
||||
{
|
||||
try {
|
||||
error_log('[Bluesky Connector] Starting content formatting for post ' . $post->ID);
|
||||
|
||||
$format = get_option('bluesky_post_format', 'image-title-excerpt-link');
|
||||
$include_title = get_option('bluesky_include_title', true);
|
||||
|
||||
return $content;
|
||||
error_log('[Bluesky Connector] Using format: ' . $format . ', Include title: ' . ($include_title ? 'yes' : 'no'));
|
||||
|
||||
// Get individual components
|
||||
$title = $include_title ? $post->post_title : '';
|
||||
$excerpt = $this->get_excerpt($post);
|
||||
$url = wp_get_shortlink($post->ID);
|
||||
|
||||
error_log('[Bluesky Connector] Content components:');
|
||||
error_log('[Bluesky Connector] - Title: ' . $title);
|
||||
error_log('[Bluesky Connector] - Excerpt length: ' . strlen($excerpt));
|
||||
error_log('[Bluesky Connector] - URL: ' . $url);
|
||||
|
||||
// Start building content
|
||||
$content = '';
|
||||
|
||||
// Add title with line break if it exists
|
||||
if (!empty($title)) {
|
||||
$content .= $title . "\n\n";
|
||||
}
|
||||
|
||||
// Add excerpt if it exists
|
||||
if (!empty($excerpt)) {
|
||||
$content .= $excerpt . "\n\n";
|
||||
}
|
||||
|
||||
// Add URL on its own line
|
||||
if (!empty($url)) {
|
||||
$content .= "Continue Reading: " . $url;
|
||||
}
|
||||
|
||||
error_log('[Bluesky Connector] Final formatted content: ' . $content);
|
||||
return $content;
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('[Bluesky Connector] Error in get_formatted_content: ' . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function get_excerpt($post) {
|
||||
private function get_excerpt($post)
|
||||
{
|
||||
try {
|
||||
error_log('[Bluesky Connector] Getting excerpt for post ' . $post->ID);
|
||||
|
||||
$text = wp_strip_all_tags($post->post_excerpt);
|
||||
if (empty($text)) {
|
||||
$text = wp_strip_all_tags($post->post_content);
|
||||
error_log('[Bluesky Connector] Using post content for excerpt (no excerpt found)');
|
||||
}
|
||||
|
||||
|
||||
$url = wp_get_shortlink($post->ID);
|
||||
$include_title = get_option('bluesky_include_title', true);
|
||||
|
||||
// Calculate available length accounting for spacing and new lines
|
||||
// Calculate available length
|
||||
$available_length = $this->max_length;
|
||||
$available_length -= strlen($url);
|
||||
$available_length -= 2; // Account for \n\n after excerpt
|
||||
$available_length -= strlen("Continue Reading: "); // Account for the prefix
|
||||
$available_length -= 4; // Account for \n\n before and after the URL
|
||||
|
||||
if ($include_title) {
|
||||
$available_length -= strlen($post->post_title);
|
||||
$available_length -= 2; // Account for \n\n after title
|
||||
}
|
||||
|
||||
|
||||
error_log('[Bluesky Connector] Available length for excerpt: ' . $available_length);
|
||||
|
||||
if (mb_strlen($text) > $available_length) {
|
||||
$text = mb_substr($text, 0, $available_length - 3) . '...';
|
||||
error_log('[Bluesky Connector] Excerpt truncated to fit length limit');
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private function parse_facets($post) {
|
||||
$facets = array();
|
||||
$content = $this->get_formatted_content($post);
|
||||
|
||||
// Add link facet for the post URL
|
||||
$url = wp_get_shortlink($post->ID);
|
||||
$text_bytes = mb_convert_encoding($content, 'UTF-8');
|
||||
$url_position = mb_strrpos($text_bytes, $url);
|
||||
|
||||
if ($url_position !== false) {
|
||||
$facets[] = array(
|
||||
'index' => array(
|
||||
'byteStart' => $url_position,
|
||||
'byteEnd' => $url_position + strlen($url),
|
||||
),
|
||||
'features' => array(
|
||||
error_log('[Bluesky Connector] Final excerpt length: ' . mb_strlen($text));
|
||||
return $text;
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('[Bluesky Connector] Error in get_excerpt: ' . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function parse_facets($post)
|
||||
{
|
||||
try {
|
||||
error_log('[Bluesky Connector] Parsing facets for post ' . $post->ID);
|
||||
|
||||
$facets = array();
|
||||
$content = $this->get_formatted_content($post);
|
||||
$url = wp_get_shortlink($post->ID);
|
||||
$text_bytes = mb_convert_encoding($content, 'UTF-8');
|
||||
$url_position = mb_strrpos($text_bytes, $url);
|
||||
|
||||
if ($url_position !== false) {
|
||||
$facets[] = array(
|
||||
'index' => array(
|
||||
'byteStart' => $url_position,
|
||||
'byteEnd' => $url_position + strlen($url),
|
||||
),
|
||||
'features' => array(
|
||||
array(
|
||||
'$type' => 'app.bsky.richtext.facet#link',
|
||||
'uri' => $url,
|
||||
),
|
||||
),
|
||||
);
|
||||
error_log('[Bluesky Connector] Added URL facet for: ' . $url);
|
||||
}
|
||||
|
||||
error_log('[Bluesky Connector] Generated facets: ' . wp_json_encode($facets));
|
||||
return $facets;
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('[Bluesky Connector] Error in parse_facets: ' . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function handle_featured_image($post_id) {
|
||||
try {
|
||||
error_log('[Bluesky Connector] Starting featured image process for post ' . $post_id);
|
||||
|
||||
// Run diagnostics first
|
||||
$thumbnail_support = $this->diagnose_thumbnail_support($post_id);
|
||||
if (!$thumbnail_support) {
|
||||
error_log('[Bluesky Connector] Thumbnail support is not properly configured');
|
||||
}
|
||||
|
||||
// Get image ID with multiple fallbacks
|
||||
$image_id = get_post_thumbnail_id($post_id);
|
||||
error_log('[Bluesky Connector] Initial image ID from get_post_thumbnail_id: ' . $image_id);
|
||||
|
||||
if (!$image_id) {
|
||||
// Try direct meta approach
|
||||
$image_id = get_post_meta($post_id, '_thumbnail_id', true);
|
||||
error_log('[Bluesky Connector] Image ID from direct meta: ' . $image_id);
|
||||
|
||||
// If still no image, check for fallback
|
||||
if (!$image_id) {
|
||||
$image_id = get_option('bluesky_fallback_image');
|
||||
error_log('[Bluesky Connector] Using fallback image ID: ' . $image_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$image_id) {
|
||||
return array('error' => 'No valid image ID found');
|
||||
}
|
||||
|
||||
// Get the image file path
|
||||
$image_path = get_attached_file($image_id);
|
||||
error_log('[Bluesky Connector] Image path: ' . ($image_path ?: 'not found'));
|
||||
|
||||
// Verify file exists and is accessible
|
||||
if (!$image_path || !file_exists($image_path)) {
|
||||
$upload_dir = wp_upload_dir();
|
||||
error_log('[Bluesky Connector] Upload directory information: ' . print_r($upload_dir, true));
|
||||
return array('error' => 'Image file not found or inaccessible');
|
||||
}
|
||||
|
||||
// Check file permissions
|
||||
error_log('[Bluesky Connector] File permissions: ' . decoct(fileperms($image_path) & 0777));
|
||||
|
||||
// Verify mime type
|
||||
$mime_type = get_post_mime_type($image_id);
|
||||
error_log('[Bluesky Connector] Mime type: ' . $mime_type);
|
||||
|
||||
// Validate mime type
|
||||
$allowed_types = array('image/jpeg', 'image/png', 'image/gif');
|
||||
if (!in_array($mime_type, $allowed_types)) {
|
||||
return array('error' => 'Unsupported image type: ' . $mime_type);
|
||||
}
|
||||
|
||||
// Get image data
|
||||
$image_data = file_get_contents($image_path);
|
||||
if ($image_data === false) {
|
||||
return array('error' => 'Failed to read image file');
|
||||
}
|
||||
|
||||
// Check and handle file size
|
||||
$size = strlen($image_data);
|
||||
error_log('[Bluesky Connector] Original image size: ' . $size . ' bytes');
|
||||
|
||||
if ($size > 1000000) {
|
||||
error_log('[Bluesky Connector] Image exceeds size limit, attempting resize');
|
||||
$resized = $this->resize_image($image_path);
|
||||
|
||||
if ($resized) {
|
||||
error_log('[Bluesky Connector] Image resized successfully');
|
||||
$image_path = $resized;
|
||||
|
||||
// Verify new size
|
||||
$new_size = filesize($resized);
|
||||
error_log('[Bluesky Connector] New image size: ' . $new_size . ' bytes');
|
||||
|
||||
if ($new_size > 1000000) {
|
||||
error_log('[Bluesky Connector] Resized image still too large');
|
||||
return array('error' => 'Unable to reduce image size below 1MB');
|
||||
}
|
||||
} else {
|
||||
error_log('[Bluesky Connector] Image resize failed');
|
||||
return array('error' => 'Image resize failed');
|
||||
}
|
||||
}
|
||||
|
||||
// Upload to Bluesky
|
||||
error_log('[Bluesky Connector] Uploading image to Bluesky');
|
||||
$response = $this->api->upload_blob($image_path, $mime_type);
|
||||
|
||||
if (isset($response['error'])) {
|
||||
error_log('[Bluesky Connector] Upload failed: ' . $response['error']);
|
||||
return $response;
|
||||
}
|
||||
|
||||
// Clean up temporary file if it exists
|
||||
if (isset($resized) && file_exists($resized)) {
|
||||
unlink($resized);
|
||||
error_log('[Bluesky Connector] Cleaned up temporary resized file');
|
||||
}
|
||||
|
||||
// Get alt text
|
||||
$alt_text = get_post_meta($image_id, '_wp_attachment_image_alt', true) ?: '';
|
||||
error_log('[Bluesky Connector] Using alt text: ' . $alt_text);
|
||||
|
||||
// Prepare final image embed
|
||||
$image_embed = array(
|
||||
'$type' => 'app.bsky.embed.images',
|
||||
'images' => array(
|
||||
array(
|
||||
'$type' => 'app.bsky.richtext.facet#link',
|
||||
'uri' => $url,
|
||||
'alt' => $alt_text,
|
||||
'image' => $response['blob'],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
error_log('[Bluesky Connector] Image embed prepared successfully');
|
||||
return $image_embed;
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('[Bluesky Connector] Error in handle_featured_image: ' . $e->getMessage());
|
||||
error_log('[Bluesky Connector] Stack trace: ' . $e->getTraceAsString());
|
||||
return array('error' => $e->getMessage());
|
||||
}
|
||||
|
||||
return $facets;
|
||||
}
|
||||
|
||||
private function handle_featured_image($post_id) {
|
||||
$image_id = get_post_thumbnail_id($post_id);
|
||||
$image_path = get_attached_file($image_id);
|
||||
|
||||
if (!$image_path) {
|
||||
return array('error' => 'Image file not found');
|
||||
}
|
||||
|
||||
$mime_type = get_post_mime_type($image_id);
|
||||
|
||||
// Get image data
|
||||
$image_data = file_get_contents($image_path);
|
||||
if ($image_data === false) {
|
||||
return array('error' => 'Failed to read image file');
|
||||
}
|
||||
|
||||
// Check file size (1MB limit for Bluesky)
|
||||
if (strlen($image_data) > 1000000) {
|
||||
// If image is too large, attempt to resize it
|
||||
$resized = $this->resize_image($image_path);
|
||||
if ($resized) {
|
||||
$image_data = file_get_contents($resized);
|
||||
unlink($resized); // Clean up temporary file
|
||||
} else {
|
||||
return array('error' => 'Image file size exceeds 1MB limit and resize failed');
|
||||
}
|
||||
}
|
||||
|
||||
// Upload image blob
|
||||
$response = $this->api->upload_blob($image_path, $mime_type);
|
||||
|
||||
if (isset($response['error'])) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
// Get the alt text
|
||||
$alt_text = get_post_meta($image_id, '_wp_attachment_image_alt', true) ?: '';
|
||||
|
||||
return array(
|
||||
'$type' => 'app.bsky.embed.images',
|
||||
'images' => array(
|
||||
array(
|
||||
'alt' => $alt_text,
|
||||
'image' => $response['blob'],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
private function resize_image($image_path) {
|
||||
// Only proceed if GD is available
|
||||
if (!function_exists('imagecreatefrompng')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$mime_type = mime_content_type($image_path);
|
||||
list($width, $height) = getimagesize($image_path);
|
||||
|
||||
// Calculate new dimensions while maintaining aspect ratio
|
||||
$max_dimension = 1000; // Reasonable size that should result in < 1MB file
|
||||
if ($width > $height) {
|
||||
$new_width = $max_dimension;
|
||||
$new_height = floor($height * ($max_dimension / $width));
|
||||
} else {
|
||||
$new_height = $max_dimension;
|
||||
$new_width = floor($width * ($max_dimension / $height));
|
||||
}
|
||||
|
||||
// Create new image
|
||||
$new_image = imagecreatetruecolor($new_width, $new_height);
|
||||
|
||||
// Handle different image types
|
||||
switch ($mime_type) {
|
||||
case 'image/jpeg':
|
||||
$source = imagecreatefromjpeg($image_path);
|
||||
break;
|
||||
case 'image/png':
|
||||
$source = imagecreatefrompng($image_path);
|
||||
// Preserve transparency
|
||||
imagealphablending($new_image, false);
|
||||
imagesavealpha($new_image, true);
|
||||
break;
|
||||
case 'image/gif':
|
||||
$source = imagecreatefromgif($image_path);
|
||||
break;
|
||||
default:
|
||||
private function resize_image($image_path)
|
||||
{
|
||||
try {
|
||||
error_log('[Bluesky Connector] Starting image resize for: ' . $image_path);
|
||||
|
||||
if (!function_exists('imagecreatefrompng')) {
|
||||
error_log('[Bluesky Connector] GD library not available');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$source) {
|
||||
$mime_type = mime_content_type($image_path);
|
||||
list($width, $height) = getimagesize($image_path);
|
||||
error_log('[Bluesky Connector] Original dimensions: ' . $width . 'x' . $height);
|
||||
|
||||
// Calculate new dimensions
|
||||
$max_dimension = 1000;
|
||||
if ($width > $height) {
|
||||
$new_width = $max_dimension;
|
||||
$new_height = floor($height * ($max_dimension / $width));
|
||||
} else {
|
||||
$new_height = $max_dimension;
|
||||
$new_width = floor($width * ($max_dimension / $height));
|
||||
}
|
||||
|
||||
error_log('[Bluesky Connector] New dimensions: ' . $new_width . 'x' . $new_height);
|
||||
|
||||
$new_image = imagecreatetruecolor($new_width, $new_height);
|
||||
|
||||
switch ($mime_type) {
|
||||
case 'image/jpeg':
|
||||
$source = imagecreatefromjpeg($image_path);
|
||||
break;
|
||||
case 'image/png':
|
||||
$source = imagecreatefrompng($image_path);
|
||||
imagealphablending($new_image, false);
|
||||
imagesavealpha($new_image, true);
|
||||
break;
|
||||
case 'image/gif':
|
||||
$source = imagecreatefromgif($image_path);
|
||||
break;
|
||||
default:
|
||||
error_log('[Bluesky Connector] Unsupported image type: ' . $mime_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$source) {
|
||||
error_log('[Bluesky Connector] Failed to create image resource');
|
||||
return false;
|
||||
}
|
||||
|
||||
imagecopyresampled(
|
||||
$new_image,
|
||||
$source,
|
||||
0, 0, 0, 0,
|
||||
$new_width,
|
||||
$new_height,
|
||||
$width,
|
||||
$height
|
||||
);
|
||||
|
||||
// Use PHP's tempnam
|
||||
$temp_file = tempnam(sys_get_temp_dir(), 'bluesky_img_');
|
||||
error_log('[Bluesky Connector] Created temp file: ' . $temp_file);
|
||||
|
||||
$success = false;
|
||||
switch ($mime_type) {
|
||||
case 'image/jpeg':
|
||||
$success = imagejpeg($new_image, $temp_file, 85);
|
||||
break;
|
||||
case 'image/png':
|
||||
$success = imagepng($new_image, $temp_file, 8);
|
||||
break;
|
||||
case 'image/gif':
|
||||
$success = imagegif($new_image, $temp_file);
|
||||
break;
|
||||
}
|
||||
|
||||
imagedestroy($source);
|
||||
imagedestroy($new_image);
|
||||
|
||||
if ($success) {
|
||||
error_log('[Bluesky Connector] Image resized successfully');
|
||||
return $temp_file;
|
||||
} else {
|
||||
error_log('[Bluesky Connector] Failed to save resized image');
|
||||
return false;
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('[Bluesky Connector] Error in resize_image: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resize
|
||||
imagecopyresampled(
|
||||
$new_image,
|
||||
$source,
|
||||
0, 0, 0, 0,
|
||||
$new_width,
|
||||
$new_height,
|
||||
$width,
|
||||
$height
|
||||
);
|
||||
|
||||
// Create temporary file
|
||||
$temp_file = tempnam(sys_get_temp_dir(), 'bluesky_img_');
|
||||
|
||||
// Save resized image
|
||||
switch ($mime_type) {
|
||||
case 'image/jpeg':
|
||||
imagejpeg($new_image, $temp_file, 85);
|
||||
break;
|
||||
case 'image/png':
|
||||
imagepng($new_image, $temp_file, 8);
|
||||
break;
|
||||
case 'image/gif':
|
||||
imagegif($new_image, $temp_file);
|
||||
break;
|
||||
}
|
||||
|
||||
// Clean up
|
||||
imagedestroy($source);
|
||||
imagedestroy($new_image);
|
||||
|
||||
return $temp_file;
|
||||
}
|
||||
}
|
@ -1,58 +1,64 @@
|
||||
<div class="bluesky-post-status">
|
||||
<?php wp_nonce_field('bluesky_post_meta_box', 'bluesky_post_meta_box_nonce'); ?>
|
||||
|
||||
<?php if (!empty($status)) : ?>
|
||||
<?php if (!empty($status)): ?>
|
||||
<p>
|
||||
<strong><?php _e('Status:', 'bluesky-connector'); ?></strong>
|
||||
<strong><?php esc_html_e('Status:', 'bluesky-connctor'); ?></strong>
|
||||
<?php
|
||||
switch ($status) {
|
||||
case 'success':
|
||||
echo '<span class="bluesky-status-success">' . esc_html__('Posted', 'bluesky-connector') . '</span>';
|
||||
echo '<span class="bluesky-status-success">' . esc_html__('Posted', 'bluesky-connctor') . '</span>';
|
||||
break;
|
||||
case 'error':
|
||||
echo '<span class="bluesky-status-error">' . esc_html__('Error', 'bluesky-connector') . '</span>';
|
||||
echo '<span class="bluesky-status-error">' . esc_html__('Error', 'bluesky-connctor') . '</span>';
|
||||
break;
|
||||
case 'queued':
|
||||
echo '<span class="bluesky-status-pending">' . esc_html__('Queued', 'bluesky-connector') . '</span>';
|
||||
case 'pending':
|
||||
echo '<span class="bluesky-status-pending">' . esc_html__('Publishing...', 'bluesky-connctor') . '</span>';
|
||||
break;
|
||||
default:
|
||||
echo '<span class="bluesky-status-unknown">' . esc_html__('Unknown', 'bluesky-connector') . '</span>';
|
||||
echo '<span class="bluesky-status-unknown">' . esc_html__('Not Posted', 'bluesky-connctor') . '</span>';
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
|
||||
<?php if ($posted_date) : ?>
|
||||
<?php if ($posted_date): ?>
|
||||
<p>
|
||||
<strong><?php _e('Posted:', 'bluesky-connector'); ?></strong>
|
||||
<strong><?php esc_html_e('Posted:', 'bluesky-connctor'); ?></strong>
|
||||
<?php echo esc_html(date_i18n(get_option('date_format') . ' ' . get_option('time_format'), strtotime($posted_date))); ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($post_id) : ?>
|
||||
<?php if ($post_id): ?>
|
||||
<p>
|
||||
<strong><?php _e('Bluesky Post ID:', 'bluesky-connector'); ?></strong>
|
||||
<code><?php echo esc_html($post_id); ?></code>
|
||||
<strong><?php esc_html_e('Bluesky Post:', 'bluesky-connctor'); ?></strong>
|
||||
<a href="https://bsky.app/profile/<?php echo esc_attr(get_option('bluesky_identifier')); ?>/post/<?php echo esc_attr($post_id); ?>"
|
||||
target="_blank" rel="noopener noreferrer">
|
||||
<?php esc_html_e('View Post', 'bluesky-connctor'); ?> ↗
|
||||
</a>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($error) : ?>
|
||||
<?php if ($error): ?>
|
||||
<p class="bluesky-error-message">
|
||||
<strong><?php _e('Error:', 'bluesky-connector'); ?></strong>
|
||||
<strong><?php esc_html_e('Error:', 'bluesky-connctor'); ?></strong>
|
||||
<?php echo esc_html($error); ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="bluesky-actions">
|
||||
<?php if ($status === 'error' || empty($post_id)) : ?>
|
||||
<button type="button" class="button bluesky-retry-post" data-post-id="<?php echo esc_attr($post->ID); ?>">
|
||||
<?php _e('Retry Post', 'bluesky-connector'); ?>
|
||||
<?php if ($status === 'error' || !$post_id): ?>
|
||||
<button type="button" class="button bluesky-retry-post" data-post-id="<?php echo esc_attr($post->ID); ?>"
|
||||
data-nonce="<?php echo esc_attr(wp_create_nonce('bluesky_retry_post')); ?>">
|
||||
<?php esc_html_e('Retry Post', 'bluesky-connctor'); ?>
|
||||
</button>
|
||||
<?php else: ?>
|
||||
<button type="button" class="button bluesky-repost" data-post-id="<?php echo esc_attr($post->ID); ?>"
|
||||
data-nonce="<?php echo esc_attr(wp_create_nonce('bluesky_repost')); ?>">
|
||||
<?php esc_html_e('Post Again', 'bluesky-connctor'); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<p><?php _e('This post has not been shared to Bluesky yet.', 'bluesky-connector'); ?></p>
|
||||
<button type="button" class="button bluesky-share-post" data-post-id="<?php echo esc_attr($post->ID); ?>">
|
||||
<?php _e('Share to Bluesky', 'bluesky-connector'); ?>
|
||||
<?php else: ?>
|
||||
<p><?php esc_html_e('This post has not been shared to Bluesky.', 'bluesky-connctor'); ?></p>
|
||||
<button type="button" class="button button-primary bluesky-share-post"
|
||||
data-post-id="<?php echo esc_attr($post->ID); ?>"
|
||||
data-nonce="<?php echo esc_attr(wp_create_nonce('bluesky_share_post')); ?>">
|
||||
<?php esc_html_e('Share to Bluesky', 'bluesky-connctor'); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
@ -1,167 +1,145 @@
|
||||
<div class="wrap">
|
||||
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
|
||||
|
||||
<?php if (!empty($settings['connection_status'])) : ?>
|
||||
<?php if ($settings['connection_status'] === 'connected') : ?>
|
||||
<div class="notice notice-success">
|
||||
<p><?php _e('Successfully connected to Bluesky!', 'bluesky-connector'); ?></p>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div class="notice notice-error">
|
||||
<p><?php printf(__('Connection error: %s', 'bluesky-connector'), esc_html($settings['last_error'])); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($settings['connection_status'] === 'connected'): ?>
|
||||
<div class="notice notice-success">
|
||||
<p><?php _e('Successfully connected to Bluesky!', 'bluesky-connctor'); ?></p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="notice notice-error">
|
||||
<!-- translators: %s: Error message -->
|
||||
<p><?php printf(
|
||||
esc_html__('Connection error: %s', 'bluesky-connctor'),
|
||||
esc_html($settings['last_error'])
|
||||
); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card">
|
||||
<h2><?php _e('Connection Settings', 'bluesky-connector'); ?></h2>
|
||||
<h2><?php esc_html_e('Connection Settings', 'bluesky-connctor'); ?></h2>
|
||||
<form method="post" action="">
|
||||
<?php wp_nonce_field('bluesky_connector_settings'); ?>
|
||||
<input type="hidden" name="action" value="update_bluesky_settings">
|
||||
|
||||
|
||||
<table class="form-table" role="presentation">
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="bluesky_domain"><?php _e('Bluesky Domain', 'bluesky-connector'); ?></label>
|
||||
<label for="bluesky_domain"><?php esc_html_e('Bluesky Domain', 'bluesky-connctor'); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<input name="bluesky_domain"
|
||||
type="url"
|
||||
id="bluesky_domain"
|
||||
value="https://bsky.social"
|
||||
class="regular-text"
|
||||
readonly>
|
||||
<input name="bluesky_connector_settings[domain]" type="url" id="bluesky_domain"
|
||||
value="https://bsky.social" class="regular-text" readonly>
|
||||
<p class="description">
|
||||
<?php _e('The Bluesky API domain (fixed to https://bsky.social)', 'bluesky-connector'); ?>
|
||||
<?php esc_html_e('The Bluesky API domain (fixed to https://bsky.social)', 'bluesky-connctor'); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="bluesky_identifier"><?php _e('Bluesky Handle', 'bluesky-connector'); ?></label>
|
||||
<label for="bluesky_identifier"><?php esc_html_e('Bluesky Handle', 'bluesky-connctor'); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<input name="bluesky_identifier"
|
||||
type="text"
|
||||
id="bluesky_identifier"
|
||||
value="<?php echo esc_attr($settings['identifier']); ?>"
|
||||
class="regular-text"
|
||||
placeholder="username.bsky.social"
|
||||
required>
|
||||
<input name="bluesky_connector_settings[identifier]" type="text" id="bluesky_identifier"
|
||||
value="<?php echo esc_attr($settings['identifier']); ?>" class="regular-text"
|
||||
placeholder="username.bsky.social" required>
|
||||
<p class="description">
|
||||
<?php _e('Your full Bluesky handle (e.g., username.bsky.social)', 'bluesky-connector'); ?>
|
||||
<?php esc_html_e('Your full Bluesky handle (e.g., username.bsky.social)', 'bluesky-connctor'); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="bluesky_password"><?php _e('App Password', 'bluesky-connector'); ?></label>
|
||||
<label for="bluesky_password"><?php esc_html_e('App Password', 'bluesky-connctor'); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<input name="bluesky_password"
|
||||
type="password"
|
||||
id="bluesky_password"
|
||||
class="regular-text"
|
||||
<?php echo empty($settings['identifier']) ? 'required' : ''; ?>>
|
||||
<input name="bluesky_connector_settings[password]" type="password" id="bluesky_password"
|
||||
class="regular-text" <?php echo empty($settings['identifier']) ? 'required' : ''; ?>>
|
||||
<p class="description">
|
||||
<?php _e('Your Bluesky app password (will not be stored)', 'bluesky-connector'); ?>
|
||||
<?php esc_html_e('Your Bluesky app password (will not be stored)', 'bluesky-connctor'); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<?php submit_button(__('Save Connection Settings', 'bluesky-connector')); ?>
|
||||
|
||||
<?php submit_button(esc_html__('Save Connection Settings', 'bluesky-connctor')); ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($settings['connection_status']) && $settings['connection_status'] === 'connected') : ?>
|
||||
<?php if (!empty($settings['connection_status']) && $settings['connection_status'] === 'connected'): ?>
|
||||
<div class="card" style="margin-top: 20px;">
|
||||
<h2><?php _e('Post Format Settings', 'bluesky-connector'); ?></h2>
|
||||
<h2><?php esc_html_e('Post Format Settings', 'bluesky-connctor'); ?></h2>
|
||||
<form method="post" action="options.php">
|
||||
<?php settings_fields('bluesky_connector_settings'); ?>
|
||||
<?php
|
||||
settings_fields('bluesky-connector');
|
||||
do_settings_sections('bluesky-connector');
|
||||
?>
|
||||
<table class="form-table" role="presentation">
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="bluesky_post_format"><?php _e('Post Layout', 'bluesky-connector'); ?></label>
|
||||
<label for="bluesky_post_format"><?php esc_html_e('Post Layout', 'bluesky-connctor'); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<select name="bluesky_post_format" id="bluesky_post_format">
|
||||
<option value="title-excerpt-link" <?php selected(get_option('bluesky_post_format'), 'title-excerpt-link'); ?>>
|
||||
<?php _e('Title + Excerpt + Link (No Image)', 'bluesky-connector'); ?>
|
||||
<select name="bluesky_connector_settings[post_format]" id="bluesky_post_format">
|
||||
<option value="title-excerpt-link" <?php selected($settings['post_format'] ?? 'title-excerpt-link', 'title-excerpt-link'); ?>>
|
||||
<?php esc_html_e('Title + Excerpt + Link (No Image)', 'bluesky-connctor'); ?>
|
||||
</option>
|
||||
<option value="image-title-excerpt-link" <?php selected(get_option('bluesky_post_format'), 'image-title-excerpt-link'); ?>>
|
||||
<?php _e('Image + Title + Excerpt + Link (Image will appear at top)', 'bluesky-connector'); ?>
|
||||
<option value="image-title-excerpt-link" <?php selected($settings['post_format'] ?? 'title-excerpt-link', 'image-title-excerpt-link'); ?>>
|
||||
<?php esc_html_e('Image + Title + Excerpt + Link', 'bluesky-connctor'); ?>
|
||||
</option>
|
||||
</select>
|
||||
<p class="description">
|
||||
<?php _e('Note: When including images, Bluesky will always display them at the top of the post regardless of format selection.', 'bluesky-connector'); ?>
|
||||
<?php esc_html_e('bluesky-connctor'); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="bluesky_include_title"><?php _e('Title Options', 'bluesky-connector'); ?></label>
|
||||
<label for="bluesky_include_title"><?php esc_html_e('Include Title', 'bluesky-connctor'); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
name="bluesky_include_title"
|
||||
id="bluesky_include_title"
|
||||
value="1"
|
||||
<?php checked(get_option('bluesky_include_title', true)); ?>>
|
||||
<?php _e('Include post title when format includes title', 'bluesky-connector'); ?>
|
||||
</label>
|
||||
<input type="checkbox" name="bluesky_connector_settings[include_title]"
|
||||
id="bluesky_include_title" value="1" <?php checked($settings['include_title'] ?? true); ?>>
|
||||
<p class="description">
|
||||
<?php _e('When enabled, the post title will be included at the beginning of the post text.', 'bluesky-connector'); ?>
|
||||
<?php esc_html_e('Include post title in the Bluesky post', 'bluesky-connctor'); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php submit_button(__('Save Format Settings', 'bluesky-connector')); ?>
|
||||
<?php submit_button(esc_html__('Save Format Settings', 'bluesky-connctor')); ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-top: 20px;">
|
||||
<h2><?php _e('Queue Management', 'bluesky-connector'); ?></h2>
|
||||
<?php
|
||||
$queue = get_option('bluesky_post_queue', array());
|
||||
$queue_count = count($queue);
|
||||
?>
|
||||
<p>
|
||||
<?php printf(
|
||||
_n(
|
||||
'There is %s post in the queue.',
|
||||
'There are %s posts in the queue.',
|
||||
$queue_count,
|
||||
'bluesky-connector'
|
||||
),
|
||||
number_format_i18n($queue_count)
|
||||
); ?>
|
||||
</p>
|
||||
|
||||
<?php if ($queue_count > 0) : ?>
|
||||
<form method="post" style="margin-top: 10px;">
|
||||
<?php wp_nonce_field('bluesky_process_queue'); ?>
|
||||
<input type="submit" name="process_queue_now" class="button button-primary"
|
||||
value="<?php esc_attr_e('Process Queue Now', 'bluesky-connector'); ?>">
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (WP_DEBUG) : ?>
|
||||
<div class="card" style="margin-top: 20px;">
|
||||
<h2><?php _e('Connection Status', 'bluesky-connector'); ?></h2>
|
||||
<h2><?php esc_html_e('Debug Information', 'bluesky-connctor'); ?></h2>
|
||||
<table class="form-table" role="presentation">
|
||||
<tr>
|
||||
<th scope="row"><?php _e('DID', 'bluesky-connector'); ?></th>
|
||||
<td><code><?php echo esc_html(get_option('bluesky_did')); ?></code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e('Last Token Refresh', 'bluesky-connector'); ?></th>
|
||||
<td><?php echo esc_html(get_option('bluesky_token_created') ? date_i18n(get_option('date_format') . ' ' . get_option('time_format'), get_option('bluesky_token_created')) : __('Never', 'bluesky-connector')); ?></td>
|
||||
<th scope="row"><?php esc_html_e('Last Post Status', 'bluesky-connctor'); ?></th>
|
||||
<td>
|
||||
<?php
|
||||
echo wp_kses(
|
||||
sprintf(
|
||||
/* translators: %s: Time of last post attempt */
|
||||
esc_html__('Last post attempt: %s', 'bluesky-connctor'),
|
||||
get_option('bluesky_last_post_time')
|
||||
? esc_html(date_i18n(get_option('date_format') . ' ' . get_option('time_format'), get_option('bluesky_last_post_time')))
|
||||
: esc_html__('Never', 'bluesky-connctor')
|
||||
),
|
||||
array('b' => array(), 'span' => array('class' => array()))
|
||||
);
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if (WP_DEBUG): ?>
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e('DID', 'bluesky-connctor'); ?></th>
|
||||
<td><code><?php echo esc_html(get_option('bluesky_did')); ?></code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e('Connection Status', 'bluesky-connctor'); ?></th>
|
||||
<td><?php echo esc_html(get_option('bluesky_connection_status')); ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user