current_time( 'timestamp' ),
'results' => $results,
)
);
add_post_meta( $post_id, '_tenon_test_hash', $hash );
}
echo "
Collapse " . $format . '
';
}
}
/**
* Get parameter driven arguments for A11y Check
*/
function am_get_arguments() {
$permalink = get_the_permalink();
$level = isset( $_GET['tenon-level'] ) ? $_GET['tenon-level'] : 'AA';
$priority = isset( $_GET['tenon-priority'] ) ? $_GET['tenon-priority'] : '0';
$certainty = isset( $_GET['tenon-certainty'] ) ? $_GET['tenon-certainty'] : '';
switch ( $level ) {
case 'A':
case 'AA':
case 'AAA':
$level = $level;
break;
default:
$level = 'AA';
}
$priority = ( is_numeric( $priority ) ) ? $priority : 0;
$certainty = ( is_numeric( $certainty ) ) ? $certainty : 20;
$args = array(
'url' => $permalink,
'level' => $level,
'priority' => $priority,
'certainty' => $certainty,
);
return apply_filters( 'access_monitor_defaults', $args );
}
/**
* Send test query to Tenon.io API
*
* @param array $post Posted data.
*
* @return mixed boolean/array results.
*/
function am_query_tenon( $post ) {
// creates the $opts array from the $post data.
// only sets items that are non-blank. This allows Tenon to revert to defaults.
$expected_post = array( 'src', 'url', 'level', 'certainty', 'priority', 'docID', 'projectID', 'viewPortHeight', 'viewPortWidth', 'uaString', 'fragment', 'store' );
foreach ( $post as $k => $v ) {
if ( in_array( $k, $expected_post, true ) ) {
if ( strlen( trim( $v ) ) > 0 ) {
$opts[ $k ] = $v;
}
}
}
$settings = get_option( 'am_settings' );
$key = ( is_multisite() && false !== (bool) get_site_option( 'tenon_multisite_key' ) ) ? get_site_option( 'tenon_multisite_key' ) : $settings['tenon_api_key'];
if ( $key ) {
$opts['key'] = $key;
$tenon = new tenon( TENON_API_URL, $opts );
$tenon->submit( AM_DEBUG );
$body = $tenon->tenon_response['body'];
$formatted = am_format_tenon( $body );
$object = json_decode( $body );
if ( property_exists( $object, 'resultSet' ) ) {
$array = (array) $object;
$results = $array['resultSet'];
$errors = $array['clientScriptErrors'];
} else {
$results = array();
$errors = '';
}
$grade = am_percentage( $object );
if ( false === $grade ) {
if ( trim( $object->message ) === 'Bad Request - Either src or url parameter must be supplied' ) {
$message = __( 'Save your post as a draft in order to test for accessibility.', 'access-monitor' );
} else {
$info = $object->status;
$message = $object->message . ': ' . $info;
}
$formatted = '' . __( 'Tenon error:', 'access-monitor' ) . ' ' . $message . '' . '
';
$grade = 0;
}
return array(
'formatted' => $formatted,
'results' => $results,
'errors' => $errors,
'grade' => $grade,
);
} else {
return false;
}
}
/**
* Format result from Tenon for viewing.
*
* @param string $body JSON object received from Tenon.
*
* @return array formatted results.
*/
function am_format_tenon( $body ) {
if ( false === $body ) {
return __( 'No Tenon API Key provided', 'access-monitor' );
}
$object = json_decode( $body );
if ( is_object( $object ) && property_exists( $object, 'resultSummary' ) ) {
// Need to parse this into arrays due to WordPress code standards.
$array = (array) $object;
$summary = (array) $array['resultSummary'];
$issues = (array) $summary['issues'];
$errors = $issues['totalIssues'];
} else {
$errors = 0;
}
if ( property_exists( $object, 'resultSet' ) ) {
$array = (array) $object;
$results = $array['resultSet'];
} else {
$results = array();
}
$return = am_format_tenon_array( $results, $errors );
return $return;
}
/**
* Format results from tenon as HTML.
*
* @param array $results Array of result objects.
* @param string $errors String describing errors.
*
* @return string HTML.
*/
function am_format_tenon_array( $results, $errors ) {
// Translators: Number of issues identified.
$return = '' . sprintf( _n( '%s accessibility issue identified.', '%s accessibility issues identified.', $errors, 'access-monitor' ), "$errors " ) . ' ';
$i = 0;
if ( ! empty( $results ) ) {
foreach ( $results as $result ) {
$result = (array) $result;
$i++;
switch ( $result['certainty'] ) {
case ( $result['certainty'] >= 80 ):
$cert = 'high';
break;
case ( $result['certainty'] >= 40 ):
$cert = 'medium';
break;
default:
$cert = 'low';
}
switch ( $result['priority'] ) {
case ( $result['priority'] >= 80 ):
$prio = 'high';
break;
case ( $result['priority'] >= 40 ):
$prio = 'medium';
break;
default:
$prio = 'low';
}
$bpid = $result['bpID'];
$tid = $result['tID'];
$xpathid = md5( $result['xpath'] );
$href = esc_url(
add_query_arg(
array(
'bpID' => $bpid,
'tID' => $tid,
),
'http://tenon.io/bestpractice.php'
)
);
$ref = '' . __( 'Read more:', 'access-monitor' ) . " $result[resultTitle] ";
$standards = '';
foreach ( $result['standards'] as $guideline ) {
$standards .= "$guideline ";
}
if ( '' !== $standards ) {
$standards = '' . __( 'Relevant Accessibility Standards', 'access-monitor' ) . "
";
}
$error_snippet = $result['errorSnippet'];
$error_title = $result['errorTitle'];
$error_desc = ( isset( $result['errorDescription'] ) ) ? $result['errorDescription'] : '';
$return .= "
$i . $result[errorTitle]
" . __( 'Certainty:', 'access-monitor' ) . " $result[certainty]%" . "
" . __( 'Priority:', 'access-monitor' ) . " $result[priority]%" . "
Error Source
" . $error_snippet . "
$error_desc $ref
Xpath: $result[xpath]
$standards
Find error $i
";
}
} else {
$return .= "Congratulations! Tenon didn't find any issues on this page.
";
}
return $return . ' ';
}
add_action( 'admin_enqueue_scripts', 'am_admin_enqueue_scripts' );
/**
* Enqueue JS for Access Monitor (admin).
*/
function am_admin_enqueue_scripts() {
global $current_screen;
if ( 'customize' === $current_screen->id || 'press-this' === $current_screen->id ) {
// We don't want any of this on these screens.
} else {
// The customizer doesn't have an adminbar; so no reason to enqueue this. Also, it breaks the customizer.
wp_enqueue_script( 'am.functions', plugins_url( 'js/jquery.ajax.js', __FILE__ ), array( 'jquery' ) );
wp_localize_script( 'am.functions', 'am_ajax_url', admin_url( 'admin-ajax.php' ) );
wp_localize_script( 'am.functions', 'am_ajax_action', 'am_ajax_query_tenon' );
wp_localize_script( 'am.functions', 'am_plugin_name', __( 'Access Monitor', 'access-monitor' ) );
wp_enqueue_script( 'am.view', plugins_url( 'js/view.tenon.js', __FILE__ ), array( 'jquery' ), '1.0.0', true );
wp_localize_script(
'am.view',
'ami18n',
array(
'expand' => __( 'Expand', 'access-monitor' ),
'collapse' => __( 'Collapse', 'access-monitor' ),
'view' => __( 'View Error', 'access-monitor' ),
'updating' => __( 'Updating', 'access-monitor' ),
'completed' => __( 'Completed', 'access-monitor' ),
)
);
wp_enqueue_style( 'am.styles', plugins_url( 'css/am-styles.css', __FILE__ ) );
}
}
add_action( 'wp_enqueue_scripts', 'am_wp_enqueue_scripts' );
/**
* Enqueue scripts for Access Monitor (public).
*/
function am_wp_enqueue_scripts() {
if ( ! is_admin() && isset( $_GET['tenon'] ) ) {
wp_enqueue_style( 'am.styles', plugins_url( 'css/am-styles.css', __FILE__ ), array( 'dashicons' ) );
wp_enqueue_script( 'am.view', plugins_url( 'js/view.tenon.js', __FILE__ ), array( 'jquery' ), '1.0.0', true );
wp_localize_script(
'am.view',
'ami18n',
array(
'expand' => __( 'Expand', 'access-monitor' ),
'collapse' => __( 'Collapse', 'access-monitor' ),
)
);
}
}
add_action( 'wp_ajax_am_ajax_query_tenon', 'am_ajax_query_tenon' );
add_action( 'wp_ajax_nopriv_am_ajax_query_tenon', 'am_ajax_query_tenon' );
/**
* AJAX query sending request to Tenon.
*/
function am_ajax_query_tenon() {
if ( isset( $_REQUEST['tenon'] ) ) {
$args = array( 'src' => stripslashes( $_REQUEST['tenon'] ) );
if ( isset( $_REQUEST['level'] ) ) {
$args['level'] = $_REQUEST['level'];
}
if ( isset( $_REQUEST['fragment'] ) ) {
$args['fragment'] = $_REQUEST['fragment'];
}
if ( isset( $_REQUEST['certainty'] ) ) {
$args['certainty'] = $_REQUEST['certainty'];
}
if ( isset( $_REQUEST['priority'] ) ) {
$args['priority'] = $_REQUEST['priority'];
}
$results = am_query_tenon( $args );
wp_send_json(
array(
'response' => 1,
'results' => $results['results'],
'formatted' => $results['formatted'],
'grade' => $results['grade'],
)
);
}
}
add_action( 'admin_footer', 'am_admin_footer' );
/**
* Create admin footer container where JS results inserted.
*/
function am_admin_footer() {
echo "
";
}
add_action( 'init', 'am_disable_admin_bar' );
/**
* If Tenon is run on the front end, disable the admin bar so it isn't incorporated in tests.
*/
function am_disable_admin_bar() {
if ( isset( $_GET['tenon'] ) ) {
add_filter( 'show_admin_bar', '__return_false' );
}
}
add_action( 'admin_bar_menu', 'am_admin_bar', 200 );
/**
* Add Tenon Accessibility Check to adminbar.
*/
function am_admin_bar() {
$settings = get_option( 'am_settings' );
$api_key = $settings['tenon_api_key'];
$multisite = get_site_option( 'tenon_multisite_key' );
if ( false !== (bool) $api_key || false !== (bool) $multisite ) {
global $wp_admin_bar;
if ( is_admin() ) {
$url = '#tenon';
} else {
global $post_id;
$nonce = wp_create_nonce( 'public-tenon-query' );
$url = add_query_arg( 'tenon', $nonce, get_permalink( $post_id ) );
}
$args = array(
'id' => 'tenonCheck',
'title' => __( 'A11y Check', 'access-monitor' ),
'href' => $url,
);
$wp_admin_bar->add_node( $args );
}
}
add_action( 'init', 'am_posttypes' );
/**
* Create Post Types used in Access Monitor.
*/
function am_posttypes() {
$value = array(
__( 'accessibility report', 'access-monitor' ),
__( 'accessibility reports', 'access-monitor' ),
__( 'Accessibility Report', 'access-monitor' ),
__( 'Accessibility Reports', 'access-monitor' ),
);
$labels = array(
'name' => $value[3],
'singular_name' => $value[2],
'add_new' => __( 'Add New', 'access-monitor' ),
'add_new_item' => __( 'Create New Accessibility Report', 'access-monitor' ),
'edit_item' => __( 'Modify Accessibility Report', 'access-monitor' ),
'new_item' => __( 'New Accessibility Report', 'access-monitor' ),
'view_item' => __( 'View Accessibility Report', 'access-monitor' ),
'search_items' => __( 'Search Accessibility Reports', 'access-monitor' ),
'not_found' => __( 'No accessibility reports found', 'access-monitor' ),
'not_found_in_trash' => __( 'No accessibility reports found in Trash', 'access-monitor' ),
'parent_item_colon' => '',
);
$args = array(
'labels' => $labels,
'public' => false,
'show_ui' => true,
'show_in_menu' => true,
'menu_icon' => 'dashicons-universal-access',
'supports' => array( 'title' ),
);
register_post_type( 'tenon-report', $args );
}
add_action( 'admin_menu', 'am_add_outer_box' );
/**
* Add meta boxes.
*/
function am_add_outer_box() {
add_meta_box( 'am_report_div', __( 'Accessibility Report', 'access-monitor' ), 'am_add_inner_box', 'tenon-report', 'normal', 'high' );
add_meta_box( 'am_about_div', __( 'About this Report', 'access-monitor' ), 'am_add_about_box', 'tenon-report', 'side', 'high' );
add_meta_box( 'am_related_div', __( 'Related Reports', 'access-monitor' ), 'am_add_related_box', 'tenon-report', 'side', 'high' );
}
add_action( 'add_meta_boxes', 'am_post_reports_data' );
/**
* Add meta box for report data.
*
* @param string $type Post Type being viewed.
*/
function am_post_reports_data( $type ) {
$types = get_post_types( array( 'public' => true ) );
if ( in_array( $type, $types, true ) ) {
$settings = get_option( 'am_settings' );
$access_options_enabled = ( true === (bool) $settings['tenon_pre_publish'] ) ? true : false;
if ( $access_options_enabled ) {
// Disable Gutenberg if this option is enabled.
add_meta_box( 'am_public_report', __( 'Accessibility Reports', 'access-monitor' ), 'am_show_public_report', $type, 'normal', 'high', array( '__block_editor_compatible_meta_box' => false ) );
} else {
add_meta_box( 'am_public_report', __( 'Accessibility Reports', 'access-monitor' ), 'am_show_public_report', $type );
}
}
}
/**
* Create HTML to display report on accessibility testing for a post.
*/
function am_show_public_report() {
global $post;
$reports = get_post_meta( $post->ID, '_tenon_test_results' );
if ( empty( $reports ) ) {
echo '' . __( 'No manual accessibility tests have been run on this post.', 'access-monitor' ) . '
';
} else {
echo '' . __( 'Only tests with changed results are shown. Duplicate results are not saved.', 'access-monitor' ) . '
';
foreach ( $reports as $report ) {
$ts = $report['date'];
$date = date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $report['date'] );
$grade = round( $report['results']['grade'], 2 );
$format = $report['results']['formatted'];
echo "";
// Translators: Date of test, grade received.
echo "
" . sprintf( __( 'Test from %1$s (Grade: %2$s)', 'access-monitor' ), "$date ", "$grade% " ) . ' ';
echo "
" . __( 'Expand', 'access-monitor' ) . ' ';
echo "
$format
";
echo '
';
}
}
}
/**
* Add record of JSON response from Tenon.
*/
function am_add_inner_box() {
global $post;
$content = stripslashes( $post->post_content );
echo '' . $content . '
';
}
/**
* Add list of related accessibility tests.
*/
function am_add_related_box() {
global $post;
$relatives = get_posts(
array(
'post_type' => 'tenon-report',
'meta_key' => '_tenon_parent',
'meta_value' => $post->ID,
)
);
$children = get_posts(
array(
'post_type' => 'tenon-report',
'meta_key' => '_tenon_child',
'meta_value' => $post->ID,
)
);
echo '' . __( 'Child Reports', 'access-monitor' ) . ' ';
echo am_format_related_reports( $relatives, $post );
echo '' . __( 'Parent Reports', 'access-monitor' ) . ' ';
echo am_format_related_reports( $children, $post );
}
/**
* Format related report data.
*
* @param array $relatives Array of post objects from query.
* @param object $post Currently viewed post.
*
* @return string list of related posts.
*/
function am_format_related_reports( $relatives, $post ) {
$related = '';
if ( ! empty( $relatives ) ) {
foreach ( $relatives as $relative ) {
$title = $relative->post_title;
$id = $relative->ID;
$link = get_edit_post_link( $id );
$date = get_the_time( 'M j, Y @ H:i', $id );
if ( $id !== $post->ID ) {
$related .= "$title : $date ";
}
}
$related = "";
}
if ( empty( $relatives ) ) {
$related = '' . __( 'No related reports.', 'access-monitor' ) . '
';
}
return $related;
}
/**
* About this post meta box.
*/
function am_add_about_box() {
global $post;
$urls = '';
$parameters = '';
$pages = get_post_meta( $post->ID, '_tenon_pages', true );
$params = get_post_meta( $post->ID, '_tenon_params', true );
$total = get_post_meta( $post->ID, '_tenon_total', true );
// Translators: Number of unique errors on this post.
echo "" . sprintf( __( '%s unique errors', 'access-monitor' ), "$total " ) . '
';
if ( is_array( $pages ) ) {
foreach ( $pages as $url ) {
$page = str_replace( array( 'http://', 'https://', 'http://www.', 'https://www.' ), '', $url );
$urls .= "$page ";
}
unset( $params['url'] );
foreach ( $params as $key => $value ) {
$key = stripslashes( trim( $key ) );
$value = stripslashes( trim( $value ) );
if ( '' === $value ) {
$value = '' . __( 'Default', 'access-monitor' ) . ' ';
}
$label = ucfirst( $key );
$parameters .= "$label : $value ";
}
echo '' . __( 'URLs Tested', 'access-monitor' ) . " ";
echo '' . __( 'Test Parameters', 'access-monitor' ) . " ";
echo "" . __( 'Tenon Request Parameters', 'access-monitor' ) . '
';
} else {
echo '' . __( 'No pages tested yet.', 'access-monitor' ) . '
';
}
}
add_action( 'admin_menu', 'am_remove_menu_item' );
/**
* Remove "Add New" from menu for Tenon Reports.
*/
function am_remove_menu_item() {
global $submenu;
unset( $submenu['edit.php?post_type=tenon-report'][10] ); // Removes 'Add New'.
}
/**
* Insert a new report to WP database.
*
* @param string $name Name of report, if provided.
*
* @return Post ID.
*/
function am_set_report( $name = false ) {
$date = date_i18n( 'Y-m-d H:i', current_time( 'timestamp' ) );
if ( ! $name ) {
$name = $date;
} else {
$name = explode( ';', $name );
$name = $name[0];
$name .= '; ' . $date;
}
$report_id = wp_insert_post(
array(
'post_content' => '',
'post_title' => $name,
'post_status' => 'draft',
'post_type' => 'tenon-report',
)
);
return $report_id;
}
register_deactivation_hook( __FILE__, 'am_deactivate_cron' );
/**
* Deactivate cron jobs on deactivation of plug-in.
*/
function am_deactivate_cron() {
wp_clear_scheduled_hook( 'amcron' );
}
add_action( 'amcron', 'am_schedule_report', 10, 4 );
/**
* Execute scheduled reports.
*
* @param int $report_id Post containing report details.
* @param array $pages Array of pages to test.
* @param string $name name of report.
* @param array $params report parameters.
*/
function am_schedule_report( $report_id, $pages, $name, $params ) {
$new_report = am_generate_report( $name, $pages, $report_id, $params ); // 'none' to prevent this from being auto-scheduled again.
$url = admin_url( "post.php?post=$new_report&action=edit" );
update_post_meta( $new_report, '_tenon_parent', $report_id );
add_post_meta( $report_id, '_tenon_child', $new_report );
wp_mail(
apply_filters( 'am_cron_notification_email', get_option( 'admin_email' ), $name ),
// Translators: Blog name.
sprintf( __( 'Scheduled Accessibility Report on %s', 'access-monitor' ), get_option( 'blogname' ) ),
// Translators: URL to view accessibility report.
sprintf( __( 'View accessibility report: %s', 'access-monitor' ), $url )
);
}
/**
* Generate an accessibility report.
*
* @param string $name name of report.
* @param mixed boolean/array $pages Array of pages to test.
* @param mixed string/int $schedule Post ID containing report details or 'none'.
* @param array $params report parameters.
*
* @return Report ID.
*/
function am_generate_report( $name, $pages = false, $schedule = 'none', $params = array() ) {
$report_id = am_set_report( $name );
if ( is_array( $pages ) ) {
$pages = $pages;
} else {
$pages = array( home_url() );
}
if ( 'none' !== $schedule ) {
if ( ! is_numeric( $schedule ) ) {
$timestamp = ( 'weekly' === $schedule ) ? current_time( 'timestamp' ) + 60 * 60 * 24 * 7 : current_time( 'timestamp' ) + ( 60 * 60 * 24 * 30.5 );
$args = array(
'report_id' => $report_id,
'pages' => $pages,
'name' => $name,
'params' => $params,
);
wp_schedule_event( $timestamp, $schedule, 'amcron', $args );
update_post_meta( $report_id, '_tenon_schedule', $schedule );
} else {
update_post_meta( $report_id, '_tenon_schedule', $schedule );
}
}
foreach ( $pages as $page ) {
if ( is_numeric( $page ) ) {
$url = get_permalink( $page );
} else {
$url = $page;
}
if ( esc_url( $url ) ) {
$params['url'] = $url;
$report = am_query_tenon( $params );
$report = $report['results'];
$saved[ $url ] = $report;
} else {
continue;
}
}
$data = am_format_tenon_report( $saved, $name );
$total = $data['total'];
$formatted = $data['html'];
remove_action( 'save_post', 'am_run_report' );
wp_update_post(
array(
'ID' => $report_id,
'post_content' => $formatted,
)
);
update_post_meta( $report_id, '_tenon_total', $total );
update_post_meta( $report_id, '_tenon_json', $saved );
if ( isset( $params['projectID'] ) && '' !== $params['projectID'] ) {
update_post_meta( $report_id, '_tenon_projectID', $params['projectID'] );
}
update_post_meta( $report_id, '_tenon_params', $params );
update_post_meta( $report_id, '_tenon_pages', $pages );
wp_publish_post( $report_id );
add_action( 'save_post', 'am_run_report' );
return $report_id;
}
add_action( 'save_post', 'am_run_report' );
/**
* Re-run a test cycle when updating post.
*
* @param int $id Post ID.
*/
function am_run_report( $id ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE || wp_is_post_revision( $id ) || 'tenon-report' === ! ( get_post_type( $id ) ) ) {
return;
}
$post = get_post( $id );
if ( 'publish' !== $post->post_status ) {
return;
}
$name = get_the_title( $id );
$pages = get_post_meta( $id, '_tenon_pages', true );
$params = get_post_meta( $id, '_tenon_params', true );
$params = ( empty( $params ) ) ? array() : $params;
if ( empty( $pages ) ) {
return;
}
remove_action( 'save_post', 'am_run_report' );
$report_id = am_generate_report( $name, $pages, 'none', $params );
add_post_meta( $id, '_tenon_child', $report_id );
update_post_meta( $report_id, '_tenon_parent', $id );
add_action( 'save_post', 'am_run_report' );
}
/**
* Display an accessibility report.
*
* @param int $report_id Post ID for report.
*/
function am_show_report( $report_id = false ) {
$report_id = ( isset( $_GET['report'] ) && is_numeric( $_GET['report'] ) ) ? $_GET['report'] : false;
$output = '';
$name = '';
if ( $report_id ) {
$report = get_post( $report_id );
$output = $report->post_content;
$name = $report->post_title;
} else {
$reports = wp_get_recent_posts(
array(
'numberposts' => 1,
'post_type' => 'tenon-report',
'post_status' => 'publish',
),
'OBJECT'
);
$report = end( $reports );
if ( $report ) {
$output = $report->post_content;
$name = $report->post_title;
}
}
if ( '' !== $output ) {
echo $output;
} else {
$data = am_format_tenon_report( get_post_meta( $report_id, '_tenon_json', true ), $name );
$formatted = $data['html'];
$total = $data['total'];
wp_update_post(
array(
'ID' => $report_id,
'post_content' => $formatted,
)
);
update_post_meta( $report_id, '_tenon_total', $total );
echo $formatted;
}
}
/**
* Add columns about test results to reports list.
*
* @param array $cols Existing table columns.
*
* @return array $cols Modified table columns.
*/
function am_column( $cols ) {
$cols['am_total'] = __( 'Errors', 'access-monitor' );
$cols['am_schedule'] = __( 'Schedule', 'access-monitor' );
$cols['am_tested'] = __( 'Level', 'access-monitor' );
return $cols;
}
/**
* Return results pertinent to object in row.
*
* @param string $column_name Name of current column.
* @param int $id Post ID for current object.
*/
function am_custom_column( $column_name, $id ) {
switch ( $column_name ) {
case 'am_total':
$total = get_post_meta( $id, '_tenon_total', true );
echo $total;
break;
case 'am_tested':
$params = get_post_meta( $id, '_tenon_params', true );
echo isset( $params['level'] ) ? $params['level'] : '';
break;
case 'am_schedule':
$schedule = get_post_meta( $id, '_tenon_schedule', true );
if ( is_numeric( $schedule ) ) {
$edit_url = admin_url( "post.php?post=$schedule&action=edit" );
$edit_link = " " . __( 'View Original Test', 'access-monitor' ) . ' ';
echo $edit_link;
} else {
if ( $schedule ) {
echo ucfirst( $schedule );
} else {
_e( 'One-time report', 'access-monitor' );
}
}
break;
}
}
/**
* Get value for columns.
*
* @param string $value Current value.
* @param string $column_name Column name.
* @param int $id Row object ID.
*
* @return value.
*/
function am_return_value( $value, $column_name, $id ) {
if ( 'am_total' === $column_name || 'am_schedule' === $column_name || 'am_level' === $column_name ) {
$value = $id;
}
return $value;
}
add_action( 'admin_init', 'am_add' );
/**
* Add custom filters & actions for post columns.
*/
function am_add() {
add_filter( 'manage_tenon-report_posts_columns', 'am_column' );
add_action( 'manage_tenon-report_posts_custom_column', 'am_custom_column', 10, 2 );
}
/**
* Format a report from tenon.
*
* @param array $results Full results from Tenon.
* @param string $name Name of this report.
*/
function am_format_tenon_report( $results, $name ) {
$return = '';
$tbody = '';
$displayed = false;
$i = 0;
$count = 0;
$total = 0;
$links = '';
if ( ! empty( $results ) ) {
$reported = array();
$count = count( $results );
foreach ( $results as $url => $result_set ) {
$tbody = '';
$thead = '';
$url_hash = md5( $url );
$result_count = is_array( $result_set ) ? count( $result_set ) : 0;
if ( $result_count > 0 ) {
foreach ( $result_set as $result ) {
$result = (array) $result;
$i++;
$hash = md5( $result['resultTitle'] . $result['ref'] . $result['errorSnippet'] . $result['xpath'] );
if ( ! in_array( $hash, $reported, true ) ) {
$displayed = true;
$total ++;
$href = esc_url(
add_query_arg(
array(
'bpid' => $result['bpID'],
'tid' => $result['tID'],
),
'https://tenon.io/bestpractice.php'
)
);
$ref = "$result[errorTitle] ";
$tbody .= "
$ref$result[resultTitle] ; $result[errorDescription]
$result[certainty]
$result[priority]
Source Close $result[errorSnippet]
xPath Close $result[xpath]
";
} else {
$displayed = false;
}
$reported[] = $hash;
}
if ( ! $displayed ) {
// Translators: Link to where errors were found.
$return .= '' . sprintf( __( 'Errors found on %s.', 'access-monitor' ), "$url " ) . " ($result_count )";
// Translators: Count of errors found that were duplicates of other page errors.
$return .= ' ' . sprintf( __( 'The %d errors found on this page were also found on other pages tested.', 'access-monitor' ), $result_count ) . '
';
} else {
$thead = "";
// Translators: Link to where errors found, number of errors found on that page.
$links .= "" . sprintf( __( 'Results for %1$s (%2$d)', 'access-monitor' ), $url, $result_count ) . ' ';
// Translators: Link to where errors were found.
$thead .= '' . sprintf( __( 'Errors found on %s.', 'access-monitor' ), "$url " ) . " ($result_count ) ";
$thead .= "
" . __( 'Issue', 'access-monitor' ) . "
" . __( 'Certainty', 'access-monitor' ) . "
" . __( 'Priority', 'access-monitor' ) . "
" . __( 'Source', 'access-monitor' ) . "
" . __( 'Xpath', 'access-monitor' ) . '
';
$tfoot = "
" . __( 'Issue', 'access-monitor' ) . "
" . __( 'Certainty', 'access-monitor' ) . "
" . __( 'Priority', 'access-monitor' ) . "
" . __( 'Source', 'access-monitor' ) . "
" . __( 'Xpath', 'access-monitor' ) . '
';
$return .= $thead . $tbody . $tfoot;
}
} else {
// Translators: URL where errors were not found.
$return .= '' . sprintf( __( 'No errors found on %s.', 'access-monitor' ), "$url " ) . '
';
// Translators: URL where errors were not found.
$links .= "" . sprintf( __( 'Results for %s (0)', 'access-monitor' ), $url ) . ' ';
}
}
} else {
$return .= "Congratulations! Tenon didn't find any issues on this page.
";
}
// Translators: number of pages tested.
$header = '' . stripslashes( $name ) . '; ' . sprintf( __( 'Results from %d pages tested', 'access-monitor' ), $count ) . ' ';
$header .= '';
return array(
'total' => $total,
'html' => $header . $return,
);
}
add_filter( 'cron_schedules', 'am_custom_schedules' );
/**
* Set up custom cron schedules.
*
* @param array $schedules Existing schedules.
*
* @return array New schedules.
*/
function am_custom_schedules( $schedules ) {
// Adds once weekly to the existing schedules.
$schedules['weekly'] = array(
'interval' => 604800,
'display' => __( 'Once Weekly', 'access-monitor' ),
);
$schedules['monthly'] = array(
'interval' => 2635200,
'display' => __( 'Once Monthly', 'access-monitor' ),
);
return $schedules;
}
/**
* Access Monitor settings page.
*/
function am_update_settings() {
if ( isset( $_POST['am_settings'] ) ) {
$nonce = $_REQUEST['_wpnonce'];
if ( ! wp_verify_nonce( $nonce, 'access-monitor-nonce' ) ) {
die( 'Security check failed' );
}
$tenon_api_key = ( isset( $_POST['tenon_api_key'] ) ) ? $_POST['tenon_api_key'] : '';
$tenon_multisite_key = ( isset( $_POST['tenon_multisite_key'] ) ) ? $_POST['tenon_multisite_key'] : '';
$tenon_pre_publish = ( isset( $_POST['tenon_pre_publish'] ) ) ? 1 : 0;
$am_post_types = ( isset( $_POST['am_post_types'] ) ) ? $_POST['am_post_types'] : array();
$am_criteria = ( isset( $_POST['am_criteria'] ) ) ? $_POST['am_criteria'] : array();
$am_notify = ( isset( $_POST['am_notify'] ) ) ? $_POST['am_notify'] : '';
update_site_option( 'tenon_multisite_key', $tenon_multisite_key );
update_option(
'am_settings',
array(
'tenon_api_key' => $tenon_api_key,
'am_post_types' => $am_post_types,
'tenon_pre_publish' => $tenon_pre_publish,
'am_criteria' => $am_criteria,
'am_notify' => $am_notify,
)
);
echo "" . __( 'Access Monitor Settings Updated', 'access-monitor' ) . '
';
}
}
add_action( 'admin_head', 'am_setup_admin_notice' );
/**
* Create Admin Notice about API keys.
*/
function am_setup_admin_notice() {
if ( ! ( isset( $_POST['tenon_api_key'] ) && '' !== $_POST['tenon_api_key'] ) && ! ( isset( $_POST['tenon_multisite_key'] ) && '' !== $_POST['tenon_multisite_key'] ) ) {
$settings = ( is_array( get_option( 'am_settings' ) ) ) ? get_option( 'am_settings' ) : array();
$tenon_api_key = ( isset( $settings['tenon_api_key'] ) ) ? $settings['tenon_api_key'] : false;
$key = ( is_multisite() && false !== (bool) get_site_option( 'tenon_multisite_key' ) ) ? get_site_option( 'tenon_multisite_key' ) : $tenon_api_key;
if ( ! $key ) {
add_action( 'admin_notices', 'am_admin_notice' );
}
}
}
/**
* Display admin notice about API key.
*/
function am_admin_notice() {
if ( isset( $_GET['page'] ) && ( 'am-support-page' === $_GET['page'] || 'am-report-page' === $_GET['page'] ) ) {
$url = '#settings';
} else {
$url = admin_url( 'edit.php?post_type=tenon-report&page=am-support-page#settings' );
}
// Translators: Settings page URL.
$message = sprintf( __( 'You must enter a Tenon API key to use Access Monitor.', 'access-monitor' ), $url );
if ( ! current_user_can( 'manage_options' ) ) {
return;
} else {
echo "";
}
}
/**
* Display Settings form.
*/
function am_settings() {
$settings = ( is_array( get_option( 'am_settings' ) ) ) ? get_option( 'am_settings' ) : array();
$settings = array_merge(
array(
'tenon_api_key' => '',
'tenon_pre_publish' => '',
'am_post_types' => array(),
'am_post_grade' => '',
'am_criteria' => array(),
),
$settings
);
$multisite = get_site_option( 'tenon_multisite_key' );
$post_types = get_post_types(
array(
'public' => true,
'show_ui' => true,
),
'objects'
);
$am_post_types = isset( $settings['am_post_types'] ) ? $settings['am_post_types'] : array();
$am_criteria = isset( $settings['am_criteria'] ) ? $settings['am_criteria'] : array();
$am_notify = isset( $settings['am_notify'] ) ? $settings['am_notify'] : get_option( 'admin_email' );
$am_post_type_options = '';
foreach ( $post_types as $type ) {
if ( in_array( $type->name, $am_post_types, true ) ) {
$selected = ' checked="checked"';
} else {
$selected = '';
}
if ( 'attachment' !== $type->name ) {
$am_post_type_options .= "" . $type->labels->name . ' ';
}
}
echo "
";
}
/**
* Form to set up a report.
*/
function am_report() {
$settings = ( is_array( get_option( 'am_settings' ) ) ) ? get_option( 'am_settings' ) : array();
$settings = array_merge( array( 'tenon_api_key' => '' ), $settings );
$multisite = get_site_option( 'tenon_multisite_key' );
if ( false === (bool) $settings['tenon_api_key'] && false === (bool) $multisite ) {
$disabled = " disabled='disabled'";
$message = "" . __( 'Sign up with Tenon to get an API key', 'access-monitor' ) . " • " . __( 'Add your API key', 'access-monitor' ) . '
';
} else {
$disabled = '';
$message = '';
}
echo am_setup_report();
$theme = wp_get_theme();
$theme_name = $theme->get( 'Name' );
$theme_version = $theme->get( 'Version' );
$name = $theme_name . ' ' . $theme_version;
echo "$message
";
}
/**
* Generate a new accessibility report.
*/
function am_setup_report() {
if ( isset( $_POST['am_generate'] ) ) {
$name = ( isset( $_POST['am_report_name'] ) ) ? sanitize_text_field( $_POST['am_report_name'] ) : false;
$pages = ( isset( $_POST['am_report_pages'] ) && ! empty( $_POST['am_report_pages'] ) ) ? $_POST['am_report_pages'] : false;
$schedule = ( isset( $_POST['report_schedule'] ) ) ? $_POST['report_schedule'] : 'none';
$store = ( isset( $_POST['store'] ) ) ? 1 : 0;
$project_id = ( isset( $_POST['projectID'] ) ) ? sanitize_text_field( $_POST['projectID'] ) : '';
$viewport = ( isset( $_POST['viewport'] ) ) ? explode( 'x', $_POST['viewport'] ) : array( '1024', '768' );
$viewportheight = $viewport[1];
$viewportwidth = $viewport[0];
$level = ( isset( $_POST['level'] ) ) ? $_POST['level'] : 'AA';
$priority = ( isset( $_POST['priority'] ) ) ? (int) $_POST['priority'] : 0;
$certainty = ( isset( $_POST['certainty'] ) ) ? (int) $_POST['certainty'] : 0;
$args = array(
'store' => $store,
'projectID' => $project_id,
'viewPortHeight' => $viewportheight,
'viewPortWidth' => $viewportwidth,
'level' => $level,
'priority' => $priority,
'certainty' => $certainty,
);
am_generate_report( $name, $pages, $schedule, $args );
am_show_report();
}
}
/**
* List accessibility reports.
*
* @param int $count Number of reports to list.
*/
function am_list_reports( $count = 10 ) {
$count = (int) $count;
$reports = wp_get_recent_posts(
array(
'post_type' => 'tenon-report',
'numberposts' => $count,
'post_status' => 'publish',
),
'OBJECT'
);
if ( is_array( $reports ) ) {
echo '';
foreach ( $reports as $report_post ) {
$report = json_decode( $report_post->post_content );
$report_id = $report_post->ID;
$link = get_edit_post_link( $report_id );
$date = get_the_time( 'Y-m-d H:i:s', $report_post );
$name = $report_post->post_title;
echo "" . stripslashes( $name ) . " ($date) ";
}
echo ' ';
} else {
echo '' . __( 'No accessibility reports created yet.', 'access-monitor' ) . '
';
}
}
/**
* Show settings page.
*/
function am_support_page() {
?>
Add New Report', 'access-monitor' ), __( 'Add New Report', 'access-monitor' ), $permissions, 'am-report-page', 'am_report_page', 'am-report-page' );
$settings_page = add_submenu_page( 'edit.php?post_type=tenon-report', __( 'Access Monitor > Access Monitor Settings', 'access-monitor' ), __( 'Access Monitor Settings', 'access-monitor' ), $permissions, 'am-support-page', 'am_support_page' );
add_action( 'load-' . $plugin_page, 'am_load_admin_styles' );
add_action( 'load-' . $settings_page, 'am_load_admin_styles' );
}
}
/**
* Enqueue admin styles.
*/
function am_load_admin_styles() {
add_action( 'admin_enqueue_scripts', 'am_admin_styles' );
}
/**
* Actually enqueue admin styles.
*/
function am_admin_styles() {
wp_enqueue_style( 'am-admin-styles', plugins_url( 'css/am-admin-styles.css', __FILE__ ) );
}
/**
* Display Access Monitor get support form.
*/
function am_get_support_form() {
global $current_user, $am_version;
$current_user = wp_get_current_user();
// send fields for Access Monitor.
$version = $am_version;
// send fields for all plugins.
$wp_version = get_bloginfo( 'version' );
$home_url = home_url();
$wp_url = site_url();
$language = get_bloginfo( 'language' );
$charset = get_bloginfo( 'charset' );
// server.
$php_version = phpversion();
// theme data.
$theme = wp_get_theme();
$theme_name = $theme->get( 'Name' );
$theme_uri = $theme->get( 'ThemeURI' );
$theme_parent = $theme->get( 'Template' );
$theme_version = $theme->get( 'Version' );
// plugin data.
$plugins = get_plugins();
$plugins_string = '';
foreach ( array_keys( $plugins ) as $key ) {
if ( is_plugin_active( $key ) ) {
$plugin =& $plugins[ $key ];
$plugin_name = $plugin['Name'];
$plugin_uri = $plugin['PluginURI'];
$plugin_version = $plugin['Version'];
$plugins_string .= "$plugin_name: $plugin_version; $plugin_uri\n";
}
}
$data = "
================ Installation Data ====================
Version: $version
==WordPress:==
Version: $wp_version
URL: $home_url
Install: $wp_url
Language: $language
Charset: $charset
==Extra info:==
PHP Version: $php_version
Server Software: $_SERVER[SERVER_SOFTWARE]
User Agent: $_SERVER[HTTP_USER_AGENT]
==Theme:==
Name: $theme_name
URI: $theme_uri
Parent: $theme_parent
Version: $theme_version
==Active Plugins:==
$plugins_string
";
if ( isset( $_POST['am_support'] ) ) {
$nonce = $_REQUEST['_wpnonce'];
if ( ! wp_verify_nonce( $nonce, 'access-monitor-nonce' ) ) {
die( 'Security check failed' );
}
$request = stripslashes( $_POST['support_request'] );
$has_donated = ( isset( $_POST['has_donated'] ) && 'on' === $_POST['has_donated'] ) ? 'Donor' : 'No donation';
$has_read_faq = ( isset( $_POST['has_read_faq'] ) && 'on' === $_POST['has_read_faq'] ) ? 'Read FAQ' : true; // has no faq, for now.
$subject = "Access Monitor support request. $has_donated";
$message = $request . "\n\n" . $data;
// Get the site domain and get rid of www. from pluggable.php.
$sitename = strtolower( $_SERVER['SERVER_NAME'] );
if ( 'www.' === substr( $sitename, 0, 4 ) ) {
$sitename = substr( $sitename, 4 );
}
$from_email = 'wordpress@' . $sitename;
$from = "From: \"$current_user->display_name\" <$from_email>\r\nReply-to: \"$current_user->display_name\" <$current_user->user_email>\r\n";
if ( ! $has_read_faq ) {
echo "" . __( 'Please read the FAQ and other Help documents before making a support request.', 'access-monitor' ) . '
';
} else {
wp_mail( 'plugins@joedolson.com', $subject, $message, $from );
if ( 'Donor' === $has_donated ) {
echo "" . __( 'Thank you for supporting the continuing development of this plug-in! I\'ll get back to you as soon as I can.', 'access-monitor' ) . '
';
} else {
echo "" . __( 'I\'ll get back to you as soon as I can, after dealing with any support requests from plug-in supporters.', 'access-monitor' ) . '
';
}
}
} else {
$request = '';
}
echo "
';
}
add_filter( 'gettext', 'am_change_publish_button', 10, 2 );
/**
* Changes the publish button from saying 'Update' to 'Re-run this test'
*
* @param string $translation Translated version of text.
* @param string $text Original text.
*
* @return Custom text.
*/
function am_change_publish_button( $translation, $text ) {
if ( is_admin() && isset( $_GET['action'] ) && 'edit' === $_GET['action'] ) {
global $post;
if ( is_object( $post ) ) {
if ( 'Update' === $text && 'tenon-report' === $post->post_type ) {
$translation = __( 'Re-run this test', 'access-monitor' );
}
}
}
return $translation;
}
add_action( 'current_screen', 'am_redirect_new' );
/**
* Prevents the default add new post screen from showing.
*/
function am_redirect_new() {
$screen = get_current_screen();
if ( 'tenon-report' === $screen->id && ! isset( $_GET['action'] ) && ! isset( $_POST['save'] ) ) {
wp_safe_redirect( admin_url( 'edit.php?post_type=tenon-report&page=am-report-page' ) );
exit;
}
}
add_filter( 'plugin_action_links', 'am_plugin_action', 10, 2 );
/**
* Add "Settings" link into Plug-in list
*
* @param array $links Existing plug-in links.
* @param string $file Current plug-in file.
*
* @return array links.
*/
function am_plugin_action( $links, $file ) {
if ( plugin_basename( dirname( __FILE__ ) . '/access-monitor.php' === $file ) ) {
$links[] = "" . __( 'Access Monitor Settings', 'access-monitor' ) . ' ';
}
return $links;
}