├── .browserslistrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .git-blame-ignore-revs ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── PULL_REQUEST_TEMPLATE.md ├── actions │ ├── determine-changed-files │ │ ├── action.yml │ │ └── determine-modified-files-count.php │ ├── plugin-build │ │ └── action.yml │ ├── setup-node-npm │ │ └── action.yml │ └── setup-php-composer │ │ └── action.yml ├── dependabot.yml ├── release.yml └── workflows │ ├── build-test-measure.yml │ ├── cache-buster.yml │ └── codeql-analysis.yml ├── .gitignore ├── .gitmodules ├── .husky └── pre-commit ├── .lintstagedrc.js ├── .npmrc ├── .nvmrc ├── .phpcs.xml.dist ├── .phpstorm.meta.php ├── .prettierrc ├── .rtlcssrc ├── .stylelintignore ├── .stylelintrc.json ├── .wordpress-org ├── banner-1544x500.png ├── banner-772x250.png ├── icon-128x128.png ├── icon-256x256.png ├── icon.svg ├── screenshot-1.png ├── screenshot-2.png ├── screenshot-3.png ├── screenshot-4.png ├── screenshot-5.png └── screenshot-6.png ├── .wp-env.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── SECURITY.md ├── SUPPORT.md ├── amp.php ├── assets ├── css │ └── src │ │ ├── admin-tables.css │ │ ├── amp-admin.css │ │ ├── amp-block-editor.css │ │ ├── amp-customizer-legacy.css │ │ ├── amp-customizer.css │ │ ├── amp-default.css │ │ ├── amp-icons.scss │ │ ├── amp-mobile-version-switcher.css │ │ ├── amp-playlist-shortcode.css │ │ ├── amp-post-meta-box.css │ │ ├── amp-validation-error-taxonomy.scss │ │ ├── amp-validation-single-error-url.css │ │ ├── amp-validation-tooltips.css │ │ └── components │ │ ├── _amp-stylesheet-list.scss │ │ ├── _amp-stylesheet-summary.scss │ │ ├── _details-column.scss │ │ ├── _error-details-toggle.scss │ │ ├── _wp-list-table-grid-lines.scss │ │ ├── _wp-list-table-kept-errors.scss │ │ ├── _wp-list-table-markup-status-icon.scss │ │ └── _wp-list-table-new-errors.scss ├── fonts │ ├── genericons.woff │ ├── nonbreakingspaceoverride.woff │ └── nonbreakingspaceoverride.woff2 ├── images │ ├── amp-alert.svg │ ├── amp-black-icon.svg │ ├── amp-css-error-icon.svg │ ├── amp-delete.svg │ ├── amp-html-error-icon.svg │ ├── amp-icon-toolbar.svg │ ├── amp-icon.svg │ ├── amp-js-error-icon.svg │ ├── amp-logo-gray.svg │ ├── amp-logo-icon.svg │ ├── amp-page-fallback-wordpress-publisher-logo.png │ ├── amp-toolbar-icon-broken.svg │ ├── amp-valid.svg │ ├── amp-validation-errors-kept.svg │ ├── amp-validation-errors.svg │ ├── amp-white-icon.svg │ ├── bell-icon.svg │ ├── down-triangle.svg │ ├── placeholder-icon.png │ └── reader-themes │ │ ├── legacy.jpg │ │ ├── twentyeleven.jpg │ │ ├── twentyfifteen.jpg │ │ ├── twentyfourteen.jpg │ │ ├── twentynineteen.jpg │ │ ├── twentyseventeen.jpg │ │ ├── twentysixteen.jpg │ │ ├── twentythirteen.jpg │ │ ├── twentytwelve.jpg │ │ ├── twentytwenty.jpg │ │ └── twentytwentyone.jpg └── src │ ├── admin │ ├── amp-plugin-install.js │ ├── amp-theme-install.js │ ├── amp-validation-tooltips.js │ ├── paired-browsing │ │ ├── app.css │ │ ├── app.js │ │ └── client.js │ ├── site-scan-notice │ │ ├── index.js │ │ ├── notice.js │ │ ├── plugins-with-amp-incompatibility.js │ │ ├── style.scss │ │ └── themes-with-amp-incompatibility.js │ └── theme-install │ │ └── view │ │ └── theme.js │ ├── amp-validation │ ├── amp-validated-url-post-edit-screen.js │ ├── amp-validation-detail-toggle.js │ ├── amp-validation-single-error-url-details.js │ ├── copy-to-clipboard-buttons.js │ ├── counts │ │ ├── index.js │ │ └── style.css │ ├── get-url-validation-table-rows.js │ └── set-validation-error-rows-classes.js │ ├── block-editor │ ├── blocks │ │ ├── amp-brid-player │ │ │ ├── edit.js │ │ │ ├── index.js │ │ │ └── save.js │ │ ├── amp-ima-video │ │ │ ├── edit.js │ │ │ ├── index.js │ │ │ └── save.js │ │ ├── amp-jwplayer │ │ │ ├── edit.js │ │ │ ├── index.js │ │ │ └── save.js │ │ ├── amp-mathml │ │ │ ├── edit.js │ │ │ ├── index.js │ │ │ └── save.js │ │ ├── amp-o2-player │ │ │ ├── edit.js │ │ │ ├── index.js │ │ │ └── save.js │ │ ├── amp-ooyala-player │ │ │ ├── edit.js │ │ │ ├── index.js │ │ │ └── save.js │ │ ├── amp-reach-player │ │ │ ├── edit.js │ │ │ ├── index.js │ │ │ └── save.js │ │ ├── amp-springboard-player │ │ │ ├── edit.js │ │ │ ├── index.js │ │ │ └── save.js │ │ └── amp-timeago │ │ │ ├── edit.js │ │ │ ├── index.js │ │ │ └── save.js │ ├── components │ │ ├── index.js │ │ ├── layout-controls.js │ │ ├── media-placeholder.js │ │ ├── preview-menu-item.js │ │ └── with-media-library-notice.js │ ├── constants.js │ ├── helpers │ │ ├── index.js │ │ └── test │ │ │ └── addAMPAttributes.js │ ├── index.js │ ├── plugins │ │ ├── amp-preview-item.js │ │ ├── post-status-info.js │ │ └── pre-publish-panel.js │ └── store │ │ ├── index.js │ │ ├── selectors.js │ │ └── test │ │ └── selectors.js │ ├── block-validation │ ├── __mocks__ │ │ └── amp-block-validation.js │ ├── components │ │ ├── amp-document-status │ │ │ ├── index.js │ │ │ └── test │ │ │ │ └── amp-document-status-notification.js │ │ ├── amp-toggle │ │ │ ├── index.js │ │ │ └── test │ │ │ │ └── amp-toggle.js │ │ ├── amp-validation-status │ │ │ ├── index.js │ │ │ ├── revalidate-notification.js │ │ │ ├── status-notification.js │ │ │ └── test │ │ │ │ ├── __snapshots__ │ │ │ │ ├── revalidate-notification.js.snap │ │ │ │ └── status-notification.js.snap │ │ │ │ ├── revalidate-notification.js │ │ │ │ └── status-notification.js │ │ ├── error │ │ │ ├── error-content.js │ │ │ ├── error-panel-title.js │ │ │ ├── error-type-icon.js │ │ │ ├── get-error-source-title.js │ │ │ ├── index.js │ │ │ ├── style.css │ │ │ └── test │ │ │ │ ├── error.js │ │ │ │ └── get-error-source-title.js │ │ ├── icon │ │ │ ├── index.js │ │ │ ├── style.css │ │ │ └── test │ │ │ │ └── icon.js │ │ ├── invalid-block-outline │ │ │ └── index.js │ │ ├── sidebar-notification │ │ │ ├── index.js │ │ │ ├── style.css │ │ │ └── test │ │ │ │ ├── __snapshots__ │ │ │ │ └── sidebar-notification.js.snap │ │ │ │ ├── sidebar-notification.js │ │ │ │ └── sidebar-notifications-container.js │ │ ├── sidebar │ │ │ ├── index.js │ │ │ └── style.css │ │ └── with-amp-toolbar-button │ │ │ ├── amp-toolbar-button.js │ │ │ ├── index.js │ │ │ └── test │ │ │ └── add-toolbar-button-to-block.js │ ├── hooks │ │ ├── test │ │ │ ├── use-amp-document-toggle.js │ │ │ ├── use-errors-fetching-state-changes.js │ │ │ ├── use-post-dirty-state-updates.js │ │ │ └── use-validation-error-state-updates.js │ │ ├── use-amp-document-toggle.js │ │ ├── use-errors-fetching-state-changes.js │ │ ├── use-post-dirty-state-changes.js │ │ └── use-validation-error-state-updates.js │ ├── index.js │ ├── plugins │ │ ├── amp-block-validation.js │ │ ├── amp-document-setting-panel.js │ │ └── amp-pre-publish-panel.js │ └── store │ │ ├── index.js │ │ └── test │ │ ├── __data__ │ │ └── raw-validation-errors.js │ │ └── store.js │ ├── classic-editor │ └── amp-post-meta-box.js │ ├── common │ ├── components │ │ ├── featured-image-cropper.js │ │ ├── higher-order │ │ │ └── with-featured-image-notice.js │ │ ├── index.js │ │ ├── pre-publish-panel.js │ │ ├── select-media-frame.js │ │ └── with-enforced-file-type.js │ ├── constants.js │ └── helpers │ │ ├── get-plugin-slug-from-file.js │ │ ├── index.js │ │ ├── is-external-url.js │ │ └── test │ │ ├── __mocks__ │ │ └── amp-block-editor-data.js │ │ ├── enforceFileType.js │ │ ├── fixtures │ │ └── mockClasses.js │ │ ├── get-plugin-slug-from-file.js │ │ ├── getMinimumFeaturedImageDimensions.js │ │ ├── getNoticeTemplate.js │ │ ├── hasMinimumDimensions.js │ │ ├── is-external-url.js │ │ ├── isFileTypeAllowed.js │ │ ├── setImageFromURL.js │ │ └── validateFeaturedImage.js │ ├── components │ ├── amp-admin-notice │ │ ├── index.js │ │ ├── style.scss │ │ └── test │ │ │ ├── __snapshots__ │ │ │ └── amp-admin-notice.js.snap │ │ │ └── amp-admin-notice.js │ ├── amp-drawer │ │ ├── index.js │ │ └── style.css │ ├── amp-info │ │ ├── index.js │ │ ├── style.css │ │ └── test │ │ │ ├── __snapshots__ │ │ │ └── index.js.snap │ │ │ └── index.js │ ├── amp-notice │ │ ├── index.js │ │ ├── style.css │ │ └── test │ │ │ ├── __snapshots__ │ │ │ └── index.js.snap │ │ │ └── index.js │ ├── amp-setting-toggle │ │ ├── index.js │ │ ├── style.css │ │ └── test │ │ │ ├── __snapshots__ │ │ │ └── index.js.snap │ │ │ └── index.js │ ├── carousel │ │ ├── carousel-nav.js │ │ ├── index.js │ │ └── test │ │ │ └── carousel-nav.js │ ├── clipboard-button │ │ ├── index.js │ │ └── test │ │ │ ├── __snapshots__ │ │ │ └── index.js.snap │ │ │ └── index.js │ ├── conditional-details │ │ ├── index.js │ │ └── test │ │ │ ├── __snapshots__ │ │ │ └── index.js.snap │ │ │ └── index.js │ ├── dev-tools-toggle │ │ ├── index.js │ │ └── test │ │ │ ├── __snapshots__ │ │ │ └── index.js.snap │ │ │ └── index.js │ ├── error-boundary │ │ └── index.js │ ├── error-context-provider │ │ └── index.js │ ├── error-screen │ │ ├── index.js │ │ ├── style.css │ │ └── test │ │ │ ├── __snapshots__ │ │ │ └── index.js.snap │ │ │ └── index.js │ ├── list-items │ │ ├── index.js │ │ ├── style.scss │ │ └── test │ │ │ ├── __snapshots__ │ │ │ └── index.js.snap │ │ │ └── index.js │ ├── loading │ │ ├── index.js │ │ ├── style.css │ │ └── test │ │ │ ├── __snapshots__ │ │ │ └── loading.js.snap │ │ │ └── loading.js │ ├── nav-menu │ │ ├── index.js │ │ ├── style.scss │ │ └── test │ │ │ ├── __snapshots__ │ │ │ └── nav-menu.js.snap │ │ │ └── nav-menu.js │ ├── options-context-provider │ │ ├── __mocks__ │ │ │ └── index.js │ │ └── index.js │ ├── phone │ │ ├── index.js │ │ └── style.css │ ├── plugins-context-provider │ │ ├── __mocks__ │ │ │ └── index.js │ │ ├── index.js │ │ ├── test │ │ │ └── use-normalized-plugins-data.js │ │ └── use-normalized-plugins-data.js │ ├── progress-bar │ │ ├── index.js │ │ ├── style.scss │ │ └── test │ │ │ ├── __snapshots__ │ │ │ └── progress-bar.js.snap │ │ │ └── progress-bar.js │ ├── reader-theme-carousel │ │ ├── index.js │ │ └── style.css │ ├── reader-theme-selection │ │ ├── index.js │ │ └── style.css │ ├── reader-themes-context-provider │ │ ├── __mocks__ │ │ │ └── index.js │ │ └── index.js │ ├── redirect-toggle │ │ ├── index.js │ │ └── test │ │ │ ├── __snapshots__ │ │ │ └── redirect-toggle.js.snap │ │ │ └── redirect-toggle.js │ ├── selectable │ │ ├── index.js │ │ ├── style.css │ │ └── test │ │ │ ├── __snapshots__ │ │ │ └── index.js.snap │ │ │ └── index.js │ ├── site-scan-context-provider │ │ ├── __mocks__ │ │ │ └── index.js │ │ ├── get-sources-from-scannable-urls.js │ │ ├── index.js │ │ └── test │ │ │ ├── get-slugs-from-validation-results.js │ │ │ └── site-scan-reducer.js │ ├── site-scan-results │ │ ├── data │ │ │ └── scannable-urls.js │ │ ├── index.js │ │ ├── plugins-with-amp-incompatibility.js │ │ ├── site-scan-results.js │ │ ├── site-scan-source-list-item.js │ │ ├── site-scan-sources-detail.js │ │ ├── site-scan-sources-list.js │ │ ├── style.scss │ │ ├── test │ │ │ └── site-scan-sources-list.js │ │ └── themes-with-amp-incompatibility.js │ ├── site-settings-provider │ │ └── index.js │ ├── supported-templates-toggle │ │ ├── index.js │ │ └── style.css │ ├── svg │ │ ├── check.js │ │ ├── desktop-icon.svg │ │ ├── icon-desktop.js │ │ ├── icon-laptop-search.js │ │ ├── icon-laptop-toggles.js │ │ ├── icon-mobile.js │ │ ├── icon-pin.js │ │ ├── landscape-hills-cogs-alt.js │ │ ├── landscape-hills-cogs.js │ │ ├── laptop-plug.js │ │ ├── logo.js │ │ ├── mobile-icon.svg │ │ ├── reader.js │ │ ├── standard.js │ │ ├── transitional.js │ │ ├── user-icons.js │ │ └── website-paint-brush.js │ ├── template-mode-option │ │ ├── index.js │ │ ├── style.css │ │ └── test │ │ │ ├── __snapshots__ │ │ │ └── index.js.snap │ │ │ └── index.js │ ├── theme-card │ │ ├── index.js │ │ └── style.css │ ├── themes-api-error │ │ └── index.js │ ├── themes-context-provider │ │ ├── __mocks__ │ │ │ └── index.js │ │ ├── index.js │ │ ├── test │ │ │ └── use-normalized-themes-data.js │ │ └── use-normalized-themes-data.js │ ├── unsaved-changes-warning │ │ └── index.js │ ├── use-template-mode-recommendation │ │ ├── index.js │ │ └── test │ │ │ └── get-template-mode-recommendation.js │ └── user-context-provider │ │ ├── __mocks__ │ │ └── index.js │ │ └── index.js │ ├── css │ ├── core-components.css │ ├── elements.css │ └── variables.css │ ├── customizer │ ├── amp-customize-controls-legacy.js │ ├── amp-customize-controls.js │ ├── amp-customize-preview-legacy.js │ └── amp-customizer-design-preview-legacy.js │ ├── icons │ └── index.js │ ├── mobile-redirection.js │ ├── onboarding-wizard │ ├── __mocks__ │ │ └── amp-settings.js │ ├── components │ │ ├── desktop │ │ │ ├── index.js │ │ │ └── style.css │ │ ├── nav │ │ │ ├── index.js │ │ │ ├── style.css │ │ │ └── test │ │ │ │ ├── __snapshots__ │ │ │ │ └── index.js.snap │ │ │ │ └── index.js │ │ ├── navigation-context-provider.js │ │ ├── stepper │ │ │ ├── index.js │ │ │ └── test │ │ │ │ ├── __snapshots__ │ │ │ │ └── index.js.snap │ │ │ │ └── index.js │ │ └── template-mode-override-context-provider.js │ ├── index.js │ ├── pages │ │ ├── choose-reader-theme │ │ │ └── index.js │ │ ├── done │ │ │ ├── index.js │ │ │ ├── preview.js │ │ │ ├── saving.js │ │ │ ├── style.scss │ │ │ └── use-preview.js │ │ ├── index.js │ │ ├── site-scan │ │ │ ├── index.js │ │ │ └── style.scss │ │ ├── technical-background │ │ │ ├── index.js │ │ │ └── style.css │ │ ├── template-mode │ │ │ ├── index.js │ │ │ ├── screen-ui.js │ │ │ └── style.scss │ │ └── welcome │ │ │ ├── index.js │ │ │ └── style.css │ ├── setup-wizard.js │ └── style.css │ ├── polyfills │ └── api-fetch.js │ ├── settings-page │ ├── analytics.js │ ├── delete-data-at-uninstall.js │ ├── developer-tools.js │ ├── index.js │ ├── mobile-redirection.js │ ├── paired-url-structure.js │ ├── plugin-suppression.js │ ├── reader-themes.js │ ├── sandboxing.js │ ├── settings-footer.js │ ├── site-review.js │ ├── site-scan.js │ ├── style.css │ ├── supported-templates.js │ ├── template-modes.js │ ├── toggle-use-native-img-tag.js │ ├── vendor-configs.js │ └── welcome.js │ └── utils │ ├── use-async-error.js │ ├── use-delayed-flag.js │ └── use-window-width.js ├── babel.config.js ├── back-compat ├── back-compat.php └── templates-v0-3 │ ├── header-bar.php │ ├── meta-author.php │ ├── meta-taxonomy.php │ ├── meta-time.php │ ├── single.php │ └── style.php ├── behat.yml ├── bin ├── add-test-widgets-to-sidebar.php ├── amphtml-update.py ├── amphtml-update.sh ├── ci │ ├── after-wp-install.sh │ └── install-wp-tests.sh ├── create-comments-on-test-post.php ├── create-embed-test-post.php ├── latest-extension-versions.json ├── local-env │ ├── .env.wp │ ├── Dockerfile │ ├── docker-compose.yml │ ├── includes.sh │ ├── install-wordpress.sh │ ├── launch-containers.sh │ ├── start.sh │ ├── stop.sh │ └── uploads.ini ├── phpcbf.sh ├── tag-built.sh ├── transform-readme.php ├── update-analytics-vendors.js ├── update-extension-files.js └── verify-version-consistency.php ├── codecov.yml ├── composer.json ├── composer.lock ├── docs ├── README.md ├── class │ ├── AMP_Base_Embed_Handler.md │ ├── AMP_Base_Sanitizer.md │ ├── AMP_DOM_Utils.md │ ├── AMP_WordPress_Embed_Handler.md │ ├── PairedUrl.md │ ├── PairedUrlStructure.md │ └── README.md ├── docs.json ├── function │ ├── README.md │ ├── amp_add_amphtml_link.md │ ├── amp_add_paired_endpoint.md │ ├── amp_add_post_template_actions.md │ ├── amp_backcompat_use_v03_templates.md │ ├── amp_frontend_add_canonical.md │ ├── amp_generate_script_hash.md │ ├── amp_get_permalink.md │ ├── amp_get_sandboxing_level.md │ ├── amp_get_slug.md │ ├── amp_has_paired_endpoint.md │ ├── amp_is_available.md │ ├── amp_is_bento_enabled.md │ ├── amp_is_canonical.md │ ├── amp_is_dev_mode.md │ ├── amp_is_legacy.md │ ├── amp_is_native_img_used.md │ ├── amp_is_post_supported.md │ ├── amp_is_request.md │ ├── amp_maybe_add_actions.md │ ├── amp_prepare_render.md │ ├── amp_remove_endpoint.md │ ├── amp_remove_paired_endpoint.md │ ├── amp_render.md │ ├── amp_render_post.md │ ├── is_amp_endpoint.md │ └── post_supports_amp.md ├── hook │ ├── README.md │ ├── amp_analytics_entries.md │ ├── amp_auto_lightbox_disabled.md │ ├── amp_bento_enabled.md │ ├── amp_comment_posted_message.md │ ├── amp_compatible_ecosystem_shown.md │ ├── amp_content_embed_handlers.md │ ├── amp_content_max_width.md │ ├── amp_content_sanitizers.md │ ├── amp_css_transient_monitoring_sampling_range.md │ ├── amp_css_transient_monitoring_threshold.md │ ├── amp_custom_paired_url_structure.md │ ├── amp_customizer_enqueue_preview_scripts.md │ ├── amp_customizer_enqueue_scripts.md │ ├── amp_customizer_get_settings.md │ ├── amp_customizer_init.md │ ├── amp_customizer_is_enabled.md │ ├── amp_customizer_post_type.md │ ├── amp_customizer_register_settings.md │ ├── amp_customizer_register_ui.md │ ├── amp_dev_mode_element_xpaths.md │ ├── amp_dev_mode_enabled.md │ ├── amp_dev_tools_user_default_enabled.md │ ├── amp_enable_optimizer.md │ ├── amp_enable_ssr.md │ ├── amp_extract_image_dimensions_batch.md │ ├── amp_extract_image_dimensions_batch_callbacks_registered.md │ ├── amp_extract_image_dimensions_get_user_agent.md │ ├── amp_featured_image_minimum_height.md │ ├── amp_featured_image_minimum_width.md │ ├── amp_frontend_show_canonical.md │ ├── amp_get_permalink.md │ ├── amp_init.md │ ├── amp_is_enabled.md │ ├── amp_mobile_client_side_redirection.md │ ├── amp_mobile_user_agents.md │ ├── amp_mobile_version_switcher_link_text.md │ ├── amp_mobile_version_switcher_styles_used.md │ ├── amp_native_img_used.md │ ├── amp_normalized_dimension_extractor_image_url.md │ ├── amp_optimizer_config.md │ ├── amp_options_menu_is_enabled.md │ ├── amp_page_cache_good_response_time_threshold.md │ ├── amp_parsed_css_transient_caching_allowed.md │ ├── amp_plugin_update.md │ ├── amp_post_status_default_enabled.md │ ├── amp_post_template_analytics.md │ ├── amp_post_template_customizer_settings.md │ ├── amp_post_template_data.md │ ├── amp_post_template_dir.md │ ├── amp_post_template_file.md │ ├── amp_post_template_include_{$template_type}.md │ ├── amp_post_template_metadata.md │ ├── amp_pre_get_permalink.md │ ├── amp_pre_is_mobile.md │ ├── amp_print_analytics.md │ ├── amp_query_var.md │ ├── amp_reader_themes.md │ ├── amp_schemaorg_metadata.md │ ├── amp_site_icon_url.md │ ├── amp_skip_post.md │ ├── amp_supportable_post_types.md │ ├── amp_supportable_templates.md │ ├── amp_to_amp_excluded_urls.md │ ├── amp_to_amp_linking_element_excluded.md │ ├── amp_to_amp_linking_enabled.md │ ├── amp_validation_data_gc_before.md │ ├── amp_validation_data_gc_delete_empty_terms.md │ ├── amp_validation_data_gc_url_count.md │ ├── amp_validation_error.md │ ├── amp_validation_error_default_sanitized.md │ ├── amp_validation_error_sanitized.md │ ├── amp_validation_error_source_file_editor_url_template.md │ ├── amp_validation_error_source_file_path.md │ └── pre_amp_render_post.md ├── includes │ └── register-wp-cli-commands.php ├── method │ ├── AMP_Base_Embed_Handler │ │ ├── __construct.md │ │ ├── create_overflow_button_element.md │ │ ├── create_overflow_button_markup.md │ │ ├── get_child_elements.md │ │ ├── get_scripts.md │ │ ├── match_element_attributes.md │ │ ├── maybe_remove_script_sibling.md │ │ ├── register_embed.md │ │ ├── unregister_embed.md │ │ └── unwrap_p_element.md │ ├── AMP_Base_Sanitizer │ │ ├── __construct.md │ │ ├── add_buffering_hooks.md │ │ ├── add_or_append_attribute.md │ │ ├── clean_up_after_attribute_removal.md │ │ ├── filter_attachment_layout_attributes.md │ │ ├── filter_data_amp_attributes.md │ │ ├── get_arg.md │ │ ├── get_args.md │ │ ├── get_body_node.md │ │ ├── get_data_amp_attributes.md │ │ ├── get_scripts.md │ │ ├── get_selector_conversion_mapping.md │ │ ├── get_stylesheets.md │ │ ├── get_validate_response_data.md │ │ ├── has_dev_mode_exemption.md │ │ ├── has_light_shadow_dom.md │ │ ├── init.md │ │ ├── is_document_in_dev_mode.md │ │ ├── is_empty_attribute_value.md │ │ ├── is_exempt_from_validation.md │ │ ├── maybe_enforce_https_src.md │ │ ├── parse_style_string.md │ │ ├── prepare_validation_error.md │ │ ├── reassemble_style_string.md │ │ ├── remove_invalid_attribute.md │ │ ├── remove_invalid_child.md │ │ ├── sanitize.md │ │ ├── sanitize_dimension.md │ │ ├── set_layout.md │ │ ├── should_sanitize_validation_error.md │ │ └── update_args.md │ ├── AMP_DOM_Utils │ │ ├── add_amp_action.md │ │ ├── add_attributes_to_node.md │ │ ├── copy_attributes.md │ │ ├── create_node.md │ │ ├── get_content_from_dom.md │ │ ├── get_content_from_dom_node.md │ │ ├── get_dom.md │ │ ├── get_dom_from_content.md │ │ ├── get_element_id.md │ │ ├── get_node_attributes_as_assoc_array.md │ │ ├── has_class.md │ │ ├── is_node_empty.md │ │ ├── is_valid_head_node.md │ │ └── merge_amp_actions.md │ ├── AMP_WordPress_Embed_Handler │ │ ├── register_embed.md │ │ ├── sanitize_raw_embeds.md │ │ └── unregister_embed.md │ ├── PairedUrl │ │ ├── add_path_suffix.md │ │ ├── add_query_var.md │ │ ├── has_path_suffix.md │ │ ├── has_query_var.md │ │ ├── remove_path_suffix.md │ │ └── remove_query_var.md │ ├── PairedUrlStructure │ │ ├── __construct.md │ │ ├── add_endpoint.md │ │ ├── has_endpoint.md │ │ └── remove_endpoint.md │ └── README.md ├── src │ ├── Cli │ │ ├── DocsCommandNamespace.php │ │ └── GenerateCommand.php │ ├── Model │ │ ├── Argument.php │ │ ├── Class_.php │ │ ├── DocBlock.php │ │ ├── File.php │ │ ├── Function_.php │ │ ├── HasArguments.php │ │ ├── HasCodeLinks.php │ │ ├── HasDocBlock.php │ │ ├── Hook.php │ │ ├── Include_.php │ │ ├── Leaf.php │ │ ├── LeafConstruction.php │ │ ├── Method.php │ │ ├── Property.php │ │ ├── Root.php │ │ ├── Tag.php │ │ └── Usage.php │ ├── Parser │ │ ├── DirectoryFilter.php │ │ ├── FileReflector.php │ │ ├── FunctionCallReflector.php │ │ ├── HookReflector.php │ │ ├── MethodCallReflector.php │ │ ├── Parser.php │ │ ├── PrettyPrinter.php │ │ └── StaticMethodCallReflector.php │ └── Templating │ │ ├── Markdown.php │ │ ├── MustacheTemplateEngine.php │ │ └── TemplateEngine.php └── templates │ ├── class.mustache │ ├── class_index.mustache │ ├── function.mustache │ ├── function_index.mustache │ ├── hook.mustache │ ├── hook_index.mustache │ ├── index.mustache │ ├── method.mustache │ └── method_index.mustache ├── includes ├── admin │ ├── class-amp-admin-pointer.php │ ├── class-amp-admin-pointers.php │ ├── class-amp-editor-blocks.php │ ├── class-amp-post-meta-box.php │ ├── class-amp-template-customizer.php │ └── functions.php ├── amp-frontend-actions.php ├── amp-helper-functions.php ├── amp-post-template-functions.php ├── bootstrap.php ├── class-amp-autoloader.php ├── class-amp-comment-walker.php ├── class-amp-http.php ├── class-amp-post-type-support.php ├── class-amp-service-worker.php ├── class-amp-theme-support.php ├── deprecated.php ├── ecosystem-data │ ├── analytics-vendors.php │ ├── plugins.php │ └── themes.php ├── embeds │ ├── class-amp-base-embed-handler.php │ ├── class-amp-core-block-handler.php │ ├── class-amp-crowdsignal-embed-handler.php │ ├── class-amp-dailymotion-embed-handler.php │ ├── class-amp-facebook-embed-handler.php │ ├── class-amp-gallery-embed-handler.php │ ├── class-amp-imgur-embed-handler.php │ ├── class-amp-instagram-embed-handler.php │ ├── class-amp-issuu-embed-handler.php │ ├── class-amp-meetup-embed-handler.php │ ├── class-amp-pinterest-embed-handler.php │ ├── class-amp-playlist-embed-handler.php │ ├── class-amp-reddit-embed-handler.php │ ├── class-amp-scribd-embed-handler.php │ ├── class-amp-soundcloud-embed-handler.php │ ├── class-amp-tiktok-embed-handler.php │ ├── class-amp-tumblr-embed-handler.php │ ├── class-amp-twitter-embed-handler.php │ ├── class-amp-vimeo-embed-handler.php │ ├── class-amp-wordpress-embed-handler.php │ ├── class-amp-wordpress-tv-embed-handler.php │ └── class-amp-youtube-embed-handler.php ├── options │ ├── class-amp-options-manager.php │ └── class-amp-reader-theme-rest-controller.php ├── sanitizers │ ├── class-amp-accessibility-sanitizer.php │ ├── class-amp-allowed-tags-generated.php │ ├── class-amp-audio-sanitizer.php │ ├── class-amp-auto-lightbox-disable-sanitizer.php │ ├── class-amp-base-sanitizer.php │ ├── class-amp-bento-sanitizer.php │ ├── class-amp-block-sanitizer.php │ ├── class-amp-comments-sanitizer.php │ ├── class-amp-core-theme-sanitizer.php │ ├── class-amp-dev-mode-sanitizer.php │ ├── class-amp-embed-sanitizer.php │ ├── class-amp-form-sanitizer.php │ ├── class-amp-gallery-block-sanitizer.php │ ├── class-amp-gtag-script-sanitizer.php │ ├── class-amp-iframe-sanitizer.php │ ├── class-amp-img-sanitizer.php │ ├── class-amp-layout-sanitizer.php │ ├── class-amp-link-sanitizer.php │ ├── class-amp-meta-sanitizer.php │ ├── class-amp-native-img-attributes-sanitizer.php │ ├── class-amp-nav-menu-dropdown-sanitizer.php │ ├── class-amp-nav-menu-toggle-sanitizer.php │ ├── class-amp-o2-player-sanitizer.php │ ├── class-amp-object-sanitizer.php │ ├── class-amp-playbuzz-sanitizer.php │ ├── class-amp-pwa-script-sanitizer.php │ ├── class-amp-rule-spec.php │ ├── class-amp-script-sanitizer.php │ ├── class-amp-srcset-sanitizer.php │ ├── class-amp-style-sanitizer.php │ ├── class-amp-tag-and-attribute-sanitizer.php │ ├── class-amp-video-sanitizer.php │ └── trait-amp-noscript-fallback.php ├── settings │ ├── class-amp-customizer-design-settings.php │ └── class-amp-customizer-settings.php ├── templates │ ├── amp-enabled-classic-editor-toggle.php │ ├── amp-paired-browsing.php │ ├── class-amp-content-sanitizer.php │ ├── class-amp-content.php │ ├── class-amp-post-template.php │ └── reader-template-loader.php ├── uninstall-functions.php ├── utils │ ├── class-amp-dom-utils.php │ ├── class-amp-html-utils.php │ ├── class-amp-image-dimension-extractor.php │ └── class-amp-string-utils.php ├── validation │ ├── class-amp-validated-url-post-type.php │ ├── class-amp-validation-callback-wrapper.php │ ├── class-amp-validation-error-taxonomy.php │ └── class-amp-validation-manager.php └── widgets │ ├── class-amp-widget-archives.php │ ├── class-amp-widget-categories.php │ └── class-amp-widget-text.php ├── package-lock.json ├── package.json ├── phpstan-baseline.php ├── phpstan.neon.dist ├── phpunit.xml.dist ├── postcss.config.js ├── src ├── Admin │ ├── AfterActivationSiteScan.php │ ├── AmpPlugins.php │ ├── AmpThemes.php │ ├── AnalyticsOptionsSubmenu.php │ ├── GoogleFonts.php │ ├── OnboardingWizardSubmenu.php │ ├── OnboardingWizardSubmenuPage.php │ ├── OptionsMenu.php │ ├── PairedBrowsing.php │ ├── PluginActivationNotice.php │ ├── PluginRowMeta.php │ ├── Polyfills.php │ ├── RESTPreloader.php │ ├── ReaderThemes.php │ ├── ReenableCssTransientCachingAjaxAction.php │ ├── SiteHealth.php │ ├── SupportLink.php │ ├── UserRESTEndpointExtension.php │ └── ValidationCounts.php ├── AmpSlugCustomizationWatcher.php ├── AmpWpPlugin.php ├── AmpWpPluginFactory.php ├── BackgroundTask │ ├── BackgroundTaskDeactivator.php │ ├── CronBasedBackgroundTask.php │ ├── MonitorCssTransientCaching.php │ ├── RecurringBackgroundTask.php │ ├── SingleScheduledBackgroundTask.php │ ├── ValidatedUrlStylesheetDataGarbageCollection.php │ └── ValidationDataGarbageCollection.php ├── Cli │ ├── AmpCommandNamespace.php │ ├── CommandNamespaceRegistration.php │ ├── OptimizerCommand.php │ ├── OptionCommand.php │ ├── TransformerCommand.php │ └── ValidationCommand.php ├── Component │ ├── CaptionedSlide.php │ ├── Carousel.php │ └── HasCaption.php ├── ConfigurationArgument.php ├── DependencySupport.php ├── DevTools │ ├── BlockSources.php │ ├── CallbackReflection.php │ ├── ErrorPage.php │ ├── FileReflection.php │ ├── LikelyCulpritDetector.php │ └── UserAccess.php ├── Dom │ ├── ElementList.php │ └── Options.php ├── Editor │ └── EditorSupport.php ├── Embed │ └── HandlesGalleryEmbed.php ├── Exception │ ├── AmpWpException.php │ ├── FailedToMakeInstance.php │ ├── InvalidEventProperties.php │ ├── InvalidService.php │ └── InvalidStopwatchEvent.php ├── ExtraThemeAndPluginHeaders.php ├── Icon.php ├── Infrastructure │ ├── Activateable.php │ ├── CliCommand.php │ ├── Conditional.php │ ├── Deactivateable.php │ ├── Delayed.php │ ├── HasRequirements.php │ ├── Injector.php │ ├── Injector │ │ ├── FallbackInstantiator.php │ │ ├── InjectionChain.php │ │ └── SimpleInjector.php │ ├── Instantiator.php │ ├── Plugin.php │ ├── Registerable.php │ ├── Service.php │ ├── ServiceBasedPlugin.php │ ├── ServiceContainer.php │ └── ServiceContainer │ │ ├── LazilyInstantiatedService.php │ │ └── SimpleServiceContainer.php ├── Instrumentation │ ├── Event.php │ ├── EventWithDuration.php │ ├── ServerTiming.php │ ├── StopWatch.php │ └── StopWatchEvent.php ├── LoadingError.php ├── MobileRedirection.php ├── ObsoleteBlockAttributeRemover.php ├── Optimizer │ ├── AmpWPConfiguration.php │ ├── HeroCandidateFiltering.php │ ├── OptimizerService.php │ └── Transformer │ │ ├── AmpSchemaOrgMetadata.php │ │ ├── AmpSchemaOrgMetadataConfiguration.php │ │ └── DetermineHeroImages.php ├── Option.php ├── OptionsRESTController.php ├── PairedRouting.php ├── PairedUrl.php ├── PairedUrlStructure.php ├── PairedUrlStructure │ ├── LegacyReaderUrlStructure.php │ ├── LegacyTransitionalUrlStructure.php │ ├── PathSuffixUrlStructure.php │ └── QueryVarUrlStructure.php ├── PluginRegistry.php ├── PluginSuppression.php ├── QueryVar.php ├── ReaderThemeLoader.php ├── ReaderThemeSupportFeatures.php ├── RemoteRequest │ ├── CachedRemoteGetRequest.php │ ├── CachedResponse.php │ └── WpHttpRemoteGetRequest.php ├── Sandboxing.php ├── Services.php ├── Validation │ ├── ScannableURLProvider.php │ ├── ScannableURLsRestController.php │ ├── URLValidationCron.php │ ├── URLValidationProvider.php │ ├── URLValidationRESTController.php │ └── ValidationCountsRestController.php └── ValidationExemption.php ├── templates ├── featured-image.php ├── footer.php ├── header-bar.php ├── header.php ├── html-end.php ├── html-start.php ├── meta-author.php ├── meta-comments-link.php ├── meta-taxonomy.php ├── meta-time.php ├── page.php ├── single.php └── style.php ├── tests ├── e2e │ ├── assets │ │ ├── large-image-36521.jpg │ │ └── small-image-100-100.jpg │ ├── config │ │ └── bootstrap.js │ ├── jest-ci.config.js │ ├── jest.config.js │ ├── plugins │ │ ├── do-not-allow-amp-validate-capability.php │ │ ├── do-not-allow-amp-validate-capability.zip │ │ ├── e2e-tests-demo-plugin.php │ │ └── e2e-tests-demo-plugin.zip │ ├── puppeteer.config.js │ ├── specs │ │ ├── admin │ │ │ ├── after-plugin-activation.js │ │ │ ├── amp-options.js │ │ │ ├── analytics-options.js │ │ │ ├── anchor-linking.js │ │ │ ├── other-settings.js │ │ │ ├── reader-theme-carousel.js │ │ │ ├── site-review-panel.js │ │ │ ├── site-scan-panel.js │ │ │ └── template-mode.js │ │ ├── amp-onboarding │ │ │ ├── close-button.js │ │ │ ├── done.js │ │ │ ├── exit-links.js │ │ │ ├── reader-themes.js │ │ │ ├── site-scan.js │ │ │ ├── technical-background.js │ │ │ ├── template-mode.js │ │ │ ├── transitional-recommendation.js │ │ │ └── welcome.js │ │ ├── block-editor │ │ │ ├── amp-preview-menu-item.js │ │ │ ├── amp-toggle.js │ │ │ └── featured-image-notice.js │ │ └── core-themes │ │ │ ├── twentyfifteen.js │ │ │ ├── twentyfourteen.js │ │ │ ├── twentynineteen.js │ │ │ ├── twentyseventeen.js │ │ │ ├── twentysixteen.js │ │ │ ├── twentythirteen.js │ │ │ ├── twentytwelve.js │ │ │ ├── twentytwenty.js │ │ │ ├── twentytwentyone.js │ │ │ └── twentytwentytwo.js │ └── utils │ │ ├── amp-settings-utils.js │ │ ├── click-button.js │ │ ├── index.js │ │ ├── nav-menu-utils.js │ │ ├── onboarding-wizard-utils.js │ │ ├── site-scan-utils.js │ │ ├── upload-media.js │ │ └── visit-admin-page-with-hash.js ├── features │ ├── optimize-command.feature │ ├── optimize-transformer-config-command.feature │ ├── optimize-transformer-list-command.feature │ ├── option-get-command.feature │ ├── option-list-command.feature │ ├── option-list-reader-themes-command.feature │ └── option-update-command.feature ├── js │ ├── jest.config.js │ ├── resolver.js │ └── setup-globals.js ├── php │ ├── bootstrap.php │ ├── data │ │ ├── css │ │ │ ├── buttons.css │ │ │ ├── forms.css │ │ │ ├── l10n.css │ │ │ └── login.css │ │ ├── images │ │ │ ├── 1024x768.png │ │ │ ├── 350x150.png │ │ │ ├── amp.svg │ │ │ ├── google.svg │ │ │ └── wordpress-logo.png │ │ ├── plugins │ │ │ ├── bad-block.php │ │ │ ├── bad-hooks.php │ │ │ ├── bad-shortcode.php │ │ │ └── bad-widget │ │ │ │ ├── bad-widget.php │ │ │ │ └── class-bad-widget.php │ │ └── themes │ │ │ ├── child-of-core │ │ │ ├── actions.php │ │ │ ├── functions.php │ │ │ └── style.css │ │ │ ├── custom │ │ │ ├── functions.php │ │ │ ├── index.php │ │ │ └── style.css │ │ │ └── with-legacy │ │ │ ├── amp │ │ │ └── meta-author.php │ │ │ └── style.css │ ├── maybe-generate-wp-cli-coverage.php │ ├── register-wp-cli-commands.php │ ├── src │ │ ├── Admin │ │ │ ├── AfterActivationSiteScanTest.php │ │ │ ├── AmpPluginsTest.php │ │ │ ├── AmpThemesTest.php │ │ │ ├── AnalyticsOptionsSubmenuTest.php │ │ │ ├── GoogleFontsTest.php │ │ │ ├── OnboardingWizardSubmenuPageTest.php │ │ │ ├── OnboardingWizardSubmenuTest.php │ │ │ ├── OptionsMenuTest.php │ │ │ ├── PairedBrowsingTest.php │ │ │ ├── PluginActivationNoticeTest.php │ │ │ ├── PluginRowMetaTest.php │ │ │ ├── PolyfillsTest.php │ │ │ ├── RESTPreloaderTest.php │ │ │ ├── ReaderThemesTest.php │ │ │ ├── ReenableCssTransientCachingAjaxActionTest.php │ │ │ ├── SiteHealthTest.php │ │ │ ├── SupportLinkTest.php │ │ │ ├── UserRESTEndpointExtensionTest.php │ │ │ └── ValidationCountsTest.php │ │ ├── AmpSlugCustomizationWatcherTest.php │ │ ├── AmpWpPluginTest.php │ │ ├── BackgroundTask │ │ │ ├── BackgroundTaskDeactivatorTest.php │ │ │ ├── MonitorCssTransientCachingTest.php │ │ │ └── ValidationDataGarbageCollectionTest.php │ │ ├── Behat │ │ │ └── FeatureContext.php │ │ ├── Cli │ │ │ ├── Export │ │ │ │ ├── ExportActivePlugins.php │ │ │ │ ├── ExportActiveThemes.php │ │ │ │ ├── ExportCustomizerSettings.php │ │ │ │ ├── ExportOptions.php │ │ │ │ ├── ExportResult.php │ │ │ │ ├── ExportThemeMods.php │ │ │ │ ├── ExportWidgets.php │ │ │ │ ├── ExportWxrFile.php │ │ │ │ └── MediaFileUploader.php │ │ │ ├── ExportStep.php │ │ │ ├── Import │ │ │ │ ├── ActivatePlugin.php │ │ │ │ ├── ActivateTheme.php │ │ │ │ ├── ImportCustomizerSettings.php │ │ │ │ ├── ImportOptions.php │ │ │ │ ├── ImportSiteMeta.php │ │ │ │ ├── ImportThemeMods.php │ │ │ │ ├── ImportWidgets.php │ │ │ │ ├── ImportWxrFile.php │ │ │ │ └── InstallTheme.php │ │ │ ├── ImportStep.php │ │ │ ├── ReferenceSiteCommandNamespace.php │ │ │ ├── ReferenceSiteExportCommand.php │ │ │ ├── ReferenceSiteImportCommand.php │ │ │ ├── ReferenceSiteImporter.php │ │ │ ├── SiteDefinition.php │ │ │ └── WpImporterCompat.php │ │ ├── DependencyInjectedTestCase.php │ │ ├── DependencySupportTest.php │ │ ├── DevTools │ │ │ ├── BlockSourcesTest.php │ │ │ ├── CallbackReflectionTest.php │ │ │ ├── ErrorPageTest.php │ │ │ ├── FileReflectionTest.php │ │ │ ├── LikelyCulpritDetectorTest.php │ │ │ └── UserAccessTest.php │ │ ├── Editor │ │ │ └── EditorSupportTest.php │ │ ├── ExtraThemeAndPluginHeadersTest.php │ │ ├── Fixture │ │ │ ├── DummyClass.php │ │ │ ├── DummyClassWithDependency.php │ │ │ ├── DummyClassWithNamedArguments.php │ │ │ ├── DummyInterface.php │ │ │ ├── DummyPairedUrlStructure.php │ │ │ ├── DummyService.php │ │ │ ├── DummyServiceBasedPlugin.php │ │ │ ├── DummyServiceWithDelay.php │ │ │ └── DummyServiceWithRequirements.php │ │ ├── Helpers │ │ │ ├── AssertRestApiField.php │ │ │ ├── ErrorComparison.php │ │ │ ├── HandleValidation.php │ │ │ ├── HomeUrlLoopbackRequestMocking.php │ │ │ ├── LoadsCoreThemes.php │ │ │ ├── MarkupComparison.php │ │ │ ├── MockAdminUser.php │ │ │ ├── MockPluginEnvironment.php │ │ │ ├── PrivateAccess.php │ │ │ ├── StubSanitizer.php │ │ │ ├── ThemesApiRequestMocking.php │ │ │ ├── ValidationRequestMocking.php │ │ │ ├── WithBlockEditorSupport.php │ │ │ └── WithoutBlockPreRendering.php │ │ ├── IconTest.php │ │ ├── Infrastructure │ │ │ ├── InjectionChainTest.php │ │ │ ├── LazilyInstantiatedServiceTest.php │ │ │ ├── ServiceBasedPluginTest.php │ │ │ ├── SimpleInjectorTest.php │ │ │ └── SimpleServiceContainerTest.php │ │ ├── Instrumentation │ │ │ ├── EventTest.php │ │ │ ├── EventWithDurationTest.php │ │ │ ├── ServerTimingTest.php │ │ │ ├── StopWatchEventTest.php │ │ │ └── StopWatchTest.php │ │ ├── LoadingErrorTest.php │ │ ├── MobileRedirectionTest.php │ │ ├── ObsoleteBlockAttributeRemoverTest.php │ │ ├── Optimizer │ │ │ ├── AmpWPConfigurationTest.php │ │ │ ├── HeroCandidateFilteringTest.php │ │ │ ├── OptimizerServiceTest.php │ │ │ └── Transformer │ │ │ │ └── DetermineHeroImagesTest.php │ │ ├── OptionsRESTControllerTest.php │ │ ├── PairedRoutingTest.php │ │ ├── PairedUrlStructure │ │ │ ├── LegacyReaderUrlStructureTest.php │ │ │ ├── LegacyTransitionalUrlStructureTest.php │ │ │ ├── PathSuffixUrlStructureTest.php │ │ │ └── QueryVarUrlStructureTest.php │ │ ├── PairedUrlStructureTest.php │ │ ├── PairedUrlTest.php │ │ ├── PhpStan │ │ │ ├── ServiceContainerDynamicReturnTypeExtension.php │ │ │ └── ServicesDynamicReturnTypeExtension.php │ │ ├── PluginRegistryTest.php │ │ ├── PluginSuppressionTest.php │ │ ├── ReaderThemeLoaderTest.php │ │ ├── ReaderThemeSupportFeaturesTest.php │ │ ├── RemoteRequest │ │ │ └── CachedRemoteGetRequestTest.php │ │ ├── SandboxingTest.php │ │ ├── TestCase.php │ │ ├── ValidatedUrlStylesheetDataGarbageCollectionTest.php │ │ ├── Validation │ │ │ ├── ScannableURLProviderTest.php │ │ │ ├── ScannableURLsRestControllerTest.php │ │ │ ├── URLValidationCronTest.php │ │ │ ├── URLValidationProviderTest.php │ │ │ ├── URLValidationRESTControllerTest.php │ │ │ └── ValidationCountsRestControllerTest.php │ │ └── ValidationExemptionTest.php │ ├── static-analysis-stubs │ │ ├── gutenberg.php │ │ ├── legacy-i18n.php │ │ ├── pwa.php │ │ ├── twentyseventeen.php │ │ ├── wordpress-defines.php │ │ └── wp-cli.php │ ├── test-amp-analytics-options.php │ ├── test-amp-audio-converter.php │ ├── test-amp-carousel.php │ ├── test-amp-crowdsignal-embed-handler.php │ ├── test-amp-dailymotion-embed-handler.php │ ├── test-amp-dev-mode-sanitizer.php │ ├── test-amp-facebook-embed-handler.php │ ├── test-amp-form-sanitizer.php │ ├── test-amp-gallery-embed-handler.php │ ├── test-amp-helper-functions.php │ ├── test-amp-iframe-sanitizer.php │ ├── test-amp-image-dimension-extract-download.php │ ├── test-amp-image-dimension-extractor.php │ ├── test-amp-img-sanitizer.php │ ├── test-amp-instagram-embed-handler.php │ ├── test-amp-layout-sanitizer.php │ ├── test-amp-o2-player-sanitizer.php │ ├── test-amp-pinterest-embed-handler.php │ ├── test-amp-playbuzz-sanitizer.php │ ├── test-amp-post-template-functions.php │ ├── test-amp-render-post.php │ ├── test-amp-scribd-embed-handler.php │ ├── test-amp-script-sanitizer.php │ ├── test-amp-soundcloud-embed-handler.php │ ├── test-amp-style-sanitizer.php │ ├── test-amp-tag-and-attribute-sanitizer-private-methods.php │ ├── test-amp-tumblr-embed-handler.php │ ├── test-amp-twitter-embed-handler.php │ ├── test-amp-video-sanitizer.php │ ├── test-amp-vimeo-embed-handler.php │ ├── test-amp-wordpress-embed-handler.php │ ├── test-amp.php │ ├── test-class-amp-accessibility-sanitizer.php │ ├── test-class-amp-admin-pointer.php │ ├── test-class-amp-auto-lightbox-disable-sanitizer.php │ ├── test-class-amp-base-sanitizer.php │ ├── test-class-amp-block-sanitizer.php │ ├── test-class-amp-cli-option-command.php │ ├── test-class-amp-cli-validation-command.php │ ├── test-class-amp-comments-sanitizer.php │ ├── test-class-amp-content-sanitizer.php │ ├── test-class-amp-core-block-handler.php │ ├── test-class-amp-core-theme-sanitizer.php │ ├── test-class-amp-customizer-design-settings.php │ ├── test-class-amp-dom-utils.php │ ├── test-class-amp-editor-blocks.php │ ├── test-class-amp-gallery-block-sanitizer.php │ ├── test-class-amp-gtag-script-sanitizer.php │ ├── test-class-amp-http.php │ ├── test-class-amp-imgur-embed-handler.php │ ├── test-class-amp-link-sanitizer.php │ ├── test-class-amp-meta-box.php │ ├── test-class-amp-meta-sanitizer.php │ ├── test-class-amp-native-img-attributes-sanitizer.php │ ├── test-class-amp-nav-menu-dropdown-sanitizer.php │ ├── test-class-amp-nav-menu-toggle-sanitizer.php │ ├── test-class-amp-object-sanitizer.php │ ├── test-class-amp-options-manager.php │ ├── test-class-amp-playlist-embed-handler.php │ ├── test-class-amp-post-type-support.php │ ├── test-class-amp-pwa-script-sanitizer.php │ ├── test-class-amp-reader-themes-rest-controller.php │ ├── test-class-amp-schema-org-metadata.php │ ├── test-class-amp-service-worker.php │ ├── test-class-amp-srcset-sanitizer.php │ ├── test-class-amp-template-customizer.php │ ├── test-class-amp-theme-support.php │ ├── test-class-amp-tiktok-embed-handler.php │ ├── test-class-amp-wordpress-tv-embed-handler.php │ ├── test-class-amp-youtube-embed-handler.php │ ├── test-dom-element-list.php │ ├── test-includes-admin-functions.php │ ├── test-tag-and-attribute-sanitizer.php │ ├── test-uninstall.php │ ├── test-wp-http-remote-get-request.php │ └── validation │ │ ├── test-class-amp-validated-url-post-type.php │ │ ├── test-class-amp-validation-error-taxonomy.php │ │ └── test-class-amp-validation-manager.php └── reference-sites │ ├── theme-unit-test.json │ ├── travel-blog.json │ └── travel-blog.xml ├── uninstall.php └── webpack.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | extends @wordpress/browserslist-config 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # WordPress Coding Standards 2 | # https://make.wordpress.org/core/handbook/coding-standards/ 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | indent_style = tab 12 | indent_size = 4 13 | 14 | [{.rtlcssrc,*.json,*.yml,*.feature}] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | [*.md] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/*.min.js 2 | **/node_modules/** 3 | **/vendor/** 4 | **/assets/js/*.js 5 | build/* 6 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # Apply Prettier formatting 2 | 614e495726bce56983b4c5dc948bac557afb4565 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Improve diff output for PHP files. 2 | *.php diff=php 3 | 4 | # Mark generated files so diffs are hidden by default. 5 | *.snap linguist-generated=true 6 | includes/sanitizers/class-amp-allowed-tags-generated.php linguist-generated=true 7 | docs/**/*.md linguist-generated=true 8 | docs/docs.json linguist-generated=true 9 | **/__data__/*.js linguist-generated=true 10 | includes/ecosystem-data/*.php linguist-generated=true 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: ❓ Plugin Support Forum 4 | url: https://wordpress.org/support/plugin/amp/ 5 | about: For plugin usage questions and compatibility issues with other plugins, please use the plugin's support forum. Before opening a new topic, please search the forum for existing topics as someone else has likely reported the issue already. 6 | - name: ℹ️ AMP for WordPress 7 | url: https://amp-wp.org/ 8 | about: Find documentation, a showcase of sites using the official AMP plugin, an ecosystem directory of compatible themes/plugins, and a blog with news on the plugin site. 9 | - name: 📺 Video Series 10 | url: https://www.youtube.com/playlist?list=PLXTOW_XMsIDRGRr5QDffrvND8Qh1RndFb 11 | about: Check out our video series on YouTube for an introduction to the plugin and how you can leverage it on your site. 12 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | 4 | Fixes # 5 | 6 | ## Checklist 7 | 8 | - [ ] My code is tested and passes existing [tests](https://github.com/ampproject/amp-wp/wiki/Engineering-Guidelines#tests). 9 | - [ ] My code follows the [Engineering Guidelines](https://github.com/ampproject/amp-wp/wiki/Engineering-Guidelines) (updates are often made to the guidelines, check it out periodically). 10 | -------------------------------------------------------------------------------- /.github/actions/determine-changed-files/determine-modified-files-count.php: -------------------------------------------------------------------------------- 1 | [--invert] 7 | * 8 | * For example: 9 | * php -f determine-modified-files-count.php "foo\/bar|bar*" "foo/bar/baz\nquux" --invert 10 | * 11 | * Would output: 1 12 | * 13 | * @codeCoverageIgnore 14 | * @package AMP 15 | */ 16 | 17 | $file_pattern = sprintf( '/^%s$/m', $argv[1] ); 18 | $modified_files = explode( "\n", trim( $argv[2] ) ); 19 | $preg_grep_flags = isset( $argv[3] ) && trim( $argv[3] ) === '--invert' ? PREG_GREP_INVERT : 0; 20 | 21 | $filtered_files = preg_grep( $file_pattern, $modified_files, $preg_grep_flags ); 22 | 23 | echo $filtered_files ? count( $filtered_files ) : 0; 24 | -------------------------------------------------------------------------------- /.github/actions/plugin-build/action.yml: -------------------------------------------------------------------------------- 1 | name: Build plugin assets 2 | 3 | description: Build and cache the plugin assets to speed up builds. 4 | 5 | runs: 6 | using: 'composite' 7 | steps: 8 | - name: Cache assets directory 9 | uses: actions/cache@v4 10 | id: assets-cache 11 | env: 12 | SEGMENT_DOWNLOAD_TIMEOUT_MINS: '5' 13 | with: 14 | path: ${{ github.workspace }}/assets 15 | key: ${{ runner.os }}-amp-wp-assets-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('assets/**') }} 16 | 17 | - name: Build plugin assets 18 | if: ${{ steps.assets-cache.outputs.cache-hit != 'true' }} 19 | shell: bash 20 | run: npm run build:js 21 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | authors: 4 | - dependabot 5 | - dependabot-preview 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | 4 | /vendor 5 | /build 6 | /artifacts 7 | /wiki 8 | /amp.zip 9 | /assets/css/* 10 | !/assets/css/src/ 11 | /assets/js/**/*.js 12 | /assets/js/*.asset.php 13 | /assets/js/*.map 14 | /built 15 | /amphtml 16 | /.env 17 | /.idea/ 18 | /.vscode/ 19 | /phpcs.xml 20 | /phpunit.xml 21 | /.phpunit.result.cache 22 | /*.sql 23 | /.wp-env.override.json 24 | 25 | # Generated via bin/transform-readme.php 26 | /readme.txt 27 | 28 | # Generated via phpstan analyse --generate-baseline temp-baseline.php 29 | /temp-baseline.php 30 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/.gitmodules -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npm run lint:staged 2 | -------------------------------------------------------------------------------- /.lintstagedrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'package.json': ['npm run lint:pkg-json'], 3 | '**/*.(css|scss)': ['npm run lint:css'], 4 | '**/*.js': ['npm run lint:js'], 5 | '**/!(amp.php).php': ['npm run lint:php'], 6 | 'amp.php': ['vendor/bin/phpcs --runtime-set testVersion 5.2-'], 7 | '*.php': () => 'composer analyze', 8 | }; 9 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | save-exact = true 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 20 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | "@wordpress/prettier-config" 2 | -------------------------------------------------------------------------------- /.rtlcssrc: -------------------------------------------------------------------------------- 1 | { 2 | "options": { 3 | "autoRename": false, 4 | "autoRenameStrict": false, 5 | "blacklist": {}, 6 | "clean": true, 7 | "greedy": false, 8 | "processUrls": false, 9 | "stringMap": [] 10 | }, 11 | "plugins": [], 12 | "map": false 13 | } 14 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | /assets/css/*.css 2 | /bin 3 | /build 4 | /qa-tester 5 | /tests 6 | /vendor 7 | -------------------------------------------------------------------------------- /.wordpress-org/banner-1544x500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/.wordpress-org/banner-1544x500.png -------------------------------------------------------------------------------- /.wordpress-org/banner-772x250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/.wordpress-org/banner-772x250.png -------------------------------------------------------------------------------- /.wordpress-org/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/.wordpress-org/icon-128x128.png -------------------------------------------------------------------------------- /.wordpress-org/icon-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/.wordpress-org/icon-256x256.png -------------------------------------------------------------------------------- /.wordpress-org/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | AMP 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.wordpress-org/screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/.wordpress-org/screenshot-1.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/.wordpress-org/screenshot-2.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/.wordpress-org/screenshot-3.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/.wordpress-org/screenshot-4.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/.wordpress-org/screenshot-5.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/.wordpress-org/screenshot-6.png -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | This document has moved to the [Contributing](https://github.com/ampproject/amp-wp/wiki/Contributing) page on the wiki. 2 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Disclosures 2 | 3 | The AMP Project accepts responsible security disclosures through the [Google Application Security program](https://www.google.com/about/appsecurity/). 4 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | For plugin usage questions and compatibility issues with other plugins, please use the [plugin's support forum](https://wordpress.org/support/plugin/amp/). Before opening a new topic, please search the forum for existing topics as someone else has likely reported the issue already. 2 | 3 | Find documentation, a showcase of sites using the official AMP plugin, an ecosystem directory of compatible themes/plugins, and a blog with news on the plugin site: [amp-wp.org](https://amp-wp.org/). 4 | 5 | Check out our [video series on YouTube](https://www.youtube.com/playlist?list=PLXTOW_XMsIDRGRr5QDffrvND8Qh1RndFb) for an introduction to the plugin and how you can leverage it on your site. 6 | -------------------------------------------------------------------------------- /assets/css/src/amp-mobile-version-switcher.css: -------------------------------------------------------------------------------- 1 | #amp-mobile-version-switcher { 2 | position: absolute; 3 | width: 100%; 4 | left: 0; 5 | z-index: 100; 6 | } 7 | 8 | #amp-mobile-version-switcher > a { 9 | display: block; 10 | padding: 15px 0; 11 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 12 | font-size: 16px; 13 | font-weight: 600; 14 | color: #eaeaea; 15 | text-align: center; 16 | text-decoration: none; 17 | background-color: #444; 18 | border: 0; 19 | } 20 | 21 | #amp-mobile-version-switcher > a:hover, 22 | #amp-mobile-version-switcher > a:focus, 23 | #amp-mobile-version-switcher > a:active { 24 | text-decoration: underline; 25 | } 26 | -------------------------------------------------------------------------------- /assets/css/src/amp-playlist-shortcode.css: -------------------------------------------------------------------------------- 1 | /** 2 | * For the custom AMP implementation of the 'playlist' shortcode. 3 | */ 4 | .wp-playlist .wp-playlist-current-item img { 5 | float: left; 6 | margin-right: 10px; 7 | } 8 | 9 | .wp-playlist audio { 10 | display: block; 11 | } 12 | 13 | .wp-playlist .amp-carousel-button { 14 | visibility: hidden; 15 | } 16 | -------------------------------------------------------------------------------- /assets/css/src/amp-validation-tooltips.css: -------------------------------------------------------------------------------- 1 | 2 | /* @todo This should be moved to admin-tables.css which is then enqueued on both screens. */ 3 | .tooltip-button { 4 | margin: 0 6px; 5 | cursor: pointer; 6 | color: #767676; 7 | } 8 | 9 | .tooltip[hidden] { 10 | visibility: hidden; 11 | } 12 | -------------------------------------------------------------------------------- /assets/css/src/components/_amp-stylesheet-summary.scss: -------------------------------------------------------------------------------- 1 | .amp-stylesheet-summary { 2 | margin-bottom: 1em; 3 | 4 | span.amp-icon { 5 | font-size: 16px; 6 | vertical-align: middle; 7 | } 8 | 9 | th { 10 | text-align: right; 11 | padding-right: 1ex; 12 | font-weight: normal; 13 | } 14 | 15 | td { 16 | font-weight: bold; 17 | text-align: right; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /assets/css/src/components/_error-details-toggle.scss: -------------------------------------------------------------------------------- 1 | // Error details toggle button used in head and foot of WP list table. 2 | .error-details-toggle { 3 | background: none; 4 | border: none; 5 | cursor: pointer; 6 | display: flex; 7 | flex-direction: column; 8 | float: right; 9 | height: 14px; 10 | margin: 0; 11 | padding: 0; 12 | 13 | .manage-column.column-sources_with_invalid_output & { 14 | margin: 0; 15 | } 16 | 17 | .column-details & { 18 | 19 | &::before, 20 | &::after { 21 | background-image: url("../images/down-triangle.svg"); 22 | background-position: center; 23 | background-size: cover; 24 | content: ""; 25 | height: 6px; 26 | width: 12px; 27 | } 28 | } 29 | 30 | &.is-open { 31 | 32 | &::before, 33 | &::after { 34 | transform: rotate(180deg); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /assets/css/src/components/_wp-list-table-grid-lines.scss: -------------------------------------------------------------------------------- 1 | // Grid lines between table rows. 2 | .wp-list-table.table-view-list > tbody > tr { 3 | 4 | > td, 5 | > th { 6 | box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.22); 7 | } 8 | 9 | &:last-child, 10 | &.expanded { 11 | 12 | > td, 13 | > th { 14 | box-shadow: none; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /assets/css/src/components/_wp-list-table-kept-errors.scss: -------------------------------------------------------------------------------- 1 | // Row left border indicating error status. 2 | .wp-list-table.table-view-list > tbody > tr { 3 | 4 | &.expanded:not(.kept) + tr > :first-child { 5 | padding-left: 10px + 4px; // Push the details content by 4px (border width) so that it aligns with the title row. 6 | } 7 | 8 | &.kept { 9 | 10 | > :first-child, 11 | &.expanded + tr > :first-child { 12 | border-left: 4px solid #d54e21; 13 | } 14 | 15 | .check-column input { 16 | margin-left: 4px; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /assets/css/src/components/_wp-list-table-markup-status-icon.scss: -------------------------------------------------------------------------------- 1 | // Add markup status icon next to the dropdown. 2 | .wp-list-table.table-view-list > tbody > tr { 3 | 4 | .amp-validation-error-status-dropdown { 5 | align-items: center; 6 | display: flex; 7 | } 8 | 9 | .amp-validation-error-status-dropdown::after { 10 | background: #d3e5e5 url("../images/amp-delete.svg") no-repeat center; 11 | background-size: 20px auto; 12 | border-radius: 5px; 13 | content: ""; 14 | display: inline-block; 15 | height: 20px; 16 | width: 20px; 17 | } 18 | 19 | &.kept .amp-validation-error-status-dropdown::after { 20 | background-color: #f7ded4; 21 | background-image: url("../images/amp-alert.svg"); 22 | background-size: 18px auto; 23 | } 24 | 25 | select.amp-validation-error-status { 26 | margin-right: 10px; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /assets/css/src/components/_wp-list-table-new-errors.scss: -------------------------------------------------------------------------------- 1 | // Grey background and bold title to indicate new errors. 2 | .wp-list-table.table-view-list > tbody { 3 | 4 | td, 5 | .row-title:not(:hover) { 6 | color: #1e1e1e; 7 | } 8 | 9 | > tr { 10 | 11 | &, 12 | &.expanded + .details { 13 | background-color: #f4f4f4; 14 | } 15 | 16 | &.new, 17 | &.new.expanded + .details { 18 | background-color: #fff; 19 | } 20 | } 21 | 22 | > tr { 23 | 24 | .row-title, 25 | .column-primary > :first-child { 26 | font-weight: 400; 27 | } 28 | 29 | &.new { 30 | 31 | .row-title, 32 | .column-primary > :first-child { 33 | font-weight: 600; 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /assets/fonts/genericons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/fonts/genericons.woff -------------------------------------------------------------------------------- /assets/fonts/nonbreakingspaceoverride.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/fonts/nonbreakingspaceoverride.woff -------------------------------------------------------------------------------- /assets/fonts/nonbreakingspaceoverride.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/fonts/nonbreakingspaceoverride.woff2 -------------------------------------------------------------------------------- /assets/images/amp-alert.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/amp-css-error-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/amp-delete.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/amp-html-error-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/amp-icon-toolbar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/amp-logo-gray.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /assets/images/amp-logo-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/amp-page-fallback-wordpress-publisher-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/images/amp-page-fallback-wordpress-publisher-logo.png -------------------------------------------------------------------------------- /assets/images/amp-valid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/bell-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/down-triangle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/placeholder-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/images/placeholder-icon.png -------------------------------------------------------------------------------- /assets/images/reader-themes/legacy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/images/reader-themes/legacy.jpg -------------------------------------------------------------------------------- /assets/images/reader-themes/twentyeleven.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/images/reader-themes/twentyeleven.jpg -------------------------------------------------------------------------------- /assets/images/reader-themes/twentyfifteen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/images/reader-themes/twentyfifteen.jpg -------------------------------------------------------------------------------- /assets/images/reader-themes/twentyfourteen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/images/reader-themes/twentyfourteen.jpg -------------------------------------------------------------------------------- /assets/images/reader-themes/twentynineteen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/images/reader-themes/twentynineteen.jpg -------------------------------------------------------------------------------- /assets/images/reader-themes/twentyseventeen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/images/reader-themes/twentyseventeen.jpg -------------------------------------------------------------------------------- /assets/images/reader-themes/twentysixteen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/images/reader-themes/twentysixteen.jpg -------------------------------------------------------------------------------- /assets/images/reader-themes/twentythirteen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/images/reader-themes/twentythirteen.jpg -------------------------------------------------------------------------------- /assets/images/reader-themes/twentytwelve.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/images/reader-themes/twentytwelve.jpg -------------------------------------------------------------------------------- /assets/images/reader-themes/twentytwenty.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/images/reader-themes/twentytwenty.jpg -------------------------------------------------------------------------------- /assets/images/reader-themes/twentytwentyone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/assets/images/reader-themes/twentytwentyone.jpg -------------------------------------------------------------------------------- /assets/src/admin/amp-validation-tooltips.js: -------------------------------------------------------------------------------- 1 | /* global jQuery */ 2 | 3 | /** 4 | * WordPress dependencies 5 | */ 6 | import domReady from '@wordpress/dom-ready'; 7 | // Disable reason: Needed so that the wp-pointer script is added to dependencies list by webpack. 8 | // eslint-disable-next-line import/no-unresolved 9 | import '@wordpress/pointer'; 10 | 11 | // WIP Pointer function 12 | function sourcesPointer() { 13 | jQuery(document).on('click', '.tooltip-button', function () { 14 | jQuery(this) 15 | .pointer({ 16 | content: jQuery(this).next('.tooltip').attr('data-content'), 17 | position: { 18 | edge: 'left', 19 | align: 'center', 20 | }, 21 | pointerClass: 'wp-pointer wp-pointer--tooltip', 22 | }) 23 | .pointer('open'); 24 | }); 25 | } 26 | 27 | domReady(sourcesPointer); 28 | -------------------------------------------------------------------------------- /assets/src/admin/site-scan-notice/style.scss: -------------------------------------------------------------------------------- 1 | .amp-site-scan-notice__cta { 2 | display: flex; 3 | flex-flow: row; 4 | margin: 0.5rem 0 1rem; 5 | 6 | > .button + .button { 7 | margin-left: 0.5rem; 8 | } 9 | } 10 | 11 | .amp-site-scan-notice__source-details { 12 | margin: 0.5rem 0; 13 | } 14 | 15 | .amp-site-scan-notice__source-summary { 16 | cursor: pointer; 17 | } 18 | 19 | .amp-site-scan-notice__urls-list { 20 | margin: 0.5rem 0 1rem; 21 | padding: 0 1rem; 22 | } 23 | -------------------------------------------------------------------------------- /assets/src/amp-validation/counts/style.css: -------------------------------------------------------------------------------- 1 | @keyframes rotate-forever { 2 | 3 | 0% { 4 | transform: rotate(0deg); 5 | } 6 | 7 | 100% { 8 | transform: rotate(360deg); 9 | } 10 | } 11 | 12 | #toplevel_page_amp-options .amp-count-loading { 13 | animation-duration: 0.75s; 14 | animation-iteration-count: infinite; 15 | animation-name: rotate-forever; 16 | animation-timing-function: linear; 17 | height: 4px; 18 | width: 4px; 19 | border: 2px solid #fff; 20 | border-right-color: transparent; 21 | border-top-color: transparent; 22 | border-radius: 50%; 23 | display: inline-block; 24 | } 25 | 26 | body.no-js #amp-new-validation-url-count, 27 | body.no-js #amp-new-error-index-count { 28 | display: none; 29 | } 30 | -------------------------------------------------------------------------------- /assets/src/amp-validation/get-url-validation-table-rows.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Gets the table rows on a single URL validation screen. 3 | * 4 | * @param {Object} options 5 | * @param {boolean} options.checkedOnly Whether to return only checked rows. 6 | */ 7 | export function getURLValidationTableRows(options = {}) { 8 | const rows = [ 9 | ...document.querySelectorAll('select.amp-validation-error-status'), 10 | ].map((select) => select.closest('tr')); 11 | 12 | if (true !== options.checkedOnly) { 13 | return rows; 14 | } 15 | 16 | return rows.filter( 17 | (row) => row.querySelector('.check-column input[type=checkbox]').checked 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /assets/src/block-editor/blocks/amp-mathml/edit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import PropTypes from 'prop-types'; 5 | 6 | /** 7 | * WordPress dependencies 8 | */ 9 | import { __ } from '@wordpress/i18n'; 10 | import { PlainText } from '@wordpress/block-editor'; 11 | 12 | const BlockEdit = ({ attributes, setAttributes }) => { 13 | const { dataFormula } = attributes; 14 | 15 | return ( 16 | setAttributes({ dataFormula: value })} 20 | /> 21 | ); 22 | }; 23 | 24 | BlockEdit.propTypes = { 25 | attributes: PropTypes.shape({ 26 | dataFormula: PropTypes.string, 27 | }), 28 | setAttributes: PropTypes.func.isRequired, 29 | }; 30 | 31 | export default BlockEdit; 32 | -------------------------------------------------------------------------------- /assets/src/block-editor/blocks/amp-mathml/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | import { __ } from '@wordpress/i18n'; 5 | 6 | /** 7 | * Internal dependencies 8 | */ 9 | import edit from './edit'; 10 | import save from './save'; 11 | 12 | export const name = 'amp/amp-mathml'; 13 | 14 | export const settings = { 15 | title: __('AMP MathML', 'amp'), 16 | category: 'common', 17 | icon: 'welcome-learn-more', 18 | keywords: [ 19 | __('Mathematical formula', 'amp'), 20 | __('Scientific content', 'amp'), 21 | ], 22 | 23 | attributes: { 24 | dataFormula: { 25 | source: 'attribute', 26 | selector: 'amp-mathml', 27 | attribute: 'data-formula', 28 | }, 29 | }, 30 | 31 | edit, 32 | 33 | save, 34 | }; 35 | -------------------------------------------------------------------------------- /assets/src/block-editor/blocks/amp-mathml/save.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import PropTypes from 'prop-types'; 5 | 6 | const BlockSave = ({ attributes }) => { 7 | const { dataFormula } = attributes; 8 | 9 | const mathmlProps = { 10 | 'data-formula': dataFormula, 11 | layout: 'container', 12 | }; 13 | return <amp-mathml {...mathmlProps} />; 14 | }; 15 | 16 | BlockSave.propTypes = { 17 | attributes: PropTypes.shape({ 18 | dataFormula: PropTypes.string, 19 | }), 20 | }; 21 | 22 | export default BlockSave; 23 | -------------------------------------------------------------------------------- /assets/src/block-editor/blocks/amp-reach-player/save.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import PropTypes from 'prop-types'; 5 | 6 | const BlockSave = ({ attributes }) => { 7 | const { dataEmbedId, ampLayout, height, width } = attributes; 8 | 9 | const reachProps = { 10 | layout: ampLayout, 11 | height, 12 | 'data-embed-id': dataEmbedId, 13 | }; 14 | if ('fixed-height' !== ampLayout && width) { 15 | reachProps.width = width; 16 | } 17 | return <amp-reach-player {...reachProps} />; 18 | }; 19 | 20 | BlockSave.propTypes = { 21 | attributes: PropTypes.shape({ 22 | dataEmbedId: PropTypes.string, 23 | ampLayout: PropTypes.string, 24 | height: PropTypes.number, 25 | width: PropTypes.number, 26 | }), 27 | }; 28 | 29 | export default BlockSave; 30 | -------------------------------------------------------------------------------- /assets/src/block-editor/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as MediaPlaceholder } from './media-placeholder'; 2 | export { default as LayoutControls } from './layout-controls'; 3 | export { default as withMediaLibraryNotice } from './with-media-library-notice'; 4 | -------------------------------------------------------------------------------- /assets/src/block-editor/constants.js: -------------------------------------------------------------------------------- 1 | export const TEXT_BLOCKS = [ 2 | 'core/paragraph', 3 | 'core/heading', 4 | 'core/code', 5 | 'core/quote', 6 | 'core/subhead', 7 | ]; 8 | -------------------------------------------------------------------------------- /assets/src/block-editor/helpers/test/addAMPAttributes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import { describe, expect, it } from '@jest/globals'; 5 | 6 | /** 7 | * Internal dependencies 8 | */ 9 | import { addAMPAttributes } from '..'; 10 | 11 | describe('addAMPAttributes', () => { 12 | it('adds attributes to core/gallery block', () => { 13 | expect(addAMPAttributes({}, 'core/gallery')).toMatchObject({ 14 | attributes: { 15 | ampCarousel: { 16 | type: 'boolean', 17 | default: true, 18 | }, 19 | ampLightbox: { 20 | type: 'boolean', 21 | default: false, 22 | }, 23 | }, 24 | }); 25 | }); 26 | 27 | it('adds attributes to core/image block', () => { 28 | expect(addAMPAttributes({}, 'core/image')).toMatchObject({ 29 | attributes: { 30 | ampLightbox: { 31 | type: 'boolean', 32 | default: false, 33 | }, 34 | }, 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /assets/src/block-editor/plugins/amp-preview-item.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Internal dependencies 3 | */ 4 | import { AMPFilledIcon } from '../../icons'; 5 | import AmpPreviewMenuItem from '../components/preview-menu-item'; 6 | 7 | export const name = 'amp-preview-menu-item'; 8 | 9 | export const icon = ( 10 | <AMPFilledIcon viewBox="0 0 62 62" height={18} width={18} /> 11 | ); 12 | 13 | export const onlyPaired = true; 14 | 15 | export const render = AmpPreviewMenuItem; 16 | -------------------------------------------------------------------------------- /assets/src/block-editor/plugins/pre-publish-panel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Internal dependencies 3 | */ 4 | import { PrePublishPanel } from '../../common/components'; 5 | 6 | export const name = 'amp-post-featured-image-pre-publish-panel'; 7 | 8 | // Add the featured image selection component as a pre-publish check. 9 | export const render = () => { 10 | return <PrePublishPanel />; 11 | }; 12 | -------------------------------------------------------------------------------- /assets/src/block-editor/store/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | import { createReduxStore, register } from '@wordpress/data'; 5 | 6 | /** 7 | * Internal dependencies 8 | */ 9 | import * as selectors from './selectors'; 10 | 11 | /** 12 | * Module Constants 13 | */ 14 | const MODULE_KEY = 'amp/block-editor'; 15 | 16 | export default register( 17 | createReduxStore(MODULE_KEY, { 18 | reducer: (state) => state, 19 | selectors, 20 | initialState: { 21 | ...window.ampBlockEditor, 22 | }, 23 | }) 24 | ); 25 | -------------------------------------------------------------------------------- /assets/src/block-validation/components/amp-validation-status/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Internal dependencies 3 | */ 4 | import { SidebarNotificationsContainer } from '../sidebar-notification'; 5 | import AMPRevalidateNotification from './revalidate-notification'; 6 | import AMPValidationStatusNotification from './status-notification'; 7 | 8 | export default function AMPValidationStatus() { 9 | return ( 10 | <SidebarNotificationsContainer isShady={true}> 11 | <AMPRevalidateNotification /> 12 | <AMPValidationStatusNotification /> 13 | </SidebarNotificationsContainer> 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /assets/src/block-validation/components/sidebar-notification/test/__snapshots__/sidebar-notification.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`SidebarNotification renders notification without icon and call to action 1`] = `"<div class="sidebar-notification"><div class="sidebar-notification__content"><p>Foobar</p></div></div>"`; 4 | 5 | exports[`SidebarNotification renders status message with icon and call to action 1`] = `"<div class="sidebar-notification"><div class="sidebar-notification__icon"><svg></svg></div><div class="sidebar-notification__content"><p>Foobar</p><div class="sidebar-notification__action"><button></button></div></div></div>"`; 6 | -------------------------------------------------------------------------------- /assets/src/block-validation/components/sidebar-notification/test/sidebar-notifications-container.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import { render } from '@testing-library/react'; 5 | import { describe, expect, it } from '@jest/globals'; 6 | 7 | /** 8 | * Internal dependencies 9 | */ 10 | import { SidebarNotificationsContainer } from '../index'; 11 | 12 | describe('SidebarNotificationsContainer', () => { 13 | it('renders sidebar notifications container along with children', () => { 14 | const { container } = render( 15 | <SidebarNotificationsContainer> 16 | {'Foo'} 17 | </SidebarNotificationsContainer> 18 | ); 19 | 20 | expect( 21 | container.querySelector('.sidebar-notifications-container') 22 | ).not.toBeNull(); 23 | expect( 24 | container.querySelector('.sidebar-notifications-container') 25 | .textContent 26 | ).toBe('Foo'); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /assets/src/block-validation/components/sidebar/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Errors list in AMP sidebar. 3 | */ 4 | .amp-sidebar__errors-list, 5 | .amp-sidebar__errors-list-item { 6 | margin-bottom: 0; 7 | margin-top: 0; 8 | } 9 | 10 | .amp-sidebar__errors-list-item > .components-panel__body { 11 | border-top-width: 0; 12 | } 13 | 14 | /* 15 | * Options in AMP sidebar. 16 | */ 17 | .amp-sidebar__options { 18 | margin: 12px 8px; 19 | } 20 | -------------------------------------------------------------------------------- /assets/src/block-validation/hooks/use-amp-document-toggle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | import { useDispatch, useSelect } from '@wordpress/data'; 5 | 6 | /** 7 | * Custom hook providing an easy way to toggle AMP and check if it is enabled. 8 | */ 9 | export function useAMPDocumentToggle() { 10 | const isAMPEnabled = useSelect( 11 | (select) => 12 | select('core/editor').getEditedPostAttribute('amp_enabled') || 13 | false, 14 | [] 15 | ); 16 | const { editPost } = useDispatch('core/editor'); 17 | const toggleAMP = () => editPost({ amp_enabled: !isAMPEnabled }); 18 | 19 | return { 20 | isAMPEnabled, 21 | toggleAMP, 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /assets/src/block-validation/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | import { addFilter } from '@wordpress/hooks'; 5 | import { registerPlugin } from '@wordpress/plugins'; 6 | 7 | /** 8 | * Internal dependencies 9 | */ 10 | import { withAMPToolbarButton } from './components/with-amp-toolbar-button'; 11 | 12 | const plugins = require.context('./plugins', true, /.*\.js$/); 13 | 14 | plugins.keys().forEach((modulePath) => { 15 | const { default: render, PLUGIN_NAME, PLUGIN_ICON } = plugins(modulePath); 16 | 17 | registerPlugin(PLUGIN_NAME, { 18 | icon: PLUGIN_ICON, 19 | render, 20 | }); 21 | }); 22 | 23 | addFilter( 24 | 'editor.BlockEdit', 25 | 'ampBlockValidation/filterEdit', 26 | withAMPToolbarButton, 27 | -99 28 | ); 29 | -------------------------------------------------------------------------------- /assets/src/block-validation/plugins/amp-document-setting-panel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | import { __ } from '@wordpress/i18n'; 5 | import { PluginDocumentSettingPanel } from '@wordpress/edit-post'; 6 | 7 | /** 8 | * Internal dependencies 9 | */ 10 | import AMPDocumentStatusNotification from '../components/amp-document-status'; 11 | 12 | export const PLUGIN_NAME = 'amp-block-validation-document-setting-panel'; 13 | export const PLUGIN_ICON = ''; 14 | 15 | /** 16 | * AMP block validation document settings panel. 17 | */ 18 | export default function AMPDocumentSettingPanel() { 19 | return ( 20 | <PluginDocumentSettingPanel 21 | name={PLUGIN_NAME} 22 | title={__('AMP', 'amp')} 23 | initialOpen={true} 24 | > 25 | <AMPDocumentStatusNotification /> 26 | </PluginDocumentSettingPanel> 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /assets/src/block-validation/plugins/amp-pre-publish-panel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | import { __ } from '@wordpress/i18n'; 5 | import { PluginPrePublishPanel } from '@wordpress/edit-post'; 6 | 7 | /** 8 | * Internal dependencies 9 | */ 10 | import AMPDocumentStatusNotification from '../components/amp-document-status'; 11 | 12 | export const PLUGIN_NAME = 'amp-block-validation-pre-publish-panel'; 13 | export const PLUGIN_ICON = ''; 14 | 15 | /** 16 | * AMP block validation pre-publish panel. 17 | */ 18 | export default function AMPPrePublishPanel() { 19 | return ( 20 | <PluginPrePublishPanel title={__('AMP', 'amp')} initialOpen={true}> 21 | <AMPDocumentStatusNotification /> 22 | </PluginPrePublishPanel> 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /assets/src/common/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as PrePublishPanel } from './pre-publish-panel'; 2 | export { default as withFeaturedImageNotice } from './higher-order/with-featured-image-notice'; 3 | export { default as withEnforcedFileType } from './with-enforced-file-type'; 4 | -------------------------------------------------------------------------------- /assets/src/common/components/pre-publish-panel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | import { PostFeaturedImage } from '@wordpress/editor'; 5 | import { PluginPrePublishPanel } from '@wordpress/edit-post'; 6 | import { __ } from '@wordpress/i18n'; 7 | 8 | /** 9 | * Adds a pre-publish panel containing the featured image selection component. 10 | * 11 | * Note: The `PostFeaturedImage` component would have already been filtered to include 12 | * any notices for the featured image so there is no need to recreate them here. 13 | * 14 | * @return {Function} A pre-publish panel containing the featured image selection component. 15 | */ 16 | const PrePublishPanel = () => { 17 | return ( 18 | <PluginPrePublishPanel 19 | title={__('Featured Image', 'amp')} 20 | initialOpen="true" 21 | > 22 | <PostFeaturedImage /> 23 | </PluginPrePublishPanel> 24 | ); 25 | }; 26 | 27 | export default PrePublishPanel; 28 | -------------------------------------------------------------------------------- /assets/src/common/constants.js: -------------------------------------------------------------------------------- 1 | // See https://github.com/ampproject/amphtml/blob/e7a1b3ff97645ec0ec482192205134bd0735943c/extensions/amp-fit-text/0.1/amp-fit-text.js#L81-L85 2 | export const MIN_FONT_SIZE = 6; 3 | export const MAX_FONT_SIZE = 72; 4 | export const FILE_TYPE_ERROR_VIEW = 'select-file-type-error'; 5 | 6 | export const READER = 'reader'; 7 | export const STANDARD = 'standard'; 8 | export const TRANSITIONAL = 'transitional'; 9 | export const DEFAULT_MOBILE_BREAKPOINT = 783; 10 | -------------------------------------------------------------------------------- /assets/src/common/helpers/get-plugin-slug-from-file.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Get plugin slug from file path. 3 | * 4 | * If the plugin file is in a directory, then the slug is just the directory name. Otherwise, if the file is not 5 | * inside of a directory and is just a single-file plugin, then the slug is the filename of the PHP file. 6 | * 7 | * If the file path contains a file extension, it will be stripped as well. 8 | * 9 | * See the corresponding PHP logic in `\AmpProject\AmpWP\get_plugin_slug_from_file()`. 10 | * 11 | * @param {string} path Plugin file path. 12 | * @return {string} Plugin slug. 13 | */ 14 | export function getPluginSlugFromFile(path = '') { 15 | return path.replace(/\/.*$/, '').replace(/\.php$/, ''); 16 | } 17 | -------------------------------------------------------------------------------- /assets/src/common/helpers/is-external-url.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Check if the provided URL is external. 3 | * 4 | * @param {string} url URL to be checked. 5 | * @return {boolean} True if the URL is external, false otherwise. 6 | */ 7 | export const isExternalUrl = (url) => 8 | global?.location?.host !== new URL(url).host; 9 | -------------------------------------------------------------------------------- /assets/src/common/helpers/test/__mocks__/amp-block-editor-data.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Mock for amp block editor data to be used in featured image test. 3 | * 4 | * @type {{featuredImageMinimumHeight: number, featuredImageMinimumWidth: number}} 5 | */ 6 | const mockAmpBlockEditorData = { 7 | featuredImageMinimumWidth: 1200, 8 | featuredImageMinimumHeight: 675, 9 | }; 10 | 11 | module.exports = mockAmpBlockEditorData; 12 | -------------------------------------------------------------------------------- /assets/src/common/helpers/test/get-plugin-slug-from-file.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import { describe, expect, it } from '@jest/globals'; 5 | 6 | /** 7 | * Internal dependencies 8 | */ 9 | import { getPluginSlugFromFile } from '../get-plugin-slug-from-file'; 10 | 11 | describe('getPluginSlugFromFile', () => { 12 | it('should return correct plugin slug', () => { 13 | expect(getPluginSlugFromFile('foo')).toBe('foo'); 14 | expect(getPluginSlugFromFile('foo.php')).toBe('foo'); 15 | expect(getPluginSlugFromFile('foo/bar')).toBe('foo'); 16 | expect(getPluginSlugFromFile('foo/baz.php')).toBe('foo'); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /assets/src/common/helpers/test/getMinimumFeaturedImageDimensions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import { describe, expect, it } from '@jest/globals'; 5 | 6 | /** 7 | * Internal dependencies 8 | */ 9 | import { getMinimumFeaturedImageDimensions } from '../'; 10 | 11 | describe('getMinimumFeaturedImageDimensions', () => { 12 | it('should return size with correct aspect ratio', () => { 13 | expect(getMinimumFeaturedImageDimensions()).toStrictEqual({ 14 | width: 1200, 15 | height: 675, 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /assets/src/common/helpers/test/getNoticeTemplate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import { describe, expect, it } from '@jest/globals'; 5 | 6 | /** 7 | * WordPress dependencies 8 | */ 9 | import { sprintf } from '@wordpress/i18n'; 10 | 11 | /** 12 | * Internal dependencies 13 | */ 14 | import { getNoticeTemplate } from '../'; 15 | 16 | describe('getNoticeTemplate', () => { 17 | const message = 'This is an example message'; 18 | const template = getNoticeTemplate(message); 19 | const type = typeof template; 20 | 21 | it('should have the proper type', () => { 22 | expect(type).toBe('function'); 23 | }); 24 | 25 | it('should return the correct message', () => { 26 | expect(template()).toBe(sprintf('<p>%s</p>', message)); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /assets/src/common/helpers/test/is-external-url.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import { describe, expect, it } from '@jest/globals'; 5 | 6 | /** 7 | * Internal dependencies 8 | */ 9 | import { isExternalUrl } from '../is-external-url'; 10 | 11 | describe('isExternalUrl', () => { 12 | it('should return true if of a URL is external and false otherwise', () => { 13 | expect(isExternalUrl('https://example.com/')).toBe(true); 14 | expect(isExternalUrl('https://localhost/')).toBe(false); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /assets/src/components/amp-admin-notice/test/__snapshots__/amp-admin-notice.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`AmpAdminNotice matches the snapshot 1`] = ` 4 | <div 5 | className="amp-admin-notice amp-admin-notice--info" 6 | /> 7 | `; 8 | -------------------------------------------------------------------------------- /assets/src/components/amp-info/style.css: -------------------------------------------------------------------------------- 1 | .amp-info { 2 | display: inline-block; 3 | font-size: 14px; 4 | font-weight: 600; 5 | margin-bottom: 1rem; 6 | } 7 | 8 | .amp-info__icon { 9 | float: left; 10 | margin: 0 0.5rem; 11 | } 12 | -------------------------------------------------------------------------------- /assets/src/components/amp-info/test/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import { create } from 'react-test-renderer'; 5 | import { describe, expect, it } from '@jest/globals'; 6 | 7 | /** 8 | * Internal dependencies 9 | */ 10 | import { AMPInfo } from '..'; 11 | import { IconMobile } from '../../svg/icon-mobile'; 12 | 13 | describe('AMPInfo', () => { 14 | it('matches snapshots', () => { 15 | let wrapper = create(<AMPInfo />); 16 | 17 | expect(wrapper.toJSON()).toMatchSnapshot(); 18 | 19 | wrapper = create( 20 | <AMPInfo 21 | className="my-class" 22 | icon={(props) => <IconMobile {...props} />} 23 | > 24 | {'Component children'} 25 | </AMPInfo> 26 | ); 27 | 28 | expect(wrapper.toJSON()).toMatchSnapshot(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /assets/src/components/amp-setting-toggle/style.css: -------------------------------------------------------------------------------- 1 | /** 2 | * AMP setting toggle component. 3 | */ 4 | .amp-setting-toggle p { 5 | font-size: 14px; 6 | } 7 | 8 | .amp .amp-setting-toggle .components-form-toggle { 9 | margin-right: 0.75rem; 10 | 11 | @media (min-width: 783px) { 12 | margin-right: 2.25rem; 13 | } 14 | } 15 | 16 | .amp-setting-toggle--disabled .components-form-toggle__input { 17 | pointer-events: none; 18 | opacity: 0.5; 19 | } 20 | 21 | .amp-setting-toggle--disabled .components-toggle-control__label { 22 | pointer-events: none; 23 | } 24 | 25 | .amp .amp-setting-toggle--compact .components-form-toggle { 26 | 27 | @media (min-width: 783px) { 28 | margin-right: 1rem; 29 | } 30 | } 31 | 32 | .amp .amp-setting-toggle--compact .amp-setting-toggle__label-text p { 33 | margin: 0; 34 | } 35 | -------------------------------------------------------------------------------- /assets/src/components/clipboard-button/test/__snapshots__/index.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`ClipboardButton matches snapshot 1`] = ` 4 | <button 5 | className="components-button components-clipboard-button" 6 | onBlur={[Function]} 7 | onClick={[Function]} 8 | onClickCapture={[Function]} 9 | onCopy={[Function]} 10 | onFocusCapture={[Function]} 11 | onKeyDownCapture={[Function]} 12 | onKeyPressCapture={[Function]} 13 | onMouseDown={[Function]} 14 | onMouseDownCapture={[Function]} 15 | onMouseEnter={[Function]} 16 | onMouseMove={[Function]} 17 | type="button" 18 | /> 19 | `; 20 | -------------------------------------------------------------------------------- /assets/src/components/clipboard-button/test/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import { create } from 'react-test-renderer'; 5 | import { describe, expect, it } from '@jest/globals'; 6 | 7 | /** 8 | * Internal dependencies 9 | */ 10 | import ClipboardButton from '..'; 11 | 12 | describe('ClipboardButton', () => { 13 | it('matches snapshot', () => { 14 | const wrapper = create(<ClipboardButton text="Sample text" />); 15 | 16 | expect(wrapper.toJSON()).toMatchSnapshot(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /assets/src/components/conditional-details/test/__snapshots__/index.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`ConditionalDetails renders as expected 1`] = ` 4 | <details> 5 | <summary> 6 | <div> 7 | Summary 8 | </div> 9 | </summary> 10 | <div> 11 | children 12 | </div> 13 | </details> 14 | `; 15 | 16 | exports[`ConditionalDetails renders as expected 2`] = ` 17 | <div> 18 | Summary 19 | </div> 20 | `; 21 | -------------------------------------------------------------------------------- /assets/src/components/dev-tools-toggle/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | import { useContext } from '@wordpress/element'; 5 | import { __ } from '@wordpress/i18n'; 6 | 7 | /** 8 | * Internal dependencies 9 | */ 10 | import { AMPSettingToggle } from '../amp-setting-toggle'; 11 | import { User } from '../user-context-provider'; 12 | import { Loading } from '../loading'; 13 | 14 | export function DevToolsToggle() { 15 | const { developerToolsOption, fetchingUser, setDeveloperToolsOption } = 16 | useContext(User); 17 | 18 | if (fetchingUser) { 19 | return <Loading />; 20 | } 21 | 22 | return ( 23 | <AMPSettingToggle 24 | checked={true === developerToolsOption} 25 | title={__('Enable Developer Tools', 'amp')} 26 | onChange={() => { 27 | setDeveloperToolsOption(!developerToolsOption); 28 | }} 29 | /> 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /assets/src/components/error-context-provider/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import PropTypes from 'prop-types'; 5 | 6 | /** 7 | * WordPress dependencies 8 | */ 9 | import { createContext, useState } from '@wordpress/element'; 10 | 11 | export const ErrorContext = createContext(); 12 | 13 | /** 14 | * Error context provider. 15 | * 16 | * @param {Object} props Component props. 17 | * @param {any} props.children Component children. 18 | */ 19 | export function ErrorContextProvider({ children }) { 20 | const [error, setError] = useState(null); 21 | 22 | return ( 23 | <ErrorContext.Provider value={{ error, setError }}> 24 | {children} 25 | </ErrorContext.Provider> 26 | ); 27 | } 28 | 29 | ErrorContextProvider.propTypes = { 30 | children: PropTypes.any, 31 | }; 32 | -------------------------------------------------------------------------------- /assets/src/components/error-screen/test/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import { create } from 'react-test-renderer'; 5 | import { describe, expect, it } from '@jest/globals'; 6 | 7 | /** 8 | * Internal dependencies 9 | */ 10 | import { ErrorScreen } from '..'; 11 | 12 | describe('ErrorScreen', () => { 13 | it('matches snapshot', () => { 14 | const wrapper = create( 15 | <ErrorScreen 16 | finishLinkLabel="Go to homepage" 17 | finishLinkUrl="http://my-exit-link.com" 18 | error={{ 19 | message: 'The application failed', 20 | stack: 'ReferenceError: foo is not defined', 21 | }} 22 | /> 23 | ); 24 | 25 | expect(wrapper.toJSON()).toMatchSnapshot(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /assets/src/components/list-items/style.scss: -------------------------------------------------------------------------------- 1 | .list-items--list-style-disc { 2 | list-style: disc; 3 | } 4 | 5 | .list-items .list-items__heading { 6 | font-size: 1rem; 7 | margin: 1.5rem 0 .5rem; 8 | } 9 | 10 | .list-items .list-items__item-key { 11 | min-width: 210px; 12 | display: inline-block; 13 | } 14 | -------------------------------------------------------------------------------- /assets/src/components/loading/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import classnames from 'classnames'; 5 | import PropTypes from 'prop-types'; 6 | 7 | /** 8 | * WordPress dependencies 9 | */ 10 | import { Spinner } from '@wordpress/components'; 11 | 12 | /** 13 | * Internal dependencies 14 | */ 15 | import './style.css'; 16 | 17 | /** 18 | * Loading indicator. 19 | * 20 | * @param {Object} props Component props. 21 | * @param {boolean} props.inline Display indicator as an inline element. 22 | */ 23 | // @todo WIP: Updated design needed. 24 | export function Loading({ inline = false }) { 25 | const Tag = inline ? 'span' : 'div'; 26 | 27 | return ( 28 | <Tag 29 | className={classnames('amp-spinner-container', { 30 | 'amp-spinner-container--inline': inline, 31 | })} 32 | > 33 | <Spinner /> 34 | </Tag> 35 | ); 36 | } 37 | 38 | Loading.propTypes = { 39 | inline: PropTypes.bool, 40 | }; 41 | -------------------------------------------------------------------------------- /assets/src/components/loading/style.css: -------------------------------------------------------------------------------- 1 | .amp-spinner-container { 2 | align-items: center; 3 | display: flex; 4 | justify-content: center; 5 | } 6 | 7 | .amp-spinner-container--inline { 8 | display: inline-flex; 9 | margin: 0 0.5em; 10 | vertical-align: middle; 11 | } 12 | 13 | .amp-spinner-container .components-spinner { 14 | margin: 0; 15 | } 16 | -------------------------------------------------------------------------------- /assets/src/components/nav-menu/test/__snapshots__/nav-menu.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`NavMenu matches the snapshot 1`] = ` 4 | <nav 5 | className="nav-menu selectable selectable--left" 6 | > 7 | <ul 8 | className="nav-menu__list" 9 | > 10 | <li 11 | className="nav-menu__item" 12 | > 13 | <a 14 | className="nav-menu__link" 15 | href="https://example.com/foo" 16 | onClick={[Function]} 17 | > 18 | Foo 19 | </a> 20 | </li> 21 | <li 22 | className="nav-menu__item" 23 | > 24 | <a 25 | className="nav-menu__link nav-menu__link--active" 26 | href="https://example.com/bar" 27 | onClick={[Function]} 28 | > 29 | Bar 30 | </a> 31 | </li> 32 | </ul> 33 | </nav> 34 | `; 35 | -------------------------------------------------------------------------------- /assets/src/components/progress-bar/test/__snapshots__/progress-bar.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`ProgressBar matches the snapshot 1`] = ` 4 | <div 5 | aria-valuemax="100" 6 | aria-valuemin="0" 7 | aria-valuenow={33} 8 | className="progress-bar" 9 | role="progressbar" 10 | > 11 | <div 12 | className="progress-bar__track" 13 | > 14 | <div 15 | className="progress-bar__indicator" 16 | style={ 17 | { 18 | "transform": "translateX(-67%)", 19 | "transitionDuration": "800ms", 20 | } 21 | } 22 | /> 23 | </div> 24 | </div> 25 | `; 26 | -------------------------------------------------------------------------------- /assets/src/components/reader-theme-carousel/style.css: -------------------------------------------------------------------------------- 1 | .reader-theme-selection { 2 | padding: 1.5rem; 3 | 4 | @media (min-width: 783px) { 5 | padding: 1.5rem 3rem; 6 | } 7 | } 8 | 9 | .reader-theme-selection .amp-notice--info { 10 | margin-bottom: 0.75rem; 11 | } 12 | 13 | .reader-theme-selection p { 14 | margin-top: 0; 15 | font-size: 14px; 16 | } 17 | 18 | .reader-theme-selection .amp-setting-toggle { 19 | margin: 1rem 0 0.5rem; 20 | } 21 | 22 | .choose-reader-theme__unavailable .choose-reader-theme__grid { 23 | display: grid; 24 | gap: 1rem; 25 | grid-template-columns: repeat(4, minmax(0, 1fr)); 26 | } 27 | 28 | .amp-carousel__page { 29 | display: grid; 30 | gap: 60px; 31 | grid-template-columns: repeat(3, minmax(0, 1fr)); 32 | } 33 | 34 | .reader-theme-selection .theme-card { 35 | margin: 0 auto; 36 | width: 275px; 37 | } 38 | -------------------------------------------------------------------------------- /assets/src/components/reader-theme-selection/style.css: -------------------------------------------------------------------------------- 1 | .choose-reader-theme > p { 2 | font-size: 1rem; 3 | margin-bottom: 1.5rem; 4 | } 5 | 6 | .choose-reader-theme__grid { 7 | display: grid; 8 | grid-gap: 40px; 9 | } 10 | 11 | @media screen and (min-width: 600px) { 12 | 13 | .choose-reader-theme__grid { 14 | grid-template-columns: repeat(2, minmax(0, 1fr)); 15 | } 16 | } 17 | 18 | @media screen and (min-width: 1100px) { 19 | 20 | .choose-reader-theme__grid { 21 | grid-template-columns: repeat(3, minmax(0, 1fr)); 22 | } 23 | } 24 | 25 | .choose-reader-theme__unavailable { 26 | padding-top: 6rem; 27 | } 28 | 29 | .choose-reader-theme__unavailable label { 30 | cursor: default; 31 | } 32 | -------------------------------------------------------------------------------- /assets/src/components/redirect-toggle/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | import { useContext } from '@wordpress/element'; 5 | import { __ } from '@wordpress/i18n'; 6 | 7 | /** 8 | * Internal dependencies 9 | */ 10 | import { Options } from '../options-context-provider'; 11 | import { AMPSettingToggle } from '../amp-setting-toggle'; 12 | 13 | export function RedirectToggle() { 14 | const { editedOptions, updateOptions } = useContext(Options); 15 | 16 | const { mobile_redirect: mobileRedirect } = editedOptions; 17 | 18 | return ( 19 | <AMPSettingToggle 20 | checked={true === mobileRedirect} 21 | title={__('Redirect mobile visitors to AMP', 'amp')} 22 | onChange={() => { 23 | updateOptions({ mobile_redirect: !mobileRedirect }); 24 | }} 25 | /> 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /assets/src/components/selectable/test/__snapshots__/index.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Selectable matches snapshot 1`] = ` 4 | <div 5 | className="selectable selectable--selected selectable--left" 6 | > 7 | <div> 8 | Component children 9 | </div> 10 | </div> 11 | `; 12 | 13 | exports[`Selectable matches snapshot 2`] = ` 14 | <section 15 | className="my-cool-class selectable selectable--selected selectable--top" 16 | > 17 | <div> 18 | Component children 19 | </div> 20 | </section> 21 | `; 22 | -------------------------------------------------------------------------------- /assets/src/components/site-scan-results/index.js: -------------------------------------------------------------------------------- 1 | export { SiteScanResults } from './site-scan-results'; 2 | export { ThemesWithAmpIncompatibility } from './themes-with-amp-incompatibility'; 3 | export { PluginsWithAmpIncompatibility } from './plugins-with-amp-incompatibility'; 4 | -------------------------------------------------------------------------------- /assets/src/components/supported-templates-toggle/style.css: -------------------------------------------------------------------------------- 1 | .amp .supported-templates .amp-setting-toggle .components-form-toggle { 2 | margin-right: 1rem; 3 | } 4 | 5 | .supported-templates .amp-setting-toggle .amp-setting-toggle__label-text > p { 6 | margin: 0; 7 | font-weight: bold; 8 | } 9 | -------------------------------------------------------------------------------- /assets/src/components/svg/check.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | import { useInstanceId } from '@wordpress/compose'; 5 | 6 | /** 7 | * Check mark SVG. 8 | */ 9 | export function Check() { 10 | const id = useInstanceId(Check); 11 | 12 | return ( 13 | <svg 14 | width="20" 15 | height="21" 16 | viewBox="0 0 20 21" 17 | fill="none" 18 | xmlns="http://www.w3.org/2000/svg" 19 | > 20 | <mask 21 | id={`mask-${id}`} 22 | style={{ maskType: 'alpha' }} 23 | maskUnits="userSpaceOnUse" 24 | x="2" 25 | y="5" 26 | width="16" 27 | height="12" 28 | > 29 | <path 30 | d="M7.32923 14.137L3.85423 10.662L2.6709 11.837L7.32923 16.4953L17.3292 6.49531L16.1542 5.32031L7.32923 14.137Z" 31 | fill="white" 32 | /> 33 | </mask> 34 | <g mask={`url(#mask-${id})`}> 35 | <rect y="0.90625" width="20" height="20" fill="white" /> 36 | </g> 37 | </svg> 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /assets/src/components/svg/icon-mobile.js: -------------------------------------------------------------------------------- 1 | export function IconMobile(props) { 2 | return ( 3 | <svg 4 | width="13" 5 | height="20" 6 | viewBox="0 0 13 20" 7 | fill="none" 8 | xmlns="http://www.w3.org/2000/svg" 9 | {...props} 10 | > 11 | <path 12 | d="M1.66211 0.265625H11.2246C11.5684 0.265625 11.8496 0.390625 12.0684 0.640625C12.3184 0.859375 12.4434 1.14063 12.4434 1.48438V18.2656C12.4434 18.6094 12.3184 18.9062 12.0684 19.1562C11.8496 19.375 11.5684 19.4844 11.2246 19.4844H1.66211C1.31836 19.4844 1.02148 19.375 0.771484 19.1562C0.552734 18.9062 0.443359 18.6094 0.443359 18.2656V1.48438C0.443359 1.14063 0.552734 0.859375 0.771484 0.640625C1.02148 0.390625 1.31836 0.265625 1.66211 0.265625ZM10.0527 14.6562V2.65625H2.83398V14.6562H10.0527ZM4.05273 3.875H8.83398L4.05273 9.875V3.875Z" 13 | fill="black" 14 | fillOpacity="0.87" 15 | /> 16 | </svg> 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /assets/src/components/svg/icon-pin.js: -------------------------------------------------------------------------------- 1 | export function IconPin(props) { 2 | return ( 3 | <svg 4 | width="15" 5 | height="21" 6 | viewBox="0 0 15 21" 7 | fill="none" 8 | xmlns="http://www.w3.org/2000/svg" 9 | {...props} 10 | > 11 | <path 12 | d="M9.60669 2.83203V7.83203C9.60669 8.95203 9.97669 9.99203 10.6067 10.832H4.60669C5.25669 9.97203 5.60669 8.93203 5.60669 7.83203V2.83203H9.60669ZM12.6067 0.832031H2.60669C2.05669 0.832031 1.60669 1.28203 1.60669 1.83203C1.60669 2.38203 2.05669 2.83203 2.60669 2.83203H3.60669V7.83203C3.60669 9.49203 2.26669 10.832 0.606689 10.832V12.832H6.57669V19.832L7.57669 20.832L8.57669 19.832V12.832H14.6067V10.832C12.9467 10.832 11.6067 9.49203 11.6067 7.83203V2.83203H12.6067C13.1567 2.83203 13.6067 2.38203 13.6067 1.83203C13.6067 1.28203 13.1567 0.832031 12.6067 0.832031Z" 13 | fill="#333D47" 14 | /> 15 | </svg> 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /assets/src/components/svg/logo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AMP logo. 3 | */ 4 | export function Logo() { 5 | return ( 6 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"> 7 | <g fill="none" fillRule="evenodd"> 8 | <path 9 | fill="#FFF" 10 | d="M0 15c0 8.284 6.716 15 15 15 8.285 0 15-6.716 15-15 0-8.284-6.715-15-15-15C6.716 0 0 6.716 0 15z" 11 | /> 12 | <path 13 | fill="#005AF0" 14 | fillRule="nonzero" 15 | d="M13.85 24.098h-1.14l1.128-6.823-3.49.005h-.05a.57.57 0 0 1-.568-.569c0-.135.125-.363.125-.363l6.272-10.46 1.16.005-1.156 6.834 3.508-.004h.056c.314 0 .569.254.569.568 0 .128-.05.24-.121.335L13.85 24.098zM15 0C6.716 0 0 6.716 0 15c0 8.284 6.716 15 15 15 8.285 0 15-6.716 15-15 0-8.284-6.715-15-15-15z" 16 | /> 17 | </g> 18 | </svg> 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /assets/src/components/themes-api-error/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | import { useContext } from '@wordpress/element'; 5 | 6 | /** 7 | * Internal dependencies 8 | */ 9 | import { AMPNotice, NOTICE_TYPE_WARNING } from '../amp-notice'; 10 | import { ReaderThemes } from '../reader-themes-context-provider'; 11 | 12 | /** 13 | * Notice showing a message when the WordPress.org themes API request has failed on the backend. 14 | */ 15 | export function ThemesAPIError() { 16 | const { themesAPIError } = useContext(ReaderThemes); 17 | 18 | if (!themesAPIError) { 19 | return null; 20 | } 21 | 22 | return ( 23 | <AMPNotice type={NOTICE_TYPE_WARNING}> 24 | <p>{themesAPIError}</p> 25 | </AMPNotice> 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /assets/src/components/user-context-provider/__mocks__/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import PropTypes from 'prop-types'; 5 | 6 | /** 7 | * WordPress dependencies 8 | */ 9 | import { createContext } from '@wordpress/element'; 10 | 11 | export const User = createContext(); 12 | 13 | /** 14 | * MOCK. 15 | * 16 | * @param {Object} props 17 | * @param {any} props.children 18 | * @param {boolean} props.fetchingUser 19 | */ 20 | export function UserContextProvider({ children, fetchingUser }) { 21 | return ( 22 | <User.Provider 23 | value={{ 24 | savingDeveloperToolsOption: false, 25 | fetchingUser, 26 | }} 27 | > 28 | {children} 29 | </User.Provider> 30 | ); 31 | } 32 | UserContextProvider.propTypes = { 33 | children: PropTypes.any, 34 | fetchingUser: PropTypes.bool, 35 | }; 36 | -------------------------------------------------------------------------------- /assets/src/customizer/amp-customize-preview-legacy.js: -------------------------------------------------------------------------------- 1 | // Note: This is only used in Legacy Reader mode. 2 | window.ampCustomizePreview = (function (api) { 3 | 'use strict'; 4 | 5 | const component = {}; 6 | 7 | /** 8 | * Boot using data sent inline. 9 | * 10 | * @param {Object} data - PHP exports. 11 | * @param {boolean} data.available - Whether AMP is available. 12 | * @param {boolean} data.enabled - Whether AMP is enabled. 13 | * @return {void} 14 | */ 15 | component.boot = function boot(data) { 16 | api.bind('preview-ready', function () { 17 | api.preview.bind('active', function () { 18 | api.preview.send('amp-status', data); 19 | }); 20 | }); 21 | }; 22 | 23 | return component; 24 | })(wp.customize); 25 | -------------------------------------------------------------------------------- /assets/src/onboarding-wizard/__mocks__/amp-settings.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | AMP_SCAN_IF_STALE: 'amp-scan-if-stale', 3 | APP_ROOT_ID: 'amp-onboarding-wizard', 4 | CLOSE_LINK: 'http://site.test/wp-admin/?page=amp-options', 5 | CURRENT_THEME: { 6 | name: 'Twenty Twenty', 7 | }, 8 | SETTINGS_LINK: 'http://site.test/wp-admin/?page=amp-options', 9 | OPTIONS_REST_PATH: 'http://site.test/wp-json/amp/v1/options', 10 | READER_THEMES_REST_PATH: 'http://site.test/wp-json/amp/v1/reader-themes', 11 | UPDATES_NONCE: '', 12 | USER_FIELD_DEVELOPER_TOOLS_ENABLED: 'developer_tools', 13 | USERS_RESOURCE_REST_PATH: 'http://site.test/wp-json/wp/v2/users', 14 | }; 15 | -------------------------------------------------------------------------------- /assets/src/onboarding-wizard/components/desktop/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import PropTypes from 'prop-types'; 5 | 6 | /** 7 | * Internal dependencies 8 | */ 9 | import './style.css'; 10 | 11 | /** 12 | * Component resembling a desktop computer with a screen. 13 | * 14 | * @param {Object} props Component props. 15 | * @param {any} props.children The elements to display in the screen. 16 | */ 17 | export function Desktop({ children }) { 18 | return ( 19 | <div className="desktop"> 20 | <div className="desktop__toolbar"> 21 | <span /> 22 | <span /> 23 | <span /> 24 | </div> 25 | {children} 26 | </div> 27 | ); 28 | } 29 | 30 | Desktop.propTypes = { 31 | children: PropTypes.any, 32 | }; 33 | -------------------------------------------------------------------------------- /assets/src/onboarding-wizard/components/desktop/style.css: -------------------------------------------------------------------------------- 1 | .desktop { 2 | background: #f1f1f1; 3 | border-radius: 12px; 4 | margin-bottom: 1.5rem; 5 | min-height: 230px; 6 | padding: 17px 13px; 7 | position: relative; 8 | } 9 | 10 | .desktop > * { 11 | max-width: 100%; 12 | } 13 | 14 | .desktop__toolbar { 15 | align-items: center; 16 | display: flex; 17 | padding-bottom: 17px; 18 | } 19 | 20 | .desktop__toolbar > span { 21 | background: #e5e5e5; 22 | border-radius: 50%; 23 | height: 11px; 24 | margin-right: 4px; 25 | overflow: hidden; 26 | width: 11px; 27 | } 28 | -------------------------------------------------------------------------------- /assets/src/onboarding-wizard/components/nav/style.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Nav component. 3 | */ 4 | 5 | .amp-settings-nav__prev-next { 6 | display: flex; 7 | } 8 | 9 | .amp-settings-nav__prev-next > * { 10 | align-items: center; 11 | display: flex; 12 | height: 36px; 13 | } 14 | 15 | .amp-settings-nav__prev-next > .components-button + .components-button { 16 | margin-left: 1rem; 17 | } 18 | 19 | .amp-settings-nav__prev { 20 | margin-right: 5px; 21 | } 22 | 23 | .amp-settings-nav__prev svg { 24 | transform: rotate(180deg); 25 | margin-left: 0; 26 | margin-right: 0.5rem; 27 | } 28 | 29 | .amp-settings-nav__close { 30 | align-items: center; 31 | display: flex; 32 | } 33 | 34 | .amp-settings-nav__close svg { 35 | margin-right: 0.5rem; 36 | } 37 | -------------------------------------------------------------------------------- /assets/src/onboarding-wizard/pages/site-scan/style.scss: -------------------------------------------------------------------------------- 1 | .site-scan__section + .site-scan__section { 2 | margin-top: 1.5rem; 3 | } 4 | 5 | .site-scan__header { 6 | align-items: center; 7 | border-bottom: 1px solid var(--amp-settings-color-border); 8 | display: flex; 9 | flex-flow: row nowrap; 10 | padding-bottom: 1rem; 11 | padding-top: 0.5rem; 12 | } 13 | 14 | .site-scan__heading { 15 | font-size: 16px; 16 | font-weight: 700; 17 | margin-left: 2rem; 18 | } 19 | -------------------------------------------------------------------------------- /assets/src/onboarding-wizard/pages/template-mode/style.scss: -------------------------------------------------------------------------------- 1 | .template-modes__header { 2 | margin-bottom: 1.75rem; 3 | } 4 | -------------------------------------------------------------------------------- /assets/src/onboarding-wizard/pages/welcome/style.css: -------------------------------------------------------------------------------- 1 | .welcome { 2 | padding-bottom: 45px; 3 | padding-top: 30px; 4 | 5 | @media screen and (min-width: 1000px) { 6 | padding-left: 90px; 7 | padding-right: 90px; 8 | } 9 | } 10 | 11 | .welcome__header { 12 | border-bottom: 2px solid #d3d9dd; 13 | margin-bottom: 3rem; 14 | text-align: center; 15 | } 16 | 17 | .welcome__header h1 { 18 | margin: 1.5rem auto; 19 | max-width: 525px; 20 | } 21 | 22 | .welcome__section { 23 | display: flex; 24 | padding-bottom: 1.5rem; 25 | } 26 | 27 | .welcome__section-icon { 28 | flex-shrink: 0; 29 | width: 64px; 30 | } 31 | 32 | .welcome__section h4, 33 | .welcome__section p { 34 | font-family: var(--font-noto); 35 | font-size: 1rem; 36 | } 37 | 38 | .welcome__section h4 { 39 | margin-bottom: 7px; 40 | margin-top: 0; 41 | } 42 | 43 | .welcome__section p { 44 | line-height: 1.5; 45 | } 46 | -------------------------------------------------------------------------------- /assets/src/polyfills/api-fetch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | // eslint-disable-next-line import/no-unresolved 5 | import apiFetch from '@wordpress/api-fetch__non-shim'; 6 | 7 | global.wp = global.wp || {}; 8 | global.wp.apiFetch = apiFetch; 9 | 10 | export default apiFetch; 11 | -------------------------------------------------------------------------------- /assets/src/settings-page/mobile-redirection.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | import { useContext } from '@wordpress/element'; 5 | 6 | /** 7 | * Internal dependencies 8 | */ 9 | import { RedirectToggle } from '../components/redirect-toggle'; 10 | import { Options } from '../components/options-context-provider'; 11 | import { STANDARD } from '../common/constants'; 12 | 13 | /** 14 | * Mobile redirection section of the settings page. 15 | */ 16 | export function MobileRedirection() { 17 | const { editedOptions } = useContext(Options); 18 | 19 | const { theme_support: themeSupport } = editedOptions || {}; 20 | 21 | // Don't show if the mode is standard or the themeSupport is not yet set. 22 | if (!themeSupport || STANDARD === themeSupport) { 23 | return null; 24 | } 25 | 26 | return ( 27 | <section className="mobile-redirection"> 28 | <RedirectToggle /> 29 | </section> 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /assets/src/settings-page/reader-themes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Internal dependencies 3 | */ 4 | import { ReaderThemeCarousel } from '../components/reader-theme-carousel'; 5 | 6 | /** 7 | * The reader themes section of the settings page. 8 | */ 9 | export function ReaderThemes() { 10 | return <ReaderThemeCarousel hideCurrentlyActiveTheme={true} />; 11 | } 12 | -------------------------------------------------------------------------------- /assets/src/utils/use-async-error.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | import { useState, useCallback } from '@wordpress/element'; 5 | 6 | /** 7 | * The error boundary component doesn't automatically catch errors in async functions. 8 | * This allows errors to be explicitly thrown. 9 | */ 10 | export function useAsyncError() { 11 | const [error, setAsyncError] = useState(); 12 | 13 | const memoizedSetError = useCallback((e) => { 14 | setAsyncError(() => { 15 | throw e; 16 | }); 17 | }, []); 18 | 19 | return { error, setAsyncError: memoizedSetError }; 20 | } 21 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | const defaultConfig = require('@wordpress/babel-preset-default'); 5 | 6 | module.exports = function (api) { 7 | const config = defaultConfig(api); 8 | 9 | return { 10 | ...config, 11 | plugins: [...config.plugins, '@babel/plugin-proposal-class-properties'], 12 | sourceMaps: true, 13 | env: { 14 | production: { 15 | plugins: [ 16 | ...config.plugins, 17 | '@babel/plugin-proposal-class-properties', 18 | 'transform-react-remove-prop-types', 19 | ], 20 | }, 21 | }, 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /back-compat/templates-v0-3/header-bar.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Legacy template for the AMP title bar. 4 | * 5 | * @package AMP 6 | */ 7 | 8 | $site_icon_url = $this->get( 'site_icon_url' ); 9 | ?> 10 | 11 | <nav class="amp-wp-title-bar"> 12 | <div> 13 | <a href="<?php echo esc_url( $this->get( 'home_url' ) ); ?>"> 14 | <?php if ( $site_icon_url ) : ?> 15 | <amp-img src="<?php echo esc_url( $site_icon_url ); ?>" width="32" height="32" class="amp-wp-site-icon"></amp-img> 16 | <?php endif; ?> 17 | 18 | <?php echo esc_html( $this->get( 'blog_name' ) ); ?> 19 | </a> 20 | </div> 21 | </nav> 22 | -------------------------------------------------------------------------------- /back-compat/templates-v0-3/meta-author.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Legacy template for the AMP author byline. 4 | * 5 | * @package AMP 6 | */ 7 | 8 | $post_author = $this->get( 'post_author' ); 9 | $avatar_url = get_avatar_url( 10 | $post_author->user_email, 11 | [ 12 | 'size' => 24, 13 | ] 14 | ); 15 | ?> 16 | <li class="amp-wp-byline"> 17 | <?php if ( function_exists( 'get_avatar_url' ) ) : ?> 18 | <amp-img src="<?php echo esc_url( $avatar_url ); ?>" width="24" height="24" layout="fixed"></amp-img> 19 | <?php endif; ?> 20 | <span class="amp-wp-author"><?php echo esc_html( $post_author->display_name ); ?></span> 21 | </li> 22 | -------------------------------------------------------------------------------- /back-compat/templates-v0-3/meta-time.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Legacy template for the AMP post date. 4 | * 5 | * @package AMP 6 | */ 7 | 8 | /** 9 | * Context. 10 | * 11 | * @var AMP_Post_Template $this 12 | */ 13 | 14 | ?> 15 | <li class="amp-wp-posted-on"> 16 | <time datetime="<?php echo esc_attr( gmdate( 'c', $this->get( 'post_publish_timestamp' ) ) ); ?>"> 17 | <?php 18 | echo esc_html( 19 | sprintf( 20 | /* translators: %s: the human-readable time difference. */ 21 | __( '%s ago', 'amp' ), 22 | human_time_diff( $this->get( 'post_publish_timestamp' ), time() ) 23 | ) 24 | ); 25 | ?> 26 | </time> 27 | </li> 28 | -------------------------------------------------------------------------------- /behat.yml: -------------------------------------------------------------------------------- 1 | default: 2 | suites: 3 | default: 4 | contexts: 5 | - AmpProject\AmpWP\Tests\Behat\FeatureContext 6 | paths: 7 | - tests/features 8 | -------------------------------------------------------------------------------- /bin/local-env/.env.wp: -------------------------------------------------------------------------------- 1 | WORDPRESS_DB_HOST=mysql 2 | WORDPRESS_DB_USER=root 3 | WORDPRESS_DB_PASSWORD=example 4 | WORDPRESS_DB_NAME=wordpress 5 | WORDPRESS_DEBUG=1 6 | WORDPRESS_CONFIG_EXTRA=define( 'SCRIPT_DEBUG', true ); define( 'FS_METHOD', 'direct' ); 7 | -------------------------------------------------------------------------------- /bin/local-env/Dockerfile: -------------------------------------------------------------------------------- 1 | # @todo: switch to wordpress:latest once it's available 2 | FROM wordpress:beta-6.7-php8.3-apache 3 | 4 | # WP CLI 5 | RUN curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar \ 6 | && chmod +x wp-cli.phar \ 7 | && mv wp-cli.phar /usr/local/bin/wp 8 | 9 | CMD ["apache2-foreground"] 10 | -------------------------------------------------------------------------------- /bin/local-env/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | wordpress: 3 | build: 4 | context: . 5 | dockerfile: Dockerfile 6 | ports: 7 | - "127.0.0.1:8890:80" 8 | env_file: 9 | - .env.wp 10 | volumes: 11 | - wordpress_data:/var/www/html 12 | - ../../:/var/www/html/wp-content/plugins/amp 13 | - ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini 14 | depends_on: 15 | - mysql 16 | 17 | mysql: 18 | image: mariadb:10 19 | restart: always 20 | environment: 21 | MYSQL_ROOT_PASSWORD: example 22 | MYSQL_DATABASE: wordpress_test 23 | 24 | volumes: 25 | wordpress_data: 26 | -------------------------------------------------------------------------------- /bin/local-env/stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Exit if any command fails. 4 | set -e 5 | 6 | # Include useful functions. 7 | . "$(dirname "$0")/includes.sh" 8 | 9 | # Check that Docker is installed. 10 | if ! command_exists "docker"; then 11 | echo -e $(error_message "Docker doesn't seem to be installed. Please head on over to the Docker site to download it: $(action_format "https://www.docker.com/products/docker-desktop")") 12 | exit 1 13 | fi 14 | 15 | # Check that Docker is running. 16 | if ! docker info >/dev/null 2>&1; then 17 | echo -e $(error_message "Docker isn't running. Please check that you've started your Docker app, and see it in your system tray.") 18 | exit 1 19 | fi 20 | 21 | # Stop existing containers. 22 | echo -e $(status_message "Stopping Docker containers...") 23 | dc down --remove-orphans >/dev/null 2>&1 24 | -------------------------------------------------------------------------------- /bin/local-env/uploads.ini: -------------------------------------------------------------------------------- 1 | file_uploads = On 2 | memory_limit = 500M 3 | upload_max_filesize = 500M 4 | post_max_size = 500M 5 | max_execution_time = 600 6 | -------------------------------------------------------------------------------- /bin/phpcbf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Wrap phpcbf to turn 1 success exit code into 0 code. 3 | # See https://github.com/squizlabs/PHP_CodeSniffer/issues/1818#issuecomment-354420927 4 | 5 | root=$( dirname "$0" )/.. 6 | 7 | "$root/vendor/bin/phpcbf" $@ 8 | exit=$? 9 | 10 | # Exit code 1 is used to indicate that all fixable errors were fixed correctly. 11 | if [[ $exit == 1 ]]; then 12 | exit=0 13 | fi 14 | 15 | exit $exit 16 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # AMP for WordPress Plugin [<img src="../assets/images/amp-logo-icon.svg" alt="AMP for WordPress Plugin Logo" align="right" height="80">](https://amp-wp.org/) 2 | 3 | Official AMP plugin, supported by the AMP team. Formerly Accelerated Mobile Pages, AMP enables great experiences across both mobile and desktop. 4 | 5 | ## Reference Documentation 6 | 7 | ### [▹ Classes](class/README.md) 8 | ### [▹ Methods](method/README.md) 9 | ### [▹ Functions](function/README.md) 10 | ### [▹ Hooks](hook/README.md) 11 | 12 | -------------------------------------------------------------------------------- /docs/class/README.md: -------------------------------------------------------------------------------- 1 | ## Classes 2 | 3 | * [`AMP_Base_Embed_Handler`](AMP_Base_Embed_Handler.md) - Class AMP_Base_Embed_Handler 4 | * [`AMP_Base_Sanitizer`](AMP_Base_Sanitizer.md) - Class AMP_Base_Sanitizer 5 | * [`AMP_DOM_Utils`](AMP_DOM_Utils.md) - Class AMP_DOM_Utils 6 | * [`AMP_WordPress_Embed_Handler`](AMP_WordPress_Embed_Handler.md) - Class AMP_WordPress_Embed_Handler 7 | * [`PairedUrl`](PairedUrl.md) - Service for manipulating a paired URL. 8 | * [`PairedUrlStructure`](PairedUrlStructure.md) - Interface for classes that implement a PairedUrl. 9 | -------------------------------------------------------------------------------- /docs/function/amp_add_post_template_actions.md: -------------------------------------------------------------------------------- 1 | ## Function `amp_add_post_template_actions` 2 | 3 | > :warning: This function is deprecated: This function is not used when &#039;amp&#039; theme support is added. 4 | 5 | ```php 6 | function amp_add_post_template_actions(); 7 | ``` 8 | 9 | Add post template actions. 10 | 11 | ### Source 12 | 13 | :link: [includes/deprecated.php:92](/includes/deprecated.php#L92-L96) 14 | 15 | <details> 16 | <summary>Show Code</summary> 17 | 18 | ```php 19 | function amp_add_post_template_actions() { 20 | _deprecated_function( __FUNCTION__, '1.5' ); 21 | require_once AMP__DIR__ . '/includes/amp-post-template-functions.php'; 22 | amp_post_template_init_hooks(); 23 | } 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/function/amp_frontend_add_canonical.md: -------------------------------------------------------------------------------- 1 | ## Function `amp_frontend_add_canonical` 2 | 3 | > :warning: This function is deprecated: Use amp_add_amphtml_link() instead. 4 | 5 | ```php 6 | function amp_frontend_add_canonical(); 7 | ``` 8 | 9 | Add amphtml link to frontend. 10 | 11 | ### Source 12 | 13 | :link: [includes/amp-frontend-actions.php:31](/includes/amp-frontend-actions.php#L31-L34) 14 | 15 | <details> 16 | <summary>Show Code</summary> 17 | 18 | ```php 19 | function amp_frontend_add_canonical() { 20 | _deprecated_function( __FUNCTION__, '1.0', 'amp_add_amphtml_link' ); 21 | amp_add_amphtml_link(); 22 | } 23 | ``` 24 | 25 | </details> 26 | -------------------------------------------------------------------------------- /docs/function/amp_get_permalink.md: -------------------------------------------------------------------------------- 1 | ## Function `amp_get_permalink` 2 | 3 | ```php 4 | function amp_get_permalink( $post_id ); 5 | ``` 6 | 7 | Retrieves the full AMP-specific permalink for the given post ID. 8 | 9 | On a site in Standard mode, this is the same as `get_permalink()`. 10 | 11 | ### Arguments 12 | 13 | * `int $post_id` - Post ID. 14 | 15 | ### Return value 16 | 17 | `string` - AMP permalink. 18 | 19 | ### Source 20 | 21 | :link: [includes/amp-helper-functions.php:674](/includes/amp-helper-functions.php#L674-L679) 22 | 23 | <details> 24 | <summary>Show Code</summary> 25 | 26 | ```php 27 | function amp_get_permalink( $post_id ) { 28 | if ( amp_is_canonical() ) { 29 | return get_permalink( $post_id ); 30 | } 31 | return amp_add_paired_endpoint( get_permalink( $post_id ) ); 32 | } 33 | ``` 34 | 35 | </details> 36 | -------------------------------------------------------------------------------- /docs/function/amp_get_sandboxing_level.md: -------------------------------------------------------------------------------- 1 | ## Function `amp_get_sandboxing_level` 2 | 3 | ```php 4 | function amp_get_sandboxing_level(); 5 | ``` 6 | 7 | Determine sandboxing level if enabled. 8 | 9 | ### Return value 10 | 11 | `int` - Following values are possible: 0: Sandbox is disabled. 1: Sandboxing level: Loose. 2: Sandboxing level: Moderate. 3: Sandboxing level: Strict. 12 | 13 | ### Source 14 | 15 | :link: [includes/amp-helper-functions.php:2142](/includes/amp-helper-functions.php#L2142-L2147) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | function amp_get_sandboxing_level() { 22 | if ( ! AMP_Options_Manager::get_option( Option::SANDBOXING_ENABLED ) ) { 23 | return 0; 24 | } 25 | return AMP_Options_Manager::get_option( Option::SANDBOXING_LEVEL ); 26 | } 27 | ``` 28 | 29 | </details> 30 | -------------------------------------------------------------------------------- /docs/function/amp_is_legacy.md: -------------------------------------------------------------------------------- 1 | ## Function `amp_is_legacy` 2 | 3 | ```php 4 | function amp_is_legacy(); 5 | ``` 6 | 7 | Determines whether the legacy AMP post templates are being used. 8 | 9 | ### Return value 10 | 11 | `bool` 12 | 13 | ### Source 14 | 15 | :link: [includes/amp-helper-functions.php:358](/includes/amp-helper-functions.php#L358-L369) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | function amp_is_legacy() { 22 | if ( AMP_Theme_Support::READER_MODE_SLUG !== AMP_Options_Manager::get_option( Option::THEME_SUPPORT ) ) { 23 | return false; 24 | } 25 | 26 | $reader_theme = AMP_Options_Manager::get_option( Option::READER_THEME ); 27 | if ( ReaderThemes::DEFAULT_READER_THEME === $reader_theme ) { 28 | return true; 29 | } 30 | 31 | return ! wp_get_theme( $reader_theme )->exists(); 32 | } 33 | ``` 34 | 35 | </details> 36 | -------------------------------------------------------------------------------- /docs/function/amp_is_post_supported.md: -------------------------------------------------------------------------------- 1 | ## Function `amp_is_post_supported` 2 | 3 | ```php 4 | function amp_is_post_supported( $post ); 5 | ``` 6 | 7 | Determine whether a given post supports AMP. 8 | 9 | ### Arguments 10 | 11 | * `\WP_Post|int $post` - Post. 12 | 13 | ### Return value 14 | 15 | `bool` - Whether the post supports AMP. 16 | 17 | ### Source 18 | 19 | :link: [includes/amp-helper-functions.php:763](/includes/amp-helper-functions.php#L763-L765) 20 | 21 | <details> 22 | <summary>Show Code</summary> 23 | 24 | ```php 25 | function amp_is_post_supported( $post ) { 26 | return 0 === count( AMP_Post_Type_Support::get_support_errors( $post ) ); 27 | } 28 | ``` 29 | 30 | </details> 31 | -------------------------------------------------------------------------------- /docs/function/amp_prepare_render.md: -------------------------------------------------------------------------------- 1 | ## Function `amp_prepare_render` 2 | 3 | > :warning: This function is deprecated: This function is not used when &#039;amp&#039; theme support is added. 4 | 5 | ```php 6 | function amp_prepare_render(); 7 | ``` 8 | 9 | Add action to do post template rendering at template_redirect action. 10 | 11 | ### Source 12 | 13 | :link: [includes/deprecated.php:106](/includes/deprecated.php#L106-L109) 14 | 15 | <details> 16 | <summary>Show Code</summary> 17 | 18 | ```php 19 | function amp_prepare_render() { 20 | _deprecated_function( __FUNCTION__, '1.5' ); 21 | add_action( 'template_redirect', 'amp_render', 11 ); 22 | } 23 | ``` 24 | 25 | </details> 26 | -------------------------------------------------------------------------------- /docs/function/amp_remove_endpoint.md: -------------------------------------------------------------------------------- 1 | ## Function `amp_remove_endpoint` 2 | 3 | > :warning: This function is deprecated: Use amp_remove_paired_endpoint() instead. 4 | 5 | ```php 6 | function amp_remove_endpoint( $url ); 7 | ``` 8 | 9 | Remove the AMP endpoint (and query var) from a given URL. 10 | 11 | ### Arguments 12 | 13 | * `string $url` - URL. 14 | 15 | ### Return value 16 | 17 | `string` - URL with AMP stripped. 18 | 19 | ### Source 20 | 21 | :link: [includes/amp-helper-functions.php:691](/includes/amp-helper-functions.php#L691-L693) 22 | 23 | <details> 24 | <summary>Show Code</summary> 25 | 26 | ```php 27 | function amp_remove_endpoint( $url ) { 28 | return amp_remove_paired_endpoint( $url ); 29 | } 30 | ``` 31 | 32 | </details> 33 | -------------------------------------------------------------------------------- /docs/function/amp_render.md: -------------------------------------------------------------------------------- 1 | ## Function `amp_render` 2 | 3 | > :warning: This function is deprecated: This function is not used when &#039;amp&#039; theme support is added. 4 | 5 | ```php 6 | function amp_render(); 7 | ``` 8 | 9 | Render AMP for queried post. 10 | 11 | ### Source 12 | 13 | :link: [includes/deprecated.php:118](/includes/deprecated.php#L118-L127) 14 | 15 | <details> 16 | <summary>Show Code</summary> 17 | 18 | ```php 19 | function amp_render() { 20 | _deprecated_function( __FUNCTION__, '1.5' ); 21 | 22 | // Note that queried object is used instead of the ID so that the_preview for the queried post can apply. 23 | $post = get_queried_object(); 24 | if ( $post instanceof WP_Post ) { 25 | amp_render_post( $post ); 26 | exit; 27 | } 28 | } 29 | ``` 30 | 31 | </details> 32 | -------------------------------------------------------------------------------- /docs/function/post_supports_amp.md: -------------------------------------------------------------------------------- 1 | ## Function `post_supports_amp` 2 | 3 | > :warning: This function is deprecated: Use amp_is_post_supported() instead. 4 | 5 | ```php 6 | function post_supports_amp( $post ); 7 | ``` 8 | 9 | Determine whether a given post supports AMP. 10 | 11 | ### Arguments 12 | 13 | * `\WP_Post $post` - Post. 14 | 15 | ### Return value 16 | 17 | `bool` - Whether the post supports AMP. 18 | 19 | ### Source 20 | 21 | :link: [includes/amp-helper-functions.php:778](/includes/amp-helper-functions.php#L778-L780) 22 | 23 | <details> 24 | <summary>Show Code</summary> 25 | 26 | ```php 27 | function post_supports_amp( $post ) { 28 | return amp_is_post_supported( $post ); 29 | } 30 | ``` 31 | 32 | </details> 33 | -------------------------------------------------------------------------------- /docs/hook/amp_auto_lightbox_disabled.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_auto_lightbox_disabled` 2 | 3 | ```php 4 | apply_filters( 'amp_auto_lightbox_disabled', $disabled ); 5 | ``` 6 | 7 | Filters whether AMP auto-lightbox is disabled. 8 | 9 | When disabled, the data-amp-auto-lightbox-disable attribute is added to the body. 10 | 11 | ### Arguments 12 | 13 | * `bool $disabled` - Whether disabled. 14 | 15 | ### Source 16 | 17 | :link: [includes/amp-helper-functions.php:1598](/includes/amp-helper-functions.php#L1598) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | $is_auto_lightbox_disabled = apply_filters( 'amp_auto_lightbox_disabled', true ); 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_bento_enabled.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_bento_enabled` 2 | 3 | > :warning: This filter is deprecated: 2.5.0 4 | 5 | ```php 6 | apply_filters( 'amp_bento_enabled', $enabled ); 7 | ``` 8 | 9 | Filters whether the use of Bento components is enabled. 10 | 11 | When Bento is enabled, newer experimental versions of AMP components are used which incorporate the next generation of the component framework. 12 | 13 | ### Arguments 14 | 15 | * `bool $enabled` - Enabled. 16 | 17 | ### Source 18 | 19 | :link: [includes/deprecated.php:384](/includes/deprecated.php#L384) 20 | 21 | <details> 22 | <summary>Show Code</summary> 23 | 24 | ```php 25 | return apply_filters_deprecated( 'amp_bento_enabled', [ false ], 'AMP 2.5.0', 'Remove bento support', 'Bento support has been removed.' ); 26 | ``` 27 | 28 | </details> 29 | -------------------------------------------------------------------------------- /docs/hook/amp_comment_posted_message.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_comment_posted_message` 2 | 3 | ```php 4 | apply_filters( 'amp_comment_posted_message' ); 5 | ``` 6 | 7 | Filters the message when comment submitted success message when 8 | 9 | ### Source 10 | 11 | :link: [includes/class-amp-http.php:502](/includes/class-amp-http.php#L502) 12 | 13 | <details> 14 | <summary>Show Code</summary> 15 | 16 | ```php 17 | $message = apply_filters( 'amp_comment_posted_message', $message, $comment ); 18 | ``` 19 | 20 | </details> 21 | -------------------------------------------------------------------------------- /docs/hook/amp_compatible_ecosystem_shown.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_compatible_ecosystem_shown` 2 | 3 | ```php 4 | apply_filters( 'amp_compatible_ecosystem_shown', $shown, $type ); 5 | ``` 6 | 7 | Filters whether to show AMP compatible ecosystem in the admin. 8 | 9 | ### Arguments 10 | 11 | * `bool $shown` - Whether to show AMP-compatible themes and plugins in the admin. 12 | * `string $type` - The type of ecosystem component being shown. May be either &#039;themes&#039; or &#039;plugins&#039;. 13 | 14 | ### Source 15 | 16 | :link: [src/Admin/AmpThemes.php:85](/src/Admin/AmpThemes.php#L85) 17 | 18 | <details> 19 | <summary>Show Code</summary> 20 | 21 | ```php 22 | return is_admin() && apply_filters( 'amp_compatible_ecosystem_shown', true, 'themes' ); 23 | ``` 24 | 25 | </details> 26 | -------------------------------------------------------------------------------- /docs/hook/amp_content_max_width.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_content_max_width` 2 | 3 | ```php 4 | apply_filters( 'amp_content_max_width', $content_max_width ); 5 | ``` 6 | 7 | Filters the content max width for Reader templates. 8 | 9 | ### Arguments 10 | 11 | * `int $content_max_width` - Content max width. 12 | 13 | ### Source 14 | 15 | :link: [includes/templates/class-amp-post-template.php:113](/includes/templates/class-amp-post-template.php#L113) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | $content_max_width = apply_filters( 'amp_content_max_width', $content_max_width ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_content_sanitizers.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_content_sanitizers` 2 | 3 | ```php 4 | apply_filters( 'amp_content_sanitizers', $handlers, $post ); 5 | ``` 6 | 7 | Filters the content sanitizers. 8 | 9 | ### Arguments 10 | 11 | * `array $handlers` - Handlers. 12 | * `\WP_Post $post` - Post. Deprecated. 13 | 14 | ### Source 15 | 16 | :link: [includes/amp-helper-functions.php:1613](/includes/amp-helper-functions.php#L1613) 17 | 18 | <details> 19 | <summary>Show Code</summary> 20 | 21 | ```php 22 | $sanitizers = apply_filters( 'amp_content_sanitizers', $sanitizers, $post ); 23 | ``` 24 | 25 | </details> 26 | -------------------------------------------------------------------------------- /docs/hook/amp_css_transient_monitoring_sampling_range.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_css_transient_monitoring_sampling_range` 2 | 3 | ```php 4 | apply_filters( 'amp_css_transient_monitoring_sampling_range', $sampling_rage ); 5 | ``` 6 | 7 | Filters the sampling range to use for monitoring the transient caching of stylesheets. 8 | 9 | ### Arguments 10 | 11 | * `int $sampling_rage` - Sampling range in number of days. 12 | 13 | ### Source 14 | 15 | :link: [src/BackgroundTask/MonitorCssTransientCaching.php:372](/src/BackgroundTask/MonitorCssTransientCaching.php#L372) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | $sampling_range = (int) apply_filters( 'amp_css_transient_monitoring_sampling_range', self::DEFAULT_SAMPLING_RANGE ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_css_transient_monitoring_threshold.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_css_transient_monitoring_threshold` 2 | 3 | ```php 4 | apply_filters( 'amp_css_transient_monitoring_threshold', $threshold ); 5 | ``` 6 | 7 | Filters the threshold to use for disabling transient caching of stylesheets. 8 | 9 | ### Arguments 10 | 11 | * `int $threshold` - Maximum average number of transients per day. 12 | 13 | ### Source 14 | 15 | :link: [src/BackgroundTask/MonitorCssTransientCaching.php:351](/src/BackgroundTask/MonitorCssTransientCaching.php#L351) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | $threshold = (float) apply_filters( 'amp_css_transient_monitoring_threshold', self::DEFAULT_THRESHOLD ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_custom_paired_url_structure.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_custom_paired_url_structure` 2 | 3 | ```php 4 | apply_filters( 'amp_custom_paired_url_structure', $structure_class ); 5 | ``` 6 | 7 | Filters to allow a custom paired URL structure to be used. 8 | 9 | ### Arguments 10 | 11 | * `string $structure_class` - Paired URL structure class. 12 | 13 | ### Source 14 | 15 | :link: [src/PairedRouting.php:252](/src/PairedRouting.php#L252) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | $structure_class = apply_filters( 'amp_custom_paired_url_structure', null ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_customizer_enqueue_preview_scripts.md: -------------------------------------------------------------------------------- 1 | ## Action `amp_customizer_enqueue_preview_scripts` 2 | 3 | ```php 4 | do_action( 'amp_customizer_enqueue_preview_scripts', $wp_customize ); 5 | ``` 6 | 7 | Fires when plugins should enqueue their own scripts for the AMP Customizer preview. 8 | 9 | ### Arguments 10 | 11 | * `\WP_Customize_Manager $wp_customize` - Manager. 12 | 13 | ### Source 14 | 15 | :link: [includes/admin/class-amp-template-customizer.php:716](/includes/admin/class-amp-template-customizer.php#L716) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | do_action( 'amp_customizer_enqueue_preview_scripts', $this->wp_customize ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_customizer_enqueue_scripts.md: -------------------------------------------------------------------------------- 1 | ## Action `amp_customizer_enqueue_scripts` 2 | 3 | ```php 4 | do_action( 'amp_customizer_enqueue_scripts', $manager ); 5 | ``` 6 | 7 | Fires when plugins should register settings for AMP. 8 | 9 | In practice the `customize_controls_enqueue_scripts` hook should be used instead. 10 | 11 | ### Arguments 12 | 13 | * `\WP_Customize_Manager $manager` - Manager. 14 | 15 | ### Source 16 | 17 | :link: [includes/admin/class-amp-template-customizer.php:628](/includes/admin/class-amp-template-customizer.php#L628) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | do_action( 'amp_customizer_enqueue_scripts', $this->wp_customize ); 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_customizer_get_settings.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_customizer_get_settings` 2 | 3 | ```php 4 | apply_filters( 'amp_customizer_get_settings', $settings ); 5 | ``` 6 | 7 | Filters the AMP Customizer settings. 8 | 9 | ### Arguments 10 | 11 | * `array $settings` - Associative array of $setting =&gt; $value pairs. 12 | 13 | ### Source 14 | 15 | :link: [includes/settings/class-amp-customizer-settings.php:43](/includes/settings/class-amp-customizer-settings.php#L43) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | return apply_filters( 'amp_customizer_get_settings', $settings ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_customizer_init.md: -------------------------------------------------------------------------------- 1 | ## Action `amp_customizer_init` 2 | 3 | ```php 4 | do_action( 'amp_customizer_init', $self ); 5 | ``` 6 | 7 | Fires when the AMP Template Customizer initializes. 8 | 9 | In practice the `customize_register` hook should be used instead. 10 | 11 | ### Arguments 12 | 13 | * `\AMP_Template_Customizer $self` - Instance. 14 | 15 | ### Source 16 | 17 | :link: [includes/admin/class-amp-template-customizer.php:108](/includes/admin/class-amp-template-customizer.php#L108) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | do_action( 'amp_customizer_init', $self ); 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_customizer_is_enabled.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_customizer_is_enabled` 2 | 3 | ```php 4 | apply_filters( 'amp_customizer_is_enabled', $enable ); 5 | ``` 6 | 7 | Filter whether to enable the AMP default template design settings. 8 | 9 | ### Arguments 10 | 11 | * `bool $enable` - Whether to enable the AMP default template design settings. Default true. 12 | 13 | ### Source 14 | 15 | :link: [includes/settings/class-amp-customizer-design-settings.php:59](/includes/settings/class-amp-customizer-design-settings.php#L59) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | return apply_filters( 'amp_customizer_is_enabled', true ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_customizer_post_type.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_customizer_post_type` 2 | 3 | ```php 4 | apply_filters( 'amp_customizer_post_type', $post_type ); 5 | ``` 6 | 7 | Filter the post type to retrieve the latest for use in the AMP template customizer. 8 | 9 | ### Arguments 10 | 11 | * `string $post_type` - Post type slug. Default &#039;post&#039;. 12 | 13 | ### Source 14 | 15 | :link: [includes/admin/functions.php:53](/includes/admin/functions.php#L53) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | $post_type = (string) apply_filters( 'amp_customizer_post_type', 'post' ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_customizer_register_settings.md: -------------------------------------------------------------------------------- 1 | ## Action `amp_customizer_register_settings` 2 | 3 | ```php 4 | do_action( 'amp_customizer_register_settings', $manager ); 5 | ``` 6 | 7 | Fires when plugins should register settings for AMP. 8 | 9 | In practice the `customize_register` hook should be used instead. 10 | 11 | ### Arguments 12 | 13 | * `\WP_Customize_Manager $manager` - Manager. 14 | 15 | ### Source 16 | 17 | :link: [includes/admin/class-amp-template-customizer.php:318](/includes/admin/class-amp-template-customizer.php#L318) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | do_action( 'amp_customizer_register_settings', $this->wp_customize ); 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_customizer_register_ui.md: -------------------------------------------------------------------------------- 1 | ## Action `amp_customizer_register_ui` 2 | 3 | ```php 4 | do_action( 'amp_customizer_register_ui', $manager ); 5 | ``` 6 | 7 | Fires after the AMP panel has been registered for plugins to add additional controls. 8 | 9 | In practice the `customize_register` hook should be used instead. 10 | 11 | ### Arguments 12 | 13 | * `\WP_Customize_Manager $manager` - Manager. 14 | 15 | ### Source 16 | 17 | :link: [includes/admin/class-amp-template-customizer.php:282](/includes/admin/class-amp-template-customizer.php#L282) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | do_action( 'amp_customizer_register_ui', $this->wp_customize ); 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_dev_tools_user_default_enabled.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_dev_tools_user_default_enabled` 2 | 3 | ```php 4 | apply_filters( 'amp_dev_tools_user_default_enabled', $enabled, $user_id ); 5 | ``` 6 | 7 | Filters whether Developer Tools is enabled by default for a user. 8 | 9 | When Reader mode is active, Developer Tools is currently disabled by default. 10 | 11 | ### Arguments 12 | 13 | * `bool $enabled` - DevTools enabled. 14 | * `int $user_id` - User ID. 15 | 16 | ### Source 17 | 18 | :link: [src/DevTools/UserAccess.php:112](/src/DevTools/UserAccess.php#L112) 19 | 20 | <details> 21 | <summary>Show Code</summary> 22 | 23 | ```php 24 | $enabled = (bool) apply_filters( 'amp_dev_tools_user_default_enabled', $enabled, $user->ID ); 25 | ``` 26 | 27 | </details> 28 | -------------------------------------------------------------------------------- /docs/hook/amp_enable_optimizer.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_enable_optimizer` 2 | 3 | ```php 4 | apply_filters( 'amp_enable_optimizer', $enable_optimizer ); 5 | ``` 6 | 7 | Filter whether the generated HTML output should be run through the AMP Optimizer or not. 8 | 9 | ### Arguments 10 | 11 | * `bool $enable_optimizer` - Whether the generated HTML output should be run through the AMP Optimizer or not. 12 | 13 | ### Source 14 | 15 | :link: [includes/class-amp-theme-support.php:2072](/includes/class-amp-theme-support.php#L2072) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | $enable_optimizer = apply_filters( 'amp_enable_optimizer', $enable_optimizer ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_enable_ssr.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_enable_ssr` 2 | 3 | ```php 4 | apply_filters( 'amp_enable_ssr', $enable_ssr ); 5 | ``` 6 | 7 | Filter whether the AMP Optimizer should use server-side rendering or not. 8 | 9 | ### Arguments 10 | 11 | * `bool $enable_ssr` - Whether the AMP Optimizer should use server-side rendering or not. 12 | 13 | ### Source 14 | 15 | :link: [src/Optimizer/AmpWPConfiguration.php:52](/src/Optimizer/AmpWPConfiguration.php#L52) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | $enable_ssr = apply_filters( 'amp_enable_ssr', true ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_extract_image_dimensions_batch.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_extract_image_dimensions_batch` 2 | 3 | ```php 4 | apply_filters( 'amp_extract_image_dimensions_batch', $extracted_dimensions ); 5 | ``` 6 | 7 | Filters the dimensions extracted from image URLs. 8 | 9 | ### Arguments 10 | 11 | * `array $extracted_dimensions` - Extracted dimensions, initially mapping images URLs to false. 12 | 13 | ### Source 14 | 15 | :link: [includes/utils/class-amp-image-dimension-extractor.php:69](/includes/utils/class-amp-image-dimension-extractor.php#L69) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | $extracted_dimensions = apply_filters( 'amp_extract_image_dimensions_batch', $extracted_dimensions ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_extract_image_dimensions_batch_callbacks_registered.md: -------------------------------------------------------------------------------- 1 | ## Action `amp_extract_image_dimensions_batch_callbacks_registered` 2 | 3 | ```php 4 | do_action( 'amp_extract_image_dimensions_batch_callbacks_registered' ); 5 | ``` 6 | 7 | Fires after the amp_extract_image_dimensions_batch filter has been added to extract by downloading images. 8 | 9 | ### Source 10 | 11 | :link: [includes/utils/class-amp-image-dimension-extractor.php:151](/includes/utils/class-amp-image-dimension-extractor.php#L151) 12 | 13 | <details> 14 | <summary>Show Code</summary> 15 | 16 | ```php 17 | do_action( 'amp_extract_image_dimensions_batch_callbacks_registered' ); 18 | ``` 19 | 20 | </details> 21 | -------------------------------------------------------------------------------- /docs/hook/amp_extract_image_dimensions_get_user_agent.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_extract_image_dimensions_get_user_agent` 2 | 3 | ```php 4 | apply_filters( 'amp_extract_image_dimensions_get_user_agent', $user_agent ); 5 | ``` 6 | 7 | Filters the user agent for obtaining the image dimensions. 8 | 9 | ### Arguments 10 | 11 | * `string $user_agent` - User agent. 12 | 13 | ### Source 14 | 15 | :link: [includes/utils/class-amp-image-dimension-extractor.php:368](/includes/utils/class-amp-image-dimension-extractor.php#L368) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | $client->setUserAgent( apply_filters( 'amp_extract_image_dimensions_get_user_agent', self::get_default_user_agent() ) ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_featured_image_minimum_height.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_featured_image_minimum_height` 2 | 3 | ```php 4 | apply_filters( 'amp_featured_image_minimum_height', $featured_image_minimum_height ); 5 | ``` 6 | 7 | Filters the minimum height required for a featured image. 8 | 9 | ### Arguments 10 | 11 | * `int $featured_image_minimum_height` - The minimum height of the image, defaults to 675. Returning a number less than or equal to zero disables the minimum constraint. 12 | 13 | ### Source 14 | 15 | :link: [includes/admin/class-amp-post-meta-box.php:319](/includes/admin/class-amp-post-meta-box.php#L319) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | $featured_image_minimum_height = (int) apply_filters( 'amp_featured_image_minimum_height', $default_height ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_featured_image_minimum_width.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_featured_image_minimum_width` 2 | 3 | ```php 4 | apply_filters( 'amp_featured_image_minimum_width', $featured_image_minimum_width ); 5 | ``` 6 | 7 | Filters the minimum width required for a featured image. 8 | 9 | ### Arguments 10 | 11 | * `int $featured_image_minimum_width` - The minimum width of the image, defaults to 1200. Returning a number less than or equal to zero disables the minimum constraint. 12 | 13 | ### Source 14 | 15 | :link: [includes/admin/class-amp-post-meta-box.php:329](/includes/admin/class-amp-post-meta-box.php#L329) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | $featured_image_minimum_width = (int) apply_filters( 'amp_featured_image_minimum_width', $default_width ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_get_permalink.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_get_permalink` 2 | 3 | ```php 4 | apply_filters( 'amp_get_permalink', $amp_url, $post_id ); 5 | ``` 6 | 7 | Filters AMP permalink. 8 | 9 | ### Arguments 10 | 11 | * `string $amp_url` - AMP URL. 12 | * `int $post_id` - Post ID. 13 | 14 | ### Source 15 | 16 | :link: [src/PairedUrlStructure/LegacyReaderUrlStructure.php:81](/src/PairedUrlStructure/LegacyReaderUrlStructure.php#L81) 17 | 18 | <details> 19 | <summary>Show Code</summary> 20 | 21 | ```php 22 | $amp_url = apply_filters( 'amp_get_permalink', $amp_url, $post_id ); 23 | ``` 24 | 25 | </details> 26 | -------------------------------------------------------------------------------- /docs/hook/amp_init.md: -------------------------------------------------------------------------------- 1 | ## Action `amp_init` 2 | 3 | ```php 4 | do_action( 'amp_init' ); 5 | ``` 6 | 7 | Triggers on init when AMP plugin is active. 8 | 9 | ### Source 10 | 11 | :link: [includes/amp-helper-functions.php:124](/includes/amp-helper-functions.php#L124) 12 | 13 | <details> 14 | <summary>Show Code</summary> 15 | 16 | ```php 17 | do_action( 'amp_init' ); 18 | ``` 19 | 20 | </details> 21 | -------------------------------------------------------------------------------- /docs/hook/amp_is_enabled.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_is_enabled` 2 | 3 | ```php 4 | apply_filters( 'amp_is_enabled', $enabled ); 5 | ``` 6 | 7 | Filters whether AMP is enabled on the current site. 8 | 9 | Useful if the plugin is network activated and you want to turn it off on select sites. 10 | 11 | ### Arguments 12 | 13 | * `bool $enabled` - Whether the AMP plugin&#039;s functionality should be enabled. 14 | 15 | ### Source 16 | 17 | :link: [includes/amp-helper-functions.php:36](/includes/amp-helper-functions.php#L36) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | return (bool) apply_filters( 'amp_is_enabled', true ); 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_mobile_user_agents.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_mobile_user_agents` 2 | 3 | ```php 4 | apply_filters( 'amp_mobile_user_agents', $user_agents ); 5 | ``` 6 | 7 | Filters the list of user agents used to determine if the user agent from the current request is a mobile one. 8 | 9 | ### Arguments 10 | 11 | * `string[] $user_agents` - List of mobile user agent search strings (and regex patterns). 12 | 13 | ### Source 14 | 15 | :link: [src/MobileRedirection.php:366](/src/MobileRedirection.php#L366) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | return apply_filters( 'amp_mobile_user_agents', $default_user_agents ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_mobile_version_switcher_link_text.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_mobile_version_switcher_link_text` 2 | 3 | ```php 4 | apply_filters( 'amp_mobile_version_switcher_link_text', $text ); 5 | ``` 6 | 7 | Filters the text to be used in the mobile switcher link. 8 | 9 | Use the `amp_is_request()` function to determine whether you are filtering the text for the link to go to the non-AMP version or the AMP version. 10 | 11 | ### Arguments 12 | 13 | * `string $text` - Link text to display. 14 | 15 | ### Source 16 | 17 | :link: [src/MobileRedirection.php:603](/src/MobileRedirection.php#L603) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | $text = apply_filters( 'amp_mobile_version_switcher_link_text', $text ); 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_mobile_version_switcher_styles_used.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_mobile_version_switcher_styles_used` 2 | 3 | ```php 4 | apply_filters( 'amp_mobile_version_switcher_styles_used', $used ); 5 | ``` 6 | 7 | Filters whether the default mobile version switcher styles are printed. 8 | 9 | ### Arguments 10 | 11 | * `bool $used` - Whether the styles are printed. 12 | 13 | ### Source 14 | 15 | :link: [src/MobileRedirection.php:558](/src/MobileRedirection.php#L558) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | if ( ! apply_filters( 'amp_mobile_version_switcher_styles_used', true ) ) { 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_native_img_used.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_native_img_used` 2 | 3 | ```php 4 | apply_filters( 'amp_native_img_used', $use_native ); 5 | ``` 6 | 7 | Filters whether to use the native `img` element rather than convert to `amp-img`. 8 | 9 | This filter is a feature flag to opt-in to discontinue using `amp-img` (and `amp-anim`) which will be deprecated in AMP in the near future. Once this lands in AMP, this filter will switch to defaulting to true instead of false. 10 | 11 | ### Arguments 12 | 13 | * `bool $use_native` - Whether to use `img`. 14 | 15 | ### Source 16 | 17 | :link: [includes/amp-helper-functions.php:1440](/includes/amp-helper-functions.php#L1440) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | return (bool) apply_filters( 'amp_native_img_used', $use_native_img_tag ); 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_normalized_dimension_extractor_image_url.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_normalized_dimension_extractor_image_url` 2 | 3 | ```php 4 | apply_filters( 'amp_normalized_dimension_extractor_image_url', $normalized_url, $url ); 5 | ``` 6 | 7 | Apply filters on the normalized image URL for dimension extraction. 8 | 9 | ### Arguments 10 | 11 | * `string $normalized_url` - Normalized image URL. 12 | * `string $url` - Original image URL. 13 | 14 | ### Source 15 | 16 | :link: [includes/utils/class-amp-image-dimension-extractor.php:132](/includes/utils/class-amp-image-dimension-extractor.php#L132) 17 | 18 | <details> 19 | <summary>Show Code</summary> 20 | 21 | ```php 22 | $normalized_url = apply_filters( 'amp_normalized_dimension_extractor_image_url', $normalized_url, $url ); 23 | ``` 24 | 25 | </details> 26 | -------------------------------------------------------------------------------- /docs/hook/amp_options_menu_is_enabled.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_options_menu_is_enabled` 2 | 3 | ```php 4 | apply_filters( 'amp_options_menu_is_enabled', $enable ); 5 | ``` 6 | 7 | Filter whether to enable the AMP settings. 8 | 9 | ### Arguments 10 | 11 | * `bool $enable` - Whether to enable the AMP settings. Default true. 12 | 13 | ### Source 14 | 15 | :link: [src/Admin/OptionsMenu.php:91](/src/Admin/OptionsMenu.php#L91) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | return (bool) apply_filters( 'amp_options_menu_is_enabled', true ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_page_cache_good_response_time_threshold.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_page_cache_good_response_time_threshold` 2 | 3 | > :warning: This filter is deprecated: 2.5.0 4 | 5 | ```php 6 | apply_filters( 'amp_page_cache_good_response_time_threshold', $threshold ); 7 | ``` 8 | 9 | Filters the threshold below which a response time is considered good. 10 | 11 | ### Arguments 12 | 13 | * `int $threshold` - Threshold in milliseconds. 14 | 15 | ### Source 16 | 17 | :link: [src/Admin/SiteHealth.php:375](/src/Admin/SiteHealth.php#L375) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | return (int) apply_filters( 'amp_page_cache_good_response_time_threshold', 600 ); 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_plugin_update.md: -------------------------------------------------------------------------------- 1 | ## Action `amp_plugin_update` 2 | 3 | ```php 4 | do_action( 'amp_plugin_update', $old_version ); 5 | ``` 6 | 7 | Triggers when after amp_init when the plugin version has updated. 8 | 9 | ### Arguments 10 | 11 | * `string $old_version` - Old version. 12 | 13 | ### Source 14 | 15 | :link: [includes/amp-helper-functions.php:174](/includes/amp-helper-functions.php#L174) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | do_action( 'amp_plugin_update', $old_version ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_post_status_default_enabled.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_post_status_default_enabled` 2 | 3 | ```php 4 | apply_filters( 'amp_post_status_default_enabled', $status, $post ); 5 | ``` 6 | 7 | Filters whether default AMP status should be enabled or not. 8 | 9 | ### Arguments 10 | 11 | * `string $status` - Status. 12 | * `\WP_Post $post` - Post. 13 | 14 | ### Source 15 | 16 | :link: [includes/class-amp-post-type-support.php:191](/includes/class-amp-post-type-support.php#L191) 17 | 18 | <details> 19 | <summary>Show Code</summary> 20 | 21 | ```php 22 | $enabled = apply_filters( 'amp_post_status_default_enabled', $enabled, $post ); 23 | ``` 24 | 25 | </details> 26 | -------------------------------------------------------------------------------- /docs/hook/amp_post_template_data.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_post_template_data` 2 | 3 | ```php 4 | apply_filters( 'amp_post_template_data', $data, $post ); 5 | ``` 6 | 7 | Filters AMP template data. 8 | 9 | ### Arguments 10 | 11 | * `array $data` - Template data. 12 | * `\WP_Post $post` - Post. 13 | 14 | ### Source 15 | 16 | :link: [includes/templates/class-amp-post-template.php:160](/includes/templates/class-amp-post-template.php#L160) 17 | 18 | <details> 19 | <summary>Show Code</summary> 20 | 21 | ```php 22 | $this->data = apply_filters( 'amp_post_template_data', $this->data, $this->post ); 23 | ``` 24 | 25 | </details> 26 | -------------------------------------------------------------------------------- /docs/hook/amp_post_template_dir.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_post_template_dir` 2 | 3 | ```php 4 | apply_filters( 'amp_post_template_dir' ); 5 | ``` 6 | 7 | Filters the Reader template directory. 8 | 9 | ### Source 10 | 11 | :link: [includes/templates/class-amp-post-template.php:177](/includes/templates/class-amp-post-template.php#L177) 12 | 13 | <details> 14 | <summary>Show Code</summary> 15 | 16 | ```php 17 | $template_dir = apply_filters( 'amp_post_template_dir', AMP__DIR__ . '/templates' ); 18 | ``` 19 | 20 | </details> 21 | -------------------------------------------------------------------------------- /docs/hook/amp_post_template_file.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_post_template_file` 2 | 3 | ```php 4 | apply_filters( 'amp_post_template_file', $file, $template_type, $post ); 5 | ``` 6 | 7 | Filters the template file being loaded for a given template type. 8 | 9 | ### Arguments 10 | 11 | * `string $file` - Template file. 12 | * `string $template_type` - Template type. 13 | * `\WP_Post $post` - Post. 14 | 15 | ### Source 16 | 17 | :link: [includes/templates/class-amp-post-template.php:470](/includes/templates/class-amp-post-template.php#L470) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | $file = apply_filters( 'amp_post_template_file', $file, $template_type, $this->post ); 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_post_template_include_{$template_type}.md: -------------------------------------------------------------------------------- 1 | ## Action `amp_post_template_include_{$template_type}` 2 | 3 | ```php 4 | do_action( 'amp_post_template_include_{$template_type}', $this ); 5 | ``` 6 | 7 | Fires before including a template. 8 | 9 | ### Arguments 10 | 11 | * `\AMP_Post_Template $this` - Post template. 12 | 13 | ### Source 14 | 15 | :link: [includes/templates/class-amp-post-template.php:484](/includes/templates/class-amp-post-template.php#L484) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | do_action( "amp_post_template_include_{$template_type}", $this ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_post_template_metadata.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_post_template_metadata` 2 | 3 | ```php 4 | apply_filters( 'amp_post_template_metadata', $metadata, $queried_object ); 5 | ``` 6 | 7 | Filters Schema.org metadata for a post. 8 | 9 | The &#039;post_template&#039; in the filter name here is due to this filter originally being introduced in `AMP_Post_Template`. In general the `amp_schemaorg_metadata` filter should be used instead. 10 | 11 | ### Arguments 12 | 13 | * `array $metadata` - Metadata. 14 | * `\WP_Post $queried_object` - Post. 15 | 16 | ### Source 17 | 18 | :link: [includes/amp-helper-functions.php:1911](/includes/amp-helper-functions.php#L1911) 19 | 20 | <details> 21 | <summary>Show Code</summary> 22 | 23 | ```php 24 | $metadata = apply_filters( 'amp_post_template_metadata', $metadata, $queried_object ); 25 | ``` 26 | 27 | </details> 28 | -------------------------------------------------------------------------------- /docs/hook/amp_pre_get_permalink.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_pre_get_permalink` 2 | 3 | ```php 4 | apply_filters( 'amp_pre_get_permalink', $url, $post_id ); 5 | ``` 6 | 7 | Filters the AMP permalink to short-circuit normal generation. 8 | 9 | Returning a string value in this filter will bypass the `get_permalink()` from being called and the `amp_get_permalink` filter will not apply. 10 | 11 | ### Arguments 12 | 13 | * `false $url` - Short-circuited URL. 14 | * `int $post_id` - Post ID. 15 | 16 | ### Source 17 | 18 | :link: [src/PairedUrlStructure/LegacyReaderUrlStructure.php:44](/src/PairedUrlStructure/LegacyReaderUrlStructure.php#L44) 19 | 20 | <details> 21 | <summary>Show Code</summary> 22 | 23 | ```php 24 | $pre_url = apply_filters( 'amp_pre_get_permalink', false, $post_id ); 25 | ``` 26 | 27 | </details> 28 | -------------------------------------------------------------------------------- /docs/hook/amp_pre_is_mobile.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_pre_is_mobile` 2 | 3 | ```php 4 | apply_filters( 'amp_pre_is_mobile', $is_mobile ); 5 | ``` 6 | 7 | Filters whether the current request is from a mobile device. This is provided as a means to short-circuit the normal determination of a mobile request below. 8 | 9 | ### Arguments 10 | 11 | * `null $is_mobile` - Whether the current request is from a mobile device. 12 | 13 | ### Source 14 | 15 | :link: [src/MobileRedirection.php:274](/src/MobileRedirection.php#L274) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | $pre_is_mobile = apply_filters( 'amp_pre_is_mobile', null ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_query_var.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_query_var` 2 | 3 | ```php 4 | apply_filters( 'amp_query_var', $query_var ); 5 | ``` 6 | 7 | Filter the AMP query variable. 8 | 9 | Warning: This filter may become deprecated. 10 | 11 | ### Arguments 12 | 13 | * `string $query_var` - The AMP query variable. 14 | 15 | ### Source 16 | 17 | :link: [includes/amp-helper-functions.php:614](/includes/amp-helper-functions.php#L614) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | return apply_filters( 'amp_query_var', defined( 'AMP_QUERY_VAR' ) ? AMP_QUERY_VAR : QueryVar::AMP ); 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_schemaorg_metadata.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_schemaorg_metadata` 2 | 3 | ```php 4 | apply_filters( 'amp_schemaorg_metadata', $metadata ); 5 | ``` 6 | 7 | Filters Schema.org metadata for a query. 8 | 9 | Check the the main query for the context for which metadata should be added. 10 | 11 | ### Arguments 12 | 13 | * `array $metadata` - Metadata. 14 | 15 | ### Source 16 | 17 | :link: [includes/amp-helper-functions.php:1925](/includes/amp-helper-functions.php#L1925) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | $metadata = apply_filters( 'amp_schemaorg_metadata', $metadata ); 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_site_icon_url.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_site_icon_url` 2 | 3 | ```php 4 | apply_filters( 'amp_site_icon_url', $schema_img_url ); 5 | ``` 6 | 7 | Filters the publisher logo URL in the schema.org data. 8 | 9 | Previously, this only filtered the Site Icon, as that was the only possible schema.org publisher logo. But the Custom Logo is now the preferred publisher logo, if it exists and its dimensions aren&#039;t too big. 10 | 11 | ### Arguments 12 | 13 | * `string $schema_img_url` - URL of the publisher logo, either the Custom Logo or the Site Icon. 14 | 15 | ### Source 16 | 17 | :link: [includes/amp-helper-functions.php:1835](/includes/amp-helper-functions.php#L1835) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | $logo_image_url = apply_filters( 'amp_site_icon_url', $logo_image_url ); 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_skip_post.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_skip_post` 2 | 3 | ```php 4 | apply_filters( 'amp_skip_post', $skipped, $post_id, $post ); 5 | ``` 6 | 7 | Filters whether to skip the post from AMP. 8 | 9 | ### Arguments 10 | 11 | * `bool $skipped` - Skipped. 12 | * `int $post_id` - Post ID. 13 | * `\WP_Post $post` - Post. 14 | 15 | ### Source 16 | 17 | :link: [includes/class-amp-post-type-support.php:141](/includes/class-amp-post-type-support.php#L141) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | if ( ! empty( $post->ID ) && true === apply_filters( 'amp_skip_post', false, $post->ID, $post ) ) { 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_supportable_post_types.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_supportable_post_types` 2 | 3 | ```php 4 | apply_filters( 'amp_supportable_post_types', $post_types ); 5 | ``` 6 | 7 | Filters the list of post types which may be supported for AMP. 8 | 9 | By default the list includes those which are public. 10 | 11 | ### Arguments 12 | 13 | * `string[] $post_types` - Post types. 14 | 15 | ### Source 16 | 17 | :link: [includes/class-amp-post-type-support.php:58](/includes/class-amp-post-type-support.php#L58) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | return array_values( (array) apply_filters( 'amp_supportable_post_types', $post_types ) ); 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_to_amp_linking_enabled.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_to_amp_linking_enabled` 2 | 3 | ```php 4 | apply_filters( 'amp_to_amp_linking_enabled', $amp_to_amp_linking_enabled ); 5 | ``` 6 | 7 | Filters whether AMP-to-AMP linking should be enabled. 8 | 9 | ### Arguments 10 | 11 | * `bool $amp_to_amp_linking_enabled` - Whether AMP-to-AMP linking should be enabled. 12 | 13 | ### Source 14 | 15 | :link: [includes/amp-helper-functions.php:1482](/includes/amp-helper-functions.php#L1482-L1485) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | $amp_to_amp_linking_enabled = (bool) apply_filters( 22 | 'amp_to_amp_linking_enabled', 23 | AMP_Theme_Support::TRANSITIONAL_MODE_SLUG === AMP_Options_Manager::get_option( Option::THEME_SUPPORT ) 24 | ); 25 | ``` 26 | 27 | </details> 28 | -------------------------------------------------------------------------------- /docs/hook/amp_validation_data_gc_before.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_validation_data_gc_before` 2 | 3 | ```php 4 | apply_filters( 'amp_validation_data_gc_before', $before ); 5 | ``` 6 | 7 | Filters the date before which validated URLs will be garbage collected. 8 | 9 | ### Arguments 10 | 11 | * `string|array $before` - Date before which to find amp_validated_url posts to delete. Default &#039;1 week ago&#039;. Accepts strtotime()-compatible string, or array of &#039;year&#039;, &#039;month&#039;, &#039;day&#039; values. 12 | 13 | ### Source 14 | 15 | :link: [src/BackgroundTask/ValidationDataGarbageCollection.php:89](/src/BackgroundTask/ValidationDataGarbageCollection.php#L89) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | $before = apply_filters( 'amp_validation_data_gc_before', '1 week ago' ); 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_validation_data_gc_delete_empty_terms.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_validation_data_gc_delete_empty_terms` 2 | 3 | ```php 4 | apply_filters( 'amp_validation_data_gc_delete_empty_terms', $enabled ); 5 | ``` 6 | 7 | Filters whether to delete empty terms during validation garbage collection. 8 | 9 | ### Arguments 10 | 11 | * `bool $enabled` - Whether enabled. Default true. 12 | 13 | ### Source 14 | 15 | :link: [src/BackgroundTask/ValidationDataGarbageCollection.php:100](/src/BackgroundTask/ValidationDataGarbageCollection.php#L100) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | if ( apply_filters( 'amp_validation_data_gc_delete_empty_terms', true ) ) { 22 | ``` 23 | 24 | </details> 25 | -------------------------------------------------------------------------------- /docs/hook/amp_validation_data_gc_url_count.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_validation_data_gc_url_count` 2 | 3 | ```php 4 | apply_filters( 'amp_validation_data_gc_url_count', $count ); 5 | ``` 6 | 7 | Filters the count of eligible validated URLs that should be garbage collected. 8 | 9 | If this is filtered to be zero or less, then garbage collection is disabled. 10 | 11 | ### Arguments 12 | 13 | * `int $count` - Validated URL count. Default 100. 14 | 15 | ### Source 16 | 17 | :link: [src/BackgroundTask/ValidationDataGarbageCollection.php:76](/src/BackgroundTask/ValidationDataGarbageCollection.php#L76) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | $count = apply_filters( 'amp_validation_data_gc_url_count', 100 ); 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/hook/amp_validation_error_source_file_path.md: -------------------------------------------------------------------------------- 1 | ## Filter `amp_validation_error_source_file_path` 2 | 3 | ```php 4 | apply_filters( 'amp_validation_error_source_file_path', $editor_url_template, $source ); 5 | ``` 6 | 7 | Filters the file path to be opened in an external editor for a given AMP validation error source. 8 | 9 | This is useful to map the file path from inside of a Docker container or VM to the host machine. 10 | 11 | ### Arguments 12 | 13 | * `string|null $editor_url_template` - Editor URL template. 14 | * `array $source` - Source information. 15 | 16 | ### Source 17 | 18 | :link: [includes/validation/class-amp-validation-error-taxonomy.php:2420](/includes/validation/class-amp-validation-error-taxonomy.php#L2420) 19 | 20 | <details> 21 | <summary>Show Code</summary> 22 | 23 | ```php 24 | $file_path = apply_filters( 'amp_validation_error_source_file_path', $file_path, $source ); 25 | ``` 26 | 27 | </details> 28 | -------------------------------------------------------------------------------- /docs/hook/pre_amp_render_post.md: -------------------------------------------------------------------------------- 1 | ## Action `pre_amp_render_post` 2 | 3 | > :warning: This action is deprecated: Check amp_is_request() on the template_redirect action instead. 4 | 5 | ```php 6 | do_action( 'pre_amp_render_post', $post_id ); 7 | ``` 8 | 9 | Fires before rendering a post in AMP. 10 | 11 | This action is not triggered when &#039;amp&#039; theme support is present. Instead, you should use &#039;template_redirect&#039; action and check if `amp_is_request()`. 12 | 13 | ### Arguments 14 | 15 | * `int $post_id` - Post ID. 16 | 17 | ### Source 18 | 19 | :link: [includes/deprecated.php:176](/includes/deprecated.php#L176) 20 | 21 | <details> 22 | <summary>Show Code</summary> 23 | 24 | ```php 25 | do_action( 'pre_amp_render_post', $post_id ); 26 | ``` 27 | 28 | </details> 29 | -------------------------------------------------------------------------------- /docs/includes/register-wp-cli-commands.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Register the WP-CLI commands for documentation generation. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | use AmpProject\AmpWP\Documentation\Cli\DocsCommandNamespace; 9 | use AmpProject\AmpWP\Documentation\Cli\GenerateCommand; 10 | 11 | if ( ! defined( 'WP_CLI' ) || ! class_exists( 'WP_CLI' ) ) { 12 | return; 13 | } 14 | 15 | WP_CLI::add_command( 'amp docs', DocsCommandNamespace::class ); 16 | WP_CLI::add_command( 'amp docs generate', GenerateCommand::class ); 17 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Embed_Handler/__construct.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Embed_Handler::__construct()` 2 | 3 | ```php 4 | public function __construct( $args = array() ); 5 | ``` 6 | 7 | Constructor. 8 | 9 | ### Arguments 10 | 11 | * `array $args` - Height and width for embed. 12 | 13 | ### Source 14 | 15 | :link: [includes/embeds/class-amp-base-embed-handler.php:66](/includes/embeds/class-amp-base-embed-handler.php#L66-L74) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | public function __construct( $args = [] ) { 22 | $this->args = wp_parse_args( 23 | $args, 24 | [ 25 | 'width' => $this->DEFAULT_WIDTH, 26 | 'height' => $this->DEFAULT_HEIGHT, 27 | ] 28 | ); 29 | } 30 | ``` 31 | 32 | </details> 33 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Embed_Handler/create_overflow_button_markup.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Embed_Handler::create_overflow_button_markup()` 2 | 3 | ```php 4 | protected function create_overflow_button_markup( $text = null ); 5 | ``` 6 | 7 | Create overflow button markup. 8 | 9 | ### Arguments 10 | 11 | * `string $text` - Button text (optional). 12 | 13 | ### Return value 14 | 15 | `string` - Button markup. 16 | 17 | ### Source 18 | 19 | :link: [includes/embeds/class-amp-base-embed-handler.php:234](/includes/embeds/class-amp-base-embed-handler.php#L234-L239) 20 | 21 | <details> 22 | <summary>Show Code</summary> 23 | 24 | ```php 25 | protected function create_overflow_button_markup( $text = null ) { 26 | if ( ! $text ) { 27 | $text = __( 'See more', 'amp' ); 28 | } 29 | return sprintf( '<button overflow type="button">%s</button>', esc_html( $text ) ); 30 | } 31 | ``` 32 | 33 | </details> 34 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Embed_Handler/get_child_elements.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Embed_Handler::get_child_elements()` 2 | 3 | ```php 4 | protected function get_child_elements( \DOMElement $node ); 5 | ``` 6 | 7 | Get all child elements of the specified element. 8 | 9 | ### Arguments 10 | 11 | * `\DOMElement $node` - Element. 12 | 13 | ### Return value 14 | 15 | `\DOMElement[]` - Array of child elements for specified element. 16 | 17 | ### Source 18 | 19 | :link: [includes/embeds/class-amp-base-embed-handler.php:129](/includes/embeds/class-amp-base-embed-handler.php#L129-L136) 20 | 21 | <details> 22 | <summary>Show Code</summary> 23 | 24 | ```php 25 | protected function get_child_elements( DOMElement $node ) { 26 | return array_filter( 27 | iterator_to_array( $node->childNodes ), 28 | static function ( DOMNode $child ) { 29 | return $child instanceof DOMElement; 30 | } 31 | ); 32 | } 33 | ``` 34 | 35 | </details> 36 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Embed_Handler/get_scripts.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Embed_Handler::get_scripts()` 2 | 3 | ```php 4 | public function get_scripts(); 5 | ``` 6 | 7 | Get mapping of AMP component names to AMP script URLs. 8 | 9 | This is normally no longer needed because the validating sanitizer will automatically detect the need for them via the spec. 10 | 11 | ### Return value 12 | 13 | `array` - Scripts. 14 | 15 | ### Source 16 | 17 | :link: [includes/embeds/class-amp-base-embed-handler.php:86](/includes/embeds/class-amp-base-embed-handler.php#L86-L88) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | public function get_scripts() { 24 | return []; 25 | } 26 | ``` 27 | 28 | </details> 29 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Embed_Handler/register_embed.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Embed_Handler::register_embed()` 2 | 3 | ```php 4 | abstract public function register_embed(); 5 | ``` 6 | 7 | Registers embed. 8 | 9 | ### Source 10 | 11 | :link: [includes/embeds/class-amp-base-embed-handler.php:54](/includes/embeds/class-amp-base-embed-handler.php#L54) 12 | 13 | <details> 14 | <summary>Show Code</summary> 15 | 16 | ```php 17 | abstract public function register_embed(); 18 | ``` 19 | 20 | </details> 21 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Embed_Handler/unregister_embed.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Embed_Handler::unregister_embed()` 2 | 3 | ```php 4 | abstract public function unregister_embed(); 5 | ``` 6 | 7 | Unregisters embed. 8 | 9 | ### Source 10 | 11 | :link: [includes/embeds/class-amp-base-embed-handler.php:59](/includes/embeds/class-amp-base-embed-handler.php#L59) 12 | 13 | <details> 14 | <summary>Show Code</summary> 15 | 16 | ```php 17 | abstract public function unregister_embed(); 18 | ``` 19 | 20 | </details> 21 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Sanitizer/get_arg.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Sanitizer::get_arg()` 2 | 3 | ```php 4 | public function get_arg( $key ); 5 | ``` 6 | 7 | Get arg. 8 | 9 | ### Arguments 10 | 11 | * `string $key` - Arg key. 12 | 13 | ### Return value 14 | 15 | `mixed` - Args. 16 | 17 | ### Source 18 | 19 | :link: [includes/sanitizers/class-amp-base-sanitizer.php:180](/includes/sanitizers/class-amp-base-sanitizer.php#L180-L185) 20 | 21 | <details> 22 | <summary>Show Code</summary> 23 | 24 | ```php 25 | public function get_arg( $key ) { 26 | if ( array_key_exists( $key, $this->args ) ) { 27 | return $this->args[ $key ]; 28 | } 29 | return null; 30 | } 31 | ``` 32 | 33 | </details> 34 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Sanitizer/get_args.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Sanitizer::get_args()` 2 | 3 | ```php 4 | public function get_args(); 5 | ``` 6 | 7 | Get args. 8 | 9 | ### Return value 10 | 11 | `array` - Args. 12 | 13 | ### Source 14 | 15 | :link: [includes/sanitizers/class-amp-base-sanitizer.php:194](/includes/sanitizers/class-amp-base-sanitizer.php#L194-L196) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | public function get_args() { 22 | return $this->args; 23 | } 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Sanitizer/get_body_node.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Sanitizer::get_body_node()` 2 | 3 | > :warning: This method is deprecated: Use $this-&gt;dom-&gt;body instead. 4 | 5 | ```php 6 | protected function get_body_node(); 7 | ``` 8 | 9 | Get HTML body as DOMElement from Dom\Document received by the constructor. 10 | 11 | ### Return value 12 | 13 | `\DOMElement` - The body element. 14 | 15 | ### Source 16 | 17 | :link: [includes/sanitizers/class-amp-base-sanitizer.php:281](/includes/sanitizers/class-amp-base-sanitizer.php#L281-L284) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | protected function get_body_node() { 24 | _deprecated_function( 'Use $this->dom->body instead', '1.5.0' ); 25 | return $this->dom->body; 26 | } 27 | ``` 28 | 29 | </details> 30 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Sanitizer/get_selector_conversion_mapping.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Sanitizer::get_selector_conversion_mapping()` 2 | 3 | ```php 4 | public function get_selector_conversion_mapping(); 5 | ``` 6 | 7 | Get mapping of HTML selectors to the AMP component selectors which they may be converted into. 8 | 9 | ### Return value 10 | 11 | `array` - Mapping. 12 | 13 | ### Source 14 | 15 | :link: [includes/sanitizers/class-amp-base-sanitizer.php:136](/includes/sanitizers/class-amp-base-sanitizer.php#L136-L138) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | public function get_selector_conversion_mapping() { 22 | return []; 23 | } 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Sanitizer/get_stylesheets.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Sanitizer::get_stylesheets()` 2 | 3 | ```php 4 | public function get_stylesheets(); 5 | ``` 6 | 7 | Get stylesheets. 8 | 9 | ### Return value 10 | 11 | `array` - Values are the CSS stylesheets. Keys are MD5 hashes of the stylesheets. 12 | 13 | ### Source 14 | 15 | :link: [includes/sanitizers/class-amp-base-sanitizer.php:262](/includes/sanitizers/class-amp-base-sanitizer.php#L262-L272) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | public function get_stylesheets() { 22 | $stylesheets = []; 23 | foreach ( $this->get_styles() as $selector => $properties ) { 24 | $stylesheet = sprintf( '%s { %s }', $selector, implode( '; ', $properties ) . ';' ); 25 | $stylesheets[ md5( $stylesheet ) ] = $stylesheet; 26 | } 27 | return $stylesheets; 28 | } 29 | ``` 30 | 31 | </details> 32 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Sanitizer/get_validate_response_data.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Sanitizer::get_validate_response_data()` 2 | 3 | ```php 4 | public function get_validate_response_data(); 5 | ``` 6 | 7 | Get data that is returned in validate responses. 8 | 9 | The array returned is merged with the overall validate response data. 10 | 11 | ### Return value 12 | 13 | `array` - Validate response data. 14 | 15 | ### Source 16 | 17 | :link: [includes/sanitizers/class-amp-base-sanitizer.php:929](/includes/sanitizers/class-amp-base-sanitizer.php#L929-L931) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | public function get_validate_response_data() { 24 | return []; 25 | } 26 | ``` 27 | 28 | </details> 29 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Sanitizer/init.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Sanitizer::init()` 2 | 3 | ```php 4 | public function init( $sanitizers ); 5 | ``` 6 | 7 | Run logic before any sanitizers are run. 8 | 9 | After the sanitizers are instantiated but before calling sanitize on each of them, this method is called with list of all the instantiated sanitizers. 10 | 11 | ### Arguments 12 | 13 | * `\AMP_Base_Sanitizer[] $sanitizers` - Sanitizers. 14 | 15 | ### Source 16 | 17 | :link: [includes/sanitizers/class-amp-base-sanitizer.php:219](/includes/sanitizers/class-amp-base-sanitizer.php#L219) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | public function init( $sanitizers ) {} // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Sanitizer/is_empty_attribute_value.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Sanitizer::is_empty_attribute_value()` 2 | 3 | ```php 4 | public function is_empty_attribute_value( $value ); 5 | ``` 6 | 7 | Determine if an attribute value is empty. 8 | 9 | ### Arguments 10 | 11 | * `string|null $value` - Attribute value. 12 | 13 | ### Return value 14 | 15 | `bool` - True if empty, false if not. 16 | 17 | ### Source 18 | 19 | :link: [includes/sanitizers/class-amp-base-sanitizer.php:333](/includes/sanitizers/class-amp-base-sanitizer.php#L333-L335) 20 | 21 | <details> 22 | <summary>Show Code</summary> 23 | 24 | ```php 25 | public function is_empty_attribute_value( $value ) { 26 | return ! isset( $value ) || '' === $value; 27 | } 28 | ``` 29 | 30 | </details> 31 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Sanitizer/sanitize.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Sanitizer::sanitize()` 2 | 3 | ```php 4 | abstract public function sanitize(); 5 | ``` 6 | 7 | Sanitize the HTML contained in the DOMDocument received by the constructor 8 | 9 | ### Source 10 | 11 | :link: [includes/sanitizers/class-amp-base-sanitizer.php:224](/includes/sanitizers/class-amp-base-sanitizer.php#L224) 12 | 13 | <details> 14 | <summary>Show Code</summary> 15 | 16 | ```php 17 | abstract public function sanitize(); 18 | ``` 19 | 20 | </details> 21 | -------------------------------------------------------------------------------- /docs/method/AMP_Base_Sanitizer/update_args.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_Base_Sanitizer::update_args()` 2 | 3 | ```php 4 | public function update_args( $args ); 5 | ``` 6 | 7 | Update args. 8 | 9 | Merges the supplied args with the existing args. 10 | 11 | ### Arguments 12 | 13 | * `array $args` - Args. 14 | 15 | ### Source 16 | 17 | :link: [includes/sanitizers/class-amp-base-sanitizer.php:207](/includes/sanitizers/class-amp-base-sanitizer.php#L207-L209) 18 | 19 | <details> 20 | <summary>Show Code</summary> 21 | 22 | ```php 23 | public function update_args( $args ) { 24 | $this->args = array_merge( $this->args, $args ); 25 | } 26 | ``` 27 | 28 | </details> 29 | -------------------------------------------------------------------------------- /docs/method/AMP_DOM_Utils/is_node_empty.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_DOM_Utils::is_node_empty()` 2 | 3 | ```php 4 | static public function is_node_empty( $node ); 5 | ``` 6 | 7 | Determines if a DOMElement&#039;s node is empty or not. 8 | 9 | . 10 | 11 | ### Arguments 12 | 13 | * `\DOMElement $node` - Represents an HTML element. 14 | 15 | ### Return value 16 | 17 | `bool` - Returns true if the DOMElement has no child nodes and the textContent property of the DOMElement is empty; Otherwise it returns false. 18 | 19 | ### Source 20 | 21 | :link: [includes/utils/class-amp-dom-utils.php:226](/includes/utils/class-amp-dom-utils.php#L226-L228) 22 | 23 | <details> 24 | <summary>Show Code</summary> 25 | 26 | ```php 27 | public static function is_node_empty( $node ) { 28 | return false === $node->hasChildNodes() && empty( $node->textContent ); 29 | } 30 | ``` 31 | 32 | </details> 33 | -------------------------------------------------------------------------------- /docs/method/AMP_WordPress_Embed_Handler/register_embed.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_WordPress_Embed_Handler::register_embed()` 2 | 3 | ```php 4 | public function register_embed(); 5 | ``` 6 | 7 | Register embed. 8 | 9 | ### Source 10 | 11 | :link: [includes/embeds/class-amp-wordpress-embed-handler.php:45](/includes/embeds/class-amp-wordpress-embed-handler.php#L45-L47) 12 | 13 | <details> 14 | <summary>Show Code</summary> 15 | 16 | ```php 17 | public function register_embed() { 18 | remove_action( 'wp_head', 'wp_oembed_add_host_js' ); 19 | } 20 | ``` 21 | 22 | </details> 23 | -------------------------------------------------------------------------------- /docs/method/AMP_WordPress_Embed_Handler/unregister_embed.md: -------------------------------------------------------------------------------- 1 | ## Method `AMP_WordPress_Embed_Handler::unregister_embed()` 2 | 3 | ```php 4 | public function unregister_embed(); 5 | ``` 6 | 7 | Unregister embed. 8 | 9 | ### Source 10 | 11 | :link: [includes/embeds/class-amp-wordpress-embed-handler.php:52](/includes/embeds/class-amp-wordpress-embed-handler.php#L52-L54) 12 | 13 | <details> 14 | <summary>Show Code</summary> 15 | 16 | ```php 17 | public function unregister_embed() { 18 | add_action( 'wp_head', 'wp_oembed_add_host_js' ); 19 | } 20 | ``` 21 | 22 | </details> 23 | -------------------------------------------------------------------------------- /docs/method/PairedUrl/add_query_var.md: -------------------------------------------------------------------------------- 1 | ## Method `PairedUrl::add_query_var()` 2 | 3 | ```php 4 | public function add_query_var( $url, $value = '1' ); 5 | ``` 6 | 7 | Get paired AMP URL using query var (`?amp=1`). 8 | 9 | ### Arguments 10 | 11 | * `string $url` - URL (or REQUEST_URI). 12 | * `string $value` - Value. Defaults to 1. 13 | 14 | ### Return value 15 | 16 | `string` - AMP URL. 17 | 18 | ### Source 19 | 20 | :link: [src/PairedUrl.php:90](/src/PairedUrl.php#L90-L92) 21 | 22 | <details> 23 | <summary>Show Code</summary> 24 | 25 | ```php 26 | public function add_query_var( $url, $value = '1' ) { 27 | return add_query_arg( amp_get_slug(), $value, $url ); 28 | } 29 | ``` 30 | 31 | </details> 32 | -------------------------------------------------------------------------------- /docs/method/PairedUrl/has_path_suffix.md: -------------------------------------------------------------------------------- 1 | ## Method `PairedUrl::has_path_suffix()` 2 | 3 | ```php 4 | public function has_path_suffix( $url ); 5 | ``` 6 | 7 | Determine whether the given URL has the endpoint suffix. 8 | 9 | ### Arguments 10 | 11 | * `string $url` - URL (or REQUEST_URI). 12 | 13 | ### Return value 14 | 15 | `bool` - Has endpoint suffix. 16 | 17 | ### Source 18 | 19 | :link: [src/PairedUrl.php:38](/src/PairedUrl.php#L38-L46) 20 | 21 | <details> 22 | <summary>Show Code</summary> 23 | 24 | ```php 25 | public function has_path_suffix( $url ) { 26 | $path = wp_parse_url( $url, PHP_URL_PATH ); 27 | $pattern = sprintf( 28 | ':/%s/?$:', 29 | preg_quote( amp_get_slug(), ':' ) 30 | ); 31 | return (bool) preg_match( $pattern, $path ); 32 | } 33 | ``` 34 | 35 | </details> 36 | -------------------------------------------------------------------------------- /docs/method/PairedUrl/has_query_var.md: -------------------------------------------------------------------------------- 1 | ## Method `PairedUrl::has_query_var()` 2 | 3 | ```php 4 | public function has_query_var( $url ); 5 | ``` 6 | 7 | Determine whether the given URL has the query var. 8 | 9 | ### Arguments 10 | 11 | * `string $url` - URL (or REQUEST_URI). 12 | 13 | ### Return value 14 | 15 | `bool` - Has query var. 16 | 17 | ### Source 18 | 19 | :link: [src/PairedUrl.php:71](/src/PairedUrl.php#L71-L81) 20 | 21 | <details> 22 | <summary>Show Code</summary> 23 | 24 | ```php 25 | public function has_query_var( $url ) { 26 | $parsed_url = wp_parse_url( $url ); 27 | if ( ! empty( $parsed_url['query'] ) ) { 28 | $query_vars = []; 29 | wp_parse_str( $parsed_url['query'], $query_vars ); 30 | if ( isset( $query_vars[ amp_get_slug() ] ) ) { 31 | return true; 32 | } 33 | } 34 | return false; 35 | } 36 | ``` 37 | 38 | </details> 39 | -------------------------------------------------------------------------------- /docs/method/PairedUrl/remove_path_suffix.md: -------------------------------------------------------------------------------- 1 | ## Method `PairedUrl::remove_path_suffix()` 2 | 3 | ```php 4 | public function remove_path_suffix( $url ); 5 | ``` 6 | 7 | Strip paired endpoint suffix. 8 | 9 | ### Arguments 10 | 11 | * `string $url` - URL (or REQUEST_URI). 12 | 13 | ### Return value 14 | 15 | `string` - URL. 16 | 17 | ### Source 18 | 19 | :link: [src/PairedUrl.php:54](/src/PairedUrl.php#L54-L63) 20 | 21 | <details> 22 | <summary>Show Code</summary> 23 | 24 | ```php 25 | public function remove_path_suffix( $url ) { 26 | return preg_replace( 27 | sprintf( 28 | ':/%s(?=/?(\?|#|$)):', 29 | preg_quote( amp_get_slug(), ':' ) 30 | ), 31 | '', 32 | $url 33 | ); 34 | } 35 | ``` 36 | 37 | </details> 38 | -------------------------------------------------------------------------------- /docs/method/PairedUrl/remove_query_var.md: -------------------------------------------------------------------------------- 1 | ## Method `PairedUrl::remove_query_var()` 2 | 3 | ```php 4 | public function remove_query_var( $url ); 5 | ``` 6 | 7 | Strip paired query var. 8 | 9 | ### Arguments 10 | 11 | * `string $url` - URL (or REQUEST_URI). 12 | 13 | ### Return value 14 | 15 | `string` - URL. 16 | 17 | ### Source 18 | 19 | :link: [src/PairedUrl.php:26](/src/PairedUrl.php#L26-L30) 20 | 21 | <details> 22 | <summary>Show Code</summary> 23 | 24 | ```php 25 | public function remove_query_var( $url ) { 26 | $url = remove_query_arg( amp_get_slug(), $url ); 27 | $url = str_replace( '?#', '#', $url ); // See <https://core.trac.wordpress.org/ticket/44499>. 28 | return $url; 29 | } 30 | ``` 31 | 32 | </details> 33 | -------------------------------------------------------------------------------- /docs/method/PairedUrlStructure/__construct.md: -------------------------------------------------------------------------------- 1 | ## Method `PairedUrlStructure::__construct()` 2 | 3 | ```php 4 | public function __construct( \AmpProject\AmpWP\PairedUrl $paired_url ); 5 | ``` 6 | 7 | PairedUrlStructure constructor. 8 | 9 | ### Arguments 10 | 11 | * `\AmpProject\AmpWP\PairedUrl $paired_url` - Paired URL service. 12 | 13 | ### Source 14 | 15 | :link: [src/PairedUrlStructure.php:30](/src/PairedUrlStructure.php#L30-L32) 16 | 17 | <details> 18 | <summary>Show Code</summary> 19 | 20 | ```php 21 | public function __construct( PairedUrl $paired_url ) { 22 | $this->paired_url = $paired_url; 23 | } 24 | ``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/method/PairedUrlStructure/add_endpoint.md: -------------------------------------------------------------------------------- 1 | ## Method `PairedUrlStructure::add_endpoint()` 2 | 3 | ```php 4 | abstract public function add_endpoint( $url ); 5 | ``` 6 | 7 | Turn a given URL into a paired AMP URL. 8 | 9 | ### Arguments 10 | 11 | * `string $url` - URL (or REQUEST_URI). 12 | 13 | ### Return value 14 | 15 | `string` - AMP URL. 16 | 17 | ### Source 18 | 19 | :link: [src/PairedUrlStructure.php:50](/src/PairedUrlStructure.php#L50) 20 | 21 | <details> 22 | <summary>Show Code</summary> 23 | 24 | ```php 25 | abstract public function add_endpoint( $url ); 26 | ``` 27 | 28 | </details> 29 | -------------------------------------------------------------------------------- /docs/method/PairedUrlStructure/has_endpoint.md: -------------------------------------------------------------------------------- 1 | ## Method `PairedUrlStructure::has_endpoint()` 2 | 3 | ```php 4 | public function has_endpoint( $url ); 5 | ``` 6 | 7 | Determine a given URL is for a paired AMP request. 8 | 9 | ### Arguments 10 | 11 | * `string $url` - URL (or REQUEST_URI). 12 | 13 | ### Return value 14 | 15 | `bool` - True if the URL has the paired endpoint. 16 | 17 | ### Source 18 | 19 | :link: [src/PairedUrlStructure.php:40](/src/PairedUrlStructure.php#L40-L42) 20 | 21 | <details> 22 | <summary>Show Code</summary> 23 | 24 | ```php 25 | public function has_endpoint( $url ) { 26 | return $url !== $this->remove_endpoint( $url ); 27 | } 28 | ``` 29 | 30 | </details> 31 | -------------------------------------------------------------------------------- /docs/method/PairedUrlStructure/remove_endpoint.md: -------------------------------------------------------------------------------- 1 | ## Method `PairedUrlStructure::remove_endpoint()` 2 | 3 | ```php 4 | abstract public function remove_endpoint( $url ); 5 | ``` 6 | 7 | Remove the paired AMP endpoint from a given URL. 8 | 9 | ### Arguments 10 | 11 | * `string $url` - URL (or REQUEST_URI). 12 | 13 | ### Return value 14 | 15 | `string` - URL with AMP stripped. 16 | 17 | ### Source 18 | 19 | :link: [src/PairedUrlStructure.php:58](/src/PairedUrlStructure.php#L58) 20 | 21 | <details> 22 | <summary>Show Code</summary> 23 | 24 | ```php 25 | abstract public function remove_endpoint( $url ); 26 | ``` 27 | 28 | </details> 29 | -------------------------------------------------------------------------------- /docs/src/Cli/DocsCommandNamespace.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Class FileReflector. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Documentation\Cli; 9 | 10 | use WP_CLI\Dispatcher\CommandNamespace; 11 | 12 | /** 13 | * Maintains the AMP reference documentation via the command line. 14 | * 15 | * @package AmpProject\AmpWP\Docs\Cli 16 | */ 17 | final class DocsCommandNamespace extends CommandNamespace { 18 | 19 | } 20 | -------------------------------------------------------------------------------- /docs/src/Model/Include_.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Class Include_. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Documentation\Model; 9 | 10 | /** 11 | * Documentation reference object representing an include or require statement. 12 | * 13 | * @property string $name 14 | * @property int $line 15 | * @property string $type 16 | * 17 | * phpcs:disable PEAR.NamingConventions.ValidClassName.Invalid 18 | */ 19 | final class Include_ implements Leaf { 20 | 21 | use LeafConstruction; 22 | 23 | /** 24 | * Get an associative array of known keys. 25 | * 26 | * @return array 27 | */ 28 | protected function get_known_keys() { 29 | return [ 30 | 'name' => '', 31 | 'line' => 0, 32 | 'type' => '', 33 | ]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /docs/src/Model/Leaf.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Interface Leaf. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Documentation\Model; 9 | 10 | /** 11 | * An individual leaf in a tree structure. 12 | * 13 | * Each leaf can have a parent within the same tree structure. 14 | */ 15 | interface Leaf { 16 | 17 | /** 18 | * Get the parent leaf object of the current leaf. 19 | * 20 | * @return Leaf|null Parent leaf, or null if none. 21 | */ 22 | public function get_parent(); 23 | } 24 | -------------------------------------------------------------------------------- /docs/src/Model/Tag.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Class Tag. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Documentation\Model; 9 | 10 | /** 11 | * Documentation reference object representing a doc-block annotation. 12 | * 13 | * @property string $name 14 | * @property string $content 15 | * @property string[] $types 16 | * @property string $variable 17 | */ 18 | final class Tag implements Leaf { 19 | 20 | use LeafConstruction; 21 | 22 | /** 23 | * Get an associative array of known keys. 24 | * 25 | * @return array 26 | */ 27 | protected function get_known_keys() { 28 | return [ 29 | 'name' => '', 30 | 'content' => '', 31 | 'types' => [], 32 | 'variable' => '', 33 | ]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /docs/src/Templating/TemplateEngine.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Interface TemplateEngine. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Documentation\Templating; 9 | 10 | use AmpProject\AmpWP\Documentation\Model\Leaf; 11 | use RuntimeException; 12 | 13 | interface TemplateEngine { 14 | 15 | /** 16 | * Render a specific template. 17 | * 18 | * @param string $template Name of the template to use. 19 | * @param array|Leaf $data Associative array of data to use for rendering. 20 | * @return string Rendered result. 21 | * @throws RuntimeException If the template file could not be located. 22 | * @throws RuntimeException If the template file could not be loaded. 23 | */ 24 | public function render( $template, $data ); 25 | } 26 | -------------------------------------------------------------------------------- /docs/templates/class.mustache: -------------------------------------------------------------------------------- 1 | ## Class `{{ get_fully_qualified_name }}` 2 | 3 | {{# is_deprecated }} 4 | > :warning: This class is deprecated: {{ get_deprecation_reason }} 5 | 6 | {{/ is_deprecated }} 7 | {{# has_description }} 8 | {{ get_description }} 9 | 10 | {{/ has_description }} 11 | ### Methods 12 | 13 | {{# methods }} 14 | * {{# is_deprecated }}~~{{/is_deprecated}}[`{{{ name }}}`](../method/{{{ get_filename }}}.md){{# has_description }} - {{ get_short_description }}{{/ has_description }}{{# is_deprecated }}~~{{/is_deprecated}} 15 | {{/ methods }} 16 | ### Source 17 | 18 | :link: [{{ get_file_path }}:{{ line }}]({{{ get_github_link }}}) 19 | 20 | <details> 21 | <summary>Show Code</summary> 22 | 23 | ```php 24 | {{{ get_code }}}``` 25 | 26 | </details> 27 | -------------------------------------------------------------------------------- /docs/templates/class_index.mustache: -------------------------------------------------------------------------------- 1 | ## Classes 2 | 3 | {{# . }} 4 | * {{# is_deprecated }}~~{{/is_deprecated}}[`{{{ get_relative_name }}}`]({{{ get_filename }}}.md){{# has_description }} - {{ get_short_description }}{{/ has_description }}{{# is_deprecated }}~~{{/is_deprecated}} 5 | {{/.}} 6 | -------------------------------------------------------------------------------- /docs/templates/function_index.mustache: -------------------------------------------------------------------------------- 1 | ## Functions 2 | 3 | {{# . }} 4 | * {{# is_deprecated }}~~{{/is_deprecated}}[`{{{ get_relative_name }}}`]({{{ get_filename }}}.md){{# has_description }} - {{ get_short_description }}{{/ has_description }}{{# is_deprecated }}~~{{/is_deprecated}} 5 | {{/.}} 6 | -------------------------------------------------------------------------------- /docs/templates/hook.mustache: -------------------------------------------------------------------------------- 1 | ## {{ get_capitalized_type }} `{{{ name }}}` 2 | 3 | {{# is_deprecated }} 4 | > :warning: This {{ type }} is deprecated: {{ get_deprecation_reason }} 5 | 6 | {{/is_deprecated}} 7 | ```php 8 | {{{ get_signature }}} 9 | ``` 10 | 11 | {{# has_description }} 12 | {{ get_description }} 13 | 14 | {{/ has_description }} 15 | {{# has_arguments }} 16 | ### Arguments 17 | 18 | {{# arguments }} 19 | * `{{{ guess_type }}} {{{ name }}}`{{# has_description}} - {{ get_description }}{{/has_description}} 20 | {{/ arguments }} 21 | 22 | {{/ has_arguments }} 23 | ### Source 24 | 25 | :link: [{{ get_file_path }}:{{ line }}]({{{ get_github_link }}}) 26 | 27 | <details> 28 | <summary>Show Code</summary> 29 | 30 | ```php 31 | {{{ get_code }}}``` 32 | 33 | </details> 34 | -------------------------------------------------------------------------------- /docs/templates/hook_index.mustache: -------------------------------------------------------------------------------- 1 | ## Hooks 2 | 3 | ### Actions 4 | 5 | {{# . }} 6 | {{# is_action }} 7 | * {{# is_deprecated }}~~{{/is_deprecated}}[`{{{ name }}}`]({{{ get_filename }}}.md){{# has_description }} - {{ get_short_description }}{{/ has_description }}{{# is_deprecated }}~~{{/is_deprecated}} 8 | {{/ is_action }} 9 | {{/.}} 10 | 11 | ### Filters 12 | 13 | {{# . }} 14 | {{# is_filter }} 15 | * {{# is_deprecated }}~~{{/is_deprecated}}[`{{{ name }}}`]({{{ get_filename }}}.md){{# has_description }} - {{ get_short_description }}{{/ has_description }}{{# is_deprecated }}~~{{/is_deprecated}} 16 | {{/ is_filter }} 17 | {{/.}} 18 | -------------------------------------------------------------------------------- /docs/templates/index.mustache: -------------------------------------------------------------------------------- 1 | # AMP for WordPress Plugin [<img src="../assets/images/amp-logo-icon.svg" alt="AMP for WordPress Plugin Logo" align="right" height="80">](https://amp-wp.org/) 2 | 3 | Official AMP plugin, supported by the AMP team. Formerly Accelerated Mobile Pages, AMP enables great experiences across both mobile and desktop. 4 | 5 | ## Reference Documentation 6 | 7 | ### [▹ Classes](class/README.md) 8 | ### [▹ Methods](method/README.md) 9 | ### [▹ Functions](function/README.md) 10 | ### [▹ Hooks](hook/README.md) 11 | 12 | -------------------------------------------------------------------------------- /docs/templates/method_index.mustache: -------------------------------------------------------------------------------- 1 | ## Methods 2 | 3 | {{# . }} 4 | * {{# is_deprecated }}~~{{/is_deprecated}}[`{{{ get_display_name }}}`]({{{ get_filename }}}.md){{# has_description }} - {{ get_short_description }}{{/ has_description }}{{# is_deprecated }}~~{{/is_deprecated}} 5 | {{/.}} 6 | -------------------------------------------------------------------------------- /includes/bootstrap.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Central bootstrapping entry point for all non-autoloaded files. 4 | * 5 | * This file is mainly used for taking direct control of included files off from Composer's 6 | * "files" directive, as that one can easily include the files multiple times, leading to 7 | * redeclaration fatal errors. 8 | * 9 | * @package AmpProject/AmpWP 10 | */ 11 | 12 | $files_to_include = [ 13 | __DIR__ . '/../back-compat/back-compat.php' => 'amp_backcompat_use_v03_templates', 14 | __DIR__ . '/../includes/amp-helper-functions.php' => 'amp_activate', 15 | __DIR__ . '/../includes/admin/functions.php' => 'amp_init_customizer', 16 | __DIR__ . '/../includes/deprecated.php' => 'amp_load_classes', 17 | ]; 18 | 19 | foreach ( $files_to_include as $file_to_include => $function_to_check ) { 20 | if ( ! function_exists( $function_to_check ) ) { 21 | include $file_to_include; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /includes/sanitizers/class-amp-auto-lightbox-disable-sanitizer.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Class AMP_Auto_Lightbox_Disable_Sanitizer 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | /** 9 | * Disable auto lightbox for images. 10 | * 11 | * @since 2.2.2 12 | * @internal 13 | */ 14 | class AMP_Auto_Lightbox_Disable_Sanitizer extends AMP_Base_Sanitizer { 15 | 16 | /** 17 | * Add "data-amp-auto-lightbox-disable" attribute to body tag. 18 | * 19 | * @return void 20 | */ 21 | public function sanitize() { 22 | $this->dom->html->setAttributeNode( $this->dom->createAttribute( 'data-amp-auto-lightbox-disable' ) ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /includes/utils/class-amp-string-utils.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Class AMP_String_Utils 4 | * 5 | * @package AMP 6 | */ 7 | 8 | /** 9 | * Class with static string utility methods. 10 | * 11 | * @internal 12 | */ 13 | class AMP_String_Utils { 14 | 15 | /** 16 | * Checks whether a given string ends in the given substring. 17 | * 18 | * @param string $haystack Input string. 19 | * @param string $needle Substring to look for at the end of $haystack. 20 | * @return bool True if $haystack ends in $needle, false otherwise. 21 | */ 22 | public static function endswith( $haystack, $needle ) { 23 | return '' !== $haystack 24 | && '' !== $needle 25 | && substr( $haystack, -strlen( $needle ) ) === $needle; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-import'), 4 | require('postcss-nested'), 5 | require('postcss-preset-env')({ 6 | stage: 0, 7 | preserve: false, // Omit pre-polyfilled CSS. 8 | features: { 9 | 'nesting-rules': false, // Uses postcss-nesting which doesn't behave like Sass. 10 | 'custom-properties': { 11 | preserve: true, // Do not remove :root selector. 12 | }, 13 | }, 14 | autoprefixer: { 15 | grid: true, 16 | }, 17 | }), 18 | ], 19 | }; 20 | -------------------------------------------------------------------------------- /src/Cli/AmpCommandNamespace.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Class AmpCommandNamespace. 4 | * 5 | * Command namespace that regroups all AMP CLI commands. 6 | * 7 | * @package AmpProject\AmpWP 8 | */ 9 | 10 | namespace AmpProject\AmpWP\Cli; 11 | 12 | use WP_CLI\Dispatcher\CommandNamespace; 13 | 14 | /** 15 | * Interacts with the AMP plugin. 16 | * 17 | * @since 1.3.0 18 | * @since 2.1.0 Renamed and refactored into PSR-4 namespace. 19 | * @internal 20 | */ 21 | final class AmpCommandNamespace extends CommandNamespace { 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/Component/HasCaption.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Interface HasCaption 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Component; 9 | 10 | use DOMElement; 11 | 12 | /** 13 | * Interface HasCaption 14 | * 15 | * @internal 16 | * @since 1.5.0 17 | */ 18 | interface HasCaption { 19 | 20 | /** 21 | * Gets the caption node. 22 | * 23 | * @return DOMElement 24 | */ 25 | public function get_caption_element(); 26 | } 27 | -------------------------------------------------------------------------------- /src/ConfigurationArgument.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Interface ConfigurationArgument. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP; 9 | 10 | /** 11 | * Constants for the options that the AmpWP plugin supports. 12 | * 13 | * @package AmpProject\AmpWP 14 | * @since 2.0 15 | * @internal 16 | */ 17 | interface ConfigurationArgument { 18 | 19 | const ENABLE_ESM = 'enable_esm'; 20 | const ENABLE_OPTIMIZER = 'enable_optimizer'; 21 | const ENABLE_SSR = 'enable_ssr'; 22 | } 23 | -------------------------------------------------------------------------------- /src/Dom/Options.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Class Options. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Dom; 9 | 10 | use AmpProject\Dom\Document; 11 | 12 | interface Options { 13 | 14 | /** 15 | * Default options to use for the Dom. 16 | * 17 | * @var array 18 | */ 19 | const DEFAULTS = [ 20 | Document\Option::AMP_BIND_SYNTAX => Document\Option::AMP_BIND_SYNTAX_DATA_ATTRIBUTE, 21 | ]; 22 | } 23 | -------------------------------------------------------------------------------- /src/Editor/EditorSupport.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Functionality around editor support for AMP plugin features. 4 | * 5 | * @since 2.1 6 | * 7 | * @package AmpProject\AmpWP 8 | */ 9 | 10 | namespace AmpProject\AmpWP\Editor; 11 | 12 | use AMP_Post_Type_Support; 13 | use AmpProject\AmpWP\Infrastructure\Service; 14 | 15 | /** 16 | * EditorSupport class. 17 | * 18 | * @internal 19 | */ 20 | final class EditorSupport implements Service { 21 | 22 | /** 23 | * Returns whether the current screen is using the block editor and the post being edited supports AMP. 24 | * 25 | * @return bool 26 | */ 27 | public function is_current_screen_block_editor_for_amp_enabled_post_type() { 28 | $screen = get_current_screen(); 29 | return ( 30 | $screen 31 | && 32 | ! empty( $screen->is_block_editor ) 33 | && 34 | in_array( get_post_type(), AMP_Post_Type_Support::get_supported_post_types(), true ) 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Exception/AmpWpException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Interface AmpWpException. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Exception; 9 | 10 | /** 11 | * This is a "marker interface" to mark all the exceptions that come with this 12 | * plugin with this one interface. 13 | * 14 | * This allows you to not only catch individual exceptions, but also catch "all 15 | * exceptions from the AmpWp plugin". 16 | * 17 | * @since 2.0 18 | * @internal 19 | */ 20 | interface AmpWpException { 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/Infrastructure/Activateable.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Interface Activateable. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Infrastructure; 9 | 10 | /** 11 | * Something that can be activated. 12 | * 13 | * By tagging a service with this interface, the system will automatically hook 14 | * it up to the WordPress activation hook. 15 | * 16 | * This way, we can just add the simple interface marker and not worry about how 17 | * to wire up the code to reach that part during the static activation hook. 18 | * 19 | * @since 2.0 20 | * @internal 21 | */ 22 | interface Activateable { 23 | 24 | /** 25 | * Activate the service. 26 | * 27 | * @param bool $network_wide Whether the activation was done network-wide. 28 | * @return void 29 | */ 30 | public function activate( $network_wide ); 31 | } 32 | -------------------------------------------------------------------------------- /src/Infrastructure/CliCommand.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Interface CliCommand. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Infrastructure; 9 | 10 | /** 11 | * A CLI command to be registered with WP-CLI. 12 | * 13 | * A class marked as being a CLI command will automatically be registered 14 | * as a command with WP-CLI. 15 | * 16 | * @since 2.1.0 17 | * @internal 18 | */ 19 | interface CliCommand { 20 | 21 | /** 22 | * Get the name under which to register the CLI command. 23 | * 24 | * @return string The name under which to register the CLI command. 25 | */ 26 | public static function get_command_name(); 27 | } 28 | -------------------------------------------------------------------------------- /src/Infrastructure/Conditional.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Interface Conditional. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Infrastructure; 9 | 10 | /** 11 | * Something that can be instantiated conditionally. 12 | * 13 | * A class marked as being conditionally can be asked whether it should be 14 | * instantiated through a static method. An example would be a service that is 15 | * only available on the admin backend. 16 | * 17 | * This allows for a more systematic and automated optimization of how the 18 | * different parts of the plugin are enabled or disabled. 19 | * 20 | * @since 2.0 21 | * @internal 22 | */ 23 | interface Conditional { 24 | 25 | /** 26 | * Check whether the conditional object is currently needed. 27 | * 28 | * @return bool Whether the conditional object is needed. 29 | */ 30 | public static function is_needed(); 31 | } 32 | -------------------------------------------------------------------------------- /src/Infrastructure/Deactivateable.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Interface Deactivateable. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Infrastructure; 9 | 10 | /** 11 | * Something that can be deactivated. 12 | * 13 | * By tagging a service with this interface, the system will automatically hook 14 | * it up to the WordPress deactivation hook. 15 | * 16 | * This way, we can just add the simple interface marker and not worry about how 17 | * to wire up the code to reach that part during the static deactivation hook. 18 | * 19 | * @since 2.0 20 | * @internal 21 | */ 22 | interface Deactivateable { 23 | 24 | /** 25 | * Deactivate the service. 26 | * 27 | * @param bool $network_wide Whether the deactivation was done network-wide. 28 | * @return void 29 | */ 30 | public function deactivate( $network_wide ); 31 | } 32 | -------------------------------------------------------------------------------- /src/Infrastructure/Delayed.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Interface Delayed. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Infrastructure; 9 | 10 | /** 11 | * Something that is delayed to a later point in the execution flow. 12 | * 13 | * A class marked as being delayed can return the action at which it requires 14 | * to be registered. 15 | * 16 | * This can be used to only register a given object after certain contextual 17 | * requirements are met, like registering a frontend rendering service only 18 | * after the loop has been set up. 19 | * 20 | * @since 2.0 21 | * @internal 22 | */ 23 | interface Delayed { 24 | 25 | /** 26 | * Get the action to use for registering the service. 27 | * 28 | * @return string Registration action to use. 29 | */ 30 | public static function get_registration_action(); 31 | } 32 | -------------------------------------------------------------------------------- /src/Infrastructure/HasRequirements.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Interface HasRequirements. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Infrastructure; 9 | 10 | /** 11 | * Something that requires other services to be registered before it can be registered. 12 | * 13 | * A class marked as having requirements can return the list of services it requires 14 | * to be available before it can be registered. 15 | * 16 | * @since 2.2 17 | * @internal 18 | */ 19 | interface HasRequirements { 20 | 21 | /** 22 | * Get the list of service IDs required for this service to be registered. 23 | * 24 | * @return string[] List of required services. 25 | */ 26 | public static function get_requirements(); 27 | } 28 | -------------------------------------------------------------------------------- /src/Infrastructure/Injector/FallbackInstantiator.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Final class FallbackInstantiator. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Infrastructure\Injector; 9 | 10 | use AmpProject\AmpWP\Infrastructure\Instantiator; 11 | 12 | /** 13 | * Fallback instantiator to use in case none was provided. 14 | * 15 | * @since 2.0 16 | * @internal 17 | */ 18 | final class FallbackInstantiator implements Instantiator { 19 | 20 | /** 21 | * Make an object instance out of an interface or class. 22 | * 23 | * @param string $class Class to make an object instance out of. 24 | * @param array $dependencies Optional. Dependencies of the class. 25 | * @return object Instantiated object. 26 | */ 27 | public function instantiate( $class, $dependencies = [] ) { 28 | return new $class( ...$dependencies ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Infrastructure/Instantiator.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Interface Instantiator. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Infrastructure; 9 | 10 | /** 11 | * Interface to make the act of instantiation extensible/replaceable. 12 | * 13 | * This way, a more elaborate mechanism can be plugged in, like using 14 | * ProxyManager to instantiate proxies instead of actual objects. 15 | * 16 | * @since 2.0 17 | * @internal 18 | */ 19 | interface Instantiator { 20 | 21 | /** 22 | * Make an object instance out of an interface or class. 23 | * 24 | * @param string $class Class to make an object instance out of. 25 | * @param array $dependencies Optional. Dependencies of the class. 26 | * @return object Instantiated object. 27 | */ 28 | public function instantiate( $class, $dependencies = [] ); 29 | } 30 | -------------------------------------------------------------------------------- /src/Infrastructure/Registerable.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Interface Registerable. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Infrastructure; 9 | 10 | /** 11 | * Something that can be registered. 12 | * 13 | * For a clean code base, a class instantiation should never have side-effects, 14 | * only initialize the internals of the object so that it is ready to be used. 15 | * 16 | * This means, though, that the system does not have any knowledge of the 17 | * objects when they are merely instantiated. 18 | * 19 | * Registering such an object is the explicit act of making it known to the 20 | * overarching system. 21 | * 22 | * @since 2.0 23 | * @internal 24 | */ 25 | interface Registerable { 26 | 27 | /** 28 | * Register the service. 29 | * 30 | * @return void 31 | */ 32 | public function register(); 33 | } 34 | -------------------------------------------------------------------------------- /src/Infrastructure/Service.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Interface Service. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Infrastructure; 9 | 10 | /** 11 | * A conceptual service. 12 | * 13 | * Splitting the logic up into independent services makes the approach of 14 | * assembling a plugin more systematic and scalable and lowers the cognitive 15 | * load when the code base increases in size. 16 | * 17 | * @since 2.0 18 | * @internal 19 | */ 20 | interface Service { 21 | 22 | } 23 | -------------------------------------------------------------------------------- /templates/footer.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Footer template part. 4 | * 5 | * 🚫🚫🚫 6 | * DO NOT EDIT THIS FILE WHILE INSIDE THE PLUGIN! Changes You make will be lost when a new version 7 | * of the AMP plugin is released. You need to copy this file out of the plugin and put it into your 8 | * custom theme, for example. To learn about how to customize these Reader-mode AMP templates, please 9 | * see: https://amp-wp.org/documentation/how-the-plugin-works/classic-templates/ 10 | * 🚫🚫🚫 11 | * 12 | * @package AMP 13 | */ 14 | 15 | /** 16 | * Context. 17 | * 18 | * @var AMP_Post_Template $this 19 | */ 20 | ?> 21 | <footer class="amp-wp-footer"> 22 | <div> 23 | <h2><?php echo esc_html( wptexturize( $this->get( 'blog_name' ) ) ); ?></h2> 24 | <a href="#top" class="back-to-top"><?php esc_html_e( 'Back to top', 'amp' ); ?></a> 25 | </div> 26 | </footer> 27 | -------------------------------------------------------------------------------- /templates/header.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Header template part. 4 | * 5 | * 🚫🚫🚫 6 | * DO NOT EDIT THIS FILE WHILE INSIDE THE PLUGIN! Changes You make will be lost when a new version 7 | * of the AMP plugin is released. You need to copy this file out of the plugin and put it into your 8 | * custom theme, for example. To learn about how to customize these Reader-mode AMP templates, please 9 | * see: https://amp-wp.org/documentation/how-the-plugin-works/classic-templates/ 10 | * 🚫🚫🚫 11 | * 12 | * @package AMP 13 | */ 14 | 15 | /** 16 | * Context. 17 | * 18 | * @var AMP_Post_Template $this 19 | */ 20 | 21 | $this->load_parts( [ 'header-bar' ] ); 22 | -------------------------------------------------------------------------------- /templates/html-end.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * HTML end template part. 4 | * 5 | * 🚫🚫🚫 6 | * DO NOT EDIT THIS FILE WHILE INSIDE THE PLUGIN! Changes You make will be lost when a new version 7 | * of the AMP plugin is released. You need to copy this file out of the plugin and put it into your 8 | * custom theme, for example. To learn about how to customize these Reader-mode AMP templates, please 9 | * see: https://amp-wp.org/documentation/how-the-plugin-works/classic-templates/ 10 | * 🚫🚫🚫 11 | * 12 | * @package AMP 13 | */ 14 | 15 | /** 16 | * Context. 17 | * 18 | * @var AMP_Post_Template $this 19 | */ 20 | ?> 21 | 22 | <?php 23 | /** 24 | * Fires just before printing the </body> closing tag. 25 | * 26 | * @since 0.2 27 | * @see wp_footer() 28 | * 29 | * @param AMP_Post_Template $this 30 | */ 31 | do_action( 'amp_post_template_footer', $this ); 32 | ?> 33 | 34 | </body> 35 | </html> 36 | -------------------------------------------------------------------------------- /tests/e2e/assets/large-image-36521.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/tests/e2e/assets/large-image-36521.jpg -------------------------------------------------------------------------------- /tests/e2e/assets/small-image-100-100.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/tests/e2e/assets/small-image-100-100.jpg -------------------------------------------------------------------------------- /tests/e2e/jest-ci.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('./jest.config'), 3 | reporters: [ 4 | ['jest-silent-reporter', { useDots: true, showPaths: true }], 5 | '<rootDir>/../../node_modules/@wordpress/scripts/config/jest-github-actions-reporter', 6 | ], 7 | }; 8 | -------------------------------------------------------------------------------- /tests/e2e/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('@wordpress/scripts/config/jest-e2e.config'), 3 | transform: { 4 | '^.+\\.[jt]sx?$': 5 | '<rootDir>/../../node_modules/@wordpress/scripts/config/babel-transform', 6 | }, 7 | transformIgnorePatterns: ['node_modules'], 8 | setupFilesAfterEnv: [ 9 | '<rootDir>/config/bootstrap.js', 10 | '@wordpress/jest-puppeteer-axe', 11 | 'expect-puppeteer', 12 | ], 13 | testPathIgnorePatterns: ['.git', 'node_modules'], 14 | }; 15 | -------------------------------------------------------------------------------- /tests/e2e/plugins/do-not-allow-amp-validate-capability.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Plugin Name: Do Not Allow AMP Validate Capability 4 | * Plugin URI: https://github.com/ampproject/amp-wp 5 | * Description: Demo plugin for revoking AMP Validate capability that can be installed during E2E tests. 6 | * Author: AMP Project Contributors 7 | * Author URI: https://github.com/ampproject/amp-wp/graphs/contributors 8 | */ 9 | 10 | add_filter( 11 | 'map_meta_cap', 12 | function ( $caps, $cap ) { 13 | if ( AMP_Validation_Manager::VALIDATE_CAPABILITY === $cap ) { 14 | $caps[] = 'do_not_allow'; 15 | } 16 | return $caps; 17 | }, 18 | 10, 19 | 3 20 | ); 21 | -------------------------------------------------------------------------------- /tests/e2e/plugins/do-not-allow-amp-validate-capability.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/tests/e2e/plugins/do-not-allow-amp-validate-capability.zip -------------------------------------------------------------------------------- /tests/e2e/plugins/e2e-tests-demo-plugin.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Plugin Name: E2E Tests Demo Plugin 4 | * Plugin URI: https://github.com/ampproject/amp-wp 5 | * Description: Demo Plugin that can be installed during E2E tests. 6 | * Author: AMP Project Contributors 7 | * Author URI: https://github.com/ampproject/amp-wp/graphs/contributors 8 | */ 9 | 10 | add_action( 11 | 'wp_footer', 12 | function () { 13 | ?> 14 | <bad-tag></bad-tag> 15 | <?php 16 | } 17 | ); 18 | 19 | add_shortcode( 20 | 'bad-tag-shortcode', 21 | function () { 22 | return '<bad-tag-shortcode></bad-tag-shortcode>'; 23 | } 24 | ); 25 | -------------------------------------------------------------------------------- /tests/e2e/plugins/e2e-tests-demo-plugin.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/tests/e2e/plugins/e2e-tests-demo-plugin.zip -------------------------------------------------------------------------------- /tests/e2e/puppeteer.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | const { executablePath } = require('puppeteer'); 5 | 6 | /** 7 | * WordPress dependencies 8 | */ 9 | const defaultPuppeteerConfig = require('@wordpress/scripts/config/puppeteer.config.js'); 10 | 11 | // eslint-disable-next-line no-console, jest/require-hook 12 | console.log( 13 | `${ 14 | process.env.CI ? '::notice::' : '' 15 | }Using Chromium from ${executablePath()}` 16 | ); 17 | 18 | module.exports = { 19 | launch: { 20 | ...defaultPuppeteerConfig.launch, 21 | executablePath: executablePath(), 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /tests/e2e/specs/amp-onboarding/welcome.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | import { visitAdminPage } from '@wordpress/e2e-test-utils'; 5 | 6 | /** 7 | * Internal dependencies 8 | */ 9 | import { 10 | testPreviousButton, 11 | testNextButton, 12 | } from '../../utils/onboarding-wizard-utils'; 13 | 14 | describe('welcome', () => { 15 | beforeEach(async () => { 16 | await visitAdminPage('admin.php', 'page=amp-onboarding-wizard'); 17 | await page.waitForSelector('.amp-settings-nav__prev-next'); 18 | }); 19 | 20 | it('should contain content', async () => { 21 | await expect(page).toMatchElement('.welcome'); 22 | 23 | await testPreviousButton({ exists: false }); 24 | await testNextButton({ text: 'Next' }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /tests/e2e/utils/click-button.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Clicks a button based on the text on the button. 3 | * 4 | * This is almost a copy of the upstream util, however, it uses page.evaluate for clicking since it seems to work more reliably. 5 | * 6 | * @param {string} buttonText The text that appears on the button to click. 7 | */ 8 | export async function clickButton(buttonText) { 9 | const button = await page.waitForXPath( 10 | `//button[contains(text(), '${buttonText}')]` 11 | ); 12 | await page.evaluate((btn) => { 13 | btn.click(); 14 | }, button); 15 | } 16 | -------------------------------------------------------------------------------- /tests/e2e/utils/index.js: -------------------------------------------------------------------------------- 1 | export { clickButton } from './click-button'; 2 | export { uploadMedia } from './upload-media'; 3 | -------------------------------------------------------------------------------- /tests/e2e/utils/nav-menu-utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WordPress dependencies 3 | */ 4 | import { createMenu, deleteAllMenus } from '@wordpress/e2e-test-utils'; 5 | 6 | export async function createTestMenu(menuLocation = 'top') { 7 | await deleteAllMenus(); 8 | await createMenu( 9 | { 10 | name: 'Test Menu 1', 11 | locations: [menuLocation], 12 | }, 13 | [ 14 | { 15 | title: 'WordPress.org', 16 | url: 'https://wordpress.org', 17 | menu_order: 1, 18 | }, 19 | { 20 | title: 'Wikipedia.org', 21 | url: 'https://wikipedia.org', 22 | menu_order: 2, 23 | }, 24 | { 25 | title: 'Google', 26 | url: 'https://google.com', 27 | menu_order: 3, 28 | parent: 1, 29 | }, 30 | ] 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /tests/features/optimize-command.feature: -------------------------------------------------------------------------------- 1 | Feature: Run the optimizer via the command line 2 | 3 | Background: 4 | Given a WP installation with the AMP plugin 5 | 6 | Scenario: Optimize an input file 7 | Given an input.html file: 8 | """ 9 | <amp-img src="https://example.com/image.jpg" width="500" height="500"></amp-img> 10 | """ 11 | 12 | When I run the WP-CLI command `amp optimizer optimize input.html` 13 | Then STDERR should be empty 14 | And STDOUT should contain: 15 | """ 16 | transformed="self;v=1" 17 | """ 18 | -------------------------------------------------------------------------------- /tests/js/setup-globals.js: -------------------------------------------------------------------------------- 1 | /** 2 | * External dependencies 3 | */ 4 | import { TextDecoder } from 'util'; 5 | import { jest } from '@jest/globals'; 6 | 7 | // Set up `wp.*` aliases. 8 | global.wp = { 9 | media: { 10 | controller: { 11 | Library: jest.fn(), 12 | Cropper: { 13 | extend: jest.fn(), 14 | }, 15 | }, 16 | View: { 17 | extend: jest.fn(), 18 | }, 19 | view: { 20 | Toolbar: { 21 | Select: { 22 | extend: jest.fn(), 23 | }, 24 | }, 25 | MediaFrame: { 26 | Select: { 27 | extend: jest.fn(), 28 | }, 29 | }, 30 | }, 31 | }, 32 | }; 33 | 34 | global.ajaxurl = 'http://site.test/wp-admin/ajax.php'; 35 | 36 | global.CSS = {}; 37 | 38 | global.TextDecoder = TextDecoder; 39 | -------------------------------------------------------------------------------- /tests/php/data/images/1024x768.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/tests/php/data/images/1024x768.png -------------------------------------------------------------------------------- /tests/php/data/images/350x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/tests/php/data/images/350x150.png -------------------------------------------------------------------------------- /tests/php/data/images/wordpress-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ampproject/amp-wp/9fd8131a4393628bf7bab05e2451702693629d4c/tests/php/data/images/wordpress-logo.png -------------------------------------------------------------------------------- /tests/php/data/plugins/bad-hooks.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Plugin Name: Bad Hooks 4 | * Description: Action and filter which add bad markup. 5 | * Version: 0.3 6 | */ 7 | 8 | add_action( 9 | 'wp_footer', 10 | function () { 11 | echo '<script>document.write("Bad action!!!");</script><noscript>Bad action!</noscript>'; 12 | } 13 | ); 14 | 15 | add_filter( 16 | 'the_content', 17 | function ( $content ) { 18 | return $content . '<script>document.write("Bad filter!!!");</script><noscript>Bad filter!</noscript>'; 19 | } 20 | ); 21 | -------------------------------------------------------------------------------- /tests/php/data/plugins/bad-shortcode.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Plugin Name: Bad Shortcode 4 | * Description: Shortcode which outputs a script. 5 | * Version: 0.4 6 | */ 7 | 8 | add_action( 9 | 'wp_enqueue_scripts', 10 | function () { 11 | wp_register_script( 'bad-shortcode', home_url( '/bad-shortcode.js' ), [ 'jquery' ], '1', true ); 12 | } 13 | ); 14 | 15 | add_shortcode( 16 | 'bad', 17 | function () { 18 | wp_enqueue_script( 'bad-shortcode' ); 19 | return '<script>document.write("Bad shortcode!!!");</script><noscript>Bad shortcode fallback!</noscript>'; 20 | } 21 | ); 22 | -------------------------------------------------------------------------------- /tests/php/data/plugins/bad-widget/class-bad-widget.php: -------------------------------------------------------------------------------- 1 | <?php 2 | // phpcs:ignoreFile 3 | 4 | class Bad_Widget extends WP_Widget { 5 | 6 | /** 7 | * Sets up the widgets name etc 8 | */ 9 | public function __construct() { 10 | parent::__construct( 'bad', 'Bad Widget' ); 11 | } 12 | 13 | /** 14 | * Outputs the content of the widget 15 | * 16 | * @param array $args Args. 17 | * @param array $instance Instance. 18 | */ 19 | public function widget( $args, $instance ) { 20 | unset( $instance ); 21 | echo $args['before_widget']; 22 | echo $args['before_title'] . 'Bad Multi Widget' . $args['after_title']; 23 | 24 | echo '<script>document.write("Bad widget!!!");</script><noscript>Bad widget fallback!</noscript>'; 25 | echo $args['after_widget']; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/php/data/themes/child-of-core/actions.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | if ( ! function_exists( 'child_of_core_after_setup_theme' ) ) { 4 | 5 | function child_of_core_after_setup_theme() { 6 | add_theme_support( 'amp' ); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/php/data/themes/child-of-core/functions.php: -------------------------------------------------------------------------------- 1 | <?php 2 | require_once __DIR__ . '/actions.php'; 3 | -------------------------------------------------------------------------------- /tests/php/data/themes/child-of-core/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | Theme Name: Child o' Twenty Seventeen 3 | Template: twentyseventeen 4 | AMP: true 5 | */ 6 | -------------------------------------------------------------------------------- /tests/php/data/themes/custom/functions.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | if ( ! function_exists( 'my_custom_after_setup_theme' ) ) { 4 | 5 | function my_custom_after_setup_theme() { 6 | add_theme_support( 'amp' ); 7 | } 8 | } 9 | 10 | add_action( 11 | 'trigger_action_to_execute', 12 | static function () { 13 | do_action( 'execute_from_within_theme' ); 14 | } 15 | ); 16 | -------------------------------------------------------------------------------- /tests/php/data/themes/custom/index.php: -------------------------------------------------------------------------------- 1 | <?php 2 | the_post(); 3 | -------------------------------------------------------------------------------- /tests/php/data/themes/custom/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | Theme Name: Custom 3 | */ 4 | -------------------------------------------------------------------------------- /tests/php/data/themes/with-legacy/amp/meta-author.php: -------------------------------------------------------------------------------- 1 | <?php 2 | echo 'Nobody!'; 3 | -------------------------------------------------------------------------------- /tests/php/data/themes/with-legacy/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | Theme Name: With Legacy Templates 3 | AMP: legacy 4 | */ 5 | -------------------------------------------------------------------------------- /tests/php/register-wp-cli-commands.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | use AmpProject\AmpWP\Tests\Cli\ReferenceSiteCommandNamespace; 4 | use AmpProject\AmpWP\Tests\Cli\ReferenceSiteExportCommand; 5 | use AmpProject\AmpWP\Tests\Cli\ReferenceSiteImportCommand; 6 | 7 | if ( ! defined( 'WP_CLI' ) || ! class_exists( 'WP_CLI' ) ) { 8 | return; 9 | } 10 | 11 | WP_CLI::add_command( 'amp reference-site', ReferenceSiteCommandNamespace::class ); 12 | WP_CLI::add_command( 'amp reference-site import', ReferenceSiteImportCommand::class ); 13 | WP_CLI::add_command( 'amp reference-site export', ReferenceSiteExportCommand::class ); 14 | -------------------------------------------------------------------------------- /tests/php/src/Cli/ExportStep.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * ExportStep interface. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Tests\Cli; 9 | 10 | use AmpProject\AmpWP\Tests\Cli\Export\ExportResult; 11 | 12 | interface ExportStep { 13 | 14 | /** 15 | * Process the export step. 16 | * 17 | * @param ExportResult $export_result Export result to adapt. 18 | * 19 | * @return ExportResult Adapted export result. 20 | */ 21 | public function process( ExportResult $export_result ); 22 | } 23 | -------------------------------------------------------------------------------- /tests/php/src/Cli/ImportStep.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * ImportStep interface. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Tests\Cli; 9 | 10 | interface ImportStep { 11 | 12 | /** 13 | * Process the import step. 14 | * 15 | * @return int Number of items that were successfully processed. 16 | * Returns -1 for failure. 17 | */ 18 | public function process(); 19 | } 20 | -------------------------------------------------------------------------------- /tests/php/src/Cli/ReferenceSiteCommandNamespace.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Abstract seed base class. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Tests\Cli; 9 | 10 | use WP_CLI\Dispatcher\CommandNamespace; 11 | 12 | /** 13 | * Manage the AMP reference site used for testing and measuring the impact of the AMP plugin. 14 | * 15 | * @package AmpProject\AmpWP\Tests\Cli 16 | */ 17 | final class ReferenceSiteCommandNamespace extends CommandNamespace { 18 | 19 | /** 20 | * Root folder to use for the reference site definition files. 21 | * 22 | * @var string 23 | */ 24 | const REFERENCE_SITES_ROOT = AMP__DIR__ . '/tests/reference-sites/'; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /tests/php/src/Fixture/DummyClass.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace AmpProject\AmpWP\Tests\Fixture; 4 | 5 | final class DummyClass { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /tests/php/src/Fixture/DummyClassWithDependency.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace AmpProject\AmpWP\Tests\Fixture; 4 | 5 | final class DummyClassWithDependency implements DummyInterface { 6 | 7 | /** @var DummyClass */ 8 | private $dummy; 9 | 10 | public function __construct( DummyClass $dummy ) { 11 | $this->dummy = $dummy; 12 | } 13 | 14 | public function get_dummy() { 15 | return $this->dummy; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/php/src/Fixture/DummyClassWithNamedArguments.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace AmpProject\AmpWP\Tests\Fixture; 4 | 5 | final class DummyClassWithNamedArguments { 6 | 7 | /** @var int */ 8 | private $argument_a; 9 | 10 | /** @var string */ 11 | private $argument_b; 12 | 13 | public function __construct( $argument_a, $argument_b = 'Mr Meeseeks' ) { 14 | $this->argument_a = $argument_a; 15 | $this->argument_b = $argument_b; 16 | } 17 | 18 | public function get_argument_a() { 19 | return $this->argument_a; 20 | } 21 | 22 | public function get_argument_b() { 23 | return $this->argument_b; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/php/src/Fixture/DummyInterface.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace AmpProject\AmpWP\Tests\Fixture; 4 | 5 | interface DummyInterface { 6 | 7 | public function get_dummy(); 8 | } 9 | -------------------------------------------------------------------------------- /tests/php/src/Fixture/DummyService.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace AmpProject\AmpWP\Tests\Fixture; 4 | 5 | use AmpProject\AmpWP\Infrastructure\Service; 6 | 7 | final class DummyService implements Service { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /tests/php/src/Fixture/DummyServiceBasedPlugin.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace AmpProject\AmpWP\Tests\Fixture; 4 | 5 | use AmpProject\AmpWP\Infrastructure\ServiceBasedPlugin; 6 | 7 | class DummyServiceBasedPlugin extends ServiceBasedPlugin { 8 | 9 | /** 10 | * Get the list of services to register. 11 | * 12 | * @return array<string> Associative array of identifiers mapped to fully 13 | * qualified class names. 14 | */ 15 | protected function get_service_classes() { 16 | return [ 17 | 'service_a' => DummyService::class, 18 | 'service_b' => DummyService::class, 19 | ]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/php/src/Fixture/DummyServiceWithDelay.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace AmpProject\AmpWP\Tests\Fixture; 4 | 5 | use AmpProject\AmpWP\Infrastructure\Delayed; 6 | use AmpProject\AmpWP\Infrastructure\Service; 7 | 8 | class DummyServiceWithDelay implements Service, Delayed { 9 | 10 | /** 11 | * Get the action to use for registering the service. 12 | * 13 | * @return string Registration action to use. 14 | */ 15 | public static function get_registration_action() { 16 | return 'some_action'; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/php/src/Fixture/DummyServiceWithRequirements.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace AmpProject\AmpWP\Tests\Fixture; 4 | 5 | use AmpProject\AmpWP\Infrastructure\HasRequirements; 6 | use AmpProject\AmpWP\Infrastructure\Service; 7 | 8 | class DummyServiceWithRequirements implements Service, HasRequirements { 9 | 10 | /** 11 | * Get the list of service IDs required for this service to be registered. 12 | * 13 | * @return array<string> List of required services. 14 | */ 15 | public static function get_requirements() { 16 | return [ 'service_a' ]; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/php/src/Helpers/HandleValidation.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * File containing helper trait for validation. 4 | * 5 | * @package AMP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Tests\Helpers; 9 | 10 | /** 11 | * Helper trait for validation 12 | */ 13 | trait HandleValidation { 14 | 15 | /** 16 | * Whether or not to enable acceptance of sanitization by default. 17 | * 18 | * @param bool $value Value to return when AMP_Validation_Manager::is_sanitization_auto_accepted() is called. 19 | * @return void 20 | */ 21 | private function accept_sanitization_by_default( $value ) { 22 | remove_all_filters( 'amp_validation_error_default_sanitized' ); 23 | 24 | add_filter( 25 | 'amp_validation_error_default_sanitized', 26 | static function () use ( $value ) { 27 | return $value; 28 | } 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/php/src/Helpers/MockAdminUser.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Trait MockAdminUser. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | namespace AmpProject\AmpWP\Tests\Helpers; 9 | 10 | /** 11 | * Helper trait for mocking an user: 12 | * - Admin user in single site. 13 | * - Super admin user in multisite. 14 | * 15 | * @package AmpProject\AmpWP 16 | */ 17 | trait MockAdminUser { 18 | 19 | /** 20 | * Mock an admin or super admin user. 21 | * 22 | * @return WP_User 23 | */ 24 | public function mock_admin_user() { 25 | $admin_user = self::factory()->user->create_and_get( [ 'role' => 'administrator' ] ); 26 | 27 | if ( is_multisite() ) { 28 | grant_super_admin( $admin_user->ID ); 29 | } 30 | 31 | wp_set_current_user( $admin_user->ID ); 32 | 33 | return $admin_user; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/php/src/Helpers/StubSanitizer.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace AmpProject\AmpWP\Tests\Helpers; 4 | 5 | use AMP_Base_Sanitizer; 6 | 7 | /** 8 | * Class StubSanitizer. 9 | * 10 | * Stub class for AMP_Base_Sanitizer, since it is an abstract class. 11 | */ 12 | class StubSanitizer extends AMP_Base_Sanitizer { 13 | 14 | public function sanitize() { 15 | return $this->dom; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/php/src/Instrumentation/StopWatchEventTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace AmpProject\AmpWP\Tests\Instrumentation; 4 | 5 | use AmpProject\AmpWP\Instrumentation\StopWatchEvent; 6 | use Yoast\PHPUnitPolyfills\TestCases\TestCase; 7 | 8 | final class StopWatchEventTest extends TestCase { 9 | 10 | public function test_it_can_measure_time() { 11 | $stop_watch_event = new StopWatchEvent(); 12 | $this->assertEquals( 0.0, $stop_watch_event->get_duration() ); 13 | usleep( 100 * 1000 ); // 100ms 14 | $stop_watch_event->stop(); 15 | $this->assertGreaterThan( 0.1, $stop_watch_event->get_duration() ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/php/src/PairedUrlStructureTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace AmpProject\AmpWP\Tests; 4 | 5 | use AmpProject\AmpWP\PairedUrlStructure; 6 | use AmpProject\AmpWP\Tests\Fixture\DummyPairedUrlStructure; 7 | 8 | /** @coversDefaultClass \AmpProject\AmpWP\PairedUrlStructure */ 9 | class PairedUrlStructureTest extends DependencyInjectedTestCase { 10 | 11 | /** @var PairedUrlStructure */ 12 | private $instance; 13 | 14 | public function set_up() { 15 | parent::set_up(); 16 | $this->instance = $this->injector->make( DummyPairedUrlStructure::class ); 17 | } 18 | 19 | /** @covers ::has_endpoint() */ 20 | public function test_has_endpoint() { 21 | $removed = home_url( '/' ); 22 | $added = $this->instance->add_endpoint( $removed ); 23 | 24 | $this->assertFalse( $this->instance->has_endpoint( $removed ) ); 25 | $this->assertTrue( $this->instance->has_endpoint( $added ) ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/php/static-analysis-stubs/gutenberg.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | /** 4 | * Checks whether we're currently loading a Gutenberg page 5 | * 6 | * @return boolean Whether Gutenberg is being loaded. 7 | * 8 | * @since 3.1.0 9 | */ 10 | function is_gutenberg_page() {} 11 | -------------------------------------------------------------------------------- /tests/php/static-analysis-stubs/legacy-i18n.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Returns Jed-formatted localization data. Added for backwards-compatibility. 4 | * 5 | * @param string $domain Translation domain. 6 | * 7 | * @return array 8 | */ 9 | function gutenberg_get_jed_locale_data( $domain ) {} 10 | 11 | /** 12 | * Returns Jed-formatted localization data. Added for backwards-compatibility. 13 | * 14 | * @param string $domain Translation domain. 15 | * 16 | * @return array 17 | */ 18 | function wp_get_jed_locale_data( $domain ) {} 19 | -------------------------------------------------------------------------------- /tests/php/static-analysis-stubs/twentyseventeen.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | /** 4 | * Return SVG markup. 5 | * 6 | * @param array $args { 7 | * Parameters needed to display an SVG. 8 | * 9 | * @type string $icon Required SVG icon filename. 10 | * @type string $title Optional SVG title. 11 | * @type string $desc Optional SVG description. 12 | * } 13 | * @return string SVG markup. 14 | */ 15 | function twentyseventeen_get_svg( $args = array() ) {} 16 | -------------------------------------------------------------------------------- /tests/php/test-class-amp-auto-lightbox-disable-sanitizer.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Class AMP_Auto_Lightbox_Disable_Sanitizer_Test. 4 | * 5 | * @package AmpProject\AmpWP 6 | */ 7 | 8 | use AmpProject\AmpWP\Tests\TestCase; 9 | 10 | /** 11 | * Tests the auto lightbox disable sanitizer class. 12 | * 13 | * @coversDefaultClass AMP_Auto_Lightbox_Disable_Sanitizer 14 | */ 15 | class AMP_Auto_Lightbox_Disable_Sanitizer_Test extends TestCase { 16 | 17 | /** 18 | * @covers ::sanitize() 19 | */ 20 | public function test_sanitize() { 21 | 22 | $source = '<html><body class="body-class"><span>Hello World!</span></body></html>'; 23 | $dom = AMP_DOM_Utils::get_dom_from_content( $source ); 24 | 25 | $sanitizer = new AMP_Auto_Lightbox_Disable_Sanitizer( $dom ); 26 | $sanitizer->sanitize(); 27 | 28 | $this->assertTrue( $dom->html->hasAttribute( 'data-amp-auto-lightbox-disable' ) ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/reference-sites/theme-unit-test.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Theme Unit Test", 3 | "version": "1.0", 4 | "description": "Theme unit test data from the theme review team.", 5 | "attributions": [ 6 | "Site content created by the Wordpress.org theme review team.\nSee https://github.com/WPTT/theme-unit-test" 7 | ], 8 | "import-steps": [ 9 | { 10 | "type": "import_wxr_file", 11 | "filename": "https://raw.githubusercontent.com/WPTT/theme-unit-test/master/themeunittestdata.wordpress.xml" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /uninstall.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Plugin uninstall file. 4 | * 5 | * @package AMP 6 | */ 7 | 8 | namespace AmpProject\AmpWP; 9 | 10 | // If uninstall.php is not called by WordPress, then die. 11 | if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) { 12 | die; 13 | } 14 | 15 | require_once dirname( __FILE__ ) . '/includes/uninstall-functions.php'; 16 | 17 | if ( is_multisite() && ! wp_is_large_network() ) { 18 | $site_ids = get_sites( 19 | [ 20 | 'fields' => 'ids', 21 | 'number' => '', 22 | 'update_site_cache' => false, 23 | 'update_site_meta_cache' => false, 24 | ] 25 | ); 26 | $site_ids = ( ! empty( $site_ids ) && is_array( $site_ids ) ) ? $site_ids : []; 27 | 28 | foreach ( $site_ids as $site_id ) { 29 | switch_to_blog( $site_id ); 30 | remove_plugin_data(); 31 | } 32 | restore_current_blog(); 33 | } else { 34 | remove_plugin_data(); 35 | } 36 | --------------------------------------------------------------------------------