File: /var/www/vhosts/uyarreklam.com.tr/httpdocs/cloud.tar
class-cloud-api.php 0000644 00000031716 15154001452 0010242 0 ustar 00 <?php
namespace Code_Snippets\Cloud;
use Code_Snippets\Snippet;
use WP_Error;
use function Code_Snippets\get_snippet_by_cloud_id;
use function Code_Snippets\get_snippets;
use function Code_Snippets\save_snippet;
use function Code_Snippets\update_snippet_fields;
/**
* Functions used to manage cloud synchronisation.
*
* @package Code_Snippets
*/
class Cloud_API {
/**
* Key used to access the local-to-cloud map transient data.
*/
private const CLOUD_MAP_TRANSIENT_KEY = 'cs_local_to_cloud_map';
/**
* Days to cache data retrieved from API.
*/
private const DAYS_TO_STORE_CS = 1;
/**
* Name of key used to cache cloud settings.
*
* @var string
*/
private const CLOUD_SETTINGS_CACHE_KEY = 'code_snippets_cloud_settings';
/**
* Token used for public API access.
*
* @var string
*/
private const CLOUD_SEARCH_API_TOKEN = 'csc-1a2b3c4d5e6f7g8h9i0j';
/**
* Cached list of cloud links.
*
* @var Cloud_Link[]|null
*/
private ?array $cached_cloud_links = null;
/**
* Retrieve the Cloud URL from wp-config or fallback to default.
*
* @return string
*/
public static function get_cloud_url(): string {
return defined( 'CS_CLOUD_URL' )
? CS_CLOUD_URL
: 'https://codesnippets.cloud/';
}
/**
* Retrieve the Cloud API URL from wp-config or fallback to default.
*
* @return string
*/
public static function get_cloud_api_url(): string {
return defined( 'CS_CLOUD_API_URL' )
? CS_CLOUD_API_URL
: self::get_cloud_url() . 'api/v1/';
}
/**
* Retrieve the cloud local token.
*
* @return string
*/
public static function get_local_token(): string {
return self::CLOUD_SEARCH_API_TOKEN;
}
/**
* Check that the cloud key is valid and verified.
*
* @return boolean
*/
public static function is_cloud_key_verified(): bool {
return false;
}
/**
* Check if the API key is set and verified.
*
* @return boolean
*/
public static function is_cloud_connection_available(): bool {
return false;
}
/**
* Create local-to-cloud map to keep track of local snippets that have been synced to the cloud.
*
* @return Cloud_Link[]
*/
private function get_cloud_links(): ?array {
// Return the cached data if available.
if ( is_array( $this->cached_cloud_links ) ) {
return $this->cached_cloud_links;
}
// Fetch data from the stored transient, if available.
$transient_data = get_transient( self::CLOUD_MAP_TRANSIENT_KEY );
if ( is_array( $transient_data ) ) {
$this->cached_cloud_links = $transient_data;
return $this->cached_cloud_links;
}
// Otherwise, regenerate the local-to-cloud-map.
$this->cached_cloud_links = [];
// Fetch and iterate through all local snippets to create the map.
foreach ( get_snippets() as $local_snippet ) {
// Skip snippets that are only stored locally.
if ( ! $local_snippet->cloud_id ) {
continue;
}
$link = new Cloud_Link();
$cloud_id_owner = $this->get_cloud_id_and_ownership( $local_snippet->cloud_id );
$cloud_id_int = intval( $cloud_id_owner['cloud_id'] );
$link->local_id = $local_snippet->id;
$link->cloud_id = $cloud_id_int;
$link->is_owner = $cloud_id_owner['is_owner'];
// Check if cloud id exists in cloud_id_rev array - this shows if the snippet is in the codevault.
$link->in_codevault = $cloud_id_rev[ $cloud_id_int ] ?? false;
// Get the cloud snippet revision if in codevault get from cloud_id_rev array otherwise get from cloud.
if ( $link->in_codevault ) {
$cloud_snippet_revision = $cloud_id_rev[ $cloud_id_int ] ?? $this->get_cloud_snippet_revision( $local_snippet->cloud_id );
$link->update_available = $local_snippet->revision < $cloud_snippet_revision;
}
$this->cached_cloud_links[] = $link;
}
set_transient(
self::CLOUD_MAP_TRANSIENT_KEY,
$this->cached_cloud_links,
DAY_IN_SECONDS * self::DAYS_TO_STORE_CS
);
return $this->cached_cloud_links;
}
/**
* Get ownership and Cloud ID of a snippet.
*
* @param string $cloud_id Cloud ID.
*
* @return array<string, mixed>
*/
public function get_cloud_id_and_ownership( string $cloud_id ): array {
$cloud_id_owner = explode( '_', $cloud_id );
return [
'cloud_id' => (int) $cloud_id_owner[0] ?? '',
'is_owner' => isset( $cloud_id_owner[1] ) && $cloud_id_owner[1],
'is_owner_string' => isset( $cloud_id_owner[1] ) && $cloud_id_owner[1] ? '1' : '0',
];
}
/**
* Unpack JSON data from a request response.
*
* @param array|WP_Error $response Response from wp_request_*.
*
* @return array<string, mixed>|null Associative array of JSON data on success, null on failure.
*/
private static function unpack_request_json( $response ): ?array {
$body = wp_remote_retrieve_body( $response );
return $body ? json_decode( $body, true ) : null;
}
/**
* Search Code Snippets Cloud -> Static Function
*
* @param string $search_method Search by name of codevault or keyword(s).
* @param string $search Search query.
* @param integer $page Search result page to retrieve. Defaults to '0'.
*
* @return Cloud_Snippets Result of search query.
*/
public static function fetch_search_results( string $search_method, string $search, int $page = 0 ): Cloud_Snippets {
$api_url = add_query_arg(
[
's_method' => $search_method,
's' => $search,
'page' => $page,
'site_token' => self::get_local_token(),
'site_host' => wp_parse_url( get_site_url(), PHP_URL_HOST ),
],
self::get_cloud_api_url() . 'public/search'
);
$results = self::unpack_request_json( wp_remote_get( $api_url ) );
$results = new Cloud_Snippets( $results );
$results->page = $page;
return $results;
}
/**
* Add a new link item to the local-to-cloud map.
*
* @param Cloud_Link $link Link to add.
*
* @return void
*/
public function add_cloud_link( Cloud_Link $link ) {
$local_to_cloud_map = get_transient( self::CLOUD_MAP_TRANSIENT_KEY );
$local_to_cloud_map[] = $link;
set_transient(
self::CLOUD_MAP_TRANSIENT_KEY,
$local_to_cloud_map,
DAY_IN_SECONDS * self::DAYS_TO_STORE_CS
);
}
/**
* Delete a snippet from local-to-cloud map.
*
* @param int $snippet_id Local snippet ID.
*
* @return void
*/
public function delete_snippet_from_transient_data( int $snippet_id ) {
if ( ! $this->cached_cloud_links ) {
$this->get_cloud_links();
}
foreach ( $this->cached_cloud_links as $link ) {
if ( $link->local_id === $snippet_id ) {
// Remove the link from the local_to_cloud_map.
$index = array_search( $link, $this->cached_cloud_links, true );
unset( $this->cached_cloud_links[ $index ] );
// Update the transient data.
set_transient(
self::CLOUD_MAP_TRANSIENT_KEY,
$this->cached_cloud_links,
DAY_IN_SECONDS * self::DAYS_TO_STORE_CS
);
}
}
}
/**
* Retrieve a single cloud snippet from the API.
*
* @param int $cloud_id Remote cloud snippet ID.
*
* @return Cloud_Snippet Retrieved snippet.
*/
public static function get_single_snippet_from_cloud( int $cloud_id ): Cloud_Snippet {
$url = self::get_cloud_api_url() . sprintf( 'public/getsnippet/%s', $cloud_id );
$response = wp_remote_get( $url );
$cloud_snippet = self::unpack_request_json( $response );
return new Cloud_Snippet( $cloud_snippet['snippet'] );
}
/**
* Get the current revision of a single cloud snippet.
*
* @param string $cloud_id Cloud snippet ID.
*
* @return string|null Revision number on success, null otherwise.
*/
public static function get_cloud_snippet_revision( string $cloud_id ): ?string {
$api_url = self::get_cloud_api_url() . sprintf( 'public/getsnippetrevision/%s', $cloud_id );
$body = wp_remote_retrieve_body( wp_remote_get( $api_url ) );
if ( ! $body ) {
return null;
}
$cloud_snippet_revision = json_decode( $body, true );
return $cloud_snippet_revision['snippet_revision'] ?? null;
}
/**
* Download a snippet from the cloud.
*
* @param int|string $cloud_id The cloud ID of the snippet as string from query args.
* @param string $source Unused in Core.
* @param string $action The action to be performed: 'download' or 'update'.
*
* @return array<string, string|bool> Result of operation: an array with `success` and `error_message` keys.
*
* @noinspection PhpUnusedParameterInspection
*/
public function download_or_update_snippet( int $cloud_id, string $source, string $action ): array {
$cloud_id = intval( $cloud_id );
$snippet_to_store = $this->get_single_snippet_from_cloud( $cloud_id );
switch ( $action ) {
case 'download':
return $this->download_snippet_from_cloud( $snippet_to_store );
case 'update':
return $this->update_snippet_from_cloud( $snippet_to_store );
default:
return [
'success' => false,
'error' => __( 'Invalid action.', 'code-snippets' ),
];
}
}
/**
* Download a snippet from the cloud.
*
* @param Cloud_Snippet $snippet_to_store The snippet to be downloaded.
*
* @return array The result of the download.
*/
public function download_snippet_from_cloud( Cloud_Snippet $snippet_to_store ): array {
$snippet = new Snippet( $snippet_to_store );
// Set the snippet id to 0 to ensure that the snippet is saved as a new snippet.
$ownership = $snippet_to_store->is_owner ? '1' : '0';
$snippet->id = 0;
$snippet->active = 0;
$snippet->cloud_id = $snippet_to_store->id . '_' . $ownership;
$snippet->desc = $snippet_to_store->description ? $snippet_to_store->description : '';
// Save the snippet to the database.
$new_snippet = save_snippet( $snippet );
$link = new Cloud_Link();
$link->local_id = $new_snippet->id;
$link->cloud_id = $snippet_to_store->id;
$link->is_owner = $snippet_to_store->is_owner;
$link->in_codevault = false;
$link->update_available = false;
$this->add_cloud_link( $link );
return [
'success' => true,
'action' => 'Single Downloaded',
'snippet_id' => $new_snippet->id,
'link_id' => $link->cloud_id,
];
}
/**
* Update a snippet from the cloud.
*
* @param Cloud_Snippet $snippet_to_store Snippet to be updated.
*
* @return array The result of the update.
*/
public function update_snippet_from_cloud( Cloud_Snippet $snippet_to_store ): array {
$cloud_id = $snippet_to_store->id . '_' . ( $snippet_to_store->is_owner ? '1' : '0' );
$local_snippet = get_snippet_by_cloud_id( sanitize_key( $cloud_id ) );
// Only update the code, active and revision fields.
$fields = [
'code' => $snippet_to_store->code,
'active' => false,
'revision' => $snippet_to_store->revision,
];
update_snippet_fields( $local_snippet->id, $fields );
$this->clear_caches();
return [
'success' => true,
'action' => __( 'Updated', 'code-snippets' ),
];
}
/**
* Find the cloud link for a given cloud snippet identifier.
*
* @param int $cloud_id Cloud ID.
*
* @return Cloud_Link|null
*/
public function get_link_for_cloud_id( int $cloud_id ): ?Cloud_Link {
$cloud_links = $this->get_cloud_links();
if ( $cloud_links ) {
foreach ( $cloud_links as $cloud_link ) {
if ( $cloud_link->cloud_id === $cloud_id ) {
return $cloud_link;
}
}
}
return null;
}
/**
* Find the cloud link for a given cloud snippet.
*
* @param Cloud_Snippet $cloud_snippet Cloud snippet.
*
* @return Cloud_Link|null
*/
public function get_link_for_cloud_snippet( Cloud_Snippet $cloud_snippet ): ?Cloud_Link {
return $this->get_link_for_cloud_id( $cloud_snippet->id );
}
/**
* Translate a snippet scope to a type.
*
* @param string $scope The scope of the snippet.
*
* @return string The type of the snippet.
*/
public static function get_type_from_scope( string $scope ): string {
switch ( $scope ) {
case 'global':
return 'php';
case 'site-css':
return 'css';
case 'site-footer-js':
return 'js';
case 'content':
return 'html';
default:
return '';
}
}
/**
* Translate a snippet status to a status-name.
*
* @param int $status The scope of the snippet.
*
* @return string The style to be used for the stats badge.
*/
public static function get_status_name_from_status( int $status ): string {
switch ( $status ) {
case 3:
return __( 'Private', 'code-snippets' );
case 4:
return __( 'Public', 'code-snippets' );
case 5:
return __( 'Unverified', 'code-snippets' );
case 6:
return __( 'AI Verified', 'code-snippets' );
case 8:
return __( 'Pro Verified', 'code-snippets' );
default:
return '';
}
}
/**
* Renders the html for the preview thickbox popup.
*
* @return void
*/
public static function render_cloud_snippet_thickbox() {
add_thickbox();
?>
<div id="show-code-preview" style="display: none;">
<h3 id="snippet-name-thickbox"></h3>
<h4><?php esc_html_e( 'Snippet Code:', 'code-snippets' ); ?></h4>
<pre class="thickbox-code-viewer">
<code id="snippet-code-thickbox"></code>
</pre>
</div>
<?php
}
/**
* Refresh the cached synced data.
*
* @return void
*/
public function clear_caches() {
$this->cached_cloud_links = null;
delete_transient( self::CLOUD_MAP_TRANSIENT_KEY );
}
}
class-cloud-link.php 0000644 00000003071 15154001452 0010417 0 ustar 00 <?php
namespace Code_Snippets\Cloud;
use Code_Snippets\Data_Item;
/**
* A connection between a local snippet and remote cloud snippet.
*
* @package Code_Snippets
*
* @property integer $local_id ID of local snippet as stored in WordPress database, if applicable.
* @property integer $cloud_id ID of remote snippet on cloud platform, if applicable.
* @property boolean $is_owner Ownership status of remote snippet on cloud platform.
* @property boolean $in_codevault Whether the remote snippet is stored in the users' codevault.
* @property boolean $update_available If synchronised, whether there is an update available on the cloud platform.
*/
class Cloud_Link extends Data_Item {
/**
* Constructor function
*
* @param array<string, mixed>|object $data Initial data fields.
*/
public function __construct( $data = null ) {
parent::__construct(
[
'local_id' => 0,
'cloud_id' => 0,
'is_owner' => false,
'in_codevault' => false,
'update_available' => false,
],
$data
);
}
/**
* Prepare a value before it is stored.
*
* @param mixed $value Value to prepare.
* @param string $field Field name.
*
* @return mixed Value in the correct format.
*/
protected function prepare_field( $value, string $field ) {
switch ( $field ) {
case 'local_id':
case 'remote_id':
return absint( $value );
case 'is_owner':
case 'in_codevault':
case 'update_available':
return is_bool( $value ) ? $value : (bool) $value;
default:
return $value;
}
}
}
class-cloud-search-list-table.php 0000644 00000030257 15154001452 0012773 0 ustar 00 <?php
/**
* Contains the class for handling the cloud search results table
*
* @package Code_Snippets
*/
namespace Code_Snippets\Cloud;
use WP_Plugin_Install_List_Table;
use function Code_Snippets\code_snippets;
if ( ! class_exists( 'WP_Plugin_Install_List_Table' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-plugin-install-list-table.php';
}
/**
* Class for handling the cloud search results table.
*
* @property string $_pagination Pagination HTML.
*
* @package Code_Snippets
*/
class Cloud_Search_List_Table extends WP_Plugin_Install_List_Table {
/**
* Instance of Cloud API class.
*
* @var Cloud_API
*/
protected Cloud_API $cloud_api;
/**
* Items for the cloud list table.
*
* @var Cloud_Snippets
*/
protected Cloud_Snippets $cloud_snippets;
/**
* Class constructor.
*/
public function __construct() {
/**
* Declare global variable due to undeclared warning.
*
* @noinspection PhpUnusedLocalVariableInspection
*/
global $tab;
parent::__construct(
[
'singular' => 'cloud-snippet',
'plural' => 'cloud-snippets',
'ajax' => false,
]
);
// Strip the result query arg from the URL.
$_SERVER['REQUEST_URI'] = remove_query_arg( [ 'result' ] );
$this->cloud_api = code_snippets()->cloud_api;
}
/**
* Prepare items for the table.
*
* @return void
*/
public function prepare_items() {
$this->cloud_snippets = $this->fetch_snippets();
$this->items = $this->cloud_snippets->snippets;
$this->process_actions();
$this->set_pagination_args(
[
'per_page' => count( $this->cloud_snippets->snippets ),
'total_items' => $this->cloud_snippets->total_snippets,
'total_pages' => $this->cloud_snippets->total_pages,
]
);
}
/**
* Process any actions that have been submitted, such as downloading cloud snippets to the local database.
*
* @return void
*/
public function process_actions() {
$_SERVER['REQUEST_URI'] = remove_query_arg(
[ 'action', 'snippet', '_wpnonce', 'source', 'cloud-bundle-run', 'cloud-bundle-show', 'bundle_share_name', 'cloud_bundles' ]
);
// Check request is coming form the cloud search page.
if ( isset( $_REQUEST['type'] ) && 'cloud_search' === $_REQUEST['type'] ) {
if ( isset( $_REQUEST['action'], $_REQUEST['snippet'], $_REQUEST['source'] ) ) {
cloud_lts_process_download_action(
sanitize_key( wp_unslash( $_REQUEST['action'] ) ),
sanitize_key( wp_unslash( $_REQUEST['source'] ) ),
sanitize_key( wp_unslash( $_REQUEST['snippet'] ) )
);
}
}
}
/**
* Output table rows.
*
* @return void
*/
public function display_rows() {
/**
* The current table item.
*
* @var $item Cloud_Snippet
*/
foreach ( $this->items as $item ) {
?>
<div class="plugin-card cloud-search-card plugin-card-<?php echo sanitize_html_class( $item->id ); ?>">
<?php
cloud_lts_display_column_hidden_input( 'code', $item );
cloud_lts_display_column_hidden_input( 'name', $item );
?>
<div class="plugin-card-top">
<div class="name column-name">
<h3>
<?php
$link = code_snippets()->cloud_api->get_link_for_cloud_snippet( $item );
if ( $link ) {
printf( '<a href="%s">', esc_url( code_snippets()->get_snippet_edit_url( $link->local_id ) ) );
} else {
printf(
'<a href="%s" title="%s" class="cloud-snippet-preview thickbox" data-snippet="%s" data-lang="%s">',
'#TB_inline?&width=700&height=500&inlineId=show-code-preview',
esc_attr__( 'Preview this snippet', 'code-snippets' ),
esc_attr( $item->id ),
esc_attr( Cloud_API::get_type_from_scope( $item->scope ) )
);
}
echo esc_html( $item->name );
// Grab first tag in array of tags.
$category = count( $item->tags ) > 0 ? strtolower( esc_attr( $item->tags[0] ) ) : '';
printf(
'<img src="%s" class="plugin-icon" alt="%s">',
esc_url( "https://codesnippets.cloud/images/plugin-icons/$category-logo.png" ),
esc_attr( $category )
);
echo '</a>';
?>
</h3>
</div>
<div class="action-links">
<?php echo wp_kses_post( cloud_lts_build_action_links( $item, 'search' ) ); ?>
</div>
<div class="desc column-description">
<p><?php echo wp_kses_post( $this->process_description( $item->description ) ); ?></p>
<p class="authors">
<cite>
<?php
esc_html_e( 'Codevault: ', 'code-snippets' );
printf(
'<a target="_blank" href="%s">%s</a>',
esc_url( sprintf( 'https://codesnippets.cloud/codevault/%s', $item->codevault ) ),
esc_html( $item->codevault )
);
?>
</cite>
</p>
</div>
</div>
<div class="plugin-card-bottom cloud-search-card-bottom">
<div class="vers column-rating voted-info">
<svg xmlns="http://www.w3.org/2000/svg"
fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="thumbs-up">
<path stroke-linecap="round" stroke-linejoin="round"
d="M6.633 10.5c.806 0 1.533-.446 2.031-1.08a9.041 9.041 0 012.861-2.4c.723-.384 1.35-.956 1.653-1.715a4.498 4.498 0 00.322-1.672V3a.75.75 0 01.75-.75A2.25 2.25 0 0116.5 4.5c0 1.152-.26 2.243-.723 3.218-.266.558.107 1.282.725 1.282h3.126c1.026 0 1.945.694 2.054 1.715.045.422.068.85.068 1.285a11.95 11.95 0 01-2.649 7.521c-.388.482-.987.729-1.605.729H13.48c-.483 0-.964-.078-1.423-.23l-3.114-1.04a4.501 4.501 0 00-1.423-.23H5.904M14.25 9h2.25M5.904 18.75c.083.205.173.405.27.602.197.4-.078.898-.523.898h-.908c-.889 0-1.713-.518-1.972-1.368a12 12 0 01-.521-3.507c0-1.553.295-3.036.831-4.398C3.387 10.203 4.167 9.75 5 9.75h1.053c.472 0 .745.556.5.96a8.958 8.958 0 00-1.302 4.665c0 1.194.232 2.333.654 3.375z"></path>
</svg>
<span class="num-ratings" aria-hidden="true">
<?php
// translators: 1: number of votes.
$votes_text = _nx( '%d time', '%d times', $item->vote_count, 'vote count', 'code-snippets' );
$votes_text = sprintf( $votes_text, number_format_i18n( $item->vote_count ) );
// translators: 1: number of users.
$users_text = _n( '%d user', '%d users', $item->total_votes, 'code-snippets' );
$users_text = sprintf( $users_text, number_format_i18n( $item->total_votes ) );
// translators: 1: number of votes with label, 2: number of users with label.
echo esc_html( sprintf( _x( '%1$s by %2$s', 'votes', 'code-snippets' ), $votes_text, $users_text ) );
?>
</span>
</div>
<div class="column-updated">
<strong><?php esc_html_e( 'Last Updated:', 'code-snippets' ); ?></strong>
<?php
// translators: %s: Human-readable time difference.
echo esc_html( sprintf( __( '%s ago', 'code-snippets' ), human_time_diff( strtotime( $item->updated ) ) ) );
?>
</div>
<div class="column-downloaded">
<?php
$status_name = $this->cloud_api->get_status_name_from_status( $item->status );
printf(
'<a class="snippet-type-badge snippet-status" data-type="%s">%s</a>',
esc_attr( sanitize_title_with_dashes( strtolower( $status_name ) ) ),
esc_html( $status_name )
);
?>
<div class="tooltip-box">
<span class="dashicons dashicons-editor-help"></span>
<div class="tooltip-text">
<p class="tooltip-text-title">
<?php esc_html_e( 'Snippet Statuses', 'code-snippets' ); ?>
</p>
<p class="tooltip-text-item">
<a class="snippet-type-badge snippet-status" data-type="public">
<?php esc_html_e( 'Public', 'code-snippets' ); ?></a>
<?php esc_html_e( 'Snippet has passed basic review.', 'code-snippets' ); ?>
</p>
<p class="tooltip-text-item">
<a class="snippet-type-badge snippet-status" data-type="ai-verified">
<?php esc_html_e( 'AI Verified', 'code-snippets' ); ?></a>
<?php esc_html_e( ' Snippet has been tested by our AI bot.', 'code-snippets' ); ?>
</p>
<p class="tooltip-text-item">
<a class="snippet-type-badge snippet-status" data-type="unverified">
<?php esc_html_e( 'Unverified', 'code-snippets' ); ?></a>
<?php esc_html_e( ' Snippet has not undergone any review yet.', 'code-snippets' ); ?>
</p>
<p class="tooltip-text-link">
<a class="tooltip-text-link"
href="https://codesnippets.cloud/getstarted"
target="_blankx">
<?php esc_html_e( 'View the full list.', 'code-snippets' ); ?></a>
</p>
</div>
</div>
</div>
<div class="column-compatibility">
<strong><?php esc_html_e( 'WP Compatability:', 'code-snippets' ); ?></strong>
<?php
if ( empty( $wp_tested ) ) {
echo '<span class="compatibility-untested">', esc_html__( 'Not indicated by author', 'code-snippets' ), '</span>';
} else {
// translators: tested status.
$text = sprintf( __( 'Author states %s', 'code-snippets' ), $wp_tested );
echo '<span class="compatibility-compatible">', esc_html( $text ), '</span>';
}
?>
</div>
</div>
</div>
<?php
}
}
/**
* Process the description text - limit to 150 characters.
*
* @param string|null $description Description as provided by the API.
*
* @return string formatted description string max 150 chars.
*/
protected function process_description( ?string $description ): string {
$description = wp_strip_all_tags( $description );
return strlen( $description ) > 150 ? substr( $description, 0, 150 ) . '…' : $description;
}
/**
* Text displayed when no snippet data is available.
*
* @return void
*/
public function no_items() {
if ( ! empty( $_REQUEST['cloud_search'] ) && count( $this->cloud_snippets->snippets ) < 1 ) {
echo '<p class="no-results">',
esc_html__( 'No snippets or codevault could be found with that search term. Please try again.', 'code-snippets' ),
'</p>';
} else {
echo '<p>', esc_html__( 'Please enter a term to start searching code snippets in the cloud.', 'code-snippets' ), '</p>';
}
}
/**
* Fetch the snippets used to populate the table.
*
* @return Cloud_Snippets
*/
public function fetch_snippets(): Cloud_Snippets {
// Check if search term has been entered.
if ( isset( $_REQUEST['type'], $_REQUEST['cloud_search'], $_REQUEST['cloud_select'] ) &&
'cloud_search' === sanitize_key( wp_unslash( $_REQUEST['type'] ) )
) {
// If we have a search query, then send a search request to cloud server API search endpoint.
$search_query = sanitize_text_field( wp_unslash( $_REQUEST['cloud_search'] ) );
$search_by = sanitize_text_field( wp_unslash( $_REQUEST['cloud_select'] ) );
return Cloud_API::fetch_search_results( $search_by, $search_query, $this->get_pagenum() - 1 );
}
// If no search results, then return empty object.
return new Cloud_Snippets();
}
/**
* Gets the current search result page number.
*
* @return integer
*/
public function get_pagenum(): int {
$page = isset( $_REQUEST['search_page'] ) ? absint( $_REQUEST['search_page'] ) : 0;
if ( isset( $this->_pagination_args['total_pages'] ) && $page > $this->_pagination_args['total_pages'] ) {
$page = $this->_pagination_args['total_pages'];
}
return max( 1, $page );
}
/**
* Display the table.
*
* @return void
*/
public function display() {
Cloud_API::render_cloud_snippet_thickbox();
parent::display();
}
/**
* Displays the pagination.
*
* @param string $which Context where the pagination will be displayed.
*
* @return void
*/
protected function pagination( $which ) {
$total_items = $this->_pagination_args['total_items'];
$total_pages = $this->_pagination_args['total_pages'];
$pagenum = $this->get_pagenum();
if ( 'top' === $which && $total_pages > 1 ) {
$this->screen->render_screen_reader_content( 'heading_pagination' );
}
$paginate = cloud_lts_pagination( $which, 'search', $total_items, $total_pages, $pagenum );
$page_class = $paginate['page_class'];
$output = $paginate['output'];
$this->_pagination = "<div class='tablenav-pages$page_class'>$output</div>";
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $this->_pagination;
// echo wp_kses_post( $this->_pagination ); TODO: This removes the top input box for page number.
}
}
class-cloud-snippet.php 0000644 00000005146 15154001452 0011151 0 ustar 00 <?php
namespace Code_Snippets\Cloud;
use Code_Snippets\Data_Item;
use function Code_Snippets\code_snippets_build_tags_array;
/**
* A snippet object as retrieved from the cloud API.
*
* @since 3.4.0
* @package Code_Snippets
*
* @property int $id The remote ID.
* @property string $name The snippet title.
* @property string $description The formatted description.
* @property string $code The executable code.
* @property array<string> $tags An array of the tags.
* @property string $scope The scope name.
* @property string $codevault Name of user codevault.
* @property string $total_votes The total number of votes.
* @property string $vote_count The number of actual votes.
* @property string $wp_tested Tested with WP version.
* @property string $status Snippet Status ID.
* @property string $created The date and time when the snippet data was first created, in ISO format.
* @property string $updated When the snippet was last updated, in ISO format.
* @property integer $revision The update revision number.
* @property bool $is_owner If user is owner or author of snippet.
*/
class Cloud_Snippet extends Data_Item {
/**
* Constructor function.
*
* @param array<string, mixed>|null $initial_data Initial snippet data.
*/
public function __construct( ?array $initial_data = null ) {
parent::__construct(
[
'id' => '',
'cloud_id' => '',
'name' => '',
'description' => '',
'code' => '',
'tags' => [],
'scope' => '',
'status' => '',
'codevault' => '',
'total_votes' => '',
'vote_count' => '',
'wp_tested' => '',
'created' => '',
'updated' => '',
'revision' => 0,
'is_owner' => false,
'shared_network' => false,
],
$initial_data
);
}
/**
* Prepare a value before it is stored.
*
* @param mixed $value Value to prepare.
* @param string $field Field name.
*
* @return mixed Value in the correct format.
*/
protected function prepare_field( $value, string $field ) {
switch ( $field ) {
case 'id':
case 'revision':
return absint( $value );
case 'is_owner':
return (bool) $value;
case 'description':
return ( null === $value ) ? '' : $value;
case 'tags':
return code_snippets_build_tags_array( $value );
default:
return $value;
}
}
}
class-cloud-snippets.php 0000644 00000004227 15154001452 0011333 0 ustar 00 <?php
namespace Code_Snippets\Cloud;
use Code_Snippets\Data_Item;
/**
* A list of snippets as retrieved from the cloud API.
*
* @since 3.4.0
* @package Code_Snippets
*
* @property Cloud_Snippet[] $snippets List of snippet items for the current page.
* @property integer $page Page of data that this data belongs to.
* @property integer $total_pages Total number of available pages of items.
* @property integer $total_snippets Total number of available snippet items.
* @property array $cloud_id_rev An array of all cloud snippet IDs and their revision numbers.
* @property bool $success If the request has any results.
*/
class Cloud_Snippets extends Data_Item {
/**
* Class constructor.
*
* @param array<string, Cloud_Snippet[]|integer> $initial_data Initial data.
*/
public function __construct( $initial_data = null ) {
parent::__construct(
[
'snippets' => [],
'total_snippets' => 0,
'total_pages' => 0,
'page' => 0,
'cloud_id_rev' => [],
],
$initial_data,
[
'items' => 'snippets',
'total_items' => 'total_snippets',
'page' => 'page',
'cloud_id_rev' => 'cloud_id_rev',
]
);
}
/**
* Prepare a value before it is stored.
*
* @param mixed $value Value to prepare.
* @param string $field Field name.
*
* @return mixed Value in the correct format.
*/
protected function prepare_field( $value, string $field ) {
switch ( $field ) {
case 'page':
case 'total_pages':
case 'total_snippets':
return absint( $value );
default:
return $value;
}
}
/**
* Prepare the `snippets` field by ensuring it is a list of Cloud_Snippets objects.
*
* @param mixed $snippets The field as provided.
*
* @return Cloud_Snippets[] The field in the correct format.
*/
protected function prepare_snippets( $snippets ): array {
$result = [];
$snippets = is_array( $snippets ) ? $snippets : [ $snippets ];
foreach ( $snippets as $snippet ) {
$result[] = $snippet instanceof Cloud_Snippet ? $snippet : new Cloud_Snippet( $snippet );
}
return $result;
}
}
list-table-shared-ops.php 0000644 00000020561 15154001452 0011361 0 ustar 00 <?php
/**
* Functions to perform snippet operations
*
* @package Code_Snippets
*/
namespace Code_Snippets\Cloud;
use function Code_Snippets\code_snippets;
/**
* Display a hidden input field for a certain column and snippet value.
*
* @param string $column_name Column name.
* @param Cloud_Snippet $snippet Column item.
*
* @return void
*/
function cloud_lts_display_column_hidden_input( string $column_name, Cloud_Snippet $snippet ) {
printf(
'<input id="cloud-snippet-%s-%s" class="cloud-snippet-item" type="hidden" name="%s" value="%s" />',
esc_attr( $column_name ),
esc_attr( $snippet->id ),
esc_attr( $column_name ),
esc_attr( $snippet->$column_name )
);
}
/**
* Process the download snippet action
*
* @param string $action Action - 'download' or 'update'.
* @param string $source Source - 'search' or 'cloud'.
* @param string $snippet Snippet ID.
* @param int $codevault_page The current page of the codevault.
*
* @return void
*/
function cloud_lts_process_download_action( string $action, string $source, string $snippet, int $codevault_page = 0 ) {
if ( 'download' === $action || 'update' === $action ) {
$result = code_snippets()->cloud_api->download_or_update_snippet( $snippet, $source, $action, $codevault_page );
if ( $result['success'] ) {
$redirect_uri = $result['snippet_id'] ?
code_snippets()->get_snippet_edit_url( (int) $result['snippet_id'] ) :
add_query_arg( 'result', $result['action'] );
wp_safe_redirect( esc_url_raw( $redirect_uri ) );
exit;
}
}
}
/**
* Build action links for snippet.
*
* @param Cloud_Snippet $cloud_snippet Snippet/Column item.
* @param string $source Source - 'search' or 'codevault'.
*
* @return string
*/
function cloud_lts_build_action_links( Cloud_Snippet $cloud_snippet, string $source ): string {
$lang = Cloud_API::get_type_from_scope( $cloud_snippet->scope );
$link = code_snippets()->cloud_api->get_link_for_cloud_snippet( $cloud_snippet );
$additional_classes = 'search' === $source ? 'action-button-link' : '';
$is_licensed = code_snippets()->licensing->is_licensed();
$download = true;
$action_link = '';
if ( ! $is_licensed && in_array( $lang, [ 'css', 'js' ], true ) ) {
$download = false;
}
if ( $link ) {
if ( $is_licensed && $link->update_available ) {
$download = false;
$update_url = add_query_arg(
[
'action' => 'update',
'snippet' => $cloud_snippet->id,
'source' => $source,
]
);
$action_link = sprintf(
'<a class="cloud-snippet-update %s" href="%s">%s</a>',
$additional_classes,
esc_url( $update_url ),
esc_html__( 'Update Available', 'code-snippets' )
);
} else {
return sprintf(
'<a href="%s" class="cloud-snippet-downloaded %s">%s</a>',
esc_url( code_snippets()->get_snippet_edit_url( $link->local_id ) ),
$additional_classes,
esc_html__( 'View', 'code-snippets' )
);
}
}
if ( $download ) {
$download_url = add_query_arg(
[
'action' => 'download',
'snippet' => $cloud_snippet->id,
'source' => $source,
]
);
$action_link = $is_licensed ?
sprintf(
'<a class="cloud-snippet-download %s" href="%s">%s</a>',
$additional_classes,
esc_url( $download_url ),
esc_html__( 'Download', 'code-snippets' )
) :
sprintf(
'<a class="cloud-snippet-download %s" href="%s" target="_blank"><span class="go-pro-badge">%s</span>%s</a>',
$additional_classes,
'https://codesnippets.pro/pricing/',
esc_html_x( 'Pro', 'pro only', 'code-snippets' ),
esc_html_x( ' Only', 'pro only', 'code-snippets' )
);
}
$thickbox_url = '#TB_inline?&width=700&height=500&inlineId=show-code-preview';
$thickbox_link = sprintf(
'<a href="%s" title="%s" class="cloud-snippet-preview cloud-snippet-preview-style thickbox %s" data-snippet="%s" data-lang="%s">%s</a>',
esc_url( $thickbox_url ),
esc_attr( $cloud_snippet->name ),
$additional_classes,
esc_attr( $cloud_snippet->id ),
esc_attr( $lang ),
esc_html__( 'Preview', 'code-snippets' )
);
return $action_link . $thickbox_link;
}
/**
* Build the pagination functionality
*
* @param string $which Context where the pagination will be displayed.
* @param string $source Source - 'search' or 'cloud'.
* @param int $total_items Total number of items.
* @param int $total_pages Total number of pages.
* @param int $pagenum Current page number.
*
* @return array
*/
function cloud_lts_pagination( string $which, string $source, int $total_items, int $total_pages, int $pagenum ): array {
/* translators: %s: Number of items. */
$num = sprintf( _n( '%s item', '%s items', $total_items, 'code-snippets' ), number_format_i18n( $total_items ) );
$output = '<span class="displaying-num">' . $num . '</span>';
$current = isset( $_REQUEST['cloud_page'] ) ? (int) $_REQUEST['cloud_page'] : $pagenum;
$current_url = remove_query_arg( wp_removable_query_args() ) . '#' . $source;
$page_links = array();
$html_current_page = '';
$total_pages_before = '<span class="paging-input">';
$total_pages_after = '</span></span>';
$disable_first = false;
$disable_last = false;
$disable_prev = false;
$disable_next = false;
if ( 1 === $current ) {
$disable_first = true;
$disable_prev = true;
}
if ( $total_pages === $current ) {
$disable_last = true;
$disable_next = true;
}
if ( $disable_first ) {
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">«</span>';
} else {
$page_links[] = sprintf(
'<a class="first-page button" href="%s"><span class="screen-reader-text">%s</span><span aria-hidden="true">‹</span></a>',
esc_url( remove_query_arg( $source . '_page', $current_url ) ),
esc_html__( 'First page', 'code-snippets' )
);
}
if ( $disable_prev ) {
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">‹</span>';
} else {
$page_links[] = sprintf(
'<a class="prev-page button" href="%s"><span class="screen-reader-text">%s</span><span aria-hidden="true">«</span></a>',
esc_url( add_query_arg( $source . '_page', max( 1, $current - 1 ), $current_url ) ),
esc_html__( 'Previous page', 'code-snippets' )
);
}
if ( 'bottom' === $which ) {
$html_current_page = $current;
$total_pages_before = sprintf( '<span class="screen-reader-text">%s</span><span id="table-paging" class="paging-input"><span class="tablenav-paging-text">', __( 'Current page', 'code-snippets' ) );
}
if ( 'top' === $which ) {
$html_current_page = sprintf(
'<label for="current-page-selector" class="screen-reader-text">%s</label><input class="current-page-selector" id="current-page-selector" type="text" name="%s_page" value="%s" size="%d" aria-describedby="table-paging" /><span class="tablenav-paging-text">',
__( 'Current page', 'code-snippets' ),
$source,
$current,
strlen( $total_pages )
);
}
$html_total_pages = sprintf( '<span class="total-pages">%s</span>', number_format_i18n( $total_pages ) );
/* translators: 1: Current page, 2: Total pages. */
$current_html = _x( '%1$s of %2$s', 'paging', 'code-snippets' );
$page_links[] = $total_pages_before . sprintf( $current_html, $html_current_page, $html_total_pages ) . $total_pages_after;
if ( $disable_next ) {
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">›</span>';
} else {
$page_links[] = sprintf(
'<a class="next-page button" href="%s"><span class="screen-reader-text">%s</span><span aria-hidden="true">%s</span></a>',
esc_url( add_query_arg( $source . '_page', min( $total_pages, $current + 1 ), $current_url ) ),
__( 'Next page' ),
'›'
);
}
if ( $disable_last ) {
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">»</span>';
} else {
$page_links[] = sprintf(
'<a class="last-page button" href="%s"><span class="screen-reader-text">%s</span><span aria-hidden="true">%s</span></a>',
esc_url( add_query_arg( $source . '_page', $total_pages, $current_url ) ),
__( 'Last page', 'code-snippets' ),
'»'
);
}
$pagination_links_class = 'pagination-links';
if ( ! empty( $infinite_scroll ) ) {
$pagination_links_class .= ' hide-if-js';
}
$output .= "\n<span class='$pagination_links_class'>" . implode( "\n", $page_links ) . '</span>';
return [
'output' => $output,
'page_class' => $total_pages ? ( $total_pages < 2 ? ' one-page' : '' ) : ' no-pages',
];
}