Initial commit: WordPress wp-content (themes, plugins, languages)
- Theme: momentry (custom theme with REST API routes) - Plugins: code-snippets (contains all API proxies) - Languages: zh_TW translations - Excludes: cache, backups, uploads, logs
This commit is contained in:
@@ -0,0 +1,406 @@
|
||||
<?php
|
||||
|
||||
namespace Code_Snippets;
|
||||
|
||||
use WP_REST_Server;
|
||||
use WP_REST_Request;
|
||||
use WP_Error;
|
||||
use const Code_Snippets\REST_API_NAMESPACE;
|
||||
|
||||
class Files_Import_Manager {
|
||||
|
||||
const VERSION = 1;
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'rest_api_init', [ $this, 'register_rest_routes' ] );
|
||||
}
|
||||
|
||||
public function register_rest_routes() {
|
||||
$namespace = REST_API_NAMESPACE . self::VERSION;
|
||||
|
||||
register_rest_route( $namespace, 'file-upload/parse', [
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => [ $this, 'parse_uploaded_files' ],
|
||||
'permission_callback' => function() {
|
||||
return current_user_can( 'manage_options' );
|
||||
},
|
||||
] );
|
||||
|
||||
register_rest_route( $namespace, 'file-upload/import', [
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => [ $this, 'import_selected_snippets' ],
|
||||
'permission_callback' => function() {
|
||||
return current_user_can( 'manage_options' );
|
||||
},
|
||||
'args' => [
|
||||
'snippets' => [
|
||||
'description' => __( 'Array of snippet data to import', 'code-snippets' ),
|
||||
'type' => 'array',
|
||||
'required' => true,
|
||||
],
|
||||
'duplicate_action' => [
|
||||
'description' => __( 'Action to take when duplicate snippets are found', 'code-snippets' ),
|
||||
'type' => 'string',
|
||||
'enum' => [ 'ignore', 'replace', 'skip' ],
|
||||
'default' => 'ignore',
|
||||
],
|
||||
'network' => [
|
||||
'description' => __( 'Whether to import to network table', 'code-snippets' ),
|
||||
'type' => 'boolean',
|
||||
'default' => false,
|
||||
],
|
||||
],
|
||||
] );
|
||||
}
|
||||
|
||||
public function parse_uploaded_files( WP_REST_Request $request ) {
|
||||
// Verify nonce for security
|
||||
$nonce = $request->get_header( 'X-WP-Nonce' );
|
||||
if ( ! $nonce || ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
|
||||
return new WP_Error(
|
||||
'rest_cookie_invalid_nonce',
|
||||
__( 'Cookie check failed', 'code-snippets' ),
|
||||
[ 'status' => 403 ]
|
||||
);
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above via REST API header
|
||||
if ( empty( $_FILES['files'] ) ) {
|
||||
return new WP_Error(
|
||||
'no_files',
|
||||
__( 'No files were uploaded.', 'code-snippets' ),
|
||||
[ 'status' => 400 ]
|
||||
);
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Nonce verified above, file data validated below
|
||||
$files = $_FILES['files'];
|
||||
|
||||
if ( ! isset( $files['name'], $files['type'], $files['tmp_name'], $files['error'] ) ) {
|
||||
return new WP_Error(
|
||||
'invalid_file_data',
|
||||
__( 'Invalid file upload data.', 'code-snippets' ),
|
||||
[ 'status' => 400 ]
|
||||
);
|
||||
}
|
||||
|
||||
$all_snippets = [];
|
||||
$errors = [];
|
||||
|
||||
$file_count = is_array( $files['name'] ) ? count( $files['name'] ) : 1;
|
||||
|
||||
for ( $i = 0; $i < $file_count; $i++ ) {
|
||||
$file_name = is_array( $files['name'] ) ? $files['name'][ $i ] : $files['name'];
|
||||
$file_type = is_array( $files['type'] ) ? $files['type'][ $i ] : $files['type'];
|
||||
$file_tmp = is_array( $files['tmp_name'] ) ? $files['tmp_name'][ $i ] : $files['tmp_name'];
|
||||
$file_error = is_array( $files['error'] ) ? $files['error'][ $i ] : $files['error'];
|
||||
|
||||
if ( UPLOAD_ERR_OK !== $file_error ) {
|
||||
$errors[] = sprintf(
|
||||
/* translators: %1$s: file name, %2$s: error message */
|
||||
__( 'Upload error for file %1$s: %2$s', 'code-snippets' ),
|
||||
$file_name,
|
||||
$this->get_upload_error_message( $file_error )
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$file_info = pathinfo( $file_name );
|
||||
$extension = strtolower( $file_info['extension'] ?? '' );
|
||||
$mime_type = sanitize_mime_type( $file_type );
|
||||
|
||||
if ( ! $this->is_valid_file_type( $extension, $mime_type ) ) {
|
||||
$errors[] = sprintf(
|
||||
/* translators: %s: file name */
|
||||
__( 'Invalid file type for %s. Only JSON and XML files are allowed.', 'code-snippets' ),
|
||||
$file_name,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$snippets = $this->parse_file_content( $file_tmp, $extension, $mime_type, $file_name );
|
||||
|
||||
if ( is_wp_error( $snippets ) ) {
|
||||
$errors[] = sprintf(
|
||||
/* translators: %1$s: file name, %2$s: error message */
|
||||
__( 'Error parsing %1$s: %2$s', 'code-snippets' ),
|
||||
$file_name,
|
||||
$snippets->get_error_message(),
|
||||
);
|
||||
} else {
|
||||
$all_snippets = array_merge( $all_snippets, $snippets );
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $all_snippets ) ) {
|
||||
return new WP_Error(
|
||||
'no_snippets_found',
|
||||
__( 'No valid snippets found in the uploaded files.', 'code-snippets' ),
|
||||
[
|
||||
'status' => 400,
|
||||
'errors' => $errors,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
$response = [
|
||||
'snippets' => $all_snippets,
|
||||
'total_count' => count( $all_snippets ),
|
||||
'message' => sprintf(
|
||||
/* translators: %d: number of snippets */
|
||||
_n(
|
||||
'Found %d snippet ready for import.',
|
||||
'Found %d snippets ready for import.',
|
||||
count( $all_snippets ),
|
||||
'code-snippets',
|
||||
),
|
||||
count( $all_snippets )
|
||||
),
|
||||
];
|
||||
|
||||
if ( ! empty( $errors ) ) {
|
||||
$response['warnings'] = $errors;
|
||||
}
|
||||
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
public function import_selected_snippets( WP_REST_Request $request ) {
|
||||
$snippets_data = $request->get_param( 'snippets' );
|
||||
$duplicate_action = $request->get_param( 'duplicate_action' ) ?? 'ignore';
|
||||
$network = $request->get_param( 'network' ) ?? false;
|
||||
|
||||
if ( empty( $snippets_data ) || ! is_array( $snippets_data ) ) {
|
||||
return new WP_Error(
|
||||
'no_snippets',
|
||||
__( 'No snippet data provided for import.', 'code-snippets' ),
|
||||
[ 'status' => 400 ]
|
||||
);
|
||||
}
|
||||
|
||||
$snippets = [];
|
||||
foreach ( $snippets_data as $snippet_data ) {
|
||||
$snippet = new Snippet();
|
||||
$snippet->network = $network;
|
||||
|
||||
$import_fields = [
|
||||
'name',
|
||||
'desc',
|
||||
'description',
|
||||
'code',
|
||||
'tags',
|
||||
'scope',
|
||||
'priority',
|
||||
'shared_network',
|
||||
'modified',
|
||||
'cloud_id',
|
||||
];
|
||||
|
||||
foreach ( $import_fields as $field ) {
|
||||
if ( isset( $snippet_data[ $field ] ) ) {
|
||||
$snippet->set_field( $field, $snippet_data[ $field ] );
|
||||
}
|
||||
}
|
||||
|
||||
$snippets[] = $snippet;
|
||||
}
|
||||
|
||||
$imported = $this->save_snippets( $snippets, $duplicate_action, $network );
|
||||
|
||||
$response = [
|
||||
'imported' => count( $imported ),
|
||||
'imported_ids' => $imported,
|
||||
'message' => sprintf(
|
||||
/* translators: %d: number of snippets */
|
||||
_n(
|
||||
'Successfully imported %d snippet.',
|
||||
'Successfully imported %d snippets.',
|
||||
count( $imported ),
|
||||
'code-snippets',
|
||||
),
|
||||
count( $imported )
|
||||
),
|
||||
];
|
||||
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
private function parse_file_content( string $file_path, string $extension, string $mime_type, string $file_name ) {
|
||||
if ( ! file_exists( $file_path ) || ! is_file( $file_path ) ) {
|
||||
return new WP_Error(
|
||||
'file_not_found',
|
||||
__( 'File not found or is not a valid file.', 'code-snippets' )
|
||||
);
|
||||
}
|
||||
|
||||
if ( 'json' === $extension || 'application/json' === $mime_type ) {
|
||||
return $this->parse_json_file( $file_path, $file_name );
|
||||
} elseif ( 'xml' === $extension || in_array( $mime_type, [ 'text/xml', 'application/xml' ], true ) ) {
|
||||
return $this->parse_xml_file( $file_path, $file_name );
|
||||
}
|
||||
|
||||
return new WP_Error(
|
||||
'unsupported_file_type',
|
||||
__( 'Unsupported file type.', 'code-snippets' )
|
||||
);
|
||||
}
|
||||
|
||||
private function parse_json_file( string $file_path, string $file_name ) {
|
||||
$raw_data = file_get_contents( $file_path );
|
||||
$data = json_decode( $raw_data, true );
|
||||
|
||||
if ( json_last_error() !== JSON_ERROR_NONE ) {
|
||||
return new WP_Error(
|
||||
'invalid_json',
|
||||
sprintf(
|
||||
/* translators: %1$s: file name, %2$s: error message */
|
||||
__( 'Invalid JSON in file %1$s: %2$s', 'code-snippets' ),
|
||||
$file_name,
|
||||
json_last_error_msg()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! isset( $data['snippets'] ) || ! is_array( $data['snippets'] ) ) {
|
||||
return new WP_Error(
|
||||
'no_snippets_in_file',
|
||||
sprintf(
|
||||
/* translators: %s: file name */
|
||||
__( 'No snippets found in file %s', 'code-snippets' ),
|
||||
$file_name
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$snippets = [];
|
||||
foreach ( $data['snippets'] as $snippet_data ) {
|
||||
$snippet_data['source_file'] = $file_name;
|
||||
|
||||
$snippet_data['table_data'] = [
|
||||
'id' => $snippet_data['id'] ?? uniqid(),
|
||||
'title' => $snippet_data['name'] ?? __( 'Untitled Snippet', 'code-snippets' ),
|
||||
'scope' => $snippet_data['scope'] ?? 'global',
|
||||
'tags' => is_array( $snippet_data['tags'] ?? null ) ? implode( ', ', $snippet_data['tags'] ) : '',
|
||||
'description' => $snippet_data['desc'] ?? $snippet_data['description'] ?? '',
|
||||
'type' => Snippet::get_type_from_scope( $snippet_data['scope'] ?? 'global' )
|
||||
];
|
||||
|
||||
$snippets[] = $snippet_data;
|
||||
}
|
||||
|
||||
return $snippets;
|
||||
}
|
||||
|
||||
private function parse_xml_file( string $file_path, string $file_name ) {
|
||||
$dom = new \DOMDocument( '1.0', get_bloginfo( 'charset' ) );
|
||||
|
||||
if ( ! $dom->load( $file_path ) ) {
|
||||
return new WP_Error(
|
||||
'invalid_xml',
|
||||
sprintf(
|
||||
/* translators: %s: file name */
|
||||
__( 'Invalid XML in file %s', 'code-snippets' ),
|
||||
$file_name
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$snippets_xml = $dom->getElementsByTagName( 'snippet' );
|
||||
$fields = [ 'name', 'description', 'desc', 'code', 'tags', 'scope' ];
|
||||
|
||||
$snippets = [];
|
||||
$index = 0;
|
||||
|
||||
foreach ( $snippets_xml as $snippet_xml ) {
|
||||
$snippet_data = [];
|
||||
|
||||
foreach ( $fields as $field_name ) {
|
||||
$field = $snippet_xml->getElementsByTagName( $field_name )->item( 0 );
|
||||
|
||||
if ( isset( $field->nodeValue ) ) {
|
||||
$snippet_data[ $field_name ] = $field->nodeValue;
|
||||
}
|
||||
}
|
||||
|
||||
$scope = $snippet_xml->getAttribute( 'scope' );
|
||||
if ( ! empty( $scope ) ) {
|
||||
$snippet_data['scope'] = $scope;
|
||||
}
|
||||
|
||||
$snippet_data['source_file'] = $file_name;
|
||||
|
||||
$snippet_data['table_data'] = [
|
||||
'id' => ++$index,
|
||||
'title' => $snippet_data['name'] ?? __( 'Untitled Snippet', 'code-snippets' ),
|
||||
'scope' => $snippet_data['scope'] ?? 'global',
|
||||
'tags' => $snippet_data['tags'] ?? '',
|
||||
'description' => $snippet_data['desc'] ?? $snippet_data['description'] ?? '',
|
||||
'type' => Snippet::get_type_from_scope( $snippet_data['scope'] ?? 'global' ),
|
||||
];
|
||||
|
||||
$snippets[] = $snippet_data;
|
||||
}
|
||||
|
||||
return $snippets;
|
||||
}
|
||||
|
||||
private function save_snippets( array $snippets, string $duplicate_action, bool $network ): array {
|
||||
$existing_snippets = [];
|
||||
|
||||
if ( 'replace' === $duplicate_action || 'skip' === $duplicate_action ) {
|
||||
$all_snippets = get_snippets( [], $network );
|
||||
|
||||
foreach ( $all_snippets as $snippet ) {
|
||||
if ( $snippet->name ) {
|
||||
$existing_snippets[ $snippet->name ] = $snippet->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$imported = [];
|
||||
|
||||
foreach ( $snippets as $snippet ) {
|
||||
if ( 'ignore' !== $duplicate_action && isset( $existing_snippets[ $snippet->name ] ) ) {
|
||||
if ( 'replace' === $duplicate_action ) {
|
||||
$snippet->id = $existing_snippets[ $snippet->name ];
|
||||
} elseif ( 'skip' === $duplicate_action ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$saved_snippet = save_snippet( $snippet );
|
||||
|
||||
$snippet_id = $saved_snippet->id;
|
||||
|
||||
if ( $snippet_id ) {
|
||||
$imported[] = $snippet_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $imported;
|
||||
}
|
||||
|
||||
private function is_valid_file_type( string $extension, string $mime_type ): bool {
|
||||
$valid_extensions = [ 'json', 'xml' ];
|
||||
$valid_mime_types = [ 'application/json', 'text/xml', 'application/xml' ];
|
||||
|
||||
return in_array( $extension, $valid_extensions, true ) ||
|
||||
in_array( $mime_type, $valid_mime_types, true );
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function get_upload_error_message( int $error_code ): string {
|
||||
$error_messages = [
|
||||
UPLOAD_ERR_INI_SIZE => __( 'File exceeds the upload_max_filesize directive.', 'code-snippets' ),
|
||||
UPLOAD_ERR_FORM_SIZE => __( 'File exceeds the MAX_FILE_SIZE directive.', 'code-snippets' ),
|
||||
UPLOAD_ERR_PARTIAL => __( 'File was only partially uploaded.', 'code-snippets' ),
|
||||
UPLOAD_ERR_NO_FILE => __( 'No file was uploaded.', 'code-snippets' ),
|
||||
UPLOAD_ERR_NO_TMP_DIR => __( 'Missing a temporary folder.', 'code-snippets' ),
|
||||
UPLOAD_ERR_CANT_WRITE => __( 'Failed to write file to disk.', 'code-snippets' ),
|
||||
UPLOAD_ERR_EXTENSION => __( 'A PHP extension stopped the file upload.', 'code-snippets' ),
|
||||
];
|
||||
|
||||
return $error_messages[ $error_code ] ?? __( 'Unknown upload error.', 'code-snippets' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
namespace Code_Snippets;
|
||||
|
||||
use MatthiasMullie\Minify;
|
||||
|
||||
class Header_Footer_Code_Manager_Importer extends Importer_Base {
|
||||
|
||||
private const FIELD_MAPPINGS = [
|
||||
'name' => 'name',
|
||||
'snippet' => 'code',
|
||||
'location' => 'scope',
|
||||
'created' => 'modified',
|
||||
];
|
||||
|
||||
private const HTML_SCOPE_TRANSFORMATIONS = [
|
||||
'' => 'content',
|
||||
'header' => 'head-content',
|
||||
'footer' => 'footer-content',
|
||||
];
|
||||
|
||||
public function get_name() {
|
||||
return 'header-footer-code-manager';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'Header Footer Code Manager', 'code-snippets' );
|
||||
}
|
||||
|
||||
public static function is_active(): bool {
|
||||
return is_plugin_active( 'header-footer-code-manager/99robots-header-footer-code-manager.php' );
|
||||
}
|
||||
|
||||
public function get_data( array $ids_to_import = [] ) {
|
||||
global $wpdb;
|
||||
$nnr_hfcm_table_name = $wpdb->prefix . 'hfcm_scripts';
|
||||
$sql = "SELECT * FROM `{$nnr_hfcm_table_name}`";
|
||||
|
||||
if ( ! empty( $ids_to_import ) ) {
|
||||
$sql .= ' WHERE script_id IN (' . implode( ',', $ids_to_import ) . ')';
|
||||
}
|
||||
|
||||
$snippets = $wpdb->get_results(
|
||||
$sql
|
||||
);
|
||||
|
||||
foreach ( $snippets as $snippet ) {
|
||||
$snippet->table_data = [
|
||||
'id' => (int) $snippet->script_id,
|
||||
'title' => $snippet->name,
|
||||
];
|
||||
}
|
||||
|
||||
return $snippets;
|
||||
}
|
||||
|
||||
public function create_snippet( $snippet_data, bool $multisite ): ?Snippet {
|
||||
$code_type = $snippet_data->snippet_type ?? '';
|
||||
|
||||
$snippet = new Snippet();
|
||||
$snippet->network = $multisite;
|
||||
|
||||
foreach ( self::FIELD_MAPPINGS as $source_field => $target_field ) {
|
||||
if ( ! isset( $snippet_data->$source_field ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $this->transform_field_value(
|
||||
$target_field,
|
||||
$snippet_data->$source_field,
|
||||
$snippet_data
|
||||
);
|
||||
|
||||
$scope_not_supported = 'scope' === $target_field && null === $value;
|
||||
if ( $scope_not_supported ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$snippet->set_field( $target_field, $value );
|
||||
}
|
||||
|
||||
return $snippet;
|
||||
}
|
||||
|
||||
private function transform_field_value( string $target_field, $value, $snippet_data ) {
|
||||
if ( 'scope' === $target_field ) {
|
||||
return $this->transform_scope_value( $value, $snippet_data );
|
||||
}
|
||||
|
||||
if ( 'code' === $target_field ) {
|
||||
return $this->transform_code_value( $value, $snippet_data );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function transform_scope_value( $location_value, $snippet_data ): ?string {
|
||||
if ( ! is_scalar( $location_value ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$code_type = $snippet_data->snippet_type;
|
||||
|
||||
switch ( $code_type ) {
|
||||
case 'html':
|
||||
$transformations = self::HTML_SCOPE_TRANSFORMATIONS;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
return $transformations[ $location_value ] ?? null;
|
||||
}
|
||||
|
||||
private function transform_code_value( $code_value, $snippet_data ): ?string {
|
||||
$code = html_entity_decode( $code_value );
|
||||
$code_type = $snippet_data->snippet_type ?? '';
|
||||
|
||||
$code = $this->strip_wrapper_tags( $code, $code_type );
|
||||
$code = $this->apply_minification( $code, $code_type );
|
||||
|
||||
return trim( $code );
|
||||
}
|
||||
|
||||
private function strip_wrapper_tags( string $code, string $code_type ): string {
|
||||
switch ( $code_type ) {
|
||||
case 'css':
|
||||
return preg_replace( '/<\s*style[^>]*>|<\s*\/\s*style\s*>/i', '', $code );
|
||||
case 'js':
|
||||
return preg_replace( '/<\s*script[^>]*>|<\s*\/\s*script\s*>/i', '', $code );
|
||||
default:
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
|
||||
private function apply_minification( string $code, string $code_type ): string {
|
||||
if ( ! in_array( $code_type, [ 'css', 'js' ], true ) ) {
|
||||
return $code;
|
||||
}
|
||||
|
||||
$setting = Settings\get_setting( 'general', 'minify_output' );
|
||||
if ( ! is_array( $setting ) || ! in_array( $code_type, $setting, true ) ) {
|
||||
return $code;
|
||||
}
|
||||
|
||||
$minifier = 'css' === $code_type ? new Minify\CSS( $code ) : new Minify\JS( $code );
|
||||
return $minifier->minify();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace Code_Snippets;
|
||||
|
||||
use WP_REST_Server;
|
||||
use const Code_Snippets\REST_API_NAMESPACE;
|
||||
|
||||
abstract class Importer_Base {
|
||||
|
||||
const VERSION = 1;
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'rest_api_init', [ $this, 'register_rest_routes' ] );
|
||||
}
|
||||
|
||||
abstract public function get_name();
|
||||
|
||||
abstract public function get_title();
|
||||
|
||||
abstract public function get_data( array $ids_to_import = [] );
|
||||
|
||||
abstract public function create_snippet( $snippet_data, bool $multisite ): ?Snippet;
|
||||
|
||||
abstract public static function is_active(): bool;
|
||||
|
||||
public function transform( array $data, bool $multisite, bool $auto_add_tags = false, string $tag_value = '' ): array {
|
||||
$snippets = [];
|
||||
|
||||
foreach ( $data as $snippet_item ) {
|
||||
if ( ! is_array( $snippet_item ) && ! is_object( $snippet_item ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$snippet = $this->create_snippet( $snippet_item, $multisite );
|
||||
|
||||
if ( $snippet ) {
|
||||
if ( $auto_add_tags && ! empty( $tag_value ) ) {
|
||||
if ( ! empty( $snippet->tags ) ) {
|
||||
$snippet->add_tag( $tag_value );
|
||||
} else {
|
||||
$snippet->tags = [ $tag_value ];
|
||||
}
|
||||
}
|
||||
|
||||
$snippets[] = $snippet;
|
||||
}
|
||||
}
|
||||
|
||||
return $snippets;
|
||||
}
|
||||
|
||||
public function import( $request ) {
|
||||
$ids_to_import = $request->get_param( 'ids' ) ?? [];
|
||||
$multisite = $request->get_param( 'network' ) ?? false;
|
||||
$auto_add_tags = $request->get_param( 'auto_add_tags' ) ?? false;
|
||||
$tag_value = $request->get_param( 'tag_value' ) ?? '';
|
||||
|
||||
$data = $this->get_data( $ids_to_import );
|
||||
|
||||
$snippets = $this->transform( $data, $multisite, $auto_add_tags, $tag_value );
|
||||
|
||||
$imported = $this->save_snippets( $snippets );
|
||||
|
||||
return [
|
||||
'imported' => $imported,
|
||||
];
|
||||
}
|
||||
|
||||
public function get_items( $request ) {
|
||||
return $this->get_data();
|
||||
}
|
||||
|
||||
protected function save_snippets( array $snippets ): array {
|
||||
$imported = [];
|
||||
|
||||
foreach ( $snippets as $snippet ) {
|
||||
$saved_snippet = save_snippet( $snippet );
|
||||
|
||||
$snippet_id = $saved_snippet->id;
|
||||
|
||||
if ( $snippet_id ) {
|
||||
$imported[] = $snippet_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $imported;
|
||||
}
|
||||
|
||||
public function register_rest_routes() {
|
||||
$namespace = REST_API_NAMESPACE . self::VERSION;
|
||||
|
||||
register_rest_route( $namespace, $this->get_name(), [
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [ $this, 'get_items' ],
|
||||
'permission_callback' => function() {
|
||||
return current_user_can( 'manage_options' );
|
||||
},
|
||||
] );
|
||||
|
||||
register_rest_route( $namespace, $this->get_name() . '/import', [
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => [ $this, 'import' ],
|
||||
'permission_callback' => function() {
|
||||
return current_user_can( 'manage_options' );
|
||||
},
|
||||
'args' => [
|
||||
'ids' => [
|
||||
'type' => 'array',
|
||||
'required' => false,
|
||||
],
|
||||
'network' => [
|
||||
'type' => 'boolean',
|
||||
'required' => false,
|
||||
],
|
||||
'auto_add_tags' => [
|
||||
'type' => 'boolean',
|
||||
'required' => false,
|
||||
],
|
||||
'tag_value' => [
|
||||
'type' => 'string',
|
||||
'required' => false,
|
||||
],
|
||||
],
|
||||
] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace Code_Snippets;
|
||||
|
||||
class Insert_Headers_And_Footers_Importer extends Importer_Base {
|
||||
|
||||
private const FIELD_MAPPINGS = [
|
||||
'title' => 'name',
|
||||
'note' => 'desc',
|
||||
'code' => 'code',
|
||||
'tags' => 'tags',
|
||||
'location' => 'scope',
|
||||
'priority' => 'priority',
|
||||
'modified' => 'modified',
|
||||
];
|
||||
|
||||
private const PHP_SCOPE_TRANSFORMATIONS = [
|
||||
'everywhere' => 'global',
|
||||
'admin_only' => 'admin',
|
||||
'frontend_only' => 'front-end',
|
||||
];
|
||||
|
||||
private const HTML_SCOPE_TRANSFORMATIONS = [
|
||||
'' => 'content',
|
||||
'site_wide_header' => 'head-content',
|
||||
'site_wide_footer' => 'footer-content',
|
||||
];
|
||||
|
||||
public function get_name() {
|
||||
return 'insert-headers-and-footers';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'WPCode (Insert Headers and Footers)', 'code-snippets' );
|
||||
}
|
||||
|
||||
public static function is_active(): bool {
|
||||
return is_plugin_active( 'insert-headers-and-footers/ihaf.php' );
|
||||
}
|
||||
|
||||
public function get_data( array $ids_to_import = [] ) {
|
||||
$query_args = [
|
||||
'post_type' => 'wpcode',
|
||||
'post_status' => [
|
||||
'publish',
|
||||
'draft',
|
||||
],
|
||||
'nopaging' => true,
|
||||
];
|
||||
|
||||
if ( ! empty( $ids_to_import ) ) {
|
||||
$query_args['include'] = $ids_to_import;
|
||||
}
|
||||
|
||||
$data = [];
|
||||
$snippets = get_posts( $query_args );
|
||||
|
||||
foreach ( $snippets as $snippet_item ) {
|
||||
$snippet = new \WPCode_Snippet( $snippet_item );
|
||||
$snippet_data = $snippet->get_data_for_caching();
|
||||
$snippet_data['tags'] = $snippet->get_tags();
|
||||
$snippet_data['note'] = $snippet->get_note();
|
||||
$snippet_data['cloud_id'] = null;
|
||||
$snippet_data['custom_shortcode'] = $snippet->get_custom_shortcode();
|
||||
$snippet_data['table_data'] = [
|
||||
'id' => $snippet_item->ID,
|
||||
'title' => $snippet_item->post_title,
|
||||
];
|
||||
|
||||
$data[] = apply_filters( 'wpcode_export_snippet_data', $snippet_data, $snippet );
|
||||
}
|
||||
|
||||
$data = array_reverse( $data );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function create_snippet( $snippet_data, bool $multisite ): ?Snippet {
|
||||
$code_type = $snippet_data['code_type'] ?? '';
|
||||
$is_supported_code_type = in_array( $code_type, [ 'php', 'css', 'html', 'js' ], true );
|
||||
if ( ! $is_supported_code_type ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$snippet = new Snippet();
|
||||
$snippet->network = $multisite;
|
||||
|
||||
foreach ( self::FIELD_MAPPINGS as $source_field => $target_field ) {
|
||||
if ( ! isset( $snippet_data[ $source_field ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $this->transform_field_value(
|
||||
$target_field,
|
||||
$snippet_data[ $source_field ],
|
||||
$snippet_data
|
||||
);
|
||||
|
||||
$scope_not_supported = 'scope' === $target_field && null === $value;
|
||||
if ( $scope_not_supported ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$snippet->set_field( $target_field, $value );
|
||||
}
|
||||
|
||||
return $snippet;
|
||||
}
|
||||
|
||||
private function transform_field_value( string $target_field, $value, array $snippet_data ) {
|
||||
if ( 'scope' === $target_field ) {
|
||||
return $this->transform_scope_value( $value, $snippet_data );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function transform_scope_value( $location_value, array $snippet_data ): ?string {
|
||||
if ( ! is_scalar( $location_value ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$code_type = $snippet_data['code_type'];
|
||||
|
||||
switch ( $code_type ) {
|
||||
case 'html':
|
||||
$transformations = self::HTML_SCOPE_TRANSFORMATIONS;
|
||||
break;
|
||||
case 'php':
|
||||
$transformations = self::PHP_SCOPE_TRANSFORMATIONS;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
return $transformations[ $location_value ] ?? null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace Code_Snippets;
|
||||
|
||||
class Insert_PHP_Code_Snippet_Importer extends Importer_Base {
|
||||
|
||||
private const FIELD_MAPPINGS = [
|
||||
'title' => 'name',
|
||||
'content' => 'code',
|
||||
'insertionLocationType' => 'scope',
|
||||
];
|
||||
|
||||
private const SCOPE_TRANSFORMATIONS = [
|
||||
0 => 'single-use',
|
||||
2 => 'admin',
|
||||
3 => 'front-end',
|
||||
];
|
||||
|
||||
private const SHORTCODE_SCOPE_TRANSFORMATIONS = [
|
||||
3 => 'content',
|
||||
];
|
||||
|
||||
public function get_name() {
|
||||
return 'insert-php-code-snippet';
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
return esc_html__( 'Insert PHP Code Snippet', 'code-snippets' );
|
||||
}
|
||||
|
||||
public static function is_active(): bool {
|
||||
return is_plugin_active( 'insert-php-code-snippet/insert-php-code-snippet.php' );
|
||||
}
|
||||
|
||||
public function get_data( array $ids_to_import = [] ) {
|
||||
global $wpdb;
|
||||
$table_name = $wpdb->prefix . 'xyz_ips_short_code';
|
||||
$sql = "SELECT * FROM `{$table_name}`";
|
||||
|
||||
if ( ! empty( $ids_to_import ) ) {
|
||||
$sql .= " WHERE id IN (" . implode( ',', $ids_to_import ) . ")";
|
||||
}
|
||||
|
||||
$snippets = $wpdb->get_results(
|
||||
$sql
|
||||
);
|
||||
|
||||
foreach ( $snippets as $snippet ) {
|
||||
$snippet->table_data = [
|
||||
'id' => (int) $snippet->id,
|
||||
'title' => $snippet->title,
|
||||
];
|
||||
}
|
||||
|
||||
return $snippets;
|
||||
}
|
||||
|
||||
public function create_snippet( $snippet_data, bool $multisite ): ?Snippet {
|
||||
$code_type = $snippet_data->snippet_type ?? '';
|
||||
|
||||
$snippet = new Snippet();
|
||||
$snippet->network = $multisite;
|
||||
|
||||
foreach ( self::FIELD_MAPPINGS as $source_field => $target_field ) {
|
||||
if ( ! isset( $snippet_data->$source_field ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $this->transform_field_value(
|
||||
$target_field,
|
||||
$snippet_data->$source_field,
|
||||
$snippet_data
|
||||
);
|
||||
|
||||
$scope_not_supported = 'scope' === $target_field && null === $value;
|
||||
if ( $scope_not_supported ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$snippet->set_field( $target_field, $value );
|
||||
}
|
||||
|
||||
return $snippet;
|
||||
}
|
||||
|
||||
private function transform_field_value( string $target_field, $value, $snippet_data ) {
|
||||
if ( 'scope' === $target_field ) {
|
||||
return $this->transform_scope_value( $value, $snippet_data );
|
||||
}
|
||||
|
||||
if ( 'code' === $target_field ) {
|
||||
return $this->transform_code_value( $value, $snippet_data );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function transform_scope_value( $location_value, $snippet_data ): ?string {
|
||||
if ( ! is_scalar( $location_value ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$transformations = self::SCOPE_TRANSFORMATIONS;
|
||||
|
||||
if ( '2' === $snippet_data->insertionMethod ) {
|
||||
$transformations = self::SHORTCODE_SCOPE_TRANSFORMATIONS;
|
||||
}
|
||||
|
||||
return $transformations[ $location_value ] ?? null;
|
||||
}
|
||||
|
||||
private function transform_code_value( $code_value, $snippet_data ): ?string {
|
||||
$code = html_entity_decode( $code_value );
|
||||
|
||||
if ( '2' !== $snippet_data->insertionMethod ) {
|
||||
$code = $this->strip_wrapper_tags( $code );
|
||||
}
|
||||
|
||||
return trim( $code );
|
||||
}
|
||||
|
||||
private function strip_wrapper_tags( string $code ): string {
|
||||
return preg_replace( '/^\s*<\?\s*(php)?\s*|\?\>\s*$/i', '', $code );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Code_Snippets;
|
||||
|
||||
use WP_REST_Server;
|
||||
use const Code_Snippets\REST_API_NAMESPACE;
|
||||
|
||||
class Plugins_Import_Manager {
|
||||
|
||||
const VERSION = 1;
|
||||
|
||||
private $plugin_importers = [];
|
||||
|
||||
public function __construct() {
|
||||
$this->init_plugin_importers();
|
||||
add_action( 'rest_api_init', [ $this, 'register_rest_routes' ] );
|
||||
}
|
||||
|
||||
private function init_plugin_importers() {
|
||||
$this->plugin_importers = [
|
||||
'insert-headers-and-footers' => new Insert_Headers_And_Footers_Importer(),
|
||||
'header-footer-code-manager' => new Header_Footer_Code_Manager_Importer(),
|
||||
'insert-php-code-snippet' => new Insert_PHP_Code_Snippet_Importer(),
|
||||
];
|
||||
}
|
||||
|
||||
public function get_importer( string $source ) {
|
||||
return $this->plugin_importers[ $source ] ?? null;
|
||||
}
|
||||
|
||||
public function get_importers() {
|
||||
if ( empty( $this->plugin_importers ) ) {
|
||||
$this->init_plugin_importers();
|
||||
}
|
||||
|
||||
$plugins_list = [];
|
||||
|
||||
foreach ( $this->plugin_importers as $importer ) {
|
||||
$plugins_list[] = [
|
||||
'name' => $importer->get_name(),
|
||||
'title' => $importer->get_title(),
|
||||
'is_active' => $importer::is_active(),
|
||||
];
|
||||
}
|
||||
|
||||
return $plugins_list;
|
||||
}
|
||||
|
||||
public function register_rest_routes() {
|
||||
$namespace = REST_API_NAMESPACE . self::VERSION;
|
||||
|
||||
register_rest_route( $namespace, 'importers', [
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [ $this, 'get_importers' ],
|
||||
'permission_callback' => function() {
|
||||
return current_user_can( 'manage_options' );
|
||||
},
|
||||
] );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user