v1.0.0
This commit is contained in:
parent
0fcf42b47b
commit
443dceb8ca
4830 changed files with 566609 additions and 230 deletions
244
robotstxt-documentation-markdown-github.php
Normal file
244
robotstxt-documentation-markdown-github.php
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
<?php
|
||||
/**
|
||||
* GitHub API Functions
|
||||
*
|
||||
* @package RobotsTxt\DocumentationMarkdown
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse GitHub URL
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $url GitHub repository URL.
|
||||
* @return array|WP_Error Array with 'owner' and 'repo' or error.
|
||||
*/
|
||||
function robotstxt_docmd_parse_github_url( $url ) {
|
||||
if ( ! str_starts_with( $url, 'https://' ) ) {
|
||||
return new WP_Error( 'invalid_url', __( 'GitHub URL must use HTTPS', 'robotstxt-documentation-markdown' ) );
|
||||
}
|
||||
|
||||
if ( preg_match( '/github\.com\/([a-zA-Z0-9_-]+)\/([a-zA-Z0-9._-]+?)(?:\.git)?\/?$/', $url, $matches ) ) {
|
||||
return array(
|
||||
'owner' => $matches[1],
|
||||
'repo' => $matches[2],
|
||||
);
|
||||
}
|
||||
|
||||
return new WP_Error( 'invalid_format', __( 'Could not parse GitHub URL', 'robotstxt-documentation-markdown' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all markdown files from repository
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $owner Repository owner.
|
||||
* @param string $repo Repository name.
|
||||
* @param string $branch Branch name.
|
||||
* @param string $token GitHub token (encrypted).
|
||||
* @return array|WP_Error Array of files or error.
|
||||
*/
|
||||
function robotstxt_docmd_get_all_markdown_files( $owner, $repo, $branch, $token ) {
|
||||
// Check cache first.
|
||||
$cache_key = sprintf( 'robotstxt_docmd_files_%s_%s_%s', $owner, $repo, $branch );
|
||||
$cached = get_transient( $cache_key );
|
||||
|
||||
if ( false !== $cached ) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
// Decrypt token.
|
||||
$decrypted_token = robotstxt_docmd_decrypt_token( $token );
|
||||
|
||||
// Get files recursively.
|
||||
$files = robotstxt_docmd_get_repository_contents_recursive( $owner, $repo, '', $branch, $decrypted_token );
|
||||
|
||||
if ( is_wp_error( $files ) ) {
|
||||
return $files;
|
||||
}
|
||||
|
||||
// Filter only markdown files.
|
||||
$markdown_files = array_filter(
|
||||
$files,
|
||||
function ( $file ) {
|
||||
return preg_match( '/\.(md|markdown)$/i', $file['path'] );
|
||||
}
|
||||
);
|
||||
|
||||
// Re-index array.
|
||||
$markdown_files = array_values( $markdown_files );
|
||||
|
||||
// Cache for 24 hours.
|
||||
set_transient( $cache_key, $markdown_files, DAY_IN_SECONDS );
|
||||
|
||||
return $markdown_files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get repository contents recursively
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $owner Repository owner.
|
||||
* @param string $repo Repository name.
|
||||
* @param string $path Path in repository.
|
||||
* @param string $branch Branch name.
|
||||
* @param string $token GitHub token (plain).
|
||||
* @param int $depth Current depth (for recursion limit).
|
||||
* @return array|WP_Error Array of files or error.
|
||||
*/
|
||||
function robotstxt_docmd_get_repository_contents_recursive( $owner, $repo, $path, $branch, $token, $depth = 0 ) {
|
||||
// Prevent infinite recursion.
|
||||
if ( $depth > 10 ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$url = sprintf(
|
||||
'https://api.github.com/repos/%s/%s/contents/%s?ref=%s',
|
||||
$owner,
|
||||
$repo,
|
||||
$path,
|
||||
$branch
|
||||
);
|
||||
|
||||
$response = wp_remote_get(
|
||||
$url,
|
||||
array(
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $token,
|
||||
'Accept' => 'application/vnd.github.v3+json',
|
||||
'User-Agent' => 'WordPress-Documentation-Plugin',
|
||||
),
|
||||
'timeout' => 30,
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$code = wp_remote_retrieve_response_code( $response );
|
||||
if ( 200 !== $code ) {
|
||||
return new WP_Error(
|
||||
'github_api_error',
|
||||
sprintf(
|
||||
/* translators: %d: HTTP response code */
|
||||
__( 'GitHub API error: %d', 'robotstxt-documentation-markdown' ),
|
||||
$code
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
$contents = json_decode( $body, true );
|
||||
|
||||
if ( ! is_array( $contents ) ) {
|
||||
return new WP_Error( 'invalid_response', __( 'Invalid GitHub API response', 'robotstxt-documentation-markdown' ) );
|
||||
}
|
||||
|
||||
$files = array();
|
||||
|
||||
foreach ( $contents as $item ) {
|
||||
if ( 'file' === $item['type'] ) {
|
||||
// Skip files larger than 10MB.
|
||||
if ( $item['size'] > 10 * 1024 * 1024 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$files[] = array(
|
||||
'path' => $item['path'],
|
||||
'name' => $item['name'],
|
||||
'size' => $item['size'],
|
||||
'sha' => $item['sha'],
|
||||
);
|
||||
} elseif ( 'dir' === $item['type'] ) {
|
||||
// Recurse into directory.
|
||||
$subfiles = robotstxt_docmd_get_repository_contents_recursive(
|
||||
$owner,
|
||||
$repo,
|
||||
$item['path'],
|
||||
$branch,
|
||||
$token,
|
||||
$depth + 1
|
||||
);
|
||||
|
||||
if ( ! is_wp_error( $subfiles ) ) {
|
||||
$files = array_merge( $files, $subfiles );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file content from GitHub
|
||||
*
|
||||
* @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.
|
||||
* @param string $token GitHub token (encrypted).
|
||||
* @return string|WP_Error File content or error.
|
||||
*/
|
||||
function robotstxt_docmd_get_file_content( $owner, $repo, $file_path, $branch, $token ) {
|
||||
$decrypted_token = robotstxt_docmd_decrypt_token( $token );
|
||||
|
||||
$url = sprintf(
|
||||
'https://api.github.com/repos/%s/%s/contents/%s?ref=%s',
|
||||
$owner,
|
||||
$repo,
|
||||
$file_path,
|
||||
$branch
|
||||
);
|
||||
|
||||
$response = wp_remote_get(
|
||||
$url,
|
||||
array(
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $decrypted_token,
|
||||
'Accept' => 'application/vnd.github.v3+json',
|
||||
'User-Agent' => 'WordPress-Documentation-Plugin',
|
||||
),
|
||||
'timeout' => 30,
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$code = wp_remote_retrieve_response_code( $response );
|
||||
if ( 200 !== $code ) {
|
||||
return new WP_Error(
|
||||
'github_api_error',
|
||||
sprintf(
|
||||
/* translators: %d: HTTP response code */
|
||||
__( 'GitHub API error: %d', 'robotstxt-documentation-markdown' ),
|
||||
$code
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
$data = json_decode( $body, true );
|
||||
|
||||
if ( ! isset( $data['content'] ) || ! isset( $data['encoding'] ) ) {
|
||||
return new WP_Error( 'invalid_response', __( 'Invalid file response from GitHub', 'robotstxt-documentation-markdown' ) );
|
||||
}
|
||||
|
||||
// Decode content (GitHub returns base64).
|
||||
if ( 'base64' === $data['encoding'] ) {
|
||||
return base64_decode( $data['content'] ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
|
||||
}
|
||||
|
||||
return $data['content'];
|
||||
}
|
||||
Loading…
Reference in a new issue