diff --git a/.github/workflows/repo-automator.yml b/.github/workflows/repo-automator.yml index 1991b048..cd8bf751 100644 --- a/.github/workflows/repo-automator.yml +++ b/.github/workflows/repo-automator.yml @@ -25,7 +25,6 @@ jobs: fail-label: needs:feedback pass-label: needs:code-review conflict-label: needs:refresh - sync-pr-branch: true reviewers: | iamdharmesh team:open-source-practice diff --git a/assets/js/admin-autoshare-for-twitter-classic-editor.js b/assets/js/admin-autoshare-for-twitter-classic-editor.js index cb7843c3..e785f33d 100644 --- a/assets/js/admin-autoshare-for-twitter-classic-editor.js +++ b/assets/js/admin-autoshare-for-twitter-classic-editor.js @@ -3,7 +3,7 @@ * * @todo soooo much dependency :facepalm: */ -(function($) { +(function ($) { 'use strict'; var $tweetPost = $('#autoshare-for-twitter-enable'), @@ -12,10 +12,16 @@ $editLink = $('#autoshare-for-twitter-edit'), $editBody = $('#autoshare-for-twitter-override-body'), $hideLink = $('.cancel-tweet-text'), - $allowTweetImage = $('#autoshare-for-twitter-tweet-allow-image'), - errorMessageContainer = document.getElementById('autoshare-for-twitter-error-message'), - counterWrap = document.getElementById('autoshare-for-twitter-counter-wrap'), - allowTweetImageWrap = $('.autoshare-for-twitter-tweet-allow-image-wrap'), + $allowTweetImage = $('#autoshare-for-twitter-tweet-allow-image'), + errorMessageContainer = document.getElementById( + 'autoshare-for-twitter-error-message' + ), + counterWrap = document.getElementById( + 'autoshare-for-twitter-counter-wrap' + ), + allowTweetImageWrap = $( + '.autoshare-for-twitter-tweet-allow-image-wrap' + ), limit = 280; const { __, sprintf } = wp.i18n; @@ -29,23 +35,26 @@ $tweetText.change(handleRequest); $tweetPost.change(toggleVisibility); $allowTweetImage.change(handleRequest); - $editLink.on('click', function() { + $editLink.on('click', function () { $editBody.slideToggle(); updateRemainingField(); $(this).hide(); }); - $tweetText.on('keyup', function() { + $tweetText.on('keyup', function () { updateRemainingField(); }); - $hideLink.on('click', function(e) { + $hideLink.on('click', function (e) { e.preventDefault(); $('#autoshare-for-twitter-override-body').slideToggle(); $editLink.show(); }); - $('input.autoshare-for-twitter-account-checkbox').on('change', handleRequest); + $('input.autoshare-for-twitter-account-checkbox').on( + 'change', + handleRequest + ); // Runs on page load to auto-enable posts to be tweeted - window.onload = function(event) { + window.onload = function (event) { if ('' === adminAutoshareForTwitter.currentStatus) { handleRequest(event, true); } @@ -77,12 +86,15 @@ function handleRequest(event, status = $tweetPost.prop('checked')) { let data = {}; let enabledAccounts = []; - $('input.autoshare-for-twitter-account-checkbox:checked').each(function() { - enabledAccounts.push($(this).val()); - }); + $('input.autoshare-for-twitter-account-checkbox:checked').each( + function () { + enabledAccounts.push($(this).val()); + } + ); data[adminAutoshareForTwitter.enableAutoshareKey] = status; data[adminAutoshareForTwitter.tweetBodyKey] = $tweetText.val(); - data[adminAutoshareForTwitter.allowTweetImageKey] = $allowTweetImage.prop('checked'); + data[adminAutoshareForTwitter.allowTweetImageKey] = + $allowTweetImage.prop('checked'); data[adminAutoshareForTwitter.tweetAccountsKey] = enabledAccounts; $('#publish').prop('disabled', true); @@ -92,14 +104,14 @@ method: 'POST', parse: false, // We'll check the response for errors. }) - .then(function(response) { + .then(function (response) { if (!response.ok) { throw response; } return response.json(); }) - .then(function(data) { + .then(function (data) { errorMessageContainer.innerText = ''; $icon.removeClass('pending'); @@ -125,15 +137,38 @@ } /** - * Updates the counter + * Calculates the permalink length */ - function updateRemainingField() { + function getPermalinkLength() { let permalinkLength = 0; - if ( $('#sample-permalink').length ) { - permalinkLength = $('#sample-permalink').text().length + if ($('#sample-permalink').length) { + if ( + ! adminAutoshareForTwitter.isLocalSite && + ! isNaN( adminAutoshareForTwitter.twitterURLLength ) + ) { + // According to this page https://developer.twitter.com/en/docs/counting-characters, all URLs are transformed to a uniform length + permalinkLength = Number( + adminAutoshareForTwitter.twitterURLLength + ); + } else { + // Calculate the permalink length. + const slug = jQuery('#editable-post-name-full').text(); + const aTagContents = jQuery('#sample-permalink > a')[0].innerHTML; + const permalinkPrefix = 'string' === typeof aTagContents ? aTagContents.split(' 0 && ( autoshareEnabled || tweetNow ) ) { + if (hasMedia > 0 && (autoshareEnabled || tweetNow)) { allowTweetImageWrap.show(); } else { allowTweetImageWrap.hide(); @@ -214,56 +265,73 @@ } // Tweet Now functionality. - $('#tweet_now').on('click', function() { - $("#autoshare-for-twitter-error-message").html(''); - $(this).addClass("disabled"); - $(".autoshare-for-twitter-tweet-now-wrapper span.spinner").addClass("is-active"); + $('#tweet_now').on('click', function () { + $('#autoshare-for-twitter-error-message').html(''); + $(this).addClass('disabled'); + $('.autoshare-for-twitter-tweet-now-wrapper span.spinner').addClass( + 'is-active' + ); - const postId = $("#post_ID").val(); + const postId = $('#post_ID').val(); const body = new FormData(); - body.append( 'action', adminAutoshareForTwitter.retweetAction ); - body.append( 'nonce', adminAutoshareForTwitter.nonce ); - body.append( 'post_id', postId ); - body.append( 'is_classic', 1 ); + body.append('action', adminAutoshareForTwitter.retweetAction); + body.append('nonce', adminAutoshareForTwitter.nonce); + body.append('post_id', postId); + body.append('is_classic', 1); // Send request to Tweet now. - fetch( ajaxurl, { + fetch(ajaxurl, { method: 'POST', body, - } ) - .then((response) => response.json()) - .then((response) => { - if ( - response && response.data && - ( ( response.success && response.data.message ) || ( false === response.success && false === response.data.is_retweeted) ) - ) { - $('.autoshare-for-twitter-status-logs-wrapper').html(response.data.message); - if ( response.data.is_retweeted ) { - $tweetText.val(''); // Reset the tweet text. - } - } else { - $("#autoshare-for-twitter-error-message").html(adminAutoshareForTwitter.unknownErrorText); - } - }) - .catch((error) => { - if(error.message){ - $("#autoshare-for-twitter-error-message").html(error.message); - } else { - $("#autoshare-for-twitter-error-message").html(adminAutoshareForTwitter.unknownErrorText); - } }) - .finally(() => { - $(this).removeClass("disabled"); - $(".autoshare-for-twitter-tweet-now-wrapper span.spinner").removeClass("is-active"); - }); + .then((response) => response.json()) + .then((response) => { + if ( + response && + response.data && + ((response.success && response.data.message) || + (false === response.success && + false === response.data.is_retweeted)) + ) { + $('.autoshare-for-twitter-status-logs-wrapper').html( + response.data.message + ); + if (response.data.is_retweeted) { + $tweetText.val(''); // Reset the tweet text. + } + } else { + $('#autoshare-for-twitter-error-message').html( + adminAutoshareForTwitter.unknownErrorText + ); + } + }) + .catch((error) => { + if (error.message) { + $('#autoshare-for-twitter-error-message').html( + error.message + ); + } else { + $('#autoshare-for-twitter-error-message').html( + adminAutoshareForTwitter.unknownErrorText + ); + } + }) + .finally(() => { + $(this).removeClass('disabled'); + $( + '.autoshare-for-twitter-tweet-now-wrapper span.spinner' + ).removeClass('is-active'); + }); }); // Toggle Tweet Now panel - jQuery("#autoshare_for_twitter_metabox .tweet-now-button").on("click", function(e){ - e.preventDefault(); - $editBody.show(); - jQuery(this).find('span').toggleClass('dashicons-arrow-up-alt2'); - jQuery(".autoshare-for-twitter-tweet-now-wrapper").slideToggle(); - }); - + jQuery('#autoshare_for_twitter_metabox .tweet-now-button').on( + 'click', + function (e) { + e.preventDefault(); + $editBody.show(); + jQuery(this).find('span').toggleClass('dashicons-arrow-up-alt2'); + jQuery('.autoshare-for-twitter-tweet-now-wrapper').slideToggle(); + } + ); })(jQuery); diff --git a/autoshare-for-twitter.php b/autoshare-for-twitter.php index ca4fa110..eced8fa8 100644 --- a/autoshare-for-twitter.php +++ b/autoshare-for-twitter.php @@ -26,6 +26,7 @@ define( 'AUTOSHARE_FOR_TWITTER_URL', plugin_dir_url( __FILE__ ) ); define( 'AUTOSHARE_FOR_TWITTER_PATH', plugin_dir_path( __FILE__ ) ); define( 'AUTOSHARE_FOR_TWITTER_INC', AUTOSHARE_FOR_TWITTER_PATH . 'includes/' ); +define( 'AUTOSHARE_FOR_TWITTER_URL_LENGTH', 23 ); /** * Get the minimum version of PHP required by this plugin. @@ -49,14 +50,14 @@ function site_meets_php_requirements() { if ( ! site_meets_php_requirements() ) { add_action( 'admin_notices', - function() { + function () { ?>

$tweet_accounts, 'tweetAccountsKey' => TWEET_ACCOUNTS_KEY, 'connectedAccounts' => $accounts ?? [], + 'isLocalSite' => is_local(), + 'twitterURLLength' => AUTOSHARE_FOR_TWITTER_URL_LENGTH, ]; wp_localize_script( $handle, 'adminAutoshareForTwitter', $localization ); diff --git a/includes/utils.php b/includes/utils.php index 2ed03e89..4d126e7d 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -19,7 +19,7 @@ /** * Helper/Wrapper function for returning the meta entries for autosharing. * - * @param int $id The post ID. + * @param int $id The post ID. * @param string $key The meta key to retrieve. * * @return mixed @@ -30,11 +30,11 @@ function get_autoshare_for_twitter_meta( $id, $key ) { /** * Filters autoshare metadata. * - * @since 1.0.0 - * * @param mixed Retrieved metadata. * @param int Post ID. * @param string The meta key. + * + * @since 1.0.0 */ return apply_filters( 'autoshare_for_twitter_meta', $data, $id, $key ); } @@ -42,9 +42,10 @@ function get_autoshare_for_twitter_meta( $id, $key ) { /** * Updates autoshare-for-twitter-related post metadata by prefixing the passed key. * - * @param int $id Post ID. - * @param string $key Autoshare meta key. + * @param int $id Post ID. + * @param string $key Autoshare meta key. * @param mixed $value The meta value to save. + * * @return mixed The meta_id if the meta doesn't exist, otherwise returns true on success and false on failure. */ function update_autoshare_for_twitter_meta( $id, $key, $value ) { @@ -54,8 +55,9 @@ function update_autoshare_for_twitter_meta( $id, $key, $value ) { /** * Determines whether an Autoshare for Twitter post meta key exists on the provided post. * - * @param int $id A Post ID. + * @param int $id A Post ID. * @param string $key A meta key. + * * @return boolean */ function has_autoshare_for_twitter_meta( $id, $key ) { @@ -65,8 +67,9 @@ function has_autoshare_for_twitter_meta( $id, $key ) { /** * Deletes autoshare-for-twitter-related metadata. * - * @param int $id The post ID. + * @param int $id The post ID. * @param string $key The key of the meta value to delete. + * * @return boolean False for failure. True for success. */ function delete_autoshare_for_twitter_meta( $id, $key ) { @@ -77,6 +80,7 @@ function delete_autoshare_for_twitter_meta( $id, $key ) { * Returns whether autoshare is enabled for a post. * * @param int $post_id A post ID. + * * @return boolean */ function autoshare_enabled( $post_id ) { @@ -98,6 +102,7 @@ function autoshare_enabled( $post_id ) { * Returns whether image is allowed in a tweet. * * @param int $post_id A post ID. + * * @return boolean */ function tweet_image_allowed( $post_id ) { @@ -121,6 +126,7 @@ function tweet_image_allowed( $post_id ) { * Returns tweet enabled Twitter accounts for the post. * * @param int $post_id A post ID. + * * @return array */ function get_tweet_accounts( $post_id ) { @@ -196,6 +202,7 @@ function is_twitter_configured() { $settings = get_autoshare_for_twitter_settings(); $credentials = array_intersect_key( $settings, $defaults ); + return 2 === count( array_filter( $credentials ) ); } @@ -220,8 +227,10 @@ function compose_tweet_body( \WP_Post $post ) { */ $url = apply_filters( 'autoshare_for_twitter_post_url', get_the_permalink( $post->ID ), $post ); - $url = esc_url( $url ); - $body_max_length = 275 - strlen( $url ); // 275 instead of 280 because of the space between body and URL and the ellipsis. + $url = esc_url( $url ); + // According to this page https://developer.twitter.com/en/docs/counting-characters, all URLs are transformed to a uniform length. + $url_length = ( ! is_local() ) ? AUTOSHARE_FOR_TWITTER_URL_LENGTH : strlen( $url ); + $body_max_length = 275 - $url_length; // 275 instead of 280 because of the space between body and URL and the ellipsis. $tweet_body = sanitize_text_field( $tweet_body ); $tweet_body = html_entity_decode( $tweet_body, ENT_QUOTES, get_bloginfo( 'charset' ) ); $tweet_body_length = strlen( $tweet_body ); @@ -282,11 +291,10 @@ function link_from_twitter( $tweet_status ) { /** * Determine if a post has already been published based on the meta entry alone. * - * @internal does NOT query the Twitter API. - * * @param int $post_id The post id. * * @return bool + * @internal does NOT query the Twitter API. */ function already_published( $post_id ) { @@ -372,8 +380,9 @@ function get_post_types_supported_by_default() { /** * Filters post types supported by default. * - * @since 1.0.0 * @param array Array of post types. + * + * @since 1.0.0 */ return (array) apply_filters( 'autoshare_for_twitter_default_post_types', [ 'post', 'page' ] ); } @@ -391,9 +400,10 @@ function get_hardcoded_supported_post_types() { $available_post_types = get_available_post_types(); $enabled_post_types = get_autoshare_for_twitter_settings( 'post_types' ); $remaining = array_diff( $available_post_types, $enabled_post_types ); + return array_filter( $remaining, - function( $post_type ) { + function ( $post_type ) { return post_type_supports( $post_type, POST_TYPE_SUPPORT_FEATURE ); } ); @@ -409,6 +419,7 @@ function get_enabled_post_types() { if ( 'all' === $enable_for ) { return get_available_post_types(); } + return get_autoshare_for_twitter_settings( 'post_types' ); } @@ -421,7 +432,7 @@ function get_enabled_post_types() { */ function mask_secure_values( $value ) { $count = strlen( $value ); - $substr = substr( $value, -5 ); + $substr = substr( $value, - 5 ); $return = str_pad( $substr, $count, '*', STR_PAD_LEFT ); return $return; @@ -435,3 +446,22 @@ function mask_secure_values( $value ) { function get_default_autoshare_accounts() { return get_autoshare_for_twitter_settings( 'autoshare_accounts' ); } + + +/** + * Returns whether WP environment is local. + * + * @return bool + */ +function is_local() { + $is_local_env = in_array( wp_get_environment_type(), [ 'local', 'development' ], true ); + $is_local_url = strpos( home_url(), '.test' ) || strpos( home_url(), '.local' ); + $is_local = $is_local_env || $is_local_url; + + /** + * Filters whether WP environment is local or not. + * + * @param bool $is_local whether WP environment is local or not. + */ + return apply_filters( 'autoshare_for_twitter_is_local', $is_local ); +} diff --git a/readme.txt b/readme.txt index 7feb3970..c15bb1e6 100644 --- a/readme.txt +++ b/readme.txt @@ -2,7 +2,7 @@ Contributors: 10up, johnwatkins0, adamsilverstein, scottlee, dinhtungdu, jeffpaul, dharm1025 Tags: twitter, tweet, autoshare, auto-share, auto share, share, sharing, social media, posse Requires at least: 5.7 -Tested up to: 6.3 +Tested up to: 6.4 Requires PHP: 7.4 Stable tag: 2.1.1 License: GPL-2.0-or-later diff --git a/src/js/components/TweetTextField.js b/src/js/components/TweetTextField.js index a852ecef..3b1c44f8 100644 --- a/src/js/components/TweetTextField.js +++ b/src/js/components/TweetTextField.js @@ -3,10 +3,16 @@ import { useSelect } from '@wordpress/data'; import { __, sprintf } from '@wordpress/i18n'; import { useTweetText } from '../hooks'; import { useEffect, useState } from '@wordpress/element'; -const { siteUrl } = adminAutoshareForTwitter; + +const { siteUrl, isLocalSite, twitterURLLength } = adminAutoshareForTwitter; export function TweetTextField() { const getPermalinkLength = ( select ) => { + if ( ! isLocalSite && ! isNaN( twitterURLLength ) ) { + // According to this page https://developer.twitter.com/en/docs/counting-characters, all URLs are transformed to a uniform length + return Number( twitterURLLength ); + } + const permalink = select( 'core/editor' ).getPermalink(); if ( permalink ) {