diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..db0657a --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @Chrico \ No newline at end of file diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index c730791..354cc7c 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -1,8 +1,17 @@ name: E2E Testing -on: +on: workflow_dispatch: push: + branches: + - master + - 1.x + - 2.x + pull_request: + branches: + - master + - 1.x + - 2.x # Cancels all previous workflow runs for pull requests that have not completed. concurrency: diff --git a/.github/workflows/frontend-qa.yml b/.github/workflows/frontend-qa.yml index 94de774..ca464a4 100644 --- a/.github/workflows/frontend-qa.yml +++ b/.github/workflows/frontend-qa.yml @@ -1,7 +1,16 @@ name: Static code analysis assets -on: - push: +on: workflow_dispatch: + push: + branches: + - master + - 1.x + - 2.x + pull_request: + branches: + - master + - 1.x + - 2.x jobs: wp-scripts-lint: uses: inpsyde/reusable-workflows/.github/workflows/wp-scripts-lint.yml@main diff --git a/.github/workflows/php-qa.yml b/.github/workflows/php-qa.yml index bbda3a1..9bd8d3d 100644 --- a/.github/workflows/php-qa.yml +++ b/.github/workflows/php-qa.yml @@ -1,5 +1,16 @@ name: PHP Quality Assurance -on: [ push ] +on: + workflow_dispatch: + push: + branches: + - master + - 1.x + - 2.x + pull_request: + branches: + - master + - 1.x + - 2.x jobs: lint-php: uses: inpsyde/reusable-workflows/.github/workflows/lint-php.yml@main @@ -12,6 +23,11 @@ jobs: uses: inpsyde/reusable-workflows/.github/workflows/coding-standards-php.yml@main with: PHP_VERSION: '8.1' + static-code-analysis-php: + uses: inpsyde/reusable-workflows/.github/workflows/static-analysis-php.yml@main + with: + PSALM_ARGS: '--threads=3' + PHP_VERSION: '8.1' tests-unit-php: runs-on: ubuntu-latest if: "!contains(github.event.head_commit.message, 'ci skip')" diff --git a/README.md b/README.md index f94e7fd..0928184 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,10 @@ ## Documentation -Documentation can be found in [readme.txt](readme.txt). - -## Requirements - -* WordPress >= 4.6. -* PHP 8.0 or higher. +1. [Intro](./docs/01-intro.md) +2. [Hooks](./docs/02-hooks.md) +3. [Collectors](./docs/03-collectors.md) +4. [FAQ](./docs/99-faq.md) ## How to start development @@ -27,11 +25,9 @@ This plugin does not include build assets and PHP-dependencies. Therefore, after **With Yarn:** ```shell -yarn install && yarn build:dev +yarn install && yarn build ``` -For more information, please refer to the [Symfony Encore docs](https://symfony.com/doc/current/frontend.html#webpack-encore) - ## Testing & Quality To run all tests you've to install composer dev-dependencies first. @@ -48,8 +44,6 @@ vendor/bin/phpcs vendor/bin/phpunit ``` -This repository automatically generates a CodeCoverage-report into the `tmp/`-folder, which will not be committed. - ## How to create a release To create a release go to the `-built` branch and create the tag and the release. diff --git a/composer.json b/composer.json index 52165b9..a92904b 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,9 @@ "require-dev": { "phpunit/phpunit": "~10", "inpsyde/php-coding-standards": "2.0.0-beta.4", - "brain/monkey": "^2" + "brain/monkey": "^2", + "vimeo/psalm": ">=4.8.1@stable", + "php-stubs/wordpress-stubs": ">=6.6@stable" }, "autoload": { "psr-4": { diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..24d209d --- /dev/null +++ b/psalm.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/svn-assets/banner-1544x500.png b/resources/svn-assets/banner-1544x500.png index 5c5b7a4..da31f8e 100644 Binary files a/resources/svn-assets/banner-1544x500.png and b/resources/svn-assets/banner-1544x500.png differ diff --git a/resources/svn-assets/banner-1880x609.png b/resources/svn-assets/banner-1880x609.png index c76bb4d..91ba085 100644 Binary files a/resources/svn-assets/banner-1880x609.png and b/resources/svn-assets/banner-1880x609.png differ diff --git a/resources/svn-assets/banner-772x250.png b/resources/svn-assets/banner-772x250.png index 3fcd36f..164cc4d 100644 Binary files a/resources/svn-assets/banner-772x250.png and b/resources/svn-assets/banner-772x250.png differ diff --git a/resources/svn-assets/icon-128x128.png b/resources/svn-assets/icon-128x128.png index 8178298..90b435d 100644 Binary files a/resources/svn-assets/icon-128x128.png and b/resources/svn-assets/icon-128x128.png differ diff --git a/resources/svn-assets/icon-256x256.png b/resources/svn-assets/icon-256x256.png index 586b6a7..f45de53 100644 Binary files a/resources/svn-assets/icon-256x256.png and b/resources/svn-assets/icon-256x256.png differ diff --git a/src/DataLayer/DataLayer.php b/src/DataLayer/DataLayer.php index 596773b..22a92c1 100644 --- a/src/DataLayer/DataLayer.php +++ b/src/DataLayer/DataLayer.php @@ -95,6 +95,7 @@ public function enabledCollectors(): array public function data(): array { $data = []; + /** @var DataCollector $collector */ foreach ($this->registry->all() as $collector) { if (!in_array($collector->id(), $this->enabledCollectors(), true)) { continue; @@ -106,7 +107,10 @@ public function data(): array $settings = $collector->sanitize($settings); } - $data[$collector->id()] = $collector->data($settings); + $collectorData = $collector->data($settings); + if ($collectorData !== null) { + $data[$collector->id()] = $collectorData; + } } return $data; @@ -176,7 +180,6 @@ public function specification(): array 'label' => __('Enable collectors', 'inpsyde-google-tag-manager'), 'name' => self::SETTING_ENABLED_COLLECTORS, 'type' => 'checkbox', - 'value' => $this->enabledCollectors(), 'choices' => (function (): array { $choices = []; foreach ($this->registry->all() as $data) { diff --git a/src/DataLayer/PostDataCollector.php b/src/DataLayer/PostDataCollector.php index 961c413..9c0a32c 100644 --- a/src/DataLayer/PostDataCollector.php +++ b/src/DataLayer/PostDataCollector.php @@ -58,6 +58,7 @@ public function data(array $settings): ?array // Post data $fields = []; foreach ($settings[self::SETTING__POST_FIELDS] as $field) { + /** @psalm-suppress DocblockTypeContradiction, RedundantConditionGivenDocblockType */ $fields[$field] = get_post_field($field) ?? ''; } $fields = array_filter($fields); @@ -67,6 +68,7 @@ public function data(array $settings): ?array // Author data $fields = []; foreach ($settings[self::SETTING__AUTHOR_FIELDS] as $field) { + /** @psalm-suppress DocblockTypeContradiction, RedundantConditionGivenDocblockType */ $fields[$field] = get_the_author_meta($field) ?? ''; } $fields = array_filter($fields); @@ -89,7 +91,6 @@ public function specification(): array 'label' => __('Post fields used in dataLayer', 'inpsyde-google-tag-manager'), 'name' => self::SETTING__POST_FIELDS, 'type' => 'checkbox', - 'value' => $this->settings[self::SETTING__POST_FIELDS], 'choices' => [ [ 'label' => __('ID', 'inpsyde-google-tag-manager'), @@ -166,7 +167,6 @@ public function specification(): array ), 'name' => self::SETTING__AUTHOR_FIELDS, 'type' => 'checkbox', - 'value' => $this->settings[self::SETTING__AUTHOR_FIELDS], 'choices' => [ [ 'label' => __('ID', 'inpsyde-google-tag-manager'), diff --git a/src/DataLayer/UserDataCollector.php b/src/DataLayer/UserDataCollector.php index 1364078..9a33002 100644 --- a/src/DataLayer/UserDataCollector.php +++ b/src/DataLayer/UserDataCollector.php @@ -51,9 +51,6 @@ public function description(): string ); } - /** - * {@inheritdoc} - */ public function data(array $settings): ?array { $isLoggedIn = is_user_logged_in(); diff --git a/src/Provider/AssetProvider.php b/src/Provider/AssetProvider.php index 778601a..a172a92 100644 --- a/src/Provider/AssetProvider.php +++ b/src/Provider/AssetProvider.php @@ -33,6 +33,9 @@ public function run(ContainerInterface $container): bool $properties = $container->get(Package::PROPERTIES); $screen = get_current_screen(); + if ($screen === null) { + return; + } if ($screen->base !== 'settings_page_' . $properties->baseName()) { return; } diff --git a/src/Provider/DataLayerProvider.php b/src/Provider/DataLayerProvider.php index f770d92..3c0ccf3 100644 --- a/src/Provider/DataLayerProvider.php +++ b/src/Provider/DataLayerProvider.php @@ -36,26 +36,10 @@ public function services(): array $container->get(DataCollectorRegistry::class), ); }, - UserDataCollector::class => static function (ContainerInterface $container): UserDataCollector { - $settingsRepository = $container->get(SettingsRepository::class); - - return UserDataCollector::new($settingsRepository->option(UserDataCollector::ID)); - }, - SiteInfoDataCollector::class => static function (ContainerInterface $container): SiteInfoDataCollector { - $settingsRepository = $container->get(SettingsRepository::class); - - return SiteInfoDataCollector::new($settingsRepository->option(SiteInfoDataCollector::ID)); - }, - PostDataCollector::class => static function (ContainerInterface $container): PostDataCollector { - $settingsRepository = $container->get(SettingsRepository::class); - - return PostDataCollector::new($settingsRepository->option(PostDataCollector::ID)); - }, - SearchDataCollector::class => static function (ContainerInterface $container): SearchDataCollector { - $settingsRepository = $container->get(SettingsRepository::class); - - return SearchDataCollector::new($settingsRepository->option(SearchDataCollector::ID)); - }, + UserDataCollector::class => [UserDataCollector::class, 'new'], + SiteInfoDataCollector::class => [SiteInfoDataCollector::class, 'new'], + PostDataCollector::class => [PostDataCollector::class, 'new'], + SearchDataCollector::class => [SearchDataCollector::class, 'new'], ]; } diff --git a/src/Provider/SettingsProvider.php b/src/Provider/SettingsProvider.php index 446f619..ff7ef6c 100644 --- a/src/Provider/SettingsProvider.php +++ b/src/Provider/SettingsProvider.php @@ -4,7 +4,6 @@ namespace Inpsyde\GoogleTagManager\Provider; -use Inpsyde\GoogleTagManager\Settings\SettingsPage; use Inpsyde\GoogleTagManager\Settings\SettingsRepository; use Inpsyde\Modularity\Module\ExecutableModule; use Inpsyde\Modularity\Module\ModuleClassNameIdTrait; @@ -30,12 +29,6 @@ public function services(): array return SettingsRepository::new($properties->textDomain()); }, - SettingsPage::class => static function (ContainerInterface $container): SettingsPage { - /** @var PluginProperties $properties */ - $properties = $container->get(Package::PROPERTIES); - - return SettingsPage::new($properties); - }, ]; } diff --git a/src/Renderer/DataLayerRenderer.php b/src/Renderer/DataLayerRenderer.php index 2b94813..a0769b0 100644 --- a/src/Renderer/DataLayerRenderer.php +++ b/src/Renderer/DataLayerRenderer.php @@ -36,6 +36,7 @@ public function render(): bool $dataLayerJs = sprintf('var %1$s = %1$s || [];', esc_js($dataLayerName)); foreach ($dataLayerPushData as $data) { + /** @psalm-suppress DocblockTypeContradiction */ if (!is_array($data) || count($data) < 1) { continue; } @@ -43,7 +44,7 @@ public function render(): bool $dataLayerJs .= sprintf( '%1$s.push(%2$s);', esc_js($dataLayerName), - wp_json_encode($data) + (string) wp_json_encode($data) ); } diff --git a/src/Rest/DataLayerEndpoint.php b/src/Rest/DataLayerEndpoint.php index 8fcb479..746fe5b 100644 --- a/src/Rest/DataLayerEndpoint.php +++ b/src/Rest/DataLayerEndpoint.php @@ -4,6 +4,7 @@ namespace Inpsyde\GoogleTagManager\Rest; +use Inpsyde\GoogleTagManager\DataLayer\DataCollector; use Inpsyde\GoogleTagManager\DataLayer\DataLayer; use Inpsyde\GoogleTagManager\Service\DataCollectorRegistry; use Inpsyde\GoogleTagManager\Settings\SettingsRepository; @@ -85,6 +86,7 @@ public function updateDataLayer(\WP_REST_Request $request): \WP_REST_Response $settings[$this->dataLayer->id()] = $dataLayerSettings; } + /** @var DataCollector $collector */ foreach ($this->registry->all() as $collector) { if (!$collector instanceof SettingsSpecification) { unset($settings[$collector->id()]); diff --git a/src/Service/DataCollectorRegistry.php b/src/Service/DataCollectorRegistry.php index 969c56a..eac2938 100644 --- a/src/Service/DataCollectorRegistry.php +++ b/src/Service/DataCollectorRegistry.php @@ -35,25 +35,4 @@ public function all(): array { return $this->collectors; } - - public function allFormFields(): array - { - $fields = []; - foreach ($this->all() as $collector) { - if (!$collector instanceof SettingsSpecification) { - continue; - } - $fields[] = [ - 'label' => $collector->name(), - 'description' => $collector->description(), - 'attributes' => [ - 'name' => $collector->id(), - 'type' => 'collection', - ], - 'elements' => $collector->settingsSpec(), - ]; - } - - return $fields; - } } diff --git a/src/Service/RestEndpointRegistry.php b/src/Service/RestEndpointRegistry.php index c1502b9..1c8abac 100644 --- a/src/Service/RestEndpointRegistry.php +++ b/src/Service/RestEndpointRegistry.php @@ -52,9 +52,10 @@ public function addEndpoint(RestEndpoint $endpoint): void foreach ($args as $arg) { $name = $arg['entityName'] ?? ''; $baseUrl = $arg['entityBaseUrl'] ?? ''; - if (!$name || !$baseUrl) { + if ($name === '' || $baseUrl === '') { continue; } + /** @psalm-suppress InvalidPropertyAssignmentValue */ $this->entities[$name] = [ 'label' => (string) $arg['label'], 'name' => (string) $name, @@ -74,7 +75,7 @@ public function addEndpoint(RestEndpoint $endpoint): void public function register(): bool { foreach ($this->endpoints as $base => $endpoint) { - if ($this->registered[$base] ?? false) { + if (isset($this->registered[$base])) { continue; } foreach ($endpoint->routes() as $route => $args) {