3bb8217690
- 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
457 lines
18 KiB
PHP
457 lines
18 KiB
PHP
<?php
|
|
class Post_Formatter
|
|
{
|
|
private $api;
|
|
private $max_length = 300;
|
|
|
|
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, $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);
|
|
|
|
$post_data = array(
|
|
'$type' => 'app.bsky.feed.post',
|
|
'text' => $content,
|
|
'createdAt' => gmdate('c', strtotime($post->post_date_gmt)),
|
|
'langs' => array('en')
|
|
);
|
|
|
|
// 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'));
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
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);
|
|
|
|
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)
|
|
{
|
|
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
|
|
$available_length = $this->max_length;
|
|
$available_length -= strlen($url);
|
|
$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');
|
|
}
|
|
|
|
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(
|
|
'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());
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
$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;
|
|
}
|
|
}
|
|
} |