├── assets-wp-repo
├── icon-128x128.png
├── icon-256x256.png
├── screenshot-1.png
└── screenshot-2.png
├── tests
└── phpunit
│ ├── framework
│ ├── Integration_Test_Case.php
│ └── Unit_Test_Case.php
│ ├── bootstrap.php
│ ├── unit
│ └── Sample_Tests.php
│ ├── integration
│ └── Sample_Tests.php
│ ├── phpunit-compat.php
│ └── bootstrap-integration.php
├── phpcs.xml.dist
├── .editorconfig
├── .gitignore
├── .codeclimate.yml
├── phpunit.xml.dist
├── phpunit-integration.xml.dist
├── .github
├── PULL_REQUEST_TEMPLATE.md
└── ISSUE_TEMPLATE.md
├── phpmd.xml.dist
├── src
├── Policies_Setting.php
├── Policy_Headers.php
├── Feature.php
├── Admin
│ ├── Pointers.php
│ └── Settings_Screen.php
├── Plugin.php
└── Features.php
├── composer.json
├── README.md
├── CONTRIBUTING.md
├── readme.txt
├── .travis.yml
├── feature-policy.php
├── deploy.sh
└── LICENSE
/assets-wp-repo/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/wp-feature-policy/HEAD/assets-wp-repo/icon-128x128.png
--------------------------------------------------------------------------------
/assets-wp-repo/icon-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/wp-feature-policy/HEAD/assets-wp-repo/icon-256x256.png
--------------------------------------------------------------------------------
/assets-wp-repo/screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/wp-feature-policy/HEAD/assets-wp-repo/screenshot-1.png
--------------------------------------------------------------------------------
/assets-wp-repo/screenshot-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/wp-feature-policy/HEAD/assets-wp-repo/screenshot-2.png
--------------------------------------------------------------------------------
/tests/phpunit/framework/Integration_Test_Case.php:
--------------------------------------------------------------------------------
1 | assertTrue( true );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/phpcs.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 | Ruleset for a WordPress plugin.
4 |
5 | ./feature-policy.php
6 | ./src
7 |
8 | ^/vendor/*
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # WordPress Coding Standards
2 | # https://make.wordpress.org/core/handbook/best-practices/coding-standards/
3 |
4 | root = true
5 |
6 | [*]
7 | charset = utf-8
8 | end_of_line = lf
9 | indent_size = 4
10 | tab_width = 4
11 | indent_style = tab
12 | insert_final_newline = true
13 | trim_trailing_whitespace = true
14 |
15 | [*.md]
16 | trim_trailing_whitespace = false
17 | indent_style = space
18 | indent_size = 2
19 |
20 | [*.txt]
21 | trim_trailing_whitespace = false
22 |
23 | [*.json]
24 | insert_final_newline = false
25 | indent_style = space
26 | indent_size = 2
27 |
28 | [.*rc]
29 | insert_final_newline = false
30 | indent_style = space
31 | indent_size = 2
32 |
33 | [*.yml]
34 | insert_final_newline = false
35 | indent_style = space
36 | indent_size = 2
37 |
--------------------------------------------------------------------------------
/tests/phpunit/integration/Sample_Tests.php:
--------------------------------------------------------------------------------
1 | assertTrue( defined( 'ABSPATH' ) );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ############
2 | ## IDEs
3 | ############
4 |
5 | *.pydevproject
6 | .project
7 | .metadata
8 | *.swp
9 | *~.nib
10 | local.properties
11 | .classpath
12 | .settings/
13 | .loadpath
14 | .externalToolBuilders/
15 | *.launch
16 | .cproject
17 | .buildpath
18 | nbproject/
19 |
20 | ############
21 | ## Vendor
22 | ############
23 |
24 | node_modules/
25 | vendor/
26 | package-lock.json
27 | composer.lock
28 |
29 | ############
30 | ## OSes
31 | ############
32 |
33 | [Tt]humbs.db
34 | [Dd]esktop.ini
35 | *.DS_store
36 | .DS_store?
37 |
38 | ############
39 | ## Misc
40 | ############
41 |
42 | tests/logs
43 | bin/
44 | tmp/
45 | *.tmp
46 | *.bak
47 | *.log
48 | *.[Cc]ache
49 | *.cpr
50 | *.orig
51 | *.php.in
52 | .idea/
53 | .sass-cache/*
54 | temp/
55 | ._*
56 | .Trashes
57 | .svn
58 |
--------------------------------------------------------------------------------
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | ---
2 | engines:
3 | csslint:
4 | enabled: true
5 | duplication:
6 | enabled: true
7 | config:
8 | languages:
9 | - ruby
10 | - javascript
11 | - python
12 | - php
13 | eslint:
14 | enabled: true
15 | fixme:
16 | enabled: true
17 | phpcodesniffer:
18 | enabled: true
19 | config:
20 | file_extensions: "php"
21 | standard: "phpcs.xml.dist"
22 | ignore_warnings: true
23 | encoding: utf-8
24 | phpmd:
25 | enabled: true
26 | config:
27 | file_extensions: "php"
28 | rulesets: "phpmd.xml.dist"
29 | ratings:
30 | paths:
31 | - "**.css"
32 | - "**.js"
33 | - "**.php"
34 | exclude_paths:
35 | - "gulpfile.js"
36 | - "node_modules/*"
37 | - "tests/*"
38 | - "vendor/*"
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 | ./tests/phpunit/unit/
21 |
22 |
23 |
24 |
25 |
26 | ./src
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/phpunit-integration.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 | ./tests/phpunit/integration/
21 |
22 |
23 |
24 |
25 |
26 | ./src
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
7 |
8 | ## Summary
9 |
10 |
11 | This PR can be summarized in the following changelog entry:
12 |
13 | *
14 |
15 |
16 | Adresses issue #
17 |
18 | ## Relevant technical choices
19 |
20 |
21 | ## Checklist:
22 | - [ ] My code is tested.
23 | - [ ] My code is backward-compatible with WordPress 4.7 and PHP 5.6.
24 | - [ ] My code follows the [WordPress](https://make.wordpress.org/core/handbook/best-practices/coding-standards/) coding standards.
25 | - [ ] My code has proper inline documentation.
26 |
--------------------------------------------------------------------------------
/phpmd.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
9 | A custom set of PHPMD rules.
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/tests/phpunit/phpunit-compat.php:
--------------------------------------------------------------------------------
1 |
10 |
11 | ## Issue Overview
12 |
13 |
14 | ## Steps to Reproduce (for bugs)
15 |
16 |
17 | 1.
18 | 2.
19 | 3.
20 | 4.
21 |
22 |
23 | ## Expected Behavior
24 |
25 |
26 |
27 | ## Current Behavior
28 |
29 |
30 |
31 | ## Possible Solution
32 |
33 |
34 |
35 | ## Screenshots / Video
36 |
37 |
38 | ## Related Issues and/or PRs
39 |
40 |
--------------------------------------------------------------------------------
/tests/phpunit/framework/Unit_Test_Case.php:
--------------------------------------------------------------------------------
1 | 'object',
36 | 'description' => __( 'Feature Policy features and their origins.', 'feature-policy' ),
37 | 'sanitize_callback' => array( $this, 'sanitize' ),
38 | 'default' => array(),
39 | )
40 | );
41 | }
42 | );
43 | }
44 |
45 | /**
46 | * Gets the features list from the option.
47 | *
48 | * @since 0.1.0
49 | *
50 | * @return array Associative array of $policy_name => $policy_origins pairs.
51 | */
52 | public function get() {
53 | return array_filter( (array) get_option( self::OPTION_NAME, array() ) );
54 | }
55 |
56 | /**
57 | * Sanitizes the value for the setting.
58 | *
59 | * @since 0.1.0
60 | *
61 | * @param mixed $value Unsanitized setting value.
62 | * @return array Associative array of $policy_name => $policy_origins pairs.
63 | */
64 | public function sanitize( $value ) {
65 | // TODO: This is probably too basic.
66 | if ( ! is_array( $value ) ) {
67 | return array();
68 | }
69 | return $value;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "google/wp-feature-policy",
3 | "description": "WordPress plugin for managing feature policy headers.",
4 | "version": "0.1.0",
5 | "license": "GPL-2.0-or-later",
6 | "type": "wordpress-plugin",
7 | "keywords": [
8 | "feature",
9 | "policy"
10 | ],
11 | "homepage": "https://wordpress.org/plugins/feature-policy/",
12 | "authors": [
13 | {
14 | "name": "Google",
15 | "email": "westonruter@google.com",
16 | "homepage": "https://opensource.google.com/"
17 | }
18 | ],
19 | "support": {
20 | "issues": "https://github.com/GoogleChromeLabs/wp-feature-policy/issues"
21 | },
22 | "autoload": {
23 | "psr-4": {
24 | "Google\\WP_Feature_Policy\\": "src"
25 | }
26 | },
27 | "autoload-dev": {
28 | "psr-4": {
29 | "Google\\WP_Feature_Policy\\Tests\\PHPUnit\\Framework\\": "tests/phpunit/framework"
30 | }
31 | },
32 | "config": {
33 | "platform": {
34 | "php": "5.6"
35 | }
36 | },
37 | "require": {
38 | "php": ">=5.6",
39 | "composer/installers": "^1"
40 | },
41 | "require-dev": {
42 | "squizlabs/php_codesniffer": "^3.3",
43 | "dealerdirect/phpcodesniffer-composer-installer": "^0.4",
44 | "wp-coding-standards/wpcs": "^2",
45 | "phpmd/phpmd": "^2.6",
46 | "phpunit/phpunit": ">4.8.20 <6.0",
47 | "brain/monkey": "^2"
48 | },
49 | "scripts": {
50 | "phplint": "find -L . -path ./vendor -prune -o -name '*.php' -print0 | xargs -0 -n 1 -P 4 php -l",
51 | "phpcs": "@php ./vendor/bin/phpcs",
52 | "phpmd": "@php ./vendor/bin/phpmd src text phpmd.xml.dist",
53 | "phpunit": "@php ./vendor/bin/phpunit",
54 | "phpunit-cov": "@php ./vendor/bin/phpunit --coverage-clover tests/logs/clover.xml",
55 | "phpunit-integration": "@php ./vendor/bin/phpunit -c phpunit-integration.xml.dist",
56 | "phpunit-integration-cov": "@php ./vendor/bin/phpunit -c phpunit-integration.xml.dist --coverage-clover tests/logs/clover.xml"
57 | }
58 | }
--------------------------------------------------------------------------------
/src/Policy_Headers.php:
--------------------------------------------------------------------------------
1 | features = $features;
46 | $this->policies_setting = $policies_setting;
47 | }
48 |
49 | /**
50 | * Sends feature policy headers.
51 | *
52 | * @since 0.1.0
53 | */
54 | public function send_headers() {
55 | $features = $this->features->get_all();
56 | $option = $this->policies_setting->get();
57 |
58 | $headers = array();
59 | foreach ( $option as $policy_slug => $policy_origins ) {
60 | if ( ! isset( $features[ $policy_slug ] ) ) {
61 | continue;
62 | }
63 |
64 | if ( empty( $policy_origins ) || array( $features[ $policy_slug ]->default_origin ) === $policy_origins ) {
65 | continue;
66 | }
67 |
68 | $policy_header = $features[ $policy_slug ]->name;
69 | foreach ( $policy_origins as $origin ) {
70 | if ( Feature::ORIGIN_SELF === $origin || Feature::ORIGIN_NONE === $origin ) {
71 | $policy_header .= " '{$origin}'";
72 | continue;
73 | }
74 |
75 | $policy_header .= " {$origin}";
76 | }
77 |
78 | $headers[] = $policy_header;
79 | }
80 |
81 | if ( empty( $headers ) ) {
82 | return;
83 | }
84 |
85 | $value = implode( '; ', $headers );
86 |
87 | header( "Feature-Policy: {$value}" );
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://wordpress.org/plugins/feature-policy/)
2 | [](https://wordpress.org/plugins/feature-policy/)
3 | [](https://travis-ci.org/GoogleChromeLabs/wp-feature-policy)
4 |
5 | # Feature Policy
6 |
7 | WordPress plugin for managing feature policy headers.
8 |
9 | ## Details
10 |
11 | As [noted on the Google Developers blog](https://developers.google.com/web/updates/2018/06/feature-policy):
12 |
13 | > Feature Policy allows web developers to selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. **It's like CSP but instead of controlling security, it controls features!**
14 | >
15 | > The feature policies themselves are little opt-in agreements between developer and browser that can help foster our goals of building (and maintaining) high quality web apps.
16 |
17 | This plugin provides an API for sending the `Feature-Policy` response headers, as well as an admin interface for deciding which policy to apply for each feature.
18 |
19 | 
20 |
21 | As the Feature Policy specification is still evolving and at an early stage, the plugin reflects that and is currently an experimental prototype, to demonstrate how Feature Policy can be used in WordPress.
22 |
23 | ### Did you know?
24 |
25 | The Feature Policy specification will integrate with the new Reporting API specification. There is a [WordPress plugin for that specification](https://github.com/GoogleChromeLabs/wp-reporting-api) as well.
26 |
27 | ## Requirements
28 |
29 | * WordPress >= 4.7
30 | * PHP >= 5.6
31 |
32 | ## Contributing
33 |
34 | Any kind of contributions to Feature Policy are welcome. Please [read the contributing guidelines](https://github.com/GoogleChromeLabs/wp-feature-policy/blob/main/CONTRIBUTING.md) to get started.
35 |
36 | ## Further Resources
37 |
38 | * [https://featurepolicy.rocks/](https://featurepolicy.rocks/)
39 | * [https://developers.google.com/web/updates/2018/06/feature-policy](https://developers.google.com/web/updates/2018/06/feature-policy)
40 | * [https://developers.google.com/web/updates/2018/09/reportingapi](https://developers.google.com/web/updates/2018/09/reportingapi)
41 | * [https://developer.mozilla.org/en-US/docs/Web/HTTP/Feature_Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Feature_Policy)
42 | * [https://wicg.github.io/feature-policy/](https://wicg.github.io/feature-policy/)
43 | * [https://github.com/WICG/feature-policy](https://github.com/WICG/feature-policy)
44 |
--------------------------------------------------------------------------------
/src/Feature.php:
--------------------------------------------------------------------------------
1 | name = $name;
58 | $this->set_args( $args );
59 | }
60 |
61 | /**
62 | * Magic isset-er.
63 | *
64 | * @since 0.1.0
65 | *
66 | * @param string $prop Property to check for.
67 | * @return bool True if the property is set, false otherwise.
68 | */
69 | public function __isset( $prop ) {
70 | if ( 'name' === $prop ) {
71 | return true;
72 | }
73 |
74 | return isset( $this->args[ $prop ] );
75 | }
76 |
77 | /**
78 | * Magic getter.
79 | *
80 | * @since 0.1.0
81 | *
82 | * @param string $prop Property to get.
83 | * @return mixed The property value, or null if property not set.
84 | */
85 | public function __get( $prop ) {
86 | if ( 'name' === $prop ) {
87 | return $this->name;
88 | }
89 |
90 | if ( isset( $this->args[ $prop ] ) ) {
91 | return $this->args[ $prop ];
92 | }
93 |
94 | return null;
95 | }
96 |
97 | /**
98 | * Sets the feature arguments.
99 | *
100 | * @since 0.1.0
101 | *
102 | * @param array $args List of feature arguments. See {@see Feature::__construct()} for a list of supported
103 | * arguments.
104 | */
105 | protected function set_args( array $args ) {
106 | $this->args = wp_parse_args(
107 | $args,
108 | array(
109 | 'title' => '',
110 | 'default_origin' => self::ORIGIN_ANY,
111 | )
112 | );
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/tests/phpunit/bootstrap-integration.php:
--------------------------------------------------------------------------------
1 | = 6.0 shim, which WordPress core only includes itself since version 4.7.
42 | if ( ! file_exists( $test_root . '/includes/phpunit6-compat.php' ) && class_exists( 'PHPUnit\Runner\Version' ) && version_compare( PHPUnit\Runner\Version::id(), '6.0', '>=' ) ) {
43 | class_alias( 'PHPUnit\Framework\TestCase', 'PHPUnit_Framework_TestCase' );
44 | class_alias( 'PHPUnit\Framework\Exception', 'PHPUnit_Framework_Exception' );
45 | class_alias( 'PHPUnit\Framework\ExpectationFailedException', 'PHPUnit_Framework_ExpectationFailedException' );
46 | class_alias( 'PHPUnit\Framework\Error\Notice', 'PHPUnit_Framework_Error_Notice' );
47 | class_alias( 'PHPUnit\Framework\Error\Warning', 'PHPUnit_Framework_Error_Warning' );
48 | class_alias( 'PHPUnit\Framework\Test', 'PHPUnit_Framework_Test' );
49 | class_alias( 'PHPUnit\Framework\Warning', 'PHPUnit_Framework_Warning' );
50 | class_alias( 'PHPUnit\Framework\AssertionFailedError', 'PHPUnit_Framework_AssertionFailedError' );
51 | class_alias( 'PHPUnit\Framework\TestSuite', 'PHPUnit_Framework_TestSuite' );
52 | class_alias( 'PHPUnit\Framework\TestListener', 'PHPUnit_Framework_TestListener' );
53 | class_alias( 'PHPUnit\Util\GlobalState', 'PHPUnit_Util_GlobalState' );
54 | class_alias( 'PHPUnit\Util\Getopt', 'PHPUnit_Util_Getopt' );
55 | class_alias( 'PHPUnit\Util\Test', 'PHPUnit_Util_Test' );
56 |
57 | // This only needs to be included to that the WP test suite does not call the `getTickets()` method which conflicts.
58 | define( 'WP_TESTS_FORCE_KNOWN_BUGS', true );
59 | }
60 |
61 | // Ensure the plugin is loaded.
62 | $GLOBALS['wp_tests_options'] = array(
63 | 'active_plugins' => array( basename( TESTS_PLUGIN_DIR ) . '/feature-policy.php' ),
64 | );
65 |
66 | // Load the WordPress tests environment.
67 | require_once $test_root . '/includes/bootstrap.php';
68 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribute to Feature Policy
2 |
3 | Bug reports, patches, translations and any kind of contributions are very welcome. When contributing, please ensure you stick to the following guidelines.
4 |
5 | ## Writing a Bug Report
6 |
7 | When writing a bug report...
8 |
9 | * [open an issue](https://github.com/GoogleChromeLabs/wp-feature-policy/issues/new)
10 | * follow the guidelines specified in the issue template
11 |
12 | We will take a look at your issue and either assign it keywords and a milestone or get back to you if there are open questions.
13 |
14 | ## Contributing Code
15 |
16 | When contributing code...
17 |
18 | * fork the `main` branch of the repository on GitHub
19 | * make changes to the forked repository
20 | * write code that is backward-compatible with WordPress 4.7 and PHP 5.6
21 | * make sure you stick to the [WordPress](https://make.wordpress.org/core/handbook/best-practices/coding-standards/) coding standards
22 | * make sure you document the code properly
23 | * test your code with the constant `WP_DEBUG` enabled
24 | * when committing, in addition to a note about the fix, please reference your issue (if present)
25 | * push the changes to your fork and [submit a pull request](https://github.com/GoogleChromeLabs/wp-feature-policy/compare) to the `main` branch
26 | * follow the guidelines specified in the pull request template
27 |
28 | After that we will review the pull-request as soon as possible and either merge it, make suggestions on improvements or ask you for further details about your implementation.
29 |
30 | ### Contributor License Agreement
31 |
32 | Contributions to this project must be accompanied by a Contributor License
33 | Agreement. You (or your employer) retain the copyright to your contribution;
34 | this simply gives us permission to use and redistribute your contributions as
35 | part of the project. Head over to to see
36 | your current agreements on file or to sign a new one.
37 |
38 | You generally only need to submit a CLA once, so if you've already submitted one
39 | (even if it was for a different project), you probably don't need to do it
40 | again.
41 |
42 | ### Code reviews
43 |
44 | All submissions, including submissions by project members, require review. We
45 | use GitHub pull requests for this purpose. Consult
46 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
47 | information on using pull requests.
48 |
49 | ## Providing Translations
50 |
51 | When providing translations...
52 |
53 | * visit our project on [translate.wordpress.org](https://translate.wordpress.org/projects/wp-plugins/feature-policy) and sign in with your wordpress.org account (create one if you haven't yet)
54 | * select the language you would like to contribute to
55 | * provide the missing translations
56 | * make sure you follow the guidelines outlined in the [Translator Handbook](https://make.wordpress.org/polyglots/handbook/translating/expectations/)
57 | * stick to the translation conventions for your locale (if there are any) - you can find these [here](https://make.wordpress.org/polyglots/handbook/tools/list-of-glossaries-per-locale/)
58 |
59 | After having provided translations, a translation editor will review your submissions soon and approve them as appropriate.
60 |
61 | ## Community Guidelines
62 |
63 | This project follows
64 | [Google's Open Source Community Guidelines](https://opensource.google.com/conduct/).
65 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | === Feature Policy ===
2 |
3 | Contributors: google, westonruter, flixos90
4 | Requires at least: 4.7
5 | Tested up to: 5.1
6 | Requires PHP: 5.6
7 | Stable tag: 0.1.0
8 | License: GNU General Public License v2 (or later)
9 | License URI: https://www.gnu.org/licenses/gpl-2.0.html
10 | Tags: feature, policy
11 |
12 | WordPress plugin for managing feature policy headers.
13 |
14 | == Description ==
15 |
16 | As [noted on the Google Developers blog](https://developers.google.com/web/updates/2018/06/feature-policy):
17 |
18 | > Feature Policy allows web developers to selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. **It's like CSP but instead of controlling security, it controls features!**
19 | >
20 | > The feature policies themselves are little opt-in agreements between developer and browser that can help foster our goals of building (and maintaining) high quality web apps.
21 |
22 | This plugin provides an API for sending the `Feature-Policy` response headers, as well as an admin interface for deciding which policy to apply for each feature.
23 |
24 | As the Feature Policy specification is still evolving and at an early stage, the plugin reflects that and is currently an experimental prototype, to demonstrate how Feature Policy can be used in WordPress.
25 |
26 | = Did you know? =
27 |
28 | The Feature Policy specification will integrate with the new Reporting API specification. There is a [WordPress plugin for that specification](https://wordpress.org/plugins/reporting-api/) as well.
29 |
30 | == Installation ==
31 |
32 | 1. Upload the entire `feature-policy` folder to the `/wp-content/plugins/` directory or download it through the WordPress backend.
33 | 2. Activate the plugin through the 'Plugins' menu in WordPress.
34 |
35 | == Frequently Asked Questions ==
36 |
37 | = Which browsers support the Feature Policy specification? =
38 |
39 | The Feature Policy standard is quite bleeding-edge, so support is currently still limited. The latest versions of Chrome, Safari, Opera and several mobile browsers support it. For detailed support stats, please check [caniuse.com/#feat=feature-policy](https://caniuse.com/#feat=feature-policy).
40 |
41 | = Where should I submit my support request? =
42 |
43 | Note that this is an experimental plugin, so support is limited and volunteer-driven. For regular support requests, please use the [wordpress.org support forums](https://wordpress.org/support/plugin/feature-policy). If you have a technical issue with the plugin where you already have more insight on how to fix it, you can also [open an issue on Github instead](https://github.com/GoogleChromeLabs/wp-feature-policy/issues).
44 |
45 | = How can I contribute to the plugin? =
46 |
47 | If you have some ideas to improve the plugin or to solve a bug, feel free to raise an issue or submit a pull request in the [Github repository for the plugin](https://github.com/GoogleChromeLabs/wp-feature-policy). Please stick to the [contributing guidelines](https://github.com/GoogleChromeLabs/wp-feature-policy/blob/main/CONTRIBUTING.md).
48 |
49 | You can also contribute to the plugin by translating it. Simply visit [translate.wordpress.org](https://translate.wordpress.org/projects/wp-plugins/feature-policy) to get started.
50 |
51 | == Screenshots ==
52 |
53 | 1. Settings screen to control policies for all available features
54 | 2. Settings screen with a link to Feature Policy reports (with the Reporting API plugin active)
55 |
56 | == Changelog ==
57 |
58 | = 0.1.0 =
59 |
60 | * Initial release
61 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | dist: trusty
3 | language: php
4 | cache:
5 | directories:
6 | - vendor
7 | - $HOME/.composer/cache
8 | matrix:
9 | include:
10 | - php: 7.3
11 | env: UNIT=1 PHPLINT=1 PHPCS=1 COVERAGE=1
12 | - php: 5.6
13 | env: UNIT=1 PHPLINT=1
14 | dist: trusty
15 | - php: 7.3
16 | env: INTEGRATION=1 WP_VERSION=latest
17 | - php: 5.6
18 | env: INTEGRATION=1 WP_VERSION=latest
19 | dist: trusty
20 | - php: 7.3
21 | env: INTEGRATION=1 WP_VERSION=4.7
22 | - php: 5.6
23 | env: INTEGRATION=1 WP_VERSION=4.7
24 | dist: trusty
25 | - php: nightly
26 | env: UNIT=1
27 | - php: 7.3
28 | env: INTEGRATION=1 WP_VERSION=master
29 | allow_failures:
30 | - php: nightly
31 | env: UNIT=1
32 | - php: 7.3
33 | env: INTEGRATION=1 WP_VERSION=master
34 | before_install:
35 | - |
36 | if [[ -z "$CC_TEST_REPORTER_ID" ]]; then
37 | COVERAGE="0"
38 | fi
39 | - |
40 | if [[ "$COVERAGE" == "1" ]]; then
41 | curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
42 | chmod +x ./cc-test-reporter
43 | ./cc-test-reporter before-build
44 | fi
45 | - |
46 | if [[ "$COVERAGE" != "1" ]]; then
47 | stable='^[0-9\.]+$'
48 | if [[ "$TRAVIS_PHP_VERSION" =~ $stable ]]; then
49 | phpenv config-rm xdebug.ini
50 | fi
51 | fi
52 | - composer install
53 | before_script:
54 | - |
55 | if [[ "$INTEGRATION" == "1" ]]; then
56 | if [[ "$WP_VERSION" == "latest" ]]; then
57 | curl -s http://api.wordpress.org/core/version-check/1.7/ > /tmp/wp-latest.json
58 | WP_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
59 | fi
60 | PLUGIN_SLUG=$(basename $(pwd))
61 | export WP_DEVELOP_DIR=/tmp/wordpress/
62 | git clone --depth=50 --branch="$WP_VERSION" git://develop.git.wordpress.org/ /tmp/wordpress
63 | cd ..
64 | cp -r "$PLUGIN_SLUG" "/tmp/wordpress/src/wp-content/plugins/$PLUGIN_SLUG"
65 | cd /tmp/wordpress/
66 | cp wp-tests-config-sample.php wp-tests-config.php
67 | sed -i "s/youremptytestdbnamehere/wordpress_tests/" wp-tests-config.php
68 | sed -i "s/yourusernamehere/travis/" wp-tests-config.php
69 | sed -i "s/yourpasswordhere//" wp-tests-config.php
70 | mysql -e "CREATE DATABASE wordpress_tests;" -uroot
71 | cd "/tmp/wordpress/src/wp-content/plugins/$PLUGIN_SLUG"
72 | fi
73 | - phpenv rehash
74 | script:
75 | - |
76 | if [[ "$PHPLINT" == "1" ]]; then
77 | composer run-script phplint
78 | fi
79 | - |
80 | if [[ "$PHPCS" == "1" ]]; then
81 | composer run-script phpcs
82 | fi
83 | - |
84 | if [[ "$PHPMD" == "1" ]]; then
85 | composer run-script phpmd
86 | fi
87 | - |
88 | if [[ "$UNIT" == "1" ]]; then
89 | if [[ "$COVERAGE" == "1" ]]; then
90 | mkdir -p tests/logs
91 | composer run-script phpunit-cov
92 | else
93 | composer run-script phpunit
94 | fi
95 | fi
96 | - |
97 | if [[ "$INTEGRATION" == "1" ]]; then
98 | if [[ "$COVERAGE" == "1" ]]; then
99 | mkdir -p tests/logs
100 | composer run-script phpunit-integration-cov
101 | else
102 | composer run-script phpunit-integration
103 | fi
104 | fi
105 | after_script:
106 | - |
107 | if [[ "$COVERAGE" == "1" ]]; then
108 | ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
109 | fi
110 | notifications:
111 | email: false
--------------------------------------------------------------------------------
/feature-policy.php:
--------------------------------------------------------------------------------
1 |
61 |
73 |
84 |
96 |
107 |
108 |
109 | composer install'
114 | );
115 | ?>
116 |
117 |
118 | get_pointers( $hook_suffix );
37 | if ( empty( $pointers ) ) {
38 | return;
39 | }
40 |
41 | $dismissed = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
42 |
43 | $pointers = array_diff_key( $pointers, array_flip( $dismissed ) );
44 |
45 | $got_pointers = false;
46 | foreach ( $pointers as $pointer_id => $pointer_args ) {
47 | if ( empty( $pointer_args['render_callback'] ) ) {
48 | continue;
49 | }
50 |
51 | if ( ! empty( $pointer_args['active_callback'] ) && ! call_user_func( $pointer_args['active_callback'] ) ) {
52 | continue;
53 | }
54 |
55 | add_action( 'admin_print_footer_scripts', $pointer_args['render_callback'] );
56 | $got_pointers = true;
57 | }
58 |
59 | // Bail if no pointers need to be loaded.
60 | if ( ! $got_pointers ) {
61 | return;
62 | }
63 |
64 | wp_enqueue_style( 'wp-pointer' );
65 | wp_enqueue_script( 'wp-pointer' );
66 | }
67 |
68 | /**
69 | * Gets available admin pointers.
70 | *
71 | * @since 0.1.0
72 | *
73 | * @param string $hook_suffix The current admin page.
74 | * @return array Associative array of $pointer_id => $pointer_args pairs.
75 | */
76 | protected function get_pointers( $hook_suffix ) {
77 | $pointers = array(
78 | self::ACTIVATION => array(
79 | 'render_callback' => function() {
80 | $content = '' . __( 'Feature Policy', 'feature-policy' ) . ' ';
81 | $content .= '' . __( 'You can now control how certain web features act on your site under Settings > Feature Policy .', 'feature-policy' ) . '
';
82 |
83 | $position = array(
84 | 'edge' => is_rtl() ? 'right' : 'left',
85 | 'align' => 'bottom',
86 | );
87 |
88 | $js_args = array(
89 | 'content' => $content,
90 | 'position' => $position,
91 | 'pointerClass' => 'wp-pointer arrow-bottom',
92 | );
93 | $this->print_js( self::ACTIVATION, '#menu-settings', $js_args );
94 | },
95 | 'active_callback' => function() {
96 | if ( ! current_user_can( Settings_Screen::CAPABILITY ) ) {
97 | return false;
98 | }
99 |
100 | return true;
101 | },
102 | ),
103 | );
104 |
105 | $pointers = array(
106 | 'index.php' => array( self::ACTIVATION => $pointers[ self::ACTIVATION ] ),
107 | 'plugins.php' => array( self::ACTIVATION => $pointers[ self::ACTIVATION ] ),
108 | );
109 |
110 | if ( ! isset( $pointers[ $hook_suffix ] ) ) {
111 | return array();
112 | }
113 |
114 | return $pointers[ $hook_suffix ];
115 | }
116 |
117 | /**
118 | * Prints JavaScript data for a given pointer.
119 | *
120 | * @since 0.1.0
121 | *
122 | * @param string $pointer_id The pointer ID.
123 | * @param string $selector The HTML elements, on which the pointer should be attached.
124 | * @param array $args Arguments to be passed to the pointer JS (see wp-pointer.js).
125 | */
126 | protected function print_js( $pointer_id, $selector, $args ) {
127 | if ( empty( $pointer_id ) || empty( $selector ) || empty( $args ) || empty( $args['content'] ) ) {
128 | return;
129 | }
130 |
131 | ?>
132 |
159 | /tmp/wppdcommitmsg.tmp
74 | echo "Done."
75 |
76 | printf "Preparing assets-wp-repo..."
77 | if [ -d $SVNPATH/trunk/assets-wp-repo ]
78 | then
79 | svn checkout --quiet $SVNURL/assets $SVNPATH/assets > /dev/null 2>&1
80 | mkdir $SVNPATH/assets/ > /dev/null 2>&1 # Create assets directory if it doesn't exists
81 | mv $SVNPATH/trunk/assets-wp-repo/* $SVNPATH/assets/ # Move new assets
82 | rm -rf $SVNPATH/trunk/assets-wp-repo # Clean up
83 | cd $SVNPATH/assets/ # Switch to assets directory
84 | svn stat | grep "^?\|^M" > /dev/null 2>&1 # Check if new or updated assets exists
85 | if [ $? -eq 0 ]
86 | then
87 | svn stat | grep "^?" | awk '{print $2}' | xargs svn add --quiet # Add new assets
88 | echo -en "Committing new assets..."
89 | svn commit --quiet -m "updated assets"
90 | echo "Done."
91 | else
92 | echo "Unchanged."
93 | fi
94 | else
95 | echo "No assets exists."
96 | fi
97 |
98 | cd $SVNPATH/trunk/
99 |
100 | composer install --no-dev
101 |
102 | printf "Ignoring GitHub specific files and deployment script..."
103 | svn propset --quiet svn:ignore ".codeclimate.yml
104 | .git
105 | .gitattributes
106 | .github
107 | .gitignore
108 | .travis.yml
109 | composer.json
110 | composer.lock
111 | CONTRIBUTING.md
112 | deploy.sh
113 | phpcs.xml.dist
114 | phpmd.xml.dist
115 | phpunit-integration.xml.dist
116 | phpunit.xml.dist
117 | README.md
118 | tests" .
119 | echo "Done."
120 |
121 | printf "Adding new files..."
122 | svn stat | grep "^?" | awk '{print $2}' | xargs svn add --quiet
123 | echo "Done."
124 |
125 | printf "Removing old files..."
126 | svn stat | grep "^\!" | awk '{print $2}' | xargs svn remove --quiet
127 | echo "Done."
128 |
129 | printf "Enter a commit message for this new SVN version..."
130 | $DEFAULT_EDITOR /tmp/wppdcommitmsg.tmp
131 | COMMITMSG=`cat /tmp/wppdcommitmsg.tmp`
132 | rm /tmp/wppdcommitmsg.tmp
133 | echo "Done."
134 |
135 | printf "Committing new SVN version..."
136 | svn commit --quiet -m "$COMMITMSG"
137 | echo "Done."
138 |
139 | printf "Tagging and committing new SVN tag..."
140 | svn copy $SVNURL/trunk $SVNURL/tags/$NEWVERSION1 --quiet -m "tagged version $NEWVERSION1"
141 | echo "Done."
142 |
143 | printf "Removing temporary directory %s..." "$SVNPATH"
144 | rm -rf $SVNPATH/
145 | echo "Done."
146 |
147 | echo
148 | echo "Plugin $PLUGINSLUG version $NEWVERSION1 has been successfully deployed."
149 | echo
150 |
--------------------------------------------------------------------------------
/src/Plugin.php:
--------------------------------------------------------------------------------
1 | main_file = $main_file;
61 |
62 | $this->features = new Features();
63 | $this->policies_setting = new Policies_Setting();
64 | }
65 |
66 | /**
67 | * Registers the plugin with WordPress.
68 | *
69 | * @since 0.1.0
70 | */
71 | public function register() {
72 | $this->policies_setting->register();
73 |
74 | add_filter(
75 | 'user_has_cap',
76 | array( $this, 'grant_feature_policy_cap' )
77 | );
78 |
79 | add_action(
80 | 'send_headers',
81 | function() {
82 | $policy_headers = new Policy_Headers( $this->features, $this->policies_setting );
83 | $policy_headers->send_headers();
84 | }
85 | );
86 |
87 | add_action(
88 | 'admin_menu',
89 | function() {
90 | $admin_screen = new Admin\Settings_Screen( $this->features, $this->policies_setting );
91 | $admin_screen->register_menu();
92 | }
93 | );
94 |
95 | add_action(
96 | 'admin_enqueue_scripts',
97 | function( $hook_suffix ) {
98 | $admin_screen = new Admin\Pointers();
99 | $admin_screen->enqueue_scripts( $hook_suffix );
100 | }
101 | );
102 | }
103 |
104 | /**
105 | * Gets the plugin basename, which consists of the plugin directory name and main file name.
106 | *
107 | * @since 0.1.0
108 | *
109 | * @return string Plugin basename.
110 | */
111 | public function basename() {
112 | return plugin_basename( $this->main_file );
113 | }
114 |
115 | /**
116 | * Gets the absolute path for a path relative to the plugin directory.
117 | *
118 | * @since 0.1.0
119 | *
120 | * @param string $relative_path Optional. Relative path. Default '/'.
121 | * @return string Absolute path.
122 | */
123 | public function path( $relative_path = '/' ) {
124 | return plugin_dir_path( $this->main_file ) . ltrim( $relative_path, '/' );
125 | }
126 |
127 | /**
128 | * Gets the full URL for a path relative to the plugin directory.
129 | *
130 | * @since 0.1.0
131 | *
132 | * @param string $relative_path Optional. Relative path. Default '/'.
133 | * @return string Full URL.
134 | */
135 | public function url( $relative_path = '/' ) {
136 | return plugin_dir_url( $this->main_file ) . ltrim( $relative_path, '/' );
137 | }
138 |
139 | /**
140 | * Gets the URL to the plugin's settings screen.
141 | *
142 | * @since 0.1.0
143 | *
144 | * @return string Settings screen URL.
145 | */
146 | public function settings_screen_url() {
147 | return add_query_arg( 'page', Admin\Settings_Screen::SLUG, admin_url( Admin\Settings_Screen::PARENT_SLUG ) );
148 | }
149 |
150 | /**
151 | * Dynamically grants the 'manage_feature_policy' capability based on 'manage_options'.
152 | *
153 | * This method is hooked into the `user_has_cap` filter and can be unhooked and replaced with custom functionality
154 | * if needed.
155 | *
156 | * @since 0.1.0
157 | *
158 | * @param array $allcaps Associative array of $cap => $grant pairs.
159 | * @return array Filtered $allcaps array.
160 | */
161 | public function grant_feature_policy_cap( array $allcaps ) {
162 | if ( isset( $allcaps['manage_options'] ) ) {
163 | $allcaps[ Admin\Settings_Screen::CAPABILITY ] = $allcaps['manage_options'];
164 | }
165 |
166 | return $allcaps;
167 | }
168 |
169 | /**
170 | * Retrieves the main instance of the plugin.
171 | *
172 | * @since 0.1.0
173 | *
174 | * @return Plugin Plugin main instance.
175 | */
176 | public static function instance() {
177 | return static::$instance;
178 | }
179 |
180 | /**
181 | * Loads the plugin main instance and initializes it.
182 | *
183 | * @since 0.1.0
184 | *
185 | * @param string $main_file Absolute path to the plugin main file.
186 | * @return bool True if the plugin main instance could be loaded, false otherwise.
187 | */
188 | public static function load( $main_file ) {
189 | if ( null !== static::$instance ) {
190 | return false;
191 | }
192 |
193 | static::$instance = new static( $main_file );
194 | static::$instance->register();
195 |
196 | return true;
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/src/Features.php:
--------------------------------------------------------------------------------
1 | $feature_instance pairs.
34 | */
35 | public function get_all() {
36 | if ( ! empty( $this->features ) ) {
37 | return $this->features;
38 | }
39 |
40 | $features = array(
41 | 'accelerometer' => array(
42 | 'title' => __( 'Accelerometer', 'feature-policy' ),
43 | 'default_origin' => Feature::ORIGIN_SELF,
44 | ),
45 | 'ambient-light-sensor' => array(
46 | 'title' => __( 'Ambient Light Sensor', 'feature-policy' ),
47 | 'default_origin' => Feature::ORIGIN_SELF,
48 | ),
49 | 'autoplay' => array(
50 | 'title' => __( 'Autoplay', 'feature-policy' ),
51 | 'default_origin' => Feature::ORIGIN_SELF,
52 | ),
53 | 'camera' => array(
54 | 'title' => __( 'Camera', 'feature-policy' ),
55 | 'default_origin' => Feature::ORIGIN_SELF,
56 | ),
57 | 'document-domain' => array(
58 | 'title' => __( 'document.domain', 'feature-policy' ),
59 | 'default_origin' => Feature::ORIGIN_ANY,
60 | ),
61 | 'document-write' => array(
62 | 'title' => __( 'document.write()', 'feature-policy' ),
63 | 'default_origin' => Feature::ORIGIN_ANY,
64 | ),
65 | 'encrypted-media' => array(
66 | 'title' => __( 'Encrypted Media', 'feature-policy' ),
67 | 'default_origin' => Feature::ORIGIN_SELF,
68 | ),
69 | 'fullscreen' => array(
70 | 'title' => __( 'Fullscreen', 'feature-policy' ),
71 | 'default_origin' => Feature::ORIGIN_SELF,
72 | ),
73 | 'geolocation' => array(
74 | 'title' => __( 'Geolocation', 'feature-policy' ),
75 | 'default_origin' => Feature::ORIGIN_SELF,
76 | ),
77 | 'gyroscope' => array(
78 | 'title' => __( 'Gyroscope', 'feature-policy' ),
79 | 'default_origin' => Feature::ORIGIN_SELF,
80 | ),
81 | 'layout-animations' => array(
82 | 'title' => __( 'Layout Animations', 'feature-policy' ),
83 | 'default_origin' => Feature::ORIGIN_ANY,
84 | ),
85 | 'lazyload' => array(
86 | 'title' => __( 'Lazy Loading', 'feature-policy' ),
87 | 'default_origin' => Feature::ORIGIN_ANY,
88 | ),
89 | 'legacy-image-formats' => array(
90 | 'title' => __( 'Legacy Image Formats', 'feature-policy' ),
91 | 'default_origin' => Feature::ORIGIN_ANY,
92 | ),
93 | 'magnetometer' => array(
94 | 'title' => __( 'Magnetometer', 'feature-policy' ),
95 | 'default_origin' => Feature::ORIGIN_SELF,
96 | ),
97 | 'microphone' => array(
98 | 'title' => __( 'Microphone', 'feature-policy' ),
99 | 'default_origin' => Feature::ORIGIN_SELF,
100 | ),
101 | 'midi' => array(
102 | 'title' => __( 'Midi', 'feature-policy' ),
103 | 'default_origin' => Feature::ORIGIN_SELF,
104 | ),
105 | 'oversized-images' => array(
106 | 'title' => __( 'Oversized Images', 'feature-policy' ),
107 | 'default_origin' => Feature::ORIGIN_ANY,
108 | ),
109 | 'payment' => array(
110 | 'title' => __( 'Payment', 'feature-policy' ),
111 | 'default_origin' => Feature::ORIGIN_SELF,
112 | ),
113 | 'picture-in-picture' => array(
114 | 'title' => __( 'Picture-in-Picture', 'feature-policy' ),
115 | 'default_origin' => Feature::ORIGIN_ANY,
116 | ),
117 | 'speaker' => array(
118 | 'title' => __( 'Speaker', 'feature-policy' ),
119 | 'default_origin' => Feature::ORIGIN_SELF,
120 | ),
121 | 'sync-script' => array(
122 | 'title' => __( 'Synchronous Scripts', 'feature-policy' ),
123 | 'default_origin' => Feature::ORIGIN_ANY,
124 | ),
125 | 'sync-xhr' => array(
126 | 'title' => __( 'Synchronous XHR', 'feature-policy' ),
127 | 'default_origin' => Feature::ORIGIN_ANY,
128 | ),
129 | 'unoptimized-images' => array(
130 | 'title' => __( 'Unoptimized Images', 'feature-policy' ),
131 | 'default_origin' => Feature::ORIGIN_ANY,
132 | ),
133 | 'unsized-media' => array(
134 | 'title' => __( 'Unsized Media', 'feature-policy' ),
135 | 'default_origin' => Feature::ORIGIN_ANY,
136 | ),
137 | 'usb' => array(
138 | 'title' => __( 'USB', 'feature-policy' ),
139 | 'default_origin' => Feature::ORIGIN_ANY,
140 | ),
141 | 'vertical-scroll' => array(
142 | 'title' => __( 'Vertical Scroll', 'feature-policy' ),
143 | 'default_origin' => Feature::ORIGIN_ANY,
144 | ),
145 | 'vr' => array(
146 | 'title' => __( 'VR', 'feature-policy' ),
147 | 'default_origin' => Feature::ORIGIN_SELF,
148 | ),
149 | );
150 |
151 | $this->features = array();
152 | foreach ( $features as $feature => $feature_info ) {
153 | $this->features[ $feature ] = new Feature(
154 | $feature,
155 | $feature_info
156 | );
157 | }
158 |
159 | return $this->features;
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/src/Admin/Settings_Screen.php:
--------------------------------------------------------------------------------
1 | features = $features;
74 | $this->policies_setting = $policies_setting;
75 | }
76 |
77 | /**
78 | * Registers the menu item for the admin screen.
79 | *
80 | * @since 0.1.0
81 | */
82 | public function register_menu() {
83 | $hook_suffix = add_submenu_page(
84 | self::PARENT_SLUG,
85 | __( 'Feature Policy Settings', 'feature-policy' ),
86 | __( 'Feature Policy', 'feature-policy' ),
87 | self::CAPABILITY,
88 | self::SLUG,
89 | array( $this, 'render' )
90 | );
91 | add_action(
92 | "load-{$hook_suffix}",
93 | function() {
94 | $this->add_settings_ui();
95 | }
96 | );
97 | }
98 |
99 | /**
100 | * Renders the admin screen.
101 | *
102 | * @since 0.1.0
103 | */
104 | public function render() {
105 | ?>
106 |
117 |
118 |
119 |
120 |
121 | reports_screen_url() ) ) . '" class="page-title-action">' . esc_html__( 'View Violation Reports', 'feature-policy' ) . '';
124 | }
125 | ?>
126 |
127 |
128 |
129 |
130 | %2$s %3$s ',
133 | esc_url( _x( 'https://developers.google.com/web/updates/2018/06/feature-policy', 'learn more link', 'feature-policy' ) ),
134 | esc_html__( 'Learn more about Feature Policy', 'feature-policy' ),
135 | /* translators: accessibility text */
136 | esc_html__( '(opens in a new tab)', 'feature-policy' )
137 | );
138 | ?>
139 |
140 |
141 |
146 |
147 | features->get_all();
159 | $option = $this->policies_setting->get();
160 |
161 | foreach ( $features as $feature ) {
162 | add_settings_field(
163 | $feature->name,
164 | $feature->title,
165 | function( $args ) use ( $feature, $option ) {
166 | $origin = isset( $option[ $feature->name ] ) ? $option[ $feature->name ][0] : $feature->default_origin;
167 | $this->render_field( $feature, $origin );
168 | },
169 | self::SLUG,
170 | 'default',
171 | array( 'label_for' => $feature->name )
172 | );
173 | }
174 | }
175 |
176 | /**
177 | * Renders the UI field for determining the status of a feature policy.
178 | *
179 | * @since 0.1.0
180 | *
181 | * @param Feature $feature Feature definition.
182 | * @param string $origin Origin set for the feature policy.
183 | */
184 | protected function render_field( Feature $feature, $origin ) {
185 | $choices = array(
186 | Feature::ORIGIN_ANY => __( 'Any', 'feature-policy' ),
187 | Feature::ORIGIN_SELF => __( 'Self', 'feature-policy' ),
188 | Feature::ORIGIN_NONE => __( 'None', 'feature-policy' ),
189 | );
190 |
191 | ?>
192 |
193 | $label ) {
195 | ?>
196 | >
197 |
198 | default_origin ) : ?>
199 |
200 |
201 |
202 |
205 |
206 |
294 | Copyright (C)
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | , 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------