315 lines
9.5 KiB
PHP
315 lines
9.5 KiB
PHP
<?php
|
|
/**
|
|
* Mapping Functions
|
|
*
|
|
* @package RobotsTxt\DocumentationMarkdown
|
|
* @since 1.0.0
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Get all mappings
|
|
*
|
|
* @since 1.0.0
|
|
*
|
|
* @return array Array of mappings.
|
|
*/
|
|
function robotstxt_docmd_get_all_mappings() {
|
|
$args = array(
|
|
'post_type' => 'robotstxt_map',
|
|
'posts_per_page' => -1,
|
|
'post_status' => 'publish',
|
|
'orderby' => 'title',
|
|
'order' => 'ASC',
|
|
);
|
|
|
|
$query = new WP_Query( $args );
|
|
$mappings = array();
|
|
|
|
foreach ( $query->posts as $post ) {
|
|
$mapping = robotstxt_docmd_get_mapping( $post->ID );
|
|
if ( $mapping ) {
|
|
$mappings[] = $mapping;
|
|
}
|
|
}
|
|
|
|
wp_reset_postdata();
|
|
|
|
return $mappings;
|
|
}
|
|
|
|
/**
|
|
* Get single mapping
|
|
*
|
|
* @since 1.0.0
|
|
*
|
|
* @param int $mapping_id Mapping post ID.
|
|
* @return array|null Mapping data or null.
|
|
*/
|
|
function robotstxt_docmd_get_mapping( $mapping_id ) {
|
|
$post = get_post( $mapping_id );
|
|
|
|
if ( ! $post || 'robotstxt_map' !== $post->post_type ) {
|
|
return null;
|
|
}
|
|
|
|
$repo_owner = get_post_meta( $mapping_id, '_robotstxt_docmd_repo_owner', true );
|
|
$repo_name = get_post_meta( $mapping_id, '_robotstxt_docmd_repo_name', true );
|
|
$file_path = get_post_meta( $mapping_id, '_robotstxt_docmd_file_path', true );
|
|
$branch = get_post_meta( $mapping_id, '_robotstxt_docmd_branch', true );
|
|
|
|
if ( empty( $branch ) ) {
|
|
$branch = 'main';
|
|
}
|
|
|
|
return array(
|
|
'id' => $mapping_id,
|
|
'title' => $post->post_title,
|
|
'repo_owner' => $repo_owner,
|
|
'repo_name' => $repo_name,
|
|
'file_path' => $file_path,
|
|
'branch' => $branch,
|
|
'github_url' => sprintf( 'https://github.com/%s/%s/blob/%s/%s', $repo_owner, $repo_name, $branch, $file_path ),
|
|
'target_post_type' => get_post_meta( $mapping_id, '_robotstxt_docmd_target_post_type', true ),
|
|
'target_post_id' => absint( get_post_meta( $mapping_id, '_robotstxt_docmd_target_post_id', true ) ),
|
|
'target_author' => absint( get_post_meta( $mapping_id, '_robotstxt_docmd_target_author', true ) ),
|
|
'target_parent' => absint( get_post_meta( $mapping_id, '_robotstxt_docmd_target_parent', true ) ),
|
|
'sync_enabled' => (bool) get_post_meta( $mapping_id, '_robotstxt_docmd_sync_enabled', true ),
|
|
'sync_frequency' => get_post_meta( $mapping_id, '_robotstxt_docmd_sync_frequency', true ),
|
|
'sync_status' => get_post_meta( $mapping_id, '_robotstxt_docmd_sync_status', true ) ? get_post_meta( $mapping_id, '_robotstxt_docmd_sync_status', true ) : 'never',
|
|
'last_sync' => get_post_meta( $mapping_id, '_robotstxt_docmd_last_sync', true ),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Create mapping
|
|
*
|
|
* @since 1.0.0
|
|
*
|
|
* @param array $data Mapping data.
|
|
* @return int|WP_Error Mapping ID or error.
|
|
*/
|
|
function robotstxt_docmd_create_mapping( $data ) {
|
|
// Check for duplicates.
|
|
if ( robotstxt_docmd_is_file_mapped( $data['repo_owner'], $data['repo_name'], $data['file_path'], $data['branch'] ) ) {
|
|
return new WP_Error( 'duplicate_mapping', __( 'This file is already mapped', 'robotstxt-documentation-markdown' ) );
|
|
}
|
|
|
|
// Create mapping post.
|
|
$post_id = wp_insert_post(
|
|
array(
|
|
'post_title' => $data['title'],
|
|
'post_type' => 'robotstxt_map',
|
|
'post_status' => 'publish',
|
|
),
|
|
true
|
|
);
|
|
|
|
if ( is_wp_error( $post_id ) ) {
|
|
return $post_id;
|
|
}
|
|
|
|
// Save metadata.
|
|
update_post_meta( $post_id, '_robotstxt_docmd_repo_owner', $data['repo_owner'] );
|
|
update_post_meta( $post_id, '_robotstxt_docmd_repo_name', $data['repo_name'] );
|
|
update_post_meta( $post_id, '_robotstxt_docmd_file_path', $data['file_path'] );
|
|
update_post_meta( $post_id, '_robotstxt_docmd_branch', $data['branch'] );
|
|
update_post_meta( $post_id, '_robotstxt_docmd_target_post_type', $data['target_post_type'] );
|
|
update_post_meta( $post_id, '_robotstxt_docmd_target_author', $data['target_author'] );
|
|
update_post_meta( $post_id, '_robotstxt_docmd_target_parent', $data['target_parent'] ?? 0 );
|
|
update_post_meta( $post_id, '_robotstxt_docmd_sync_enabled', $data['sync_enabled'] ? 1 : 0 );
|
|
update_post_meta( $post_id, '_robotstxt_docmd_sync_frequency', $data['sync_frequency'] );
|
|
|
|
if ( ! empty( $data['target_post_id'] ) ) {
|
|
update_post_meta( $post_id, '_robotstxt_docmd_target_post_id', $data['target_post_id'] );
|
|
}
|
|
|
|
// Schedule cron if enabled.
|
|
if ( $data['sync_enabled'] && 'never' !== $data['sync_frequency'] ) {
|
|
robotstxt_docmd_schedule_mapping_sync( $post_id, $data['sync_frequency'] );
|
|
}
|
|
|
|
return $post_id;
|
|
}
|
|
|
|
/**
|
|
* Update mapping
|
|
*
|
|
* @since 1.0.0
|
|
*
|
|
* @param int $mapping_id Mapping ID.
|
|
* @param array $data Mapping data.
|
|
* @return bool|WP_Error True on success or error.
|
|
*/
|
|
function robotstxt_docmd_update_mapping( $mapping_id, $data ) {
|
|
// Update post title.
|
|
wp_update_post(
|
|
array(
|
|
'ID' => $mapping_id,
|
|
'post_title' => $data['title'],
|
|
)
|
|
);
|
|
|
|
// Update metadata.
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_repo_owner', $data['repo_owner'] );
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_repo_name', $data['repo_name'] );
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_file_path', $data['file_path'] );
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_branch', $data['branch'] );
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_target_post_type', $data['target_post_type'] );
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_target_author', $data['target_author'] );
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_target_parent', $data['target_parent'] ?? 0 );
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_sync_enabled', $data['sync_enabled'] ? 1 : 0 );
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_sync_frequency', $data['sync_frequency'] );
|
|
|
|
if ( ! empty( $data['target_post_id'] ) ) {
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_target_post_id', $data['target_post_id'] );
|
|
}
|
|
|
|
// Update cron schedule.
|
|
robotstxt_docmd_unschedule_mapping_sync( $mapping_id );
|
|
if ( $data['sync_enabled'] && 'never' !== $data['sync_frequency'] ) {
|
|
robotstxt_docmd_schedule_mapping_sync( $mapping_id, $data['sync_frequency'] );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Delete mapping
|
|
*
|
|
* @since 1.0.0
|
|
*
|
|
* @param int $mapping_id Mapping ID.
|
|
* @return bool True on success.
|
|
*/
|
|
function robotstxt_docmd_delete_mapping( $mapping_id ) {
|
|
robotstxt_docmd_unschedule_mapping_sync( $mapping_id );
|
|
wp_delete_post( $mapping_id, true );
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Check if file is already mapped
|
|
*
|
|
* @since 1.0.0
|
|
*
|
|
* @param string $owner Repository owner.
|
|
* @param string $repo Repository name.
|
|
* @param string $file_path File path.
|
|
* @param string $branch Branch name.
|
|
* @return bool True if mapped.
|
|
*/
|
|
function robotstxt_docmd_is_file_mapped( $owner, $repo, $file_path, $branch ) {
|
|
$args = array(
|
|
'post_type' => 'robotstxt_map',
|
|
'posts_per_page' => 1,
|
|
'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
|
|
array(
|
|
'key' => '_robotstxt_docmd_repo_owner',
|
|
'value' => $owner,
|
|
),
|
|
array(
|
|
'key' => '_robotstxt_docmd_repo_name',
|
|
'value' => $repo,
|
|
),
|
|
array(
|
|
'key' => '_robotstxt_docmd_file_path',
|
|
'value' => $file_path,
|
|
),
|
|
array(
|
|
'key' => '_robotstxt_docmd_branch',
|
|
'value' => $branch,
|
|
),
|
|
),
|
|
);
|
|
|
|
$query = new WP_Query( $args );
|
|
return $query->have_posts();
|
|
}
|
|
|
|
/**
|
|
* Sync mapping (pull content from GitHub and update WordPress)
|
|
*
|
|
* @since 1.0.0
|
|
*
|
|
* @param int $mapping_id Mapping ID.
|
|
* @return bool|WP_Error True on success or error.
|
|
*/
|
|
function robotstxt_docmd_sync_mapping( $mapping_id ) {
|
|
$mapping = robotstxt_docmd_get_mapping( $mapping_id );
|
|
|
|
if ( ! $mapping ) {
|
|
return new WP_Error( 'invalid_mapping', __( 'Mapping not found', 'robotstxt-documentation-markdown' ) );
|
|
}
|
|
|
|
// Update status.
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_sync_status', 'pending' );
|
|
|
|
// Get settings.
|
|
$settings = get_option( 'robotstxt_docmd_settings', array() );
|
|
$token = $settings['github_token'] ?? '';
|
|
|
|
if ( empty( $token ) ) {
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_sync_status', 'error' );
|
|
return new WP_Error( 'no_token', __( 'GitHub token not configured', 'robotstxt-documentation-markdown' ) );
|
|
}
|
|
|
|
// Get file content from GitHub.
|
|
$content = robotstxt_docmd_get_file_content(
|
|
$mapping['repo_owner'],
|
|
$mapping['repo_name'],
|
|
$mapping['file_path'],
|
|
$mapping['branch'],
|
|
$token
|
|
);
|
|
|
|
if ( is_wp_error( $content ) ) {
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_sync_status', 'error' );
|
|
return $content;
|
|
}
|
|
|
|
// Convert Markdown to HTML using CommonMark.
|
|
$converter = new \League\CommonMark\CommonMarkConverter();
|
|
$html_content = $converter->convert( $content )->getContent();
|
|
|
|
// Create or update WordPress post.
|
|
if ( empty( $mapping['target_post_id'] ) ) {
|
|
// Create new post.
|
|
$post_id = wp_insert_post(
|
|
array(
|
|
'post_title' => $mapping['title'],
|
|
'post_content' => $html_content,
|
|
'post_type' => $mapping['target_post_type'],
|
|
'post_status' => 'publish',
|
|
'post_author' => $mapping['target_author'],
|
|
'post_parent' => $mapping['target_parent'],
|
|
),
|
|
true
|
|
);
|
|
|
|
if ( is_wp_error( $post_id ) ) {
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_sync_status', 'error' );
|
|
return $post_id;
|
|
}
|
|
|
|
// Save the post ID for future syncs.
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_target_post_id', $post_id );
|
|
} else {
|
|
// Update existing post.
|
|
wp_update_post(
|
|
array(
|
|
'ID' => $mapping['target_post_id'],
|
|
'post_content' => $html_content,
|
|
)
|
|
);
|
|
}
|
|
|
|
// Update sync status.
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_sync_status', 'success' );
|
|
update_post_meta( $mapping_id, '_robotstxt_docmd_last_sync', current_time( 'mysql' ) );
|
|
|
|
return true;
|
|
}
|