Basic release
This commit is contained in:
Binary file not shown.
@ -0,0 +1,97 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pfadfinden-theme-updater\n"
|
||||
"POT-Creation-Date: 2015-08-26 01:49+0100\n"
|
||||
"PO-Revision-Date: 2015-08-26 02:02+0100\n"
|
||||
"Last-Translator: Philipp Cordes <philipp.cordes@pfadfinden.de>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: de_DE\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 1.6.10\n"
|
||||
"X-Poedit-Basepath: ..\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Poedit-KeywordsList: __;_e;_x;esc_html_e;esc_html__;esc_attr_e;esc_attr__;_ex:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2;_x:1,2c;_n:1,2;_n_noop:1,2;__ngettext_noop:1,2;_c,_nc:4c,1,2;\n"
|
||||
"X-Poedit-SearchPath-0: .\n"
|
||||
|
||||
#: pfadfinden-theme-updater.php:70
|
||||
msgid ""
|
||||
"Couldn’t load required library “shy-wordpress”. Reinstalling the plugin may "
|
||||
"solve this problem."
|
||||
msgstr ""
|
||||
"Konnte die erforderliche Bibliothek „shy-wordpress“ nicht laden. "
|
||||
"Neuinstallation des Plugins sollte das Problem beheben."
|
||||
|
||||
#: pfadfinden-theme-updater.php:81
|
||||
msgid "The plugin is incomplete. Reinstalling it may solve this problem."
|
||||
msgstr ""
|
||||
"Das Plugin ist unvollständig. Neuinstallation sollte das Problem beheben."
|
||||
|
||||
#: pfadfinden-theme-updater.php:96
|
||||
#, php-format
|
||||
msgid ""
|
||||
"You need at least PHP 5.4 to use Pfadfinden Theme Updater. Your are using %s."
|
||||
msgstr ""
|
||||
"Du brauchst mindestens PHP 5.4, um den Pfadfinden-Theme-Updater zu benutzen. "
|
||||
"Aktuell benutzt du PHP %s."
|
||||
|
||||
#: pfadfinden-theme-updater.php:104
|
||||
msgid "Pfadfinden Theme Updater"
|
||||
msgstr "Pfadfinden-Theme-Updater"
|
||||
|
||||
#: pfadfinden-theme-updater.php:105
|
||||
msgid ""
|
||||
"Adds the Pfadfinden theme repository to your choice of themes. Requires an "
|
||||
"API key."
|
||||
msgstr ""
|
||||
"Fügt den Pfadfinden-Theme-Katalog zu Deiner Auswahl an Themes hinzu. "
|
||||
"Benötigt einen API-Schlüssel."
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeRepository.php:81
|
||||
msgid "Your theme repository query is too long."
|
||||
msgstr "Deine Anfrage an den Theme-Katalog ist zu lang."
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeRepository.php:114
|
||||
msgid "Unknown theme repository server error, no message attached."
|
||||
msgstr ""
|
||||
"Unbekannter Theme-Katalog-Serverfehler, keine Fehlerbeschreibung "
|
||||
"mitgeschickt."
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeRepository.php:186
|
||||
msgid "Ambiguous result for single theme information call."
|
||||
msgstr "Mehrere Ergebnisse für Abfrage nach Informationen zu einem Theme."
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:69
|
||||
msgid "Pfadfinden Theme Updater Settings"
|
||||
msgstr "Pfadfinden-Theme-Updater-Einstellungen"
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:74
|
||||
msgid "Pfadfinden Updater"
|
||||
msgstr "Pfadfinden-Updater"
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:84
|
||||
msgid "API Key"
|
||||
msgstr "API-Schlüssel"
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:89
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:116
|
||||
msgid "An API key consists of 10 alphanumeric characters."
|
||||
msgstr "Ein API-Schlüssel besteht aus zehn alphanumerischen Zeichen."
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:96
|
||||
msgid "Keep Settings"
|
||||
msgstr "Einstellungen merken"
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:97
|
||||
msgid "Don’t delete settings when uninstalling the plugin."
|
||||
msgstr "Einstellungen nicht löschen, wenn das Plugin deinstalliert wird."
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:107
|
||||
msgid "Just testing? Try APITESTKEY."
|
||||
msgstr ""
|
||||
"Nur Ausprobieren? Nimm APITESTKEY. Aber BdP-Themes gibt es damit nicht…"
|
||||
|
||||
#~ msgid "Activated Features"
|
||||
#~ msgstr "Aktivierte Funktionen"
|
@ -0,0 +1,84 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pfadfinden-theme-updater\n"
|
||||
"POT-Creation-Date: 2015-08-26 01:49+0100\n"
|
||||
"PO-Revision-Date: 2015-08-26 01:50+0100\n"
|
||||
"Last-Translator: Philipp Cordes <philipp.cordes@pfadfinden.de>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: de_DE\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 1.6.10\n"
|
||||
"X-Poedit-Basepath: ..\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Poedit-KeywordsList: __;_e;_x;esc_html_e;esc_html__;esc_attr_e;esc_attr__;_ex:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2;_x:1,2c;_n:1,2;_n_noop:1,2;__ngettext_noop:1,2;_c,_nc:4c,1,2;\n"
|
||||
"X-Poedit-SearchPath-0: .\n"
|
||||
|
||||
#: pfadfinden-theme-updater.php:70
|
||||
msgid ""
|
||||
"Couldn’t load required library “shy-wordpress”. Reinstalling the plugin may "
|
||||
"solve this problem."
|
||||
msgstr ""
|
||||
|
||||
#: pfadfinden-theme-updater.php:81
|
||||
msgid "The plugin is incomplete. Reinstalling it may solve this problem."
|
||||
msgstr ""
|
||||
|
||||
#: pfadfinden-theme-updater.php:96
|
||||
#, php-format
|
||||
msgid ""
|
||||
"You need at least PHP 5.4 to use Pfadfinden Theme Updater. Your are using %s."
|
||||
msgstr ""
|
||||
|
||||
#: pfadfinden-theme-updater.php:104
|
||||
msgid "Pfadfinden Theme Updater"
|
||||
msgstr ""
|
||||
|
||||
#: pfadfinden-theme-updater.php:105
|
||||
msgid ""
|
||||
"Adds the Pfadfinden theme repository to your choice of themes. Requires an "
|
||||
"API key."
|
||||
msgstr ""
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeRepository.php:81
|
||||
msgid "Your theme repository query is too long."
|
||||
msgstr ""
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeRepository.php:114
|
||||
msgid "Unknown theme repository server error, no message attached."
|
||||
msgstr ""
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeRepository.php:186
|
||||
msgid "Ambiguous result for single theme information call."
|
||||
msgstr ""
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:69
|
||||
msgid "Pfadfinden Theme Updater Settings"
|
||||
msgstr ""
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:74
|
||||
msgid "Pfadfinden Updater"
|
||||
msgstr ""
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:84
|
||||
msgid "API Key"
|
||||
msgstr ""
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:89
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:116
|
||||
msgid "An API key consists of 10 alphanumeric characters."
|
||||
msgstr ""
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:96
|
||||
msgid "Keep Settings"
|
||||
msgstr ""
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:97
|
||||
msgid "Don’t delete settings when uninstalling the plugin."
|
||||
msgstr ""
|
||||
|
||||
#: src/Pfadfinden/WordPress/ThemeUpdaterSettings.php:107
|
||||
msgid "Just testing? Try APITESTKEY."
|
||||
msgstr ""
|
149
plugins/pfadfinden-theme-updater/pfadfinden-theme-updater.php
Normal file
149
plugins/pfadfinden-theme-updater/pfadfinden-theme-updater.php
Normal file
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
/*
|
||||
Plugin Name: Pfadfinden Theme Updater
|
||||
Plugin URI: http://lab.hanseaten-bremen.de/themes/
|
||||
Description: Adds the Pfadfinden theme repository to your choice of themes. Requires an API key.
|
||||
Version: 0.2
|
||||
Author: Philipp Cordes
|
||||
Text Domain: pfadfinden-theme-updater
|
||||
Domain Path: /languages/
|
||||
License: GPLv2 or later
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'I’m a plugin.' );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load localized strings for the plugin.
|
||||
*
|
||||
* @see http://geertdedeckere.be/article/loading-wordpress-language-files-the-right-way
|
||||
*/
|
||||
function pfadfinden_theme_updater_load_textdomain()
|
||||
{
|
||||
remove_action( 'init', __FUNCTION__ );
|
||||
|
||||
$domain = 'pfadfinden-theme-updater';
|
||||
// Filter known from load_plugin_textdomain().
|
||||
$locale = apply_filters( 'plugin_locale', get_locale(), $domain );
|
||||
|
||||
load_textdomain( $domain, WP_LANG_DIR . "/pfadfinden-theme-updater/$domain-$locale.mo" );
|
||||
load_plugin_textdomain( $domain, false, basename( __DIR__ ) . '/languages/' );
|
||||
}
|
||||
add_action( 'init', 'pfadfinden_theme_updater_load_textdomain' );
|
||||
|
||||
|
||||
if ( ! function_exists( 'trigger_pfadfinden_plugin_error' ) ) {
|
||||
/**
|
||||
* Show an error message.
|
||||
*
|
||||
* @see http://www.squarepenguin.com/wordpress/?p=6 Inspiration
|
||||
*
|
||||
* @param string $message
|
||||
* @param int $type optional
|
||||
* @return bool
|
||||
*/
|
||||
function trigger_pfadfinden_plugin_error( $message, $type = 0 )
|
||||
{
|
||||
if ( isset( $_GET['action'] ) && 'error_scrape' === $_GET['action'] ) {
|
||||
echo $message;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! $type ) {
|
||||
$type = E_USER_WARNING;
|
||||
}
|
||||
|
||||
return trigger_error( $message, $type );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check for suitable environment
|
||||
if ( defined( 'PHP_VERSION_ID' ) && PHP_VERSION_ID >= 50400 ) {
|
||||
// If we’re the first user of the library, use the bundled one
|
||||
if ( ! class_exists( 'Shy\WordPress\Plugin' ) ) {
|
||||
pfadfinden_theme_updater_load_textdomain();
|
||||
if ( ! include_once __DIR__ . '/use/shy-wordpress/src/autoloader.php' ) {
|
||||
trigger_pfadfinden_plugin_error(
|
||||
__( 'Couldn’t load required library “shy-wordpress”. Reinstalling the plugin may solve this problem.', 'pfadfinden-theme-updater' ),
|
||||
E_USER_ERROR
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Register our autoloader
|
||||
if ( ! include_once __DIR__ . '/src/autoloader.php' ) {
|
||||
pfadfinden_theme_updater_load_textdomain();
|
||||
trigger_pfadfinden_plugin_error(
|
||||
__( 'The plugin is incomplete. Reinstalling it may solve this problem.', 'pfadfinden-theme-updater' ),
|
||||
E_USER_ERROR
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// PHP < 5.3 issues a parse error if we instance the class here
|
||||
return require_once __DIR__ . '/startup.php';
|
||||
}
|
||||
|
||||
|
||||
// Display error message
|
||||
pfadfinden_theme_updater_load_textdomain();
|
||||
trigger_pfadfinden_plugin_error(
|
||||
sprintf(
|
||||
__( 'You need at least PHP 5.4 to use Pfadfinden Theme Updater. Your are using %s.', 'pfadfinden-theme-updater' ),
|
||||
PHP_VERSION
|
||||
),
|
||||
E_USER_ERROR
|
||||
);
|
||||
|
||||
if ( false ) {
|
||||
// Dummy calls for translation to include metadata in translation files
|
||||
__( 'Pfadfinden Theme Updater', 'pfadfinden-theme-updater' );
|
||||
__( 'Adds the Pfadfinden theme repository to your choice of themes. Requires an API key.', 'pfadfinden-theme-updater' );
|
||||
}
|
||||
|
||||
class Nginx {
|
||||
|
||||
private $plugin = 'nginx-helper/nginx-helper.php';
|
||||
private $pluginPath = ABSPATH . 'wp-content/plugins/nginx-helper/nginx-helper.php';
|
||||
|
||||
public function __construct() {
|
||||
if(is_readable($this->pluginPath)) {
|
||||
require_once(ABSPATH .'/wp-admin/includes/plugin.php');
|
||||
$this->activatePlugin();
|
||||
$this->loadCss();
|
||||
}
|
||||
}
|
||||
|
||||
private function activatePlugin() {
|
||||
if( is_plugin_active( $this->plugin ) && get_option('cloudpit_nginx_activated_once') == 1 ) {
|
||||
//if the plugin is active already and our option is set, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
if( !is_plugin_active( $this->plugin ) && get_option('cloudpit_nginx_activated_once') == 1 ) {
|
||||
//if the plugin is deactivated on purpuse after installation, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
activate_plugin($this->pluginPath);
|
||||
|
||||
$options = 'a:23:{s:12:"enable_purge";s:1:"1";s:12:"cache_method";s:14:"enable_fastcgi";s:12:"purge_method";s:11:"get_request";s:10:"enable_map";N;s:10:"enable_log";N;s:9:"log_level";s:4:"INFO";s:12:"log_filesize";s:1:"5";s:12:"enable_stamp";N;s:22:"purge_homepage_on_edit";s:1:"1";s:21:"purge_homepage_on_del";s:1:"1";s:21:"purge_archive_on_edit";s:1:"1";s:20:"purge_archive_on_del";s:1:"1";s:28:"purge_archive_on_new_comment";N;s:32:"purge_archive_on_deleted_comment";N;s:17:"purge_page_on_mod";s:1:"1";s:25:"purge_page_on_new_comment";s:1:"1";s:29:"purge_page_on_deleted_comment";s:1:"1";s:14:"redis_hostname";s:9:"127.0.0.1";s:10:"redis_port";s:4:"6379";s:12:"redis_prefix";s:12:"nginx-cache:";s:9:"purge_url";s:0:"";s:25:"redis_enabled_by_constant";i:0;s:28:"smart_http_expire_form_nonce";s:10:"87a3b2c240";}';
|
||||
add_option('rt_wp_nginx_helper_options', unserialize($options));
|
||||
|
||||
if(!get_option('cloudpit_nginx_activated_once')) {
|
||||
add_option('cloudpit_nginx_activated_once', 1);
|
||||
}
|
||||
}
|
||||
|
||||
private function loadCss() {
|
||||
if( !is_plugin_active( $this->plugin ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_style('cloudpit-css', plugin_dir_url( __FILE__ ) . 'assets/style.css',array(), filemtime(plugin_dir_path( __FILE__ ) . 'assets/style.css'));
|
||||
}
|
||||
}
|
7
plugins/pfadfinden-theme-updater/phpunit.xml.dist
Normal file
7
plugins/pfadfinden-theme-updater/phpunit.xml.dist
Normal file
@ -0,0 +1,7 @@
|
||||
<phpunit bootstrap="tests/bootstrap.php">
|
||||
<testsuites>
|
||||
<testsuite>
|
||||
<directory suffix="Test.php" phpVersion="5.4.0">tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
31
plugins/pfadfinden-theme-updater/readme.txt
Normal file
31
plugins/pfadfinden-theme-updater/readme.txt
Normal file
@ -0,0 +1,31 @@
|
||||
=== Pfadfinden Theme Updater ===
|
||||
Contributors: Corphi
|
||||
Tags: themes
|
||||
Requires at least: 4.0
|
||||
Tested up to: 4.3
|
||||
Stable tag: trunk
|
||||
License: GPLv2 or later
|
||||
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
This plugin allows for easy installation of BdP e.V. corporate design themes. If you <a href="http://lab.hanseaten-bremen.de/register/">have an API key</a>.
|
||||
|
||||
== Description ==
|
||||
|
||||
This plugins makes all corporate design themes of the BdP e.V. available to your WordPress installation.
|
||||
|
||||
== Installation ==
|
||||
|
||||
1. Install the plugin from the plugin repository.
|
||||
1. Activate the plugin through the 'Plugins' menu in WordPress.
|
||||
1. Get an API key from http://lab.hanseaten-bremen.de/register/.
|
||||
1. Enter the API key in the setting section.
|
||||
1. Browse the additional featured themes.
|
||||
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 0.2 =
|
||||
* Users of PHP versions below 5.3 should now get reasonable error messages.
|
||||
|
||||
= 0.1 =
|
||||
* Initial release.
|
@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace Pfadfinden\WordPress;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A theme repository.
|
||||
*
|
||||
* It’s a simple wrapper around a web service mimicking the wordpress.org theme repository.
|
||||
*
|
||||
* @author Philipp Cordes <philipp.cordes@pfadfinden.de>
|
||||
*/
|
||||
class ThemeRepository
|
||||
{
|
||||
const URL = 'http://lab.hanseaten-bremen.de/themes/api/';
|
||||
|
||||
|
||||
/**
|
||||
* Slugs of managed themes.
|
||||
*
|
||||
* FIXME: Move to a transient.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
private $known_themes = [ 'bdp-reloaded', 'bdp-test', 'buena' ];
|
||||
|
||||
|
||||
/**
|
||||
* @var ThemeUpdaterSettings
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
|
||||
public function __construct( ThemeUpdaterSettings $settings )
|
||||
{
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Whether theme information is available.
|
||||
*
|
||||
* @param string $theme_slug
|
||||
* @return bool
|
||||
*/
|
||||
public function isKnownTheme( $theme_slug )
|
||||
{
|
||||
return in_array( $theme_slug, $this->known_themes, true );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper around HTTP calls, always returns an array of theme information.
|
||||
*
|
||||
* @param string $action One of the supported actions of the repository
|
||||
* @param array $params Parameters for the action
|
||||
* @param string $locale
|
||||
* @return array<object>|\WP_Error
|
||||
*/
|
||||
protected function doApiQuery( $action, array $params = [], $locale = '' )
|
||||
{
|
||||
$url_params = [
|
||||
'key' => $this->settings['key'],
|
||||
'action' => $action,
|
||||
];
|
||||
if ( $params ) {
|
||||
if ( function_exists( 'gzcompress' ) ) {
|
||||
$url_params['gzparams'] = gzcompress( json_encode( $params ), 9 );
|
||||
} else {
|
||||
$url_params['params'] = json_encode( $params );
|
||||
}
|
||||
}
|
||||
$url_params = array_map( 'rawurlencode', $url_params );
|
||||
|
||||
$url = add_query_arg( $url_params, self::URL );
|
||||
if ( strlen( $url ) > 2000 ) {
|
||||
// Lengths beyond 2000 seem unhealthy.
|
||||
return new \WP_Error(
|
||||
815,
|
||||
__( 'Your theme repository query is too long.', 'pfadfinden-theme-updater' )
|
||||
);
|
||||
}
|
||||
|
||||
$headers = [];
|
||||
if ( ! strlen( $locale ) ) {
|
||||
$locale = get_locale();
|
||||
}
|
||||
if ( strlen( $locale ) ) {
|
||||
$locale = str_replace( '_', '-', $locale );
|
||||
$headers['Accept-Language'] = "$locale, en; q=0.6, *; q=0.1";
|
||||
}
|
||||
|
||||
// A GET request allows for caching
|
||||
$response = wp_remote_get( $url, [
|
||||
'headers' => $headers,
|
||||
] );
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$body = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
if ( isset( $body['type'] ) && 'success' === $body['type'] ) {
|
||||
return array_map( function ( array $theme ) {
|
||||
return (object) $theme;
|
||||
}, $body['themes'] );
|
||||
}
|
||||
|
||||
if ( WP_DEBUG ) {
|
||||
trigger_error( wp_remote_retrieve_body( $response ), E_USER_ERROR );
|
||||
}
|
||||
$error = new \WP_Error(
|
||||
wp_remote_retrieve_response_code( $response ),
|
||||
isset( $body['message'] ) ? $body['message'] : __( 'Unknown theme repository server error, no message attached.', 'pfadfinden-theme-updater' )
|
||||
);
|
||||
if ( isset( $body['exception'] ) ) {
|
||||
$error->add_data( $body['exception'] );
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array<bool> $fields to explicitly include or exclude
|
||||
* @param string $locale
|
||||
* @return array<object {
|
||||
* @type string $name
|
||||
* @type string $slug lowercase, hyphenated
|
||||
* @type string $version
|
||||
* @type string $author
|
||||
* @type string $preview_url
|
||||
* @type string $screenshot_url
|
||||
* @type float $rating between 0 and 100
|
||||
* @type int $num_ratings
|
||||
* @type int $downloaded
|
||||
* @type string $last_updated Y-m-d
|
||||
* @type string $homepage
|
||||
* @type string $description
|
||||
* @type array $tags
|
||||
* }>
|
||||
*/
|
||||
public function queryFeaturedThemes( array $fields = [], $locale = '' )
|
||||
{
|
||||
return $this->doApiQuery( 'featured', [ 'fields' => $fields ], $locale );
|
||||
}
|
||||
|
||||
/**
|
||||
* Query information about a specific theme.
|
||||
*
|
||||
* @param string|array $slugs theme slug(s)
|
||||
* @param array<bool> $fields to explicitly include or exclude
|
||||
* @param string $locale
|
||||
* @return object {
|
||||
* @type string $name
|
||||
* @type string $slug
|
||||
* @type string $version
|
||||
* @type string $author
|
||||
* @type string $preview_url
|
||||
* @type string $screenshot_url
|
||||
* @type float $rating between 0.0 and 100.0
|
||||
* @type int $num_ratings
|
||||
* @type int $downloaded
|
||||
* @type string $last_updated
|
||||
* @type string $homepage
|
||||
* @type array $sections {
|
||||
* @type string $description
|
||||
* }
|
||||
* @type string $description empty string when having sections
|
||||
* @type string $download_link
|
||||
* @type array<string> $tags keys are tag slugs, values also lowercase. strange.
|
||||
* }
|
||||
*/
|
||||
public function queryThemeInformation( $slugs, array $fields = [], $locale = '' )
|
||||
{
|
||||
$themes = $this->doApiQuery( 'information', [
|
||||
'slugs' => (array) $slugs,
|
||||
'fields' => $fields,
|
||||
], $locale );
|
||||
if ( is_wp_error( $themes ) ) {
|
||||
return $themes;
|
||||
}
|
||||
|
||||
if ( is_string( $slugs ) ) {
|
||||
if ( count( $themes ) !== 1 ) {
|
||||
return new \WP_Error( __( 'Ambiguous result for single theme information call.', 'pfadfinden-theme-updater' ) );
|
||||
}
|
||||
|
||||
return reset( $themes );
|
||||
}
|
||||
|
||||
return $themes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query information about updates for installed themes.
|
||||
*
|
||||
* @param array<bool> $fields to explicitly include or exclude
|
||||
* @param string $locale
|
||||
* @return array<object>
|
||||
*/
|
||||
public function queryUpdates( array $fields = [], $locale = '' )
|
||||
{
|
||||
// FIXME: Only include installed themes
|
||||
return $this->queryThemeInformation( $this->known_themes, $fields, $locale );
|
||||
}
|
||||
}
|
@ -0,0 +1,231 @@
|
||||
<?php
|
||||
|
||||
namespace Pfadfinden\WordPress;
|
||||
|
||||
use Shy\WordPress\Plugin;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A plugin that hooks the Pfadfinden theme repository into the Theme Updater.
|
||||
*
|
||||
* It knows about the way that WordPress handles and stores theme information.
|
||||
*
|
||||
* @author Philipp Cordes <philipp.cordes@pfadfinden.de>
|
||||
*/
|
||||
class ThemeUpdaterPlugin extends Plugin
|
||||
{
|
||||
const ACTION_QUERY_THEMES = 'query_themes';
|
||||
const ACTION_FEATURE_LIST = 'feature_list';
|
||||
const ACTION_THEME_INFORMATION = 'theme_information';
|
||||
|
||||
|
||||
/**
|
||||
* @var ThemeUpdaterSettings
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* @var ThemeRepository
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->settings = new ThemeUpdaterSettings();
|
||||
|
||||
if ( ! $this->settings['key'] ) {
|
||||
// Bail out if there is no key.
|
||||
return;
|
||||
}
|
||||
|
||||
$this->repository = new ThemeRepository( $this->settings );
|
||||
|
||||
|
||||
$this->addHookMethod( 'themes_api', 'filterApiCall' );
|
||||
$this->addHookMethod( 'themes_api_result', 'filterApiResult' );
|
||||
|
||||
$this->addHookMethod( 'themes_update_check_locales', 'filterThemeUpdateLocales' );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replace a Theme API call.
|
||||
*
|
||||
* Actually, only the call for theme information in special cases.
|
||||
*
|
||||
* @param \WP_Error|object|false $result
|
||||
* @param string $action 'theme_information', 'feature_list' or 'query_themes'
|
||||
* @param object $args
|
||||
* @return \WP_Error|object|array|false
|
||||
*/
|
||||
public function filterApiCall( $result, $action, $args )
|
||||
{
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ( self::ACTION_THEME_INFORMATION === $action
|
||||
&& $this->repository->isKnownTheme( $args->slug )
|
||||
) {
|
||||
// Only handle our theme information calls
|
||||
return $this->repository->queryThemeInformation( $args->slug, $args->fields, $args->locale );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a Theme API result.
|
||||
*
|
||||
* Inject our themes at appropriate places.
|
||||
*
|
||||
* @param object|\WP_Error $result
|
||||
* @param string $action 'theme_information', 'feature_list', 'query_themes'
|
||||
* @param object|array $args An array after using built-in API, object otherwise.
|
||||
* @return object
|
||||
*/
|
||||
public function filterApiResult( $result, $action, $args )
|
||||
{
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// FIXME: Workaround to be removed on 2015-10-23
|
||||
if ( is_array( $args ) && isset( $args['body']['request'] ) ) {
|
||||
// See https://core.trac.wordpress.org/ticket/29079, fixed in 4.2
|
||||
$args = unserialize( $args['body']['request'] ); // Unpack original args
|
||||
}
|
||||
|
||||
if ( self::ACTION_QUERY_THEMES !== $action || ! isset( $args->browse ) || 'featured' !== $args->browse ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ( ! $result || ! is_object( $result ) ) {
|
||||
// Construct empty result
|
||||
// FIXME: Maybe unneccessary
|
||||
$result = (object) [
|
||||
'info' => [
|
||||
'page' => 1,
|
||||
'pages' => 0,
|
||||
'results' => false,
|
||||
],
|
||||
'themes' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$themes = $this->repository->queryFeaturedThemes( $args->fields, $args->locale );
|
||||
if ( ! is_wp_error( $themes ) ) {
|
||||
$this->spliceThemes( $result, $themes );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splice additional themes into an existing Theme API result.
|
||||
*
|
||||
* Put them in front.
|
||||
*
|
||||
* @param object $result {
|
||||
* @type object $info {
|
||||
* @type integer|false $results have browser count if false
|
||||
* @type integer|string $page
|
||||
* @type integer $pages may be 0
|
||||
* }
|
||||
* @type array $themes
|
||||
* }
|
||||
* @param array $themes
|
||||
* @return void
|
||||
*/
|
||||
public function spliceThemes( $result, array $themes )
|
||||
{
|
||||
$add = function ( $number, $increment ) {
|
||||
return is_integer( $number ) ? $number + $increment : $number;
|
||||
};
|
||||
|
||||
if ( is_array( $result->info ) ) {
|
||||
$result->info['results'] = $add( $result->info['results'], count( $themes ) );
|
||||
} elseif ( is_object( $result->info ) ) {
|
||||
// Seemed to be an object once…
|
||||
$result->info->results = $add( $result->info->results, count( $themes ) );
|
||||
}
|
||||
|
||||
array_splice( $result->themes, 0, 0, $themes );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Filter locales queried for a theme update.
|
||||
*
|
||||
* Just in time to wait for the theme updates HTTP request…
|
||||
*
|
||||
* @param array $locales
|
||||
* @return array
|
||||
*/
|
||||
public function filterThemeUpdateLocales( $locales )
|
||||
{
|
||||
$this->addHookMethod( 'http_response', 'filterThemeUpdateResponse' );
|
||||
|
||||
return $locales;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @return bool
|
||||
*/
|
||||
protected function isThemeUpdateUrl( $url )
|
||||
{
|
||||
return (bool) preg_match( '@^https?://api.wordpress.org/themes/update-check/1.1/$@', $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add our updates to the list.
|
||||
*
|
||||
* @param array $response
|
||||
* @param array $args Original args to request
|
||||
* @param string $url
|
||||
*/
|
||||
public function filterThemeUpdateResponse( array $response, array $args, $url )
|
||||
{
|
||||
if ( ! $this->isThemeUpdateUrl( $url ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->removeHookMethod( 'http_response', __FUNCTION__ );
|
||||
|
||||
$themes = $this->repository->queryUpdates( [
|
||||
// Eliminate worst offenders
|
||||
'author' => false,
|
||||
'description' => false,
|
||||
'preview_url' => false,
|
||||
'screenshot_url' => false,
|
||||
] );
|
||||
if ( is_wp_error( $themes ) ) {
|
||||
// Silently fail.
|
||||
return $response;
|
||||
}
|
||||
|
||||
$updates = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
|
||||
foreach ( $themes as $theme ) {
|
||||
$installed_theme = wp_get_theme( $theme->slug );
|
||||
if ( ! $installed_theme->exists() || version_compare( $theme->version, $installed_theme->version, '<=' ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Because that’s why: Rename all the fields.
|
||||
$updates['themes'][ $theme->slug ] = [
|
||||
'theme' => $theme->slug,
|
||||
'new_version' => $theme->version,
|
||||
'url' => $theme->homepage,
|
||||
'package' => $theme->download_link,
|
||||
];
|
||||
}
|
||||
|
||||
$response['body'] = json_encode( $updates );
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
namespace Pfadfinden\WordPress;
|
||||
|
||||
use Shy\WordPress\SettingsPage;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The code managing the plugin settings.
|
||||
*
|
||||
* @author Philipp Cordes <philipp.cordes@pfadfinden.de>
|
||||
*/
|
||||
class ThemeUpdaterSettings extends SettingsPage
|
||||
{
|
||||
/**
|
||||
* Full path of plugin main file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getPluginFilename()
|
||||
{
|
||||
return preg_replace( '/src\\/.*?$/', 'pfadfinden-theme-updater.php', __DIR__ );
|
||||
}
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct( 'pfadfinden-theme-updater' );
|
||||
|
||||
$this->addHookMethod( 'plugin_action_links', 'filterPluginActions' );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add our settings entry to the plugin actions.
|
||||
*
|
||||
* @param array<string> $actions
|
||||
* @param string $plugin_file
|
||||
* @param array $plugin_data
|
||||
* @param string $context
|
||||
* @return array<string>
|
||||
*/
|
||||
public function filterPluginActions( array $actions, $plugin_file, array $plugin_data, $context )
|
||||
{
|
||||
// Dereference possible symlink
|
||||
$plugin_file = realpath( WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . $plugin_file );
|
||||
if ( $this->getPluginFilename() !== $plugin_file ) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
return array(
|
||||
'settings' => sprintf(
|
||||
'<a href="themes.php?page=%s">%s</a>',
|
||||
esc_attr( urlencode( $this->slug ) ),
|
||||
esc_html__( 'Settings' )
|
||||
),
|
||||
) + $actions;
|
||||
}
|
||||
|
||||
|
||||
protected function getParentSlug()
|
||||
{
|
||||
return 'themes.php';
|
||||
}
|
||||
|
||||
protected function getPageTitle()
|
||||
{
|
||||
return __( 'Pfadfinden Theme Updater Settings', 'pfadfinden-theme-updater' );
|
||||
}
|
||||
|
||||
protected function getMenuTitle()
|
||||
{
|
||||
return __( 'Pfadfinden Updater', 'pfadfinden-theme-updater' );
|
||||
}
|
||||
|
||||
|
||||
public function registerSettings()
|
||||
{
|
||||
$this->addSection( '', 'plugin' );
|
||||
|
||||
$this->addTextField(
|
||||
'key',
|
||||
__( 'API Key', 'pfadfinden-theme-updater' ),
|
||||
[ 'attr' => [
|
||||
'minlength' => '10',
|
||||
'maxlength' => '10',
|
||||
'pattern' => '^[A-Za-z0-9]{10}$',
|
||||
'title' => __( 'An API key consists of 10 alphanumeric characters.', 'pfadfinden-theme-updater' ),
|
||||
] ],
|
||||
[ $this, 'renderApiKeyField' ]
|
||||
);
|
||||
|
||||
$this->addCheckboxField(
|
||||
'keep-settings',
|
||||
__( 'Keep Settings', 'pfadfinden-theme-updater' ),
|
||||
__( 'Don’t delete settings when uninstalling the plugin.', 'pfadfinden-theme-updater' )
|
||||
);
|
||||
|
||||
parent::registerSettings();
|
||||
}
|
||||
|
||||
public function renderApiKeyField( array $args )
|
||||
{
|
||||
$this->renderTextField( $args );
|
||||
|
||||
echo '<p class="description">' . __( 'Just testing? Try APITESTKEY.', 'pfadfinden-theme-updater' ) . '</p>';
|
||||
}
|
||||
|
||||
public function sanitizeOptions( array $options )
|
||||
{
|
||||
if ( isset( $options['key'] ) ) {
|
||||
$key = preg_replace( '/[^A-Za-z0-9]+/', '', $options['key'] );
|
||||
$keylen = strlen( $key );
|
||||
if ( 0 !== $keylen && 10 !== $keylen ) {
|
||||
$this->addError( 'key', __( 'An API key consists of 10 alphanumeric characters.', 'pfadfinden-theme-updater' ) );
|
||||
}
|
||||
$options['key'] = $key;
|
||||
}
|
||||
|
||||
return $options + $this->getDefaults();
|
||||
}
|
||||
|
||||
public function getDefaults()
|
||||
{
|
||||
return [
|
||||
'key' => '',
|
||||
'keep-settings' => false,
|
||||
];
|
||||
}
|
||||
}
|
19
plugins/pfadfinden-theme-updater/src/autoloader.php
Normal file
19
plugins/pfadfinden-theme-updater/src/autoloader.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Try to load a Pfadfinden WordPress class.
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
function pfadfinden_wordpress_autoloader( $name )
|
||||
{
|
||||
if ( substr( $name, 0, 21 ) !== 'Pfadfinden\\WordPress\\' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$name = __DIR__ . '/' . str_replace( '\\', DIRECTORY_SEPARATOR, $name ) . '.php';
|
||||
return is_file( $name ) && include( $name );
|
||||
}
|
||||
|
||||
spl_autoload_register( 'pfadfinden_wordpress_autoloader' );
|
3
plugins/pfadfinden-theme-updater/startup.php
Normal file
3
plugins/pfadfinden-theme-updater/startup.php
Normal file
@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
return new \Pfadfinden\WordPress\ThemeUpdaterPlugin();
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Pfadfinden\WordPress\Tests;
|
||||
|
||||
|
||||
|
||||
class ThemeRepositoryTest extends \WP_UnitTestCase
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Pfadfinden\WordPress\Tests;
|
||||
|
||||
|
||||
|
||||
class ThemeUpdaterPluginTest extends \WP_UnitTestCase
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace Pfadfinden\WordPress\Tests;
|
||||
|
||||
use Pfadfinden\WordPress\ThemeUpdaterSettings;
|
||||
use PHPUnit_Framework_MockObject_MockObject as MockObject;
|
||||
use PHPUnit_Framework_MockObject_Builder_InvocationMocker as BuilderInvocationMocker;
|
||||
|
||||
|
||||
|
||||
class ThemeUpdaterSettingsTest extends \WP_UnitTestCase
|
||||
{
|
||||
/**
|
||||
* @return ThemeUpdaterSettings|MockObject {
|
||||
* @method BuilderInvocationMocker method(string)
|
||||
* }
|
||||
*/
|
||||
protected function createMock()
|
||||
{
|
||||
return $this->getMockBuilder( 'Pfadfinden\WordPress\ThemeUpdaterSettings' )
|
||||
->enableProxyingToOriginalMethods()
|
||||
->getMock();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array<array {
|
||||
* @type array<string> $0
|
||||
* }>
|
||||
*/
|
||||
public function pluginActionProvider()
|
||||
{
|
||||
return array(
|
||||
array( array() ),
|
||||
array( array( 'edit' => '<a href="edit-url.php">Edit</a>' ) ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider pluginActionProvider
|
||||
* @param array<string> $old_actions
|
||||
*/
|
||||
public function testFilterPluginActions( array $old_actions )
|
||||
{
|
||||
$settings = $this->createMock();
|
||||
|
||||
$new_actions = $settings->filterPluginActions( $old_actions, 'pfadfinden-theme-updater/pfadfinden-theme-updater.php', array(), 'All' );
|
||||
$this->assertCount( 1, array_diff_assoc( $new_actions, $old_actions ), 'Our action gets added.' );
|
||||
$this->assertCount( 0, array_diff_assoc( $old_actions, $new_actions ), 'No actions are removed.' );
|
||||
}
|
||||
|
||||
public function testRegisterSettings()
|
||||
{
|
||||
global $wp_settings_fields;
|
||||
|
||||
$settings = $this->createMock();
|
||||
$settings->registerSettings();
|
||||
|
||||
$sections = $settings->getSections();
|
||||
$this->assertCount( 1, $sections, 'One section is generated.' );
|
||||
|
||||
$fields = $settings->getFieldsForSection( $sections[0] );
|
||||
$this->assertEquals( array( 'key', 'keep-settings' ), array_keys( $fields ), 'Known settings are there.' );
|
||||
}
|
||||
|
||||
public function testSanitizeOptionDefaults()
|
||||
{
|
||||
$settings = $this->createMock();
|
||||
|
||||
$this->assertEquals(
|
||||
$settings->getDefaults(),
|
||||
$settings->sanitizeOptions( array() ),
|
||||
'sanitizeOptions() adds in default values if missing.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<array {
|
||||
* @type string $0
|
||||
* @type string $1
|
||||
* @type int $2
|
||||
* }>
|
||||
*/
|
||||
public function keyProvider()
|
||||
{
|
||||
return array(
|
||||
array( '', '', 0 ),
|
||||
array( 'ABCDEFGHIJ', 'ABCDEFGHIJ', 0 ),
|
||||
array( 'abcdefghij', 'abcdefghij', 0 ),
|
||||
array( '1234567890', '1234567890', 0 ),
|
||||
array( '123456789', '123456789', 1 ),
|
||||
array( '12345678901', '12345678901', 1 ),
|
||||
array( ' 1234567890', '1234567890', 0 ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider keyProvider
|
||||
* @param string $key
|
||||
* @param string $expected
|
||||
* @param int $errorCount
|
||||
*/
|
||||
public function testSanitizeKeyOption( $key, $expected, $errorCount )
|
||||
{
|
||||
$settings = $this->createMock();
|
||||
|
||||
$sanitized = $settings->sanitizeOptions( array( 'key' => $key ) )['key'];
|
||||
$this->assertEquals( $expected, $sanitized, 'Expected sanitized value.' );
|
||||
$this->assertCount( $errorCount, $settings->getErrors(), 'Number of generated errors.' );
|
||||
}
|
||||
|
||||
public function testDefaults()
|
||||
{
|
||||
$defaults = $this->createMock()->getDefaults();
|
||||
|
||||
$this->assertEquals(
|
||||
array( 'key', 'keep-settings' ),
|
||||
array_keys( $defaults ),
|
||||
'Defaults for all options.'
|
||||
);
|
||||
}
|
||||
}
|
19
plugins/pfadfinden-theme-updater/tests/autoloader.php
Normal file
19
plugins/pfadfinden-theme-updater/tests/autoloader.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Try to load a Pfadfinden WordPress class.
|
||||
*
|
||||
* @param string $name
|
||||
* @return boolean
|
||||
*/
|
||||
function pfadfinden_wordpress_tests_autoloader( $name )
|
||||
{
|
||||
if ( substr( $name, 0, 27 ) !== 'Pfadfinden\\WordPress\\Tests\\' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$name = __DIR__ . '/' . str_replace( '\\', DIRECTORY_SEPARATOR, $name ) . '.php';
|
||||
return is_file( $name ) && include( $name );
|
||||
}
|
||||
|
||||
spl_autoload_register( 'pfadfinden_wordpress_tests_autoloader' );
|
33
plugins/pfadfinden-theme-updater/tests/bootstrap.php
Normal file
33
plugins/pfadfinden-theme-updater/tests/bootstrap.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPUnit bootstrap file
|
||||
*
|
||||
* Variant of the one from github.com/tierra/wordpress-plugins-tests
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../use/shy-wordpress/src/autoloader.php';
|
||||
require_once __DIR__ . '/../src/autoloader.php';
|
||||
require_once __DIR__ . '/autoloader.php';
|
||||
|
||||
|
||||
|
||||
$GLOBALS['wp_test_plugins'] = array(
|
||||
'active_plugins' => array( 'pfadfinden-theme-updater/pfadfinden-theme-updater.php' ),
|
||||
);
|
||||
|
||||
|
||||
|
||||
echo 'Setting up WordPress...' . PHP_EOL;
|
||||
|
||||
if ( ! isset( $argv )
|
||||
|| ( ! in_array( '-v', $argv ) && ! in_array( '--verbose', $argv ) )
|
||||
) {
|
||||
ob_start();
|
||||
}
|
||||
|
||||
require_once ( getenv( 'WP_DEVELOP_DIR' ) ?: '../../../..' )
|
||||
. '/tests/phpunit/includes/bootstrap.php';
|
||||
|
||||
if ( ob_get_level() ) {
|
||||
ob_end_clean();
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<phpunit boostrap="tests/bootstrap.php">
|
||||
<testsuites>
|
||||
<testsuite>
|
||||
<directory suffix="Test.php" phpVersion="5.4.0">tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Shy\WordPress;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A composite option with a fixed number of suboptions and their default values.
|
||||
*/
|
||||
abstract class CompositeOption implements \ArrayAccess, \Countable, \IteratorAggregate
|
||||
{
|
||||
use HookableTrait;
|
||||
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $slug;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSlug()
|
||||
{
|
||||
return $this->slug;
|
||||
}
|
||||
|
||||
|
||||
protected function __construct( $slug )
|
||||
{
|
||||
$this->slug = (string) $slug;
|
||||
|
||||
$this->addHookMethod( 'default_option_' . $this->slug, 'getDefaults' );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return default values for all suboptions.
|
||||
* Hooked into get_option() defaults.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function getDefaults();
|
||||
|
||||
/**
|
||||
* @param string $offset
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefault( $offset )
|
||||
{
|
||||
return $this->getDefaults()[ $offset ];
|
||||
}
|
||||
|
||||
|
||||
public function offsetExists( $offset )
|
||||
{
|
||||
$settings = get_option( $this->slug );
|
||||
return isset( $settings[ $offset ] );
|
||||
}
|
||||
|
||||
public function offsetGet( $offset )
|
||||
{
|
||||
$settings = get_option( $this->slug );
|
||||
if ( ! isset( $settings[ $offset ] ) ) {
|
||||
throw new \OutOfBoundsException( "There is no setting '$offset'." );
|
||||
}
|
||||
|
||||
return $settings[ $offset ];
|
||||
}
|
||||
|
||||
public function offsetSet( $offset, $value )
|
||||
{
|
||||
$settings = get_option( $this->slug );
|
||||
if ( ! isset( $settings[ $offset ] ) ) {
|
||||
throw new \OutOfBoundsException( "There is no setting '$offset'." );
|
||||
}
|
||||
|
||||
$settings[ $offset ] = $value;
|
||||
update_option( $this->slug, $settings );
|
||||
}
|
||||
|
||||
public function offsetUnset( $offset )
|
||||
{
|
||||
throw new \BadMethodCallException( 'You cannot unset settings.' );
|
||||
}
|
||||
|
||||
|
||||
public function count()
|
||||
{
|
||||
return count( $this->getDefaults() );
|
||||
}
|
||||
|
||||
|
||||
public function getIterator()
|
||||
{
|
||||
return new \ArrayIterator( get_option( $this->slug ) );
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Shy\WordPress;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Making actions and filters how they should be.
|
||||
*
|
||||
* Default to pass all arguments.
|
||||
*/
|
||||
trait HookableTrait
|
||||
{
|
||||
/**
|
||||
* @param string $action_or_filter
|
||||
* @param string $method
|
||||
* @param int $priority
|
||||
* @param int $acceptedArgs
|
||||
*/
|
||||
protected function addHookMethod( $action_or_filter, $method, $priority = 10, $acceptedArgs = 99 )
|
||||
{
|
||||
add_filter( $action_or_filter, array( $this, $method ), $priority, $acceptedArgs );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $action_or_filter
|
||||
* @param string $method
|
||||
* @param int $priority
|
||||
* @param int $acceptedArgs
|
||||
*/
|
||||
protected function removeHookMethod( $action_or_filter, $method, $priority = 10, $acceptedArgs = 99 )
|
||||
{
|
||||
remove_filter( $action_or_filter, array( $this, $method ), $priority, $acceptedArgs );
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Shy\WordPress;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Options wrapper.
|
||||
*/
|
||||
class Options implements \ArrayAccess
|
||||
{
|
||||
/**
|
||||
* Remember a default value.
|
||||
*
|
||||
* Creates a closure and hooks it into the 'default_option_*' filter.
|
||||
*
|
||||
* @param string $option
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setDefault( $option, $value )
|
||||
{
|
||||
add_filter( 'default_option_' . $option, function () use ( $value ) {
|
||||
return $value;
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
public function offsetExists( $option )
|
||||
{
|
||||
// Unfortunately, we can’t really tell whether it exists…
|
||||
$value = get_option( $option );
|
||||
return false !== $value && null !== $value;
|
||||
}
|
||||
|
||||
public function offsetGet( $option )
|
||||
{
|
||||
return get_option( $option );
|
||||
}
|
||||
|
||||
public function offsetSet( $option, $value )
|
||||
{
|
||||
update_option( $option, $value );
|
||||
}
|
||||
|
||||
public function offsetUnset( $option )
|
||||
{
|
||||
delete_option( $option );
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Shy\WordPress;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Marker class for WordPress plugins.
|
||||
*/
|
||||
abstract class Plugin
|
||||
{
|
||||
use HookableTrait;
|
||||
}
|
@ -0,0 +1,378 @@
|
||||
<?php
|
||||
|
||||
namespace Shy\WordPress;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Abstracts common functionality and escaping for the Settings API.
|
||||
*
|
||||
* TODO: Check slug and field names for illegal characters.
|
||||
* TODO: Refactor to not extend but use CompositeOption
|
||||
*/
|
||||
abstract class SettingsPage extends CompositeOption
|
||||
{
|
||||
use HookableTrait;
|
||||
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $capability;
|
||||
|
||||
|
||||
/**
|
||||
* Slug (file name) of the parent menu entry.
|
||||
*
|
||||
* @see add_submenu_page() for suggestions.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function getParentSlug()
|
||||
{
|
||||
return 'options-general.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Title for this setting page.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getPageTitle();
|
||||
|
||||
/**
|
||||
* String to show in the menu entry.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getMenuTitle()
|
||||
{
|
||||
return $this->getPageTitle();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $slug Page slug
|
||||
* @param string $capability Required capability to view
|
||||
*/
|
||||
protected function __construct( $slug, $capability = 'manage_options' )
|
||||
{
|
||||
parent::__construct( $slug );
|
||||
|
||||
$this->capability = (string) $capability;
|
||||
|
||||
$this->addHookMethod( 'admin_menu', 'registerPage' );
|
||||
$this->addHookMethod( 'admin_init', 'registerSettings' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register our options page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function registerPage()
|
||||
{
|
||||
add_submenu_page(
|
||||
$this->getParentSlug(),
|
||||
$this->getPageTitle(),
|
||||
$this->getMenuTitle(),
|
||||
$this->capability,
|
||||
$this->slug,
|
||||
array( $this, 'renderPage' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the actual settings.
|
||||
* Override and use addSection() and add*Field() methods.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function registerSettings()
|
||||
{
|
||||
register_setting(
|
||||
$this->slug,
|
||||
$this->slug,
|
||||
array( $this, 'sanitizeOptions' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize option values after form submission.
|
||||
*
|
||||
* @param array $options
|
||||
* @return array
|
||||
*/
|
||||
abstract public function sanitizeOptions( array $options );
|
||||
|
||||
|
||||
/**
|
||||
* Section to add fields to.
|
||||
*
|
||||
* Parameter default from add_settings_field().
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $currentSection = 'default';
|
||||
|
||||
/**
|
||||
* Add a new section and return its generated name.
|
||||
*
|
||||
* @param string $title optional, can be empty
|
||||
* @param string $name optional, will be generated if empty
|
||||
* @return string
|
||||
*/
|
||||
protected function addSection( $title = '', $name = '' )
|
||||
{
|
||||
$name = (string) $name;
|
||||
if ( ! strlen( $name ) ) {
|
||||
$name = $this->slug . '-section' . ( count( $this->getSections() ) + 1 );
|
||||
}
|
||||
|
||||
add_settings_section(
|
||||
$name,
|
||||
esc_html( $title ),
|
||||
array( $this, 'renderSectionTeaser' ),
|
||||
$this->slug
|
||||
);
|
||||
|
||||
return $this->currentSection = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback before output of section fields.
|
||||
*
|
||||
* Teasers must escape their output themselves.
|
||||
*
|
||||
* @param array $section {
|
||||
* @type string $id
|
||||
* @type string $title
|
||||
* @type callable $callback
|
||||
* }
|
||||
*/
|
||||
public function renderSectionTeaser( array $section )
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all known section names on this page.
|
||||
*
|
||||
* @global $wp_settings_fields
|
||||
* @return array<string>
|
||||
*/
|
||||
public function getSections()
|
||||
{
|
||||
global $wp_settings_fields;
|
||||
|
||||
if ( ! isset( $wp_settings_fields[ $this->slug ] ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return array_keys( $wp_settings_fields[ $this->slug ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @global $wp_settings_fields
|
||||
* @param string $section
|
||||
* @return array<string, array {
|
||||
* @type string $id
|
||||
* @type string $title
|
||||
* @type callable $callback
|
||||
* @type array $args
|
||||
* }>
|
||||
*/
|
||||
public function getFieldsForSection( $section )
|
||||
{
|
||||
global $wp_settings_fields;
|
||||
|
||||
return $wp_settings_fields[ $this->slug ][ $section ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom field to this setting page.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $label
|
||||
* @param callable $callback
|
||||
* @param array $args
|
||||
*/
|
||||
protected function addField( $name, $label, $callback, $args = array() )
|
||||
{
|
||||
if ( ! is_callable( $callback ) ) {
|
||||
throw new \InvalidArgumentException( 'Parameter $callback must be callable.' );
|
||||
}
|
||||
|
||||
add_settings_field(
|
||||
$name,
|
||||
esc_html( $label ),
|
||||
$callback,
|
||||
$this->slug,
|
||||
$this->currentSection,
|
||||
$args
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a text field to this settings page.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $label
|
||||
* @param array $args
|
||||
* @param string $callback
|
||||
*/
|
||||
protected function addTextField( $name, $label, $args = array(), $callback = '' )
|
||||
{
|
||||
if ( ! $callback || ! is_callable( $callback ) ) {
|
||||
$callback = array( $this, 'renderTextField' );
|
||||
}
|
||||
|
||||
$this->addField(
|
||||
$name,
|
||||
$label,
|
||||
$callback,
|
||||
$args + array(
|
||||
'label_for' => $this->slug . '-' . $name,
|
||||
'name' => $name,
|
||||
'attr' => array(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $label
|
||||
* @param string $caption
|
||||
* @param array $args
|
||||
* @param callable $callback
|
||||
*/
|
||||
protected function addCheckboxField( $name, $label, $caption, $args = array(), $callback = '' )
|
||||
{
|
||||
if ( ! $callback || ! is_callable( $callback ) ) {
|
||||
$callback = array( $this, 'renderCheckboxField' );
|
||||
}
|
||||
|
||||
$this->addField(
|
||||
$name,
|
||||
$label,
|
||||
$callback,
|
||||
$args + array(
|
||||
'label_for' => $this->slug . '-' . $name,
|
||||
'name' => $name,
|
||||
'caption' => $caption,
|
||||
'attr' => array(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an error.
|
||||
*
|
||||
* @param string $code
|
||||
* @param string $message
|
||||
*/
|
||||
protected function addError( $code, $message )
|
||||
{
|
||||
add_settings_error( $this->slug, $code, $message );
|
||||
}
|
||||
|
||||
/**
|
||||
* Errors for this setting.
|
||||
*
|
||||
* @return array {
|
||||
* @type string $setting
|
||||
* @type string $code
|
||||
* @type string $message
|
||||
* @type string $type 'error'
|
||||
* }
|
||||
*/
|
||||
public function getErrors()
|
||||
{
|
||||
return get_settings_errors( $this->slug );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render a setting as text field.
|
||||
*
|
||||
* @param array $args {
|
||||
* @type string $name
|
||||
* @type string $label_for
|
||||
* @type array $attr
|
||||
* }
|
||||
*/
|
||||
public function renderTextField( array $args )
|
||||
{
|
||||
$name = $args['name'];
|
||||
|
||||
$this->renderInputTag( array(
|
||||
'type' => 'text',
|
||||
'id' => $args['label_for'],
|
||||
'class' => 'regular-text',
|
||||
'name' => $this->slug . '[' . $name . ']',
|
||||
'value' => $this[ $name ],
|
||||
) + $args['attr'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a setting as checkbox.
|
||||
*
|
||||
* @param array $args {
|
||||
* @type string $caption
|
||||
* @type string $name
|
||||
* @type string $label_for
|
||||
* @type array $attr
|
||||
* }
|
||||
*/
|
||||
public function renderCheckboxField( array $args )
|
||||
{
|
||||
$name = $args['name'];
|
||||
|
||||
echo '<label>';
|
||||
$this->renderInputTag( array(
|
||||
'type' => 'checkbox',
|
||||
'id' => isset( $args['label_for'] ) ? $args['label_for'] : null,
|
||||
'name' => $this->slug . '[' . $name . ']',
|
||||
'value' => '1',
|
||||
'checked' => $this[ $name ] ? 'checked' : null,
|
||||
) + $args['attr'] );
|
||||
echo ' ' . esc_html( $args['caption'] ) . '</label>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Output an input tag with given HTML attributes.
|
||||
*
|
||||
* @param array $attr
|
||||
*/
|
||||
protected function renderInputTag( array $attr )
|
||||
{
|
||||
echo '<input';
|
||||
foreach ( $attr as $k => $v ) {
|
||||
if ( null !== $v ) {
|
||||
printf( ' %s="%s"', $k, esc_attr( $v ) );
|
||||
}
|
||||
}
|
||||
echo ' />';
|
||||
}
|
||||
|
||||
/**
|
||||
* Output settings page.
|
||||
*/
|
||||
public function renderPage()
|
||||
{
|
||||
if ( ! current_user_can( $this->capability ) ) {
|
||||
wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
|
||||
}
|
||||
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h2><?php echo esc_html( $this->getPageTitle() ); ?></h2>
|
||||
<form action="options.php" method="post">
|
||||
<?php settings_errors( 'general' ); // “Settings saved.” message ?>
|
||||
<?php settings_fields( $this->slug ); ?>
|
||||
<?php do_settings_sections( $this->slug ); ?>
|
||||
<?php submit_button(); ?>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Shy\WordPress;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Site options wrapper.
|
||||
*/
|
||||
class SiteOptions implements \ArrayAccess
|
||||
{
|
||||
/**
|
||||
* Remember a default value.
|
||||
*
|
||||
* Creates a closure and hooks it into the 'default_site_option_*' filter.
|
||||
*
|
||||
* @param string $option
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setDefault( $option, $value )
|
||||
{
|
||||
add_filter( 'default_site_option_' . $option, function () use ( $value ) {
|
||||
return $value;
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
public function offsetExists( $option )
|
||||
{
|
||||
// Unfortunately, we can’t really tell whether it exists…
|
||||
$value = get_site_option( $option );
|
||||
return false !== $value && null !== $value;
|
||||
}
|
||||
|
||||
public function offsetGet( $option )
|
||||
{
|
||||
return get_site_option( $option );
|
||||
}
|
||||
|
||||
public function offsetSet( $option, $value )
|
||||
{
|
||||
update_site_option( $option, $value );
|
||||
}
|
||||
|
||||
public function offsetUnset( $option )
|
||||
{
|
||||
delete_site_option( $option );
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Shy\WordPress;
|
||||
|
||||
|
||||
|
||||
abstract class Theme extends Plugin
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$GLOBALS['content_width'] = $this->getContentWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
abstract public function getContentWidth();
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Try to load a Shy WordPress class.
|
||||
*
|
||||
* @param string $name
|
||||
* @return boolean
|
||||
*/
|
||||
function shy_wordpress_autoloader( $name )
|
||||
{
|
||||
if ( substr( $name, 0, 14 ) !== 'Shy\\WordPress\\' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$name = __DIR__ . '/' . str_replace( '\\', DIRECTORY_SEPARATOR, $name ) . '.php';
|
||||
|
||||
return is_file( $name ) && include( $name );
|
||||
}
|
||||
|
||||
spl_autoload_register( 'shy_wordpress_autoloader' );
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Shy\WordPress\Tests;
|
||||
|
||||
use Shy\WordPress\HookableTrait;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check that HookableTrait actually works.
|
||||
*
|
||||
* @author Philipp Cordes <pc@irgendware.net>
|
||||
*/
|
||||
class HookableTraitTest extends \WP_UnitTestCase
|
||||
{
|
||||
use HookableTrait;
|
||||
|
||||
|
||||
public function actionMethod()
|
||||
{
|
||||
}
|
||||
|
||||
public function testWorksAsAction()
|
||||
{
|
||||
$this->addHookMethod( 'shywp_test_action', 'actionMethod' );
|
||||
$this->assertTrue( has_action( 'shywp_test_action' ), 'Registering an action via addHookMethod() worked.' );
|
||||
}
|
||||
|
||||
|
||||
public function filterMethod( $value )
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function testWorksAsFilter()
|
||||
{
|
||||
$this->addHookMethod( 'shywp_test_filter', 'filterMethod' );
|
||||
$this->assertTrue( has_filter( 'shywp_test_filter' ), 'Registering a filter via addHookMethod() worked.' );
|
||||
}
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
namespace Shy\WordPress\Tests;
|
||||
|
||||
use Shy\WordPress\SettingsPage;
|
||||
use PHPUnit_Framework_MockObject_MockObject as MockObject;
|
||||
use PHPUnit_Framework_MockObject_Builder_InvocationMocker as BuilderInvocationMocker;
|
||||
|
||||
|
||||
|
||||
class SettingsPageTest extends \WP_UnitTestCase
|
||||
{
|
||||
/**
|
||||
* Mock a SettingsPage.
|
||||
*
|
||||
* @param string|null $slug
|
||||
* @param string $capability
|
||||
* @return SettingsPage|MockObject {
|
||||
* @method BuilderInvocationMocker method(string)
|
||||
* }
|
||||
*/
|
||||
protected function mockSettingsPage( $slug = null, $capability = 'manage_options' )
|
||||
{
|
||||
$builder = $this->getMockBuilder( 'Shy\WordPress\SettingsPage' )
|
||||
->enableProxyingToOriginalMethods();
|
||||
|
||||
if ( null === $slug ) {
|
||||
$builder->disableOriginalConstructor();
|
||||
} else {
|
||||
$builder->setConstructorArgs( array( $slug, $capability ) );
|
||||
}
|
||||
|
||||
return $builder->getMock();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test reading defaults from the settings page.
|
||||
*
|
||||
* @covers SettingsPage::__construct()
|
||||
* @covers SettingsPage::getDefaults()
|
||||
* @covers SettingsPage::offsetExists()
|
||||
* @covers SettingsPage::offsetGet()
|
||||
* @expectedException OutOfBoundsException
|
||||
*/
|
||||
public function testReading()
|
||||
{
|
||||
$slug = 'shywp_settingspage_test_slug_reading';
|
||||
$defaults = array( 'foo' => 'bar' );
|
||||
|
||||
$page = $this->mockSettingsPage( $slug );
|
||||
$page->method( 'getDefaults' )->willReturn( $defaults );
|
||||
|
||||
$this->assertEquals( $defaults, get_option( $slug ) );
|
||||
|
||||
$this->assertArrayHasKey( 'foo', $page );
|
||||
$this->assertEquals( $defaults['foo'], $page['foo'] );
|
||||
|
||||
$this->assertArrayNotHasKey( 'baz', $page );
|
||||
$page['baz'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test writing to the settings page.
|
||||
*
|
||||
* @covers SettingsPage::offsetSet()
|
||||
* @expectedException OutOfBoundsException
|
||||
*/
|
||||
public function testWriting()
|
||||
{
|
||||
$slug = 'shywp_settingspage_test_slug_writing';
|
||||
$defaults = array( 'foo' => 'bar' );
|
||||
|
||||
$page = $this->mockSettingsPage( $slug );
|
||||
$page->method( 'getDefaults' )->willReturn( $defaults );
|
||||
|
||||
$page['foo'] = 'foo';
|
||||
$this->assertEquals( 'foo', $page['foo'] );
|
||||
$page['baz'] = '123';
|
||||
}
|
||||
|
||||
/**
|
||||
* Fail to remove a setting.
|
||||
*
|
||||
* @covers SettingPage::offsetUnset()
|
||||
* @expectedException BadMethodCallException
|
||||
*/
|
||||
public function testRemoving()
|
||||
{
|
||||
$slug = 'shywp_settingspage_test_slug_removing';
|
||||
$defaults = array();
|
||||
|
||||
$page = $this->mockSettingsPage( $slug );
|
||||
$page->method( 'getDefaults' )->willReturn( $defaults );
|
||||
|
||||
unset( $page['baz'] );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test whether the settings page can be showed.
|
||||
*
|
||||
* @covers SettingsPage::__construct()
|
||||
* @covers SettingsPage::getParentSlug()
|
||||
* @covers SettingsPage::getPageTitle()
|
||||
* @covers SettingsPage::getMenuTitle()
|
||||
*/
|
||||
public function testRegisterPage()
|
||||
{
|
||||
$this->expectOutputRegex( '/<page&title>/' );
|
||||
|
||||
$slug = 'shywp_settingspage_test_slug_registerpage';
|
||||
|
||||
$page = $this->mockSettingsPage( $slug );
|
||||
$page->method( 'getParentSlug' )->willReturn( 'index.php' );
|
||||
$page->method( 'getPageTitle' )->willReturn( '<page&title>' );
|
||||
$page->method( 'getMenuTitle' )->willReturn( '<menu&title>' );
|
||||
|
||||
$page->expects( $this->once() )->method( 'registerPage' )->with();
|
||||
$page->expects( $this->once() )->method( 'registerSettings' )->with();
|
||||
|
||||
// FIXME: Simulate display of backend.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @covers SettingsPage::sanitizeOptions()
|
||||
*/
|
||||
public function testSanitize()
|
||||
{
|
||||
$slug = 'shywp_settingspage_test_slug_sanitize';
|
||||
|
||||
$page = $this->mockSettingsPage( $slug );
|
||||
$page->method( 'sanitizeOptions' )->will( $this->returnArgument( 0 ) );
|
||||
$page->expects( $this->atLeastOnce() )->method( 'sanitizeOptions' );
|
||||
|
||||
$this->markTestIncomplete();
|
||||
// FIXME: Simulate form submission
|
||||
}
|
||||
|
||||
public function testRenderTextField()
|
||||
{
|
||||
$this->expectOutputRegex( '/^<input type="text"/' );
|
||||
|
||||
$page = $this->mockSettingsPage();
|
||||
$page->renderTextField( array(
|
||||
'label_for' => 'foo',
|
||||
'name' => 'bar',
|
||||
) );
|
||||
}
|
||||
|
||||
public function testRenderCheckboxField()
|
||||
{
|
||||
$this->expectOutputRegex( '/^<label><input type="checkbox"/' );
|
||||
|
||||
$page = $this->mockSettingsPage();
|
||||
$page->renderCheckboxField( array(
|
||||
'label_for' => 'foo',
|
||||
'name' => 'bar',
|
||||
'caption' => 'baz',
|
||||
) );
|
||||
}
|
||||
|
||||
public function testRenderPage()
|
||||
{
|
||||
$this->markTestIncomplete();
|
||||
$this->expectOutputRegex( '/<form action="options.php" method="post">.*<3&>.*cryptic_teaser.*</form>/' );
|
||||
|
||||
$slug = 'shywp_settingspage_test_slug_renderpage';
|
||||
|
||||
$page = $this->mockSettingsPage( $slug, 'read' );
|
||||
$page->method( 'getPageTitle' )->willReturn( '<3&>' );
|
||||
$page->method( 'renderSectionTeaser' )->will( $this->returnCallback( function () use ( $teaser ) {
|
||||
echo 'cryptic_teaser';
|
||||
} ) );
|
||||
|
||||
// FIXME: Simulate view of the settings page
|
||||
$page->renderPage();
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Try to load a Shy WordPress test class.
|
||||
*
|
||||
* @param string $name
|
||||
* @return boolean
|
||||
*/
|
||||
function shy_wordpress_tests_autoloader( $name )
|
||||
{
|
||||
if ( substr( $name, 0, 20 ) !== 'Shy\\WordPress\\Tests\\' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$name = __DIR__ . '/' . str_replace( '\\', DIRECTORY_SEPARATOR, $name ) . '.php';
|
||||
|
||||
return is_file( $name ) && include( $name );
|
||||
}
|
||||
|
||||
spl_autoload_register( 'shy_wordpress_tests_autoloader' );
|
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPUnit bootstrap file
|
||||
*
|
||||
* Variant of the one from github.com/tierra/wordpress-plugins-tests
|
||||
*/
|
||||
|
||||
require_once '../src/autoloader.php';
|
||||
require_once 'autoloader.php';
|
||||
|
||||
|
||||
|
||||
require_once ( getenv( 'WP_DEVELOP_DIR' ) ?: '../../../..' )
|
||||
. '/tests/phpunit/includes/bootstrap.php';
|
Reference in New Issue
Block a user