Skip to content

Add option to keep AMP data upon uninstalling of plugin #6632

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion amp.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
/**
* Plugin Name: AMP
* Description: An easier path to great Page Experience for everyone. Powered by AMP.
* Description: An easier path to great Page Experience for everyone. Powered by AMP. <em class="amp-deletion-notice"><strong>Uninstall Note:</strong> To control whether all data from this plugin is deleted at uninstallation, first activate the plugin, go to the Other section on the Settings screen, and set the “Delete plugin data at uninstall” toggle.</em>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if the install note should be on a separate line for better visibility 🤔

Suggested change
* Description: An easier path to great Page Experience for everyone. Powered by AMP. <em class="amp-deletion-notice"><strong>Uninstall Note:</strong> To control whether all data from this plugin is deleted at uninstallation, first activate the plugin, go to the Other section on the Settings screen, and set the “Delete plugin data at uninstall” toggle.</em>
* Description: An easier path to great Page Experience for everyone. Powered by AMP. <br><em class="amp-deletion-notice"><strong>Uninstall Note:</strong> To control whether all data from this plugin is deleted at uninstallation, first activate the plugin, go to the Other section on the Settings screen, and set the “Delete plugin data at uninstall” toggle.</em>
Before After
image image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, yes. Unfortunately, the br tag is not allowed. Only abbr, acronym, code, em, strong, and a are allowed: https://github.com/WordPress/wordpress-develop/blob/ed9f437fc098ba2c9ba18eda0fa341ecd0476ca9/src/wp-admin/includes/plugin.php#L173-L186

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see, unfortunate indeed.

* Plugin URI: https://amp-wp.org
* Author: AMP Project Contributors
* Author URI: https://github.com/ampproject/amp-wp/graphs/contributors
Expand Down
39 changes: 39 additions & 0 deletions assets/src/settings-page/delete-data-at-uninstall.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* WordPress dependencies
*/
import { useContext } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { AMPSettingToggle } from '../components/amp-setting-toggle';
import { Options } from '../components/options-context-provider';
import { Loading } from '../components/loading';

/**
* Data deletion at uninstallation toggle on the settings page.
*/
export function DeleteDataAtUninstall() {
const { editedOptions, fetchingOptions, updateOptions } = useContext( Options );

if ( fetchingOptions ) {
return <Loading />;
}

const deleteDataAtUninstall = editedOptions?.delete_data_at_uninstall;
return (
<section className="delete-data-at-uninstall">
<AMPSettingToggle
checked={ true === deleteDataAtUninstall }
title={ __( 'Delete plugin data at uninstall', 'amp' ) }
onChange={ () => {
updateOptions( { delete_data_at_uninstall: ! deleteDataAtUninstall } );
} }
/>
<p>
{ __( 'When you uninstall the plugin you have the choice of whether its data should also be deleted. Examples of plugin data include the settings, validated URLs, and transients used to store image dimensions and parsed stylesheets.', 'amp' ) }
</p>
</section>
);
}
2 changes: 2 additions & 0 deletions assets/src/settings-page/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { Analytics } from './analytics';
import { PairedUrlStructure } from './paired-url-structure';
import { MobileRedirection } from './mobile-redirection';
import { DeveloperTools } from './developer-tools';
import { DeleteDataAtUninstall } from './delete-data-at-uninstall';

const { ajaxurl: wpAjaxUrl } = global;

Expand Down Expand Up @@ -250,6 +251,7 @@ function Root( { appRoot } ) {
>
<MobileRedirection />
<DeveloperTools />
<DeleteDataAtUninstall />
</AMPDrawer>
<SettingsFooter />
</form>
Expand Down
6 changes: 1 addition & 5 deletions assets/src/settings-page/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -610,10 +610,6 @@ li.error-kept {
margin: 0;
}

.amp-other-settings .developer-tools h4 {
margin-bottom: 0;
}

.amp-other-settings .developer-tools p {
.amp-other-settings p {
font-size: 0.875rem;
}
25 changes: 25 additions & 0 deletions includes/amp-helper-functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ function amp_bootstrap_plugin() {
add_action( 'after_setup_theme', 'amp_after_setup_theme', 5 );

add_action( 'plugins_loaded', '_amp_bootstrap_customizer', 9 ); // Should be hooked before priority 10 on 'plugins_loaded' to properly unhook core panels.

// @todo Eliminate this once https://core.trac.wordpress.org/ticket/20578 has finally landed.
add_filter( 'all_plugins', 'amp_modify_plugin_description' );
}

/**
Expand Down Expand Up @@ -219,6 +222,28 @@ function() {
);
}

/**
* When AMP plugin is active remove instruction of plugin data removal steps.
*
* @since 2.2
* @internal
*
* @param array $meta An array of plugins to display in the list table.
* @return array An array of plugins to display in the list table.
*/
function amp_modify_plugin_description( $meta ) {

if ( isset( $meta['amp/amp.php']['Description'] ) ) {
$meta['amp/amp.php']['Description'] = preg_replace(
':\s*<em class=\"amp-deletion-notice\">.+?</em>:',
'',
$meta['amp/amp.php']['Description']
);
}

return $meta;
}

/**
* Set up AMP.
*
Expand Down
23 changes: 14 additions & 9 deletions includes/options/class-amp-options-manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,16 @@ class AMP_Options_Manager {
* @var array
*/
protected static $defaults = [
Option::THEME_SUPPORT => AMP_Theme_Support::READER_MODE_SLUG,
Option::SUPPORTED_POST_TYPES => [ 'post', 'page' ],
Option::ANALYTICS => [],
Option::ALL_TEMPLATES_SUPPORTED => true,
Option::SUPPORTED_TEMPLATES => [ 'is_singular' ],
Option::VERSION => AMP__VERSION,
Option::READER_THEME => ReaderThemes::DEFAULT_READER_THEME,
Option::PAIRED_URL_STRUCTURE => Option::PAIRED_URL_STRUCTURE_QUERY_VAR,
Option::PLUGIN_CONFIGURED => false,
Option::THEME_SUPPORT => AMP_Theme_Support::READER_MODE_SLUG,
Option::SUPPORTED_POST_TYPES => [ 'post', 'page' ],
Option::ANALYTICS => [],
Option::ALL_TEMPLATES_SUPPORTED => true,
Option::SUPPORTED_TEMPLATES => [ 'is_singular' ],
Option::VERSION => AMP__VERSION,
Option::READER_THEME => ReaderThemes::DEFAULT_READER_THEME,
Option::PAIRED_URL_STRUCTURE => Option::PAIRED_URL_STRUCTURE_QUERY_VAR,
Option::PLUGIN_CONFIGURED => false,
Option::DELETE_DATA_AT_UNINSTALL => true,
];

/**
Expand Down Expand Up @@ -320,6 +321,10 @@ public static function validate_options( $new_options ) {
$options[ Option::PLUGIN_CONFIGURED ] = (bool) $new_options[ OPTION::PLUGIN_CONFIGURED ];
}

if ( isset( $new_options[ Option::DELETE_DATA_AT_UNINSTALL ] ) ) {
$options[ Option::DELETE_DATA_AT_UNINSTALL ] = (bool) $new_options[ OPTION::DELETE_DATA_AT_UNINSTALL ];
}

// Validate analytics.
if ( isset( $new_options[ Option::ANALYTICS ] ) && $new_options[ Option::ANALYTICS ] !== $options[ Option::ANALYTICS ] ) {
$new_analytics_option = [];
Expand Down
19 changes: 13 additions & 6 deletions includes/uninstall-functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ function delete_transients() {

// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Cannot cache result since we're deleting the records.
$wpdb->query(
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- See use of prepare in foreach loop above.
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- See use of prepare in foreach loop above.
"DELETE FROM $wpdb->options WHERE " . implode( ' OR ', $where_clause )
);
}
Expand All @@ -187,10 +187,17 @@ function delete_transients() {
* @internal
*/
function remove_plugin_data() {
$options = get_option( 'amp-options' );

delete_options();
delete_user_metadata();
delete_posts();
delete_terms();
delete_transients();
if (
is_array( $options ) && array_key_exists( 'delete_data_at_uninstall', $options )
? $options['delete_data_at_uninstall']
: true
) {
delete_options();
delete_user_metadata();
delete_posts();
delete_terms();
delete_transients();
}
}
7 changes: 7 additions & 0 deletions src/Option.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ interface Option {
*/
const PLUGIN_CONFIGURED = 'plugin_configured';

/**
* The key of the option storing whether to delete AMP data upon uninstalling the plugin.
*
* @var string
*/
const DELETE_DATA_AT_UNINSTALL = 'delete_data_at_uninstall';

/**
* Cached slug when it is defined late.
*
Expand Down
34 changes: 19 additions & 15 deletions src/OptionsRESTController.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,15 +280,15 @@ public function get_item_schema() {
'type' => 'object',
'properties' => [
// Note: The sanitize_callback from AMP_Options_Manager::register_settings() is applying to this option.
Option::THEME_SUPPORT => [
Option::THEME_SUPPORT => [
'type' => 'string',
'enum' => [
AMP_Theme_Support::READER_MODE_SLUG,
AMP_Theme_Support::STANDARD_MODE_SLUG,
AMP_Theme_Support::TRANSITIONAL_MODE_SLUG,
],
],
Option::READER_THEME => [
Option::READER_THEME => [
'type' => 'string',
'arg_options' => [
'validate_callback' => function ( $value ) {
Expand All @@ -297,57 +297,61 @@ public function get_item_schema() {
},
],
],
Option::MOBILE_REDIRECT => [
Option::MOBILE_REDIRECT => [
'type' => 'boolean',
'default' => false,
],
self::PREVIEW_PERMALINK => [
self::PREVIEW_PERMALINK => [
'type' => 'string',
'readonly' => true,
'format' => 'url',
],
Option::PLUGIN_CONFIGURED => [
Option::PLUGIN_CONFIGURED => [
'type' => 'boolean',
'default' => false,
],
Option::ALL_TEMPLATES_SUPPORTED => [
Option::ALL_TEMPLATES_SUPPORTED => [
'type' => 'boolean',
],
Option::SUPPRESSED_PLUGINS => [
Option::SUPPRESSED_PLUGINS => [
'type' => 'object',
],
self::SUPPRESSIBLE_PLUGINS => [
self::SUPPRESSIBLE_PLUGINS => [
'type' => 'object',
'readonly' => true,
],
Option::SUPPORTED_TEMPLATES => [
Option::SUPPORTED_TEMPLATES => [
'type' => 'array',
'items' => [
'type' => 'string',
],
],
Option::SUPPORTED_POST_TYPES => [
Option::SUPPORTED_POST_TYPES => [
'type' => 'array',
'items' => [
'type' => 'string',
],
],
Option::ANALYTICS => [
Option::ANALYTICS => [
'type' => 'object',
],
self::SUPPORTABLE_POST_TYPES => [
Option::DELETE_DATA_AT_UNINSTALL => [
'type' => 'boolean',
'default' => true,
],
self::SUPPORTABLE_POST_TYPES => [
'type' => 'array',
'readonly' => true,
],
self::SUPPORTABLE_TEMPLATES => [
self::SUPPORTABLE_TEMPLATES => [
'type' => 'array',
'readonly' => true,
],
self::ONBOARDING_WIZARD_LINK => [
self::ONBOARDING_WIZARD_LINK => [
'type' => 'url',
'readonly' => true,
],
self::CUSTOMIZER_LINK => [
self::CUSTOMIZER_LINK => [
'type' => 'url',
'readonly' => true,
],
Expand Down
1 change: 1 addition & 0 deletions tests/php/src/OptionsRESTControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public function test_get_items() {
'mobile_redirect',
'plugin_configured',
'all_templates_supported',
'delete_data_at_uninstall',
'suppressed_plugins',
'supported_templates',
'supported_post_types',
Expand Down
21 changes: 21 additions & 0 deletions tests/php/test-amp-helper-functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ public function test_amp_bootstrap_plugin() {

$this->assertEquals( PHP_INT_MAX, has_filter( 'script_loader_tag', 'amp_filter_script_loader_tag' ) );
$this->assertEquals( 10, has_filter( 'style_loader_tag', 'amp_filter_font_style_loader_tag_with_crossorigin_anonymous' ) );
$this->assertEquals( 10, has_filter( 'all_plugins', 'amp_modify_plugin_description' ) );
}

/** @covers ::amp_bootstrap_plugin() */
Expand Down Expand Up @@ -2417,6 +2418,26 @@ public function test_amp_has_paired_endpoint_passed( $paired_url_structure, $suf
$this->assertEquals( $is_amp, amp_has_paired_endpoint( $url ) );
}

/**
* @covers ::amp_modify_plugin_description()
*/
public function test_amp_modify_plugin_description() {
$input = [
'amp/amp.php' => [
'Description' => 'An easier path to great Page Experience for everyone. Powered by AMP. <em class="amp-deletion-notice"><strong>Deletion Note:</strong> To delete all plugin data with uninstallation, first activate the plugin, <strong>Go to Settings screen > Scroll to “Other” section in Advanced settings > Enable “Delete plugin data upon uninstall” toggle</strong> (if you haven\'t done so already).</em>',
],
'foo/foo.php' => [
'Description' => 'This is not about foo[d]!',
],
];

$expected = $input;

$expected['amp/amp.php']['Description'] = 'An easier path to great Page Experience for everyone. Powered by AMP.';

$this->assertEquals( $expected, amp_modify_plugin_description( $input ) );
}

/**
* Get a mock publisher logo URL, to test that the filter works as expected.
*
Expand Down
37 changes: 21 additions & 16 deletions tests/php/test-class-amp-options-manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,19 @@ public function test_get_and_set_options() {
delete_option( AMP_Options_Manager::OPTION_NAME );
$this->assertEquals(
[
Option::THEME_SUPPORT => AMP_Theme_Support::READER_MODE_SLUG,
Option::SUPPORTED_POST_TYPES => [ 'post', 'page' ],
Option::ANALYTICS => [],
Option::ALL_TEMPLATES_SUPPORTED => true,
Option::SUPPORTED_TEMPLATES => [ 'is_singular' ],
Option::SUPPRESSED_PLUGINS => [],
Option::VERSION => AMP__VERSION,
Option::MOBILE_REDIRECT => true,
Option::READER_THEME => 'legacy',
Option::PLUGIN_CONFIGURED => false,
Option::PAIRED_URL_STRUCTURE => Option::PAIRED_URL_STRUCTURE_QUERY_VAR,
Option::LATE_DEFINED_SLUG => null,
Option::THEME_SUPPORT => AMP_Theme_Support::READER_MODE_SLUG,
Option::SUPPORTED_POST_TYPES => [ 'post', 'page' ],
Option::ANALYTICS => [],
Option::ALL_TEMPLATES_SUPPORTED => true,
Option::SUPPORTED_TEMPLATES => [ 'is_singular' ],
Option::SUPPRESSED_PLUGINS => [],
Option::VERSION => AMP__VERSION,
Option::MOBILE_REDIRECT => true,
Option::READER_THEME => 'legacy',
Option::PLUGIN_CONFIGURED => false,
Option::PAIRED_URL_STRUCTURE => Option::PAIRED_URL_STRUCTURE_QUERY_VAR,
Option::LATE_DEFINED_SLUG => null,
Option::DELETE_DATA_AT_UNINSTALL => true,
],
AMP_Options_Manager::get_options()
);
Expand Down Expand Up @@ -262,21 +263,25 @@ public function test_get_options_changing_plugin_configured_default() {
update_option(
AMP_Options_Manager::OPTION_NAME,
[
Option::VERSION => AMP__VERSION,
Option::PLUGIN_CONFIGURED => false,
Option::VERSION => AMP__VERSION,
Option::PLUGIN_CONFIGURED => false,
Option::DELETE_DATA_AT_UNINSTALL => false,
]
);
$this->assertFalse( AMP_Options_Manager::get_option( Option::PLUGIN_CONFIGURED ) );
$this->assertFalse( AMP_Options_Manager::get_option( Option::DELETE_DATA_AT_UNINSTALL ) );

// Ensure plugin_configured is false when explicitly set as such in the DB.
update_option(
AMP_Options_Manager::OPTION_NAME,
[
Option::VERSION => AMP__VERSION,
Option::PLUGIN_CONFIGURED => true,
Option::VERSION => AMP__VERSION,
Option::PLUGIN_CONFIGURED => true,
Option::DELETE_DATA_AT_UNINSTALL => true,
]
);
$this->assertTrue( AMP_Options_Manager::get_option( Option::PLUGIN_CONFIGURED ) );
$this->assertTrue( AMP_Options_Manager::get_option( Option::DELETE_DATA_AT_UNINSTALL ) );
}

/** @return array */
Expand Down
Loading