GIF94;
| Path : /var/www/wordpress/wp-content/plugins/oxymade/includes/ |
| Current File : /var/www/wordpress/wp-content/plugins/oxymade/includes/class-paste-css-handler.php |
<?php
/**
* Paste CSS Handler
* Handles creation of Oxygen classes from extracted inline CSS
*
* @package OxyMade
*/
namespace OxyMade\Paste;
class PasteCSSHandler {
/**
* Initialize the handler
*/
public static function init() {
\add_action('wp_ajax_oxymade_create_classes_from_paste', [self::class, 'handle_create_classes']);
}
/**
* AJAX Handler: Create classes from pasted CSS
*/
public static function handle_create_classes() {
// 1. SECURITY CHECKS
// Check nonce
if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field($_POST['nonce']), 'oxymade-admin-nonce')) {
wp_send_json_error('Invalid security token');
exit;
}
// Check capability
if (!current_user_can('edit_posts')) {
wp_send_json_error('You do not have permission to perform this action');
exit;
}
// 2. GET AND VALIDATE INPUT
if (!isset($_POST['classes'])) {
wp_send_json_error('No class data provided');
exit;
}
// Don't sanitize JSON string - it will break the structure
// WordPress handles POST data safely already
$classes_json = isset($_POST['classes']) ? wp_unslash($_POST['classes']) : '';
$classes_data = json_decode($classes_json, true);
if (!$classes_data || !is_array($classes_data)) {
wp_send_json_error('Invalid class data format');
exit;
}
// 3. CHECK IF OXYGEN IS ACTIVE
if (!function_exists('\Breakdance\Data\get_global_option')) {
wp_send_json_error('Oxygen is not active');
exit;
}
// 4. CREATE CLASSES IN OXYGEN
$created_classes = [];
$errors = [];
try {
// Get existing selectors
$current_selectors_data = \Breakdance\Data\get_global_option('oxy_selectors_json_string');
if (is_string($current_selectors_data)) {
$current_selectors = json_decode($current_selectors_data, true);
} else {
$current_selectors = is_array($current_selectors_data) ? $current_selectors_data : [];
}
if (!is_array($current_selectors)) {
$current_selectors = [];
}
// Process each extracted class
foreach ($classes_data as $class_name => $class_info) {
$css_content = $class_info['css'] ?? '';
$element_type = $class_info['elementType'] ?? 'unknown';
$element_id = $class_info['elementId'] ?? 'no-id';
// Validate class name
if (!self::is_valid_class_name($class_name)) {
$errors[] = "Invalid class name: {$class_name}";
continue;
}
// Validate CSS content
if (!$css_content || !is_string($css_content)) {
$errors[] = "Invalid CSS for class: {$class_name}";
continue;
}
// Create selector object
$selector = self::create_selector_object(
$class_name,
$css_content,
$element_type,
$element_id
);
if ($selector) {
// Check if class already exists
$exists = false;
foreach ($current_selectors as $existing) {
if ($existing['name'] === $class_name) {
$exists = true;
break;
}
}
if (!$exists) {
$current_selectors[] = $selector;
$created_classes[] = $class_name;
}
}
}
// 5. SAVE TO OXYGEN
if (!empty($created_classes)) {
// Save selectors
\Breakdance\Data\set_global_option('oxy_selectors_json_string', $current_selectors);
// Update collections
$collections = self::extract_collections($current_selectors);
\Breakdance\Data\set_global_option('oxy_selectors_collections_json_string', $collections);
// Add revision
if (function_exists('\Breakdance\Data\GlobalRevisions\add_new_revision')) {
\Breakdance\Data\GlobalRevisions\add_new_revision($current_selectors, 'oxygen_selectors');
}
// Regenerate cache
if (function_exists('\Breakdance\Render\generateCacheForGlobalSettings')) {
\Breakdance\Render\generateCacheForGlobalSettings();
}
// Log the operation
self::log_extraction([
'count' => count($created_classes),
'classes' => $created_classes,
'timestamp' => current_time('mysql'),
'user_id' => get_current_user_id()
]);
wp_send_json_success([
'message' => count($created_classes) . ' CSS classes created successfully',
'created' => $created_classes,
'errors' => $errors
]);
} else {
wp_send_json_error([
'message' => 'No classes were created',
'errors' => $errors
]);
}
} catch (\Exception $e) {
wp_send_json_error('Error creating classes: ' . $e->getMessage());
}
exit;
}
/**
* Create a selector object for Oxygen
*/
private static function create_selector_object($class_name, $css_content, $element_type, $element_id) {
// Generate UUID for the selector
$uuid = self::generate_uuid();
// Sanitize CSS
$css_content = self::sanitize_css($css_content);
// Replace placeholder with actual class selector
$css_content = str_replace('%%SELECTOR%%', '.' . $class_name, $css_content);
$css_content = str_replace('%%ELEMENT%%', '.' . $class_name, $css_content);
// Create selector object
// Properties format matches Oxygen's standard structure
$selector = [
'id' => $uuid,
'name' => $class_name,
'type' => 'class',
'collection' => 'Extracted CSS',
'properties' => [
'breakpoint_base' => [
'custom_css' => [
'custom_css' => $css_content
]
]
],
'children' => [],
'locked' => false,
'_meta' => [
'source' => 'paste_extraction',
'element_type' => $element_type,
'element_id' => $element_id,
'created_at' => current_time('mysql')
]
];
return $selector;
}
/**
* Generate a UUID v4
*/
private static function generate_uuid() {
if (function_exists('\wp_generate_uuid4')) {
return \wp_generate_uuid4();
}
// Fallback UUID v4 generation
return sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
}
/**
* Validate class name
*/
private static function is_valid_class_name($name) {
// Must start with letter or hyphen
// Can contain letters, digits, hyphens, underscores
return (bool) preg_match('/^[a-zA-Z_-][a-zA-Z0-9_-]*$/', $name);
}
/**
* Sanitize CSS content
*/
private static function sanitize_css($css) {
// Basic sanitization - allow CSS but remove any PHP/script tags
$css = preg_replace('/<\?.*?\?>/s', '', $css);
$css = preg_replace('/<script[^>]*>.*?<\/script>/is', '', $css);
// Allow safe CSS properties
// Don't strip selectors or content
return $css;
}
/**
* Extract collections from selectors array
*/
private static function extract_collections($selectors) {
$collections = [];
if (is_array($selectors)) {
foreach ($selectors as $selector) {
if (isset($selector['collection']) && !in_array($selector['collection'], $collections)) {
$collections[] = $selector['collection'];
}
}
}
return $collections;
}
/**
* Log extraction event
*/
private static function log_extraction($data) {
// Store in transient for admin notice
set_transient(
'_oxymade_paste_extraction_' . time(),
$data,
HOUR_IN_SECONDS
);
}
}
// Initialize
PasteCSSHandler::init();