WP Manifestindependent plugin directory
manifest / content / content-insights-for-editors

Content Insights for Editors WP Registry grade D+. High-severity findings · 4 findingsWP RegistryHigh-severity findings · 4 findingsOpen the reportD+

An easy way for content editors to keep track of their work and get notified when it is not working properly

★ 3stars
2.6kcomposer installs
1.2.3latest · 6 years ago

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/whitespace-se/content-insights-for-editors/archive/refs/heads/master.zip

On Packagist as municipio/content-insights-for-editors:

composer require municipio/content-insights-for-editors
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

An easy way for content editors to keep track of their work and get notified when it is not working properly

Content Insights for Editors is a WordPress plugin

Table of Contents

Usage

Prerequisites

Content Insights for Editors uses matomo for visitor statistics and helsingborg-stad/broken-link-detector for analysing content.

Installing

The package can be downloaded manually and unzipped in the /wp-content/plugins/ directory or by using composer.

Install by running the following command:

composer require municipio/content-insights-for-editors

Example of how composer works here

When resources have been installed. The plugin can be activated by looking for a "Content Insights for Editors" entry in the plugins page and clicking on "Activate".

Hooks

Here are the hooks for customizing the plugin

Set the mail logo url

cife_notification_mail_logo_url

Example usage

add_action('cife_notification_mail_logo_url', function ($currentLogo) {
  $logo = get_field('logotype', 'option');
  return wp_get_attachment_url($logo['id']);
});

Adding a section to mail notification

cife_notification_mail_list_sections

Example usage

add_action('cife_notification_mail_list_sections', function($sections){
    array_push($sections, [
        'section_header' => '', // string, Title rendered above section
        'list' => [
            [
                'url' => '', // string, list item url
                'title' => '', // string, list item title
                'value' => 0, // mixed, Value to display in the second column (OPTIONAL)
            ],
            ...
        ],
        'list_header' => ['title' => '', 'value' => ''], // array, Explaining list.title and list.value
        'no_items_text' => '', // string, Replace list if empty
    ]);
    return $sections;
});

Modify which section template to use during render

cife_notification_mail_render_section

Example usage

add_action('cife_notification_mail_list_sections', function (
  $template,
  $sectionVars
) {
  if (
    $_sectionVars['id'] === 'most-viewed' &&
    class_exists('\CustomerFeedback\App')
  ) {
    return CONTENT_INSIGHTS_FOR_EDITORS_MAIL_TEMPLATE_PATH .
      '/partials/section-3-cols-customer-feedback.template.php';
  }
  return $template; // Absolute php file path
});

Customizing content of mail notification

cife_notification_mail_vars

Exposed variables

'logo'  // string, Logourl showed in top of email
'intro_header' // string, Title showen in top of email
'intro_text' // string, Text showen in top of email
'button_cta_text' // string, NULL to hide
'button_cta_url' // string, NULL to hide

Example usage

add_action('cife_notification_mail_vars', function ($html_vars) {
  $html_vars['logo'] = "...";
  return $html_vars;
});

Develop

These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See Usage for notes on how to use the plugin in production.

Local prerequisites

Content Insights for Editors uses matomo for visitor statistics and helsingborg-stad/broken-link-detector for analysing content.

Local installation

The plugin can be installed with composer or by cloning this repo from github into the /wp-content/plugins/ directory of your WordPress installation.

With composer

Add this to your composer.json

"repositories": [
    {
        "type": "path",
        "url": "/my/local/path/content-insights-for-editors"
    },
    ...
]

"require": {
    ...
    "content-insights-for-editors": "dev-master"
},

And this to install helsingborg-stad/broken-link-detector

"repositories": [
    {
        "type": "vcs",
        "url": "git@github.com:helsingborg-stad/broken-link-detector.git",
        "no-api": true
    },
    ...
]

"require": {
    ...
    "helsingborg-stad/broken-link-detector": "^1.3",
},

Then run

composer install

Example of how composer works here

Contributing

  1. Fork it (https://github.com/yourname/yourproject/fork)
  2. Create your feature branch (git checkout -b feature/fooBar)
  3. Commit your changes (git commit -am 'Add some fooBar')
  4. Push to the branch (git push origin feature/fooBar)
  5. Create a new Pull Request

Versioning

We use SemVer for versioning. For the versions available, see the tags on this repository.

Authors

See the list of contributors who participated in this project.

License

This project is licensed under the MIT License - see the LICENSE.md file for details

Releases

5 releases.

Tag
Published
1.2.3 latest
Jun 29, 2020 6 years ago
Jun 29, 2020 6 years ago
Mar 29, 2020 6 years ago
Mar 29, 2020 6 years ago
Aug 26, 2019 7 years ago

These releases are tags only. The author does not attach a packaged zip, so there are no download counts to report.

D+ grade

Security

Content Insights for Editors 1.1.5 · audited by WP Registry

High-severity findings.

2 high 1 medium 1 low
Audited release
1.1.5
Findings
4
Worst severity
high
Content hash
be9e9aa3179e9716d8eda9aa…

Findings

  • high SQL injection via unsanitized ORDER BY in PostQuery::getListPosts

    sql_injection

    getListPosts() appends $_GET['orderby'] and $_GET['order'] into SQL after only esc_sql(). That is not an identifier allowlist; parentheses, commas, and function calls survive magic quotes and mysqli escaping. The query is executed from two admin surfaces: (1) Metabox::metaBoxMarkup on post.php/post-new.php — add_meta_box() is given Settings::getSelectedPostTypes(), which is false when analysed_post_types is unset, and WordPress then attaches the box to the current screen, so Contributor+ can open /wp-admin/post.php?post=ID&action=edit&orderby=(SLEEP(5)); (2) the manage_options list table (sortable columns). The JOIN to BrokenLinks::$dbTable must resolve (helsingborg-stad/broken-link-detector, a documented prerequisite) or MySQL errors before ORDER BY runs. Time-based and error-based payloads can read wp_users/wp_options; the list-table path also allows boolean extraction via sort order. Still present on GitHub master (plugin header 2.2.0).

    source/php/Util/PostQuery.php:113-121

    Recommendation

    Allowlist orderby to the known column aliases (length, modified, week_visitors, month_visitors, title) and order to ASC|DESC. Do not read $_GET inside a shared query helper used by the metabox. Use $wpdb->prepare() only for values, not identifiers.

  • high ACF settings submenu defaults to edit_posts; Contributor+ can steal Matomo token and SSRF the fetcher

    missing_capability

    acf_add_options_sub_page() is called without a capability argument. ACF's options-page default is capability => edit_posts, and acf_admin_options_page registers add_submenu_page(parent, ..., $page['capability'], 'content-insights-for-editors-page-settings'). WordPress then allows any edit_posts user to open admin.php?page=content-insights-for-editors-page-settings even though the parent menu is manage_options (the submenu is often hidden but the slug is guessable and is linked from the plugin's own admin_notices). ACF save on load-{$slug} only checks acf_verify_nonce('options') and then acf_save_post('options'). Fields include matomo_api_url (free text), matomo_api_key (token_auth), matomo_id_site, and use_broken_links_cron. Contributor can read the live Matomo token (visitor analytics / Matomo superuser API as documented in the field instructions) or point matomo_api_url at an internal/attacker URL. Matomo::request() concatenates that URL with token_auth and curl_exec()s it (SSL verify disabled, no timeout, no host allowlist) from daily cron and from the ungated AJAX trigger. Toggling use_broken_links_cron schedules cife_cron_mail, which emails every administrator, editor, and author. Parent menu manage_options does not protect this submenu.

    source/php/Admin/Settings.php:61-78

    Recommendation

    Pass 'capability' => 'manage_options' (and the same cap as the parent menu) into acf_add_options_sub_page(). Store the Matomo token in an auth-only field, restrict matomo_api_url to https hosts you expect, and do not treat edit_posts as sufficient to read site-wide API credentials.

  • medium wp_ajax_trigger_update_analytics has no capability check and no nonce

    missing_capability

    Main registers wp_ajax_trigger_update_analytics (logged-in only, no nopriv) pointing at triggerUpdateAnalytics(). The callback instantiates Matomo and calls updatePagesWeekAndMonth() with no current_user_can, check_ajax_referer, or wp_verify_nonce. Localized JS on the manage_options page posts {action: trigger_update_analytics} with no nonce field. Any Subscriber can POST /wp-admin/admin-ajax.php with that action; any logged-in user can also be CSRF'd from a third-party page. Effect: two curl requests to the configured Matomo URL (token_auth in the query string), then url_to_postid() over up to 2000 paths and upserts into {$wpdb->prefix}content_insights_for_editors. There is no CURLOPT_TIMEOUT, so a slow or Contributor-poisoned URL holds a PHP worker. Combined with the edit_posts ACF settings bug this is the SSRF trigger; on a default install it is a missing-authorization analytics refresh and worker DoS. GitHub master is unchanged.

    source/php/Admin/Main.php:17-20,204-217

    Recommendation

    Require current_user_can('manage_options') and check_ajax_referer before calling updatePagesWeekAndMonth(). Pass a nonce in wp_localize_script and include it in the POST body. Add a curl timeout and cap how often the job may run.

  • low Matomo fetcher disables TLS certificate verification and sends token_auth in the query string

    insecure_config

    Matomo::request() sets CURLOPT_SSL_VERIFYHOST and CURLOPT_SSL_VERIFYPEER to 0, then curl_execs $matomoUrl concatenated with urldecode(http_build_query($parameters)), which includes token_auth. A network attacker who can MITM the WordPress host's outbound HTTPS (or who already poisoned matomo_api_url to an http:// endpoint) can read the Matomo API token and the Actions.getPageUrls response (visitor paths). urldecode after http_build_query also reintroduces raw & in option values. This path is exercised by the Subscriber-reachable AJAX trigger and by the daily cron.

    source/php/Util/Matomo.php:145-157

    Recommendation

    Leave curl's default certificate verification on (or use wp_remote_get() which verifies TLS). Do not urldecode the built query string. Prefer Matomo's POST token_auth rather than putting the secret in the URL.

WP Registry hashes the installable build and reports on that exact bytes-for-bytes copy. Embargoed findings are withheld until they are disclosed, so a clean verdict means nothing public is outstanding. WP Manifest does not audit code itself.