diff --git a/.eslintrc.json b/.eslintrc.json
index d8ee40e3..83237ed3 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -2,7 +2,10 @@
"globals": {
"adminAutoshareForTwitter": "readonly",
"jQuery": "readonly",
- "wp": "readonly"
+ "wp": "readonly",
+ "FormData": "readonly",
+ "fetch": "readonly",
+ "ajaxurl": "readonly"
},
"extends": "plugin:@wordpress/eslint-plugin/recommended"
}
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 00000000..0acec209
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,8 @@
+# These owners will be the default owners for everything in the repo. Unless a later match takes precedence, @iamdharmesh, as primary maintainer will be requested for review when someone opens a Pull Request.
+* @iamdharmesh
+
+# GitHub and WordPress.org specifics
+/.github/ @jeffpaul
+/.wordpress-org/ @jeffpaul
+CODE_OF_CONDUCT.md @jeffpaul
+LICENSE.md @jeffpaul
diff --git a/.github/workflows/build-release-zip.yml b/.github/workflows/build-release-zip.yml
index fb12f47c..afcc2cf6 100644
--- a/.github/workflows/build-release-zip.yml
+++ b/.github/workflows/build-release-zip.yml
@@ -2,6 +2,7 @@ name: Build release zip
on:
workflow_dispatch:
+ workflow_call:
push:
branches:
- trunk
@@ -31,7 +32,10 @@ jobs:
env:
cache-name: cache-node-modules
with:
- path: node_modules
+ path: |
+ node_modules
+ ~/.cache
+ ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
- name: Setup node version and npm cache
diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml
index d9299824..09ee3b5a 100644
--- a/.github/workflows/cypress.yml
+++ b/.github/workflows/cypress.yml
@@ -8,9 +8,17 @@ on:
pull_request:
branches:
- develop
+ paths:
+ - '**.js'
+ - '**.php'
+ - '**.css'
jobs:
+ build:
+ uses: 10up/autoshare-for-twitter/.github/workflows/build-release-zip.yml@develop
+
cypress:
+ needs: build
runs-on: ubuntu-latest
strategy:
@@ -22,26 +30,47 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
- - name: Install dependencies
- run: npm i && npm i -g cypress@9.0.0
+ - name: Download build zip
+ uses: actions/download-artifact@v3
+ with:
+ name: ${{ github.event.repository.name }}
+ path: ${{ github.event.repository.name }}
+
+ - name: Display structure of downloaded files
+ run: ls -R
+ working-directory: ${{ github.event.repository.name }}
- - name: Build asset
- run: npm run build
+ - name: Cache node_modules
+ id: cache-node-modules
+ uses: actions/cache@v3
+ env:
+ cache-name: cache-node-modules
+ with:
+ path: |
+ node_modules
+ ~/.cache
+ ~/.npm
+ key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
- - name: Add dependencies
- run: composer install -o --no-dev --ignore-platform-reqs
+ - name: Install dependencies
+ run: npm install
- - name: Set the core version
- run: ./tests/bin/set-core-version.js ${{ matrix.core.version }}
+ - 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
- name: Set up WP environment
run: npm run env:start
- name: Test
- run: cypress run --config-file tests/cypress/config.json --env TWITTER_API_KEY=${{ secrets.TWITTER_API_KEY }},TWITTER_API_SECRET=${{ secrets.TWITTER_API_SECRET }},TWITTER_ACCESS_TOKEN=${{ secrets.TWITTER_ACCESS_TOKEN }},TWITTER_ACCESS_SECRET=${{ secrets.TWITTER_ACCESS_SECRET }}
-
+ run: npm run cypress:run
+ env:
+ CYPRESS_TWITTER_API_KEY: ${{ secrets.TWITTER_API_KEY }}
+ CYPRESS_TWITTER_API_SECRET: ${{ secrets.TWITTER_API_SECRET }}
+ CYPRESS_TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }}
+ CYPRESS_TWITTER_ACCESS_SECRET: ${{ secrets.TWITTER_ACCESS_SECRET }}
+
- name: Upload artifacts
uses: actions/upload-artifact@v2
if: failure()
diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml
index 1493f8d4..91314fd1 100644
--- a/.github/workflows/eslint.yml
+++ b/.github/workflows/eslint.yml
@@ -8,6 +8,8 @@ on:
pull_request:
branches:
- develop
+ paths: # Note: Update paths here will also require updating paths in ignore.eslint.yml.
+ - '**.js'
jobs:
eslint:
diff --git a/.github/workflows/ignore-eslint.yml b/.github/workflows/ignore-eslint.yml
new file mode 100644
index 00000000..9400f9f1
--- /dev/null
+++ b/.github/workflows/ignore-eslint.yml
@@ -0,0 +1,14 @@
+name: ESLint
+
+on:
+ pull_request:
+ branches:
+ - develop
+ paths-ignore:
+ - '**.js'
+
+jobs:
+ eslint:
+ runs-on: ubuntu-latest
+ steps:
+ - run: 'echo "No ESLint check required"'
diff --git a/.github/workflows/ignore-phpcs.yml b/.github/workflows/ignore-phpcs.yml
new file mode 100644
index 00000000..33aa4180
--- /dev/null
+++ b/.github/workflows/ignore-phpcs.yml
@@ -0,0 +1,14 @@
+name: PHPCS
+
+on:
+ pull_request:
+ branches:
+ - develop
+ paths-ignore:
+ - '**.php'
+
+jobs:
+ phpcs:
+ runs-on: ubuntu-latest
+ steps:
+ - run: 'echo "No PHPCS check required"'
diff --git a/.github/workflows/ignore-phpunit.yml b/.github/workflows/ignore-phpunit.yml
new file mode 100644
index 00000000..93b13956
--- /dev/null
+++ b/.github/workflows/ignore-phpunit.yml
@@ -0,0 +1,18 @@
+name: PHPUnit
+
+on:
+ pull_request:
+ branches:
+ - develop
+ paths-ignore:
+ - '**.php'
+
+jobs:
+ phpunit:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ php-versions: ['7.4', '8.0']
+ steps:
+ - run: 'echo "No PHPUnit check required"'
diff --git a/.github/workflows/php-compatibility.yml b/.github/workflows/php-compatibility.yml
index b563cf6c..30692ede 100644
--- a/.github/workflows/php-compatibility.yml
+++ b/.github/workflows/php-compatibility.yml
@@ -8,6 +8,8 @@ on:
pull_request:
branches:
- develop
+ paths:
+ - '**.php'
jobs:
php_compatibility:
diff --git a/.github/workflows/phpcs.yml b/.github/workflows/phpcs.yml
index a806311a..95c10242 100644
--- a/.github/workflows/phpcs.yml
+++ b/.github/workflows/phpcs.yml
@@ -8,6 +8,8 @@ on:
pull_request:
branches:
- develop
+ paths: # Note: Update paths here will also require updating paths in ignore.phpcs.yml.
+ - '**.php'
jobs:
phpcs:
diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml
index 1e0f8d3f..6ae0c436 100644
--- a/.github/workflows/phpunit.yml
+++ b/.github/workflows/phpunit.yml
@@ -8,6 +8,8 @@ on:
pull_request:
branches:
- develop
+ paths: # Note: Update paths here will also require updating paths in ignore.phpunit.yml.
+ - '**.php'
jobs:
phpunit:
diff --git a/.wordpress-org/screenshot-1.png b/.wordpress-org/screenshot-1.png
new file mode 100644
index 00000000..06ee489a
Binary files /dev/null and b/.wordpress-org/screenshot-1.png differ
diff --git a/.wordpress-org/screenshot-2.png b/.wordpress-org/screenshot-2.png
new file mode 100644
index 00000000..ecda3116
Binary files /dev/null and b/.wordpress-org/screenshot-2.png differ
diff --git a/.wordpress-org/screenshot-3.png b/.wordpress-org/screenshot-3.png
new file mode 100644
index 00000000..e28a5636
Binary files /dev/null and b/.wordpress-org/screenshot-3.png differ
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 34db8072..d7d86429 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,7 +6,28 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
## [Unreleased] - TBD
-## [1.2.1] - 2022-12-05
+## [1.3.0] - 2023-01-19
+### Added
+- "Tweet now" functionality (props [@Sidsector9](https://github.com/Sidsector9), [@iamdharmesh](https://github.com/iamdharmesh), [@cadic](https://github.com/cadic), [@jeffpaul](https://github.com/jeffpaul), [@linawiezkowiak](https://github.com/linawiezkowiak), [@oszkarnagy](https://github.com/oszkarnagy) via [#188](https://github.com/10up/autoshare-for-twitter/pull/188)).
+- Toggle for adding/removing featured image from the tweet (props [@Sidsector9](https://github.com/Sidsector9), [@iamdharmesh](https://github.com/iamdharmesh), [@cadic](https://github.com/cadic), [@jeffpaul](https://github.com/jeffpaul), [@linawiezkowiak](https://github.com/linawiezkowiak), [@oszkarnagy](https://github.com/oszkarnagy) via [#188](https://github.com/10up/autoshare-for-twitter/pull/188)).
+- Show Twitter status logs for the draft post if the post has been switched back to Draft from Published, and has already been Tweeted (props [@iamdharmesh](https://github.com/iamdharmesh), [@faisal-alvi](https://github.com/faisal-alvi), [@jeffpaul](https://github.com/jeffpaul), [@linawiezkowiak](https://github.com/linawiezkowiak), [@oszkarnagy](https://github.com/oszkarnagy) via [#215](https://github.com/10up/autoshare-for-twitter/pull/215)).
+- Plugin screenshots to readme files (props [@iamdharmesh](https://github.com/iamdharmesh) via [#218](https://github.com/10up/autoshare-for-twitter/pull/218)).
+
+### Changed
+- UI Improvements in Tweet status (props [@Sidsector9](https://github.com/Sidsector9), [@iamdharmesh](https://github.com/iamdharmesh), [@cadic](https://github.com/cadic), [@jeffpaul](https://github.com/jeffpaul), [@linawiezkowiak](https://github.com/linawiezkowiak), [@oszkarnagy](https://github.com/oszkarnagy) via [#188](https://github.com/10up/autoshare-for-twitter/pull/188)).
+- UI Improvements in tweet message character count (props [@iamdharmesh](https://github.com/iamdharmesh), [@Sidsector9](https://github.com/Sidsector9), [@ravinderk](https://github.com/ravinderk), [@jeffpaul](https://github.com/jeffpaul), [@linawiezkowiak](https://github.com/linawiezkowiak), [@oszkarnagy](https://github.com/oszkarnagy) via [#214](https://github.com/10up/autoshare-for-twitter/pull/214)).
+- Run GitHub Action workflows only when it required (props [@iamdharmesh](https://github.com/iamdharmesh), [@peterwilsoncc](https://github.com/peterwilsoncc) via [#204](https://github.com/10up/autoshare-for-twitter/pull/204)).
+- Migrated Cypress from 9.0.0 to 11.2.0 (props [@iamdharmesh](https://github.com/iamdharmesh), [@Sidsector9](https://github.com/Sidsector9) via [#205](https://github.com/10up/autoshare-for-twitter/pull/205)).
+- Run E2E tests on the zip generated by "Build release zip" action (props [@iamdharmesh](https://github.com/iamdharmesh), [@dkotter](https://github.com/dkotter), [@Sidsector9](https://github.com/Sidsector9) via [#206](https://github.com/10up/autoshare-for-twitter/pull/206)).
+
+### Fixed
+- E2E tests fail in the CI with warm cache (props [@cadic](https://github.com/cadic), [@iamdharmesh](https://github.com/iamdharmesh) via [#212](https://github.com/10up/autoshare-for-twitter/pull/212)).
+
+### Security
+- Bump `decode-uri-component` from 0.2.0 to 0.2.2 (props [@dependabot](https://github.com/apps/dependabot), [@iamdharmesh](https://github.com/iamdharmesh) via [#208](https://github.com/10up/autoshare-for-twitter/pull/208)).
+- Bump `simple-git` from 3.14.1 to 3.15.1 (props [@dependabot](https://github.com/apps/dependabot), [@iamdharmesh](https://github.com/iamdharmesh) via [#210](https://github.com/10up/autoshare-for-twitter/pull/210)).
+
+## [1.2.1] - 2022-12-07
**Note that this release bumps the WordPress minimum from 5.3 to 5.7 and PHP minimum from 7.2 to 7.4.**
### Added
@@ -159,6 +180,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Initial closed source release (props [@scottlee](https://github.com/scottlee/)).
[Unreleased]: https://github.com/10up/autoshare-for-twitter/compare/trunk...develop
+[1.3.0]: https://github.com/10up/autoshare-for-twitter/compare/1.2.1...1.3.0
[1.2.1]: https://github.com/10up/autoshare-for-twitter/compare/1.2.0...1.2.1
[1.2.0]: https://github.com/10up/autoshare-for-twitter/compare/1.1.2...1.2.0
[1.1.2]: https://github.com/10up/autoshare-for-twitter/compare/1.1.1...1.1.2
diff --git a/CREDITS.md b/CREDITS.md
index 7350e703..41ef1ca0 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -4,13 +4,13 @@ The following acknowledges the Maintainers for this repository, those who have C
The following individuals are responsible for curating the list of issues, responding to pull requests, and ensuring regular releases happen.
-[Jeffrey Paul (@jeffpaul)](https://github.com/jeffpaul), [Dharmesh Patel (@iamdharmesh)](https://github.com/iamdharmesh).
+[Dharmesh Patel (@iamdharmesh)](https://github.com/iamdharmesh), [Jeffrey Paul (@jeffpaul)](https://github.com/jeffpaul).
## Contributors
Thank you to all the people who have already contributed to this repository via bug reports, code, design, ideas, project management, translation, testing, etc.
-[Adam Silverstein (@adamsilverstein)](https://github.com/adamsilverstein), [John Watkins (@johnwatkins0)](https://github.com/johnwatkins0), [Scott Lee (@scottlee)](https://github.com/scottlee), [Jeffrey Paul (@jeffpaul)](https://github.com/jeffpaul), [Stephanie Campbell (@sncampbell)](https://github.com/sncampbell), [Ryan Welcher (@ryanwelcher)](https://github.com/ryanwelcher), [Ricky Lee Whittemore (@rickalee)](https://github.com/rickalee), [Tung Du (@dinhtungdu)](https://github.com/dinhtungdu), [Lina Wiezkowiak (@linawiezkowiak)](https://github.com/linawiezkowiak), [Oszkar Nagy (@oszkarnagy)](https://github.com/oszkarnagy), [Helen Hou-Sandi (@helen)](https://github.com/helen), [Thrijith Thankachan (@thrijith)](https://github.com/thrijith), [Barney Jeffries (@barneyjeffries)](https://github.com/barneyjeffries), [Darin Kotter (@dkotter)](https://github.com/dkotter), [Siddharth Thevaril (@Sidsector9)](https://github.com/Sidsector9), [Dharmesh Patel (@iamdharmesh)](https://github.com/iamdharmesh), [Faisal Alvi (@faisal-alvi)](https://github.com/faisal-alvi), [Sudip Dadhaniya (@sudip-10up)](https://github.com/sudip-10up), [Peter Wilson (@peterwilsoncc)](https://github.com/peterwilsoncc), [Max Lyuchin (@cadic)](https://github.com/cadic), [Vikram Moparthy (@vikrampm1)](https://github.com/vikrampm1), [GitHub Dependabot (@dependabot)](https://github.com/apps/dependabot).
+[Adam Silverstein (@adamsilverstein)](https://github.com/adamsilverstein), [John Watkins (@johnwatkins0)](https://github.com/johnwatkins0), [Scott Lee (@scottlee)](https://github.com/scottlee), [Jeffrey Paul (@jeffpaul)](https://github.com/jeffpaul), [Stephanie Campbell (@sncampbell)](https://github.com/sncampbell), [Ryan Welcher (@ryanwelcher)](https://github.com/ryanwelcher), [Ricky Lee Whittemore (@rickalee)](https://github.com/rickalee), [Tung Du (@dinhtungdu)](https://github.com/dinhtungdu), [Lina Wiezkowiak (@linawiezkowiak)](https://github.com/linawiezkowiak), [Oszkar Nagy (@oszkarnagy)](https://github.com/oszkarnagy), [Helen Hou-Sandi (@helen)](https://github.com/helen), [Thrijith Thankachan (@thrijith)](https://github.com/thrijith), [Barney Jeffries (@barneyjeffries)](https://github.com/barneyjeffries), [Darin Kotter (@dkotter)](https://github.com/dkotter), [Siddharth Thevaril (@Sidsector9)](https://github.com/Sidsector9), [Dharmesh Patel (@iamdharmesh)](https://github.com/iamdharmesh), [Faisal Alvi (@faisal-alvi)](https://github.com/faisal-alvi), [Sudip Dadhaniya (@sudip-10up)](https://github.com/sudip-10up), [Peter Wilson (@peterwilsoncc)](https://github.com/peterwilsoncc), [Max Lyuchin (@cadic)](https://github.com/cadic), [Vikram Moparthy (@vikrampm1)](https://github.com/vikrampm1), [GitHub Dependabot (@dependabot)](https://github.com/apps/dependabot), [Ravinder Kumar (@ravinderk)](https://github.com/ravinderk).
## Libraries
diff --git a/README.md b/README.md
index 4efc263f..10af0ffa 100644
--- a/README.md
+++ b/README.md
@@ -54,6 +54,14 @@ add_filter( 'dt_blacklisted_meta', function( $blacklisted_metas ) {
} )
```
+| Autoshare for Twitter Settings, found under `Settings` > `Autoshare for Twitter`. |
+| --------------- |
+|[![Autoshare for Twitter Settings, found under `Settings` > `Autoshare for Twitter`.](.wordpress-org/screenshot-1.png)](.wordpress-org/screenshot-1.png)|
+
+| Create post screen with Autoshare for Twitter options | Published post screen with Autoshare for Twitter options. |
+| -------------- | ---------------- |
+| [![Create post screen with Autoshare for Twitter options](.wordpress-org/screenshot-2.png)](.wordpress-org/screenshot-2.png) | [![Published post screen with Autoshare for Twitter options.](.wordpress-org/screenshot-3.png)](.wordpress-org/screenshot-3.png) |
+
## Requirements
- PHP 7.4+
@@ -61,9 +69,9 @@ add_filter( 'dt_blacklisted_meta', function( $blacklisted_metas ) {
## Installation
-1. Upload the entire `/autoshare-for-twitter` directory to the `/wp-content/plugins/` directory.
-2. Activate the plugin
-3. Register post type support for types that should be allowed to autoshare. `add_post_type_support( 'post', 'autoshare-for-twitter' );`
+1. Install the plugin via the plugin installer, either by searching for it or uploading a .ZIP file.
+2. Activate the plugin.
+3. Save Twitter connection settings, found under `Settings` > `Autoshare for Twitter`.
## FAQs
diff --git a/assets/css/admin-autoshare-for-twitter.css b/assets/css/admin-autoshare-for-twitter.css
index 25106eaa..c86bf703 100644
--- a/assets/css/admin-autoshare-for-twitter.css
+++ b/assets/css/admin-autoshare-for-twitter.css
@@ -10,6 +10,7 @@
#autoshare_for_twitter_metabox pre {
font-size: 11px;
white-space: normal;
+ margin: 0px;
}
.autoshare-for-twitter-toggle-control {
@@ -24,13 +25,12 @@
margin-top: 0.5rem;
}
-.autoshare-for-twitter-post-status {
+.autoshare-for-twitter-post-status .autoshare-for-twitter-log{
font-style: italic;
}
.autoshare-for-twitter-post-status svg {
- transform: translate3d(0, 3px, 0);
- margin-right: 5px;
+ margin-right: 4px;
}
#autoshare-for-twitter-icon.pending,
@@ -73,7 +73,6 @@ textarea#autoshare-for-twitter-text {
width: 100%
}
span#autoshare-for-twitter-counter-wrap {
- background: rgba(0, 0, 0, 0.07);
font-family: Consolas, Monaco, monospace;
}
@@ -130,3 +129,90 @@ tbody .autoshare-for-twitter-status-logo--disabled::before {
width: 24px;
height: 24px;
}
+
+.autoshare-for-twitter-log {
+ display: flex;
+ align-items: flex-start;
+ margin-bottom: 5px;
+}
+
+.autoshare-for-twitter-log svg {
+ max-width: 20px;
+ height: auto;
+}
+
+
+#autoshare_for_twitter_metabox .autoshare-for-twitter-status-icon::before {
+ background-image: url('../images/twitter_default.svg');
+ background-repeat: no-repeat;
+ background-size: 24px 24px;
+ content: ' ';
+ display: inline-block;
+ height: 24px;
+ width: 24px;
+ vertical-align: top;
+ margin-right: 5px;
+}
+
+#autoshare_for_twitter_metabox .autoshare-for-twitter-status-icon--published::before {
+ background-image: url('../images/twitter_tweeted.svg');
+}
+
+#autoshare_for_twitter_metabox .autoshare-for-twitter-status-icon--error::before {
+ background-image: url('../images/twitter_failed.svg');
+}
+
+#autoshare_for_twitter_metabox .autoshare-for-twitter-status-icon--enabled::before {
+ background-image: url('../images/twitter_enabled.svg');
+}
+
+#autoshare_for_twitter_metabox .autoshare-for-twitter-status-icon--disabled::before {
+ background-image: url('../images/twitter_disabled.svg');
+}
+
+#autoshare_for_twitter_metabox .autoshare-for-twitter-status-log-data {
+ display: inline-block;
+ max-width: 85%;
+}
+
+#autoshare_for_twitter_metabox .autoshare-for-twitter-status-wrap {
+ margin-bottom: 8px;
+}
+
+#autoshare_for_twitter_metabox .tweet-now-button{
+ text-decoration: none;
+ padding: 5px 12px 5px 0px;
+ font-weight: bold;
+ box-shadow: none;
+ outline: 0px;
+ background-color: #fff;
+}
+
+#autoshare_for_twitter_metabox .tweet-now-button span.dashicons {
+ vertical-align: bottom;
+ font-size: 16px;
+}
+
+#autoshare_for_twitter_metabox .autoshare-for-twitter-tweet-now-wrapper label.autoshare-for-twitter-enable-wrap {
+ display: none;
+}
+
+#autoshare_for_twitter_metabox .autoshare-for-twitter-tweet-now-wrapper a.cancel-tweet-text {
+ display: none;
+}
+
+#autoshare_for_twitter_metabox p#autoshare-for-twitter-error-message {
+ color: red;
+}
+
+#autoshare_for_twitter_metabox .autoshare-for-twitter-tweet-now-wrapper span.spinner {
+ float: none;
+}
+
+#autoshare_for_twitter_metabox span#autoshare-for-twitter-counter-wrap {
+ font-size: 12px;
+}
+
+.autoshare-for-twitter-editor-panel .autoshare-for-twitter-tweet-text label {
+ width: 100%;
+}
diff --git a/assets/js/admin-autoshare-for-twitter.js b/assets/js/admin-autoshare-for-twitter.js
index b46e95c0..cf38e319 100644
--- a/assets/js/admin-autoshare-for-twitter.js
+++ b/assets/js/admin-autoshare-for-twitter.js
@@ -12,9 +12,12 @@
$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'),
limit = 280;
+ const { __, sprintf } = wp.i18n;
// Add enabled class if checked
if ($tweetPost.prop('checked')) {
@@ -24,6 +27,8 @@
// Event handlers.
$tweetPost.on('click', handleRequest);
$tweetText.change(handleRequest);
+ $tweetPost.change(toggleAllowImageVisibility);
+ $allowTweetImage.change(handleRequest);
$editLink.on('click', function() {
$editBody.slideToggle();
updateRemainingField();
@@ -43,6 +48,7 @@
if ('' === adminAutoshareForTwitter.currentStatus) {
handleRequest(event, true);
}
+ updateRemainingField();
};
/**
@@ -71,6 +77,7 @@
var data = {};
data[adminAutoshareForTwitter.enableAutoshareKey] = status;
data[adminAutoshareForTwitter.tweetBodyKey] = $tweetText.val();
+ data[adminAutoshareForTwitter.allowTweetImageKey] = $allowTweetImage.prop('checked');
$('#submit').attr('disabled', true);
wp.apiFetch({
@@ -91,13 +98,21 @@
$icon.removeClass('pending');
if (data.enabled) {
- $icon.toggleClass('enabled');
+ $icon.removeClass('disabled');
+ $icon.addClass('enabled');
$tweetPost.prop('checked', true);
} else {
- $icon.toggleClass('disabled');
+ $icon.removeClass('enabled');
+ $icon.addClass('disabled');
$tweetPost.prop('checked', false);
}
+ if (data.allowImage) {
+ $allowTweetImage.prop('checked', true);
+ } else {
+ $allowTweetImage.prop('checked', false);
+ }
+
$('#submit').attr('disabled', false);
})
.catch(onRequestFail);
@@ -107,18 +122,40 @@
* Updates the counter
*/
function updateRemainingField() {
- var count = $tweetText.val().length;
+ let permalinkLength = 0;
+ if ( $('#sample-permalink').length ) {
+ permalinkLength = $('#sample-permalink').text().length
+ }
+ // +5 because of the space between body and URL and the ellipsis.
+ permalinkLength += 5;
+
+ var count = $tweetText.val().length + permalinkLength;
+ $tweetText.attr('maxlength', limit - permalinkLength);
$(counterWrap).text(count);
// Toggle the .over-limit class.
- if (limit < count) {
+ if (limit <= count) {
+ counterWrap.classList.remove('near-limit');
counterWrap.classList.add('over-limit');
- } else if (counterWrap.classList.contains('over-limit')) {
+ /* translators: %d is tweet message character count */
+ $(counterWrap).text( sprintf( __( '%d - Too Long!', 'autoshare-for-twitter' ), count ) );
+ } else if (240 <= count) {
+ counterWrap.classList.remove('over-limit');
+ counterWrap.classList.add('near-limit');
+ /* translators: %d is tweet message character count */
+ $(counterWrap).text( sprintf( __( '%d - Getting Long!', 'autoshare-for-twitter' ), count ) );
+ } else {
+ counterWrap.classList.remove('near-limit');
counterWrap.classList.remove('over-limit');
}
}
+ // Update the counter when the permalink is changed.
+ $( '#titlediv' ).on( 'focus', '.edit-slug', function() {
+ updateRemainingField();
+ });
+
/**
* Helper for toggling classes to indicate something is happening.
*/
@@ -127,4 +164,82 @@
$icon.removeClass('enabled');
$icon.removeClass('disabled');
}
+
+ // Show/Hide "Use featured image in Tweet" checkbox.
+ if ( allowTweetImageWrap && wp.media.featuredImage ) {
+ toggleAllowImageVisibility();
+ // Listen event for add/remove featured image.
+ wp.media.featuredImage.frame().on( 'select', toggleAllowImageVisibility );
+ $('#postimagediv').on( 'click', '#remove-post-thumbnail', toggleAllowImageVisibility );
+ }
+
+ /**
+ * Show/Hide "Use featured image in Tweet" checkbox.
+ */
+ function toggleAllowImageVisibility( event ) {
+ let hasMedia = wp.media.featuredImage.get();
+ // Handle remove post thumbnail click
+ if( event && event.target && 'remove-post-thumbnail' === event.target.id && 'click' === event.type ) {
+ hasMedia = -1;
+ }
+
+ const tweetNow = $('#tweet_now').length;
+ const autoshareEnabled = $tweetPost.prop('checked');
+ // Autoshare is enabled and post has featured image.
+ if ( hasMedia > 0 && ( autoshareEnabled || tweetNow ) ) {
+ allowTweetImageWrap.show();
+ } else {
+ allowTweetImageWrap.hide();
+ }
+ }
+
+ // 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");
+
+ 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 );
+
+ // Send request to Tweet now.
+ 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);
+ } 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);
diff --git a/autoshare-for-twitter.php b/autoshare-for-twitter.php
index 255eb06b..b6cd7b50 100644
--- a/autoshare-for-twitter.php
+++ b/autoshare-for-twitter.php
@@ -3,7 +3,7 @@
* Plugin Name: Autoshare for Twitter
* Description: Automatically tweets the post title or custom message and a link to the post.
* Disclaimer: TWITTER, TWEET, RETWEET and the Twitter logo are trademarks of Twitter, Inc. or its affiliates.
- * Version: 1.2.1
+ * Version: 1.3.0
* Requires at least: 5.7
* Requires PHP: 7.4
* Author: 10up
@@ -20,7 +20,7 @@
}
define( 'AUTOSHARE_FOR_TWITTER', __FILE__ );
-define( 'AUTOSHARE_FOR_TWITTER_VERSION', '1.2.1' );
+define( 'AUTOSHARE_FOR_TWITTER_VERSION', '1.3.0' );
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/' );
diff --git a/composer.json b/composer.json
index cb6db5d1..c6362de0 100644
--- a/composer.json
+++ b/composer.json
@@ -29,7 +29,7 @@
},
"minimum-stability": "dev",
"config": {
- "autoloader-suffix": "10upAutoshareForTwitterV121",
+ "autoloader-suffix": "10upAutoshareForTwitterV130",
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
diff --git a/includes/admin/assets.php b/includes/admin/assets.php
index f447aee6..dcb0aa15 100644
--- a/includes/admin/assets.php
+++ b/includes/admin/assets.php
@@ -12,10 +12,12 @@
use function TenUp\AutoshareForTwitter\Utils\opted_into_autoshare_for_twitter;
use function TenUp\AutoshareForTwitter\REST\post_autoshare_for_twitter_meta_rest_route;
use function TenUp\AutoshareForTwitter\Utils\autoshare_enabled;
+use function TenUp\AutoshareForTwitter\Utils\tweet_image_allowed;
use const TenUp\AutoshareForTwitter\Core\Post_Meta\ENABLE_AUTOSHARE_FOR_TWITTER_KEY;
use const TenUp\AutoshareForTwitter\Core\Post_Meta\TWEET_BODY_KEY;
use const TenUp\AutoshareForTwitter\Core\Post_Meta\TWITTER_STATUS_KEY;
+use const TenUp\AutoshareForTwitter\Core\Post_Meta\TWEET_ALLOW_IMAGE;
/**
* The handle used in registering plugin assets.
@@ -201,6 +203,9 @@ function localize_data( $handle = SCRIPT_HANDLE ) {
'status' => $status_meta && is_array( $status_meta ) ? $status_meta : null,
'unknownErrorText' => __( 'An unknown error occurred', 'autoshare-for-twitter' ),
'siteUrl' => home_url(),
+ 'allowTweetImage' => tweet_image_allowed( $post_id ),
+ 'allowTweetImageKey' => TWEET_ALLOW_IMAGE,
+ 'retweetAction' => 'tenup_autoshare_retweet',
];
wp_localize_script( $handle, 'adminAutoshareForTwitter', $localization );
diff --git a/includes/admin/post-meta.php b/includes/admin/post-meta.php
index fec044a3..12c2fb39 100644
--- a/includes/admin/post-meta.php
+++ b/includes/admin/post-meta.php
@@ -14,6 +14,7 @@
use function TenUp\AutoshareForTwitter\Utils\autoshare_enabled;
use function TenUp\AutoshareForTwitter\Utils\update_autoshare_for_twitter_meta;
+use function TenUp\AutoshareForTwitter\Utils\tweet_image_allowed;
use function TenUp\AutoshareForTwitter\Utils\delete_autoshare_for_twitter_meta;
/**
@@ -38,14 +39,16 @@
*/
const TWITTER_STATUS_KEY = 'status';
+const TWEET_ALLOW_IMAGE = 'tweet-allow-image';
+
/**
* The setup function
*
* @return void
*/
function setup() {
- add_action( 'post_submitbox_misc_actions', __NAMESPACE__ . '\tweet_submitbox_callback', 15 );
- add_action( 'autoshare_for_twitter_metabox', __NAMESPACE__ . '\render_tweet_submitbox', 10, 1 );
+ // Add Autoshare for twitter meta box to classic editor.
+ add_action( 'add_meta_boxes', __NAMESPACE__ . '\autoshare_for_twitter_metabox', 10, 2 );
add_action( 'save_post', __NAMESPACE__ . '\save_tweet_meta', 10, 3 );
}
@@ -114,6 +117,7 @@ function sanitize_autoshare_for_twitter_meta_data( $data ) {
$filtered_data = [];
foreach ( $data as $key => $value ) {
switch ( $key ) {
+ case TWEET_ALLOW_IMAGE:
case ENABLE_AUTOSHARE_FOR_TWITTER_KEY:
$filtered_data[ $key ] = boolval( $value );
break;
@@ -149,6 +153,16 @@ function save_autoshare_for_twitter_meta_data( $post_id, $data ) {
}
}
+ if ( ! array_key_exists( TWEET_ALLOW_IMAGE, $data ) ) {
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ if ( isset( $_POST['classic-editor'] ) ) {
+ // Handle unchecked "Tweet this post" checkbox for classic editor.
+ $data[ TWEET_ALLOW_IMAGE ] = 0;
+ } else {
+ $data[ TWEET_ALLOW_IMAGE ] = tweet_image_allowed( $post_id ) ? 1 : 0;
+ }
+ }
+
foreach ( $data as $key => $value ) {
switch ( $key ) {
case ENABLE_AUTOSHARE_FOR_TWITTER_KEY:
@@ -161,19 +175,28 @@ function save_autoshare_for_twitter_meta_data( $post_id, $data ) {
} else {
delete_autoshare_for_twitter_meta( $post_id, TWEET_BODY_KEY );
}
+
+ break;
+
+ case TWEET_ALLOW_IMAGE:
+ update_autoshare_for_twitter_meta( $post_id, TWEET_ALLOW_IMAGE, $value ? 'yes' : 'no' );
+ break;
+
+ default:
+ break;
}
}
}
/**
- * Callback for the Auto Tweet box in the Submit meta box.
+ * Add Autoshare for twitter metabox on post/post types.
*
- * @param \WP_Post $post The post being submitted.
+ * @param string $post_type Post Type.
+ * @param WP_Post $post WP_Post object.
*
- * @return void
+ * @since 1.3.0
*/
-function tweet_submitbox_callback( $post ) {
-
+function autoshare_for_twitter_metabox( $post_type, $post ) {
/**
* Don't bother enqueuing assets if the post type hasn't opted into autosharing.
*/
@@ -181,11 +204,15 @@ function tweet_submitbox_callback( $post ) {
return;
}
- ?>
-
- true )
+ );
}
/**
@@ -201,33 +228,35 @@ function render_tweet_submitbox( $post ) {
// If the post is already published the output varies slightly.
if ( 'publish' === $post_status ) {
-
- $twitter_status = Utils\get_autoshare_for_twitter_meta( get_the_ID(), TWITTER_STATUS_KEY );
- $status = isset( $twitter_status['status'] ) ? $twitter_status['status'] : '';
-
- switch ( $status ) {
-
- case 'published':
- $output = markup_published( $twitter_status );
- break;
-
- case 'error':
- $output = markup_error( $twitter_status );
- break;
-
- case 'unknown':
- $output = markup_unknown( $twitter_status );
- break;
-
- default:
- $output = __( 'This post was not tweeted.', 'autoshare-for-twitter' );
- break;
- }
-
- echo wp_kses_post( "" );
-
+ // Display tweet status logs.
+ ?>
+
+
+
+
+
+
+
+ $response_array ];
+ }
- $twitter_status = Utils\get_autoshare_for_twitter_meta( $post->ID, TWITTER_STATUS_KEY );
- $status = isset( $twitter_status['status'] ) ? $twitter_status['status'] : '';
+ $tweet_metas = Utils\get_autoshare_for_twitter_meta( $post->ID, TWITTER_STATUS_KEY );
+
+ if ( empty( $tweet_metas ) || isset( $tweet_metas['twitter_id'] ) ) {
+ $tweet_metas = array(
+ array(
+ 'status' => isset( $tweet_metas['status'] ) ? $tweet_metas['status'] : '',
+ 'created_at' => isset( $tweet_metas['created_at'] ) ? $tweet_metas['created_at'] : '',
+ 'twitter_id' => isset( $tweet_metas['twitter_id'] ) ? $tweet_metas['twitter_id'] : '',
+ ),
+ );
+ } elseif ( isset( $tweet_metas['status'] ) && ( 'error' === $tweet_metas['status'] || 'unknown' === $tweet_metas['status'] || 'other' === $tweet_metas['status'] ) ) {
+ $tweet_metas = array(
+ $tweet_metas,
+ );
+ }
+
+ foreach ( $tweet_metas as $tweet_meta ) {
+ $status = $tweet_meta['status'];
+ if ( 'publish' !== $post_status && empty( $status ) ) {
+ continue;
+ }
switch ( $status ) {
case 'published':
- $date = Utils\date_from_twitter( $twitter_status['created_at'] );
- $twitter_url = Utils\link_from_twitter( $twitter_status['twitter_id'] );
+ $date = Utils\date_from_twitter( $tweet_meta['created_at'] );
+ $twitter_url = Utils\link_from_twitter( $tweet_meta['twitter_id'] );
- return [
+ $response_array[] = [
// Translators: Placeholder is a date.
'message' => sprintf( __( 'Tweeted on %s', 'autoshare-for-twitter' ), $date ),
'url' => $twitter_url,
'status' => $status,
];
+ break;
+
case 'error':
- return [
- 'message' => __( 'Failed to tweet: ', 'autoshare-for-twitter' ) . $twitter_status['message'],
+ $response_array[] = [
+ 'message' => __( 'Failed to tweet: ', 'autoshare-for-twitter' ) . $tweet_meta['message'],
'status' => $status,
];
+ break;
+
case 'unknown':
- return [
- 'message' => $twitter_status['message'],
+ $response_array[] = [
+ 'message' => $tweet_meta['message'],
'status' => $status,
];
+ break;
+
default:
- return [
+ $response_array[] = [
'message' => __( 'This post was not tweeted.', 'autoshare-for-twitter' ),
'status' => $status,
];
}
}
- return [ 'message' => '' ];
+ return [ 'message' => $response_array ];
}
+/**
+ * Gets info on the post's Tweet status to display in classic editor metabox.
+ *
+ * @since 1.3.0
+ *
+ * @param int|WP_Post $post The post we are rendering on.
+ * @return string markup containing the tweet status logs if the post was tweeted.
+ */
+function get_tweet_status_logs( $post ) {
+ $post = get_post( $post );
+ $post_status = get_post_status( $post );
+ $status_logs = '';
+
+ $tweet_metas = Utils\get_autoshare_for_twitter_meta( $post->ID, TWITTER_STATUS_KEY );
+
+ if ( empty( $tweet_metas ) || isset( $tweet_metas['twitter_id'] ) ) {
+ $tweet_metas = array(
+ array(
+ 'status' => isset( $tweet_metas['status'] ) ? $tweet_metas['status'] : '',
+ 'created_at' => isset( $tweet_metas['created_at'] ) ? $tweet_metas['created_at'] : '',
+ 'twitter_id' => isset( $tweet_metas['twitter_id'] ) ? $tweet_metas['twitter_id'] : '',
+ ),
+ );
+ } elseif ( isset( $tweet_metas['status'] ) && ( 'error' === $tweet_metas['status'] || 'unknown' === $tweet_metas['status'] || 'other' === $tweet_metas['status'] ) ) {
+ $tweet_metas = array(
+ $tweet_metas,
+ );
+ }
+
+ foreach ( $tweet_metas as $twitter_meta ) {
+ $status = isset( $twitter_meta['status'] ) ? $twitter_meta['status'] : '';
+ if ( 'publish' !== $post_status && empty( $status ) ) {
+ continue;
+ }
+
+ switch ( $status ) {
+
+ case 'published':
+ $output = markup_published( $twitter_meta );
+ break;
+
+ case 'error':
+ $output = markup_error( $twitter_meta );
+ break;
+
+ case 'unknown':
+ $output = markup_unknown( $twitter_meta );
+ break;
+
+ default:
+ $output = __( 'This post was not tweeted.', 'autoshare-for-twitter' );
+ break;
+ }
+
+ $status_logs .= "";
+ }
+
+ return wp_kses_post( $status_logs );
+}
+
/**
* Outputs the markup and language to be used when a post has been successfully
* sent to Twitter
@@ -300,7 +417,7 @@ function markup_published( $status_meta ) {
$twitter_url = Utils\link_from_twitter( $status_meta['twitter_id'] );
return sprintf(
- '%s %s (%s )',
+ '',
esc_html__( 'Tweeted on', 'autoshare-for-twitter' ),
esc_html( $date ),
esc_url( $twitter_url ),
@@ -319,7 +436,7 @@ function markup_published( $status_meta ) {
function markup_error( $status_meta ) {
return sprintf(
- '%s%s ',
+ '',
esc_html__( 'Failed to tweet', 'autoshare-for-twitter' ),
esc_html( $status_meta['message'] )
);
@@ -334,7 +451,10 @@ function markup_error( $status_meta ) {
* @return string
*/
function markup_unknown( $status_meta ) {
- return $status_meta['message'];
+ return sprintf(
+ '',
+ esc_html( $status_meta['message'] )
+ );
}
/**
@@ -343,10 +463,11 @@ function markup_unknown( $status_meta ) {
* @return string
*/
function _safe_markup_default() {
-
+ $count = ( strlen( get_permalink( get_the_ID() ) ) + 5 );
+ $max_length = 280 - $count;
ob_start();
?>
-
+
+
+
diff --git a/includes/admin/post-transition.php b/includes/admin/post-transition.php
index b842636a..1159e316 100644
--- a/includes/admin/post-transition.php
+++ b/includes/admin/post-transition.php
@@ -11,9 +11,12 @@
use TenUp\AutoshareForTwitter\Core\AST_Staging\AST_Staging;
use TenUp\AutoshareForTwitter\Core\Post_Meta as Meta;
use TenUp\AutoshareForTwitter\Utils as Utils;
-use function TenUp\AutoshareForTwitter\Utils\delete_autoshare_for_twitter_meta;
+
+use function TenUp\AutoshareForTwitter\Core\Post_Meta\get_tweet_status_message;
use function TenUp\AutoshareForTwitter\Utils\update_autoshare_for_twitter_meta;
use function TenUp\AutoshareForTwitter\Core\Post_Meta\save_tweet_meta;
+use function TenUp\AutoshareForTwitter\Utils\get_autoshare_for_twitter_meta;
+use function TenUp\AutoshareForTwitter\Core\Post_Meta\get_tweet_status_logs;
/**
* Setup function.
@@ -22,6 +25,7 @@
*/
function setup() {
add_action( 'transition_post_status', __NAMESPACE__ . '\maybe_publish_tweet', 10, 3 );
+ add_action( 'wp_ajax_tenup_autoshare_retweet', __NAMESPACE__ . '\retweet', 10, 3 );
}
/**
@@ -85,11 +89,12 @@ function( $post ) {
/**
* Primary handler for the process of publishing to Twitter.
*
- * @param int $post_id The current post ID.
+ * @param int $post_id The current post ID.
+ * @param bool $force Publish tweet regardless of autoshare enabled or disabled on post.
*
* @return object
*/
-function publish_tweet( $post_id ) {
+function publish_tweet( $post_id, $force = false ) {
$post = get_post( $post_id );
/*
@@ -112,7 +117,7 @@ function publish_tweet( $post_id ) {
/*
* One final check: was the "auto tweet" checkbox selected?
*/
- if ( Utils\autoshare_enabled( $post->ID ) ) {
+ if ( Utils\autoshare_enabled( $post->ID ) || $force ) {
$tweet = Utils\compose_tweet_body( $post );
$publish = new Publish_Tweet();
@@ -128,6 +133,8 @@ function publish_tweet( $post_id ) {
*/
do_action( 'autoshare_for_twitter_success' );
+ return true;
+
} else {
// something here about it failing so do not allow republishing just in case.
update_autoshare_for_twitter_meta_from_response( $post->ID, $response );
@@ -136,8 +143,38 @@ function publish_tweet( $post_id ) {
* Fires if the response back from Twitter was an error.
*/
do_action( 'autoshare_for_twitter_failed' );
+
+ return false;
}
}
+
+ return false;
+}
+
+/**
+ * Handles Re-tweeting.
+ */
+function retweet() {
+ if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wp_rest' ) ) {
+ wp_send_json_error( __( 'Nonce verification failed.', 'autoshare-for-twitter' ) );
+ }
+
+ $post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
+ $is_retweeted = publish_tweet( $post_id, true );
+
+ // Send status logs markup for classic editor.
+ if ( isset( $_POST['is_classic'] ) && ! empty( $_POST['is_classic'] ) ) {
+ $message = [ 'message' => get_tweet_status_logs( $post_id ) ];
+ } else {
+ $message = get_tweet_status_message( $post_id );
+ }
+ $message['is_retweeted'] = $is_retweeted;
+
+ if ( $is_retweeted ) {
+ wp_send_json_success( $message );
+ } else {
+ wp_send_json_error( $message );
+ }
}
/**
@@ -204,12 +241,28 @@ function update_autoshare_for_twitter_meta_from_response( $post_id, $data ) {
*/
$response = apply_filters( 'autoshare_for_twitter_post_status_meta', $response );
+ $tweet_meta = get_autoshare_for_twitter_meta( $post_id, Meta\TWITTER_STATUS_KEY );
+
+ if ( '' === $tweet_meta ) {
+ $tweet_meta = array();
+ }
+
+ /**
+ * Handles meta for multiple tweets.
+ */
+ if ( isset( $tweet_meta['twitter_id'] ) || isset( $tweet_meta['status'] ) ) {
+ $tweet_meta = array(
+ $tweet_meta,
+ $response,
+ );
+ } else {
+ $tweet_meta[] = $response;
+ }
+
/**
- * Update the post meta entry that stores the response
- * and remove the "Autoshare this post" value as a double-check.
+ * Update the post meta entry that stores the response.
*/
- update_autoshare_for_twitter_meta( $post_id, Meta\TWITTER_STATUS_KEY, $response );
- delete_autoshare_for_twitter_meta( $post_id, Meta\ENABLE_AUTOSHARE_FOR_TWITTER_KEY );
+ update_autoshare_for_twitter_meta( $post_id, Meta\TWITTER_STATUS_KEY, $tweet_meta );
/**
* Fires after the response from Twitter has been written as meta to the post.
diff --git a/includes/class-publish-tweet.php b/includes/class-publish-tweet.php
index 255058fd..9852c81e 100644
--- a/includes/class-publish-tweet.php
+++ b/includes/class-publish-tweet.php
@@ -9,6 +9,7 @@
use TenUp\AutoshareForTwitter\Utils as Utils;
use Abraham\TwitterOAuth\TwitterOAuth as TwitterOAuth;
+use const \TenUp\AutoshareForTwitter\Core\Post_Meta\TWEET_ALLOW_IMAGE;
/**
* Publish tweets to twitter.
@@ -98,13 +99,17 @@ public function status_update( $body, $post ) {
if ( empty( $body ) ) {
return;
}
+
$update_data = array(
'status' => $body, // URL encoding handled by buildHttpQuery vai TwitterOAuth.
);
- $media_id = $this->get_upload_data_media_id( $post );
- if ( $media_id ) {
- $update_data['media_ids'] = [ $media_id ];
+ $is_image_allowed = Utils\get_autoshare_for_twitter_meta( $post->ID, TWEET_ALLOW_IMAGE );
+ if ( 'no' !== $is_image_allowed ) {
+ $media_id = $this->get_upload_data_media_id( $post );
+ if ( $media_id ) {
+ $update_data['media_ids'] = [ $media_id ];
+ }
}
/**
diff --git a/includes/core.php b/includes/core.php
index 4542ab64..d68f92e1 100644
--- a/includes/core.php
+++ b/includes/core.php
@@ -40,7 +40,7 @@ function setup() {
// Setup hooks to add post type support and tweet status columns for supported / enabled post types.
add_action( 'init', __NAMESPACE__ . '\set_post_type_supports_with_custom_columns' );
add_filter( 'autoshare_for_twitter_enabled_default', __NAMESPACE__ . '\maybe_enable_autoshare_by_default' );
- add_filter( 'autoshare_for_twitter_attached_image', __NAMESPACE__ . '\maybe_disable_upload_image' );
+ add_filter( 'autoshare_for_twitter_attached_image', __NAMESPACE__ . '\maybe_disable_upload_image', 10, 2 );
}
/**
@@ -81,11 +81,12 @@ function maybe_enable_autoshare_by_default() {
* @since 1.0.0
*
* @param null|int $attachment_id ID of attachment being uploaded.
+ * @param \WP_Post $post Post being tweeted.
*
* @return null|int|bool
*/
-function maybe_disable_upload_image( $attachment_id ) {
- if ( ! Utils\get_autoshare_for_twitter_settings( 'enable_upload' ) ) {
+function maybe_disable_upload_image( $attachment_id, $post ) {
+ if ( ! Utils\tweet_image_allowed( $post->ID ) ) {
return false;
}
@@ -125,9 +126,17 @@ function modify_post_type_add_tweet_status( $column_name, $post_id ) {
return;
}
- $post_status = get_post_status( $post_id );
- $tweet_status = Utils\get_autoshare_for_twitter_meta( $post_id, TWITTER_STATUS_KEY );
- $status = isset( $tweet_status['status'] ) ? $tweet_status['status'] : '';
+ $post_status = get_post_status( $post_id );
+ $tweet_meta = Utils\get_autoshare_for_twitter_meta( $post_id, TWITTER_STATUS_KEY );
+
+ $tweet_status = array();
+ if ( isset( $tweet_meta['status'] ) ) {
+ $tweet_status = $tweet_meta;
+ } elseif ( ! empty( $tweet_meta ) ) {
+ $tweet_status = end( $tweet_meta );
+ }
+
+ $status = isset( $tweet_status['status'] ) ? $tweet_status['status'] : '';
if ( 'publish' === $post_status && 'published' === $status ) {
$date = Utils\date_from_twitter( $tweet_status['created_at'] );
diff --git a/includes/rest.php b/includes/rest.php
index fbef3881..c2a36fee 100644
--- a/includes/rest.php
+++ b/includes/rest.php
@@ -12,6 +12,7 @@
use WP_REST_Server;
use const TenUp\AutoshareForTwitter\Core\Post_Meta\TWEET_BODY_KEY;
use const TenUp\AutoshareForTwitter\Core\Post_Meta\ENABLE_AUTOSHARE_FOR_TWITTER_KEY;
+use const TenUp\AutoshareForTwitter\Core\Post_Meta\TWEET_ALLOW_IMAGE;
use const TenUp\AutoshareForTwitter\Core\POST_TYPE_SUPPORT_FEATURE;
use function TenUp\AutoshareForTwitter\Core\Post_Meta\get_tweet_status_message;
@@ -84,6 +85,12 @@ function register_post_autoshare_for_twitter_meta_rest_route() {
'type' => 'boolean',
'validate_callback' => 'rest_validate_request_arg',
],
+ TWEET_ALLOW_IMAGE => [
+ 'description' => __( 'Whether the tweet has an image.', 'autoshare-for-twitter' ),
+ 'required' => true,
+ 'type' => 'boolean',
+ 'validate_callback' => 'rest_validate_request_arg',
+ ],
],
]
);
@@ -123,16 +130,18 @@ function update_post_autoshare_for_twitter_meta( $request ) {
save_autoshare_for_twitter_meta_data( $request['id'], $params );
- $enabled = (bool) get_autoshare_for_twitter_meta( $request['id'], ENABLE_AUTOSHARE_FOR_TWITTER_KEY, true );
- $message = $enabled ?
+ $enabled = (bool) get_autoshare_for_twitter_meta( $request['id'], ENABLE_AUTOSHARE_FOR_TWITTER_KEY, true );
+ $tweet_allow_image = (bool) ( 'yes' === get_autoshare_for_twitter_meta( $request['id'], TWEET_ALLOW_IMAGE, true ) );
+ $message = $enabled ?
__( 'Autoshare enabled.', 'autoshare-for-twitter' ) :
__( 'Autoshare disabled.', 'autoshare-for-twitter' );
return rest_ensure_response(
[
- 'enabled' => $enabled,
- 'message' => $message,
- 'override' => ! empty( get_autoshare_for_twitter_meta( $request['id'], TWEET_BODY_KEY, true ) ),
+ 'enabled' => $enabled,
+ 'message' => $message,
+ 'override' => ! empty( get_autoshare_for_twitter_meta( $request['id'], TWEET_BODY_KEY, true ) ),
+ 'allowImage' => $tweet_allow_image,
]
);
}
diff --git a/includes/utils.php b/includes/utils.php
index 3ad7c762..74de553f 100644
--- a/includes/utils.php
+++ b/includes/utils.php
@@ -13,6 +13,7 @@
use const TenUp\AutoshareForTwitter\Core\Post_Meta\META_PREFIX;
use const TenUp\AutoshareForTwitter\Core\Post_Meta\TWEET_BODY_KEY;
use const TenUp\AutoshareForTwitter\Core\Post_Meta\TWITTER_STATUS_KEY;
+use const TenUp\AutoshareForTwitter\Core\Post_Meta\TWEET_ALLOW_IMAGE;
/**
* Helper/Wrapper function for returning the meta entries for autosharing.
@@ -92,6 +93,29 @@ function autoshare_enabled( $post_id ) {
return apply_filters( 'autoshare_for_twitter_enabled_default', false, get_post_type( $post_id ), $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 ) {
+ if ( has_autoshare_for_twitter_meta( $post_id, TWEET_ALLOW_IMAGE ) ) {
+ return ( 'yes' === get_autoshare_for_twitter_meta( $post_id, TWEET_ALLOW_IMAGE ) );
+ }
+
+ $is_allowed = (bool) get_autoshare_for_twitter_settings( 'enable_upload' );
+
+ /**
+ * Filters whether autoshare is enabled by default on a post type or post.
+ *
+ * @param bool Whether autoshare is enabled by default. True by default.
+ * @param string Post type.
+ * @param int The current post ID.
+ */
+ return apply_filters( 'autoshare_for_twitter_tweet_image_allowed', $is_allowed, get_post_type( $post_id ), $post_id );
+}
+
/**
* Helper for returning the Auto Tweet site settings.
*
diff --git a/package-lock.json b/package-lock.json
index 89aad917..9888cd13 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@10up/autoshare-for-twitter",
- "version": "1.2.1",
+ "version": "1.3.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@10up/autoshare-for-twitter",
- "version": "1.2.1",
+ "version": "1.3.0",
"dependencies": {
"@wordpress/api-fetch": "^3.5.0"
},
@@ -16,12 +16,12 @@
"@babel/core": "^7.6.0",
"@babel/preset-env": "^7.6.0",
"@babel/preset-react": "^7.0.0",
- "@wordpress/env": "^5.4.0",
+ "@wordpress/env": "^5.7.0",
"@wordpress/eslint-plugin": "^3.0.0",
"@wordpress/prettier-config": "^1.1.1",
"babel-eslint": "^10.0.3",
"babel-loader": "^8.0.6",
- "cypress": "^9.0.0",
+ "cypress": "^11.2.0",
"eslint": "^6.3.0",
"husky": "^3.0.5",
"lint-staged": "^9.2.5",
@@ -4143,9 +4143,9 @@
}
},
"node_modules/@wordpress/env": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-5.5.0.tgz",
- "integrity": "sha512-Dm/XHkCD8rVSfm9fGvK92EbfZ7UhZCkIoNdv8wq21cwiZ0/2O0iPaC73aJ/4pTaY0PBODz5Z/LD4gE/cRSDcxg==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-5.7.0.tgz",
+ "integrity": "sha512-9H5ZUhqRzdjghQgVMpxZDpx/W0Tf74D7mExFEQPGZdfoJUWNiHpgfbRK70IGKJk2kGit+9b90zuMIIA6PDahNw==",
"dev": true,
"dependencies": {
"chalk": "^4.0.0",
@@ -5929,9 +5929,9 @@
}
},
"node_modules/cypress": {
- "version": "9.7.0",
- "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.7.0.tgz",
- "integrity": "sha512-+1EE1nuuuwIt/N1KXRR2iWHU+OiIt7H28jJDyyI4tiUftId/DrXYEwoDa5+kH2pki1zxnA0r6HrUGHV5eLbF5Q==",
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/cypress/-/cypress-11.2.0.tgz",
+ "integrity": "sha512-u61UGwtu7lpsNWLUma/FKNOsrjcI6wleNmda/TyKHe0dOBcVjbCPlp1N6uwFZ0doXev7f/91YDpU9bqDCFeBLA==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
@@ -5954,7 +5954,7 @@
"dayjs": "^1.10.4",
"debug": "^4.3.2",
"enquirer": "^2.3.6",
- "eventemitter2": "^6.4.3",
+ "eventemitter2": "6.4.7",
"execa": "4.1.0",
"executable": "^4.1.1",
"extract-zip": "2.0.1",
@@ -6160,9 +6160,9 @@
}
},
"node_modules/decode-uri-component": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
- "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==",
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
+ "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
"engines": {
"node": ">=0.10"
}
@@ -6952,9 +6952,9 @@
}
},
"node_modules/eventemitter2": {
- "version": "6.4.9",
- "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz",
- "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==",
+ "version": "6.4.7",
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz",
+ "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==",
"dev": true
},
"node_modules/events": {
@@ -10307,9 +10307,9 @@
}
},
"node_modules/loader-utils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz",
- "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
+ "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
"dev": true,
"dependencies": {
"big.js": "^5.2.2",
@@ -13855,9 +13855,9 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
},
"node_modules/simple-git": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.14.1.tgz",
- "integrity": "sha512-1ThF4PamK9wBORVGMK9HK5si4zoGS2GpRO7tkAFObA4FZv6dKaCVHLQT+8zlgiBm6K2h+wEU9yOaFCu/SR3OyA==",
+ "version": "3.15.1",
+ "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.15.1.tgz",
+ "integrity": "sha512-73MVa5984t/JP4JcQt0oZlKGr42ROYWC3BcUZfuHtT3IHKPspIvL0cZBnvPXF7LL3S/qVeVHVdYYmJ3LOTw4Rg==",
"dev": true,
"dependencies": {
"@kwsites/file-exists": "^1.1.1",
@@ -18951,9 +18951,9 @@
}
},
"@wordpress/env": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-5.5.0.tgz",
- "integrity": "sha512-Dm/XHkCD8rVSfm9fGvK92EbfZ7UhZCkIoNdv8wq21cwiZ0/2O0iPaC73aJ/4pTaY0PBODz5Z/LD4gE/cRSDcxg==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-5.7.0.tgz",
+ "integrity": "sha512-9H5ZUhqRzdjghQgVMpxZDpx/W0Tf74D7mExFEQPGZdfoJUWNiHpgfbRK70IGKJk2kGit+9b90zuMIIA6PDahNw==",
"dev": true,
"requires": {
"chalk": "^4.0.0",
@@ -20326,9 +20326,9 @@
}
},
"cypress": {
- "version": "9.7.0",
- "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.7.0.tgz",
- "integrity": "sha512-+1EE1nuuuwIt/N1KXRR2iWHU+OiIt7H28jJDyyI4tiUftId/DrXYEwoDa5+kH2pki1zxnA0r6HrUGHV5eLbF5Q==",
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/cypress/-/cypress-11.2.0.tgz",
+ "integrity": "sha512-u61UGwtu7lpsNWLUma/FKNOsrjcI6wleNmda/TyKHe0dOBcVjbCPlp1N6uwFZ0doXev7f/91YDpU9bqDCFeBLA==",
"dev": true,
"requires": {
"@cypress/request": "^2.88.10",
@@ -20350,7 +20350,7 @@
"dayjs": "^1.10.4",
"debug": "^4.3.2",
"enquirer": "^2.3.6",
- "eventemitter2": "^6.4.3",
+ "eventemitter2": "6.4.7",
"execa": "4.1.0",
"executable": "^4.1.1",
"extract-zip": "2.0.1",
@@ -20499,9 +20499,9 @@
"peer": true
},
"decode-uri-component": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
- "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og=="
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
+ "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ=="
},
"decompress-response": {
"version": "6.0.0",
@@ -21088,9 +21088,9 @@
"peer": true
},
"eventemitter2": {
- "version": "6.4.9",
- "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz",
- "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==",
+ "version": "6.4.7",
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz",
+ "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==",
"dev": true
},
"events": {
@@ -23647,9 +23647,9 @@
"dev": true
},
"loader-utils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz",
- "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
+ "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
"dev": true,
"requires": {
"big.js": "^5.2.2",
@@ -26413,9 +26413,9 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
},
"simple-git": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.14.1.tgz",
- "integrity": "sha512-1ThF4PamK9wBORVGMK9HK5si4zoGS2GpRO7tkAFObA4FZv6dKaCVHLQT+8zlgiBm6K2h+wEU9yOaFCu/SR3OyA==",
+ "version": "3.15.1",
+ "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.15.1.tgz",
+ "integrity": "sha512-73MVa5984t/JP4JcQt0oZlKGr42ROYWC3BcUZfuHtT3IHKPspIvL0cZBnvPXF7LL3S/qVeVHVdYYmJ3LOTw4Rg==",
"dev": true,
"requires": {
"@kwsites/file-exists": "^1.1.1",
diff --git a/package.json b/package.json
index 607c820c..c37e8b07 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@10up/autoshare-for-twitter",
- "version": "1.2.1",
+ "version": "1.3.0",
"description": "Automatically tweets a post title, URL, and optional description.",
"scripts": {
"watch": "webpack -w --devtool eval-cheap-module-source-map --output-pathinfo --mode development --config webpack.gutenberg.config.js",
@@ -10,8 +10,8 @@
"env:start": "wp-env start",
"env:stop": "wp-env stop",
"postenv:start": "./tests/bin/initialize.sh",
- "cypress:open": "cypress open --config-file tests/cypress/config.json",
- "cypress:run": "cypress run --config-file tests/cypress/config.json",
+ "cypress:open": "cypress open --config-file tests/cypress/cypress.config.js --e2e --browser chrome",
+ "cypress:run": "cypress run --config-file tests/cypress/cypress.config.js",
"lint": "eslint ."
},
"husky": {
@@ -42,12 +42,12 @@
"@babel/core": "^7.6.0",
"@babel/preset-env": "^7.6.0",
"@babel/preset-react": "^7.0.0",
- "@wordpress/env": "^5.4.0",
+ "@wordpress/env": "^5.7.0",
"@wordpress/eslint-plugin": "^3.0.0",
"@wordpress/prettier-config": "^1.1.1",
"babel-eslint": "^10.0.3",
"babel-loader": "^8.0.6",
- "cypress": "^9.0.0",
+ "cypress": "^11.2.0",
"eslint": "^6.3.0",
"husky": "^3.0.5",
"lint-staged": "^9.2.5",
diff --git a/readme.txt b/readme.txt
index 982bb6ce..0da5d05f 100644
--- a/readme.txt
+++ b/readme.txt
@@ -4,7 +4,7 @@ Tags: twitter, tweet, autoshare, auto-share, auto share, share, soc
Requires at least: 5.7
Tested up to: 6.1
Requires PHP: 7.4
-Stable tag: 1.2.1
+Stable tag: 1.3.0
License: GPL-2.0-or-later
License URI: https://spdx.org/licenses/GPL-2.0-or-later.html
@@ -12,15 +12,44 @@ Automatically tweets the post title or custom message and a link to the post.
== Description ==
-Automatically tweets the post title or custom message and a link to the post. Additional technical details can be found in [our GitHub repository](https://github.com/10up/autoshare-for-twitter#overview).
+Automatically tweets the post title or custom message and a link to the post.
-**Disclaimer:** *TWITTER, TWEET, RETWEET and the Twitter logo are trademarks of Twitter, Inc. or its affiliates.*
+**Note:** Posts and pages are supported by default. Developers can use the `autoshare_for_twitter_default_post_types` filter to change the default supported post types
+
+Custom post types can now be opted into autoshare features like so:
+
+`
+function opt_my_cpt_into_autoshare() {
+ add_post_type_support( 'my-cpt', 'autoshare-for-twitter' );
+}
+add_action( 'init', 'opt_my_cpt_into_autoshare' );
+`
+
+In addition, adding support while registering custom post types also works. Post types are automatically set to autoshare. Future versions of this plugin could allow this to be set manually.
+
+While the autoshare feature can be opted into for post types using the above filter, by default the editor still has to manually enable autoshare during the post prepublish flow. The `autoshare_for_twitter_enabled_default` filter allows autoshare to be enabled by default for all posts of a given post type. Editors can still manually uncheck the option during the publishing flow.
+
+Example:
-== Manual Installation ==
+`
+function enable_autoshare_by_default_for_core_post_type( $enabled, $post_type ) {
+ if ( 'post' === $post_type ) {
+ return true;
+ }
-1. Upload the entire `/autoshare-for-twitter` directory to the `/wp-content/plugins/` directory.
-2. Activate the plugin
-3. Register post type support for types that should be allowed to autoshare: `add_post_type_support( 'post', 'autoshare-for-twitter' );`
+ return $enabled;
+}
+add_filter( 'autoshare_for_twitter_enabled_default', 'enable_autoshare_by_default_for_core_post_type', 10, 2 );
+`
+
+Additional technical details can be found in [our GitHub repository](https://github.com/10up/autoshare-for-twitter#overview).
+
+**Disclaimer:** *TWITTER, TWEET, RETWEET and the Twitter logo are trademarks of Twitter, Inc. or its affiliates.*
+
+== Installation ==
+1. Install the plugin via the plugin installer, either by searching for it or uploading a .ZIP file.
+2. Activate the plugin.
+3. Save Twitter connection settings, found under `Settings` > `Autoshare for Twitter`.
== Frequently Asked Questions ==
@@ -28,8 +57,28 @@ Automatically tweets the post title or custom message and a link to the post. A
Yes, yes it does! For more details on this, see [#44](https://github.com/10up/autoshare-for-twitter/pull/44).
+== Screenshots ==
+
+1. Autoshare for Twitter Settings, found under `Settings` > `Autoshare for Twitter`.
+2. Create post screen with Autoshare for Twitter options.
+3. Published post screen with Autoshare for Twitter options.
+
== Changelog ==
-= 1.2.1 - 2022-12-05 =
+= 1.3.0 - 2023-01-19 =
+* **Added:** "Tweet now" functionality (props [@Sidsector9](https://github.com/Sidsector9), [@iamdharmesh](https://github.com/iamdharmesh), [@cadic](https://github.com/cadic), [@jeffpaul](https://github.com/jeffpaul), [@linawiezkowiak](https://github.com/linawiezkowiak), [@oszkarnagy](https://github.com/oszkarnagy) via [#188](https://github.com/10up/autoshare-for-twitter/pull/188)).
+* **Added:** Toggle for adding/removing featured image from the tweet (props [@Sidsector9](https://github.com/Sidsector9), [@iamdharmesh](https://github.com/iamdharmesh), [@cadic](https://github.com/cadic), [@jeffpaul](https://github.com/jeffpaul), [@linawiezkowiak](https://github.com/linawiezkowiak), [@oszkarnagy](https://github.com/oszkarnagy) via [#188](https://github.com/10up/autoshare-for-twitter/pull/188)).
+* **Added:** Show Twitter status logs for the draft post if the post has been switched back to Draft from Published, and has already been Tweeted (props [@iamdharmesh](https://github.com/iamdharmesh), [@faisal-alvi](https://github.com/faisal-alvi), [@jeffpaul](https://github.com/jeffpaul), [@linawiezkowiak](https://github.com/linawiezkowiak), [@oszkarnagy](https://github.com/oszkarnagy) via [#215](https://github.com/10up/autoshare-for-twitter/pull/215)).
+* **Added:** Plugin screenshots to readme files (props [@iamdharmesh](https://github.com/iamdharmesh) via [#218](https://github.com/10up/autoshare-for-twitter/pull/218)).
+* **Changed:** UI Improvements in Tweet status (props [@Sidsector9](https://github.com/Sidsector9), [@iamdharmesh](https://github.com/iamdharmesh), [@cadic](https://github.com/cadic), [@jeffpaul](https://github.com/jeffpaul), [@linawiezkowiak](https://github.com/linawiezkowiak), [@oszkarnagy](https://github.com/oszkarnagy) via [#188](https://github.com/10up/autoshare-for-twitter/pull/188)).
+* **Changed:** UI Improvements in tweet message character count (props [@iamdharmesh](https://github.com/iamdharmesh), [@Sidsector9](https://github.com/Sidsector9), [@ravinderk](https://github.com/ravinderk), [@jeffpaul](https://github.com/jeffpaul), [@linawiezkowiak](https://github.com/linawiezkowiak), [@oszkarnagy](https://github.com/oszkarnagy) via [#214](https://github.com/10up/autoshare-for-twitter/pull/214)).
+* **Changed:** Run GitHub Action workflows only when it required (props [@iamdharmesh](https://github.com/iamdharmesh), [@peterwilsoncc](https://github.com/peterwilsoncc) via [#204](https://github.com/10up/autoshare-for-twitter/pull/204)).
+* **Changed:** Migrated Cypress from 9.0.0 to 11.2.0 (props [@iamdharmesh](https://github.com/iamdharmesh), [@Sidsector9](https://github.com/Sidsector9) via [#205](https://github.com/10up/autoshare-for-twitter/pull/205)).
+* **Changed:** Run E2E tests on the zip generated by "Build release zip" action (props [@iamdharmesh](https://github.com/iamdharmesh), [@dkotter](https://github.com/dkotter), [@Sidsector9](https://github.com/Sidsector9) via [#206](https://github.com/10up/autoshare-for-twitter/pull/206)).
+* **Fixed:** E2E tests fail in the CI with warm cache (props [@cadic](https://github.com/cadic), [@iamdharmesh](https://github.com/iamdharmesh) via [#212](https://github.com/10up/autoshare-for-twitter/pull/212)).
+* **Security:** Bump `decode-uri-component` from 0.2.0 to 0.2.2 (props [@dependabot](https://github.com/apps/dependabot), [@iamdharmesh](https://github.com/iamdharmesh) via [#208](https://github.com/10up/autoshare-for-twitter/pull/208)).
+* **Security:** Bump `simple-git` from 3.14.1 to 3.15.1 (props [@dependabot](https://github.com/apps/dependabot), [@iamdharmesh](https://github.com/iamdharmesh) via [#210](https://github.com/10up/autoshare-for-twitter/pull/210)).
+
+= 1.2.1 - 2022-12-07 =
**Note that this release bumps the WordPress minimum from 5.3 to 5.7 and PHP minimum from 7.2 to 7.4.**
* **Added:** "PR Automator" GitHub Action (props [@iamdharmesh](https://github.com/iamdharmesh), [@Sidsector9](https://github.com/Sidsector9), [@jeffpaul](https://github.com/jeffpaul) via [#194](https://github.com/10up/autoshare-for-twitter/pull/194), [#196](https://github.com/10up/autoshare-for-twitter/pull/196)).
diff --git a/src/js/AutoshareForTwitterPostStatusInfo.js b/src/js/AutoshareForTwitterPostStatusInfo.js
index d29d4109..44ddd2a6 100644
--- a/src/js/AutoshareForTwitterPostStatusInfo.js
+++ b/src/js/AutoshareForTwitterPostStatusInfo.js
@@ -1,25 +1,100 @@
import { __ } from '@wordpress/i18n';
import { compose } from '@wordpress/compose';
-import { withSelect } from '@wordpress/data';
-import { Dashicon } from '@wordpress/components';
+import { useState } from '@wordpress/element';
+import { withSelect, useSelect } from '@wordpress/data';
+import { Button, ToggleControl, CardDivider, Icon, ExternalLink } from '@wordpress/components';
+import { TweetTextField } from './components/TweetTextField';
+import { useHasFeaturedImage, useAllowTweetImage, useSaveTwitterData } from './hooks';
+
+import { getIconByStatus } from './utils';
+
+export function AutoshareForTwitterPostStatusInfo() {
+ const hasFeaturedImage = useHasFeaturedImage();
+ const [ allowTweetImage, setAllowTweetImage ] = useAllowTweetImage();
+ const [ reTweet, setReTweet ] = useState( false );
+ const [ tweetNow, setTweetNow ] = useState( false );
+ const { messages } = useSelect( ( select ) => {
+ return {
+ messages: select( 'core/editor' ).getCurrentPostAttribute( 'autoshare_for_twitter_status' ),
+ };
+ } );
+
+ const [ statusMessages, setStatusMessages ] = useState( messages );
+
+ useSaveTwitterData();
+
+ const reTweetHandler = async () => {
+ setReTweet( true );
+
+ const postId = await wp.data.select( 'core/editor' ).getCurrentPostId();
+ const body = new FormData();
+
+ body.append( 'action', adminAutoshareForTwitter.retweetAction );
+ body.append( 'nonce', adminAutoshareForTwitter.nonce );
+ body.append( 'post_id', postId );
+
+ const apiResponse = await fetch( ajaxurl, {
+ method: 'POST',
+ body,
+ } );
+
+ const { data } = await apiResponse.json();
+
+ setStatusMessages( data );
+ setReTweet( false );
+ };
+
+ if ( statusMessages && ! statusMessages.message.length ) {
+ return null;
+ }
+
+ const chevronUp = } />;
+ const chevronDown = } />;
-export function AutoshareForTwitterPostStatusInfo( { statusMessage } ) {
return (
- statusMessage.message && (
-
- )
+
+ { statusMessages.message.map( ( statusMessage, index ) => {
+ const TweetIcon = getIconByStatus( statusMessage.status );
+
+ return (
+
+ { TweetIcon }{ statusMessage.url ? { statusMessage.message } : statusMessage.message }
+
+ );
+ } ) }
+
+
setTweetNow( ! tweetNow ) }
+ iconPosition="right"
+ icon={ tweetNow ? chevronUp : chevronDown }
+ />
+ { tweetNow && (
+ <>
+ { hasFeaturedImage && (
+ {
+ setAllowTweetImage( ! allowTweetImage );
+ } }
+ className="autoshare-for-twitter-toggle-control"
+ />
+ ) }
+
+ {
+ reTweetHandler();
+ } }
+ />
+ >
+ ) }
+
);
}
diff --git a/src/js/AutoshareForTwitterPrePublishPanel.js b/src/js/AutoshareForTwitterPrePublishPanel.js
index 13c35312..ea047e55 100644
--- a/src/js/AutoshareForTwitterPrePublishPanel.js
+++ b/src/js/AutoshareForTwitterPrePublishPanel.js
@@ -1,183 +1,79 @@
-import apiFetch from '@wordpress/api-fetch';
-import { Button, TextareaControl, ToggleControl } from '@wordpress/components';
-import { withDispatch, withSelect } from '@wordpress/data';
-import { compose } from '@wordpress/compose';
-import { Component } from '@wordpress/element';
-import { debounce } from 'lodash';
-import { enableAutoshareKey, errorText, restUrl, siteUrl, tweetBodyKey } from 'admin-autoshare-for-twitter';
+import { Button, ToggleControl, ExternalLink, CardDivider } from '@wordpress/components';
+import { select } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
-
-import { STORE } from './store';
-
-class AutoshareForTwitterPrePublishPanel extends Component {
- constructor( props ) {
- super( props );
-
- // Although these values are delivered as props, we copy them into state so that we can check for changes
- // and save data when they update.
- this.state = { autoshareEnabled: null, tweetText: null };
-
- this.saveData = debounce( this.saveData.bind( this ), 250 );
- }
-
- componentDidMount() {
- const { autoshareEnabled, tweetText } = this.props;
-
- this.setState( { autoshareEnabled, tweetText } );
- }
-
- componentDidUpdate() {
- const { autoshareEnabled, tweetText } = this.props;
-
- // Update if either of these values has changed in the data store.
- if ( autoshareEnabled !== this.state.autoshareEnabled || tweetText !== this.state.tweetText ) {
- this.setState( { autoshareEnabled, tweetText }, () => {
- this.props.setSaving( true );
- this.saveData();
- } );
- }
- }
-
- async saveData() {
- const { autoshareEnabled, setErrorMessage, setSaving, tweetText } = this.props;
-
- const body = {};
- body[ enableAutoshareKey ] = autoshareEnabled;
- body[ tweetBodyKey ] = tweetText;
-
- try {
- const response = await apiFetch( {
- url: restUrl,
- data: body,
- method: 'POST',
- parse: false, // We'll check the response for errors.
- } );
-
- if ( ! response.ok ) {
- throw response;
- }
-
- await response.json();
-
- setErrorMessage( '' );
- setSaving( false );
- } catch ( e ) {
- setErrorMessage(
- e.statusText ? `${ errorText } ${ e.status }: ${ e.statusText }` : __( 'An error occurred.', 'autoshare-for-twitter' ),
- );
-
- setSaving( false );
- }
- }
-
- render() {
- const {
- autoshareEnabled,
- errorMessage,
- overriding,
- permalinkLength,
- setAutoshareEnabled,
- setOverriding,
- setTweetText,
- tweetText,
- } = this.props;
-
- const overrideLengthClass = () => {
- if ( 280 <= permalinkLength + tweetText.length ) {
- return 'over-limit';
- }
-
- if ( 240 <= permalinkLength + tweetText.length ) {
- return 'near-limit';
- }
-
- return null;
- };
-
- return (
- <>
+import { TweetTextField } from './components/TweetTextField';
+import {
+ useTwitterAutoshareEnabled,
+ useTwitterTextOverriding,
+ useAllowTweetImage,
+ useTwitterAutoshareErrorMessage,
+ useSaveTwitterData,
+ useHasFeaturedImage,
+} from './hooks';
+import { getIconByStatus } from './utils';
+
+export default function AutoshareForTwitterPrePublishPanel() {
+ const [ autoshareEnabled, setAutoshareEnabled ] = useTwitterAutoshareEnabled();
+ const [ overriding, setOverriding ] = useTwitterTextOverriding();
+ const [ allowTweetImage, setAllowTweetImage ] = useAllowTweetImage();
+ const [ errorMessage ] = useTwitterAutoshareErrorMessage();
+ const hasFeaturedImage = useHasFeaturedImage();
+
+ const messages = select( 'core/editor' ).getCurrentPostAttribute( 'autoshare_for_twitter_status' );
+ useSaveTwitterData();
+
+ return (
+ <>
+ { messages && !!messages.message.length && (
+ { messages.message.map( ( statusMessage, index ) => {
+ const TweetIcon = getIconByStatus( statusMessage.status );
+
+ return (
+
+ { TweetIcon }{ statusMessage.url ? { statusMessage.message } : statusMessage.message }
+
+ );
+ } ) }
+
+
) }
+ {
+ setAutoshareEnabled( checked );
+ } }
+ className="autoshare-for-twitter-toggle-control"
+ />
+
+ { autoshareEnabled && hasFeaturedImage && (
{
- setAutoshareEnabled( checked );
+ label={ __( 'Use featured image in Tweet', 'autoshare-for-twitter' ) }
+ checked={ allowTweetImage }
+ onChange={ () => {
+ setAllowTweetImage( ! allowTweetImage );
} }
className="autoshare-for-twitter-toggle-control"
/>
-
- { autoshareEnabled && (
-
- { overriding && (
- {
- setTweetText( value );
- } }
- label={
-
- { __( 'Custom message:', 'autoshare-for-twitter' ) }
-
-
- }
- />
- ) }
-
- {
- setOverriding( ! overriding );
- } }
- >
- { overriding ? __( 'Hide', 'autoshare-for-twitter' ) : __( 'Edit', 'autoshare-for-twitter' ) }
-
-
- ) }
-
- { errorMessage }
- >
- );
- }
+ ) }
+
+ { autoshareEnabled && (
+
+ { overriding && (
+
+ ) }
+
+ {
+ setOverriding( ! overriding );
+ } }
+ >
+ { overriding ? __( 'Hide', 'autoshare-for-twitter' ) : __( 'Edit', 'autoshare-for-twitter' ) }
+
+
+ ) }
+ { errorMessage }
+ >
+ );
}
-
-const permalinkLength = ( select ) => {
- const permalink = select( 'core/editor' ).getPermalink();
- if ( permalink ) {
- return permalink.length;
- }
-
- const title = select( 'core/editor' ).getEditedPostAttribute( 'title' );
- if ( title && 'rendered' in title ) {
- return ( siteUrl + title.rendered ).length;
- }
-
- return siteUrl.length;
-};
-
-export default compose(
- withSelect( ( select ) => ( {
- autoshareEnabled: select( STORE ).getAutoshareEnabled(),
- errorMessage: select( STORE ).getErrorMessage(),
- overriding: select( STORE ).getOverriding(),
- permalinkLength: permalinkLength( select ),
- saving: select( STORE ).getSaving(),
- tweetText: select( STORE ).getTweetText(),
- } ) ),
- withDispatch( ( dispatch ) => ( {
- setAutoshareEnabled: dispatch( STORE ).setAutoshareEnabled,
- setErrorMessage: dispatch( STORE ).setErrorMessage,
- setOverriding: dispatch( STORE ).setOverriding,
- setSaving: ( saving ) => {
- dispatch( STORE ).setSaving( saving );
-
- if ( saving ) {
- dispatch( 'core/editor' ).lockPostSaving();
- } else {
- dispatch( 'core/editor' ).unlockPostSaving();
- }
- },
- setTweetText: dispatch( STORE ).setTweetText,
- } ) ),
-)( AutoshareForTwitterPrePublishPanel );
diff --git a/src/js/components/TweetTextField.js b/src/js/components/TweetTextField.js
new file mode 100644
index 00000000..3bf2dc70
--- /dev/null
+++ b/src/js/components/TweetTextField.js
@@ -0,0 +1,75 @@
+import { TextareaControl, Tooltip } from '@wordpress/components';
+import { useSelect } from '@wordpress/data';
+import { siteUrl } from 'admin-autoshare-for-twitter';
+import { __, sprintf } from '@wordpress/i18n';
+import { useTweetText } from '../hooks';
+
+export function TweetTextField() {
+ const getPermalinkLength = ( select ) => {
+ const permalink = select( 'core/editor' ).getPermalink();
+
+ if ( permalink ) {
+ return permalink.length;
+ }
+
+ const title = select( 'core/editor' ).getEditedPostAttribute( 'title' );
+
+ if ( title && 'rendered' in title ) {
+ return ( siteUrl + title.rendered ).length;
+ }
+
+ return siteUrl.length;
+ };
+
+ const { permalinkLength, maxLength } = useSelect( ( select ) => {
+ return {
+ permalinkLength: getPermalinkLength( select ),
+ maxLength: ( 275 - getPermalinkLength( select ) ),
+ };
+ } );
+
+ const getTweetLength = () => {
+ // +5 because of the space between body and URL and the ellipsis.
+ const length = permalinkLength + tweetText.length + 5;
+ if ( 280 <= length ) {
+ /* translators: %d is tweet message character count */
+ return { tweetLength: sprintf( __( '%d - Too Long!', 'autoshare-for-twitter' ), length ), overrideLengthClass: 'over-limit' };
+ }
+
+ if ( 240 <= length ) {
+ /* translators: %d is tweet message character count */
+ return { tweetLength: sprintf( __( '%d - Getting Long!', 'autoshare-for-twitter' ), length ), overrideLengthClass: 'near-limit' };
+ }
+
+ return { tweetLength: `${ length }`, overrideLengthClass: '' };
+ };
+
+ const [ tweetText, setTweetText ] = useTweetText();
+ const { tweetLength, overrideLengthClass } = getTweetLength();
+
+ const CounterTooltip = () => (
+
+ { tweetLength }
+
+ );
+
+ return (
+ {
+ setTweetText( value );
+ } }
+ className="autoshare-for-twitter-tweet-text"
+ maxLength={ maxLength }
+ label={
+
+ { __( 'Custom message:', 'autoshare-for-twitter' ) }
+
+
+ }
+ />
+ );
+}
diff --git a/src/js/hooks/index.js b/src/js/hooks/index.js
new file mode 100644
index 00000000..93064a19
--- /dev/null
+++ b/src/js/hooks/index.js
@@ -0,0 +1,152 @@
+import { useSelect, useDispatch, dispatch } from '@wordpress/data';
+import { useEffect, useCallback } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import apiFetch from '@wordpress/api-fetch';
+import { enableAutoshareKey, errorText, restUrl, tweetBodyKey, allowTweetImageKey } from 'admin-autoshare-for-twitter';
+import { debounce } from 'lodash';
+import { STORE } from '../store';
+
+export function useTweetText() {
+ const { tweetText } = useSelect( ( select ) => {
+ return {
+ tweetText: select( STORE ).getTweetText(),
+ };
+ } );
+
+ const { setTweetText } = useDispatch( STORE );
+
+ return [ tweetText, setTweetText ];
+}
+
+export function useTwitterAutoshareEnabled() {
+ const { autoshareEnabled } = useSelect( ( select ) => {
+ return {
+ autoshareEnabled: select( STORE ).getAutoshareEnabled(),
+ };
+ } );
+
+ const { setAutoshareEnabled } = useDispatch( STORE );
+
+ return [ autoshareEnabled, setAutoshareEnabled ];
+}
+
+export function useTwitterTextOverriding() {
+ const { overriding } = useSelect( ( select ) => {
+ return {
+ overriding: select( STORE ).getOverriding(),
+ };
+ } );
+
+ const { setOverriding } = useDispatch( STORE );
+
+ return [ overriding, setOverriding ];
+}
+
+export function useSavingTweetData() {
+ function setSaving( saving ) {
+ dispatch( STORE ).setSaving( saving );
+
+ if ( saving ) {
+ dispatch( 'core/editor' ).lockPostSaving();
+ } else {
+ dispatch( 'core/editor' ).unlockPostSaving();
+ }
+ }
+
+ const { saving } = useSelect( ( select ) => {
+ return {
+ saving: select( STORE ).getSaving(),
+ };
+ } );
+
+ return [ saving, setSaving ];
+}
+
+export function useAllowTweetImage() {
+ const { allowTweetImage } = useSelect( ( select ) => {
+ return {
+ allowTweetImage: select( STORE ).getAllowTweetImage(),
+ };
+ } );
+
+ const { setAllowTweetImage } = useDispatch( STORE );
+
+ return [ allowTweetImage, setAllowTweetImage ];
+}
+
+export function useTwitterAutoshareErrorMessage() {
+ const { errorMessage } = useSelect( ( select ) => {
+ return {
+ errorMessage: select( STORE ).getErrorMessage(),
+ };
+ } );
+
+ const { setErrorMessage } = useDispatch( STORE );
+
+ return [ errorMessage, setErrorMessage ];
+}
+
+export function useHasFeaturedImage() {
+ const { imageId } = useSelect( ( select ) => {
+ return {
+ imageId: select( 'core/editor' ).getEditedPostAttribute( 'featured_media' ),
+ };
+ } );
+
+ const hasFeaturedImage = imageId > 0;
+
+ return hasFeaturedImage;
+}
+
+export function useSaveTwitterData() {
+ const [ autoshareEnabled ] = useTwitterAutoshareEnabled();
+ const [ allowTweetImage ] = useAllowTweetImage();
+ const [ tweetText ] = useTweetText();
+ const [ , setErrorMessage ] = useTwitterAutoshareErrorMessage();
+ const [ , setSaving ] = useSavingTweetData();
+
+ const { hasFeaturedImage } = useSelect( ( select ) => {
+ const imageId = select( 'core/editor' ).getEditedPostAttribute( 'featured_media' );
+
+ return {
+ hasFeaturedImage: imageId > 0,
+ };
+ } );
+
+ async function saveData( autoshareEnabledArg, tweetTextArg, allowTweetImageArg ) {
+ const body = {};
+ body[ enableAutoshareKey ] = autoshareEnabledArg;
+ body[ tweetBodyKey ] = tweetTextArg;
+ body[ allowTweetImageKey ] = allowTweetImageArg;
+
+ try {
+ const response = await apiFetch( {
+ url: restUrl,
+ data: body,
+ method: 'POST',
+ parse: false, // We'll check the response for errors.
+ } );
+
+ if ( ! response.ok ) {
+ throw response;
+ }
+
+ await response.json();
+
+ setErrorMessage( '' );
+ setSaving( false );
+ } catch ( e ) {
+ setErrorMessage(
+ e.statusText ? `${ errorText } ${ e.status }: ${ e.statusText }` : __( 'An error occurred.', 'autoshare-for-twitter' ),
+ );
+
+ setSaving( false );
+ }
+ }
+
+ const saveDataDebounced = useCallback( debounce( saveData, 250 ), [] );
+
+ useEffect( () => {
+ saveDataDebounced( autoshareEnabled, tweetText, allowTweetImage );
+ }, [ autoshareEnabled, tweetText, hasFeaturedImage, allowTweetImage ] );
+}
diff --git a/src/js/index.js b/src/js/index.js
index 2cfa40ec..b4addd89 100644
--- a/src/js/index.js
+++ b/src/js/index.js
@@ -6,14 +6,12 @@ import { Icon } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { createAutoshareStore, STORE } from './store';
+import { getIconByStatus } from './utils';
import AutoshareForTwitterPrePublishPanel from './AutoshareForTwitterPrePublishPanel';
import AutoshareForTwitterPostStatusInfo from './AutoshareForTwitterPostStatusInfo';
import EnabledIcon from '../../assets/images/twitter_enabled.svg';
import DisabledIcon from '../../assets/images/twitter_disabled.svg';
-import FailedIcon from '../../assets/images/twitter_failed.svg';
-import TweetedIcon from '../../assets/images/twitter_tweeted.svg';
-import DefaultIcon from '../../assets/images/twitter_default.svg';
createAutoshareStore();
@@ -105,30 +103,16 @@ class AutoshareForTwitterEditorPanelPlugin extends Component {
render() {
const postStatus = select( 'core/editor' ).getCurrentPostAttribute( 'status' );
if ( 'publish' === postStatus ) {
- const tweetStatus = select( 'core/editor' ).getCurrentPostAttribute( 'autoshare_for_twitter_status' );
- let StatusIcon = DefaultIcon;
- if ( tweetStatus && tweetStatus.status ) {
- if ( tweetStatus.status === 'published' ) {
- StatusIcon = TweetedIcon;
- } else if ( tweetStatus.status === 'error' ) {
- StatusIcon = FailedIcon;
- } else {
- StatusIcon = DefaultIcon;
- }
+ const tweetMeta = select( 'core/editor' ).getCurrentPostAttribute( 'autoshare_for_twitter_status' );
+ let tweetStatus = '';
+ if ( tweetMeta && tweetMeta.message && tweetMeta.message.length ) {
+ tweetStatus = tweetMeta.message[ tweetMeta.message.length - 1 ].status || '';
}
- const TweetStatusIcon = (
- }
- size={ 24 }
- />
- );
-
return (
diff --git a/src/js/store/actions.js b/src/js/store/actions.js
index 1084ef32..d0cb9cdc 100644
--- a/src/js/store/actions.js
+++ b/src/js/store/actions.js
@@ -5,6 +5,7 @@ import {
SET_SAVING,
SET_LOADED,
SET_OVERRIDING,
+ SET_ALLOW_TWEET_IMAGE,
} from './constants';
export const setAutoshareEnabled = ( autoshareEnabled ) => ( {
@@ -35,3 +36,8 @@ export const setTweetText = ( tweetText ) => ( {
type: SET_TWEET_TEXT,
tweetText,
} );
+
+export const setAllowTweetImage = ( allowTweetImage ) => ( {
+ type: SET_ALLOW_TWEET_IMAGE,
+ allowTweetImage,
+} );
diff --git a/src/js/store/constants.js b/src/js/store/constants.js
index 34fa28b2..abe66ee3 100644
--- a/src/js/store/constants.js
+++ b/src/js/store/constants.js
@@ -4,3 +4,4 @@ export const SET_LOADED = 'SET_LOADED';
export const SET_OVERRIDING = 'SET_OVERRIDING';
export const SET_SAVING = 'SET_SAVING';
export const SET_TWEET_TEXT = 'SET_TWEET_TEXT';
+export const SET_ALLOW_TWEET_IMAGE = 'SET_ALLOW_TWEET_IMAGE';
diff --git a/src/js/store/reducer.js b/src/js/store/reducer.js
index 877ef20b..25e808f9 100644
--- a/src/js/store/reducer.js
+++ b/src/js/store/reducer.js
@@ -1,4 +1,4 @@
-import { enabled } from 'admin-autoshare-for-twitter';
+import { enabled, allowTweetImage } from 'admin-autoshare-for-twitter';
import {
SET_AUTOSHARE_FOR_TWITTER_ENABLED,
@@ -7,6 +7,7 @@ import {
SET_SAVING,
SET_LOADED,
SET_OVERRIDING,
+ SET_ALLOW_TWEET_IMAGE,
} from './constants';
export const DEFAULT_STATE = {
@@ -16,6 +17,7 @@ export const DEFAULT_STATE = {
overriding: false,
overrideLength: 0,
tweetText: '',
+ allowTweetImage: ! ! allowTweetImage,
};
export default function reducer( state = DEFAULT_STATE, action ) {
@@ -59,5 +61,12 @@ export default function reducer( state = DEFAULT_STATE, action ) {
tweetText: action.tweetText,
};
}
+
+ case SET_ALLOW_TWEET_IMAGE: {
+ return {
+ ...state,
+ allowTweetImage: action.allowTweetImage,
+ };
+ }
}
}
diff --git a/src/js/store/selectors.js b/src/js/store/selectors.js
index ab59d6c1..d0268c94 100644
--- a/src/js/store/selectors.js
+++ b/src/js/store/selectors.js
@@ -7,3 +7,5 @@ export const getOverriding = ( state ) => state.overriding;
export const getSaving = ( state ) => state.saving;
export const getTweetText = ( state ) => state.tweetText;
+
+export const getAllowTweetImage = ( state ) => state.allowTweetImage;
diff --git a/src/js/utils.js b/src/js/utils.js
new file mode 100644
index 00000000..7308e6f3
--- /dev/null
+++ b/src/js/utils.js
@@ -0,0 +1,29 @@
+import { Icon } from '@wordpress/components';
+
+import FailedIcon from '../../assets/images/twitter_failed.svg';
+import TweetedIcon from '../../assets/images/twitter_tweeted.svg';
+import DefaultIcon from '../../assets/images/twitter_default.svg';
+
+export const getIconByStatus = ( tweetStatus ) => {
+ let StatusIcon = DefaultIcon;
+
+ if ( tweetStatus ) {
+ if ( tweetStatus === 'published' ) {
+ StatusIcon = TweetedIcon;
+ } else if ( tweetStatus === 'error' ) {
+ StatusIcon = FailedIcon;
+ } else {
+ StatusIcon = DefaultIcon;
+ }
+ }
+
+ const TweetStatusIcon = (
+ }
+ size={ 24 }
+ />
+ );
+
+ return TweetStatusIcon;
+};
diff --git a/tests/bin/set-core-version.js b/tests/bin/set-core-version.js
deleted file mode 100755
index b6a573ef..00000000
--- a/tests/bin/set-core-version.js
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env node
-
-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.1.6.1.zip' ] };
-
-const args = process.argv.slice( 2 );
-
-if ( args.length == 0 ) return;
-
-if ( args[ 0 ] == 'latest' ) return;
-
-config.core = args[ 0 ];
-
-try {
- fs.writeFileSync( path, JSON.stringify( config ) );
-} catch ( err ) {
- console.error( err );
-}
\ No newline at end of file
diff --git a/tests/bin/set-wp-config.js b/tests/bin/set-wp-config.js
new file mode 100755
index 00000000..9125a305
--- /dev/null
+++ b/tests/bin/set-wp-config.js
@@ -0,0 +1,46 @@
+#!/usr/bin/env node
+
+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.1.6.1.zip' ] };
+
+const args = {};
+process.argv
+ .slice(2, process.argv.length)
+ .forEach( arg => {
+ if (arg.slice(0,2) === '--') {
+ const param = arg.split('=');
+ const paramName = param[0].slice(2,param[0].length);
+ const paramValue = param.length > 1 ? param[1] : true;
+ args[paramName] = paramValue;
+ }
+ });
+
+if ( ! args.core && ! args.plugins ) {
+ return;
+}
+
+if ( 'latest' === args.core ) {
+ delete args.core;
+}
+
+if( Object.keys(args).length === 0 ) {
+ return;
+}
+
+if ( args.plugins ) {
+ args.plugins = args.plugins.split(',');
+}
+
+config = {
+ ...config,
+ ...args,
+}
+
+try {
+ fs.writeFileSync( path, JSON.stringify( config ) );
+} catch ( err ) {
+ console.error( err );
+}
\ No newline at end of file
diff --git a/tests/cypress/config.json b/tests/cypress/config.json
deleted file mode 100644
index f12cce6c..00000000
--- a/tests/cypress/config.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "fixturesFolder": "tests/cypress/fixtures",
- "integrationFolder": "tests/cypress/integration",
- "pluginsFile": "tests/cypress/plugins/index.js",
- "screenshotsFolder": "tests/cypress/screenshots",
- "videosFolder": "tests/cypress/videos",
- "downloadsFolder": "tests/cypress/downloads",
- "supportFile": "tests/cypress/support/index.js",
- "video": false
-}
diff --git a/tests/cypress/cypress.config.js b/tests/cypress/cypress.config.js
new file mode 100644
index 00000000..7076ab83
--- /dev/null
+++ b/tests/cypress/cypress.config.js
@@ -0,0 +1,38 @@
+const { defineConfig } = require('cypress');
+const { readConfig } = require('@wordpress/env/lib/config');
+
+module.exports = defineConfig({
+ fixturesFolder: 'tests/cypress/fixtures',
+ screenshotsFolder: 'tests/cypress/screenshots',
+ videosFolder: 'tests/cypress/videos',
+ downloadsFolder: 'tests/cypress/downloads',
+ video: false,
+ e2e: {
+ setupNodeEvents(on, config) {
+ return setBaseUrl(on, config);
+ },
+ specPattern: 'tests/cypress/e2e/**/*.test.{js,jsx,ts,tsx}',
+ supportFile: 'tests/cypress/support/e2e.js',
+ },
+});
+
+/**
+ * Set WP URL as baseUrl in Cypress config.
+ *
+ * @param {Function} on function that used to register listeners on various events.
+ * @param {object} config Cypress Config object.
+ * @returns config Updated Cypress Config object.
+ */
+const setBaseUrl = async (on, config) => {
+ const wpEnvConfig = await readConfig('wp-env');
+
+ if (wpEnvConfig) {
+ const port = wpEnvConfig.env.tests.port || null;
+
+ if (port) {
+ config.baseUrl = wpEnvConfig.env.tests.config.WP_SITEURL;
+ }
+ }
+
+ return config;
+};
\ No newline at end of file
diff --git a/tests/cypress/integration/admin.test.js b/tests/cypress/e2e/admin.test.js
similarity index 100%
rename from tests/cypress/integration/admin.test.js
rename to tests/cypress/e2e/admin.test.js
diff --git a/tests/cypress/integration/block-editor.test.js b/tests/cypress/e2e/block-editor.test.js
similarity index 77%
rename from tests/cypress/integration/block-editor.test.js
rename to tests/cypress/e2e/block-editor.test.js
index 3d81e8a4..7cf390dc 100644
--- a/tests/cypress/integration/block-editor.test.js
+++ b/tests/cypress/e2e/block-editor.test.js
@@ -1,3 +1,5 @@
+import { getRandomText } from "../support/functions";
+
describe('Test Autoshare for Twitter with Block Editor.', () => {
before(() => {
cy.login();
@@ -117,5 +119,31 @@ describe('Test Autoshare for Twitter with Block Editor.', () => {
cy.get('.autoshare-for-twitter-post-status').should('be.visible');
cy.get('.autoshare-for-twitter-post-status').contains('Tweeted on');
});
+
+ it('Tweet Now should work fine', () => {
+ // 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.get('[aria-disabled="false"].editor-post-publish-button').should('be.visible');
+ cy.get('.editor-post-publish-button').click();
+
+ // Post-publish.
+ cy.get('.autoshare-for-twitter-post-status').should('be.visible');
+ cy.get('.autoshare-for-twitter-post-status').contains('This post was not tweeted.');
+
+ cy.get('.editor-post-publish-panel button[aria-label="Close panel"]').click();
+ cy.openDocumentSettingsPanel('Autotweet');
+ cy.get('.autoshare-for-twitter-post-status button.autoshare-for-twitter-tweet-now').click();
+ cy.get('.autoshare-for-twitter-post-status .autoshare-for-twitter-tweet-text textarea').clear().type(`Random Tweet ${getRandomText(6)}`);
+ cy.get('.autoshare-for-twitter-post-status button.autoshare-for-twitter-re-tweet').click();
+ cy.get('.autoshare-for-twitter-log a').contains('Tweeted on');
+ });
});
});
diff --git a/tests/cypress/integration/classic-editor.test.js b/tests/cypress/e2e/classic-editor.test.js
similarity index 75%
rename from tests/cypress/integration/classic-editor.test.js
rename to tests/cypress/e2e/classic-editor.test.js
index 3b4e8d6b..da692a17 100644
--- a/tests/cypress/integration/classic-editor.test.js
+++ b/tests/cypress/e2e/classic-editor.test.js
@@ -1,3 +1,5 @@
+import { getRandomText } from "../support/functions";
+
describe('Test Autoshare for Twitter with Classic Editor.', () => {
before(() => {
cy.login();
@@ -87,5 +89,28 @@ describe('Test Autoshare for Twitter with Classic Editor.', () => {
cy.get('#autoshare_for_twitter_metabox').should('be.visible');
cy.get('#autoshare_for_twitter_metabox').contains('Tweeted on');
});
+
+ it('Tweet Now should work fine', () => {
+ // 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').click();
+
+ // Post-publish.
+ cy.get('#autoshare_for_twitter_metabox').should('be.visible');
+ cy.get('#autoshare_for_twitter_metabox').contains('This post was not tweeted');
+
+ cy.get('#autoshare_for_twitter_metabox button.tweet-now-button').contains('Tweet 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('Tweeted on');
+ });
});
-});
\ No newline at end of file
+});
diff --git a/tests/cypress/plugins/index.js b/tests/cypress/plugins/index.js
deleted file mode 100644
index 3ebdcd65..00000000
--- a/tests/cypress/plugins/index.js
+++ /dev/null
@@ -1,33 +0,0 @@
-///
-// ***********************************************************
-// This example plugins/index.js can be used to load plugins
-//
-// You can change the location of this file or turn off loading
-// the plugins file with the 'pluginsFile' configuration option.
-//
-// You can read more here:
-// https://on.cypress.io/plugins-guide
-// ***********************************************************
-
-// This function is called when a project is opened or re-opened (e.g. due to
-// the project's config changing)
-
-const { readConfig } = require( '@wordpress/env/lib/config' );
-
-/**
- * @type {Cypress.PluginConfig}
- */
-// eslint-disable-next-line no-unused-vars
-module.exports = async ( on, config ) => {
- wpEnvConfig = await readConfig( 'wp-env' );
-
- if ( wpEnvConfig ) {
- const port = wpEnvConfig.env.tests.port || null;
-
- if ( port ) {
- config.baseUrl = wpEnvConfig.env.tests.config.WP_SITEURL;
- }
- }
-
- return config;
-};
diff --git a/tests/cypress/support/commands.js b/tests/cypress/support/commands.js
index 329f4215..8eee9729 100644
--- a/tests/cypress/support/commands.js
+++ b/tests/cypress/support/commands.js
@@ -62,7 +62,7 @@ Cypress.Commands.add( 'enableCheckbox', ( checkboxSelector, defaultBehavior, che
}
cy.intercept('**/autoshare/v1/post-autoshare-for-twitter-meta/*').as('enableCheckbox');
if (true === check) {
- cy.get(checkboxSelector).check();
+ cy.get(checkboxSelector).check({force: true});
if(defaultBehavior !== check){
cy.wait('@enableCheckbox').then(response => {
expect(response.response?.body?.enabled).to.equal(check);
@@ -70,7 +70,7 @@ Cypress.Commands.add( 'enableCheckbox', ( checkboxSelector, defaultBehavior, che
}
cy.get(checkboxSelector).should('be.checked');
} else {
- cy.get(checkboxSelector).uncheck();
+ cy.get(checkboxSelector).uncheck({force: true});
if(defaultBehavior !== check){
cy.wait('@enableCheckbox').then(response => {
expect(response.response?.body?.enabled).to.equal(check);
diff --git a/tests/cypress/support/index.js b/tests/cypress/support/e2e.js
similarity index 100%
rename from tests/cypress/support/index.js
rename to tests/cypress/support/e2e.js
diff --git a/tests/phpunit/integration/TestPostMeta.php b/tests/phpunit/integration/TestPostMeta.php
index 39d922f0..b669f7fc 100644
--- a/tests/phpunit/integration/TestPostMeta.php
+++ b/tests/phpunit/integration/TestPostMeta.php
@@ -38,15 +38,8 @@ class TestPostMeta extends WP_UnitTestCase {
public function test_setup_hooks() {
$this->assertTrue(
check_method_exists(
- 'post_submitbox_misc_actions',
- 'TenUp\AutoshareForTwitter\Core\Post_Meta\tweet_submitbox_callback'
- )
- );
-
- $this->assertTrue(
- check_method_exists(
- 'autoshare_for_twitter_metabox',
- 'TenUp\AutoshareForTwitter\Core\Post_Meta\render_tweet_submitbox'
+ 'add_meta_boxes',
+ 'TenUp\AutoshareForTwitter\Core\Post_Meta\autoshare_for_twitter_metabox'
)
);
@@ -64,7 +57,7 @@ public function test_setup_hooks() {
public function test_get_tweet_status_message() {
$this->assertEquals(
[
- 'message' => '',
+ 'message' => array(),
],
get_tweet_status_message( -1 )
);
@@ -85,9 +78,13 @@ public function test_get_tweet_status_message() {
add_filter( 'autoshare_for_twitter_meta', $published_filter, 10, 3 );
$this->assertEquals(
[
- 'message' => 'Tweeted on 2017-01-01 @ 12:00AM',
- 'url' => 'https://twitter.com//status/444',
- 'status' => 'published',
+ 'message' => [
+ [
+ 'message' => 'Tweeted on 2017-01-01 @ 12:00AM',
+ 'url' => 'https://twitter.com//status/444',
+ 'status' => 'published',
+ ],
+ ],
],
get_tweet_status_message( $post )
);
@@ -95,13 +92,14 @@ public function test_get_tweet_status_message() {
$twitter_status = get_autoshare_for_twitter_meta( $post, TWITTER_STATUS_KEY );
$this->assertEquals(
sprintf(
- '%s %s (View )',
+ '',
esc_html__( 'Tweeted on', 'autoshare-for-twitter' ),
esc_html( date_from_twitter( $twitter_status['created_at'] ) ),
esc_url( link_from_twitter( $twitter_status['twitter_id'] ) )
),
markup_published( $twitter_status )
);
+
remove_filter( 'autoshare_for_twitter_meta', $published_filter );
$failed_filter = function( $data, $id, $key ) use ( $post ) {
@@ -115,10 +113,16 @@ public function test_get_tweet_status_message() {
return $data;
};
add_filter( 'autoshare_for_twitter_meta', $failed_filter, 10, 3 );
+
+ $noo = get_tweet_status_message( $post );
$this->assertEquals(
[
- 'message' => 'Failed to tweet: There was an error.',
- 'status' => 'error',
+ 'message' => [
+ [
+ 'message' => 'Failed to tweet: There was an error.',
+ 'status' => 'error',
+ ],
+ ],
],
get_tweet_status_message( $post )
);
@@ -126,7 +130,7 @@ public function test_get_tweet_status_message() {
$twitter_status = get_autoshare_for_twitter_meta( $post, TWITTER_STATUS_KEY );
$this->assertEquals(
sprintf(
- '%s%s ',
+ '',
esc_html__( 'Failed to tweet', 'autoshare-for-twitter' ),
esc_html( $twitter_status['message'] )
),
@@ -147,14 +151,18 @@ public function test_get_tweet_status_message() {
add_filter( 'autoshare_for_twitter_meta', $unknown_filter, 10, 3 );
$this->assertEquals(
[
- 'message' => 'There was an error.',
- 'status' => 'unknown',
+ 'message' => [
+ [
+ 'message' => 'There was an error.',
+ 'status' => 'unknown',
+ ],
+ ],
],
get_tweet_status_message( $post )
);
// Make sure the rendered markup is as expected in post metabox.
$twitter_status = get_autoshare_for_twitter_meta( $post, TWITTER_STATUS_KEY );
- $this->assertEquals( $twitter_status['message'], markup_unknown( $twitter_status ) );
+ $this->assertEquals( '', markup_unknown( $twitter_status ) );
remove_filter( 'autoshare_for_twitter_meta', $unknown_filter );
$other_filter = function( $data, $id, $key ) use ( $post ) {
@@ -169,8 +177,12 @@ public function test_get_tweet_status_message() {
add_filter( 'autoshare_for_twitter_meta', $other_filter, 10, 3 );
$this->assertEquals(
[
- 'message' => 'This post was not tweeted.',
- 'status' => 'other',
+ 'message' => [
+ [
+ 'message' => 'This post was not tweeted.',
+ 'status' => 'other',
+ ],
+ ],
],
get_tweet_status_message( $post )
);
diff --git a/tests/phpunit/integration/TestRest.php b/tests/phpunit/integration/TestRest.php
index dd3d1adb..085db161 100644
--- a/tests/phpunit/integration/TestRest.php
+++ b/tests/phpunit/integration/TestRest.php
@@ -116,9 +116,10 @@ public function test_update_post_autoshare_for_twitter_meta() {
$response = update_post_autoshare_for_twitter_meta( $this->get_valid_request() );
$this->assertEquals(
[
- 'enabled' => true,
- 'message' => 'Autoshare enabled.',
- 'override' => true,
+ 'enabled' => true,
+ 'message' => 'Autoshare enabled.',
+ 'override' => true,
+ 'allowImage' => true,
],
$response->get_data()
);
diff --git a/tests/phpunit/integration/TestUtils.php b/tests/phpunit/integration/TestUtils.php
index b3ba5935..5c12175a 100644
--- a/tests/phpunit/integration/TestUtils.php
+++ b/tests/phpunit/integration/TestUtils.php
@@ -15,9 +15,11 @@
use function TenUp\AutoshareForTwitter\Utils\update_autoshare_for_twitter_meta;
use function TenUp\AutoshareForTwitter\Utils\delete_autoshare_for_twitter_meta;
use function TenUp\AutoshareForTwitter\Utils\autoshare_enabled;
+use function TenUp\AutoshareForTwitter\Utils\tweet_image_allowed;
use function TenUp\AutoshareForTwitter\Utils\get_available_post_types;
use function TenUp\AutoshareForTwitter\Utils\get_autoshare_for_twitter_settings;
use const TenUp\AutoshareForTwitter\Core\Post_Meta\META_PREFIX;
+use const \TenUp\AutoshareForTwitter\Core\Post_Meta\TWEET_ALLOW_IMAGE;
/**
* TestUtils class.
@@ -107,6 +109,29 @@ public function test_autoshare_enabled() {
$this->assertFalse( autoshare_enabled( $other_post ) );
}
+ /**
+ * Tests the tweet_image_allowed function.
+ *
+ * @since 1.3.0
+ */
+ public function test_tweet_image_allowed() {
+ $post_id = $this->factory->post->create();
+
+ update_autoshare_for_twitter_meta( $post_id, TWEET_ALLOW_IMAGE, 'yes' );
+ $this->assertTrue( tweet_image_allowed( $post_id ) );
+
+ update_autoshare_for_twitter_meta( $post_id, TWEET_ALLOW_IMAGE, 'no' );
+ $this->assertFalse( tweet_image_allowed( $post_id ) );
+
+ delete_autoshare_for_twitter_meta( $post_id, TWEET_ALLOW_IMAGE );
+ $is_allowed = (bool) get_autoshare_for_twitter_settings( 'enable_upload' );
+ $this->assertSame( $is_allowed, tweet_image_allowed( $post_id ) );
+
+ add_filter( 'autoshare_for_twitter_tweet_image_allowed', '__return_false' );
+ $this->assertFalse( tweet_image_allowed( $post_id ) );
+ remove_filter( 'autoshare_for_twitter_tweet_image_allowed', '__return_false' );
+ }
+
/**
* Tests the get_autoshare_for_twitter_settings function.
*