diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml
new file mode 100644
index 00000000..e8c73690
--- /dev/null
+++ b/.github/workflows/run_tests.yml
@@ -0,0 +1,105 @@
+name: CI
+
+on:
+ pull_request:
+ branches:
+ - develop
+ - master
+
+permissions:
+ contents: read
+
+jobs:
+ run_tests:
+ name: Run Unit & Acceptance Tests
+ runs-on: ubuntu-latest
+ services:
+ mysql:
+ image: mysql:8
+ env:
+ MYSQL_ROOT_PASSWORD: wordpress
+ MYSQL_USER: wordpress
+ MYSQL_PASSWORD: wordpress
+ MYSQL_DATABASE: wordpress_test
+ ports:
+ - 3306:3306
+ options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Set up PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 8.1
+ coverage: none
+ tools: wp-cli
+
+ - name: Install Composer dependencies
+ run: composer install
+
+ - name: Setup Node
+ uses: actions/setup-node@v2
+ with:
+ node-version: '17'
+
+ - name: Prepare testing environment
+ run: |
+ # Move the plugin files to the separate folder
+ mkdir ssp && mv `ls -A | grep -v ssp` ssp
+
+ # Download WordPress
+ wp core download --allow-root
+
+ # Set up .env
+ echo "TEST_WP_ROOT=$(pwd)" > .env.testing
+ echo "TEST_DB_HOST=127.0.0.1" >> .env.testing
+ echo "TEST_DB_NAME=wordpress_test" >> .env.testing
+ echo "TEST_DB_USER=wordpress" >> .env.testing
+ echo "TEST_DB_PASSWORD=wordpress" >> .env.testing
+ echo "TEST_DOMAIN=localhost" >> .env.testing
+ mv .env.testing ssp/
+
+ # Move the plugin to the plugins folder
+ mv ssp ./wp-content/plugins/seriously-simple-podcasting
+ cd wp-content/plugins/seriously-simple-podcasting
+ npm install -g grunt-cli
+ npm install
+ npm rebuild node-sass
+ grunt uglify && grunt cssmin && npm run build
+
+ - name: Run Unit tests
+ run: cd wp-content/plugins/seriously-simple-podcasting && vendor/bin/codecept run wpunit
+
+ - name: Run Acceptance tests
+ run: |
+ wp config create --dbname=wordpress_test --dbuser=wordpress --dbpass=wordpress --dbhost=127.0.0.1 --dbprefix=wsy_ --allow-root
+ wp config set WP_SITEURL http://localhost:8000 --type=constant --allow-root
+ wp config set WP_HOME http://localhost:8000 --type=constant --allow-root
+ nohup php -S localhost:8000 &
+ cd wp-content/plugins/seriously-simple-podcasting
+ echo "SITE_URL=http://localhost:8000" >> .env.testing
+ echo "SITE_USER=autotest" >> .env.testing
+ echo "SITE_USER_PASS=password" >> .env.testing
+ echo "PODCAST_GUID=dd94465b-580a-501c-a892-caf224d23d7a" >> .env.testing
+ sudo apt-get update -qq
+ sudo env DEBIAN_FRONTEND=noninteractive apt-get install -qq mysql-client default-libmysqlclient-dev
+ gzip -d tests/seed.sql.gz && wp db import tests/seed.sql --allow-root
+ wp core update-db --allow-root
+ wp theme activate twentytwentyfour --allow-root
+ wp plugin install classic-editor --allow-root
+ vendor/bin/codecept run acceptance --steps
+
+ - name: Upload codeception output on failure
+ if: failure()
+ uses: actions/upload-artifact@v4
+ with:
+ name: acceptance-tests
+ path: wp-content/plugins/seriously-simple-podcasting/tests/_output
+
+ - name: Upload PHP server logs on failure
+ if: failure()
+ uses: actions/upload-artifact@v4
+ with:
+ name: acceptance-tests
+ path: nohup.out
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9caf71f3..c9b187e4 100755
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -46,7 +46,6 @@ unit_tests:
# Prepare testing environment file
- touch .env.testing
- - echo "TEST_WP_ROOT=$(pwd)"
- echo "TEST_WP_ROOT=$(pwd)" >> .env.testing
- echo "TEST_DB_HOST=db" >> .env.testing
- echo "TEST_DB_NAME=$MYSQL_DATABASE" >> .env.testing
@@ -151,6 +150,7 @@ acceptance_tests:
- echo "SITE_URL=$SSH_USER" >> .env.testing
- echo "SITE_USER=$SITE_USER" >> .env.testing
- echo "SITE_USER_PASS=$SITE_USER_PASS" >> .env.testing
+ - echo "PODCAST_GUID=115e423a-72d2-531e-9d3c-ece7dd4b74fe" >> .env.testing
# Run Acceptance tests
- vendor/bin/codecept run acceptance --steps
diff --git a/assets/admin/css/admin.css b/assets/admin/css/admin.css
index e2597b1f..ca9cbd7c 100644
--- a/assets/admin/css/admin.css
+++ b/assets/admin/css/admin.css
@@ -204,6 +204,16 @@ textarea#episode_embed_code {
font-size: 16px;
top: -3px; }
+#podmotor_account_api_token {
+ width: 100%;
+ min-width: 100%;
+ display: block;
+ margin-bottom: 8px; }
+
+.ssp-settings-integrations table label {
+ margin-top: 10px;
+ display: block; }
+
.ssp-settings:not(.ssp-settings-extensions, .ssp-settings-integrations) {
background: #FFFFFF;
margin-top: 28px;
@@ -219,8 +229,6 @@ textarea#episode_embed_code {
.ssp-settings table input.regular-text {
max-width: 90%;
background: #F1F5F9; }
- .ssp-settings .validate-api-credentials-message {
- margin-left: 30px; }
.ssp-settings .loader {
position: relative; }
.ssp-settings .loader:after {
@@ -243,6 +251,32 @@ textarea#episode_embed_code {
.ssp-settings .ssp-sync-msg.success .sync-overview {
color: #4caf50; }
+.ssp-main-settings .error {
+ color: #DF4E4F; }
+
+.ssp-main-settings .hidden {
+ display: none; }
+
+.ssp-main-settings .disconnect-castos {
+ margin-right: 8px;
+ vertical-align: middle; }
+
+.ssp-main-settings.tab-castos-hosting .loader {
+ position: relative; }
+ .ssp-main-settings.tab-castos-hosting .loader:after {
+ content: '';
+ display: block;
+ background: url(../img/loader2.svg) no-repeat;
+ position: absolute;
+ right: -50px;
+ top: -9px;
+ background-size: contain;
+ width: 44px;
+ height: 44px; }
+
+.connect-castos-message {
+ margin-left: 20px; }
+
.ssp-sync-podcast {
display: flex;
justify-content: space-between;
@@ -467,6 +501,8 @@ textarea#episode_embed_code {
right: 350px; }
.ssp-onboarding-step-4 .ssp-onboarding__steps::after {
right: 180px; }
+ .ssp-onboarding-step-4 .ssp-onboarding__settings-body {
+ padding: 24px 24px 36px; }
.ssp-onboarding-step-4__info {
display: flex;
flex-direction: column;
@@ -659,7 +695,7 @@ textarea#episode_embed_code {
z-index: 0;
visibility: hidden;
transition: .6s;
- margin-top: -444px; }
+ margin-top: -345px; }
.ssp-onboarding-step-4__form--opened {
visibility: visible;
margin-top: 0; }
@@ -749,6 +785,10 @@ textarea#episode_embed_code {
text-align: right;
margin-top: 25px;
position: relative; }
+ .ssp-onboarding__submit span.connect-castos-message {
+ display: block;
+ text-align: left;
+ margin: 20px 0 0; }
.ssp-onboarding__submit button[type=submit], .ssp-onboarding__submit .button {
position: relative;
height: 50px;
@@ -794,39 +834,56 @@ textarea#episode_embed_code {
background: #516178; }
.ssp-onboarding__submit .button span {
line-height: 50px; }
- .ssp-onboarding__submit .validate-token {
+ .ssp-onboarding__submit .castos-connect {
float: left;
position: relative;
padding: 0 20px 0 45px; }
- .ssp-onboarding__submit .validate-token:after {
+ .ssp-onboarding__submit .castos-connect:after {
content: '';
display: block;
position: absolute;
- background: url(../img/validate.svg) no-repeat;
- background-size: cover;
- left: 19px;
- top: 17px;
- width: 14px;
- height: 18px;
- filter: none; }
- .ssp-onboarding__submit .validate-token.validating {
- background: #374151; }
- .ssp-onboarding__submit .validate-token.validating:hover, .ssp-onboarding__submit .validate-token.validating:active, .ssp-onboarding__submit .validate-token.validating:focus {
- background: #374151; }
- .ssp-onboarding__submit .validate-token.validating:after {
+ background: url(../img/connect.svg) no-repeat;
+ left: 13px;
+ top: 13px;
+ width: 25px;
+ height: 23px;
+ filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(198deg) brightness(101%) contrast(102%);
+ background-size: contain; }
+ .ssp-onboarding__submit .castos-connect:disabled {
+ background: #9CA3AF !important;
+ color: #D1D5DB !important; }
+ .ssp-onboarding__submit .castos-connect:disabled:after {
+ filter: invert(94%) sepia(8%) saturate(150%) hue-rotate(177deg) brightness(90%) contrast(93%);
+ transition: none; }
+ .ssp-onboarding__submit .castos-connect.connecting {
+ background: #DE7373 !important;
+ color: #FFFFFF !important; }
+ .ssp-onboarding__submit .castos-connect.connecting:hover, .ssp-onboarding__submit .castos-connect.connecting:active, .ssp-onboarding__submit .castos-connect.connecting:focus, .ssp-onboarding__submit .castos-connect.connecting:disabled {
+ background: #DE7373; }
+ .ssp-onboarding__submit .castos-connect.connecting:after {
width: 17px;
height: 18px;
- background-image: url(../img/validating.svg); }
- .ssp-onboarding__submit .validate-token.valid {
- background: #10B981;
- padding: 0 16px 0 45px; }
- .ssp-onboarding__submit .validate-token.valid:hover, .ssp-onboarding__submit .validate-token.valid:active, .ssp-onboarding__submit .validate-token.valid:focus {
+ background-image: url(../img/connecting.svg);
+ animation: rotation 2s infinite linear;
+ filter: none;
+ transition: none;
+ top: 15px;
+ left: 15px; }
+ .ssp-onboarding__submit .castos-connect.connected {
+ background: #10B981 !important;
+ color: #FFFFFF !important;
+ padding: 0 16px 0 45px;
+ opacity: .7; }
+ .ssp-onboarding__submit .castos-connect.connected:hover, .ssp-onboarding__submit .castos-connect.connected:active, .ssp-onboarding__submit .castos-connect.connected:focus {
background: #10B981; }
- .ssp-onboarding__submit .validate-token.valid:after {
- width: 16px;
- height: 12px;
- top: 19px;
- background-image: url(../img/checkbox.svg); }
+ .ssp-onboarding__submit .castos-connect.connected:after {
+ background-image: url(../img/connect.svg);
+ left: 13px;
+ top: 13px;
+ width: 25px;
+ height: 23px;
+ filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(198deg) brightness(101%) contrast(102%);
+ background-size: contain; }
.ssp-onboarding__image-info {
position: absolute;
display: flex;
@@ -864,10 +921,6 @@ textarea#episode_embed_code {
transform: rotate(-45deg); }
.ssp-onboarding__delete-image:hover:before, .ssp-onboarding__delete-image:hover:after {
background: #fff; }
- .ssp-onboarding .validate-api-credentials-message {
- position: absolute;
- left: 0;
- bottom: -18px; }
.ssp-onboarding__links {
display: flex;
text-align: left; }
@@ -977,17 +1030,17 @@ textarea#episode_embed_code {
font-family: dashicons, 'Inter', sans-serif; }
/* Hide the WP bars */
-.admin_page_ssp-onboarding-1 #adminmenumain, .admin_page_ssp-onboarding-1 #wpadminbar, .admin_page_ssp-onboarding-1 #wpfooter, .admin_page_ssp-onboarding-2 #adminmenumain, .admin_page_ssp-onboarding-2 #wpadminbar, .admin_page_ssp-onboarding-2 #wpfooter, .admin_page_ssp-onboarding-3 #adminmenumain, .admin_page_ssp-onboarding-3 #wpadminbar, .admin_page_ssp-onboarding-3 #wpfooter, .admin_page_ssp-onboarding-4 #adminmenumain, .admin_page_ssp-onboarding-4 #wpadminbar, .admin_page_ssp-onboarding-4 #wpfooter, .admin_page_ssp-onboarding-5 #adminmenumain, .admin_page_ssp-onboarding-5 #wpadminbar, .admin_page_ssp-onboarding-5 #wpfooter {
+.podcast_page_ssp-onboarding-1 #adminmenumain, .podcast_page_ssp-onboarding-1 #wpadminbar, .podcast_page_ssp-onboarding-1 #wpfooter, .admin_page_ssp-onboarding-1 #adminmenumain, .admin_page_ssp-onboarding-1 #wpadminbar, .admin_page_ssp-onboarding-1 #wpfooter, .admin_page_ssp-onboarding-2 #adminmenumain, .admin_page_ssp-onboarding-2 #wpadminbar, .admin_page_ssp-onboarding-2 #wpfooter, .admin_page_ssp-onboarding-3 #adminmenumain, .admin_page_ssp-onboarding-3 #wpadminbar, .admin_page_ssp-onboarding-3 #wpfooter, .admin_page_ssp-onboarding-4 #adminmenumain, .admin_page_ssp-onboarding-4 #wpadminbar, .admin_page_ssp-onboarding-4 #wpfooter, .admin_page_ssp-onboarding-5 #adminmenumain, .admin_page_ssp-onboarding-5 #wpadminbar, .admin_page_ssp-onboarding-5 #wpfooter {
display: none; }
-.admin_page_ssp-onboarding-1 #wpcontent, .admin_page_ssp-onboarding-2 #wpcontent, .admin_page_ssp-onboarding-3 #wpcontent, .admin_page_ssp-onboarding-4 #wpcontent, .admin_page_ssp-onboarding-5 #wpcontent {
+.podcast_page_ssp-onboarding-1 #wpcontent, .admin_page_ssp-onboarding-1 #wpcontent, .admin_page_ssp-onboarding-2 #wpcontent, .admin_page_ssp-onboarding-3 #wpcontent, .admin_page_ssp-onboarding-4 #wpcontent, .admin_page_ssp-onboarding-5 #wpcontent {
margin-left: 0;
padding-left: 0; }
-.admin_page_ssp-onboarding-1 #wpbody-content, .admin_page_ssp-onboarding-2 #wpbody-content, .admin_page_ssp-onboarding-3 #wpbody-content, .admin_page_ssp-onboarding-4 #wpbody-content, .admin_page_ssp-onboarding-5 #wpbody-content {
+.podcast_page_ssp-onboarding-1 #wpbody-content, .admin_page_ssp-onboarding-1 #wpbody-content, .admin_page_ssp-onboarding-2 #wpbody-content, .admin_page_ssp-onboarding-3 #wpbody-content, .admin_page_ssp-onboarding-4 #wpbody-content, .admin_page_ssp-onboarding-5 #wpbody-content {
padding-bottom: 30px; }
-.admin_page_ssp-onboarding-1 .notice, .admin_page_ssp-onboarding-1 .error, .admin_page_ssp-onboarding-2 .notice, .admin_page_ssp-onboarding-2 .error, .admin_page_ssp-onboarding-3 .notice, .admin_page_ssp-onboarding-3 .error, .admin_page_ssp-onboarding-4 .notice, .admin_page_ssp-onboarding-4 .error, .admin_page_ssp-onboarding-5 .notice, .admin_page_ssp-onboarding-5 .error {
+.podcast_page_ssp-onboarding-1 .notice, .podcast_page_ssp-onboarding-1 .error, .admin_page_ssp-onboarding-1 .notice, .admin_page_ssp-onboarding-1 .error, .admin_page_ssp-onboarding-2 .notice, .admin_page_ssp-onboarding-2 .error, .admin_page_ssp-onboarding-3 .notice, .admin_page_ssp-onboarding-3 .error, .admin_page_ssp-onboarding-4 .notice, .admin_page_ssp-onboarding-4 .error, .admin_page_ssp-onboarding-5 .notice, .admin_page_ssp-onboarding-5 .error {
display: none; }
.ssp-review-notice {
diff --git a/assets/admin/img/connect.svg b/assets/admin/img/connect.svg
new file mode 100644
index 00000000..463acfb4
--- /dev/null
+++ b/assets/admin/img/connect.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/admin/img/connecting.svg b/assets/admin/img/connecting.svg
new file mode 100644
index 00000000..23295e5b
--- /dev/null
+++ b/assets/admin/img/connecting.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/admin/img/loader2.svg b/assets/admin/img/loader2.svg
new file mode 100644
index 00000000..25f1ca19
--- /dev/null
+++ b/assets/admin/img/loader2.svg
@@ -0,0 +1,57 @@
+
\ No newline at end of file
diff --git a/assets/admin/js/onboarding.js b/assets/admin/js/onboarding.js
index 9c46ad01..d4866290 100644
--- a/assets/admin/js/onboarding.js
+++ b/assets/admin/js/onboarding.js
@@ -5,7 +5,7 @@ jQuery(document).ready(function($) {
$imgName = $imgInfo.find('.js-onboarding-img-name'),
$fields = $('.js-onboarding-field'),
$btn = $('.js-onboarding-btn'),
- $validateTokenBtn = $('.js-onboarding-validate-token'),
+ $connectCastosBtn = $('.js-onboarding-castos-connect'),
$hostingStep2 = $('.js-hosting-form'),
$accordion = $('.js-accordion'),
$dragable = $('.js-onboarding-dragable'),
@@ -54,29 +54,33 @@ jQuery(document).ready(function($) {
});
},
initTokenValidation = function(){
- $validateTokenBtn.on('validated', function () {
- //don't use $btn since it has custom validation
- var $form = $validateTokenBtn.closest('form'),
- $nextButton = $form.find('button[type=submit]');
- $(this).removeClass('validating');
- if ($validateTokenBtn.hasClass('valid')) {
+ $connectCastosBtn.on('connected', function (e, response) {
+ var $form = $connectCastosBtn.closest('form'),
+ $nextButton = $form.find('button[type=submit]'),
+ $me = $(this),
+ $msg = $form.find('.connect-castos-message'),
+ $field = $('.js-onboarding-castos-connect-field');
+ $me.removeClass('connecting');
+ $msg.show();
+
+ if ("success" === response.status) {
+ $me.html($me.data('connected-txt'));
+ $field.attr('disabled', 'disabled');
$nextButton.removeAttr('disabled');
- $form.find('.validate-api-credentials-message').html('');
- $(this).html($(this).data('valid-txt'));
} else {
- $(this).html($(this).data('initial-txt'));
+ $me.html($me.data('initial-txt'));
$nextButton.attr('disabled', 'disabled');
}
});
- $validateTokenBtn.on('click', function(){
- $(this).addClass('validating').html($(this).data('validating-txt'));
+ $connectCastosBtn.on('connecting', function(){
+ $(this).addClass('connecting').html($(this).data('connecting-txt'));
});
- $('.js-onboarding-validate-token-field').on('change paste keyup', function(){
- var $nextButton = $validateTokenBtn.closest('form').find('button[type=submit]');
- $validateTokenBtn.html($validateTokenBtn.data('initial-txt'));
- $validateTokenBtn.removeClass('valid');
+ $('.js-onboarding-castos-connect-field').on('change paste keyup', function(){
+ var $nextButton = $connectCastosBtn.closest('form').find('button[type=submit]');
+ $connectCastosBtn.html($connectCastosBtn.data('initial-txt'));
+ $connectCastosBtn.removeClass('valid');
$nextButton.attr('disabled', 'disabled');
});
},
diff --git a/assets/admin/scss/_admin.scss b/assets/admin/scss/_admin.scss
index ce7728fd..e85ff61b 100644
--- a/assets/admin/scss/_admin.scss
+++ b/assets/admin/scss/_admin.scss
@@ -271,6 +271,19 @@ textarea#episode_embed_code {
}
}
+#podmotor_account_api_token {
+ width: 100%;
+ min-width: 100%;
+ display: block;
+ margin-bottom: 8px;
+}
+
+.ssp-settings-integrations {
+ table label {
+ margin-top: 10px;
+ display: block;
+ }
+}
.ssp-settings:not(.ssp-settings-extensions,.ssp-settings-integrations) {
background: $clr_white;
@@ -298,10 +311,6 @@ textarea#episode_embed_code {
}
}
- .validate-api-credentials-message {
- margin-left: 30px;
- }
-
.loader {
position: relative;
&:after {
@@ -334,6 +343,42 @@ textarea#episode_embed_code {
}
}
+.ssp-main-settings {
+ .error {
+ color: $clr_red_400;
+ }
+
+ .hidden {
+ display: none;
+ }
+
+ .disconnect-castos {
+ margin-right: 8px;
+ vertical-align: middle;
+ }
+
+ &.tab-castos-hosting {
+ .loader {
+ position: relative;
+ &:after {
+ content: '';
+ display: block;
+ background: url(../img/loader2.svg) no-repeat;
+ position: absolute;
+ right: -50px;
+ top: -9px;
+ background-size: contain;
+ width: 44px;
+ height: 44px;
+ }
+ }
+ }
+}
+
+.connect-castos-message {
+ margin-left: 20px;
+}
+
.ssp-sync-podcast {
display: flex;
justify-content: space-between;
diff --git a/assets/admin/scss/_onboarding.scss b/assets/admin/scss/_onboarding.scss
index a9bda3c3..7eb298af 100644
--- a/assets/admin/scss/_onboarding.scss
+++ b/assets/admin/scss/_onboarding.scss
@@ -156,7 +156,7 @@
&-step-2, &-step-3, &-step-4, &-step-5 {
.ssp-onboarding__steps::after {
- background: #DF4E4F;
+ background: $clr_red_400;
width: initial;
}
}
@@ -191,6 +191,10 @@
right: 180px;
}
+ .ssp-onboarding__settings-body {
+ padding: 24px 24px 36px;
+ }
+
&__info {
display: flex;
flex-direction: column;
@@ -317,7 +321,7 @@
li {
&:hover {
svg path, svg rect {
- fill: #DF4E4F;
+ fill: $clr_red_400;
}
}
}
@@ -452,7 +456,7 @@
z-index: 0;
visibility: hidden;
transition: .6s;
- margin-top: -444px;
+ margin-top: -345px;
&--opened {
visibility: visible;
@@ -585,13 +589,19 @@
margin-top: 25px;
position: relative;
+ span.connect-castos-message {
+ display: block;
+ text-align: left;
+ margin: 20px 0 0;
+ }
+
button[type=submit], .button {
position: relative;
height: 50px;
border-radius: 6px;
border: 0;
color: #FFFFFF;
- background: #DF4E4F;
+ background: $clr_red_400;
font-size: 18px;
padding: 0 55px 0 33px;
transition: .3s;
@@ -650,7 +660,7 @@
}
}
- .validate-token {
+ .castos-connect {
float: left;
position: relative;
padding: 0 20px 0 45px;
@@ -659,42 +669,62 @@
content: '';
display: block;
position: absolute;
- background: url(../img/validate.svg) no-repeat;
- background-size: cover;
- left: 19px;
- top: 17px;
- width: 14px;
- height: 18px;
- filter: none;
+ background: url(../img/connect.svg) no-repeat;
+ left: 13px;
+ top: 13px;
+ width: 25px;
+ height: 23px;
+ filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(198deg) brightness(101%) contrast(102%);
+ background-size: contain;
+ }
+
+ &:disabled {
+ background: #9CA3AF !important;
+ color: #D1D5DB !important;
+ &:after {
+ //filter: invert(92%) sepia(17%) saturate(74%) hue-rotate(176deg) brightness(92%) contrast(88%);
+ filter: invert(94%) sepia(8%) saturate(150%) hue-rotate(177deg) brightness(90%) contrast(93%);
+ transition: none;
+ }
}
- &.validating {
- background: #374151;
+ &.connecting {
+ background: #DE7373 !important;
+ color: #FFFFFF !important;
- &:hover, &:active, &:focus {
- background: #374151;
+ &:hover, &:active, &:focus, &:disabled {
+ background: #DE7373;
}
&:after {
width: 17px;
height: 18px;
- background-image: url(../img/validating.svg);
+ background-image: url(../img/connecting.svg);
+ animation: rotation 2s infinite linear;
+ filter: none;
+ transition: none;
+ top: 15px;
+ left: 15px;
}
}
- &.valid {
- background: #10B981;
+ &.connected {
+ background: #10B981 !important;
+ color: $clr_white !important;
padding: 0 16px 0 45px;
-
&:hover, &:active, &:focus {
background: #10B981;
}
+ opacity: .7;
&:after {
- width: 16px;
- height: 12px;
- top: 19px;
- background-image: url(../img/checkbox.svg);
+ background-image: url(../img/connect.svg);
+ left: 13px;
+ top: 13px;
+ width: 25px;
+ height: 23px;
+ filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(198deg) brightness(101%) contrast(102%);
+ background-size: contain;
}
}
}
@@ -732,7 +762,7 @@
display: block;
height: 1.5px;
width: 14px;
- background: #DF4E4F;
+ background: $clr_red_400;
position: absolute;
left: 7px;
top: 46%;
@@ -752,12 +782,6 @@
}
}
- .validate-api-credentials-message {
- position: absolute;
- left: 0;
- bottom: -18px;
- }
-
&__links {
display: flex;
text-align: left;
@@ -822,7 +846,7 @@
width: 30px;
height: 30px;
background: #FFF;
- color: #DF4E4F;
+ color: $clr_red_400;
font-size: 20px;
font-weight: 600;
border-radius: 50%;
@@ -907,7 +931,7 @@
}
/* Hide the WP bars */
-.admin_page_ssp-onboarding-1, .admin_page_ssp-onboarding-2, .admin_page_ssp-onboarding-3, .admin_page_ssp-onboarding-4, .admin_page_ssp-onboarding-5 {
+.podcast_page_ssp-onboarding-1, .admin_page_ssp-onboarding-1, .admin_page_ssp-onboarding-2, .admin_page_ssp-onboarding-3, .admin_page_ssp-onboarding-4, .admin_page_ssp-onboarding-5 {
#adminmenumain, #wpadminbar, #wpfooter {
display: none;
}
diff --git a/assets/css/settings.css b/assets/css/settings.css
index 95cb20c5..de8323bb 100644
--- a/assets/css/settings.css
+++ b/assets/css/settings.css
@@ -18,7 +18,7 @@
height: auto;
}
-#ssp-main-settings {
+#ssp-main-settings.castos-disconnected {
width: 75%;
float: left;
}
@@ -36,11 +36,6 @@
overflow: hidden;
}
-#ssp-sidebar .sidebar-content.castos-connected {
- border: none;
- background: none;
-}
-
#ssp-sidebar .sidebar-content h3 {
color: #6c25d0;
margin: -20px -20px 0 -20px;
diff --git a/assets/js/admin-menu.js b/assets/js/admin-menu.js
new file mode 100644
index 00000000..e75ddc8f
--- /dev/null
+++ b/assets/js/admin-menu.js
@@ -0,0 +1,11 @@
+jQuery( document ).ready( function( $ ) {
+ var initOnboardingMenu = function() {
+ var $firstMenuItem = $( '#menu-posts-podcast' ).find( '.wp-submenu a.wp-first-item' );
+
+ if ( $firstMenuItem.length && $firstMenuItem.attr( 'href' ).includes( 'page=ssp-onboarding-1' ) ) {
+ $firstMenuItem.closest('ul').find('li').not('.wp-first-item').hide();
+ }
+ }
+
+ initOnboardingMenu();
+} );
diff --git a/assets/js/admin.js b/assets/js/admin.js
index 65937b54..90888b60 100644
--- a/assets/js/admin.js
+++ b/assets/js/admin.js
@@ -257,5 +257,19 @@ jQuery(document).ready(function($) {
});
}
+ var initNotifications = function () {
+ $('.notice.is-constant').on( 'click', '.notice-dismiss', function () {
+ var $notice = $(this).closest('.notice'),
+ data = {
+ 'action': 'remove_constant_notice',
+ 'id': $notice.data('id'),
+ 'nonce': $notice.data('nonce'),
+ };
+
+ $.post(ajaxurl, data);
+ });
+ };
+
initDynamoBtn();
+ initNotifications();
});
diff --git a/assets/js/settings.js b/assets/js/settings.js
index d6bad924..b26e80ad 100644
--- a/assets/js/settings.js
+++ b/assets/js/settings.js
@@ -5,11 +5,8 @@
*/
jQuery(document).ready(function($) {
-
- var $podmotorAccountEmail = $("#podmotor_account_email"),
- $podmotorAccountAPIToken = $("#podmotor_account_api_token"),
- $parentCategories = $('.js-parent-category'),
- $validateBtn = $("#validate_api_credentials");
+ var $podmotorAccountAPIToken = $("#podmotor_account_api_token"),
+ $parentCategories = $('.js-parent-category');
const { __ } = wp.i18n;
@@ -35,103 +32,106 @@ jQuery(document).ready(function($) {
}
function initCastosAPICredentials() {
- var disableSubmitButton = function () {
- /**
- * If either API field is empty, disable the submit button
- */
- if ($podmotorAccountEmail.val() === '' || $podmotorAccountAPIToken.val() === '') {
- $("#ssp-settings-submit").prop("disabled", "disabled");
- }
-
- /**
- * If the user changes the email, disable the submit button
- */
- $podmotorAccountEmail.on("change paste keydown keyup", function () {
- $("#ssp-settings-submit").prop("disabled", "disabled");
- });
-
- /**
- * If the user changes the account api key, disable the submit button
- */
- $podmotorAccountAPIToken.on("change paste keydown keyup", function () {
- $("#ssp-settings-submit").prop("disabled", "disabled");
- });
- },
- /**
- * Validate the api credentials
- */
- validateAPICredentials = function () {
- $validateBtn.on("click", function () {
-
- var podmotor_account_email = $("#podmotor_account_email").val(),
- podmotor_account_api_token = $("#podmotor_account_api_token").val(),
- nonce = $("#podcast_settings_tab_nonce").val(),
- $msg = $('.validate-api-credentials-message');
-
- if (!$msg.length) {
- $msg = $('');
- $validateBtn.parent().append($msg);
- }
-
- $msg.html("Validating API credentials...");
-
- $validateBtn.addClass('loader');
-
- $.ajax({
- method: "GET",
- url: ajaxurl,
- data: {
- action: "validate_castos_credentials",
- api_token: podmotor_account_api_token,
- email: podmotor_account_email,
- nonce: nonce
- }
- })
- .done(function (response) {
- $validateBtn.removeClass('loader');
- if (response.status === 'success') {
- $(".validate-api-credentials-message").html("Credentials Valid. Please click 'Save Settings' to save Credentials.");
- $("#ssp-settings-submit").prop("disabled", "");
- $validateBtn.val('Valid Credentials');
- $validateBtn.addClass('valid');
- } else {
- $validateBtn.addClass('invalid');
- $(".validate-api-credentials-message").html(response.message);
- }
- $validateBtn.trigger('validated');
- });
- });
- },
- /**
- * Disconnect Castos checkbox on change, renders a confirmation message to the user.
- */
- disconnectCastos = function () {
- $('#podmotor_disconnect').on('change', function (event) {
- var $checkbox = $(this);
-
- // if the change is to uncheck the checkbox
- if (!$checkbox.is(':checked')) {
- return;
- }
-
- var $message = 'If you disconnect from Castos hosting you will no longer be able to upload media files to the Castos hosting platform. If you’re no longer a Castos customer your media files may no longer be available to your listeners.';
- var user_input = confirm($message);
- if (user_input !== true) {
- // Ensures this code runs AFTER the browser handles click however it wants.
- setTimeout(function () {
- $checkbox.removeAttr('checked');
- }, 0);
- event.preventDefault();
- event.stopPropagation();
- }
- });
- }
-
- if ($podmotorAccountEmail.length > 0 && $podmotorAccountAPIToken.length > 0) {
- disableSubmitButton();
- validateAPICredentials();
- disconnectCastos();
+ var $connectBtn = $(".castos-connect"),
+ disableConnectButton = function(){
+ $connectBtn.prop("disabled", "disabled");
+ },
+ enableConnectButton = function(){
+ $connectBtn.prop("disabled", "").removeClass('disabled');
+ },
+ connectButtonStates = function () {
+ if ($podmotorAccountAPIToken.length) {
+ $connectBtn.show();
+ }
+ $podmotorAccountAPIToken.on("focus change paste keydown keyup", function () {
+ $podmotorAccountAPIToken.val() ? enableConnectButton() : disableConnectButton();
+ });
+
+ $podmotorAccountAPIToken.on("focus", function(){
+ $('.connect-castos-message').html('').removeClass('error');
+ });
+ },
+ /**
+ * Validate the api credentials
+ */
+ initConnect = function () {
+ $connectBtn.on('click', function (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ $connectBtn.prop('disabled', 'disabled');
+ $connectBtn.trigger('connecting');
+
+ var podmotor_account_api_token = $('#podmotor_account_api_token').val(),
+ nonce = $('#podcast_settings_tab_nonce').val(),
+ $msg = $('.connect-castos-message');
+
+ if ($msg.length) {
+ $msg.html('').removeClass('error');
+ } else {
+ $msg = $('');
+ $connectBtn.parent().append($msg);
+ }
+
+ $connectBtn.addClass('loader');
+
+ $.ajax({
+ method: 'GET',
+ url: ajaxurl,
+ data: {
+ action: 'connect_castos',
+ api_token: podmotor_account_api_token,
+ nonce: nonce,
+ },
+ })
+ .done(function (response) {
+ $connectBtn.trigger('connected', response);
+ if (response.status === 'success') {
+ $connectBtn.addClass('connected');
+ if ( ! $connectBtn.data( 'no-reload' ) ) {
+ window.location.reload();
+ } else {
+ $msg.html( response.message );
+ }
+ } else {
+ $connectBtn.removeClass('loader');
+ $msg.addClass('error');
+ $msg.html(response.message);
+ }
+ })
+ })
+ },
+ /**
+ * Disconnect Castos checkbox on change, renders a confirmation message to the user.
+ */
+ initDisconnect = function () {
+ var $disconnect = $('#disconnect_castos');
+ $disconnect.on('click', function (event) {
+ var $message = 'If you disconnect from Castos hosting you will no longer be able to upload media files to the Castos hosting platform. If you’re no longer a Castos customer your media files may no longer be available to your listeners.';
+ var user_input = confirm($message);
+ if (user_input === true) {
+ $disconnect.addClass('loader');
+ $disconnect.parent().find('label').remove();
+ $.ajax({
+ method: 'GET',
+ url: ajaxurl,
+ data: {
+ action: 'disconnect_castos',
+ nonce: $('#podcast_settings_tab_nonce').val(),
+ },
+ })
+ .done(function (response) {
+ window.location.reload();
+ })
+ }
+ });
+ }
+
+ if ($podmotorAccountAPIToken.length > 0) {
+ connectButtonStates();
+ initConnect();
}
+
+ initDisconnect();
}
function initSubcategoryFiltration(){
diff --git a/package.json b/package.json
index 86cfe793..73ec5df8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "seriously-simple-podcasting",
- "version": "3.2.0",
+ "version": "3.5.0",
"main": "build/index.js",
"author": "CastosHQ",
"devDependencies": {
diff --git a/php/classes/controllers/class-ads-controller.php b/php/classes/controllers/class-ads-controller.php
index 61b0a0e5..29f55e43 100644
--- a/php/classes/controllers/class-ads-controller.php
+++ b/php/classes/controllers/class-ads-controller.php
@@ -113,7 +113,7 @@ protected function is_ads_enabled_in_castos() {
$series_id = $this->get_current_feed_series_id();
- if ( empty( $podcasts['data']['podcast_list'] ) ) {
+ if ( ! is_array( $podcasts ) || empty( $podcasts['data']['podcast_list'] ) ) {
return false;
}
diff --git a/php/classes/controllers/class-app-controller.php b/php/classes/controllers/class-app-controller.php
index bafc448a..a2dce628 100644
--- a/php/classes/controllers/class-app-controller.php
+++ b/php/classes/controllers/class-app-controller.php
@@ -259,7 +259,9 @@ protected function bootstrap() {
$this->episode_repository = new Episode_Repository( $this->feed_handler );
- $this->castos_handler = new Castos_Handler( $this->feed_handler, $this->logger );
+ $this->admin_notices_handler = new Admin_Notifications_Handler();
+
+ $this->castos_handler = new Castos_Handler( $this->feed_handler, $this->logger, $this->admin_notices_handler );
$this->onboarding_controller = new Onboarding_Controller( $this->renderer, $this->settings_handler );
@@ -273,15 +275,13 @@ protected function bootstrap() {
$this->widgets_controller = new Widgets_Controller( $this->file, $this->version );
- $this->ajax_handler = new Ajax_Handler( $this->castos_handler );
+ $this->ajax_handler = new Ajax_Handler( $this->castos_handler, $this->admin_notices_handler );
$this->podping_handler = new Podping_Handler( $this->logger );
- $this->admin_notices_handler = new Admin_Notifications_Handler( $this->token );
-
$this->assets_controller = new Assets_Controller();
- $this->series_handler = new Series_Handler( $this->admin_notices_handler, $this->roles_handler, $this->castos_handler, $this->settings_handler, $this->episode_repository );
+ $this->series_handler = new Series_Handler( $this->admin_notices_handler, $this->roles_handler, $this->castos_handler, $this->settings_handler, $this->episode_repository );
$this->upgrade_handler = new Upgrade_Handler( $this->episode_repository, $this->castos_handler, $this->series_handler );
@@ -331,7 +331,7 @@ protected function bootstrap() {
$this->load_plugin_textdomain();
}
- protected function init_integrations(){
+ protected function init_integrations() {
/*
* Gutenberg integration.
* Only load Blocks if the WordPress version is newer than 5.0.
@@ -393,7 +393,7 @@ public function get_available_services() {
*
* @return string
* */
- protected function get_wp_version(){
+ protected function get_wp_version() {
global $wp_version;
return $wp_version;
@@ -402,7 +402,7 @@ protected function get_wp_version(){
/**
* Init REST API
*/
- protected function init_rest_api(){
+ protected function init_rest_api() {
global $wp_version;
// Only load WP REST API Endpoints if the WordPress version is newer than 4.7.
@@ -494,7 +494,6 @@ public function get_settings_handler() {
}
-
/**
* Register the Castos Blog dashboard widget
* Hooks into the wp_dashboard_setup action hook
@@ -547,9 +546,9 @@ public function ssp_castos_dashboard_output( $widget_id, $feeds ) {
/**
* Check if there is a cached version of the RSS Feed and output it
*/
- $locale = get_user_locale();
- $cache_key = 'ssp_dash_v2_' . md5( $widget_id . '_' . $locale );
- $rss_output = get_transient( $cache_key );
+ $locale = get_user_locale();
+ $cache_key = 'ssp_dash_v2_' . md5( $widget_id . '_' . $locale );
+ $rss_output = get_transient( $cache_key );
if ( false !== $rss_output ) {
return $rss_output;
}
@@ -568,13 +567,14 @@ public function ssp_castos_dashboard_output( $widget_id, $feeds ) {
* Set up the cached version to expire in 12 hours and output the content
*/
set_transient( $cache_key, $rss_output, 12 * HOUR_IN_SECONDS );
+
return $rss_output;
}
/**
* Adding podcast episodes to 'At a glance' dashboard widget
*
- * @param array $items Existing items
+ * @param array $items Existing items
*
* @return array Updated items
*/
@@ -583,8 +583,8 @@ public function glance_items( $items = array() ) {
$num_posts = count( ssp_episodes( - 1, '', false, 'glance' ) );
$post_type_object = get_post_type_object( $this->token );
- $text = _n( '%s Episode', '%s Episodes', $num_posts, 'seriously-simple-podcasting' );
- $text = sprintf( $text, number_format_i18n( $num_posts ) );
+ $text = _n( '%s Episode', '%s Episodes', $num_posts, 'seriously-simple-podcasting' );
+ $text = sprintf( $text, number_format_i18n( $num_posts ) );
if ( $post_type_object && current_user_can( $post_type_object->cap->edit_posts ) ) {
$items[] = sprintf( '%2$s', $this->token, $text ) . "\n";
@@ -598,10 +598,10 @@ public function glance_items( $items = array() ) {
/**
* Adding appreciation links to the SSP record in the plugin list table
*
- * @param array $plugin_meta Default plugin meta links
- * @param string $plugin_file Plugin file
- * @param array $plugin_data Array of plugin data
- * @param string $status Plugin status
+ * @param array $plugin_meta Default plugin meta links
+ * @param string $plugin_file Plugin file
+ * @param array $plugin_data Array of plugin data
+ * @param string $status Plugin status
*
* @return array Modified plugin meta links
*/
@@ -613,6 +613,7 @@ public function plugin_row_meta( $plugin_meta = array(), $plugin_file = '', $plu
$plugin_meta['docs'] = '' . __( 'Documentation', 'seriously-simple-podcasting' ) . '';
$plugin_meta['addons'] = '' . __( 'Add-ons', 'seriously-simple-podcasting' ) . '';
$plugin_meta['review'] = '' . __( 'Write a review', 'seriously-simple-podcasting' ) . '';
+
return $plugin_meta;
}
@@ -650,7 +651,7 @@ public function load_plugin_textdomain() {
/**
* Hide RSS footer created by WordPress SEO from podcast RSS feed
*
- * @param boolean $include_footer Default inclusion value
+ * @param boolean $include_footer Default inclusion value
*
* @return boolean Modified inclusion value
*/
@@ -688,6 +689,7 @@ public function activate() {
public function deactivate() {
flush_rewrite_rules();
$this->roles_handler->remove_custom_roles();
+ $this->castos_handler->remove_api_credentials();
}
/**
@@ -710,7 +712,7 @@ public function maybe_run_plugin_updates() {
/**
* Add rating link to admin footer on SSP settings pages
*
- * @param string $footer_text Default footer text
+ * @param string $footer_text Default footer text
*
* @return string Modified footer text
*/
@@ -722,7 +724,7 @@ public function admin_footer_text( $footer_text ) {
// Change the footer text
if ( ! get_option( 'ssp_admin_footer_text_rated' ) ) {
$footer_text = sprintf( __( 'If you like %1$sSeriously Simple Podcasting%2$s please leave a %3$s★★★★★%4$s rating. A huge thank you in advance!', 'seriously-simple-podcasting' ), '', '', '', '' );
- $footer_text .= sprintf("