├── .nvmrc ├── .husky ├── .gitignore └── pre-commit ├── .eslintignore ├── .wp-env.json ├── assets ├── js │ ├── blocks │ │ ├── podcast │ │ │ ├── index.js │ │ │ └── index.scss │ │ ├── latest-episode │ │ │ ├── index.js │ │ │ └── index.scss │ │ └── podcast-platforms │ │ │ ├── index.js │ │ │ ├── index.scss │ │ │ └── edit.js │ ├── onboarding.js │ ├── transforms.js │ ├── podcasting-edit-post.js │ ├── deprecated.js │ ├── podcasting-edit-term.js │ ├── blocks.js │ └── create-podcast-show.js ├── images │ ├── icons │ │ ├── RSS │ │ │ ├── black-100.png │ │ │ ├── black-40.png │ │ │ ├── color-100.png │ │ │ ├── color-40.png │ │ │ ├── white-100.png │ │ │ └── white-40.png │ │ ├── castro │ │ │ ├── black-100.png │ │ │ ├── black-40.png │ │ │ ├── color-100.png │ │ │ ├── color-40.png │ │ │ ├── white-100.png │ │ │ └── white-40.png │ │ ├── pandora │ │ │ ├── black-40.png │ │ │ ├── color-40.png │ │ │ ├── white-40.png │ │ │ ├── black-100.png │ │ │ ├── color-100.png │ │ │ └── white-100.png │ │ ├── spotify │ │ │ ├── black-40.png │ │ │ ├── color-40.png │ │ │ ├── white-40.png │ │ │ ├── black-100.png │ │ │ ├── color-100.png │ │ │ └── white-100.png │ │ ├── tunein │ │ │ ├── black-100.png │ │ │ ├── black-40.png │ │ │ ├── color-100.png │ │ │ ├── color-40.png │ │ │ ├── white-100.png │ │ │ └── white-40.png │ │ ├── overcast │ │ │ ├── black-100.png │ │ │ ├── black-40.png │ │ │ ├── color-100.png │ │ │ ├── color-40.png │ │ │ ├── white-100.png │ │ │ └── white-40.png │ │ ├── playerfm │ │ │ ├── black-100.png │ │ │ ├── black-40.png │ │ │ ├── color-100.png │ │ │ ├── color-40.png │ │ │ ├── white-100.png │ │ │ └── white-40.png │ │ ├── stitcher │ │ │ ├── black-100.png │ │ │ ├── black-40.png │ │ │ ├── color-100.png │ │ │ ├── color-40.png │ │ │ ├── white-100.png │ │ │ └── white-40.png │ │ ├── pocket-casts │ │ │ ├── black-40.png │ │ │ ├── color-40.png │ │ │ ├── white-40.png │ │ │ ├── black-100.png │ │ │ ├── color-100.png │ │ │ └── white-100.png │ │ ├── apple-podcasts │ │ │ ├── black-40.png │ │ │ ├── color-40.png │ │ │ ├── white-40.png │ │ │ ├── black-100.png │ │ │ ├── color-100.png │ │ │ └── white-100.png │ │ └── google-podcasts │ │ │ ├── black-100.png │ │ │ ├── black-40.png │ │ │ ├── color-100.png │ │ │ ├── color-40.png │ │ │ ├── white-100.png │ │ │ └── white-40.png │ ├── podcast-block-preview.png │ └── podcast-block-preview@2x.png └── css │ ├── podcasting-transcript.css │ ├── podcasting-editor-screen.css │ ├── podcasting-edit-term.css │ └── podcasting-onboarding.scss ├── .wordpress-version-checker.json ├── .prettierrc ├── .wordpress-org ├── icon-128x128.png ├── icon-256x256.png ├── screenshot-1.png ├── screenshot-2.png ├── screenshot-3.png ├── screenshot-4.png ├── screenshot-5.png ├── screenshot-6.png ├── banner-1544x500.png ├── banner-772x250.png ├── banner-772x250-rtl.png ├── banner-1544x500-rtl.png └── blueprints │ └── blueprint.json ├── .eslintrc ├── tests ├── cypress │ ├── fixtures │ │ ├── example.jpg │ │ ├── example.mp3 │ │ └── example.json │ ├── .eslintrc │ ├── tsconfig.json │ ├── integration │ │ ├── admin.test.js │ │ ├── onboarding.test.js │ │ ├── block.test.js │ │ ├── taxonomy.test.js │ │ └── podcast-setting-panel.test.js │ ├── support │ │ ├── index.js │ │ └── functions.js │ ├── config.config.js │ └── plugins │ │ └── index.js ├── bin │ └── set-wp-config.js └── unit │ ├── bootstrap.php │ ├── test-transcript.php │ ├── test-rest-external-url.php │ ├── test-datatypes.php │ ├── test-helpers.php │ └── test-blocks.php ├── includes ├── blocks │ ├── podcast-transcript │ │ ├── styles.css │ │ ├── index.js │ │ ├── markup.php │ │ ├── cite.js │ │ ├── time.js │ │ ├── formats.js │ │ └── edit.js │ └── podcast │ │ └── markup.php ├── upgrade.php ├── admin │ ├── views │ │ ├── onboarding-header.php │ │ ├── onboarding-page-two.php │ │ └── onboarding-page-one.php │ ├── create-podcast-component.php │ └── onboarding.php ├── block-patterns.php ├── rest-external-url.php ├── transcripts.php ├── helpers.php ├── create-podcast.php └── post-meta-box.php ├── .phpcs.xml.dist ├── .editorconfig ├── .distignore ├── .github ├── CODEOWNERS └── workflows │ ├── wordpress-version-checker.yml │ ├── phpcs.yml │ ├── repo-automator.yml │ ├── push-asset-readme-update.yml │ ├── dependency-review.yml │ ├── push-deploy.yml │ ├── build-release-zip.yml │ ├── php-compatibility.yml │ ├── phpunit.yml │ ├── close-stale-issues.yml │ └── cypress.yml ├── .gitignore ├── phpunit.xml.dist ├── composer.json ├── templates └── transcript.php ├── webpack.config.js ├── package.json ├── CODE_OF_CONDUCT.md ├── CREDITS.md ├── CONTRIBUTING.md ├── simple-podcasting.php └── README.md /.nvmrc: -------------------------------------------------------------------------------- 1 | v20 2 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | assets/js/frontend/vendor/*.js 2 | -------------------------------------------------------------------------------- /.wp-env.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["."] 3 | } 4 | -------------------------------------------------------------------------------- /assets/js/blocks/podcast/index.js: -------------------------------------------------------------------------------- 1 | import './index.scss'; 2 | -------------------------------------------------------------------------------- /assets/js/blocks/latest-episode/index.js: -------------------------------------------------------------------------------- 1 | import './index.scss'; 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.wordpress-version-checker.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "readme.txt", 3 | "channel": "rc" 4 | } 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "printWidth": 90, 4 | "tabWidth": 4, 5 | "singleQuote": true 6 | } 7 | -------------------------------------------------------------------------------- /.wordpress-org/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/.wordpress-org/icon-128x128.png -------------------------------------------------------------------------------- /.wordpress-org/icon-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/.wordpress-org/icon-256x256.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/.wordpress-org/screenshot-1.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/.wordpress-org/screenshot-2.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/.wordpress-org/screenshot-3.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/.wordpress-org/screenshot-4.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/.wordpress-org/screenshot-5.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/.wordpress-org/screenshot-6.png -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ "plugin:@wordpress/eslint-plugin/recommended" ], 3 | "ignorePatterns": ["**/vendor/**"] 4 | } 5 | -------------------------------------------------------------------------------- /.wordpress-org/banner-1544x500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/.wordpress-org/banner-1544x500.png -------------------------------------------------------------------------------- /.wordpress-org/banner-772x250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/.wordpress-org/banner-772x250.png -------------------------------------------------------------------------------- /tests/cypress/fixtures/example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/tests/cypress/fixtures/example.jpg -------------------------------------------------------------------------------- /tests/cypress/fixtures/example.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/tests/cypress/fixtures/example.mp3 -------------------------------------------------------------------------------- /.wordpress-org/banner-772x250-rtl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/.wordpress-org/banner-772x250-rtl.png -------------------------------------------------------------------------------- /assets/images/icons/RSS/black-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/RSS/black-100.png -------------------------------------------------------------------------------- /assets/images/icons/RSS/black-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/RSS/black-40.png -------------------------------------------------------------------------------- /assets/images/icons/RSS/color-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/RSS/color-100.png -------------------------------------------------------------------------------- /assets/images/icons/RSS/color-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/RSS/color-40.png -------------------------------------------------------------------------------- /assets/images/icons/RSS/white-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/RSS/white-100.png -------------------------------------------------------------------------------- /assets/images/icons/RSS/white-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/RSS/white-40.png -------------------------------------------------------------------------------- /.wordpress-org/banner-1544x500-rtl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/.wordpress-org/banner-1544x500-rtl.png -------------------------------------------------------------------------------- /assets/images/icons/castro/black-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/castro/black-100.png -------------------------------------------------------------------------------- /assets/images/icons/castro/black-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/castro/black-40.png -------------------------------------------------------------------------------- /assets/images/icons/castro/color-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/castro/color-100.png -------------------------------------------------------------------------------- /assets/images/icons/castro/color-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/castro/color-40.png -------------------------------------------------------------------------------- /assets/images/icons/castro/white-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/castro/white-100.png -------------------------------------------------------------------------------- /assets/images/icons/castro/white-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/castro/white-40.png -------------------------------------------------------------------------------- /assets/images/icons/pandora/black-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/pandora/black-40.png -------------------------------------------------------------------------------- /assets/images/icons/pandora/color-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/pandora/color-40.png -------------------------------------------------------------------------------- /assets/images/icons/pandora/white-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/pandora/white-40.png -------------------------------------------------------------------------------- /assets/images/icons/spotify/black-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/spotify/black-40.png -------------------------------------------------------------------------------- /assets/images/icons/spotify/color-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/spotify/color-40.png -------------------------------------------------------------------------------- /assets/images/icons/spotify/white-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/spotify/white-40.png -------------------------------------------------------------------------------- /assets/images/icons/tunein/black-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/tunein/black-100.png -------------------------------------------------------------------------------- /assets/images/icons/tunein/black-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/tunein/black-40.png -------------------------------------------------------------------------------- /assets/images/icons/tunein/color-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/tunein/color-100.png -------------------------------------------------------------------------------- /assets/images/icons/tunein/color-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/tunein/color-40.png -------------------------------------------------------------------------------- /assets/images/icons/tunein/white-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/tunein/white-100.png -------------------------------------------------------------------------------- /assets/images/icons/tunein/white-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/tunein/white-40.png -------------------------------------------------------------------------------- /assets/images/podcast-block-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/podcast-block-preview.png -------------------------------------------------------------------------------- /assets/images/icons/overcast/black-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/overcast/black-100.png -------------------------------------------------------------------------------- /assets/images/icons/overcast/black-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/overcast/black-40.png -------------------------------------------------------------------------------- /assets/images/icons/overcast/color-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/overcast/color-100.png -------------------------------------------------------------------------------- /assets/images/icons/overcast/color-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/overcast/color-40.png -------------------------------------------------------------------------------- /assets/images/icons/overcast/white-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/overcast/white-100.png -------------------------------------------------------------------------------- /assets/images/icons/overcast/white-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/overcast/white-40.png -------------------------------------------------------------------------------- /assets/images/icons/pandora/black-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/pandora/black-100.png -------------------------------------------------------------------------------- /assets/images/icons/pandora/color-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/pandora/color-100.png -------------------------------------------------------------------------------- /assets/images/icons/pandora/white-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/pandora/white-100.png -------------------------------------------------------------------------------- /assets/images/icons/playerfm/black-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/playerfm/black-100.png -------------------------------------------------------------------------------- /assets/images/icons/playerfm/black-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/playerfm/black-40.png -------------------------------------------------------------------------------- /assets/images/icons/playerfm/color-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/playerfm/color-100.png -------------------------------------------------------------------------------- /assets/images/icons/playerfm/color-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/playerfm/color-40.png -------------------------------------------------------------------------------- /assets/images/icons/playerfm/white-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/playerfm/white-100.png -------------------------------------------------------------------------------- /assets/images/icons/playerfm/white-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/playerfm/white-40.png -------------------------------------------------------------------------------- /assets/images/icons/spotify/black-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/spotify/black-100.png -------------------------------------------------------------------------------- /assets/images/icons/spotify/color-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/spotify/color-100.png -------------------------------------------------------------------------------- /assets/images/icons/spotify/white-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/spotify/white-100.png -------------------------------------------------------------------------------- /assets/images/icons/stitcher/black-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/stitcher/black-100.png -------------------------------------------------------------------------------- /assets/images/icons/stitcher/black-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/stitcher/black-40.png -------------------------------------------------------------------------------- /assets/images/icons/stitcher/color-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/stitcher/color-100.png -------------------------------------------------------------------------------- /assets/images/icons/stitcher/color-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/stitcher/color-40.png -------------------------------------------------------------------------------- /assets/images/icons/stitcher/white-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/stitcher/white-100.png -------------------------------------------------------------------------------- /assets/images/icons/stitcher/white-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/stitcher/white-40.png -------------------------------------------------------------------------------- /assets/images/podcast-block-preview@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/podcast-block-preview@2x.png -------------------------------------------------------------------------------- /tests/cypress/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "plugin:cypress/recommended", 3 | "rules": { 4 | "jest/expect-expect": "off", 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /assets/images/icons/pocket-casts/black-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/pocket-casts/black-40.png -------------------------------------------------------------------------------- /assets/images/icons/pocket-casts/color-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/pocket-casts/color-40.png -------------------------------------------------------------------------------- /assets/images/icons/pocket-casts/white-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/pocket-casts/white-40.png -------------------------------------------------------------------------------- /assets/images/icons/apple-podcasts/black-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/apple-podcasts/black-40.png -------------------------------------------------------------------------------- /assets/images/icons/apple-podcasts/color-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/apple-podcasts/color-40.png -------------------------------------------------------------------------------- /assets/images/icons/apple-podcasts/white-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/apple-podcasts/white-40.png -------------------------------------------------------------------------------- /assets/images/icons/pocket-casts/black-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/pocket-casts/black-100.png -------------------------------------------------------------------------------- /assets/images/icons/pocket-casts/color-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/pocket-casts/color-100.png -------------------------------------------------------------------------------- /assets/images/icons/pocket-casts/white-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/pocket-casts/white-100.png -------------------------------------------------------------------------------- /assets/images/icons/apple-podcasts/black-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/apple-podcasts/black-100.png -------------------------------------------------------------------------------- /assets/images/icons/apple-podcasts/color-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/apple-podcasts/color-100.png -------------------------------------------------------------------------------- /assets/images/icons/apple-podcasts/white-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/apple-podcasts/white-100.png -------------------------------------------------------------------------------- /assets/images/icons/google-podcasts/black-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/google-podcasts/black-100.png -------------------------------------------------------------------------------- /assets/images/icons/google-podcasts/black-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/google-podcasts/black-40.png -------------------------------------------------------------------------------- /assets/images/icons/google-podcasts/color-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/google-podcasts/color-100.png -------------------------------------------------------------------------------- /assets/images/icons/google-podcasts/color-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/google-podcasts/color-40.png -------------------------------------------------------------------------------- /assets/images/icons/google-podcasts/white-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/google-podcasts/white-100.png -------------------------------------------------------------------------------- /assets/images/icons/google-podcasts/white-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10up/simple-podcasting/HEAD/assets/images/icons/google-podcasts/white-40.png -------------------------------------------------------------------------------- /tests/cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "types": ["cypress"] 5 | }, 6 | "include": ["**/*.*"] 7 | } 8 | -------------------------------------------------------------------------------- /assets/css/podcasting-transcript.css: -------------------------------------------------------------------------------- 1 | .wp-block-podcasting-podcast-transcript cite, 2 | .wp-block-podcasting-podcast-transcript time { 3 | display: block; 4 | } 5 | -------------------------------------------------------------------------------- /includes/blocks/podcast-transcript/styles.css: -------------------------------------------------------------------------------- 1 | .wp-block-podcasting-podcast-transcript cite, 2 | .wp-block-podcasting-podcast-transcript time { 3 | display: block; 4 | } 5 | -------------------------------------------------------------------------------- /tests/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /.phpcs.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | . 5 | dist/ 6 | vendor/ 7 | tests/ 8 | 9 | -------------------------------------------------------------------------------- /assets/css/podcasting-editor-screen.css: -------------------------------------------------------------------------------- 1 | .components-input-control, 2 | .components-base-control { 3 | width: 100%; 4 | } 5 | .cover-art-container { 6 | display: flex; 7 | flex-direction: column; 8 | justify-content: center; 9 | align-items: center; 10 | } 11 | .cover-art-container button { 12 | margin: 10px 0; 13 | } 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | indent_style = tab 9 | 10 | [{*.json,*.yml,.babelrc,.bowerrc,.postcssrc}] 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [*.txt,wp-config-sample.php] 15 | end_of_line = crlf 16 | -------------------------------------------------------------------------------- /tests/cypress/integration/admin.test.js: -------------------------------------------------------------------------------- 1 | describe('Admin can login and make sure plugin is activated', () => { 2 | beforeEach(() => { 3 | cy.login(); 4 | }); 5 | 6 | it('Can activate plugin if it is deactivated', () => { 7 | cy.deactivatePlugin('simple-podcasting'); 8 | cy.activatePlugin('simple-podcasting'); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /includes/blocks/podcast-transcript/index.js: -------------------------------------------------------------------------------- 1 | import { registerBlockType } from '@wordpress/blocks'; 2 | import { InnerBlocks } from '@wordpress/block-editor'; 3 | import './styles.css'; 4 | 5 | import Edit from './edit'; 6 | 7 | import './cite'; 8 | import './time'; 9 | 10 | registerBlockType('podcasting/podcast-transcript', { 11 | edit: Edit, 12 | save: () => , 13 | }); 14 | -------------------------------------------------------------------------------- /.distignore: -------------------------------------------------------------------------------- 1 | # Directories 2 | /.git 3 | /.github 4 | /.husky 5 | /.wordpress-org 6 | /assets 7 | /gulp-tasks 8 | /node_modules 9 | /tests 10 | /vendor 11 | 12 | # Files 13 | .* 14 | /CHANGELOG.md 15 | /CODE_OF_CONDUCT.md 16 | /composer.json 17 | /composer.lock 18 | /CONTRIBUTING.md 19 | /CREDITS.md 20 | /gulpfile.babel.js 21 | /LICENSE.md 22 | /package.json 23 | /package-lock.json 24 | /phpunit.xml.dist 25 | /README.md 26 | /webpack.config.js 27 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in the repo. Unless a later match takes precedence, @10up/open-source-practice, as primary maintainers will be requested for review when someone opens a Pull Request. 2 | * @10up/open-source-practice 3 | 4 | # GitHub and WordPress.org specifics 5 | /.github/ @jeffpaul 6 | /.wordpress-org/ @jeffpaul 7 | CODE_OF_CONDUCT.md @jeffpaul 8 | LICENSE.md @jeffpaul 9 | -------------------------------------------------------------------------------- /.github/workflows/wordpress-version-checker.yml: -------------------------------------------------------------------------------- 1 | name: "WordPress version checker" 2 | 3 | on: 4 | push: 5 | branches: 6 | - develop 7 | - trunk 8 | pull_request: 9 | branches: 10 | - develop 11 | schedule: 12 | - cron: '0 0 * * 1' 13 | 14 | permissions: 15 | issues: write 16 | 17 | jobs: 18 | wordpress-version-checker: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: WordPress version checker 22 | uses: skaut/wordpress-version-checker@9d247334f5b30202cb9c1f4aee74c52f37399f69 # v2.2.3 23 | with: 24 | repo-token: ${{ secrets.GITHUB_TOKEN }} 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | languages 4 | release 5 | vendor 6 | phpunit.xml 7 | .idea 8 | .phpunit.result.cache 9 | 10 | # Project Files 11 | dist 12 | ruleset.xml 13 | 14 | # Editors 15 | *.esproj 16 | *.tmproj 17 | *.tmproject 18 | tmtags 19 | .*.sw[a-z] 20 | *.un~ 21 | Session.vim 22 | *.swp 23 | *.csv 24 | 25 | # Mac OSX 26 | .DS_Store 27 | ._* 28 | .Spotlight-V100 29 | .Trashes 30 | 31 | # Windows 32 | Thumbs.db 33 | Desktop.ini 34 | 35 | # E2E testing 36 | .wp-env.override.json 37 | artifacts 38 | tests/cypress/downloads 39 | tests/cypress/screenshots 40 | tests/cypress/videos 41 | tests/cypress/reports 42 | -------------------------------------------------------------------------------- /includes/upgrade.php: -------------------------------------------------------------------------------- 1 | =' ) ) { 18 | flush_rewrite_rules(); 19 | update_option( 'simple_podcasting_db_version', PODCASTING_VERSION ); 20 | } 21 | } 22 | 23 | add_filter( 'admin_init', __NAMESPACE__ . '\\maybe_flush_rewrite', 10, 1 ); 24 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests/unit 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | import '@10up/cypress-wp-utils'; 17 | import 'cypress-file-upload'; 18 | -------------------------------------------------------------------------------- /.wordpress-org/blueprints/blueprint.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://playground.wordpress.net/blueprint-schema.json", 3 | "landingPage": "\/wp-admin\/admin.php?page=simple-podcasting-onboarding&step=1", 4 | "preferredVersions": { 5 | "php": "7.4", 6 | "wp": "latest" 7 | }, 8 | "phpExtensionBundles": ["kitchen-sink"], 9 | "features": { 10 | "networking": true 11 | }, 12 | "steps": [ 13 | { 14 | "step": "login", 15 | "username": "admin", 16 | "password": "password" 17 | }, 18 | { 19 | "step": "installPlugin", 20 | "pluginZipFile": { 21 | "resource": "wordpress.org\/plugins", 22 | "slug": "simple-podcasting" 23 | }, 24 | "options": { 25 | "activate": true 26 | } 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /assets/js/onboarding.js: -------------------------------------------------------------------------------- 1 | import '../css/podcasting-onboarding.scss'; 2 | 3 | ( function( $ ) { 4 | $( function() { 5 | const selectImageBtn = $( '#simple-podcasting__upload-cover-image' ); 6 | const coverImage = $( 'input[name="podcast-cover-image-id"]' ); 7 | const coverImagePreview = $( '#simple-podcasting__cover-image-preview' ); 8 | let uploader_frame = null; 9 | 10 | /** Upload image button handler */ 11 | selectImageBtn.on( 'click', function() { 12 | uploader_frame = wp.media( { 13 | multiple: false, 14 | library: { 15 | type: 'image' 16 | } 17 | } ).on( 'select', function() { 18 | const { id, url } = uploader_frame.state().get( 'selection' ).first().toJSON(); 19 | coverImagePreview.html( `` ) 20 | coverImage.val( id ); 21 | } ); 22 | 23 | uploader_frame.open(); 24 | } ); 25 | } ) 26 | } )( jQuery ) -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "10up/simple-podcasting", 3 | "description": "A simple podcasting solution for WordPress. ", 4 | "homepage": "https://github.com/10up/simple-podcasting", 5 | "license": "GPL-2.0-or-later", 6 | "authors": [ 7 | { 8 | "name": "10up", 9 | "email": "opensource@10up.com", 10 | "homepage": "https://10up.com" 11 | } 12 | ], 13 | "support": { 14 | "issues": "https://github.com/10up/simple-podcasting/issues" 15 | }, 16 | "require": { 17 | "php": ">=7.3" 18 | }, 19 | "require-dev": { 20 | "10up/phpcs-composer": "^3.0", 21 | "10up/wp_mock": "^0.4.2", 22 | "phpunit/phpunit": "^9.5", 23 | "phpcompatibility/php-compatibility": "dev-develop as 9.99.99" 24 | }, 25 | "config": { 26 | "allow-plugins": { 27 | "dealerdirect/phpcodesniffer-composer-installer": true 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.github/workflows/phpcs.yml: -------------------------------------------------------------------------------- 1 | name: PHPCS 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | push: 8 | branches: 9 | - develop 10 | - trunk 11 | paths: 12 | - "**.php" 13 | pull_request: 14 | branches: 15 | - develop 16 | paths: 17 | - "**.php" 18 | 19 | jobs: 20 | phpcs: 21 | runs-on: ubuntu-latest 22 | 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 26 | 27 | - name: Set PHP version 28 | uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 29 | with: 30 | php-version: '7.4' 31 | coverage: none 32 | tools: composer:v2 33 | 34 | - name: Install dependencies 35 | run: composer install 36 | 37 | - name: Test 38 | run: ./vendor/bin/phpcs --runtime-set testVersion 7.4 . 39 | -------------------------------------------------------------------------------- /.github/workflows/repo-automator.yml: -------------------------------------------------------------------------------- 1 | name: 'Repo Automator' 2 | 3 | permissions: 4 | contents: read 5 | issues: write 6 | 7 | on: 8 | issues: 9 | types: 10 | - opened 11 | push: 12 | branches: 13 | - develop 14 | pull_request: 15 | types: 16 | - opened 17 | - edited 18 | - synchronize 19 | - converted_to_draft 20 | - ready_for_review 21 | branches: 22 | - develop 23 | 24 | jobs: 25 | Validate: 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: 10up/action-repo-automator@280f5dc0b4ed1b5c50c816e08623bdefce55cdce # v2.1.3 29 | with: 30 | fail-label: needs:feedback 31 | pass-label: needs:code-review 32 | conflict-label: needs:refresh 33 | reviewers: | 34 | team:open-source-practice 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 37 | -------------------------------------------------------------------------------- /.github/workflows/push-asset-readme-update.yml: -------------------------------------------------------------------------------- 1 | name: Plugin asset/readme update 2 | 3 | on: 4 | push: 5 | branches: 6 | - trunk 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | trunk: 13 | name: Push to trunk 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout code 18 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 19 | 20 | - name: install node 21 | uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 22 | with: 23 | node-version-file: .nvmrc 24 | 25 | - name: Build 26 | run: | 27 | npm ci 28 | npm run build 29 | 30 | - name: WordPress.org plugin asset/readme update 31 | uses: 10up/action-wordpress-plugin-asset-update@2480306f6f693672726d08b5917ea114cb2825f7 # v2.2.0 32 | env: 33 | SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} 34 | SVN_USERNAME: ${{ secrets.SVN_USERNAME }} 35 | -------------------------------------------------------------------------------- /assets/css/podcasting-edit-term.css: -------------------------------------------------------------------------------- 1 | .taxonomy-podcasting_podcasts .term-parent-wrap { 2 | display: none; 3 | } 4 | .podcast-image-thumbnail { 5 | max-width: 300px; 6 | max-height: 200px; 7 | } 8 | 9 | .column-podcasting_image img { 10 | height: auto; 11 | max-width: 100%; 12 | width: 75px; 13 | } 14 | 15 | .simple_podcasting__platforms img { 16 | display: block; 17 | max-width: 42px; 18 | margin: 0 auto; 19 | height: auto; 20 | } 21 | 22 | .simple_podcasting__platforms th { 23 | padding: 15px 10px; 24 | text-align: center; 25 | } 26 | 27 | .simple_podcasting__platforms td { 28 | vertical-align: middle; 29 | padding: 15px 10px; 30 | } 31 | 32 | .simple_podcasting__platforms-url { 33 | min-width: 220px; 34 | } 35 | 36 | .simple_podcasting__platforms-icon { 37 | transition: background-color 0.2s ease-out; 38 | } 39 | 40 | .simple_podcasting__platforms-icon--darken-bg { 41 | background-color: rgb(28 52 59 / 22%); 42 | transition: background-color 0.2s ease-in; 43 | } 44 | -------------------------------------------------------------------------------- /includes/admin/views/onboarding-header.php: -------------------------------------------------------------------------------- 1 | 9 |
10 |
11 | 14 |
15 | 16 |
17 |
18 | 19 |
20 | 21 |
22 | 23 |
24 | 25 |
26 |
27 | -------------------------------------------------------------------------------- /assets/js/blocks/podcast-platforms/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Internal block libraries 3 | */ 4 | import { __ } from '@wordpress/i18n'; 5 | import { registerBlockType } from '@wordpress/blocks'; 6 | 7 | import Edit from './edit'; 8 | import './index.scss'; 9 | 10 | /** 11 | * Register Podcast Platforms block 12 | */ 13 | export default registerBlockType( 14 | 'podcasting/podcast-platforms', 15 | { 16 | title: __( 'Podcast Platforms', 'simple-podcasting' ), 17 | description: __( 'Displays the list of platforms where the selected show is available.', 'simple-podcasting' ), 18 | category: 'common', 19 | icon: 'microphone', 20 | supports: { 21 | multiple: false, 22 | }, 23 | attributes: { 24 | showId: { 25 | type: 'number', 26 | default: 0, 27 | }, 28 | iconSize: { 29 | type: 'number', 30 | default: 48, 31 | }, 32 | align: { 33 | type: 'string', 34 | default: 'center', 35 | } 36 | }, 37 | 38 | edit: Edit, 39 | 40 | save: () => null, 41 | }, 42 | ); 43 | -------------------------------------------------------------------------------- /assets/js/transforms.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | const { select } = wp.data; 5 | const { createBlock } = wp.blocks; 6 | 7 | /** 8 | * Transforms 9 | */ 10 | const transforms = { 11 | from: [ 12 | { 13 | type: 'block', 14 | blocks: [ 'core/audio' ], 15 | transform: ( attributes ) => { 16 | return createBlock( 'podcasting/podcast', { 17 | id: attributes.id, 18 | src: attributes.src 19 | } ); 20 | }, 21 | }, 22 | ], 23 | to: [ 24 | { 25 | type: 'block', 26 | blocks: [ 'core/audio' ], 27 | isMatch: ( { id } ) => { 28 | if ( ! id ) { 29 | return false; 30 | } 31 | const { getMedia } = select( 'core' ); 32 | const media = getMedia( id ); 33 | return !! media && media.mime_type.includes( 'audio' ); 34 | }, 35 | transform: ( attributes ) => { 36 | return createBlock( 'core/audio', { 37 | src: attributes.src, 38 | id: attributes.id 39 | } ); 40 | }, 41 | }, 42 | ], 43 | 44 | }; 45 | 46 | export default transforms; 47 | -------------------------------------------------------------------------------- /includes/blocks/podcast-transcript/markup.php: -------------------------------------------------------------------------------- 1 | 16 |
> 17 | %s

', 29 | esc_url( get_transcript_link_from_post( get_post() ) ), 30 | esc_html( $attributes['linkText'] ) 31 | ); 32 | break; 33 | } 34 | ?> 35 |
36 | 37 | -------------------------------------------------------------------------------- /tests/bin/set-wp-config.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const fs = require('fs'); 4 | 5 | const path = `${process.cwd()}/.wp-env.override.json`; 6 | 7 | let config = fs.existsSync(path) ? require(path) : { plugins: ['.'] }; 8 | 9 | const args = {}; 10 | process.argv.slice(2, process.argv.length).forEach((arg) => { 11 | if (arg.slice(0, 2) === '--') { 12 | const param = arg.split('='); 13 | const paramName = param[0].slice(2, param[0].length); 14 | const paramValue = param.length > 1 ? param[1] : true; 15 | args[paramName] = paramValue; 16 | } 17 | }); 18 | 19 | if (!args.core && !args.plugins) { 20 | return; 21 | } 22 | 23 | if ('latest' === args.core) { 24 | delete args.core; 25 | } 26 | 27 | if (Object.keys(args).length === 0) { 28 | return; 29 | } 30 | 31 | if (args.plugins) { 32 | args.plugins = args.plugins.split(','); 33 | } 34 | 35 | config = { 36 | ...config, 37 | ...args, 38 | }; 39 | 40 | try { 41 | fs.writeFileSync(path, JSON.stringify(config)); 42 | } catch (err) { 43 | console.error(err); 44 | } 45 | -------------------------------------------------------------------------------- /assets/js/podcasting-edit-post.js: -------------------------------------------------------------------------------- 1 | /*global jQuery */ 2 | jQuery( document ).ready( function( $ ) { 3 | $( '#podcasting-enclosure-button' ).click( function( e ) { 4 | e.preventDefault(); 5 | 6 | var $this = $( this ), 7 | $input = $( 'input#podcasting-enclosure-url' ), 8 | mediaUploader; 9 | 10 | // If the uploader object has already been created, reopen the dialog. 11 | if ( mediaUploader ) { 12 | mediaUploader.open(); 13 | return; 14 | } 15 | 16 | // eslint-disable-next-line camelcase 17 | mediaUploader = wp.media.frames.file_frame = wp.media( { 18 | title: $this.data( 'modalTitle' ), 19 | button: { 20 | text: $this.data( 'modalButton' ) 21 | }, 22 | library: { 23 | type: 'audio' 24 | }, 25 | multiple: false 26 | }); 27 | 28 | mediaUploader.off( 'select' ); 29 | mediaUploader.on( 'select', function() { 30 | var attachment = mediaUploader.state().get('selection').first(); 31 | 32 | $input.val( attachment.get('url') ); 33 | }); 34 | 35 | mediaUploader.open(); 36 | } ); 37 | } ); 38 | -------------------------------------------------------------------------------- /assets/js/blocks/latest-episode/index.scss: -------------------------------------------------------------------------------- 1 | .podcasting-latest-episode { 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: end; 5 | min-height: 20rem; 6 | overflow: hidden; 7 | position: relative; 8 | 9 | & .wp-block-post-featured-image { 10 | height: 100%; 11 | object-fit: fill; 12 | object-position: center; 13 | position: absolute; 14 | width: 100%; 15 | 16 | &::after { 17 | background-color: rgb(0 0 0 / 75%); 18 | content: ""; 19 | display: block; 20 | height: 100%; 21 | left: 0; 22 | position: absolute; 23 | top: 0; 24 | width: 100%; 25 | } 26 | } 27 | } 28 | 29 | .podcasting-latest-episode__content { 30 | color: #fff; 31 | padding: 3rem; 32 | position: relative; 33 | z-index: 1; 34 | 35 | @media (min-width: 768px) { 36 | padding: 3rem; 37 | } 38 | 39 | & .wp-block-post-excerpt, 40 | & .wp-block-post-excerpt__more-text { 41 | margin-top: 0.25rem; 42 | } 43 | 44 | & .wp-block-post-excerpt__more-link { 45 | color: #fff; 46 | } 47 | } 48 | 49 | .editor-styles-wrapper .wp-block-post-content .podcasting-latest-episode__content .wp-block-post-excerpt__more-link:where(:not(.wp-element-button)) { 50 | color: #fff; 51 | } 52 | -------------------------------------------------------------------------------- /tests/unit/bootstrap.php: -------------------------------------------------------------------------------- 1 | { 11 | const blockProps = useBlockProps(); 12 | return ( 13 | setAttributes({ text: content })} 17 | allowedFormats={[]} 18 | withoutInteractiveFormatting 19 | onSplit={(value, isOriginal) => { 20 | let block; 21 | 22 | if (isOriginal || value) { 23 | block = createBlock('podcasting/podcast-transcript-cite', { 24 | ...attributes, 25 | content: value, 26 | }); 27 | } else { 28 | block = createBlock('core/paragraph'); 29 | } 30 | 31 | if (isOriginal) { 32 | block.clientId = clientId; 33 | } 34 | 35 | return block; 36 | }} 37 | onReplace={onReplace} 38 | {...blockProps} 39 | /> 40 | ); 41 | }; 42 | 43 | registerBlockType('podcasting/podcast-transcript-cite', { 44 | edit: Edit, 45 | save: ({ attributes: { text } }) => {text}, 46 | }); 47 | -------------------------------------------------------------------------------- /includes/blocks/podcast-transcript/time.js: -------------------------------------------------------------------------------- 1 | import { registerBlockType, createBlock } from '@wordpress/blocks'; 2 | import { useBlockProps, RichText } from '@wordpress/block-editor'; 3 | 4 | const Edit = ({ 5 | attributes, 6 | attributes: { text }, 7 | setAttributes, 8 | clientId, 9 | onReplace, 10 | }) => { 11 | const blockProps = useBlockProps(); 12 | return ( 13 | setAttributes({ text: content })} 17 | allowedFormats={[]} 18 | withoutInteractiveFormatting 19 | onSplit={(value, isOriginal) => { 20 | let block; 21 | 22 | if (isOriginal || value) { 23 | block = createBlock('podcasting/podcast-transcript-time', { 24 | ...attributes, 25 | content: value, 26 | }); 27 | } else { 28 | block = createBlock('core/paragraph'); 29 | } 30 | 31 | if (isOriginal) { 32 | block.clientId = clientId; 33 | } 34 | 35 | return block; 36 | }} 37 | onReplace={onReplace} 38 | {...blockProps} 39 | /> 40 | ); 41 | }; 42 | 43 | registerBlockType('podcasting/podcast-transcript-time', { 44 | edit: Edit, 45 | save: ({ attributes: { text } }) => , 46 | }); 47 | -------------------------------------------------------------------------------- /tests/cypress/config.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('cypress'); 2 | 3 | module.exports = defineConfig({ 4 | fixturesFolder: __dirname + '/fixtures', 5 | screenshotsFolder: __dirname + '/screenshots', 6 | videosFolder: __dirname + '/videos', 7 | downloadsFolder: __dirname + '/downloads', 8 | video: true, 9 | reporter: 'mochawesome', 10 | reporterOptions: { 11 | mochaFile: 'mochawesome-[name]', 12 | reportDir: __dirname + '/reports', 13 | overwrite: false, 14 | html: false, 15 | json: true, 16 | }, 17 | chromeWebSecurity: false, 18 | env: { 19 | HAS_BLOCK_EDITOR: true, 20 | }, 21 | e2e: { 22 | // We've imported your old cypress plugins here. 23 | // You may want to clean this up later by importing these. 24 | setupNodeEvents(on, config) { 25 | return require(__dirname + '/plugins/index.js')(on, config); 26 | }, 27 | supportFile: __dirname + '/support/index.js', 28 | specPattern: [ 29 | 'tests/cypress/integration/admin.test.js', 30 | 'tests/cypress/integration/onboarding.test.js', 31 | 'tests/cypress/integration/taxonomy.test.js', 32 | 'tests/cypress/integration/block.test.js', 33 | 'tests/cypress/integration/podcast-setting-panel.test.js', 34 | ], 35 | }, 36 | }); 37 | -------------------------------------------------------------------------------- /tests/cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************************** 3 | // This example plugins/index.js can be used to load plugins 4 | // 5 | // You can change the location of this file or turn off loading 6 | // the plugins file with the 'pluginsFile' configuration option. 7 | // 8 | // You can read more here: 9 | // https://on.cypress.io/plugins-guide 10 | // *********************************************************** 11 | 12 | // This function is called when a project is opened or re-opened (e.g. due to 13 | // the project's config changing) 14 | 15 | const { loadConfig } = require('@wordpress/env/lib/config'); 16 | const getCacheDirectory = require('@wordpress/env/lib/config/get-cache-directory'); 17 | 18 | /** 19 | * @type {Cypress.PluginConfig} 20 | */ 21 | // eslint-disable-next-line no-unused-vars 22 | module.exports = async (on, config) => { 23 | const cacheDirectory = await getCacheDirectory(); 24 | const wpEnvConfig = await loadConfig(cacheDirectory); 25 | 26 | if (wpEnvConfig) { 27 | const port = wpEnvConfig.env.tests.port || null; 28 | 29 | if (port) { 30 | config.baseUrl = wpEnvConfig.env.tests.config.WP_SITEURL; 31 | } 32 | } 33 | 34 | return config; 35 | }; 36 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | # Dependency Review Action 2 | # 3 | # This Action will scan dependency manifest files that change as part of a Pull Reqest, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. 4 | # 5 | # Source repository: https://github.com/actions/dependency-review-action 6 | # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement 7 | name: 'Dependency Review' 8 | on: [pull_request] 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | dependency-review: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: 'Checkout Repository' 18 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 19 | 20 | - name: Dependency Review 21 | uses: actions/dependency-review-action@72eb03d02c7872a771aacd928f3123ac62ad6d3a # v4.3.3 22 | with: 23 | license-check: true 24 | vulnerability-check: false 25 | config-file: 10up/.github/.github/dependency-review-config.yml@trunk 26 | -------------------------------------------------------------------------------- /includes/admin/create-podcast-component.php: -------------------------------------------------------------------------------- 1 | id ) ) { 29 | return; 30 | } 31 | 32 | wp_enqueue_script( 33 | 'podcasting_create_podcast_show_plugin', 34 | PODCASTING_URL . 'dist/create-podcast-show.js', 35 | array(), 36 | PODCASTING_VERSION, 37 | true 38 | ); 39 | 40 | wp_localize_script( 41 | 'podcasting_create_podcast_show_plugin', 42 | 'podcastingShowPluginVars', 43 | array( 44 | 'categories' => \tenup_podcasting\get_podcasting_categories_options(), 45 | ) 46 | ); 47 | } 48 | } 49 | 50 | new Create_Podcast_Component(); 51 | -------------------------------------------------------------------------------- /templates/transcript.php: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 22 | 23 | <?php 24 | printf( 25 | /* translators: %s: The page title */ 26 | esc_html__( 'Transcript - %s', 'simple-podcasting' ), 27 | wp_strip_all_tags( get_the_title() ) // phpcs:ignore WordPress.Security.EscapeOutput 28 | ); 29 | ?> 30 | 31 | 32 | 33 | ID, 'podcast_transcript', true ) 40 | ) 41 | ); 42 | } 43 | ?> 44 | 45 | 46 | -------------------------------------------------------------------------------- /.github/workflows/push-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to WordPress.org 2 | 3 | permissions: 4 | contents: write 5 | packages: read 6 | actions: write 7 | 8 | on: 9 | release: 10 | types: [published] 11 | 12 | jobs: 13 | tag: 14 | name: New release 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout code 19 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 20 | 21 | - name: install node 22 | uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 23 | with: 24 | node-version-file: .nvmrc 25 | 26 | - name: Build 27 | run: | 28 | npm ci 29 | npm run build 30 | npm run makepot 31 | 32 | - name: WordPress Plugin Deploy 33 | id: deploy 34 | uses: 10up/action-wordpress-plugin-deploy@54bd289b8525fd23a5c365ec369185f2966529c2 # v2.3.0 35 | with: 36 | generate-zip: true 37 | env: 38 | SVN_USERNAME: ${{ secrets.SVN_USERNAME }} 39 | SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} 40 | 41 | - name: Upload release asset 42 | uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2.2.1 43 | env: 44 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 45 | with: 46 | files: ${{ github.workspace }}/${{ github.event.repository.name }}.zip 47 | -------------------------------------------------------------------------------- /.github/workflows/build-release-zip.yml: -------------------------------------------------------------------------------- 1 | name: Build release zip 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | workflow_dispatch: 8 | workflow_call: 9 | push: 10 | branches: 11 | - trunk 12 | 13 | jobs: 14 | build: 15 | name: Build release zip 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 21 | 22 | - name: Cache node_modules 23 | id: cache-node-modules 24 | uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 25 | env: 26 | cache-name: cache-node-modules 27 | with: 28 | path: node_modules 29 | key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} 30 | 31 | - name: Setup node version and npm cache 32 | uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 33 | with: 34 | node-version-file: '.nvmrc' 35 | cache: 'npm' 36 | 37 | - name: Install Node dependencies 38 | if: steps.cache-node-modules.outputs.cache-hit != 'true' 39 | run: npm ci --no-optional 40 | 41 | - name: Build plugin 42 | run: npm run build 43 | 44 | - name: Generate ZIP file 45 | uses: 10up/action-wordpress-plugin-build-zip@b9e621e1261ccf51592b6f3943e4dc4518fca0d1 # v1.0.2 46 | -------------------------------------------------------------------------------- /tests/unit/test-transcript.php: -------------------------------------------------------------------------------- 1 | post_name = 'latest-podcast'; 29 | $terms = [ new stdClass() ]; 30 | $terms[0]->term_id = 100; 31 | 32 | \WP_Mock::userFunction( 'get_post' )->andReturn( $post ); 33 | \WP_Mock::userFunction( 'get_the_terms' )->andReturn( $terms ); 34 | \WP_Mock::userFunction( 'get_term_link' )->andReturn( 'https://simple-podcasting.test/podcasts/test-podcast/' ); 35 | \WP_Mock::userFunction( 'trailingslashit' )->andReturnUsing( function( $url ) { 36 | return rtrim( $url, '/\\' ) . '/'; 37 | } ); 38 | 39 | $this->assertSame( 40 | tenup_podcasting\transcripts\get_transcript_link_from_post( $post ), 41 | 'https://simple-podcasting.test/podcasts/test-podcast/latest-podcast/transcript/' 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/unit/test-rest-external-url.php: -------------------------------------------------------------------------------- 1 | shouldReceive( 'offsetGet' ) 32 | ->with( 'url' ) 33 | ->andReturn( $url ); 34 | 35 | $mock_request->shouldReceive( 'offsetExists' ) 36 | ->with( 'url' ) 37 | ->andReturn( true ); 38 | 39 | $cache_key = 'spc_external_url_' . $url; 40 | 41 | \WP_Mock::userFunction( 'get_transient' ) 42 | ->with( $cache_key ) 43 | ->andReturn( 'Podcast Meta' ); 44 | 45 | \WP_Mock::passthruFunction( 'rest_ensure_response' ); 46 | 47 | $response = array( 48 | 'success' => true, 49 | 'data' => 'Podcast Meta', 50 | ); 51 | 52 | $this->assertSame( 53 | $response, 54 | tenup_podcasting\endpoints\externalurl\handle_request( $mock_request ), 55 | 'handle_request() should return cached result' 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /.github/workflows/php-compatibility.yml: -------------------------------------------------------------------------------- 1 | name: PHP Compatibility 2 | 3 | permissions: 4 | contents: read 5 | 6 | env: 7 | COMPOSER_VERSION: "2" 8 | COMPOSER_CACHE: "${{ github.workspace }}/.composer-cache" 9 | 10 | on: 11 | push: 12 | branches: 13 | - develop 14 | - trunk 15 | pull_request: 16 | branches: 17 | - develop 18 | 19 | jobs: 20 | php_compatibility: 21 | name: PHP ${{ matrix.php }} 22 | runs-on: ubuntu-latest 23 | 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 27 | 28 | - name: Set standard 10up cache directories 29 | run: | 30 | composer config -g cache-dir "${{ env.COMPOSER_CACHE }}" 31 | 32 | - name: Prepare composer cache 33 | uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 34 | with: 35 | path: ${{ env.COMPOSER_CACHE }} 36 | key: composer-${{ env.COMPOSER_VERSION }}-${{ hashFiles('**/composer.lock') }} 37 | restore-keys: | 38 | composer-${{ env.COMPOSER_VERSION }}- 39 | 40 | - name: Set PHP version 41 | uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 42 | with: 43 | php-version: '7.4' 44 | coverage: none 45 | tools: prestissimo, composer:v2 46 | 47 | - name: Install dependencies 48 | run: composer install 49 | 50 | - name: Check PHP Compatibility 51 | run: ./vendor/bin/phpcs -p simple-podcasting.php includes --standard=PHPCompatibilityWP --extensions=php --runtime-set testVersion 7.4- 52 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const defaultConfig = require('@wordpress/scripts/config/webpack.config'); 2 | const CopyPlugin = require('copy-webpack-plugin'); 3 | const path = require('path'); 4 | 5 | module.exports = { 6 | ...defaultConfig, 7 | output: { 8 | ...defaultConfig.output, 9 | path: path.resolve(process.cwd(), 'dist'), 10 | }, 11 | entry: { 12 | blocks: path.resolve(process.cwd(), 'assets/js', 'blocks.js'), 13 | 'podcasting-edit-post': path.resolve( 14 | process.cwd(), 15 | 'assets/js', 16 | 'podcasting-edit-post.js' 17 | ), 18 | 'podcasting-edit-term': path.resolve( 19 | process.cwd(), 20 | 'assets/js', 21 | 'podcasting-edit-term.js' 22 | ), 23 | 'podcast-platforms-block': path.resolve( 24 | process.cwd(), 25 | 'assets/js/blocks/podcast-platforms', 26 | 'index.js' 27 | ), 28 | 'podcasting-onboarding': path.resolve( 29 | process.cwd(), 30 | 'assets/js', 31 | 'onboarding.js' 32 | ), 33 | 'podcasting-transcript': path.resolve( 34 | process.cwd(), 35 | 'includes/blocks/podcast-transcript', 36 | 'index.js' 37 | ), 38 | 'create-podcast-show': path.resolve( 39 | process.cwd(), 40 | 'assets/js', 41 | 'create-podcast-show.js' 42 | ), 43 | 'latest-episode': path.resolve( 44 | process.cwd(), 45 | 'assets/js/blocks/latest-episode', 46 | 'index.js' 47 | ), 48 | 'podcast': path.resolve( 49 | process.cwd(), 50 | 'assets/js/blocks/podcast', 51 | 'index.js' 52 | ), 53 | }, 54 | plugins: [ 55 | ...defaultConfig.plugins, 56 | new CopyPlugin({ 57 | patterns: [ 58 | { from: 'assets/images/*', to: './' }, 59 | { from: 'assets/images/icons', to: './images/icons' }, 60 | ], 61 | }), 62 | ], 63 | }; 64 | -------------------------------------------------------------------------------- /assets/js/blocks/podcast-platforms/index.scss: -------------------------------------------------------------------------------- 1 | .wp-block { 2 | .simple-podcasting__podcasting-platform-list { 3 | margin-bottom: 3rem; 4 | } 5 | 6 | .simple-podcasting__podcast-platforms { 7 | padding: 2.5rem 1rem 1rem 1rem; 8 | } 9 | } 10 | 11 | .simple-podcasting { 12 | &__podcast-platforms { 13 | padding: 1rem 0 1rem 0; 14 | } 15 | 16 | &__podcast-search-results { 17 | cursor: pointer; 18 | } 19 | 20 | &__select-show-popover { 21 | max-width: 400px; 22 | width: 100%; 23 | 24 | .components-popover__content { 25 | width: 100%; 26 | padding: 1rem; 27 | } 28 | } 29 | 30 | &__podcasting-platform-list { 31 | display: flex; 32 | flex-flow: row wrap; 33 | 34 | &--left { 35 | justify-content: start; 36 | } 37 | 38 | &--center { 39 | justify-content: center; 40 | } 41 | 42 | &--right { 43 | justify-content: end; 44 | } 45 | 46 | a { 47 | text-decoration: none !important; 48 | } 49 | 50 | img { 51 | display: block; 52 | 53 | @for $i from 1 through 6 { 54 | &.simple-pocasting__icon-size--#{$i * 16} { 55 | max-width: #{$i * 16}px; 56 | } 57 | } 58 | } 59 | } 60 | 61 | &__podcasting-platform-list-item { 62 | display: flex; 63 | align-self: center; 64 | padding: 0.75rem; 65 | 66 | @media screen and ( max-width: 480px ) { 67 | justify-content: center; 68 | width: 25%; 69 | } 70 | } 71 | 72 | &__podcasting-search-controls { 73 | position: relative; 74 | 75 | input[type="search"] { 76 | font-size: 1rem; 77 | } 78 | } 79 | 80 | &__podcasting-search-results { 81 | position: absolute; 82 | border: 1px solid; 83 | background-color: #fff; 84 | min-width: 200px; 85 | z-index: 10; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /assets/js/blocks/podcast/index.scss: -------------------------------------------------------------------------------- 1 | .wp-block-podcasting-podcast-outer { 2 | border: 1px solid #707070; 3 | border-radius: 4px; 4 | padding: 20px; 5 | } 6 | 7 | .wp-block-podcasting-podcast__container { 8 | margin-bottom: 10px; 9 | 10 | @media (min-width: 768px) { 11 | display: flex; 12 | } 13 | } 14 | 15 | .wp-block-podcasting-podcast__show-art { 16 | margin-bottom: 20px; 17 | 18 | @media (min-width: 768px) { 19 | flex-basis: 100px; 20 | margin-bottom: 0; 21 | margin-right: 20px; 22 | } 23 | } 24 | 25 | .wp-block-podcasting-podcast__image { 26 | aspect-ratio: 1/1; 27 | height: auto; 28 | position: relative; 29 | 30 | & img { 31 | display: block; 32 | height: 100%; 33 | object-fit: cover; 34 | width: 100%; 35 | } 36 | } 37 | 38 | .wp-block-podcasting-podcast__show-title { 39 | margin: 0; 40 | } 41 | 42 | .wp-block-podcasting-podcast__show-details { 43 | color: #575757; 44 | font-size: 0.875rem; 45 | text-transform: uppercase; 46 | 47 | & span { 48 | display: block; 49 | margin-right: 6px; 50 | 51 | @media (min-width: 768px) { 52 | display: inline; 53 | } 54 | 55 | &::after { 56 | 57 | @media (min-width: 768px) { 58 | content: '/'; 59 | margin-left: 6px; 60 | } 61 | } 62 | 63 | &:last-child { 64 | margin-right: 0; 65 | 66 | &::after { 67 | display: none; 68 | } 69 | } 70 | } 71 | } 72 | 73 | .wp-block-podcasting-podcast__caption { 74 | margin-bottom: 10px; 75 | } 76 | 77 | .wp-block-podcasting-podcast { 78 | margin: 0; 79 | 80 | & audio { 81 | display: block; 82 | width: 100%; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /.github/workflows/phpunit.yml: -------------------------------------------------------------------------------- 1 | name: Unit Tests 2 | 3 | permissions: 4 | contents: read 5 | 6 | env: 7 | COMPOSER_VERSION: "2" 8 | COMPOSER_CACHE: "${{ github.workspace }}/.composer-cache" 9 | 10 | on: 11 | push: 12 | branches: 13 | - develop 14 | - trunk 15 | pull_request: 16 | branches: 17 | - develop 18 | 19 | jobs: 20 | phpunit: 21 | name: ${{ matrix.php.name }} 22 | runs-on: ubuntu-latest 23 | 24 | strategy: 25 | fail-fast: false 26 | matrix: 27 | php: 28 | - {name: 'PHP 7.4', version: '7.4'} 29 | - {name: 'PHP 8.1', version: '8.1'} 30 | 31 | steps: 32 | - name: Checkout 33 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 34 | 35 | - name: Set standard 10up cache directories 36 | run: | 37 | composer config -g cache-dir "${{ env.COMPOSER_CACHE }}" 38 | 39 | - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 40 | with: 41 | node-version-file: '.nvmrc' 42 | 43 | - name: Prepare composer cache 44 | uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 45 | with: 46 | path: ${{ env.COMPOSER_CACHE }} 47 | key: composer-${{ env.COMPOSER_VERSION }}-${{ hashFiles('**/composer.lock') }} 48 | restore-keys: | 49 | composer-${{ env.COMPOSER_VERSION }}- 50 | 51 | - name: Set PHP version 52 | uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 53 | with: 54 | php-version: '${{ matrix.php.version }}' 55 | coverage: none 56 | tools: composer:v2 57 | 58 | - name: Install dependencies 59 | run: composer install && npm install 60 | 61 | - name: Build 62 | run: npm run build 63 | 64 | - name: Test 65 | run: ./vendor/bin/phpunit -v 66 | -------------------------------------------------------------------------------- /.github/workflows/close-stale-issues.yml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues' 2 | 3 | # **What it does**: Closes issues where the original author doesn't respond to a request for information. 4 | # **Why we have it**: To remove the need for maintainers to remember to check back on issues periodically to see if contributors have responded. 5 | 6 | on: 7 | schedule: 8 | # Schedule for every day at 1:30am UTC 9 | - cron: '30 1 * * *' 10 | 11 | permissions: 12 | issues: write 13 | 14 | jobs: 15 | stale: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0 19 | with: 20 | days-before-stale: 7 21 | days-before-close: 7 22 | stale-issue-message: > 23 | It has been 7 days since more information was requested from you in this issue and we have not heard back. This issue is now marked as stale and will be closed in 7 days, but if you have more information to add then please comment and the issue will stay open. 24 | close-issue-message: > 25 | This issue has been automatically closed because there has been no response 26 | to our request for more information. With only the 27 | information that is currently in the issue, we don't have enough information 28 | to take action. Please reach out if you have or find the answers we need so 29 | that we can investigate further. See [this blog post on bug reports and the 30 | importance of repro steps](https://www.lee-dohm.com/2015/01/04/writing-good-bug-reports/) 31 | for more information about the kind of information that may be helpful. 32 | stale-issue-label: 'stale' 33 | close-issue-reason: 'not_planned' 34 | any-of-labels: 'needs:feedback' 35 | remove-stale-when-updated: true 36 | -------------------------------------------------------------------------------- /assets/js/deprecated.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | attributes: { 4 | id: { 5 | type: 'number', 6 | }, 7 | src: { 8 | type: 'string', 9 | source: 'attribute', 10 | selector: 'audio', 11 | attribute: 'src', 12 | }, 13 | url: { 14 | type: 'string', 15 | source: 'meta', 16 | meta: 'podcast_url', 17 | }, 18 | filesize: { 19 | type: 'number', 20 | source: 'meta', 21 | meta: 'podcast_filesize', 22 | }, 23 | duration: { 24 | type: 'string', 25 | source: 'meta', 26 | meta: 'podcast_duration', 27 | }, 28 | mime: { 29 | type: 'string', 30 | source: 'meta', 31 | meta: 'podcast_mime', 32 | }, 33 | caption: { 34 | type: 'array', 35 | source: 'children', 36 | selector: 'figcaption', 37 | }, 38 | captioned: { 39 | type: 'boolean', 40 | source: 'meta', 41 | meta: 'podcast_captioned', 42 | default: false, 43 | }, 44 | explicit: { 45 | type: 'string', 46 | source: 'meta', 47 | meta: 'podcast_explicit', 48 | default: 'no', 49 | }, 50 | enclosure: { 51 | type: 'string', 52 | source: 'meta', 53 | meta: 'enclosure', 54 | }, 55 | seasonNumber: { 56 | type: 'string', 57 | source: 'meta', 58 | meta: 'podcast_season_number', 59 | }, 60 | episodeNumber: { 61 | type: 'string', 62 | source: 'meta', 63 | meta: 'podcast_episode_number', 64 | }, 65 | episodeType: { 66 | type: 'string', 67 | source: 'meta', 68 | meta: 'podcast_episode_type', 69 | } 70 | }, 71 | supports: { 72 | multiple: false, 73 | }, 74 | save: props => { 75 | const { 76 | id, 77 | src, 78 | caption 79 | } = props.attributes; 80 | 81 | return ( 82 |
83 |
86 | ); 87 | }, 88 | }, 89 | ]; 90 | -------------------------------------------------------------------------------- /tests/cypress/support/functions.js: -------------------------------------------------------------------------------- 1 | export const randomName = () => Math.random().toString(16).substring(7); 2 | 3 | export const getFirstImage = () => { 4 | cy.get('#menu-item-browse').click(); 5 | cy.get('ul.attachments li:first-of-type').click(); 6 | cy.get('.media-button-select').click(); 7 | }; 8 | 9 | /** 10 | * Populates a podcast taxonomy. 11 | * @param {Object} args The podcast data to populate. 12 | * @param {string} args.typeOfShowName The type of show. 13 | * @param {string} args.author The author of the podcast. 14 | * @param {string} args.summary The summary of the podcast. 15 | * @param {string} args.category The category of the podcast. 16 | * @param {boolean} args.onboarding Whether this is onboarding or not. 17 | */ 18 | export const populatePodcast = (args) => { 19 | for (const [key, value] of Object.entries(args)) { 20 | switch (key) { 21 | case 'typeOfShowName': 22 | cy.get('#podcasting_type_of_show').select(value); 23 | break; 24 | case 'author': 25 | if (args.onboarding) { 26 | cy.get('input[name="podcast-artist"]').type(value); 27 | } else { 28 | cy.get('#podcasting_talent_name').type(value); 29 | } 30 | break; 31 | case 'summary': 32 | if (args.onboarding) { 33 | cy.get('textarea[name="podcast-description"]').type(value); 34 | } else { 35 | cy.get('#podcasting_summary').type(value); 36 | } 37 | break; 38 | case 'category': 39 | if (args.onboarding) { 40 | cy.get('select[name=podcast-category]').select(value); 41 | } else { 42 | cy.get('#podcasting_category_1').select(value); 43 | } 44 | break; 45 | } 46 | } 47 | // Get first image from media library. 48 | if (args.onboarding) { 49 | cy.get('#simple-podcasting__upload-cover-image').click(); 50 | } else { 51 | cy.get('#image-podcasting_image').click(); 52 | } 53 | getFirstImage(); 54 | }; 55 | 56 | export const deleteAllTerms = () => { 57 | cy.get('body').then(($body) => { 58 | if ($body.find('#doaction').length > 0) { 59 | cy.get('#cb-select-all-1').click({ force: true }); 60 | cy.get('#bulk-action-selector-top').select('delete'); 61 | cy.get('#doaction').click(); 62 | } 63 | }); 64 | }; 65 | -------------------------------------------------------------------------------- /includes/blocks/podcast-transcript/formats.js: -------------------------------------------------------------------------------- 1 | import { registerFormatType, toggleFormat } from '@wordpress/rich-text'; 2 | import { BlockControls } from '@wordpress/block-editor'; 3 | import { ToolbarGroup, ToolbarButton } from '@wordpress/components'; 4 | import { useSelect } from '@wordpress/data'; 5 | import { __ } from '@wordpress/i18n'; 6 | 7 | const Cite = ({ isActive, onChange, value }) => { 8 | const selectedBlock = useSelect((select) => { 9 | return select('core/block-editor').getSelectedBlock(); 10 | }, []); 11 | 12 | if ( 13 | selectedBlock && 14 | selectedBlock.name !== 'podcasting/podcast-transcript' 15 | ) { 16 | return null; 17 | } 18 | 19 | return ( 20 | 21 | 22 | { 26 | onChange( 27 | toggleFormat(value, { 28 | type: 'podcasting/transcript-cite', 29 | }) 30 | ); 31 | }} 32 | isActive={isActive} 33 | /> 34 | 35 | 36 | ); 37 | }; 38 | 39 | registerFormatType('podcasting/transcript-cite', { 40 | title: __('Cite', 'simple-podcasting'), 41 | tagName: 'cite', 42 | className: null, 43 | edit: Cite, 44 | }); 45 | 46 | const Time = ({ isActive, onChange, value }) => { 47 | const selectedBlock = useSelect((select) => { 48 | return select('core/block-editor').getSelectedBlock(); 49 | }, []); 50 | 51 | if ( 52 | selectedBlock && 53 | selectedBlock.name !== 'podcasting/podcast-transcript' 54 | ) { 55 | return null; 56 | } 57 | 58 | return ( 59 | 60 | 61 | { 65 | onChange( 66 | toggleFormat(value, { 67 | type: 'podcasting/transcript-time', 68 | }) 69 | ); 70 | }} 71 | isActive={isActive} 72 | /> 73 | 74 | 75 | ); 76 | }; 77 | 78 | registerFormatType('podcasting/transcript-time', { 79 | title: __('Time', 'simple-podcasting'), 80 | tagName: 'time', 81 | className: null, 82 | edit: Time, 83 | }); 84 | -------------------------------------------------------------------------------- /tests/cypress/integration/onboarding.test.js: -------------------------------------------------------------------------------- 1 | const { 2 | randomName, 3 | populatePodcast, 4 | deleteAllTerms, 5 | } = require('../support/functions'); 6 | 7 | describe('Onboarding tests', () => { 8 | beforeEach(() => { 9 | cy.login(); 10 | cy.uploadMedia('tests/cypress/fixtures/example.jpg'); 11 | cy.activatePlugin('simple-podcasting'); 12 | cy.visit( 13 | '/wp-admin/edit-tags.php?taxonomy=podcasting_podcasts&podcasts=true' 14 | ); 15 | deleteAllTerms(); 16 | cy.deactivatePlugin('simple-podcasting'); 17 | cy.visit('/wp-admin/options.php'); 18 | cy.get('body').then(($body) => { 19 | if ($body.find('#simple_podcasting_onboarding').length !== 0) { 20 | cy.get('#simple_podcasting_onboarding') 21 | .click() 22 | .type('{selectAll}no'); 23 | cy.get('.submit input[type=submit]').click(); 24 | } 25 | }); 26 | cy.activatePlugin('simple-podcasting'); 27 | }); 28 | 29 | it('Should indicate errors', () => { 30 | cy.url().should('include', 'simple-podcasting-onboarding'); 31 | cy.url().should('include', 'step=1'); 32 | 33 | cy.get('#simple-podcasting__create-podcast-button') 34 | .closest('form') 35 | .submit(); 36 | 37 | cy.get('.notice-error').should( 38 | 'contain', 39 | 'A podcast name is required.' 40 | ); 41 | }); 42 | 43 | it('Should pass onboarding', () => { 44 | cy.url().should('include', 'simple-podcasting-onboarding'); 45 | cy.url().should('include', 'step=1'); 46 | 47 | const podcastName = 'Onboarding ' + randomName(); 48 | cy.get('input[name=podcast-name]').click().type(podcastName); 49 | populatePodcast({ 50 | author: 'Person Doe', 51 | summary: 'Lorem ipsum dolor', 52 | category: 'Arts', 53 | onboarding: true, 54 | }); 55 | cy.get('#simple-podcasting__create-podcast-button') 56 | .closest('form') 57 | .submit(); 58 | 59 | cy.url().should('include', 'step=2'); 60 | 61 | cy.visit( 62 | '/wp-admin/edit-tags.php?taxonomy=podcasting_podcasts&podcasts=true' 63 | ); 64 | 65 | // Podcast was created. 66 | cy.contains(podcastName); 67 | 68 | // Option was saved. 69 | cy.visit('/wp-admin/options.php'); 70 | cy.get('#simple_podcasting_onboarding').should( 71 | 'have.value', 72 | 'completed' 73 | ); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /includes/block-patterns.php: -------------------------------------------------------------------------------- 1 | PODCASTING_TAXONOMY_NAME, 17 | 'fields' => 'ids', 18 | ] 19 | ); 20 | 21 | if ( empty( $podcast_terms ) ) { 22 | return; 23 | } 24 | 25 | register_block_pattern( 26 | 'podcasting/podcast-grid', 27 | array( 28 | 'title' => __( 'Podcast Grid', 'simple-podcasting' ), 29 | 'description' => _x( 'Podcast Grid', 'This block pattern is used to display podcast in a grid structure.', 'simple-podcasting' ), 30 | 'categories' => [ 'query' ], 31 | 'content' => ' 32 |
33 | 34 | 35 |
36 | 37 |
38 | 39 | 40 | 41 |
42 |
43 | 44 | 45 |
46 | ', 47 | ) 48 | ); 49 | } 50 | add_action( 'init', __NAMESPACE__ . '\init' ); 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@10up/simple-podcasting", 3 | "version": "1.9.1", 4 | "description": "A simple podcasting solution for WordPress. ", 5 | "homepage": "https://github.com/10up/simple-podcasting", 6 | "bugs": { 7 | "url": "https://github.com/10up/simple-podcasting/issues" 8 | }, 9 | "license": "GPL-2.0-or-later", 10 | "author": { 11 | "name": "10up", 12 | "email": "opensource@10up.com", 13 | "url": "https://10up.com", 14 | "role": "developer" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/10up/simple-podcasting" 19 | }, 20 | "scripts": { 21 | "start": "wp-scripts start", 22 | "build": "wp-scripts build", 23 | "deploy": "npm install && npm run build", 24 | "makepot": "wpi18n makepot --domain-path languages --pot-file simple-podcasting.pot --type plugin --main-file simple-podcasting.php --exclude node_modules,tests,docs,vendor", 25 | "prepare": "husky install", 26 | "wp-env": "wp-env", 27 | "env:start": "wp-env start", 28 | "env:stop": "wp-env stop", 29 | "cypress:open": "cypress open --browser chrome --config-file tests/cypress/config.config.js", 30 | "cypress:run": "cypress run --browser chrome --config-file tests/cypress/config.config.js" 31 | }, 32 | "lint-staged": { 33 | "*.php": [ 34 | "./vendor/bin/phpcs --standard=10up-Default --extensions=php --warning-severity=8 -s --runtime-set testVersion 7.4" 35 | ], 36 | "tests/**/*.js": [ 37 | "./node_modules/.bin/wp-scripts format" 38 | ] 39 | }, 40 | "devDependencies": { 41 | "@10up/cypress-wp-utils": "^0.3.0", 42 | "@wordpress/plugins": "^6.2.0", 43 | "@wordpress/prettier-config": "^2.2.0", 44 | "ansi-regex": ">=6.0.1", 45 | "@wordpress/env": "^10.28.0", 46 | "@wordpress/scripts": "^30.6.0", 47 | "copy-webpack-plugin": "^11.0.0", 48 | "cypress": "^13.2.0", 49 | "cypress-file-upload": "^5.0.8", 50 | "cypress-localstorage-commands": "^2.2.4", 51 | "cypress-mochawesome-reporter": "^3.6.0", 52 | "husky": "^8.0.1", 53 | "json-schema": ">=0.4.0", 54 | "lint-staged": "^13.0.3", 55 | "markdown-it": "^13.0.1", 56 | "mochawesome-json-to-md": "^0.7.2", 57 | "node-wp-i18n": "^1.2.6" 58 | }, 59 | "prettier": "@wordpress/prettier-config", 60 | "dependencies": { 61 | "use-debounce": "^8.0.4" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /includes/rest-external-url.php: -------------------------------------------------------------------------------- 1 | \WP_REST_Server::READABLE, 37 | 'callback' => __NAMESPACE__ . '\handle_request', 38 | 'permission_callback' => function () { 39 | return true; 40 | }, 41 | 'args' => array( 42 | 'url' => array( 43 | 'required' => true, 44 | 'sanitize_callback' => 'sanitize_text_field', 45 | ), 46 | ), 47 | ) 48 | ); 49 | } 50 | 51 | /** 52 | * Callbakc for the external-url endpoint. 53 | * 54 | * @param \WP_REST_Request $request The API request 55 | * 56 | * @return mixed|\WP_REST_Response 57 | */ 58 | function handle_request( \WP_REST_Request $request ) { 59 | 60 | $url = $request['url']; 61 | $cache_key = 'spc_external_url_' . $url; 62 | $podcast_meta = get_transient( $cache_key ); 63 | if ( false === $podcast_meta ) { 64 | if ( filter_var( $url, FILTER_VALIDATE_URL ) ) { 65 | $podcast_meta = \tenup_podcasting\helpers\get_podcast_meta_from_url( $url ); 66 | if ( $podcast_meta ) { 67 | $response = array( 68 | 'success' => true, 69 | 'data' => $podcast_meta, 70 | ); 71 | set_transient( $cache_key, $podcast_meta, MONTH_IN_SECONDS ); // We add the long expiry so we don't autoload the option in a non-object-cached env. 72 | } 73 | } else { 74 | $response = array( 75 | 'success' => false, 76 | 'message' => 'Invalid URL parameter passed', 77 | ); 78 | } 79 | } else { 80 | $response = array( 81 | 'success' => true, 82 | 'data' => $podcast_meta, 83 | ); 84 | } 85 | return rest_ensure_response( $response ); 86 | } 87 | -------------------------------------------------------------------------------- /includes/transcripts.php: -------------------------------------------------------------------------------- 1 | term_id ) ) . $post->post_name . '/transcript/'; 73 | } 74 | 75 | /** 76 | * Adds