Changeset 3270523
- Timestamp:
- 04/10/2025 02:16:18 PM (9 months ago)
- Location:
- autoblue
- Files:
-
- 45 added
- 24 edited
- 1 copied
-
assets/screenshot-1.jpg (added)
-
assets/screenshot-2.jpg (added)
-
assets/screenshot-3.jpg (added)
-
tags/0.0.5 (copied) (copied from autoblue/trunk)
-
tags/0.0.5/autoblue.php (modified) (2 diffs)
-
tags/0.0.5/composer.json (modified) (1 diff)
-
tags/0.0.5/includes/Bluesky.php (modified) (5 diffs)
-
tags/0.0.5/includes/Bluesky/TextParser.php (modified) (6 diffs)
-
tags/0.0.5/includes/Logging/Setup.php (modified) (2 diffs)
-
tags/0.0.5/includes/Utils (added)
-
tags/0.0.5/includes/Utils/TLD.php (added)
-
tags/0.0.5/includes/Utils/Text.php (added)
-
tags/0.0.5/readme.txt (modified) (2 diffs)
-
tags/0.0.5/tests (added)
-
tags/0.0.5/tests/.env (added)
-
tags/0.0.5/tests/_data (added)
-
tags/0.0.5/tests/_output (added)
-
tags/0.0.5/tests/_support (added)
-
tags/0.0.5/tests/_support/Helper (added)
-
tags/0.0.5/tests/_support/Helper/Wpunit.php (added)
-
tags/0.0.5/tests/_support/WpunitTester.php (added)
-
tags/0.0.5/tests/_support/_generated (added)
-
tags/0.0.5/tests/wpunit (added)
-
tags/0.0.5/tests/wpunit.suite.yml (added)
-
tags/0.0.5/tests/wpunit/Bluesky (added)
-
tags/0.0.5/tests/wpunit/Bluesky/APITest.php (added)
-
tags/0.0.5/tests/wpunit/Bluesky/TextParserTest.php (added)
-
tags/0.0.5/tests/wpunit/BlueskyTest.php (added)
-
tags/0.0.5/tests/wpunit/Utils (added)
-
tags/0.0.5/tests/wpunit/Utils/TextTest.php (added)
-
tags/0.0.5/tests/wpunit/_bootstrap.php (added)
-
tags/0.0.5/vendor/autoload.php (modified) (1 diff)
-
tags/0.0.5/vendor/composer/InstalledVersions.php (modified) (4 diffs)
-
tags/0.0.5/vendor/composer/autoload_classmap.php (modified) (1 diff)
-
tags/0.0.5/vendor/composer/autoload_real.php (modified) (2 diffs)
-
tags/0.0.5/vendor/composer/autoload_static.php (modified) (3 diffs)
-
tags/0.0.5/vendor/composer/installed.php (modified) (2 diffs)
-
trunk/autoblue.php (modified) (2 diffs)
-
trunk/composer.json (modified) (1 diff)
-
trunk/includes/Bluesky.php (modified) (5 diffs)
-
trunk/includes/Bluesky/TextParser.php (modified) (6 diffs)
-
trunk/includes/Logging/Setup.php (modified) (2 diffs)
-
trunk/includes/Utils (added)
-
trunk/includes/Utils/TLD.php (added)
-
trunk/includes/Utils/Text.php (added)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/tests (added)
-
trunk/tests/.env (added)
-
trunk/tests/_data (added)
-
trunk/tests/_output (added)
-
trunk/tests/_support (added)
-
trunk/tests/_support/Helper (added)
-
trunk/tests/_support/Helper/Wpunit.php (added)
-
trunk/tests/_support/WpunitTester.php (added)
-
trunk/tests/_support/_generated (added)
-
trunk/tests/wpunit (added)
-
trunk/tests/wpunit.suite.yml (added)
-
trunk/tests/wpunit/Bluesky (added)
-
trunk/tests/wpunit/Bluesky/APITest.php (added)
-
trunk/tests/wpunit/Bluesky/TextParserTest.php (added)
-
trunk/tests/wpunit/BlueskyTest.php (added)
-
trunk/tests/wpunit/Utils (added)
-
trunk/tests/wpunit/Utils/TextTest.php (added)
-
trunk/tests/wpunit/_bootstrap.php (added)
-
trunk/vendor/autoload.php (modified) (1 diff)
-
trunk/vendor/composer/InstalledVersions.php (modified) (4 diffs)
-
trunk/vendor/composer/autoload_classmap.php (modified) (1 diff)
-
trunk/vendor/composer/autoload_real.php (modified) (2 diffs)
-
trunk/vendor/composer/autoload_static.php (modified) (3 diffs)
-
trunk/vendor/composer/installed.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
autoblue/tags/0.0.5/autoblue.php
r3223262 r3270523 8 8 * License: GPLv2 or later 9 9 * License URI: https://www.gnu.org/licenses/gpl-2.0.html 10 * Version: 0.0. 410 * Version: 0.0.5 11 11 * Text Domain: autoblue 12 12 * Requires at least: 6.6 … … 21 21 require_once __DIR__ . '/vendor/autoload.php'; 22 22 23 define( 'AUTOBLUE_VERSION', '0.0. 4' );23 define( 'AUTOBLUE_VERSION', '0.0.5' ); 24 24 define( 'AUTOBLUE_SLUG', 'autoblue' ); 25 25 define( 'AUTOBLUE_BASENAME', plugin_basename( __FILE__ ) ); -
autoblue/tags/0.0.5/composer.json
r3214602 r3270523 17 17 "szepeviktor/phpstan-wordpress": "^2.0", 18 18 "phpstan/phpstan": "^2.0", 19 "php-stubs/wp-cli-stubs": "^2.11" 19 "php-stubs/wp-cli-stubs": "^2.11", 20 "lucatume/wp-browser": "^4.4", 21 "mockery/mockery": "^1.6" 20 22 }, 21 23 "config": { -
autoblue/tags/0.0.5/includes/Bluesky.php
r3211894 r3270523 14 14 private Logging\Log $log; 15 15 16 public function __construct( ) {17 $this->api_client = new Bluesky\API();18 $this->log = new Logging\Log();16 public function __construct( Bluesky\API $api_client = null, Logging\Log $log = null ) { 17 $this->api_client = $api_client ?: new Bluesky\API(); 18 $this->log = $log ?: new Logging\Log(); 19 19 } 20 20 … … 29 29 * @return array<string,mixed>|false The connection data or false if no connection is found. 30 30 */ 31 p rivatefunction get_connection() {31 public function get_connection() { 32 32 $connections = ( new ConnectionsManager() )->get_all_connections(); 33 33 … … 37 37 38 38 return $connections[0]; 39 } 40 41 /** 42 * Refresh the connection tokens for a given DID. 43 * 44 * @param string $did The DID to refresh the connection for. 45 * @return array<string,mixed>|\WP_Error The refreshed connection data or error object. 46 */ 47 public function refresh_connection( string $did ) { 48 $connections_manager = new ConnectionsManager(); 49 $connection = $connections_manager->refresh_tokens( $did ); 50 51 return $connection; 39 52 } 40 53 … … 112 125 } 113 126 114 $connections_manager = new ConnectionsManager(); 115 $connection = $connections_manager->refresh_tokens( $connection['did'] ); 127 $connection = $this->refresh_connection( $connection['did'] ); 116 128 117 129 if ( is_wp_error( $connection ) ) { … … 121 133 122 134 $message = get_post_meta( $post_id, 'autoblue_custom_message', true ); 123 $excerpt = html_entity_decode( get_the_excerpt( $post->ID ) ); 124 $message = ! empty( $message ) ? wp_strip_all_tags( html_entity_decode( $message ) ) : $excerpt; 135 $excerpt = get_the_excerpt( $post->ID ); 136 $message = ! empty( $message ) ? $message : $excerpt; 137 138 /** 139 * Filters the message to be shared on Bluesky. 140 * 141 * @param string $message The message to be shared. 142 * @param int $post_id The post ID of the post being shared. 143 */ 144 $message = apply_filters( 'autoblue/share_message', $message, $post_id ); 145 146 $message = html_entity_decode( wp_strip_all_tags( $message ) ); 147 $message = ( new Utils\Text() )->trim_text( $message, 300 ); 125 148 126 149 $body = [ -
autoblue/tags/0.0.5/includes/Bluesky/TextParser.php
r3211894 r3270523 18 18 // - Can contain letters, numbers, underscores. 19 19 // - Excludes trailing punctuation. 20 public const TAG_REGEX = '/( ?:^|\s)(#[^\d\s]\S*?)(?:\s|$|[!.,;?])/u';20 public const TAG_REGEX = '/(^|\s)[##]((?!\x{fe0f})[^\s\x{00AD}\x{2060}\x{200A}\x{200B}\x{200C}\x{200D}\x{20e2}]*[^\d\s\p{P}\x{00AD}\x{2060}\x{200A}\x{200B}\x{200C}\x{200D}\x{20e2}]+[^\s\x{00AD}\x{2060}\x{200A}\x{200B}\x{200C}\x{200D}\x{20e2}]*)?/u'; 21 21 22 22 /** … … 27 27 public $api_client; 28 28 29 public function __construct() { 30 $this->api_client = new API(); 29 /** 30 * @param API|null $api_client The Bluesky API client. 31 */ 32 public function __construct( $api_client = null ) { 33 $this->api_client = $api_client ?? new API(); 31 34 } 32 35 … … 36 39 private function is_valid_handle( string $handle ): bool { 37 40 return preg_match( '/^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/', $handle ) === 1; 41 } 42 43 private function is_valid_domain( string $str ): bool { 44 $tlds = \Autoblue\Utils\TLD::get_valid_tlds(); 45 46 foreach ( $tlds as $tld ) { 47 $i = strrpos( $str, $tld ); 48 49 if ( $i === false ) { 50 continue; 51 } 52 53 if ( $str[ $i - 1 ] === '.' && $i === strlen( $str ) - strlen( $tld ) ) { 54 return true; 55 } 56 } 57 58 return false; 38 59 } 39 60 … … 50 71 // Skip if handle doesn't match ATProto spec. 51 72 if ( ! $this->is_valid_handle( $handle ) ) { 73 continue; 74 } 75 76 // Probably not a domain. 77 if ( ! $this->is_valid_domain( $handle ) && substr( $handle, -5 ) !== '.test' ) { 52 78 continue; 53 79 } … … 70 96 */ 71 97 public function parse_urls( string $text ): array { 72 $spans = []; 73 preg_match_all( self::URL_REGEX, $text, $matches, PREG_OFFSET_CAPTURE ); 74 75 foreach ( $matches[1] as $match ) { 98 $spans = []; 99 $offset = 0; 100 101 while ( preg_match( self::URL_REGEX, $text, $match, PREG_OFFSET_CAPTURE, $offset ) ) { 102 $uri = $match[1][0]; 103 104 // If it doesn't start with http, ensure it's a valid domain and add https://. 105 if ( strpos( $uri, 'http' ) !== 0 ) { 106 // Extract domain from URI. 107 if ( preg_match( '/^(?:www\.)?([^\/]+)/', $uri, $domain_match ) ) { 108 $domain = $domain_match[1]; 109 if ( ! $this->is_valid_domain( $domain ) ) { 110 $offset = $match[0][1] + 1; 111 continue; 112 } 113 $uri = 'https://' . $uri; 114 } else { 115 $offset = $match[0][1] + 1; 116 continue; 117 } 118 } 119 120 $start = $match[1][1]; 121 $end = $start + strlen( $match[1][0] ); 122 123 // Strip ending punctuation. 124 if ( preg_match( '/[.,;:!?]$/', $uri ) ) { 125 $uri = substr( $uri, 0, -1 ); 126 --$end; 127 } 128 129 // Handle closing parenthesis. 130 if ( substr( $uri, -1 ) === ')' && strpos( $uri, '(' ) === false ) { 131 $uri = substr( $uri, 0, -1 ); 132 --$end; 133 } 134 76 135 $spans[] = [ 77 'start' => mb_strlen( substr( $text, 0, $match[1] ), '8bit' ), 78 'end' => mb_strlen( substr( $text, 0, $match[1] + strlen( $match[0] ) ), '8bit' ), 79 'url' => $match[0], 80 ]; 136 'start' => mb_strlen( substr( $text, 0, $start ), '8bit' ), 137 'end' => mb_strlen( substr( $text, 0, $end ), '8bit' ), 138 'url' => $uri, 139 ]; 140 141 $offset = $match[0][1] + 1; 81 142 } 82 143 … … 88 149 */ 89 150 public function parse_tags( string $text ): array { 90 $spans = []; 91 preg_match_all( self::TAG_REGEX, $text, $matches, PREG_OFFSET_CAPTURE ); 92 93 foreach ( $matches[1] as $match ) { 94 $tag = $match[0]; 95 // Clean up the tag. 151 $facets = []; 152 $offset = 0; 153 154 while ( preg_match( self::TAG_REGEX, $text, $match, PREG_OFFSET_CAPTURE, $offset ) ) { 155 $leading = $match[1][0]; // The space or start of string. 156 $tag = $match[2][0] ?? ''; // The tag content without #. 157 158 if ( empty( $tag ) ) { 159 $offset = $match[0][1] + 1; 160 continue; 161 } 162 163 // Strip ending punctuation and spaces. 96 164 $tag = trim( $tag ); 97 $tag = preg_replace( '/ \p{P}+$/u', '', $tag );98 99 if ( empty( $tag )) {100 continue;101 }102 103 // Skip if tag is too long (over 64 chars including #). 104 if ( mb_strlen( $tag ) > 66 ) {105 continue; 106 }107 108 $spans[] = [109 ' start' => mb_strlen( substr( $text, 0, $match[1] ), '8bit' ),110 'end' => mb_strlen( substr( $text, 0, $match[1] + strlen( $tag ) ), '8bit' ),111 'tag' => ltrim( $tag, '#' ), 112 ];113 } 114 115 return $ spans;165 $tag = preg_replace( '/[.,!?:;]*$/', '', $tag ); 166 167 if ( is_null( $tag ) || strlen( $tag ) === 0 || strlen( $tag ) > 64 ) { 168 $offset = $match[0][1] + 1; 169 continue; 170 } 171 172 $index = $match[0][1] + strlen( $leading ); // Match index + leading space length. 173 174 $facets[] = [ 175 'start' => mb_strlen( substr( $text, 0, $index ), '8bit' ), 176 'end' => mb_strlen( substr( $text, 0, $index + strlen( $tag ) + 1 ), '8bit' ), // +1 for # 177 'tag' => $tag, 178 ]; 179 180 $offset = $match[0][1] + 1; // Move past current match. 181 } 182 183 return $facets; 116 184 } 117 185 -
autoblue/tags/0.0.5/includes/Logging/Setup.php
r3223262 r3270523 4 4 5 5 class Setup { 6 private const DB_VERSION = '20241202'; // YYYYMMDD 6 private const DB_VERSION = '20241202'; // YYYYMMDD. 7 7 8 8 public function register_hooks(): void { … … 16 16 } 17 17 18 p rivatefunction create_table(): void {18 public function create_table(): void { 19 19 global $wpdb; 20 20 -
autoblue/tags/0.0.5/readme.txt
r3223262 r3270523 2 2 Contributors: danielpost 3 3 Tags: social, bluesky, auto, share, post 4 Stable tag: 0.0. 44 Stable tag: 0.0.5 5 5 Requires at least: 6.6 6 6 Tested up to: 6.7 … … 41 41 == Screenshots == 42 42 43 1. Easily connect your Bluesky account to your WordPress site. 44 2. Set a custom text, choose a featured image and publish your post. 43 1. Easily connect your Bluesky account to your WordPress site and start sharing. 44 2. Show Bluesky likes and replies on your WordPress site. 45 3. Keep track of everything that Autoblue does. 45 46 46 47 == Changelog == 48 49 = 0.0.5 = 50 * Feature: Add filter for setting a custom share message 51 * Fix: Excerpts are now trimmed correctly before being shared 47 52 48 53 = 0.0.4 = -
autoblue/tags/0.0.5/vendor/autoload.php
r3214602 r3270523 15 15 } 16 16 } 17 trigger_error( 18 $err, 19 E_USER_ERROR 20 ); 17 throw new RuntimeException($err); 21 18 } 22 19 23 20 require_once __DIR__ . '/composer/autoload_real.php'; 24 21 25 return ComposerAutoloaderInit 7e988a03fbffe9893b5755a660fe73f5::getLoader();22 return ComposerAutoloaderInitbfb327bc5b5bd0bc00762088df045c8a::getLoader(); -
autoblue/tags/0.0.5/vendor/composer/InstalledVersions.php
r3211894 r3270523 28 28 { 29 29 /** 30 * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to 31 * @internal 32 */ 33 private static $selfDir = null; 34 35 /** 30 36 * @var mixed[]|null 31 37 * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null 32 38 */ 33 39 private static $installed; 40 41 /** 42 * @var bool 43 */ 44 private static $installedIsLocalDir; 34 45 35 46 /** … … 310 321 self::$installed = $data; 311 322 self::$installedByVendor = array(); 323 324 // when using reload, we disable the duplicate protection to ensure that self::$installed data is 325 // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not, 326 // so we have to assume it does not, and that may result in duplicate data being returned when listing 327 // all installed packages for example 328 self::$installedIsLocalDir = false; 329 } 330 331 /** 332 * @return string 333 */ 334 private static function getSelfDir() 335 { 336 if (self::$selfDir === null) { 337 self::$selfDir = strtr(__DIR__, '\\', '/'); 338 } 339 340 return self::$selfDir; 312 341 } 313 342 … … 326 355 327 356 if (self::$canGetVendors) { 357 $selfDir = self::getSelfDir(); 328 358 foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { 359 $vendorDir = strtr($vendorDir, '\\', '/'); 329 360 if (isset(self::$installedByVendor[$vendorDir])) { 330 361 $installed[] = self::$installedByVendor[$vendorDir]; … … 334 365 self::$installedByVendor[$vendorDir] = $required; 335 366 $installed[] = $required; 336 if (s trtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {367 if (self::$installed === null && $vendorDir.'/composer' === $selfDir) { 337 368 self::$installed = $required; 338 $copiedLocalDir = true;369 self::$installedIsLocalDir = true; 339 370 } 371 } 372 if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) { 373 $copiedLocalDir = true; 340 374 } 341 375 } -
autoblue/tags/0.0.5/vendor/composer/autoload_classmap.php
r3211894 r3270523 31 31 'Autoblue\\Setup' => $baseDir . '/includes/Setup.php', 32 32 'Autoblue\\Utils' => $baseDir . '/includes/Utils.php', 33 'Autoblue\\Utils\\TLD' => $baseDir . '/includes/Utils/TLD.php', 34 'Autoblue\\Utils\\Text' => $baseDir . '/includes/Utils/Text.php', 33 35 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 34 36 ); -
autoblue/tags/0.0.5/vendor/composer/autoload_real.php
r3214602 r3270523 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit 7e988a03fbffe9893b5755a660fe73f55 class ComposerAutoloaderInitbfb327bc5b5bd0bc00762088df045c8a 6 6 { 7 7 private static $loader; … … 25 25 require __DIR__ . '/platform_check.php'; 26 26 27 spl_autoload_register(array('ComposerAutoloaderInit 7e988a03fbffe9893b5755a660fe73f5', 'loadClassLoader'), true, true);27 spl_autoload_register(array('ComposerAutoloaderInitbfb327bc5b5bd0bc00762088df045c8a', 'loadClassLoader'), true, true); 28 28 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); 29 spl_autoload_unregister(array('ComposerAutoloaderInit 7e988a03fbffe9893b5755a660fe73f5', 'loadClassLoader'));29 spl_autoload_unregister(array('ComposerAutoloaderInitbfb327bc5b5bd0bc00762088df045c8a', 'loadClassLoader')); 30 30 31 31 require __DIR__ . '/autoload_static.php'; 32 call_user_func(\Composer\Autoload\ComposerStaticInit 7e988a03fbffe9893b5755a660fe73f5::getInitializer($loader));32 call_user_func(\Composer\Autoload\ComposerStaticInitbfb327bc5b5bd0bc00762088df045c8a::getInitializer($loader)); 33 33 34 34 $loader->register(true); -
autoblue/tags/0.0.5/vendor/composer/autoload_static.php
r3214602 r3270523 5 5 namespace Composer\Autoload; 6 6 7 class ComposerStaticInit 7e988a03fbffe9893b5755a660fe73f57 class ComposerStaticInitbfb327bc5b5bd0bc00762088df045c8a 8 8 { 9 9 public static $prefixLengthsPsr4 = array ( … … 54 54 'Autoblue\\Setup' => __DIR__ . '/../..' . '/includes/Setup.php', 55 55 'Autoblue\\Utils' => __DIR__ . '/../..' . '/includes/Utils.php', 56 'Autoblue\\Utils\\TLD' => __DIR__ . '/../..' . '/includes/Utils/TLD.php', 57 'Autoblue\\Utils\\Text' => __DIR__ . '/../..' . '/includes/Utils/Text.php', 56 58 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 57 59 ); … … 60 62 { 61 63 return \Closure::bind(function () use ($loader) { 62 $loader->prefixLengthsPsr4 = ComposerStaticInit 7e988a03fbffe9893b5755a660fe73f5::$prefixLengthsPsr4;63 $loader->prefixDirsPsr4 = ComposerStaticInit 7e988a03fbffe9893b5755a660fe73f5::$prefixDirsPsr4;64 $loader->classMap = ComposerStaticInit 7e988a03fbffe9893b5755a660fe73f5::$classMap;64 $loader->prefixLengthsPsr4 = ComposerStaticInitbfb327bc5b5bd0bc00762088df045c8a::$prefixLengthsPsr4; 65 $loader->prefixDirsPsr4 = ComposerStaticInitbfb327bc5b5bd0bc00762088df045c8a::$prefixDirsPsr4; 66 $loader->classMap = ComposerStaticInitbfb327bc5b5bd0bc00762088df045c8a::$classMap; 65 67 66 68 }, null, ClassLoader::class); -
autoblue/tags/0.0.5/vendor/composer/installed.php
r3223262 r3270523 2 2 'root' => array( 3 3 'name' => 'posty/autoblue', 4 'pretty_version' => 'v0.0. 4',5 'version' => '0.0. 4.0',6 'reference' => ' 0725945813790284b417f9553bbd96ac7f4c89f2',4 'pretty_version' => 'v0.0.5', 5 'version' => '0.0.5.0', 6 'reference' => 'e777fe95e9c1caa7da4a76a4b09a863896f9d54b', 7 7 'type' => 'project', 8 8 'install_path' => __DIR__ . '/../../', … … 21 21 ), 22 22 'posty/autoblue' => array( 23 'pretty_version' => 'v0.0. 4',24 'version' => '0.0. 4.0',25 'reference' => ' 0725945813790284b417f9553bbd96ac7f4c89f2',23 'pretty_version' => 'v0.0.5', 24 'version' => '0.0.5.0', 25 'reference' => 'e777fe95e9c1caa7da4a76a4b09a863896f9d54b', 26 26 'type' => 'project', 27 27 'install_path' => __DIR__ . '/../../', -
autoblue/trunk/autoblue.php
r3223262 r3270523 8 8 * License: GPLv2 or later 9 9 * License URI: https://www.gnu.org/licenses/gpl-2.0.html 10 * Version: 0.0. 410 * Version: 0.0.5 11 11 * Text Domain: autoblue 12 12 * Requires at least: 6.6 … … 21 21 require_once __DIR__ . '/vendor/autoload.php'; 22 22 23 define( 'AUTOBLUE_VERSION', '0.0. 4' );23 define( 'AUTOBLUE_VERSION', '0.0.5' ); 24 24 define( 'AUTOBLUE_SLUG', 'autoblue' ); 25 25 define( 'AUTOBLUE_BASENAME', plugin_basename( __FILE__ ) ); -
autoblue/trunk/composer.json
r3214602 r3270523 17 17 "szepeviktor/phpstan-wordpress": "^2.0", 18 18 "phpstan/phpstan": "^2.0", 19 "php-stubs/wp-cli-stubs": "^2.11" 19 "php-stubs/wp-cli-stubs": "^2.11", 20 "lucatume/wp-browser": "^4.4", 21 "mockery/mockery": "^1.6" 20 22 }, 21 23 "config": { -
autoblue/trunk/includes/Bluesky.php
r3211894 r3270523 14 14 private Logging\Log $log; 15 15 16 public function __construct( ) {17 $this->api_client = new Bluesky\API();18 $this->log = new Logging\Log();16 public function __construct( Bluesky\API $api_client = null, Logging\Log $log = null ) { 17 $this->api_client = $api_client ?: new Bluesky\API(); 18 $this->log = $log ?: new Logging\Log(); 19 19 } 20 20 … … 29 29 * @return array<string,mixed>|false The connection data or false if no connection is found. 30 30 */ 31 p rivatefunction get_connection() {31 public function get_connection() { 32 32 $connections = ( new ConnectionsManager() )->get_all_connections(); 33 33 … … 37 37 38 38 return $connections[0]; 39 } 40 41 /** 42 * Refresh the connection tokens for a given DID. 43 * 44 * @param string $did The DID to refresh the connection for. 45 * @return array<string,mixed>|\WP_Error The refreshed connection data or error object. 46 */ 47 public function refresh_connection( string $did ) { 48 $connections_manager = new ConnectionsManager(); 49 $connection = $connections_manager->refresh_tokens( $did ); 50 51 return $connection; 39 52 } 40 53 … … 112 125 } 113 126 114 $connections_manager = new ConnectionsManager(); 115 $connection = $connections_manager->refresh_tokens( $connection['did'] ); 127 $connection = $this->refresh_connection( $connection['did'] ); 116 128 117 129 if ( is_wp_error( $connection ) ) { … … 121 133 122 134 $message = get_post_meta( $post_id, 'autoblue_custom_message', true ); 123 $excerpt = html_entity_decode( get_the_excerpt( $post->ID ) ); 124 $message = ! empty( $message ) ? wp_strip_all_tags( html_entity_decode( $message ) ) : $excerpt; 135 $excerpt = get_the_excerpt( $post->ID ); 136 $message = ! empty( $message ) ? $message : $excerpt; 137 138 /** 139 * Filters the message to be shared on Bluesky. 140 * 141 * @param string $message The message to be shared. 142 * @param int $post_id The post ID of the post being shared. 143 */ 144 $message = apply_filters( 'autoblue/share_message', $message, $post_id ); 145 146 $message = html_entity_decode( wp_strip_all_tags( $message ) ); 147 $message = ( new Utils\Text() )->trim_text( $message, 300 ); 125 148 126 149 $body = [ -
autoblue/trunk/includes/Bluesky/TextParser.php
r3211894 r3270523 18 18 // - Can contain letters, numbers, underscores. 19 19 // - Excludes trailing punctuation. 20 public const TAG_REGEX = '/( ?:^|\s)(#[^\d\s]\S*?)(?:\s|$|[!.,;?])/u';20 public const TAG_REGEX = '/(^|\s)[##]((?!\x{fe0f})[^\s\x{00AD}\x{2060}\x{200A}\x{200B}\x{200C}\x{200D}\x{20e2}]*[^\d\s\p{P}\x{00AD}\x{2060}\x{200A}\x{200B}\x{200C}\x{200D}\x{20e2}]+[^\s\x{00AD}\x{2060}\x{200A}\x{200B}\x{200C}\x{200D}\x{20e2}]*)?/u'; 21 21 22 22 /** … … 27 27 public $api_client; 28 28 29 public function __construct() { 30 $this->api_client = new API(); 29 /** 30 * @param API|null $api_client The Bluesky API client. 31 */ 32 public function __construct( $api_client = null ) { 33 $this->api_client = $api_client ?? new API(); 31 34 } 32 35 … … 36 39 private function is_valid_handle( string $handle ): bool { 37 40 return preg_match( '/^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/', $handle ) === 1; 41 } 42 43 private function is_valid_domain( string $str ): bool { 44 $tlds = \Autoblue\Utils\TLD::get_valid_tlds(); 45 46 foreach ( $tlds as $tld ) { 47 $i = strrpos( $str, $tld ); 48 49 if ( $i === false ) { 50 continue; 51 } 52 53 if ( $str[ $i - 1 ] === '.' && $i === strlen( $str ) - strlen( $tld ) ) { 54 return true; 55 } 56 } 57 58 return false; 38 59 } 39 60 … … 50 71 // Skip if handle doesn't match ATProto spec. 51 72 if ( ! $this->is_valid_handle( $handle ) ) { 73 continue; 74 } 75 76 // Probably not a domain. 77 if ( ! $this->is_valid_domain( $handle ) && substr( $handle, -5 ) !== '.test' ) { 52 78 continue; 53 79 } … … 70 96 */ 71 97 public function parse_urls( string $text ): array { 72 $spans = []; 73 preg_match_all( self::URL_REGEX, $text, $matches, PREG_OFFSET_CAPTURE ); 74 75 foreach ( $matches[1] as $match ) { 98 $spans = []; 99 $offset = 0; 100 101 while ( preg_match( self::URL_REGEX, $text, $match, PREG_OFFSET_CAPTURE, $offset ) ) { 102 $uri = $match[1][0]; 103 104 // If it doesn't start with http, ensure it's a valid domain and add https://. 105 if ( strpos( $uri, 'http' ) !== 0 ) { 106 // Extract domain from URI. 107 if ( preg_match( '/^(?:www\.)?([^\/]+)/', $uri, $domain_match ) ) { 108 $domain = $domain_match[1]; 109 if ( ! $this->is_valid_domain( $domain ) ) { 110 $offset = $match[0][1] + 1; 111 continue; 112 } 113 $uri = 'https://' . $uri; 114 } else { 115 $offset = $match[0][1] + 1; 116 continue; 117 } 118 } 119 120 $start = $match[1][1]; 121 $end = $start + strlen( $match[1][0] ); 122 123 // Strip ending punctuation. 124 if ( preg_match( '/[.,;:!?]$/', $uri ) ) { 125 $uri = substr( $uri, 0, -1 ); 126 --$end; 127 } 128 129 // Handle closing parenthesis. 130 if ( substr( $uri, -1 ) === ')' && strpos( $uri, '(' ) === false ) { 131 $uri = substr( $uri, 0, -1 ); 132 --$end; 133 } 134 76 135 $spans[] = [ 77 'start' => mb_strlen( substr( $text, 0, $match[1] ), '8bit' ), 78 'end' => mb_strlen( substr( $text, 0, $match[1] + strlen( $match[0] ) ), '8bit' ), 79 'url' => $match[0], 80 ]; 136 'start' => mb_strlen( substr( $text, 0, $start ), '8bit' ), 137 'end' => mb_strlen( substr( $text, 0, $end ), '8bit' ), 138 'url' => $uri, 139 ]; 140 141 $offset = $match[0][1] + 1; 81 142 } 82 143 … … 88 149 */ 89 150 public function parse_tags( string $text ): array { 90 $spans = []; 91 preg_match_all( self::TAG_REGEX, $text, $matches, PREG_OFFSET_CAPTURE ); 92 93 foreach ( $matches[1] as $match ) { 94 $tag = $match[0]; 95 // Clean up the tag. 151 $facets = []; 152 $offset = 0; 153 154 while ( preg_match( self::TAG_REGEX, $text, $match, PREG_OFFSET_CAPTURE, $offset ) ) { 155 $leading = $match[1][0]; // The space or start of string. 156 $tag = $match[2][0] ?? ''; // The tag content without #. 157 158 if ( empty( $tag ) ) { 159 $offset = $match[0][1] + 1; 160 continue; 161 } 162 163 // Strip ending punctuation and spaces. 96 164 $tag = trim( $tag ); 97 $tag = preg_replace( '/ \p{P}+$/u', '', $tag );98 99 if ( empty( $tag )) {100 continue;101 }102 103 // Skip if tag is too long (over 64 chars including #). 104 if ( mb_strlen( $tag ) > 66 ) {105 continue; 106 }107 108 $spans[] = [109 ' start' => mb_strlen( substr( $text, 0, $match[1] ), '8bit' ),110 'end' => mb_strlen( substr( $text, 0, $match[1] + strlen( $tag ) ), '8bit' ),111 'tag' => ltrim( $tag, '#' ), 112 ];113 } 114 115 return $ spans;165 $tag = preg_replace( '/[.,!?:;]*$/', '', $tag ); 166 167 if ( is_null( $tag ) || strlen( $tag ) === 0 || strlen( $tag ) > 64 ) { 168 $offset = $match[0][1] + 1; 169 continue; 170 } 171 172 $index = $match[0][1] + strlen( $leading ); // Match index + leading space length. 173 174 $facets[] = [ 175 'start' => mb_strlen( substr( $text, 0, $index ), '8bit' ), 176 'end' => mb_strlen( substr( $text, 0, $index + strlen( $tag ) + 1 ), '8bit' ), // +1 for # 177 'tag' => $tag, 178 ]; 179 180 $offset = $match[0][1] + 1; // Move past current match. 181 } 182 183 return $facets; 116 184 } 117 185 -
autoblue/trunk/includes/Logging/Setup.php
r3223262 r3270523 4 4 5 5 class Setup { 6 private const DB_VERSION = '20241202'; // YYYYMMDD 6 private const DB_VERSION = '20241202'; // YYYYMMDD. 7 7 8 8 public function register_hooks(): void { … … 16 16 } 17 17 18 p rivatefunction create_table(): void {18 public function create_table(): void { 19 19 global $wpdb; 20 20 -
autoblue/trunk/readme.txt
r3223262 r3270523 2 2 Contributors: danielpost 3 3 Tags: social, bluesky, auto, share, post 4 Stable tag: 0.0. 44 Stable tag: 0.0.5 5 5 Requires at least: 6.6 6 6 Tested up to: 6.7 … … 41 41 == Screenshots == 42 42 43 1. Easily connect your Bluesky account to your WordPress site. 44 2. Set a custom text, choose a featured image and publish your post. 43 1. Easily connect your Bluesky account to your WordPress site and start sharing. 44 2. Show Bluesky likes and replies on your WordPress site. 45 3. Keep track of everything that Autoblue does. 45 46 46 47 == Changelog == 48 49 = 0.0.5 = 50 * Feature: Add filter for setting a custom share message 51 * Fix: Excerpts are now trimmed correctly before being shared 47 52 48 53 = 0.0.4 = -
autoblue/trunk/vendor/autoload.php
r3214602 r3270523 15 15 } 16 16 } 17 trigger_error( 18 $err, 19 E_USER_ERROR 20 ); 17 throw new RuntimeException($err); 21 18 } 22 19 23 20 require_once __DIR__ . '/composer/autoload_real.php'; 24 21 25 return ComposerAutoloaderInit 7e988a03fbffe9893b5755a660fe73f5::getLoader();22 return ComposerAutoloaderInitbfb327bc5b5bd0bc00762088df045c8a::getLoader(); -
autoblue/trunk/vendor/composer/InstalledVersions.php
r3211894 r3270523 28 28 { 29 29 /** 30 * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to 31 * @internal 32 */ 33 private static $selfDir = null; 34 35 /** 30 36 * @var mixed[]|null 31 37 * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null 32 38 */ 33 39 private static $installed; 40 41 /** 42 * @var bool 43 */ 44 private static $installedIsLocalDir; 34 45 35 46 /** … … 310 321 self::$installed = $data; 311 322 self::$installedByVendor = array(); 323 324 // when using reload, we disable the duplicate protection to ensure that self::$installed data is 325 // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not, 326 // so we have to assume it does not, and that may result in duplicate data being returned when listing 327 // all installed packages for example 328 self::$installedIsLocalDir = false; 329 } 330 331 /** 332 * @return string 333 */ 334 private static function getSelfDir() 335 { 336 if (self::$selfDir === null) { 337 self::$selfDir = strtr(__DIR__, '\\', '/'); 338 } 339 340 return self::$selfDir; 312 341 } 313 342 … … 326 355 327 356 if (self::$canGetVendors) { 357 $selfDir = self::getSelfDir(); 328 358 foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { 359 $vendorDir = strtr($vendorDir, '\\', '/'); 329 360 if (isset(self::$installedByVendor[$vendorDir])) { 330 361 $installed[] = self::$installedByVendor[$vendorDir]; … … 334 365 self::$installedByVendor[$vendorDir] = $required; 335 366 $installed[] = $required; 336 if (s trtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {367 if (self::$installed === null && $vendorDir.'/composer' === $selfDir) { 337 368 self::$installed = $required; 338 $copiedLocalDir = true;369 self::$installedIsLocalDir = true; 339 370 } 371 } 372 if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) { 373 $copiedLocalDir = true; 340 374 } 341 375 } -
autoblue/trunk/vendor/composer/autoload_classmap.php
r3211894 r3270523 31 31 'Autoblue\\Setup' => $baseDir . '/includes/Setup.php', 32 32 'Autoblue\\Utils' => $baseDir . '/includes/Utils.php', 33 'Autoblue\\Utils\\TLD' => $baseDir . '/includes/Utils/TLD.php', 34 'Autoblue\\Utils\\Text' => $baseDir . '/includes/Utils/Text.php', 33 35 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 34 36 ); -
autoblue/trunk/vendor/composer/autoload_real.php
r3214602 r3270523 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit 7e988a03fbffe9893b5755a660fe73f55 class ComposerAutoloaderInitbfb327bc5b5bd0bc00762088df045c8a 6 6 { 7 7 private static $loader; … … 25 25 require __DIR__ . '/platform_check.php'; 26 26 27 spl_autoload_register(array('ComposerAutoloaderInit 7e988a03fbffe9893b5755a660fe73f5', 'loadClassLoader'), true, true);27 spl_autoload_register(array('ComposerAutoloaderInitbfb327bc5b5bd0bc00762088df045c8a', 'loadClassLoader'), true, true); 28 28 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); 29 spl_autoload_unregister(array('ComposerAutoloaderInit 7e988a03fbffe9893b5755a660fe73f5', 'loadClassLoader'));29 spl_autoload_unregister(array('ComposerAutoloaderInitbfb327bc5b5bd0bc00762088df045c8a', 'loadClassLoader')); 30 30 31 31 require __DIR__ . '/autoload_static.php'; 32 call_user_func(\Composer\Autoload\ComposerStaticInit 7e988a03fbffe9893b5755a660fe73f5::getInitializer($loader));32 call_user_func(\Composer\Autoload\ComposerStaticInitbfb327bc5b5bd0bc00762088df045c8a::getInitializer($loader)); 33 33 34 34 $loader->register(true); -
autoblue/trunk/vendor/composer/autoload_static.php
r3214602 r3270523 5 5 namespace Composer\Autoload; 6 6 7 class ComposerStaticInit 7e988a03fbffe9893b5755a660fe73f57 class ComposerStaticInitbfb327bc5b5bd0bc00762088df045c8a 8 8 { 9 9 public static $prefixLengthsPsr4 = array ( … … 54 54 'Autoblue\\Setup' => __DIR__ . '/../..' . '/includes/Setup.php', 55 55 'Autoblue\\Utils' => __DIR__ . '/../..' . '/includes/Utils.php', 56 'Autoblue\\Utils\\TLD' => __DIR__ . '/../..' . '/includes/Utils/TLD.php', 57 'Autoblue\\Utils\\Text' => __DIR__ . '/../..' . '/includes/Utils/Text.php', 56 58 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 57 59 ); … … 60 62 { 61 63 return \Closure::bind(function () use ($loader) { 62 $loader->prefixLengthsPsr4 = ComposerStaticInit 7e988a03fbffe9893b5755a660fe73f5::$prefixLengthsPsr4;63 $loader->prefixDirsPsr4 = ComposerStaticInit 7e988a03fbffe9893b5755a660fe73f5::$prefixDirsPsr4;64 $loader->classMap = ComposerStaticInit 7e988a03fbffe9893b5755a660fe73f5::$classMap;64 $loader->prefixLengthsPsr4 = ComposerStaticInitbfb327bc5b5bd0bc00762088df045c8a::$prefixLengthsPsr4; 65 $loader->prefixDirsPsr4 = ComposerStaticInitbfb327bc5b5bd0bc00762088df045c8a::$prefixDirsPsr4; 66 $loader->classMap = ComposerStaticInitbfb327bc5b5bd0bc00762088df045c8a::$classMap; 65 67 66 68 }, null, ClassLoader::class); -
autoblue/trunk/vendor/composer/installed.php
r3223262 r3270523 2 2 'root' => array( 3 3 'name' => 'posty/autoblue', 4 'pretty_version' => 'v0.0. 4',5 'version' => '0.0. 4.0',6 'reference' => ' 0725945813790284b417f9553bbd96ac7f4c89f2',4 'pretty_version' => 'v0.0.5', 5 'version' => '0.0.5.0', 6 'reference' => 'e777fe95e9c1caa7da4a76a4b09a863896f9d54b', 7 7 'type' => 'project', 8 8 'install_path' => __DIR__ . '/../../', … … 21 21 ), 22 22 'posty/autoblue' => array( 23 'pretty_version' => 'v0.0. 4',24 'version' => '0.0. 4.0',25 'reference' => ' 0725945813790284b417f9553bbd96ac7f4c89f2',23 'pretty_version' => 'v0.0.5', 24 'version' => '0.0.5.0', 25 'reference' => 'e777fe95e9c1caa7da4a76a4b09a863896f9d54b', 26 26 'type' => 'project', 27 27 'install_path' => __DIR__ . '/../../',
Note: See TracChangeset
for help on using the changeset viewer.