Compare commits
2 Commits
9270e457c6
...
c95bdf0ae5
Author | SHA1 | Date | |
---|---|---|---|
c95bdf0ae5 | |||
44a5d16921 |
@ -2,9 +2,10 @@
|
||||
/**
|
||||
* Plugin Name: antisocial-safety
|
||||
* Description: Secures attachment uploads and comments with the OpenAI moderation endpoint
|
||||
* Version: 1.6
|
||||
* Version: 1.7
|
||||
*/
|
||||
|
||||
|
||||
// Prevent direct access to the file
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
@ -54,9 +55,14 @@ function oai_moderate_attachment($post_ID) {
|
||||
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');
|
||||
|
||||
// Delete the flagged attachment
|
||||
wp_delete_attachment($post_ID, true);
|
||||
|
||||
// Set a transient to show an admin notice
|
||||
set_transient('oai_flagged_upload_notice', __('An uploaded image was flagged by OpenAI Moderation and has been removed.', 'antisocial-safety'), 10);
|
||||
|
||||
// Optionally, you can log this event or take other actions
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -93,7 +99,7 @@ function oai_moderate_image($image_url) {
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
// For graceful failure, return an empty array
|
||||
return array();
|
||||
return array('error' => $response->get_error_message());
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
@ -107,22 +113,14 @@ function oai_moderate_image($image_url) {
|
||||
}
|
||||
}
|
||||
|
||||
// Hook into 'template_redirect' to block access to flagged attachments
|
||||
add_action('template_redirect', 'oai_block_flagged_attachments');
|
||||
// Display admin notice if an upload was flagged and removed
|
||||
add_action('admin_notices', 'oai_flagged_upload_admin_notice');
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
function oai_flagged_upload_admin_notice() {
|
||||
if ($message = get_transient('oai_flagged_upload_notice')) {
|
||||
echo '<div class="notice notice-warning is-dismissible">
|
||||
<p>' . esc_html($message) . '</p>
|
||||
</div>';
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,7 +229,7 @@ function oai_moderate_text($text) {
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
// For graceful failure, return an empty array
|
||||
return array();
|
||||
return array('error' => $response->get_error_message());
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
@ -245,6 +243,47 @@ function oai_moderate_text($text) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymizer Functionality
|
||||
*/
|
||||
|
||||
// Hook into 'wp_handle_upload_prefilter' to anonymize filenames if enabled
|
||||
add_filter('wp_handle_upload_prefilter', 'oai_anonymize_filename');
|
||||
|
||||
function oai_anonymize_filename($file) {
|
||||
// Check if anonymizer is enabled
|
||||
$anonymizer_enabled = get_option('oai_enable_anonymizer', false);
|
||||
if (!$anonymizer_enabled) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
// Get the file extension
|
||||
$file_info = pathinfo($file['name']);
|
||||
$extension = isset($file_info['extension']) ? '.' . strtolower($file_info['extension']) : '';
|
||||
|
||||
// Generate a unique 10-digit filename
|
||||
$new_filename = oai_generate_unique_filename($extension);
|
||||
|
||||
// Replace the original filename with the new anonymized filename
|
||||
$file['name'] = $new_filename;
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
function oai_generate_unique_filename($extension) {
|
||||
$upload_dir = wp_upload_dir();
|
||||
$base_dir = trailingslashit($upload_dir['basedir']);
|
||||
|
||||
do {
|
||||
// Generate a random number between 0000000000 and 9999999999
|
||||
$random_number = str_pad(mt_rand(0, 9999999999), 10, '0', STR_PAD_LEFT);
|
||||
$new_filename = $random_number . $extension;
|
||||
$file_path = $base_dir . $new_filename;
|
||||
} while (file_exists($file_path));
|
||||
|
||||
return $new_filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin Columns for Media and Comments
|
||||
*/
|
||||
@ -252,18 +291,19 @@ function oai_moderate_text($text) {
|
||||
// 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');
|
||||
$columns['oai_moderation'] = __('Moderation', 'antisocial-safety');
|
||||
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') {
|
||||
$moderation_result = get_post_meta($post_ID, '_oai_moderation_result', true);
|
||||
$flagged = get_post_meta($post_ID, '_oai_moderation_flagged', true);
|
||||
if ($flagged) {
|
||||
echo '<span style="color:red;">' . __('Flagged', 'oai') . '</span>';
|
||||
echo '<span style="color:red;">' . __('Flagged', 'antisocial-safety') . '</span>';
|
||||
} else {
|
||||
echo '<span style="color:green;">' . __('OK', 'oai') . '</span>';
|
||||
echo '<span style="color:green;">' . __('OK', 'antisocial-safety') . '</span>';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -271,7 +311,7 @@ function oai_media_column_content($column_name, $post_ID) {
|
||||
// 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');
|
||||
$columns['oai_moderation'] = __('Moderation', 'antisocial-safety');
|
||||
return $columns;
|
||||
}
|
||||
|
||||
@ -280,11 +320,11 @@ 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>';
|
||||
echo '<span style="color:orange;">' . __('Pending Approval', 'antisocial-safety') . '</span>';
|
||||
} elseif ($flagged === 'flagged') {
|
||||
echo '<span style="color:red;">' . __('Flagged', 'oai') . '</span>';
|
||||
echo '<span style="color:red;">' . __('Flagged', 'antisocial-safety') . '</span>';
|
||||
} else {
|
||||
echo '<span style="color:green;">' . __('OK', 'oai') . '</span>';
|
||||
echo '<span style="color:green;">' . __('OK', 'antisocial-safety') . '</span>';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -307,22 +347,22 @@ function oai_attachment_fields($form_fields, $post) {
|
||||
|
||||
if ($flagged) {
|
||||
$form_fields['oai_moderation'] = array(
|
||||
'label' => __('OpenAI Moderation', 'oai'),
|
||||
'label' => __('OpenAI Moderation', 'antisocial-safety'),
|
||||
'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'),
|
||||
'html' => '<span style="color:red;">' . __('This attachment was flagged by OpenAI Moderation and has been removed.', 'antisocial-safety') . '</span>',
|
||||
'helps' => __('Flagged content is blocked from being served to users.', 'antisocial-safety'),
|
||||
);
|
||||
} else {
|
||||
$form_fields['oai_moderation'] = array(
|
||||
'label' => __('OpenAI Moderation', 'oai'),
|
||||
'label' => __('OpenAI Moderation', 'antisocial-safety'),
|
||||
'input' => 'html',
|
||||
'html' => '<span style="color:green;">' . __('This attachment passed OpenAI Moderation.', 'oai') . '</span>',
|
||||
'html' => '<span style="color:green;">' . __('This attachment passed OpenAI Moderation.', 'antisocial-safety') . '</span>',
|
||||
);
|
||||
}
|
||||
|
||||
if ($moderation_result) {
|
||||
$form_fields['oai_moderation_result'] = array(
|
||||
'label' => __('Moderation Details', 'oai'),
|
||||
'label' => __('Moderation Details', 'antisocial-safety'),
|
||||
'input' => 'html',
|
||||
'html' => '<pre>' . esc_html(print_r($moderation_result, true)) . '</pre>',
|
||||
);
|
||||
@ -336,7 +376,7 @@ 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'),
|
||||
__('OpenAI Moderation Details', 'antisocial-safety'),
|
||||
'oai_comment_moderation_meta_box',
|
||||
'comment',
|
||||
'normal',
|
||||
@ -355,20 +395,20 @@ function oai_comment_moderation_meta_box($comment) {
|
||||
$flagged = get_comment_meta($comment->comment_ID, '_oai_moderation_flagged', true);
|
||||
|
||||
if ($flagged) {
|
||||
echo '<p><strong>' . __('Status:', 'oai') . '</strong> ';
|
||||
echo '<p><strong>' . __('Status:', 'antisocial-safety') . '</strong> ';
|
||||
if ($flagged === 'pending') {
|
||||
echo '<span style="color:orange;">' . __('Pending Approval', 'oai') . '</span>';
|
||||
echo '<span style="color:orange;">' . __('Pending Approval', 'antisocial-safety') . '</span>';
|
||||
} elseif ($flagged === 'flagged') {
|
||||
echo '<span style="color:red;">' . __('Flagged', 'oai') . '</span>';
|
||||
echo '<span style="color:red;">' . __('Flagged', 'antisocial-safety') . '</span>';
|
||||
}
|
||||
echo '</p>';
|
||||
|
||||
if ($moderation_result) {
|
||||
echo '<h4>' . __('Moderation Details', 'oai') . '</h4>';
|
||||
echo '<h4>' . __('Moderation Details', 'antisocial-safety') . '</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>';
|
||||
echo '<p><span style="color:green;">' . __('This comment passed OpenAI Moderation.', 'antisocial-safety') . '</span></p>';
|
||||
}
|
||||
}
|
||||
|
||||
@ -381,8 +421,8 @@ add_action('admin_menu', 'oai_add_admin_menu');
|
||||
|
||||
function oai_add_admin_menu() {
|
||||
add_options_page(
|
||||
__('OpenAI Moderation', 'oai'),
|
||||
__('OpenAI Moderation', 'oai'),
|
||||
__('OpenAI Moderation', 'antisocial-safety'),
|
||||
__('OpenAI Moderation', 'antisocial-safety'),
|
||||
'manage_options',
|
||||
'openai-moderation',
|
||||
'oai_options_page'
|
||||
@ -392,7 +432,7 @@ function oai_add_admin_menu() {
|
||||
function oai_options_page() {
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php esc_html_e('OpenAI Moderation Settings', 'oai'); ?></h1>
|
||||
<h1><?php esc_html_e('OpenAI Moderation Settings', 'antisocial-safety'); ?></h1>
|
||||
<form method="post" action="options.php">
|
||||
<?php
|
||||
settings_fields('oai_options_group');
|
||||
@ -409,25 +449,34 @@ add_action('admin_init', 'oai_settings_init');
|
||||
|
||||
function oai_settings_init() {
|
||||
register_setting('oai_options_group', 'oai_api_key');
|
||||
register_setting('oai_options_group', 'oai_enable_anonymizer');
|
||||
|
||||
add_settings_section(
|
||||
'oai_settings_section',
|
||||
__('OpenAI API Settings', 'oai'),
|
||||
__('OpenAI API Settings', 'antisocial-safety'),
|
||||
'oai_settings_section_callback',
|
||||
'openai-moderation'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'oai_api_key_field',
|
||||
__('OpenAI API Key', 'oai'),
|
||||
__('OpenAI API Key', 'antisocial-safety'),
|
||||
'oai_api_key_render',
|
||||
'openai-moderation',
|
||||
'oai_settings_section'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'oai_enable_anonymizer_field',
|
||||
__('Enable Filename Anonymizer', 'antisocial-safety'),
|
||||
'oai_enable_anonymizer_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>';
|
||||
echo '<p>' . esc_html__('Enter your OpenAI API key to enable moderation. You can also toggle the filename anonymizer below.', 'antisocial-safety') . '</p>';
|
||||
}
|
||||
|
||||
function oai_api_key_render() {
|
||||
@ -437,6 +486,14 @@ function oai_api_key_render() {
|
||||
<?php
|
||||
}
|
||||
|
||||
function oai_enable_anonymizer_render() {
|
||||
$enabled = get_option('oai_enable_anonymizer', false);
|
||||
?>
|
||||
<input type="checkbox" name="oai_enable_anonymizer" value="1" <?php checked(1, $enabled, true); ?> />
|
||||
<label for="oai_enable_anonymizer"><?php esc_html_e('Rename uploaded files to unique 10-digit random numbers.', 'antisocial-safety'); ?></label>
|
||||
<?php
|
||||
}
|
||||
|
||||
// Display admin notice if API key is not set
|
||||
add_action('admin_notices', 'oai_admin_notices');
|
||||
|
||||
@ -454,7 +511,7 @@ function oai_admin_notices() {
|
||||
$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>
|
||||
<p>' . __('OpenAI API key is not set. Moderation features are disabled until you enter a valid API key.', 'antisocial-safety') . '</p>
|
||||
</div>';
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ it keeps your site clean by blocking offensive or illegal images and comments be
|
||||
|
||||
## features
|
||||
|
||||
- **attachment moderation**: images are checked during upload. flagged images are blocked from being accessed.
|
||||
- **attachment moderation**: images are checked during upload. flagged images are blocked. optionally, anonymize file names.
|
||||
- **comment moderation**: comments are reviewed before they're saved. flagged comments are set to unapproved.
|
||||
- **admin integration**: see moderation status directly in your media library and comments list. detailed info available in edit screens.
|
||||
- **easy setup**: just add your openai api key in the settings.
|
||||
@ -24,7 +24,7 @@ it keeps your site clean by blocking offensive or illegal images and comments be
|
||||
### attachment moderation
|
||||
|
||||
- when an image is uploaded, the plugin sends it to openai's moderation api using the `omni-moderation-latest` model.
|
||||
- if the image is flagged, the plugin blocks access to it by sending a 403 forbidden response when someone tries to view it.
|
||||
- if the image is flagged in any of the abuse categories, the attachment does not get created.
|
||||
|
||||
### comment moderation
|
||||
|
||||
@ -34,7 +34,6 @@ it keeps your site clean by blocking offensive or illegal images and comments be
|
||||
### backend functionality
|
||||
|
||||
- hooks into `add_attachment` to moderate images upon upload.
|
||||
- uses `template_redirect` to block access to flagged attachments.
|
||||
- hooks into `preprocess_comment` and `pre_comment_approved` to moderate comments before saving.
|
||||
- stores moderation results in post and comment meta.
|
||||
- adds custom columns in admin screens to display moderation status.
|
||||
|
Loading…
Reference in New Issue
Block a user