bluesky-Connector/includes/post-formatter.php

457 lines
18 KiB
PHP
Raw Permalink Normal View History

2024-11-21 09:05:37 +00:00
<?php
class Post_Formatter
{
2024-11-21 09:05:37 +00:00
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);
2024-11-21 09:05:37 +00:00
$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'));
}
2024-11-21 09:05:37 +00:00
}
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));
2024-11-21 09:05:37 +00:00
return $response;
} catch (Exception $e) {
error_log('[Bluesky Connector] Error in format_and_post: ' . $e->getMessage());
return array('error' => $e->getMessage());
2024-11-21 09:05:37 +00:00
}
}
2024-11-21 09:05:37 +00:00
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;
}
2024-11-21 09:05:37 +00:00
}
private function get_excerpt($post)
{
try {
error_log('[Bluesky Connector] Getting excerpt for post ' . $post->ID);
2024-11-21 09:05:37 +00:00
$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)');
2024-11-21 09:05:37 +00:00
}
2024-11-21 09:05:37 +00:00
$url = wp_get_shortlink($post->ID);
$include_title = get_option('bluesky_include_title', true);
// Calculate available length
2024-11-21 09:05:37 +00:00
$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
2024-11-21 09:05:37 +00:00
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);
2024-11-21 09:05:37 +00:00
if (mb_strlen($text) > $available_length) {
$text = mb_substr($text, 0, $available_length - 3) . '...';
error_log('[Bluesky Connector] Excerpt truncated to fit length limit');
2024-11-21 09:05:37 +00:00
}
error_log('[Bluesky Connector] Final excerpt length: ' . mb_strlen($text));
2024-11-21 09:05:37 +00:00
return $text;
} catch (Exception $e) {
error_log('[Bluesky Connector] Error in get_excerpt: ' . $e->getMessage());
throw $e;
2024-11-21 09:05:37 +00:00
}
}
2024-11-21 09:05:37 +00:00
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(
2024-11-21 09:05:37 +00:00
array(
'alt' => $alt_text,
'image' => $response['blob'],
2024-11-21 09:05:37 +00:00
),
),
);
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());
2024-11-21 09:05:37 +00:00
}
}
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;
}
2024-11-21 09:05:37 +00:00
$mime_type = mime_content_type($image_path);
list($width, $height) = getimagesize($image_path);
error_log('[Bluesky Connector] Original dimensions: ' . $width . 'x' . $height);
2024-11-21 09:05:37 +00:00
// Calculate new dimensions
$max_dimension = 1000;
if ($width > $height) {
$new_width = $max_dimension;
$new_height = floor($height * ($max_dimension / $width));
2024-11-21 09:05:37 +00:00
} else {
$new_height = $max_dimension;
$new_width = floor($width * ($max_dimension / $height));
2024-11-21 09:05:37 +00:00
}
error_log('[Bluesky Connector] New dimensions: ' . $new_width . 'x' . $new_height);
2024-11-21 09:05:37 +00:00
$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;
}
2024-11-21 09:05:37 +00:00
if (!$source) {
error_log('[Bluesky Connector] Failed to create image resource');
return false;
}
2024-11-21 09:05:37 +00:00
imagecopyresampled(
$new_image,
$source,
0, 0, 0, 0,
$new_width,
$new_height,
$width,
$height
);
2024-11-21 09:05:37 +00:00
// Use PHP's tempnam
$temp_file = tempnam(sys_get_temp_dir(), 'bluesky_img_');
error_log('[Bluesky Connector] Created temp file: ' . $temp_file);
2024-11-21 09:05:37 +00:00
$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;
}
2024-11-21 09:05:37 +00:00
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');
2024-11-21 09:05:37 +00:00
return false;
}
2024-11-21 09:05:37 +00:00
} catch (Exception $e) {
error_log('[Bluesky Connector] Error in resize_image: ' . $e->getMessage());
2024-11-21 09:05:37 +00:00
return false;
}
}
}