diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml index 19e70d20..99200549 100644 --- a/.github/workflows/cypress.yml +++ b/.github/workflows/cypress.yml @@ -54,7 +54,7 @@ jobs: run: npm install - name: Set the core version and plugins config - run: ./tests/bin/set-wp-config.js --core=${{ matrix.core.version }} --plugins=./${{ github.event.repository.name }},https://downloads.wordpress.org/plugin/classic-editor.1.6.1.zip,./tests/test-plugin + run: ./tests/bin/set-wp-config.js --core=${{ matrix.core.version }} --plugins=./${{ github.event.repository.name }},https://downloads.wordpress.org/plugin/classic-editor.1.6.1.zip,https://downloads.wordpress.org/plugin/syndication-links.4.4.20.zip,./tests/test-plugin - name: Set up WP environment run: npm run env:start diff --git a/.wp-env.json b/.wp-env.json index d8bde471..cc48e107 100644 --- a/.wp-env.json +++ b/.wp-env.json @@ -1,6 +1,7 @@ { "plugins": [ "https://downloads.wordpress.org/plugin/classic-editor.1.6.1.zip", + "https://downloads.wordpress.org/plugin/syndication-links.4.4.20.zip", ".", "./tests/test-plugin" ], diff --git a/assets/js/admin-autoshare-for-twitter-classic-editor.js b/assets/js/admin-autoshare-for-twitter-classic-editor.js index 9195f99b..1eef5ecf 100644 --- a/assets/js/admin-autoshare-for-twitter-classic-editor.js +++ b/assets/js/admin-autoshare-for-twitter-classic-editor.js @@ -243,6 +243,64 @@ } } + function addSyndicatedLinks( data ) { + if ( ! data ) { + return; + } + + // Get the Syndication URL inputs. + const syndicationUrlInputs = Array.from( + document.querySelectorAll( 'input[name="syndication_urls[]"]' ) + ); + + // Bail if there are no Syndication URL inputs. + if ( ! syndicationUrlInputs.length ) { + return; + } + + // Get the URLs from the status messages. + // We'll use these to compare and populate the Syndication URL inputs. + const statusMessagesUrls = Array.from(document.querySelectorAll('.autoshare-for-twitter-status-logs-wrapper a')).map( ( link ) => { + return link.getAttribute('href'); + } ); + + // Get the existing URLs from the Syndication URL inputs. + const syndicationUrlInputsUrls = syndicationUrlInputs.map( + ( input ) => { + return input.value; + } + ); + + // Get the Syndication URL list. + const syndicationUrlList = document.querySelector( + '.syndication_url_list ul' + ); + + statusMessagesUrls.forEach( ( url ) => { + // If the URL is already in the Syndication URL inputs, bail. + if ( syndicationUrlInputsUrls.includes( url ) ) { + return; + } + + // Create the Syndication URL input list item. + const syndicationUrlInputListItem = document.createElement( 'li' ); + + // Create the Syndication URL input. + const syndicationUrlInput = document.createElement( 'input' ); + syndicationUrlInput.classList.add( 'widefat' ); + syndicationUrlInput.type = 'text'; + syndicationUrlInput.name = 'syndication_urls[]'; + syndicationUrlInput.value = url; + + // Append the Syndication URL input to the Syndication URL list. + syndicationUrlInputListItem.appendChild( syndicationUrlInput ); + syndicationUrlList.appendChild( syndicationUrlInputListItem ); + + // Add the URL to the Syndication URL inputs URLs so we don't repeat ourselves. + syndicationUrlInputsUrls.push( url ); + } ); + } + // Tweet Now functionality. $('#tweet_now').on('click', function () { $('#autoshare-for-twitter-error-message').html(''); @@ -272,9 +330,13 @@ (false === response.success && false === response.data.is_retweeted)) ) { + console.log({ data: response.data }) $('.autoshare-for-twitter-status-logs-wrapper').html( response.data.message ); + + addSyndicatedLinks( response.data ); + if (response.data.is_retweeted) { $tweetText.val(''); // Reset the tweet text. } diff --git a/includes/admin/post-transition.php b/includes/admin/post-transition.php index ad618de9..87c2b375 100644 --- a/includes/admin/post-transition.php +++ b/includes/admin/post-transition.php @@ -314,6 +314,16 @@ function update_autoshare_for_twitter_meta_from_response( $post_id, $data, $hand */ update_autoshare_for_twitter_meta( $post_id, Meta\TWITTER_STATUS_KEY, $tweet_meta ); + if ( method_exists( 'Syn_Meta', 'add_syndication_link' ) ) { + // Add syndication link to the post. + foreach ( $tweet_meta as $tweet ) { + if ( 'published' === $tweet['status'] ) { + $uri = Utils\link_from_twitter( $tweet ); + \Syn_Meta::add_syndication_link( 'post', $post_id, $uri ); + } + } + } + /** * Fires after the response from Twitter has been written as meta to the post. */ diff --git a/src/js/AutoshareForTwitterPostStatusInfo.js b/src/js/AutoshareForTwitterPostStatusInfo.js index 65f3d1c3..0d640fb8 100644 --- a/src/js/AutoshareForTwitterPostStatusInfo.js +++ b/src/js/AutoshareForTwitterPostStatusInfo.js @@ -30,6 +30,77 @@ export function AutoshareForTwitterPostStatusInfo() { const [ statusMessages, setStatusMessages ] = useState( messages ); + // Syndication Links plugin support. + // This is all so that the Syndication Links plugin can show updates in real time with our status messages. + // In addition, this fixes an issue where a user might actually remove a syndicated link unintentionally when clicking "update" on the post. + function addSyndicatedLinks( data ) { + // No data, bail. + if ( ! data ) { + return; + } + + const { message } = data; + + // No messages, bail. + if ( ! message?.length ) { + return; + } + + // Get the Syndication URL inputs. + const syndicationUrlInputs = Array.from( + document.querySelectorAll( 'input[name="syndication_urls[]"]' ) + ); + + // Bail if there are no Syndication URL inputs. + if ( ! syndicationUrlInputs.length ) { + return; + } + + // Get the URLs from the status messages. + // We'll use these to compare and populate the Syndication URL inputs. + const statusMessagesUrls = message + .map( ( entry ) => { + return entry.url; + } ) + .filter( ( url ) => url ); + + // Get the existing URLs from the Syndication URL inputs. + const syndicationUrlInputsUrls = syndicationUrlInputs.map( + ( input ) => { + return input.value; + } + ); + + // Get the Syndication URL list. + const syndicationUrlList = document.querySelector( + '.syndication_url_list ul' + ); + + statusMessagesUrls.forEach( ( url ) => { + // If the URL is already in the Syndication URL inputs, bail. + if ( syndicationUrlInputsUrls.includes( url ) ) { + return; + } + + // Create the Syndication URL input list item. + const syndicationUrlInputListItem = document.createElement( 'li' ); + + // Create the Syndication URL input. + const syndicationUrlInput = document.createElement( 'input' ); + syndicationUrlInput.classList.add( 'widefat' ); + syndicationUrlInput.type = 'text'; + syndicationUrlInput.name = 'syndication_urls[]'; + syndicationUrlInput.value = url; + + // Append the Syndication URL input to the Syndication URL list. + syndicationUrlInputListItem.appendChild( syndicationUrlInput ); + syndicationUrlList.appendChild( syndicationUrlInputListItem ); + + // Add the URL to the Syndication URL inputs URLs so we don't repeat ourselves. + syndicationUrlInputsUrls.push( url ); + } ); + } + useSaveTwitterData(); const reTweetHandler = async () => { @@ -54,6 +125,7 @@ export function AutoshareForTwitterPostStatusInfo() { setTweetText( '' ); } setStatusMessages( data ); + addSyndicatedLinks( data ); setReTweet( false ); }; diff --git a/tests/bin/set-wp-config.js b/tests/bin/set-wp-config.js index c1f438dc..acf1f4eb 100755 --- a/tests/bin/set-wp-config.js +++ b/tests/bin/set-wp-config.js @@ -4,7 +4,7 @@ const fs = require( 'fs' ); const path = `${ process.cwd() }/.wp-env.json`; -let config = fs.existsSync( path ) ? require( path ) : { plugins: [ '.', 'https://downloads.wordpress.org/plugin/classic-editor.zip' ] }; +let config = fs.existsSync( path ) ? require( path ) : { plugins: [ '.', 'https://downloads.wordpress.org/plugin/classic-editor.zip', 'https://downloads.wordpress.org/plugin/syndication-links.zip' ] }; const args = {}; process.argv diff --git a/tests/cypress/e2e/syndication-links.test.js b/tests/cypress/e2e/syndication-links.test.js new file mode 100644 index 00000000..9da00acd --- /dev/null +++ b/tests/cypress/e2e/syndication-links.test.js @@ -0,0 +1,113 @@ +import { getRandomText } from "../support/functions"; + +describe('Admin can login and make sure plugin is activated', () => { + beforeEach(() => { + cy.login(); + cy.clearPluginSettings(); + }); + + it('Can activate Syndication Links plugin if it is deactivated', () => { + cy.activatePlugin('syndication-links'); + }); +}); + +describe('Test Autopost for X with Syndication Links.', () => { + before(() => { + cy.login(); + cy.configurePlugin(); + }); + + beforeEach(() => { + cy.login(); + // Enable Autoshare on account. + cy.markAccountForAutoshare(); + }); + + // Run test cases with default Autoshare enabled and disabled both. + const defaultBehaviors = [false, true]; + defaultBehaviors.forEach( (defaultBehavior) => { + it(`Can ${(defaultBehavior ? 'Enable': 'Disable')} default Autoshare`, () => { + cy.visit('/wp-admin/options-general.php?page=autoshare-for-twitter'); + cy.get('input:checkbox[name="autoshare-for-twitter[enable_default]"]').should('exist'); + if (true === defaultBehavior) { + cy.get('input:checkbox[name="autoshare-for-twitter[enable_default]"]').check(); + } else { + cy.get('input:checkbox[name="autoshare-for-twitter[enable_default]"]').uncheck(); + } + cy.get('#submit').click(); + }); + + it(`Tweet Now should work fine (Classic Editor) - Autoshare: ${(defaultBehavior ? 'Enable': 'Disable')}`, () => { + // Use the right editor. + cy.enableEditor('classic'); + + // Start create post. + cy.classicStartCreatePost(); + + // Save Draft + cy.get('#save-post').click(); + + // Uncheck the checkbox and publish + cy.enableCheckbox('#autoshare-for-twitter-enable', defaultBehavior, false); + cy.get('#publish').should('not.be.disabled'); + cy.get('#publish').should('be.visible').click(); + + // Post-publish. + cy.get('#autoshare_for_twitter_metabox').should('be.visible'); + cy.get('#autoshare_for_twitter_metabox').contains('This post has not been posted to X/Twitter'); + + cy.get('#autoshare_for_twitter_metabox button.tweet-now-button').contains('Post to X/Twitter now').click(); + cy.get('#autoshare-for-twitter-override-body textarea').should('be.visible') + .clear() + .type(`Random Tweet ${getRandomText(6)}`); + cy.get('.autoshare-for-twitter-tweet-now-wrapper #tweet_now').should('be.visible').click(); + cy.get('.autoshare-for-twitter-status-log-data').contains('Posted to X/Twitter on'); + + // Syndication Links. + cy.get('.autoshare-for-twitter-status-log-data a').then(($a) => { + const url = $a.attr('href'); + + cy.get('input[name="syndication_urls[]"]').should('exist'); + cy.get('input[name="syndication_urls[]"]').eq(1).should('exist'); + cy.get('input[name="syndication_urls[]"]').eq(1).should('have.value', url); + }); + }); + + it(`Tweet Now should work fine (Block Editor) - Autoshare: ${(defaultBehavior ? 'Enable': 'Disable')}`, () => { + // Use the right editor + cy.enableEditor('block'); + + // Start create new post by enter post title + cy.startCreatePost(); + + // Open pre-publish Panel. + cy.openPrePublishPanel(); + + // Check enable checkbox for auto-share. + cy.enableCheckbox('.autoshare-for-twitter-toggle-control input:checkbox', defaultBehavior, false); + + // Publish + cy.publishPost(); + + // Post-publish. + cy.get('.autoshare-for-twitter-post-status').should('be.visible'); + cy.get('.autoshare-for-twitter-post-status').contains('This post has not been posted to X/Twitter.'); + + cy.get('.editor-post-publish-panel button[aria-label="Close panel"]').click(); + cy.openAutoTweetPanel(); + cy.get('.autoshare-for-twitter-editor-panel button.autoshare-for-twitter-tweet-now').click(); + cy.get('.autoshare-for-twitter-editor-panel .autoshare-for-twitter-tweet-text textarea').clear().type(`Random Tweet ${getRandomText(6)}`, {force: true}); + cy.get('.autoshare-for-twitter-editor-panel button.autoshare-for-twitter-re-tweet').click(); + cy.get('.autoshare-for-twitter-log a').contains('Posted to X/Twitter on'); + + // Syndication Links. + cy.get('.autoshare-for-twitter-log a').then(($a) => { + const url = $a.attr('href'); + + cy.get('input[name="syndication_urls[]"]').should('exist'); + cy.get('input[name="syndication_urls[]"]').eq(1).should('exist'); + cy.get('input[name="syndication_urls[]"]').eq(1).should('have.value', url); + }); + }); + }); +}); \ No newline at end of file