1
0
antisocial-safety/antisocial-safety.php

460 lines
14 KiB
PHP
Raw Normal View History

2024-10-10 19:10:14 +02:00
<?php
/**
* Plugin Name: antisocial-safety
* Description: Secures attachment uploads and comments with the OpenAI moderation endpoint
* Version: 1.6
*/
// Prevent direct access to the file
if (!defined('ABSPATH')) {
exit;
}
/**
* Global variable to store moderation results temporarily
*/
global $oai_moderation_results;
$oai_moderation_results = array();
/**
* Attachment Moderation
*/
// Hook into 'add_attachment' to moderate attachments upon upload
add_action('add_attachment', 'oai_moderate_attachment');
function oai_moderate_attachment($post_ID) {
$attachment = get_post($post_ID);
$mime_type = get_post_mime_type($post_ID);
// Only moderate images
if (strpos($mime_type, 'image/') !== false) {
// Get the API key
$api_key = get_option('oai_api_key');
if (!$api_key) {
// API key not set; skip moderation
return;
}
// Get the file URL
$file_url = wp_get_attachment_url($post_ID);
// Moderate the image
$result = oai_moderate_image($file_url);
if (isset($result['error'])) {
// Handle error (optional: log the error)
// For graceful failure, do not flag the attachment
return;
}
// Save the moderation result
update_post_meta($post_ID, '_oai_moderation_result', $result);
if ($result['flagged']) {
// Mark as flagged
update_post_meta($post_ID, '_oai_moderation_flagged', true);
} else {
// Remove any previous flag
delete_post_meta($post_ID, '_oai_moderation_flagged');
}
}
}
function oai_moderate_image($image_url) {
$api_key = get_option('oai_api_key');
if (!$api_key) {
// API key not set; skip moderation
return array();
}
$endpoint = 'https://api.openai.com/v1/moderations';
$data = array(
'model' => 'omni-moderation-latest',
'input' => array(
array(
'type' => 'image_url',
'image_url' => array('url' => $image_url),
),
),
);
$args = array(
'headers' => array(
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $api_key,
),
'body' => wp_json_encode($data),
'timeout' => 60,
);
$response = wp_remote_post($endpoint, $args);
if (is_wp_error($response)) {
// For graceful failure, return an empty array
return array();
}
$body = wp_remote_retrieve_body($response);
$result = json_decode($body, true);
if (isset($result['results'][0])) {
return $result['results'][0];
} else {
// Invalid response; return an empty array
return array();
}
}
// Hook into 'template_redirect' to block access to flagged attachments
add_action('template_redirect', 'oai_block_flagged_attachments');
function oai_block_flagged_attachments() {
if (is_attachment()) {
global $post;
if ($post) {
$flagged = get_post_meta($post->ID, '_oai_moderation_flagged', true);
if ($flagged) {
// Send 403 Forbidden header and exit
status_header(403);
nocache_headers();
// Optionally, display a message
wp_die(__('You are not allowed to access this content.', 'oai'), __('Forbidden', 'oai'), array('response' => 403));
}
}
}
}
/**
* Comments Moderation
*/
// Moderate comments before saving
add_filter('preprocess_comment', 'oai_moderate_comment');
function oai_moderate_comment($commentdata) {
$api_key = get_option('oai_api_key');
if (!$api_key) {
return $commentdata; // If API key not set, let the comment pass
}
$comment_content = $commentdata['comment_content'];
// Moderate the comment text
$result = oai_moderate_text($comment_content);
if (isset($result['error'])) {
// Handle error (optional: log the error)
// For graceful failure, let the comment pass
return $commentdata;
}
// Store the moderation result in a global variable indexed by comment content hash
$hash = md5($comment_content);
global $oai_moderation_results;
$oai_moderation_results[$hash] = $result;
return $commentdata;
}
// Set the comment approval status based on moderation result
add_filter('pre_comment_approved', 'oai_set_comment_approval_status', 10, 2);
function oai_set_comment_approval_status($approved, $commentdata) {
$api_key = get_option('oai_api_key');
if (!$api_key) {
return $approved; // Let the comment pass if API key not set
}
$comment_content = $commentdata['comment_content'];
$hash = md5($comment_content);
global $oai_moderation_results;
if (isset($oai_moderation_results[$hash])) {
$result = $oai_moderation_results[$hash];
if ($result['flagged']) {
// Set comment to unapproved
return '0'; // Unapproved
}
}
return $approved;
}
// Save the moderation result after the comment is inserted
add_action('comment_post', 'oai_save_comment_moderation_meta', 10, 2);
function oai_save_comment_moderation_meta($comment_ID, $comment_approved) {
$comment = get_comment($comment_ID);
$comment_content = $comment->comment_content;
$hash = md5($comment_content);
global $oai_moderation_results;
if (isset($oai_moderation_results[$hash])) {
$result = $oai_moderation_results[$hash];
update_comment_meta($comment_ID, '_oai_moderation_result', $result);
update_comment_meta($comment_ID, '_oai_moderation_flagged', $result['flagged'] ? 'pending' : 'ok');
// Remove from global variable
unset($oai_moderation_results[$hash]);
}
}
function oai_moderate_text($text) {
$api_key = get_option('oai_api_key');
if (!$api_key) {
// API key not set; skip moderation
return array(); // Return an empty array indicating no moderation
}
$endpoint = 'https://api.openai.com/v1/moderations';
$data = array(
'model' => 'omni-moderation-latest',
'input' => array(
array(
'type' => 'text',
'text' => $text,
),
),
);
$args = array(
'headers' => array(
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $api_key,
),
'body' => wp_json_encode($data),
'timeout' => 60,
);
$response = wp_remote_post($endpoint, $args);
if (is_wp_error($response)) {
// For graceful failure, return an empty array
return array();
}
$body = wp_remote_retrieve_body($response);
$result = json_decode($body, true);
if (isset($result['results'][0])) {
return $result['results'][0];
} else {
// Invalid response; return an empty array
return array();
}
}
/**
* Admin Columns for Media and Comments
*/
// Add a custom column to the media library
add_filter('manage_media_columns', 'oai_add_media_column');
function oai_add_media_column($columns) {
$columns['oai_moderation'] = __('Moderation', 'oai');
return $columns;
}
add_action('manage_media_custom_column', 'oai_media_column_content', 10, 2);
function oai_media_column_content($column_name, $post_ID) {
if ($column_name == 'oai_moderation') {
$flagged = get_post_meta($post_ID, '_oai_moderation_flagged', true);
if ($flagged) {
echo '<span style="color:red;">' . __('Flagged', 'oai') . '</span>';
} else {
echo '<span style="color:green;">' . __('OK', 'oai') . '</span>';
}
}
}
// Add a custom column to the comments list
add_filter('manage_edit-comments_columns', 'oai_add_comments_column');
function oai_add_comments_column($columns) {
$columns['oai_moderation'] = __('Moderation', 'oai');
return $columns;
}
add_action('manage_comments_custom_column', 'oai_comments_column_content', 10, 2);
function oai_comments_column_content($column_name, $comment_ID) {
if ($column_name == 'oai_moderation') {
$flagged = get_comment_meta($comment_ID, '_oai_moderation_flagged', true);
if ($flagged === 'pending') {
echo '<span style="color:orange;">' . __('Pending Approval', 'oai') . '</span>';
} elseif ($flagged === 'flagged') {
echo '<span style="color:red;">' . __('Flagged', 'oai') . '</span>';
} else {
echo '<span style="color:green;">' . __('OK', 'oai') . '</span>';
}
}
}
/**
* Display Moderation Details in Admin Screens
*/
// Add moderation info to the attachment edit screen
add_filter('attachment_fields_to_edit', 'oai_attachment_fields', 10, 2);
function oai_attachment_fields($form_fields, $post) {
$api_key = get_option('oai_api_key');
if (!$api_key) {
// API key not set; do not display moderation fields
return $form_fields;
}
$flagged = get_post_meta($post->ID, '_oai_moderation_flagged', true);
$moderation_result = get_post_meta($post->ID, '_oai_moderation_result', true);
if ($flagged) {
$form_fields['oai_moderation'] = array(
'label' => __('OpenAI Moderation', 'oai'),
'input' => 'html',
'html' => '<span style="color:red;">' . __('This attachment has been flagged by OpenAI Moderation.', 'oai') . '</span>',
'helps' => __('Flagged content is blocked from being served to users.', 'oai'),
);
} else {
$form_fields['oai_moderation'] = array(
'label' => __('OpenAI Moderation', 'oai'),
'input' => 'html',
'html' => '<span style="color:green;">' . __('This attachment passed OpenAI Moderation.', 'oai') . '</span>',
);
}
if ($moderation_result) {
$form_fields['oai_moderation_result'] = array(
'label' => __('Moderation Details', 'oai'),
'input' => 'html',
'html' => '<pre>' . esc_html(print_r($moderation_result, true)) . '</pre>',
);
}
return $form_fields;
}
// Add a meta box to the comment edit screen for moderation details
add_action('add_meta_boxes_comment', 'oai_add_comment_meta_box');
function oai_add_comment_meta_box() {
add_meta_box(
'oai_comment_moderation',
__('OpenAI Moderation Details', 'oai'),
'oai_comment_moderation_meta_box',
'comment',
'normal',
'high'
);
}
function oai_comment_moderation_meta_box($comment) {
$api_key = get_option('oai_api_key');
if (!$api_key) {
// API key not set; do not display moderation details
return;
}
$moderation_result = get_comment_meta($comment->comment_ID, '_oai_moderation_result', true);
$flagged = get_comment_meta($comment->comment_ID, '_oai_moderation_flagged', true);
if ($flagged) {
echo '<p><strong>' . __('Status:', 'oai') . '</strong> ';
if ($flagged === 'pending') {
echo '<span style="color:orange;">' . __('Pending Approval', 'oai') . '</span>';
} elseif ($flagged === 'flagged') {
echo '<span style="color:red;">' . __('Flagged', 'oai') . '</span>';
}
echo '</p>';
if ($moderation_result) {
echo '<h4>' . __('Moderation Details', 'oai') . '</h4>';
echo '<pre>' . esc_html(print_r($moderation_result, true)) . '</pre>';
}
} else {
echo '<p><span style="color:green;">' . __('This comment passed OpenAI Moderation.', 'oai') . '</span></p>';
}
}
/**
* Settings Page
*/
// Add settings page under Settings menu
add_action('admin_menu', 'oai_add_admin_menu');
function oai_add_admin_menu() {
add_options_page(
__('OpenAI Moderation', 'oai'),
__('OpenAI Moderation', 'oai'),
'manage_options',
'openai-moderation',
'oai_options_page'
);
}
function oai_options_page() {
?>
<div class="wrap">
<h1><?php esc_html_e('OpenAI Moderation Settings', 'oai'); ?></h1>
<form method="post" action="options.php">
<?php
settings_fields('oai_options_group');
do_settings_sections('openai-moderation');
submit_button();
?>
</form>
</div>
<?php
}
// Initialize settings
add_action('admin_init', 'oai_settings_init');
function oai_settings_init() {
register_setting('oai_options_group', 'oai_api_key');
add_settings_section(
'oai_settings_section',
__('OpenAI API Settings', 'oai'),
'oai_settings_section_callback',
'openai-moderation'
);
add_settings_field(
'oai_api_key_field',
__('OpenAI API Key', 'oai'),
'oai_api_key_render',
'openai-moderation',
'oai_settings_section'
);
}
function oai_settings_section_callback() {
echo '<p>' . esc_html__('Enter your OpenAI API key to enable moderation.', 'oai') . '</p>';
}
function oai_api_key_render() {
$api_key = get_option('oai_api_key');
?>
<input type="text" name="oai_api_key" value="<?php echo esc_attr($api_key); ?>" size="50">
<?php
}
// Display admin notice if API key is not set
add_action('admin_notices', 'oai_admin_notices');
function oai_admin_notices() {
if (!current_user_can('manage_options')) {
return;
}
// Check if we're on the OpenAI Moderation settings page
$screen = get_current_screen();
if ($screen->id !== 'settings_page_openai-moderation') {
return;
}
$api_key = get_option('oai_api_key');
if (!$api_key) {
echo '<div class="notice notice-warning is-dismissible">
<p>' . __('OpenAI API key is not set. Moderation features are disabled until you enter a valid API key.', 'oai') . '</p>
</div>';
}
}