block-styles.php 0000644 00000004611 14720673703 0007703 0 ustar 00 'twentytwentyone-columns-overlap',
'label' => esc_html__( 'Overlap', 'twentytwentyone' ),
)
);
// Cover: Borders.
register_block_style(
'core/cover',
array(
'name' => 'twentytwentyone-border',
'label' => esc_html__( 'Borders', 'twentytwentyone' ),
)
);
// Group: Borders.
register_block_style(
'core/group',
array(
'name' => 'twentytwentyone-border',
'label' => esc_html__( 'Borders', 'twentytwentyone' ),
)
);
// Image: Borders.
register_block_style(
'core/image',
array(
'name' => 'twentytwentyone-border',
'label' => esc_html__( 'Borders', 'twentytwentyone' ),
)
);
// Image: Frame.
register_block_style(
'core/image',
array(
'name' => 'twentytwentyone-image-frame',
'label' => esc_html__( 'Frame', 'twentytwentyone' ),
)
);
// Latest Posts: Dividers.
register_block_style(
'core/latest-posts',
array(
'name' => 'twentytwentyone-latest-posts-dividers',
'label' => esc_html__( 'Dividers', 'twentytwentyone' ),
)
);
// Latest Posts: Borders.
register_block_style(
'core/latest-posts',
array(
'name' => 'twentytwentyone-latest-posts-borders',
'label' => esc_html__( 'Borders', 'twentytwentyone' ),
)
);
// Media & Text: Borders.
register_block_style(
'core/media-text',
array(
'name' => 'twentytwentyone-border',
'label' => esc_html__( 'Borders', 'twentytwentyone' ),
)
);
// Separator: Thick.
register_block_style(
'core/separator',
array(
'name' => 'twentytwentyone-separator-thick',
'label' => esc_html__( 'Thick', 'twentytwentyone' ),
)
);
// Social icons: Dark gray color.
register_block_style(
'core/social-links',
array(
'name' => 'twentytwentyone-social-icons-color',
'label' => esc_html__( 'Dark gray', 'twentytwentyone' ),
)
);
}
add_action( 'init', 'twenty_twenty_one_register_block_styles' );
}
template-tags.php 0000644 00000016544 14720673703 0010047 0 ustar 00 %2$s';
$time_string = sprintf(
$time_string,
esc_attr( get_the_date( DATE_W3C ) ),
esc_html( get_the_date() )
);
echo '';
printf(
/* translators: %s: Publish date. */
esc_html__( 'Published %s', 'twentytwentyone' ),
$time_string // phpcs:ignore WordPress.Security.EscapeOutput
);
echo ' ';
}
}
if ( ! function_exists( 'twenty_twenty_one_posted_by' ) ) {
/**
* Prints HTML with meta information about theme author.
*
* @since Twenty Twenty-One 1.0
*
* @return void
*/
function twenty_twenty_one_posted_by() {
if ( ! get_the_author_meta( 'description' ) && post_type_supports( get_post_type(), 'author' ) ) {
echo '';
printf(
/* translators: %s: Author name. */
esc_html__( 'By %s', 'twentytwentyone' ),
'' . esc_html( get_the_author() ) . ' '
);
echo ' ';
}
}
}
if ( ! function_exists( 'twenty_twenty_one_entry_meta_footer' ) ) {
/**
* Prints HTML with meta information for the categories, tags and comments.
* Footer entry meta is displayed differently in archives and single posts.
*
* @since Twenty Twenty-One 1.0
*
* @return void
*/
function twenty_twenty_one_entry_meta_footer() {
// Early exit if not a post.
if ( 'post' !== get_post_type() ) {
return;
}
// Hide meta information on pages.
if ( ! is_single() ) {
if ( is_sticky() ) {
echo '
' . esc_html_x( 'Featured post', 'Label for sticky posts', 'twentytwentyone' ) . '
';
}
$post_format = get_post_format();
if ( 'aside' === $post_format || 'status' === $post_format ) {
echo '' . twenty_twenty_one_continue_reading_text() . '
'; // phpcs:ignore WordPress.Security.EscapeOutput
}
// Posted on.
twenty_twenty_one_posted_on();
// Edit post link.
edit_post_link(
sprintf(
/* translators: %s: Post title. Only visible to screen readers. */
esc_html__( 'Edit %s', 'twentytwentyone' ),
'' . get_the_title() . ' '
),
'',
' '
);
if ( has_category() || has_tag() ) {
echo '';
$categories_list = get_the_category_list( wp_get_list_item_separator() );
if ( $categories_list ) {
printf(
/* translators: %s: List of categories. */
'' . esc_html__( 'Categorized as %s', 'twentytwentyone' ) . ' ',
$categories_list // phpcs:ignore WordPress.Security.EscapeOutput
);
}
$tags_list = get_the_tag_list( '', wp_get_list_item_separator() );
if ( $tags_list && ! is_wp_error( $tags_list ) ) {
printf(
/* translators: %s: List of tags. */
'' . esc_html__( 'Tagged %s', 'twentytwentyone' ) . ' ',
$tags_list // phpcs:ignore WordPress.Security.EscapeOutput
);
}
echo '
';
}
} else {
echo '';
// Posted on.
twenty_twenty_one_posted_on();
// Posted by.
twenty_twenty_one_posted_by();
// Edit post link.
edit_post_link(
sprintf(
/* translators: %s: Post title. Only visible to screen readers. */
esc_html__( 'Edit %s', 'twentytwentyone' ),
'' . get_the_title() . ' '
),
'',
' '
);
echo '
';
if ( has_category() || has_tag() ) {
echo '';
$categories_list = get_the_category_list( wp_get_list_item_separator() );
if ( $categories_list ) {
printf(
/* translators: %s: List of categories. */
'' . esc_html__( 'Categorized as %s', 'twentytwentyone' ) . ' ',
$categories_list // phpcs:ignore WordPress.Security.EscapeOutput
);
}
$tags_list = get_the_tag_list( '', wp_get_list_item_separator() );
if ( $tags_list && ! is_wp_error( $tags_list ) ) {
printf(
/* translators: %s: List of tags. */
'' . esc_html__( 'Tagged %s', 'twentytwentyone' ) . ' ',
$tags_list // phpcs:ignore WordPress.Security.EscapeOutput
);
}
echo '
';
}
}
}
}
if ( ! function_exists( 'twenty_twenty_one_post_thumbnail' ) ) {
/**
* Displays an optional post thumbnail.
*
* Wraps the post thumbnail in an anchor element on index views, or a div
* element when on single views.
*
* @since Twenty Twenty-One 1.0
*
* @return void
*/
function twenty_twenty_one_post_thumbnail() {
if ( ! twenty_twenty_one_can_show_post_thumbnail() ) {
return;
}
?>
false ) );
?>
esc_html__( 'Page', 'twentytwentyone' ) . ' ',
'mid_size' => 0,
'prev_text' => sprintf(
'%s %s ',
is_rtl() ? twenty_twenty_one_get_icon_svg( 'ui', 'arrow_right' ) : twenty_twenty_one_get_icon_svg( 'ui', 'arrow_left' ),
wp_kses(
__( 'Newer posts ', 'twentytwentyone' ),
array(
'span' => array(
'class' => array(),
),
)
)
),
'next_text' => sprintf(
'%s %s',
wp_kses(
__( 'Older posts ', 'twentytwentyone' ),
array(
'span' => array(
'class' => array(),
),
)
),
is_rtl() ? twenty_twenty_one_get_icon_svg( 'ui', 'arrow_left' ) : twenty_twenty_one_get_icon_svg( 'ui', 'arrow_right' )
),
)
);
}
}
template-functions.php 0000644 00000042434 14720673703 0011116 0 ustar 00 ';
}
}
add_action( 'wp_head', 'twenty_twenty_one_pingback_header' );
/**
* Remove the `no-js` class from body if JS is supported.
*
* @since Twenty Twenty-One 1.0
*
* @return void
*/
function twenty_twenty_one_supports_js() {
echo '';
}
add_action( 'wp_footer', 'twenty_twenty_one_supports_js' );
/**
* Changes comment form default fields.
*
* @since Twenty Twenty-One 1.0
*
* @param array $defaults The form defaults.
* @return array
*/
function twenty_twenty_one_comment_form_defaults( $defaults ) {
// Adjust height of comment form.
$defaults['comment_field'] = preg_replace( '/rows="\d+"/', 'rows="5"', $defaults['comment_field'] );
return $defaults;
}
add_filter( 'comment_form_defaults', 'twenty_twenty_one_comment_form_defaults' );
/**
* Determines if post thumbnail can be displayed.
*
* @since Twenty Twenty-One 1.0
*
* @return bool
*/
function twenty_twenty_one_can_show_post_thumbnail() {
/**
* Filters whether post thumbnail can be displayed.
*
* @since Twenty Twenty-One 1.0
*
* @param bool $show_post_thumbnail Whether to show post thumbnail.
*/
return apply_filters(
'twenty_twenty_one_can_show_post_thumbnail',
! post_password_required() && ! is_attachment() && has_post_thumbnail()
);
}
/**
* Returns the size for avatars used in the theme.
*
* @since Twenty Twenty-One 1.0
*
* @return int
*/
function twenty_twenty_one_get_avatar_size() {
return 60;
}
/**
* Creates continue reading text.
*
* @since Twenty Twenty-One 1.0
*/
function twenty_twenty_one_continue_reading_text() {
$continue_reading = sprintf(
/* translators: %s: Post title. Only visible to screen readers. */
esc_html__( 'Continue reading %s', 'twentytwentyone' ),
the_title( '', ' ', false )
);
return $continue_reading;
}
/**
* Creates the continue reading link for excerpt.
*
* @since Twenty Twenty-One 1.0
*/
function twenty_twenty_one_continue_reading_link_excerpt() {
if ( ! is_admin() ) {
return '… ' . twenty_twenty_one_continue_reading_text() . ' ';
}
}
// Filter the excerpt more link.
add_filter( 'excerpt_more', 'twenty_twenty_one_continue_reading_link_excerpt' );
/**
* Creates the continue reading link.
*
* @since Twenty Twenty-One 1.0
*/
function twenty_twenty_one_continue_reading_link() {
if ( ! is_admin() ) {
return '';
}
}
// Filter the content more link.
add_filter( 'the_content_more_link', 'twenty_twenty_one_continue_reading_link' );
if ( ! function_exists( 'twenty_twenty_one_post_title' ) ) {
/**
* Adds a title to posts and pages that are missing titles.
*
* @since Twenty Twenty-One 1.0
*
* @param string $title The title.
* @return string
*/
function twenty_twenty_one_post_title( $title ) {
return '' === $title ? esc_html_x( 'Untitled', 'Added to posts and pages that are missing titles', 'twentytwentyone' ) : $title;
}
}
add_filter( 'the_title', 'twenty_twenty_one_post_title' );
/**
* Gets the SVG code for a given icon.
*
* @since Twenty Twenty-One 1.0
*
* @param string $group The icon group.
* @param string $icon The icon.
* @param int $size The icon size in pixels.
* @return string
*/
function twenty_twenty_one_get_icon_svg( $group, $icon, $size = 24 ) {
return Twenty_Twenty_One_SVG_Icons::get_svg( $group, $icon, $size );
}
/**
* Changes the default navigation arrows to svg icons
*
* @since Twenty Twenty-One 1.0
*
* @param string $calendar_output The generated HTML of the calendar.
* @return string
*/
function twenty_twenty_one_change_calendar_nav_arrows( $calendar_output ) {
$calendar_output = str_replace( '« ', is_rtl() ? twenty_twenty_one_get_icon_svg( 'ui', 'arrow_right' ) : twenty_twenty_one_get_icon_svg( 'ui', 'arrow_left' ), $calendar_output );
$calendar_output = str_replace( ' »', is_rtl() ? twenty_twenty_one_get_icon_svg( 'ui', 'arrow_left' ) : twenty_twenty_one_get_icon_svg( 'ui', 'arrow_right' ), $calendar_output );
return $calendar_output;
}
add_filter( 'get_calendar', 'twenty_twenty_one_change_calendar_nav_arrows' );
/**
* Get custom CSS.
*
* Return CSS for non-latin language, if available, or null
*
* @since Twenty Twenty-One 1.0
*
* @param string $type Whether to return CSS for the "front-end", "block-editor", or "classic-editor".
* @return string
*/
function twenty_twenty_one_get_non_latin_css( $type = 'front-end' ) {
// Fetch site locale.
$locale = get_bloginfo( 'language' );
/**
* Filters the fallback fonts for non-latin languages.
*
* @since Twenty Twenty-One 1.0
*
* @param array $font_family An array of locales and font families.
*/
$font_family = apply_filters(
'twenty_twenty_one_get_localized_font_family_types',
array(
// Arabic.
'ar' => array( 'Tahoma', 'Arial', 'sans-serif' ),
'ary' => array( 'Tahoma', 'Arial', 'sans-serif' ),
'azb' => array( 'Tahoma', 'Arial', 'sans-serif' ),
'ckb' => array( 'Tahoma', 'Arial', 'sans-serif' ),
'fa-IR' => array( 'Tahoma', 'Arial', 'sans-serif' ),
'haz' => array( 'Tahoma', 'Arial', 'sans-serif' ),
'ps' => array( 'Tahoma', 'Arial', 'sans-serif' ),
// Chinese Simplified (China) - Noto Sans SC.
'zh-CN' => array( '\'PingFang SC\'', '\'Helvetica Neue\'', '\'Microsoft YaHei New\'', '\'STHeiti Light\'', 'sans-serif' ),
// Chinese Traditional (Taiwan) - Noto Sans TC.
'zh-TW' => array( '\'PingFang TC\'', '\'Helvetica Neue\'', '\'Microsoft YaHei New\'', '\'STHeiti Light\'', 'sans-serif' ),
// Chinese (Hong Kong) - Noto Sans HK.
'zh-HK' => array( '\'PingFang HK\'', '\'Helvetica Neue\'', '\'Microsoft YaHei New\'', '\'STHeiti Light\'', 'sans-serif' ),
// Cyrillic.
'bel' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
'bg-BG' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
'kk' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
'mk-MK' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
'mn' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
'ru-RU' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
'sah' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
'sr-RS' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
'tt-RU' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
'uk' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
// Devanagari.
'bn-BD' => array( 'Arial', 'sans-serif' ),
'hi-IN' => array( 'Arial', 'sans-serif' ),
'mr' => array( 'Arial', 'sans-serif' ),
'ne-NP' => array( 'Arial', 'sans-serif' ),
// Greek.
'el' => array( '\'Helvetica Neue\', Helvetica, Arial, sans-serif' ),
// Gujarati.
'gu' => array( 'Arial', 'sans-serif' ),
// Hebrew.
'he-IL' => array( '\'Arial Hebrew\'', 'Arial', 'sans-serif' ),
// Japanese.
'ja' => array( 'sans-serif' ),
// Korean.
'ko-KR' => array( '\'Apple SD Gothic Neo\'', '\'Malgun Gothic\'', '\'Nanum Gothic\'', 'Dotum', 'sans-serif' ),
// Thai.
'th' => array( '\'Sukhumvit Set\'', '\'Helvetica Neue\'', 'Helvetica', 'Arial', 'sans-serif' ),
// Vietnamese.
'vi' => array( '\'Libre Franklin\'', 'sans-serif' ),
)
);
// Return if the selected language has no fallback fonts.
if ( empty( $font_family[ $locale ] ) ) {
return '';
}
/**
* Filters the elements to apply fallback fonts to.
*
* @since Twenty Twenty-One 1.0
*
* @param array $elements An array of elements for "front-end", "block-editor", or "classic-editor".
*/
$elements = apply_filters(
'twenty_twenty_one_get_localized_font_family_elements',
array(
'front-end' => array( 'body', 'input', 'textarea', 'button', '.button', '.faux-button', '.wp-block-button__link', '.wp-block-file__button', '.has-drop-cap:not(:focus)::first-letter', '.entry-content .wp-block-archives', '.entry-content .wp-block-categories', '.entry-content .wp-block-cover-image', '.entry-content .wp-block-latest-comments', '.entry-content .wp-block-latest-posts', '.entry-content .wp-block-pullquote', '.entry-content .wp-block-quote.is-large', '.entry-content .wp-block-quote.is-style-large', '.entry-content .wp-block-archives *', '.entry-content .wp-block-categories *', '.entry-content .wp-block-latest-posts *', '.entry-content .wp-block-latest-comments *', '.entry-content p', '.entry-content ol', '.entry-content ul', '.entry-content dl', '.entry-content dt', '.entry-content cite', '.entry-content figcaption', '.entry-content .wp-caption-text', '.comment-content p', '.comment-content ol', '.comment-content ul', '.comment-content dl', '.comment-content dt', '.comment-content cite', '.comment-content figcaption', '.comment-content .wp-caption-text', '.widget_text p', '.widget_text ol', '.widget_text ul', '.widget_text dl', '.widget_text dt', '.widget-content .rssSummary', '.widget-content cite', '.widget-content figcaption', '.widget-content .wp-caption-text' ),
'block-editor' => array( '.editor-styles-wrapper > *', '.editor-styles-wrapper p', '.editor-styles-wrapper ol', '.editor-styles-wrapper ul', '.editor-styles-wrapper dl', '.editor-styles-wrapper dt', '.editor-post-title__block .editor-post-title__input', '.editor-styles-wrapper .wp-block h1', '.editor-styles-wrapper .wp-block h2', '.editor-styles-wrapper .wp-block h3', '.editor-styles-wrapper .wp-block h4', '.editor-styles-wrapper .wp-block h5', '.editor-styles-wrapper .wp-block h6', '.editor-styles-wrapper .has-drop-cap:not(:focus)::first-letter', '.editor-styles-wrapper cite', '.editor-styles-wrapper figcaption', '.editor-styles-wrapper .wp-caption-text' ),
'classic-editor' => array( 'body#tinymce.wp-editor', 'body#tinymce.wp-editor p', 'body#tinymce.wp-editor ol', 'body#tinymce.wp-editor ul', 'body#tinymce.wp-editor dl', 'body#tinymce.wp-editor dt', 'body#tinymce.wp-editor figcaption', 'body#tinymce.wp-editor .wp-caption-text', 'body#tinymce.wp-editor .wp-caption-dd', 'body#tinymce.wp-editor cite', 'body#tinymce.wp-editor table' ),
)
);
// Return if the specified type doesn't exist.
if ( empty( $elements[ $type ] ) ) {
return '';
}
// Include file if function doesn't exist.
if ( ! function_exists( 'twenty_twenty_one_generate_css' ) ) {
require_once get_theme_file_path( 'inc/custom-css.php' ); // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude.FileIncludeFound
}
// Return the specified styles.
return twenty_twenty_one_generate_css( // @phpstan-ignore-line.
implode( ',', $elements[ $type ] ),
'font-family',
implode( ',', $font_family[ $locale ] ),
null,
null,
false
);
}
/**
* Print the first instance of a block in the content, and then break away.
*
* @since Twenty Twenty-One 1.0
*
* @param string $block_name The full block type name, or a partial match.
* Example: `core/image`, `core-embed/*`.
* @param string|null $content The content to search in. Use null for get_the_content().
* @param int $instances How many instances of the block will be printed (max). Default 1.
* @return bool Returns true if a block was located & printed, otherwise false.
*/
function twenty_twenty_one_print_first_instance_of_block( $block_name, $content = null, $instances = 1 ) {
$instances_count = 0;
$blocks_content = '';
if ( ! $content ) {
$content = get_the_content();
}
// Parse blocks in the content.
$blocks = parse_blocks( $content );
// Loop blocks.
foreach ( $blocks as $block ) {
// Confidence check.
if ( ! isset( $block['blockName'] ) ) {
continue;
}
// Check if this the block matches the $block_name.
$is_matching_block = false;
// If the block ends with *, try to match the first portion.
if ( '*' === $block_name[-1] ) {
$is_matching_block = 0 === strpos( $block['blockName'], rtrim( $block_name, '*' ) );
} else {
$is_matching_block = $block_name === $block['blockName'];
}
if ( $is_matching_block ) {
// Increment count.
++$instances_count;
// Add the block HTML.
$blocks_content .= render_block( $block );
// Break the loop if the $instances count was reached.
if ( $instances_count >= $instances ) {
break;
}
}
}
if ( $blocks_content ) {
/** This filter is documented in wp-includes/post-template.php */
echo apply_filters( 'the_content', $blocks_content ); // phpcs:ignore WordPress.Security.EscapeOutput
return true;
}
return false;
}
/**
* Retrieve protected post password form content.
*
* @since Twenty Twenty-One 1.0
* @since Twenty Twenty-One 1.4 Corrected parameter name for `$output`,
* added the `$post` parameter.
*
* @param string $output The password form HTML output.
* @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
* @return string HTML content for password form for password protected post.
*/
function twenty_twenty_one_password_form( $output, $post = 0 ) {
$post = get_post( $post );
$label = 'pwbox-' . ( empty( $post->ID ) ? wp_rand() : $post->ID );
$output = '' . esc_html__( 'This content is password protected. Please enter a password to view.', 'twentytwentyone' ) . '
';
return $output;
}
add_filter( 'the_password_form', 'twenty_twenty_one_password_form', 10, 2 );
/**
* Filters the list of attachment image attributes.
*
* @since Twenty Twenty-One 1.0
*
* @param string[] $attr Array of attribute values for the image markup, keyed by attribute name.
* See wp_get_attachment_image().
* @param WP_Post $attachment Image attachment post.
* @param string|int[] $size Requested image size. Can be any registered image size name, or
* an array of width and height values in pixels (in that order).
* @return string[] The filtered attributes for the image markup.
*/
function twenty_twenty_one_get_attachment_image_attributes( $attr, $attachment, $size ) {
if ( is_admin() ) {
return $attr;
}
if ( isset( $attr['class'] ) && false !== strpos( $attr['class'], 'custom-logo' ) ) {
return $attr;
}
$width = false;
$height = false;
if ( is_array( $size ) ) {
$width = (int) $size[0];
$height = (int) $size[1];
} elseif ( $attachment && is_object( $attachment ) && $attachment->ID ) {
$meta = wp_get_attachment_metadata( $attachment->ID );
if ( isset( $meta['width'] ) && isset( $meta['height'] ) ) {
$width = (int) $meta['width'];
$height = (int) $meta['height'];
}
}
if ( $width && $height ) {
// Add style.
$attr['style'] = isset( $attr['style'] ) ? $attr['style'] : '';
$attr['style'] = 'width:100%;height:' . round( 100 * $height / $width, 2 ) . '%;max-width:' . $width . 'px;' . $attr['style'];
}
return $attr;
}
add_filter( 'wp_get_attachment_image_attributes', 'twenty_twenty_one_get_attachment_image_attributes', 10, 3 );
back-compat.php 0000644 00000004654 14720673703 0007460 0 ustar 00 ';
printf(
/* translators: %s: WordPress Version. */
esc_html__( 'This theme requires WordPress 5.3 or newer. You are running version %s. Please upgrade.', 'twentytwentyone' ),
esc_html( $GLOBALS['wp_version'] )
);
echo '
';
}
/**
* Prevents the Customizer from being loaded on WordPress versions prior to 5.3.
*
* @since Twenty Twenty-One 1.0
*
* @global string $wp_version WordPress version.
*
* @return void
*/
function twenty_twenty_one_customize() {
wp_die(
sprintf(
/* translators: %s: WordPress Version. */
esc_html__( 'This theme requires WordPress 5.3 or newer. You are running version %s. Please upgrade.', 'twentytwentyone' ),
esc_html( $GLOBALS['wp_version'] )
),
'',
array(
'back_link' => true,
)
);
}
add_action( 'load-customize.php', 'twenty_twenty_one_customize' );
/**
* Prevents the Theme Preview from being loaded on WordPress versions prior to 5.3.
*
* @since Twenty Twenty-One 1.0
*
* @global string $wp_version WordPress version.
*
* @return void
*/
function twenty_twenty_one_preview() {
if ( isset( $_GET['preview'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
wp_die(
sprintf(
/* translators: %s: WordPress Version. */
esc_html__( 'This theme requires WordPress 5.3 or newer. You are running version %s. Please upgrade.', 'twentytwentyone' ),
esc_html( $GLOBALS['wp_version'] )
)
);
}
}
add_action( 'template_redirect', 'twenty_twenty_one_preview' );
block-patterns.php 0000644 00000050051 14720673703 0010217 0 ustar 00 esc_html__( 'Twenty Twenty-One', 'twentytwentyone' ) )
);
}
add_action( 'init', 'twenty_twenty_one_register_block_pattern_category' );
}
/**
* Register Block Patterns.
*/
if ( function_exists( 'register_block_pattern' ) ) {
/**
* Register Block Pattern.
*
* @since Twenty Twenty-One 1.0
*
* @return void
*/
function twenty_twenty_one_register_block_pattern() {
// Large Text.
register_block_pattern(
'twentytwentyone/large-text',
array(
'title' => esc_html__( 'Large text', 'twentytwentyone' ),
'categories' => array( 'twentytwentyone' ),
'viewportWidth' => 1440,
'blockTypes' => array( 'core/heading' ),
'content' => '' . esc_html__( 'A new portfolio default theme for WordPress', 'twentytwentyone' ) . ' ',
)
);
// Links Area.
register_block_pattern(
'twentytwentyone/links-area',
array(
'title' => esc_html__( 'Links area', 'twentytwentyone' ),
'categories' => array( 'twentytwentyone' ),
'viewportWidth' => 1440,
'blockTypes' => array( 'core/cover' ),
'description' => esc_html_x( 'A huge text followed by social networks and email address links.', 'Block pattern description', 'twentytwentyone' ),
'content' => '
' . wp_kses_post( __( 'Let’s Connect.', 'twentytwentyone' ) ) . '
',
)
);
// Media & Text Article Title.
register_block_pattern(
'twentytwentyone/media-text-article-title',
array(
'title' => esc_html__( 'Media and text article title', 'twentytwentyone' ),
'categories' => array( 'twentytwentyone' ),
'viewportWidth' => 1440,
'description' => esc_html_x( 'A Media & Text block with a big image on the left and a heading on the right. The heading is followed by a separator and a description paragraph.', 'Block pattern description', 'twentytwentyone' ),
'content' => '' . esc_html__( 'Playing in the Sand', 'twentytwentyone' ) . ' ' . wp_kses_post( __( 'Berthe Morisot (French, 1841-1895)', 'twentytwentyone' ) ) . '
',
)
);
// Overlapping Images.
register_block_pattern(
'twentytwentyone/overlapping-images',
array(
'title' => esc_html__( 'Overlapping images', 'twentytwentyone' ),
'categories' => array( 'twentytwentyone' ),
'viewportWidth' => 1024,
'blockTypes' => array( 'core/columns' ),
'description' => esc_html_x( 'Three images inside an overlapping columns block.', 'Block pattern description', 'twentytwentyone' ),
'content' => '',
)
);
// Two Images Showcase.
register_block_pattern(
'twentytwentyone/two-images-showcase',
array(
'title' => esc_html__( 'Two images showcase', 'twentytwentyone' ),
'categories' => array( 'twentytwentyone' ),
'viewportWidth' => 1440,
'description' => esc_html_x( 'A media & text block with a big image on the left and a smaller one with bordered frame on the right.', 'Block pattern description', 'twentytwentyone' ),
'content' => '',
)
);
// Overlapping Images and Text.
register_block_pattern(
'twentytwentyone/overlapping-images-and-text',
array(
'title' => esc_html__( 'Overlapping images and text', 'twentytwentyone' ),
'categories' => array( 'twentytwentyone' ),
'viewportWidth' => 1440,
'blockTypes' => array( 'core/columns' ),
'description' => esc_html_x( 'An overlapping columns block with two images and a text description.', 'Block pattern description', 'twentytwentyone' ),
'content' => ' ',
)
);
// Portfolio List.
register_block_pattern(
'twentytwentyone/portfolio-list',
array(
'title' => esc_html__( 'Portfolio list', 'twentytwentyone' ),
'categories' => array( 'twentytwentyone' ),
'description' => esc_html_x( 'A list of projects with thumbnail images.', 'Block pattern description', 'twentytwentyone' ),
'content' => ' ',
)
);
register_block_pattern(
'twentytwentyone/contact-information',
array(
'title' => esc_html__( 'Contact information', 'twentytwentyone' ),
'categories' => array( 'twentytwentyone' ),
'blockTypes' => array( 'core/columns' ),
'description' => esc_html_x( 'A block with 3 columns that display contact information and social media links.', 'Block pattern description', 'twentytwentyone' ),
'content' => '' . esc_html_x( '123 Main Street', 'Block pattern sample content', 'twentytwentyone' ) . ' ' . esc_html_x( 'Cambridge, MA, 02139', 'Block pattern sample content', 'twentytwentyone' ) . '
',
)
);
}
add_action( 'init', 'twenty_twenty_one_register_block_pattern' );
}
custom-css.php 0000644 00000002257 14720673703 0007374 0 ustar 00 tags and can only be interpreted as CSS on the browser.
* Using wp_strip_all_tags() here is sufficient escaping to avoid
* malicious attempts to close and open a
__( 'User not allowed to update items.', 'envato-market' ) ) );
}
update_option( self::AJAX_ACTION, 'dismissed' );
wp_send_json_success();
}
}
if ( ! function_exists( 'envato_market_github' ) ) :
/**
* Envato_Market_Github Instance
*
* @since 1.0.0
*
* @return Envato_Market_Github
*/
function envato_market_github() {
return Envato_Market_Github::instance();
}
endif;
/**
* Loads the main instance of Envato_Market_Github
*
* @since 1.0.0
*/
add_action( 'after_setup_theme', 'envato_market_github', 99 );
endif;
class-envato-market.php 0000644 00000024235 14720702445 0011150 0 ustar 00 init_globals();
self::$_instance->init_includes();
self::$_instance->init_actions();
}
return self::$_instance;
}
/**
* A dummy constructor to prevent this class from being loaded more than once.
*
* @see Envato_Market::instance()
*
* @since 1.0.0
* @access private
* @codeCoverageIgnore
*/
private function __construct() {
/* We do nothing here! */
}
/**
* You cannot clone this class.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function __clone() {
_doing_it_wrong( __FUNCTION__, __( 'Cheatin’ huh?', 'envato-market' ), '1.0.0' );
}
/**
* You cannot unserialize instances of this class.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function __wakeup() {
_doing_it_wrong( __FUNCTION__, __( 'Cheatin’ huh?', 'envato-market' ), '1.0.0' );
}
/**
* Setup the class globals.
*
* @since 1.0.0
* @access private
* @codeCoverageIgnore
*/
private function init_globals() {
$this->data = new stdClass();
$this->version = ENVATO_MARKET_VERSION;
$this->slug = 'envato-market';
$this->option_name = self::sanitize_key( $this->slug );
$this->plugin_url = ENVATO_MARKET_URI;
$this->plugin_path = ENVATO_MARKET_PATH;
$this->page_url = ENVATO_MARKET_NETWORK_ACTIVATED ? network_admin_url( 'admin.php?page=' . $this->slug ) : admin_url( 'admin.php?page=' . $this->slug );
$this->data->admin = true;
if ( defined('ENVATO_LOCAL_DEVELOPMENT') ) {
$this->envato_api_domain = ENVATO_API_DOMAIN;
$this->envato_api_headers = ENVATO_API_HEADERS;
} else {
$this->envato_api_headers = [ 'Authorization' => 'Bearer ' . $this->get_option( 'token' ) ];
$this->envato_api_domain = 'https://api.envato.com';
}
}
/**
* Include required files.
*
* @since 1.0.0
* @access private
* @codeCoverageIgnore
*/
private function init_includes() {
require $this->plugin_path . '/inc/admin/class-envato-market-admin.php';
require $this->plugin_path . '/inc/admin/functions.php';
require $this->plugin_path . '/inc/class-envato-market-api.php';
require $this->plugin_path . '/inc/class-envato-market-items.php';
require $this->plugin_path . '/inc/class-envato-market-github.php';
}
/**
* Setup the hooks, actions and filters.
*
* @uses add_action() To add actions.
* @uses add_filter() To add filters.
*
* @since 1.0.0
* @access private
* @codeCoverageIgnore
*/
private function init_actions() {
// Activate plugin.
register_activation_hook( ENVATO_MARKET_CORE_FILE, array( $this, 'activate' ) );
// Deactivate plugin.
register_deactivation_hook( ENVATO_MARKET_CORE_FILE, array( $this, 'deactivate' ) );
// Load the textdomain.
add_action( 'init', array( $this, 'load_textdomain' ) );
// Load OAuth.
add_action( 'init', array( $this, 'admin' ) );
// Load Upgrader.
add_action( 'init', array( $this, 'items' ) );
}
/**
* Activate plugin.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function activate() {
self::set_plugin_state( true );
}
/**
* Deactivate plugin.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function deactivate() {
self::set_plugin_state( false );
}
/**
* Loads the plugin's translated strings.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function load_textdomain() {
load_plugin_textdomain( 'envato-market', false, ENVATO_MARKET_PATH . 'languages/' );
}
/**
* Sanitize data key.
*
* @since 1.0.0
* @access private
*
* @param string $key An alpha numeric string to sanitize.
* @return string
*/
private function sanitize_key( $key ) {
return preg_replace( '/[^A-Za-z0-9\_]/i', '', str_replace( array( '-', ':' ), '_', $key ) );
}
/**
* Recursively converts data arrays to objects.
*
* @since 1.0.0
* @access private
*
* @param array $array An array of data.
* @return object
*/
private function convert_data( $array ) {
foreach ( (array) $array as $key => $value ) {
if ( is_array( $value ) ) {
$array[ $key ] = self::convert_data( $value );
}
}
return (object) $array;
}
/**
* Set the `is_plugin_active` option.
*
* This setting helps determine context. Since the plugin can be included in your theme root you
* might want to hide the admin UI when the plugin is not activated and implement your own.
*
* @since 1.0.0
* @access private
*
* @param bool $value Whether or not the plugin is active.
*/
private function set_plugin_state( $value ) {
self::set_option( 'is_plugin_active', $value );
}
/**
* Set option value.
*
* @since 1.0.0
*
* @param string $name Option name.
* @param mixed $option Option data.
*/
public function set_option( $name, $option ) {
$options = self::get_options();
$name = self::sanitize_key( $name );
$options[ $name ] = esc_html( $option );
$this->set_options( $options );
}
/**
* Set option.
*
* @since 2.0.0
*
* @param mixed $options Option data.
*/
public function set_options( $options ) {
ENVATO_MARKET_NETWORK_ACTIVATED ? update_site_option( $this->option_name, $options ) : update_option( $this->option_name, $options );
}
/**
* Return the option settings array.
*
* @since 1.0.0
*/
public function get_options() {
return ENVATO_MARKET_NETWORK_ACTIVATED ? get_site_option( $this->option_name, array() ) : get_option( $this->option_name, array() );
}
/**
* Return a value from the option settings array.
*
* @since 1.0.0
*
* @param string $name Option name.
* @param mixed $default The default value if nothing is set.
* @return mixed
*/
public function get_option( $name, $default = '' ) {
$options = self::get_options();
$name = self::sanitize_key( $name );
return isset( $options[ $name ] ) ? $options[ $name ] : $default;
}
/**
* Set data.
*
* @since 1.0.0
*
* @param string $key Unique object key.
* @param mixed $data Any kind of data.
*/
public function set_data( $key, $data ) {
if ( ! empty( $key ) ) {
if ( is_array( $data ) ) {
$data = self::convert_data( $data );
}
$key = self::sanitize_key( $key );
// @codingStandardsIgnoreStart
$this->data->$key = $data;
// @codingStandardsIgnoreEnd
}
}
/**
* Get data.
*
* @since 1.0.0
*
* @param string $key Unique object key.
* @return string|object
*/
public function get_data( $key ) {
return isset( $this->data->$key ) ? $this->data->$key : '';
}
/**
* Return the plugin slug.
*
* @since 1.0.0
*
* @return string
*/
public function get_slug() {
return $this->slug;
}
/**
* Return the plugin version number.
*
* @since 1.0.0
*
* @return string
*/
public function get_version() {
return $this->version;
}
/**
* Return the plugin URL.
*
* @since 1.0.0
*
* @return string
*/
public function get_plugin_url() {
return $this->plugin_url;
}
/**
* Return the plugin path.
*
* @since 1.0.0
*
* @return string
*/
public function get_plugin_path() {
return $this->plugin_path;
}
/**
* Return the plugin page URL.
*
* @since 1.0.0
*
* @return string
*/
public function get_page_url() {
return $this->page_url;
}
/**
* Return the option settings name.
*
* @since 1.0.0
*
* @return string
*/
public function get_option_name() {
return $this->option_name;
}
/**
* Admin UI class.
*
* @since 1.0.0
*
* @return Envato_Market_Admin
*/
public function admin() {
return Envato_Market_Admin::instance();
}
/**
* Envato API class.
*
* @since 1.0.0
*
* @return Envato_Market_API
*/
public function api() {
return Envato_Market_API::instance();
}
/**
* Items class.
*
* @since 1.0.0
*
* @return Envato_Market_Items
*/
public function items() {
return Envato_Market_Items::instance();
}
public function get_envato_api_domain() {
return $this->envato_api_domain;
}
public function get_envato_api_headers() {
return $this->envato_api_headers;
}
}
endif;
class-envato-market-items.php 0000644 00000041660 14720702445 0012270 0 ustar 00 init_actions();
}
return self::$_instance;
}
/**
* A dummy constructor to prevent this class from being loaded more than once.
*
* @see Envato_Market_Items::instance()
*
* @since 1.0.0
* @access private
* @codeCoverageIgnore
*/
private function __construct() {
/* We do nothing here! */
}
/**
* You cannot clone this class.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function __clone() {
_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'envato-market' ), '1.0.0' );
}
/**
* You cannot unserialize instances of this class.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function __wakeup() {
_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'envato-market' ), '1.0.0' );
}
/**
* Setup the hooks, actions and filters.
*
* @uses add_action() To add actions.
* @uses add_filter() To add filters.
*
* @since 1.0.0
*/
public function init_actions() {
// Check for theme & plugin updates.
add_filter( 'http_request_args', array( $this, 'update_check' ), 5, 2 );
// Inject plugin updates into the response array.
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'update_plugins' ), 5, 1 );
add_filter( 'pre_set_transient_update_plugins', array( $this, 'update_plugins' ), 5, 1 );
// Inject theme updates into the response array.
add_filter( 'pre_set_site_transient_update_themes', array( $this, 'update_themes' ), 1, 99999 );
add_filter( 'pre_set_transient_update_themes', array( $this, 'update_themes' ), 1, 99999 );
// Inject plugin information into the API calls.
add_filter( 'plugins_api', array( $this, 'plugins_api' ), 10, 3 );
// Rebuild the saved theme data.
add_action( 'after_switch_theme', array( $this, 'rebuild_themes' ) );
// Rebuild the saved plugin data.
add_action( 'activated_plugin', array( $this, 'rebuild_plugins' ) );
add_action( 'deactivated_plugin', array( $this, 'rebuild_plugins' ) );
}
/**
* Get the premium plugins list.
*
* @since 1.0.0
*
* @param string $group The plugin group. Options are 'purchased', 'active', 'installed', or 'install'.
* @return array
*/
public function plugins( $group = '' ) {
if ( ! empty( $group ) ) {
if ( isset( self::$plugins[ $group ] ) ) {
return self::$plugins[ $group ];
} else {
return array();
}
}
return self::$plugins;
}
/**
* Get the premium themes list.
*
* @since 1.0.0
*
* @param string $group The theme group. Options are 'purchased', 'active', 'installed', or 'install'.
* @return array
*/
public function themes( $group = '' ) {
if ( ! empty( $group ) ) {
if ( isset( self::$themes[ $group ] ) ) {
return self::$themes[ $group ];
} else {
return array();
}
}
return self::$themes;
}
/**
* Get the list of WordPress plugins
*
* @since 1.0.0
*
* @param bool $flush Forces a cache flush. Default is 'false'.
* @return array
*/
public function wp_plugins( $flush = false ) {
if ( empty( self::$wp_plugins ) || true === $flush ) {
wp_cache_set( 'plugins', false, 'plugins' );
self::$wp_plugins = get_plugins();
}
return self::$wp_plugins;
}
/**
* Disables requests to the wp.org repository for premium themes.
*
* @since 1.0.0
*
* @param array $request An array of HTTP request arguments.
* @param string $url The request URL.
* @return array
*/
public function update_check( $request, $url ) {
// Theme update request.
if ( false !== strpos( $url, '//api.wordpress.org/themes/update-check/1.1/' ) ) {
/**
* Excluded theme slugs that should never ping the WordPress API.
* We don't need the extra http requests for themes we know are premium.
*/
self::set_themes();
$installed = self::$themes['installed'];
// Decode JSON so we can manipulate the array.
$data = json_decode( $request['body']['themes'] );
// Remove the excluded themes.
foreach ( $installed as $slug => $id ) {
unset( $data->themes->$slug );
}
// Encode back into JSON and update the response.
$request['body']['themes'] = wp_json_encode( $data );
}
// Plugin update request.
if ( false !== strpos( $url, '//api.wordpress.org/plugins/update-check/1.1/' ) ) {
/**
* Excluded theme slugs that should never ping the WordPress API.
* We don't need the extra http requests for themes we know are premium.
*/
self::set_plugins();
$installed = self::$plugins['installed'];
// Decode JSON so we can manipulate the array.
$data = json_decode( $request['body']['plugins'] );
// Remove the excluded themes.
foreach ( $installed as $slug => $id ) {
unset( $data->plugins->$slug );
}
// Encode back into JSON and update the response.
$request['body']['plugins'] = wp_json_encode( $data );
}
return $request;
}
/**
* Inject update data for premium themes.
*
* @since 1.0.0
*
* @param object $transient The pre-saved value of the `update_themes` site transient.
* @return object
*/
public function update_themes( $transient ) {
// Process premium theme updates.
if ( isset( $transient->checked ) ) {
self::set_themes( true );
$installed = array_merge( self::$themes['active'], self::$themes['installed'] );
foreach ( $installed as $slug => $premium ) {
$theme = wp_get_theme( $slug );
if ( $theme->exists() && version_compare( $theme->get( 'Version' ), $premium['version'], '<' ) ) {
$transient->response[ $slug ] = array(
'theme' => $slug,
'new_version' => $premium['version'],
'url' => $premium['url'],
'package' => envato_market()->api()->deferred_download( $premium['id'] ),
);
}
}
}
return $transient;
}
/**
* Inject update data for premium plugins.
*
* @since 1.0.0
*
* @param object $transient The pre-saved value of the `update_plugins` site transient.
* @return object
*/
public function update_plugins( $transient ) {
self::set_plugins( true );
// Process premium plugin updates.
$installed = array_merge( self::$plugins['active'], self::$plugins['installed'] );
$plugins = self::wp_plugins();
foreach ( $installed as $plugin => $premium ) {
if ( isset( $plugins[ $plugin ] ) && version_compare( $plugins[ $plugin ]['Version'], $premium['version'], '<' ) ) {
$_plugin = array(
'slug' => dirname( $plugin ),
'plugin' => $plugin,
'new_version' => $premium['version'],
'url' => $premium['url'],
'package' => envato_market()->api()->deferred_download( $premium['id'] ),
);
$transient->response[ $plugin ] = (object) $_plugin;
}
}
return $transient;
}
/**
* Inject API data for premium plugins.
*
* @since 1.0.0
*
* @param bool $response Always false.
* @param string $action The API action being performed.
* @param object $args Plugin arguments.
* @return bool|object $response The plugin info or false.
*/
public function plugins_api( $response, $action, $args ) {
self::set_plugins( true );
// Process premium theme updates.
if ( 'plugin_information' === $action && isset( $args->slug ) ) {
$installed = array_merge( self::$plugins['active'], self::$plugins['installed'] );
foreach ( $installed as $slug => $plugin ) {
if ( dirname( $slug ) === $args->slug ) {
$response = new stdClass();
$response->slug = $args->slug;
$response->plugin = $slug;
$response->plugin_name = $plugin['name'];
$response->name = $plugin['name'];
$response->version = $plugin['version'];
$response->author = $plugin['author'];
$response->homepage = $plugin['url'];
$response->requires = $plugin['requires'];
$response->tested = $plugin['tested'];
$response->downloaded = $plugin['number_of_sales'];
$response->last_updated = $plugin['updated_at'];
$response->sections = array( 'description' => $plugin['description'] );
$response->banners['low'] = $plugin['landscape_url'];
$response->rating = ! empty( $plugin['rating'] ) && ! empty( $plugin['rating']['rating'] ) && $plugin['rating']['rating'] > 0 ? $plugin['rating']['rating'] / 5 * 100 : 0;
$response->num_ratings = ! empty( $plugin['rating'] ) && ! empty( $plugin['rating']['count'] ) ? $plugin['rating']['count'] : 0;
$response->download_link = envato_market()->api()->deferred_download( $plugin['id'] );
break;
}
}
}
return $response;
}
/**
* Set the list of themes
*
* @since 1.0.0
*
* @param bool $forced Forces an API request. Default is 'false'.
* @param bool $use_cache Attempts to rebuild from the cache before making an API request.
*/
public function set_themes( $forced = false, $use_cache = false ) {
$themes_transient = get_site_transient( envato_market()->get_option_name() . '_themes' );
self::$themes = is_array($themes_transient) ? $themes_transient : array();
if ( empty(self::$themes) || true === $forced ) {
$themes = envato_market()->api()->themes();
foreach ( envato_market()->get_option( 'items', array() ) as $item ) {
if ( empty( $item ) ) {
continue;
}
if ( 'theme' === $item['type'] ) {
$request_args = array(
'headers' => array(
'Authorization' => 'Bearer ' . $item['token'],
),
);
$request = envato_market()->api()->item( $item['id'], $request_args );
if ( false !== $request ) {
$themes[] = $request;
}
}
}
self::process_themes( $themes );
} elseif ( true === $use_cache ) {
self::process_themes( self::$themes['purchased'] );
}
}
/**
* Set the list of plugins
*
* @since 1.0.0
*
* @param bool $forced Forces an API request. Default is 'false'.
* @param bool $use_cache Attempts to rebuild from the cache before making an API request.
* @param array $args Used to remove or add a plugin during activate and deactivate routines.
*/
public function set_plugins( $forced = false, $use_cache = false, $args = array() ) {
$plugins_transient = get_site_transient( envato_market()->get_option_name() . '_plugins' );
self::$plugins = is_array($plugins_transient) ? $plugins_transient : array();
if ( empty(self::$plugins) || true === $forced ) {
$plugins = envato_market()->api()->plugins();
foreach ( envato_market()->get_option( 'items', array() ) as $item ) {
if ( empty( $item ) ) {
continue;
}
if ( 'plugin' === $item['type'] ) {
$request_args = array(
'headers' => array(
'Authorization' => 'Bearer ' . $item['token'],
),
);
$request = envato_market()->api()->item( $item['id'], $request_args );
if ( false !== $request ) {
$plugins[] = $request;
}
}
}
self::process_plugins( $plugins, $args );
} elseif ( true === $use_cache ) {
self::process_plugins( self::$plugins['purchased'], $args );
}
}
/**
* Rebuild the themes array using the cache value if possible.
*
* @since 1.0.0
*
* @param mixed $filter Any data being filtered.
* @return mixed
*/
public function rebuild_themes( $filter ) {
self::set_themes( false, true );
return $filter;
}
/**
* Rebuild the plugins array using the cache value if possible.
*
* @since 1.0.0
*
* @param string $plugin The plugin to add or remove.
*/
public function rebuild_plugins( $plugin ) {
$remove = ( 'deactivated_plugin' === current_filter() ) ? true : false;
self::set_plugins(
false,
true,
array(
'plugin' => $plugin,
'remove' => $remove,
)
);
}
/**
* Normalizes a string to do a value check against.
*
* Strip all HTML tags including script and style & then decode the
* HTML entities so `&` will equal `&` in the value check and
* finally lower case the entire string. This is required becuase some
* themes & plugins add a link to the Author field or ambersands to the
* names, or change the case of their files or names, which will not match
* the saved value in the database causing a false negative.
*
* @since 1.0.0
*
* @param string $string The string to normalize.
* @return string
*/
public function normalize( $string ) {
return strtolower( html_entity_decode( wp_strip_all_tags( $string ) ) );
}
/**
* Process the themes and save the transient.
*
* @since 1.0.0
*
* @param array $purchased The purchased themes array.
*/
private function process_themes( $purchased ) {
if ( is_wp_error( $purchased ) ) {
$purchased = array();
}
$current = wp_get_theme()->get_template();
$active = array();
$installed = array();
$install = $purchased;
if ( ! empty( $purchased ) ) {
foreach ( wp_get_themes() as $theme ) {
/**
* WP_Theme object.
*
* @var WP_Theme $theme
*/
$template = $theme->get_template();
$title = $theme->get( 'Name' );
$author = $theme->get( 'Author' );
foreach ( $install as $key => $value ) {
if ( $this->normalize( $value['name'] ) === $this->normalize( $title ) && $this->normalize( $value['author'] ) === $this->normalize( $author ) ) {
$installed[ $template ] = $value;
unset( $install[ $key ] );
}
}
}
}
if ( isset( $installed[ $current ] ) ) {
$active[ $current ] = $installed[ $current ];
unset( $installed[ $current ] );
}
self::$themes['purchased'] = array_unique( $purchased, SORT_REGULAR );
self::$themes['active'] = array_unique( $active, SORT_REGULAR );
self::$themes['installed'] = array_unique( $installed, SORT_REGULAR );
self::$themes['install'] = array_unique( array_values( $install ), SORT_REGULAR );
set_site_transient( envato_market()->get_option_name() . '_themes', self::$themes, HOUR_IN_SECONDS );
}
/**
* Process the plugins and save the transient.
*
* @since 1.0.0
*
* @param array $purchased The purchased plugins array.
* @param array $args Used to remove or add a plugin during activate and deactivate routines.
*/
private function process_plugins( $purchased, $args = array() ) {
if ( is_wp_error( $purchased ) ) {
$purchased = array();
}
$active = array();
$installed = array();
$install = $purchased;
if ( ! empty( $purchased ) ) {
foreach ( self::wp_plugins( true ) as $slug => $plugin ) {
foreach ( $install as $key => $value ) {
if ( $this->normalize( $value['name'] ) === $this->normalize( $plugin['Name'] ) && $this->normalize( $value['author'] ) === $this->normalize( $plugin['Author'] ) && file_exists( WP_PLUGIN_DIR . '/' . $slug ) ) {
$installed[ $slug ] = $value;
unset( $install[ $key ] );
}
}
}
}
foreach ( $installed as $slug => $plugin ) {
$condition = false;
if ( ! empty( $args ) && $slug === $args['plugin'] ) {
if ( true === $args['remove'] ) {
continue;
}
$condition = true;
}
if ( $condition || is_plugin_active( $slug ) ) {
$active[ $slug ] = $plugin;
unset( $installed[ $slug ] );
}
}
self::$plugins['purchased'] = array_unique( $purchased, SORT_REGULAR );
self::$plugins['active'] = array_unique( $active, SORT_REGULAR );
self::$plugins['installed'] = array_unique( $installed, SORT_REGULAR );
self::$plugins['install'] = array_unique( array_values( $install ), SORT_REGULAR );
set_site_transient( envato_market()->get_option_name() . '_plugins', self::$plugins, HOUR_IN_SECONDS );
}
}
endif;
admin/view/callback/section/oauth.php 0000644 00000002737 14720702445 0013655 0 ustar 00
' . esc_html__( 'envato.com', 'envato-market' ) . '' ); ?>
admin()->get_generate_token_url() . '" target="_blank">' . esc_html__( 'clicking this link', 'envato-market' ) . '' ); ?>
admin/view/callback/section/items.php 0000644 00000001032 14720702445 0013641 0 ustar 00
admin/view/callback/setting/token.php 0000644 00000000612 14720702445 0013654 0 ustar 00
admin/view/callback/setting/items.php 0000644 00000003531 14720702445 0013660 0 ustar 00 get_option( 'items', array() );
?>
$item ) {
if ( empty( $item['name'] ) || empty( $item['token'] ) || empty( $item['id'] ) || empty( $item['type'] ) || empty( $item['authorized'] ) ) {
continue;
}
$class = 'success' === $item['authorized'] ? 'is-authorized' : 'not-authorized';
echo '
' . esc_html__( 'ID', 'envato-market' ) . ': ' . esc_html( $item['id'] ) . ' - ' . esc_html( $item['name'] ) . '
' . esc_html__( 'Delete', 'envato-market' ) . '
';
}
}
?>
admin/view/callback/admin.php 0000644 00000002011 14720702445 0012142 0 ustar 00
admin/view/notice/error-single-use.php 0000644 00000000424 14720702445 0014007 0 ustar 00
admin/view/notice/success.php 0000644 00000000353 14720702445 0012256 0 ustar 00
admin/view/notice/error.php 0000644 00000000513 14720702445 0011735 0 ustar 00
admin/view/notice/error-http.php 0000644 00000000741 14720702445 0012715 0 ustar 00
admin/view/notice/success-no-items.php 0000644 00000000457 14720702445 0014014 0 ustar 00
admin/view/notice/success-single-use.php 0000644 00000000367 14720702445 0014334 0 ustar 00
admin/view/notice/error-permissions.php 0000644 00000001054 14720702445 0014307 0 ustar 00
get_required_permissions() as $permission ) { ?>
admin/view/notice/error-details.php 0000644 00000000466 14720702445 0013367 0 ustar 00
Additional Error Details: %s. %s %s', esc_html( $title ), esc_html( $message ), esc_html( json_encode( $data ) ) ); ?>
admin/view/partials/plugins.php 0000644 00000000726 14720702445 0012631 0 ustar 00 items()->plugins( 'purchased' );
?>
admin/view/partials/intro.php 0000644 00000001671 14720702445 0012303 0 ustar 00
get_version() ); ?>
', '' ); ?>
admin/view/partials/help.php 0000644 00000005201 14720702445 0012071 0 ustar 00
Troubleshooting:
If you’re having trouble with the plugin, please
Confirm the old Envato Toolkit
plugin is not installed.
Confirm the latest version of WordPress is installed.
Confirm the latest version of the Envato Market plugin is installed.
Try creating a new API token has from the build.envato.com website - ensure only the following permissions have been granted
View and search Envato sites
Download your purchased items
List purchases you've made
Check with the hosting provider to ensure the API connection to api.envato.com
is not blocked.
Check with the hosting provider that the minimum TLS version is 1.2 or above on the server.
If you can’t see your items - check with the item author to confirm the Theme or Plugin is compatible with the Envato Market plugin.
Confirm your Envato account is still active and the items are still visible from your downloads page .
Note - if an item has been recently updated, it may take up to 24 hours for the latest version to appear in the Envato Market plugin.
Health Check:
Problem starting healthcheck. Please check javascript console for errors.
Support:
The Envato Market plugin is maintained - we ensure it works best on the latest version of WordPress and on a modern hosting platform, however we can’t guarantee it’ll work on all WordPress sites or hosting environments.
If you’ve tried all the troubleshooting steps and you’re still unable to get the Envato Market plugin to work on your site/hosting, at this time, our advice is to remove the Envato Market plugin and instead visit the Downloads section of ThemeForest/CodeCanyon to download the latest version of your items.
If you’re having trouble with a specific item from ThemeForest or CodeCanyon, it’s best you browse to the Theme or Plugin item page, visit the ‘support’ tab and follow the next steps.
admin/view/partials/tabs.php 0000644 00000002724 14720702445 0012101 0 ustar 00 items()->themes( 'purchased' );
$plugins = envato_market()->items()->plugins( 'purchased' );
?>
' . esc_html__( 'Themes', 'envato-market' ) . '';
// Plugins tab.
$plugin_class = array();
if ( ! empty( $plugins ) ) {
if ( empty( $tab ) ) {
$tab = 'plugins';
}
if ( 'plugins' === $tab ) {
$plugin_class[] = 'nav-tab-active';
}
} else {
$plugin_class[] = 'hidden';
}
echo '' . esc_html__( 'Plugins', 'envato-market' ) . ' ';
// Settings tab.
echo '' . esc_html__( 'Settings', 'envato-market' ) . ' ';
// Help tab.
echo '' . esc_html__( 'Help', 'envato-market' ) . ' ';
?>
admin/view/partials/settings.php 0000644 00000001760 14720702445 0013007 0 ustar 00 get_option( 'token' );
$items = envato_market()->get_option( 'items', array() );
?>
admin/view/partials/themes.php 0000644 00000000715 14720702445 0012433 0 ustar 00 items()->themes( 'purchased' );
?>
admin/class-envato-market-theme-installer-skin.php 0000644 00000011106 14720702445 0016266 0 ustar 00 upgrader->result['destination_name'] ) ) {
return;
}
$theme_info = $this->upgrader->theme_info();
if ( empty( $theme_info ) ) {
return;
}
$name = $theme_info->display( 'Name' );
$stylesheet = $this->upgrader->result['destination_name'];
$template = $theme_info->get_template();
$activate_link = add_query_arg(
array(
'action' => 'activate',
'template' => urlencode( $template ),
'stylesheet' => urlencode( $stylesheet ),
),
admin_url( 'themes.php' )
);
$activate_link = wp_nonce_url( $activate_link, 'switch-theme_' . $stylesheet );
$install_actions = array();
if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
$install_actions['preview'] = '' . __( 'Live Preview', 'envato-market' ) . ' ' . sprintf( __( 'Live Preview “%s”', 'envato-market' ), $name ) . ' ';
}
if ( is_multisite() ) {
if ( current_user_can( 'manage_network_themes' ) ) {
$install_actions['network_enable'] = '' . __( 'Network Enable', 'envato-market' ) . ' ';
}
}
$install_actions['activate'] = '' . __( 'Activate', 'envato-market' ) . ' ' . sprintf( __( 'Activate “%s”', 'envato-market' ), $name ) . ' ';
$install_actions['themes_page'] = '' . __( 'Return to Theme Installer', 'envato-market' ) . ' ';
if ( ! $this->result || is_wp_error( $this->result ) || is_multisite() || ! current_user_can( 'switch_themes' ) ) {
unset( $install_actions['activate'], $install_actions['preview'] );
}
if ( ! empty( $install_actions ) ) {
$this->feedback( implode( ' | ', $install_actions ) );
}
}
}
endif;
if ( ! class_exists( 'Envato_Market_Plugin_Installer_Skin' ) ) :
/**
* Plugin Installer Skin.
*
* @class Envato_Market_Plugin_Installer_Skin
* @version 1.0.0
* @since 1.0.0
*/
class Envato_Market_Plugin_Installer_Skin extends Plugin_Installer_Skin {
/**
* Modify the install actions.
*
* @since 1.0.0
*/
public function after() {
$plugin_file = $this->upgrader->plugin_info();
$install_actions = array();
if ( current_user_can( 'activate_plugins' ) ) {
$install_actions['activate_plugin'] = '' . __( 'Activate Plugin', 'envato-market' ) . ' ';
}
if ( is_multisite() ) {
unset( $install_actions['activate_plugin'] );
if ( current_user_can( 'manage_network_plugins' ) ) {
$install_actions['network_activate'] = '' . __( 'Network Activate', 'envato-market' ) . ' ';
}
}
$install_actions['plugins_page'] = '' . __( 'Return to Plugin Installer', 'envato-market' ) . ' ';
if ( ! $this->result || is_wp_error( $this->result ) ) {
unset( $install_actions['activate_plugin'], $install_actions['site_activate'], $install_actions['network_activate'] );
}
if ( ! empty( $install_actions ) ) {
$this->feedback( implode( ' | ', $install_actions ) );
}
}
}
endif;
admin/class-envato-market-theme-upgrader.php 0000644 00000003723 14720702445 0015146 0 ustar 00 strings['downloading_package'] = __( 'Downloading the Envato Market upgrade package…', 'envato-market' );
}
/**
* Initialize the install strings.
*
* @since 1.0.0
*/
public function install_strings() {
parent::install_strings();
$this->strings['downloading_package'] = __( 'Downloading the Envato Market install package…', 'envato-market' );
}
}
endif;
if ( ! class_exists( 'Envato_Market_Plugin_Upgrader' ) ) :
/**
* Extends the WordPress Plugin_Upgrader class.
*
* This class makes modifications to the strings during install & upgrade.
*
* @class Envato_Market_Plugin_Upgrader
* @version 1.0.0
* @since 1.0.0
*/
class Envato_Market_Plugin_Upgrader extends Plugin_Upgrader {
/**
* Initialize the upgrade strings.
*
* @since 1.0.0
*/
public function upgrade_strings() {
parent::upgrade_strings();
$this->strings['downloading_package'] = __( 'Downloading the Envato Market upgrade package…', 'envato-market' );
}
/**
* Initialize the install strings.
*
* @since 1.0.0
*/
public function install_strings() {
parent::install_strings();
$this->strings['downloading_package'] = __( 'Downloading the Envato Market install package…', 'envato-market' );
}
}
endif;
admin/class-envato-market-admin.php 0000644 00000162261 14720702445 0013330 0 ustar 00 init_actions();
}
return self::$_instance;
}
/**
* A dummy constructor to prevent this class from being loaded more than once.
*
* @see Envato_Market_Admin::instance()
*
* @since 1.0.0
* @access private
* @codeCoverageIgnore
*/
private function __construct() {
/* We do nothing here! */
}
/**
* You cannot clone this class.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function __clone() {
_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'envato-market' ), '1.0.0' );
}
/**
* You cannot unserialize instances of this class.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function __wakeup() {
_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'envato-market' ), '1.0.0' );
}
/**
* Setup the hooks, actions and filters.
*
* @uses add_action() To add actions.
* @uses add_filter() To add filters.
*
* @since 1.0.0
*/
public function init_actions() {
// @codeCoverageIgnoreStart
if ( false === envato_market()->get_data( 'admin' ) && false === envato_market()->get_option( 'is_plugin_active' ) ) { // Turns the UI off if allowed.
return;
}
// @codeCoverageIgnoreEnd
// Deferred Download.
add_action( 'upgrader_package_options', array( $this, 'maybe_deferred_download' ), 9 );
// Add pre download filter to help with 3rd party plugin integration.
add_filter( 'upgrader_pre_download', array( $this, 'upgrader_pre_download' ), 2, 4 );
// Add item AJAX handler.
add_action( 'wp_ajax_' . self::AJAX_ACTION . '_add_item', array( $this, 'ajax_add_item' ) );
// Remove item AJAX handler.
add_action( 'wp_ajax_' . self::AJAX_ACTION . '_remove_item', array( $this, 'ajax_remove_item' ) );
// Health check AJAX handler
add_action( 'wp_ajax_' . self::AJAX_ACTION . '_healthcheck', array( $this, 'ajax_healthcheck' ) );
// Maybe delete the site transients.
add_action( 'init', array( $this, 'maybe_delete_transients' ), 11 );
// Add the menu.
add_action( 'admin_menu', array( $this, 'add_menu_page' ) );
// Register the settings.
add_action( 'admin_init', array( $this, 'register_settings' ) );
// We may need to redirect after an item is enabled.
add_action( 'current_screen', array( $this, 'maybe_redirect' ) );
// Add authorization notices.
add_action( 'current_screen', array( $this, 'add_notices' ) );
// Set the API values.
add_action( 'current_screen', array( $this, 'set_items' ) );
// Hook to verify the API token before saving it.
add_filter(
'pre_update_option_' . envato_market()->get_option_name(),
array(
$this,
'check_api_token_before_saving',
),
9,
3
);
add_filter(
'pre_update_site_option_' . envato_market()->get_option_name(),
array(
$this,
'check_api_token_before_saving',
),
9,
3
);
// When network enabled, add the network options menu.
add_action( 'network_admin_menu', array( $this, 'add_menu_page' ) );
// Ability to make use of the Settings API when in multisite mode.
add_action( 'network_admin_edit_envato_market_network_settings', array( $this, 'save_network_settings' ) );
}
/**
* This runs before we save the Envato Market options array.
* If the token has changed then we set a transient so we can do the update check.
*
* @param array $value The option to save.
* @param array $old_value The old option value.
* @param array $option Serialized option value.
*
* @return array $value The updated option value.
* @since 2.0.1
*/
public function check_api_token_before_saving( $value, $old_value, $option ) {
if ( ! empty( $value['token'] ) && ( empty( $old_value['token'] ) || $old_value['token'] != $value['token'] || isset( $_POST['envato_market'] ) ) ) {
set_site_transient( envato_market()->get_option_name() . '_check_token', $value['token'], HOUR_IN_SECONDS );
}
return $value;
}
/**
* Defers building the API download url until the last responsible moment to limit file requests.
*
* Filter the package options before running an update.
*
* @param array $options {
* Options used by the upgrader.
*
* @type string $package Package for update.
* @type string $destination Update location.
* @type bool $clear_destination Clear the destination resource.
* @type bool $clear_working Clear the working resource.
* @type bool $abort_if_destination_exists Abort if the Destination directory exists.
* @type bool $is_multi Whether the upgrader is running multiple times.
* @type array $hook_extra Extra hook arguments.
* }
* @since 1.0.0
*/
public function maybe_deferred_download( $options ) {
$package = $options['package'];
if ( false !== strrpos( $package, 'deferred_download' ) && false !== strrpos( $package, 'item_id' ) ) {
parse_str( parse_url( $package, PHP_URL_QUERY ), $vars );
if ( $vars['item_id'] ) {
$args = $this->set_bearer_args( $vars['item_id'] );
$options['package'] = envato_market()->api()->download( $vars['item_id'], $args );
}
}
return $options;
}
/**
* We want to stop certain popular 3rd party scripts from blocking the update process by
* adjusting the plugin name slightly so the 3rd party plugin checks stop.
*
* Currently works for: Visual Composer.
*
* @param string $reply Package URL.
* @param string $package Package URL.
* @param object $updater Updater Object.
*
* @return string $reply New Package URL.
* @since 2.0.0
*/
public function upgrader_pre_download( $reply, $package, $updater ) {
if ( strpos( $package, 'marketplace.envato.com/short-dl' ) !== false ) {
if ( isset( $updater->skin->plugin_info ) && ! empty( $updater->skin->plugin_info['Name'] ) ) {
$updater->skin->plugin_info['Name'] = $updater->skin->plugin_info['Name'] . '.';
} else {
$updater->skin->plugin_info = array(
'Name' => 'Name',
);
}
}
return $reply;
}
/**
* Returns the bearer arguments for a request with a single use API Token.
*
* @param int $id The item ID.
*
* @return array
* @since 1.0.0
*/
public function set_bearer_args( $id ) {
$token = '';
$args = array();
foreach ( envato_market()->get_option( 'items', array() ) as $item ) {
if ( absint( $item['id'] ) === absint( $id ) ) {
$token = $item['token'];
break;
}
}
if ( ! empty( $token ) ) {
$args = array(
'headers' => array(
'Authorization' => 'Bearer ' . $token,
),
);
}
return $args;
}
/**
* Maybe delete the site transients.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function maybe_delete_transients() {
if ( isset( $_POST[ envato_market()->get_option_name() ] ) ) {
// Nonce check.
if ( isset( $_POST['_wpnonce'] ) && ! wp_verify_nonce( $_POST['_wpnonce'], envato_market()->get_slug() . '-options' ) ) {
wp_die( __( 'You do not have sufficient permissions to delete transients.', 'envato-market' ) );
}
self::delete_transients();
} elseif ( ! envato_market()->get_option( 'installed_version', 0 ) || version_compare( envato_market()->get_version(), envato_market()->get_option( 'installed_version', 0 ), '<' ) ) {
// When the plugin updates we want to delete transients.
envato_market()->set_option( 'installed_version', envato_market()->get_version() );
self::delete_transients();
}
}
/**
* Delete the site transients.
*
* @since 1.0.0
* @access private
*/
private function delete_transients() {
delete_site_transient( envato_market()->get_option_name() . '_themes' );
delete_site_transient( envato_market()->get_option_name() . '_plugins' );
}
/**
* Prints out all settings sections added to a particular settings page in columns.
*
* @param string $page The slug name of the page whos settings sections you want to output.
* @param int $columns The number of columns in each row.
*
* @since 1.0.0
*
* @global array $wp_settings_sections Storage array of all settings sections added to admin pages
* @global array $wp_settings_fields Storage array of settings fields and info about their pages/sections
*/
public static function do_settings_sections( $page, $columns = 2 ) {
global $wp_settings_sections, $wp_settings_fields;
// @codeCoverageIgnoreStart
if ( ! isset( $wp_settings_sections[ $page ] ) ) {
return;
}
// @codeCoverageIgnoreEnd
foreach ( (array) $wp_settings_sections[ $page ] as $section ) {
// @codeCoverageIgnoreStart
if ( ! isset( $wp_settings_fields ) || ! isset( $wp_settings_fields[ $page ] ) || ! isset( $wp_settings_fields[ $page ][ $section['id'] ] ) ) {
continue;
}
// @codeCoverageIgnoreEnd
// Set the column class.
$class = 'envato-market-block';
?>
' . esc_html( $section['title'] ) . '' . "\n";
}
if ( ! empty( $section['callback'] ) ) {
call_user_func( $section['callback'], $section );
}
?>
';
$page = add_menu_page(
__( 'Envato Market', 'envato-market' ),
__( 'Envato Market', 'envato-market' ),
'manage_options',
envato_market()->get_slug(),
array(
$this,
'render_admin_callback',
),
'data:image/svg+xml;base64,' . base64_encode($svg_icon)
);
// Enqueue admin CSS.
add_action( 'admin_print_styles-' . $page, array( $this, 'admin_enqueue_style' ) );
// Enqueue admin JavaScript.
add_action( 'admin_print_scripts-' . $page, array( $this, 'admin_enqueue_script' ) );
// Add Underscore.js templates.
add_action( 'admin_footer-' . $page, array( $this, 'render_templates' ) );
}
/**
* Enqueue admin css.
*
* @since 1.0.0
*/
public function admin_enqueue_style() {
$file_url = envato_market()->get_plugin_url() . 'css/envato-market' . ( is_rtl() ? '-rtl' : '' ) . '.css';
wp_enqueue_style( envato_market()->get_slug(), $file_url, array( 'wp-jquery-ui-dialog' ), envato_market()->get_version() );
}
/**
* Enqueue admin script.
*
* @since 1.0.0
*/
public function admin_enqueue_script() {
$min = ( WP_DEBUG ? '' : '.min' );
$slug = envato_market()->get_slug();
$version = envato_market()->get_version();
$plugin_url = envato_market()->get_plugin_url();
wp_enqueue_script(
$slug,
$plugin_url . 'js/envato-market' . $min . '.js',
array(
'jquery',
'jquery-ui-dialog',
'wp-util',
),
$version,
true
);
wp_enqueue_script(
$slug . '-updates',
$plugin_url . 'js/updates' . $min . '.js',
array(
'jquery',
'updates',
'wp-a11y',
'wp-util',
),
$version,
true
);
// Script data array.
$exports = array(
'nonce' => wp_create_nonce( self::AJAX_ACTION ),
'action' => self::AJAX_ACTION,
'i18n' => array(
'save' => __( 'Save', 'envato-market' ),
'remove' => __( 'Remove', 'envato-market' ),
'cancel' => __( 'Cancel', 'envato-market' ),
'error' => __( 'An unknown error occurred. Try again.', 'envato-market' ),
),
);
// Export data to JS.
wp_scripts()->add_data(
$slug,
'data',
sprintf( 'var _envatoMarket = %s;', wp_json_encode( $exports ) )
);
}
/**
* Underscore (JS) templates for dialog windows.
*
* @codeCoverageIgnore
*/
public function render_templates() {
?>
get_slug(), envato_market()->get_option_name() );
// OAuth section.
add_settings_section(
envato_market()->get_option_name() . '_oauth_section',
__( 'Getting Started (Simple)', 'envato-market' ),
array( $this, 'render_oauth_section_callback' ),
envato_market()->get_slug()
);
// Token setting.
add_settings_field(
'token',
__( 'Token', 'envato-market' ),
array( $this, 'render_token_setting_callback' ),
envato_market()->get_slug(),
envato_market()->get_option_name() . '_oauth_section'
);
// Items section.
add_settings_section(
envato_market()->get_option_name() . '_items_section',
__( 'Single Item Tokens (Advanced)', 'envato-market' ),
array( $this, 'render_items_section_callback' ),
envato_market()->get_slug()
);
// Items setting.
add_settings_field(
'items',
__( 'Envato Market Items', 'envato-market' ),
array( $this, 'render_items_setting_callback' ),
envato_market()->get_slug(),
envato_market()->get_option_name() . '_items_section'
);
}
/**
* Redirect after the enable action runs.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function maybe_redirect() {
if ( $this->are_we_on_settings_page() ) {
if ( ! empty( $_GET['action'] ) && 'install-theme' === $_GET['action'] && ! empty( $_GET['enabled'] ) ) {
wp_safe_redirect( esc_url( envato_market()->get_page_url() ) );
exit;
}
}
}
/**
* Add authorization notices.
*
* @since 1.0.0
*/
public function add_notices() {
if ( $this->are_we_on_settings_page() ) {
// @codeCoverageIgnoreStart
if ( get_site_transient( envato_market()->get_option_name() . '_check_token' ) || ( isset( $_GET['authorization'] ) && 'check' === $_GET['authorization'] ) ) {
delete_site_transient( envato_market()->get_option_name() . '_check_token' );
self::authorization_redirect();
}
// @codeCoverageIgnoreEnd
// Get the option array.
$option = envato_market()->get_options();
// Display success/error notices.
if ( ! empty( $option['notices'] ) ) {
self::delete_transients();
// Show succes notice.
if ( isset( $option['notices']['success'] ) ) {
add_action(
( ENVATO_MARKET_NETWORK_ACTIVATED ? 'network_' : '' ) . 'admin_notices',
array(
$this,
'render_success_notice',
)
);
}
// Show succes no-items notice.
if ( isset( $option['notices']['success-no-items'] ) ) {
add_action(
( ENVATO_MARKET_NETWORK_ACTIVATED ? 'network_' : '' ) . 'admin_notices',
array(
$this,
'render_success_no_items_notice',
)
);
}
// Show single-use succes notice.
if ( isset( $option['notices']['success-single-use'] ) ) {
add_action(
( ENVATO_MARKET_NETWORK_ACTIVATED ? 'network_' : '' ) . 'admin_notices',
array(
$this,
'render_success_single_use_notice',
)
);
}
// Show error notice.
if ( isset( $option['notices']['error'] ) ) {
add_action(
( ENVATO_MARKET_NETWORK_ACTIVATED ? 'network_' : '' ) . 'admin_notices',
array(
$this,
'render_error_notice',
)
);
}
// Show invalid permissions error notice.
if ( isset( $option['notices']['error-permissions'] ) ) {
add_action(
( ENVATO_MARKET_NETWORK_ACTIVATED ? 'network_' : '' ) . 'admin_notices',
array(
$this,
'render_error_permissions',
)
);
}
// Show single-use error notice.
if ( isset( $option['notices']['error-single-use'] ) ) {
add_action(
( ENVATO_MARKET_NETWORK_ACTIVATED ? 'network_' : '' ) . 'admin_notices',
array(
$this,
'render_error_single_use_notice',
)
);
}
// Show missing zip notice.
if ( isset( $option['notices']['missing-package-zip'] ) ) {
add_action(
( ENVATO_MARKET_NETWORK_ACTIVATED ? 'network_' : '' ) . 'admin_notices',
array(
$this,
'render_error_missing_zip',
)
);
}
// Show missing http connection error.
if ( isset( $option['notices']['http_error'] ) ) {
add_action(
( ENVATO_MARKET_NETWORK_ACTIVATED ? 'network_' : '' ) . 'admin_notices',
array(
$this,
'render_error_http',
)
);
}
// Update the saved data so the notice disappears on the next page load.
unset( $option['notices'] );
envato_market()->set_options( $option );
}
}
}
/**
* Set the API values.
*
* @since 1.0.0
*/
public function set_items() {
if ( $this->are_we_on_settings_page() ) {
envato_market()->items()->set_themes();
envato_market()->items()->set_plugins();
}
}
/**
* Check if we're on the settings page.
*
* @since 2.0.0
* @access private
*/
private function are_we_on_settings_page() {
return 'toplevel_page_' . envato_market()->get_slug() === get_current_screen()->id || 'toplevel_page_' . envato_market()->get_slug() . '-network' === get_current_screen()->id;
}
/**
* Check for authorization and redirect.
*
* @since 1.0.0
* @access private
* @codeCoverageIgnore
*/
private function authorization_redirect() {
self::authorization();
wp_safe_redirect( esc_url( envato_market()->get_page_url() . '#settings' ) );
exit;
}
/**
* Set the Envato API authorization value.
*
* @since 1.0.0
*/
public function authorization() {
// Get the option array.
$option = envato_market()->get_options();
$option['notices'] = array();
// Check for global token.
if ( envato_market()->get_option( 'token' ) || envato_market()->api()->token ) {
$notice = 'success';
$scope_check = $this->authorize_token_permissions();
if ( 'http_error' === $scope_check ) {
$notice = 'http_error';
} elseif ( 'error' === $this->authorize_total_items() || 'error' === $scope_check ) {
$notice = 'error';
} else {
if ( 'missing-permissions' == $scope_check ) {
$notice = 'error-permissions';
} elseif ( 'too-many-permissions' === $scope_check ) {
$notice = 'error-permissions';
} else {
$themes_notice = $this->authorize_themes();
$plugins_notice = $this->authorize_plugins();
if ( 'error' === $themes_notice || 'error' === $plugins_notice ) {
$notice = 'error';
} elseif ( 'success-no-themes' === $themes_notice && 'success-no-plugins' === $plugins_notice ) {
$notice = 'success-no-items';
}
}
}
$option['notices'][ $notice ] = true;
}
// Check for single-use token.
if ( ! empty( $option['items'] ) ) {
$failed = false;
foreach ( $option['items'] as $key => $item ) {
if ( empty( $item['name'] ) || empty( $item['token'] ) || empty( $item['id'] ) || empty( $item['type'] ) || empty( $item['authorized'] ) ) {
continue;
}
$request_args = array(
'headers' => array(
'Authorization' => 'Bearer ' . $item['token'],
),
);
// Uncached API response with single-use token.
$response = envato_market()->api()->item( $item['id'], $request_args );
if ( ! is_wp_error( $response ) && isset( $response['id'] ) ) {
$option['items'][ $key ]['authorized'] = 'success';
} else {
if ( is_wp_error( $response ) ) {
$this->store_additional_error_debug_information( 'Unable to query single item ID ' . $item['id'], $response->get_error_message(), $response->get_error_data() );
}
$failed = true;
$option['items'][ $key ]['authorized'] = 'failed';
}
}
if ( true === $failed ) {
$option['notices']['error-single-use'] = true;
} else {
$option['notices']['success-single-use'] = true;
}
}
// Set the option array.
if ( ! empty( $option['notices'] ) ) {
envato_market()->set_options( $option );
}
}
/**
* Check that themes are authorized.
*
* @return bool
* @since 1.0.0
*/
public function authorize_total_items() {
$domain = envato_market()->get_envato_api_domain();
$path = envato_market()->api()->api_path_for('total-items');
$url = $domain . $path;
$response = envato_market()->api()->request( $url );
$notice = 'success';
if ( is_wp_error( $response ) ) {
$notice = 'error';
$this->store_additional_error_debug_information( 'Failed to query total number of items in API response', $response->get_error_message(), $response->get_error_data() );
} elseif ( ! isset( $response['total-items'] ) ) {
$notice = 'error';
$this->store_additional_error_debug_information( 'Incorrect response from API when querying total items' );
}
return $notice;
}
/**
* Get the required API permissions for this plugin to work.
*
* @single 2.0.1
*
* @return array
*/
public function get_required_permissions() {
return apply_filters(
'envato_market_required_permissions',
array(
'default' => 'View and search Envato sites',
'purchase:download' => 'Download your purchased items',
'purchase:list' => 'List purchases you\'ve made',
)
);
}
/**
* Return the URL a user needs to click to generate a personal token.
*
* @single 2.0.1
*
* @return string The full URL to request a token.
*/
public function get_generate_token_url() {
return 'https://build.envato.com/create-token/?' . implode(
'&',
array_map(
function ( $val ) {
return $val . '=t';
},
array_keys( $this->get_required_permissions() )
)
);
}
/**
* Check that themes are authorized.
*
* @return bool
* @since 1.0.0
*/
public function authorize_token_permissions() {
if ( defined('ENVATO_LOCAL_DEVELOPMENT') ) {
return 'success';
}
$notice = 'success';
$response = envato_market()->api()->request( 'https://api.envato.com/whoami' );
if ( is_wp_error( $response ) && ( $response->get_error_code() === 'http_error' || $response->get_error_code() == 500 ) ) {
$this->store_additional_error_debug_information( 'An error occured checking token permissions', $response->get_error_message(), $response->get_error_data() );
$notice = 'http_error';
} elseif ( is_wp_error( $response ) || ! isset( $response['scopes'] ) || ! is_array( $response['scopes'] ) ) {
$this->store_additional_error_debug_information( 'No scopes found in API response message', $response->get_error_message(), $response->get_error_data() );
$notice = 'error';
} else {
$minimum_scopes = $this->get_required_permissions();
$maximum_scopes = array( 'default' => 'Default' ) + $minimum_scopes;
foreach ( $minimum_scopes as $required_scope => $required_scope_name ) {
if ( ! in_array( $required_scope, $response['scopes'] ) ) {
// The scope minimum required scope doesn't exist.
$this->store_additional_error_debug_information( 'Could not find required API permission scope in output.', $required_scope );
$notice = 'missing-permissions';
}
}
foreach ( $response['scopes'] as $scope ) {
if ( ! isset( $maximum_scopes[ $scope ] ) ) {
// The available scope is outside our maximum bounds.
$this->store_additional_error_debug_information( 'Found too many permissions on token.', $scope );
$notice = 'too-many-permissions';
}
}
}
return $notice;
}
/**
* Check that themes or plugins are authorized and downloadable.
*
* @param string $type The filter type, either 'themes' or 'plugins'. Default 'themes'.
*
* @return bool|null
* @since 1.0.0
*/
public function authorize_items( $type = 'themes' ) {
$domain = envato_market()->get_envato_api_domain();
$path = envato_market()->api()->api_path_for('list-purchases');
$api_url = $domain . $path . '?filter_by=wordpress-' . $type;
$response = envato_market()->api()->request( $api_url );
$notice = 'success';
if ( is_wp_error( $response ) ) {
$notice = 'error';
$this->store_additional_error_debug_information( 'Error listing buyer purchases.', $response->get_error_message(), $response->get_error_data() );
} elseif ( empty( $response ) ) {
$notice = 'error';
$this->store_additional_error_debug_information( 'Empty API result listing buyer purchases' );
} elseif ( empty( $response['results'] ) ) {
$notice = 'success-no-' . $type;
} else {
shuffle( $response['results'] );
$item = array_shift( $response['results'] );
if ( ! isset( $item['item']['id'] ) || ! envato_market()->api()->download( $item['item']['id'] ) ) {
$this->store_additional_error_debug_information( 'Failed to find the correct item format in API response' );
$notice = 'error';
}
}
return $notice;
}
/**
* Check that themes are authorized.
*
* @return bool
* @since 1.0.0
*/
public function authorize_themes() {
return $this->authorize_items( 'themes' );
}
/**
* Check that plugins are authorized.
*
* @return bool
* @since 1.0.0
*/
public function authorize_plugins() {
return $this->authorize_items( 'plugins' );
}
/**
* Install plugin.
*
* @param string $plugin The plugin item ID.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function install_plugin( $plugin ) {
if ( ! current_user_can( 'install_plugins' ) ) {
$msg = '
';
wp_die( $msg );
}
check_admin_referer( 'install-plugin_' . $plugin );
envato_market()->items()->set_plugins( true );
$install = envato_market()->items()->plugins( 'install' );
$api = new stdClass();
foreach ( $install as $value ) {
if ( absint( $value['id'] ) === absint( $plugin ) ) {
$api->name = $value['name'];
$api->version = $value['version'];
}
}
$array_api = (array) $api;
if ( empty( $array_api ) ) {
$msg = '
';
wp_die( $msg );
}
$title = sprintf( __( 'Installing Plugin: %s', 'envato-market' ), esc_html( $api->name . ' ' . $api->version ) );
$nonce = 'install-plugin_' . $plugin;
$url = 'admin.php?page=' . envato_market()->get_slug() . '&action=install-plugin&plugin=' . urlencode( $plugin );
$type = 'web'; // Install plugin type, From Web or an Upload.
$api->download_link = envato_market()->api()->download( $plugin, $this->set_bearer_args( $plugin ) );
// Must have the upgrader & skin.
require envato_market()->get_plugin_path() . '/inc/admin/class-envato-market-theme-upgrader.php';
require envato_market()->get_plugin_path() . '/inc/admin/class-envato-market-theme-installer-skin.php';
$upgrader = new Envato_Market_Plugin_Upgrader( new Envato_Market_Plugin_Installer_Skin( compact( 'title', 'url', 'nonce', 'plugin', 'api' ) ) );
$upgrader->install( $api->download_link );
}
/**
* Install theme.
*
* @param string $theme The theme item ID.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function install_theme( $theme ) {
if ( ! current_user_can( 'install_themes' ) ) {
$msg = '
';
wp_die( $msg );
}
check_admin_referer( 'install-theme_' . $theme );
envato_market()->items()->set_themes( true );
$install = envato_market()->items()->themes( 'install' );
$api = new stdClass();
foreach ( $install as $value ) {
if ( absint( $value['id'] ) === absint( $theme ) ) {
$api->name = $value['name'];
$api->version = $value['version'];
}
}
$array_api = (array) $api;
if ( empty( $array_api ) ) {
$msg = '
';
wp_die( $msg );
}
wp_enqueue_script( 'customize-loader' );
$title = sprintf( __( 'Installing Theme: %s', 'envato-market' ), esc_html( $api->name . ' ' . $api->version ) );
$nonce = 'install-theme_' . $theme;
$url = 'admin.php?page=' . envato_market()->get_slug() . '&action=install-theme&theme=' . urlencode( $theme );
$type = 'web'; // Install theme type, From Web or an Upload.
$api->download_link = envato_market()->api()->download( $theme, $this->set_bearer_args( $theme ) );
// Must have the upgrader & skin.
require_once envato_market()->get_plugin_path() . '/inc/admin/class-envato-market-theme-upgrader.php';
require_once envato_market()->get_plugin_path() . '/inc/admin/class-envato-market-theme-installer-skin.php';
$upgrader = new Envato_Market_Theme_Upgrader( new Envato_Market_Theme_Installer_Skin( compact( 'title', 'url', 'nonce', 'api' ) ) );
$upgrader->install( $api->download_link );
}
/**
* AJAX handler for adding items that use a non global token.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function ajax_add_item() {
if ( ! check_ajax_referer( self::AJAX_ACTION, 'nonce', false ) ) {
status_header( 400 );
wp_send_json_error( 'bad_nonce' );
} elseif ( 'POST' !== $_SERVER['REQUEST_METHOD'] ) {
status_header( 405 );
wp_send_json_error( 'bad_method' );
} elseif ( empty( $_POST['token'] ) ) {
wp_send_json_error( array( 'message' => __( 'The Token is missing.', 'envato-market' ) ) );
} elseif ( empty( $_POST['id'] ) ) {
wp_send_json_error( array( 'message' => __( 'The Item ID is missing.', 'envato-market' ) ) );
} elseif ( ! current_user_can( 'install_themes' ) || ! current_user_can( 'install_plugins' ) ) {
wp_send_json_error( array( 'message' => __( 'User not allowed to install items.', 'envato-market' ) ) );
}
$args = array(
'headers' => array(
'Authorization' => 'Bearer ' . $_POST['token'],
),
);
$request = envato_market()->api()->item( $_POST['id'], $args );
if ( false === $request ) {
wp_send_json_error( array( 'message' => __( 'The Token or Item ID is incorrect.', 'envato-market' ) ) );
}
if ( false === envato_market()->api()->download( $_POST['id'], $args ) ) {
wp_send_json_error( array( 'message' => __( 'The item cannot be downloaded.', 'envato-market' ) ) );
}
if ( isset( $request['number_of_sales'] ) ) {
$type = 'plugin';
} else {
$type = 'theme';
}
if ( isset( $type ) ) {
$response = array(
'name' => $request['name'],
'token' => $_POST['token'],
'id' => $_POST['id'],
'type' => $type,
'authorized' => 'success',
);
$options = get_option( envato_market()->get_option_name(), array() );
if ( ! empty( $options['items'] ) ) {
$options['items'] = array_values( $options['items'] );
$key = count( $options['items'] );
} else {
$options['items'] = array();
$key = 0;
}
$options['items'][] = $response;
envato_market()->set_options( $options );
// Rebuild the theme cache.
if ( 'theme' === $type ) {
envato_market()->items()->set_themes( true, false );
$install_link = add_query_arg(
array(
'page' => envato_market()->get_slug(),
'action' => 'install-theme',
'id' => $_POST['id'],
),
self_admin_url( 'admin.php' )
);
$request['install'] = wp_nonce_url( $install_link, 'install-theme_' . $_POST['id'] );
}
// Rebuild the plugin cache.
if ( 'plugin' === $type ) {
envato_market()->items()->set_plugins( true, false );
$install_link = add_query_arg(
array(
'page' => envato_market()->get_slug(),
'action' => 'install-plugin',
'id' => $_POST['id'],
),
self_admin_url( 'admin.php' )
);
$request['install'] = wp_nonce_url( $install_link, 'install-plugin_' . $_POST['id'] );
}
$response['key'] = $key;
$response['item'] = $request;
wp_send_json_success( $response );
}
wp_send_json_error( array( 'message' => __( 'An unknown error occurred.', 'envato-market' ) ) );
}
/**
* AJAX handler for removing items that use a non global token.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function ajax_remove_item() {
if ( ! check_ajax_referer( self::AJAX_ACTION, 'nonce', false ) ) {
status_header( 400 );
wp_send_json_error( 'bad_nonce' );
} elseif ( 'POST' !== $_SERVER['REQUEST_METHOD'] ) {
status_header( 405 );
wp_send_json_error( 'bad_method' );
} elseif ( empty( $_POST['id'] ) ) {
wp_send_json_error( array( 'message' => __( 'The Item ID is missing.', 'envato-market' ) ) );
} elseif ( ! current_user_can( 'delete_plugins' ) || ! current_user_can( 'delete_themes' ) ) {
wp_send_json_error( array( 'message' => __( 'User not allowed to update items.', 'envato-market' ) ) );
}
$options = get_option( envato_market()->get_option_name(), array() );
$type = '';
foreach ( $options['items'] as $key => $item ) {
if ( $item['id'] === $_POST['id'] ) {
$type = $item['type'];
unset( $options['items'][ $key ] );
break;
}
}
$options['items'] = array_values( $options['items'] );
envato_market()->set_options( $options );
// Rebuild the theme cache.
if ( 'theme' === $type ) {
envato_market()->items()->set_themes( true, false );
}
// Rebuild the plugin cache.
if ( 'plugin' === $type ) {
envato_market()->items()->set_plugins( true, false );
}
wp_send_json_success();
}
/**
* AJAX handler for performing a healthcheck of the current website.
*
* @since 2.0.6
* @codeCoverageIgnore
*/
public function ajax_healthcheck() {
if ( ! check_ajax_referer( self::AJAX_ACTION, 'nonce', false ) ) {
status_header( 400 );
wp_send_json_error( 'bad_nonce' );
} elseif ( 'POST' !== $_SERVER['REQUEST_METHOD'] ) {
status_header( 405 );
wp_send_json_error( 'bad_method' );
} elseif ( ! current_user_can( 'install_themes' ) || ! current_user_can( 'install_plugins' ) ) {
wp_send_json_error( array( 'message' => __( 'User not allowed to install items.', 'envato-market' ) ) );
}
$limits = $this->get_server_limits();
wp_send_json_success( array(
'limits' => $limits
) );
}
/**
* AJAX handler for performing a healthcheck of the current website.
*
* @since 2.0.6
* @codeCoverageIgnore
*/
public function get_server_limits() {
$limits = [];
// Check memory limit is > 256 M
try {
$memory_limit = wp_convert_hr_to_bytes( ini_get( 'memory_limit' ) );
$memory_limit_desired = 256;
$memory_limit_ok = $memory_limit < 0 || $memory_limit >= $memory_limit_desired * 1024 * 1024;
$memory_limit_in_mb = $memory_limit < 0 ? 'Unlimited' : floor( $memory_limit / ( 1024 * 1024 ) ) . 'M';
$limits['memory_limit'] = [
'title' => 'PHP Memory Limit',
'ok' => $memory_limit_ok,
'message' => $memory_limit_ok ? "is ok at {$memory_limit_in_mb}." : "{$memory_limit_in_mb} may be too small. If you are having issues please set your PHP memory limit to at least 256M - or ask your hosting provider to do this if you're unsure."
];
} catch ( \Exception $e ) {
$limits['memory_limit'] = [
'title' => 'PHP Memory Limit',
'ok' => false,
'message' => 'Failed to check memory limit. If you are having issues please ask hosting provider to raise the memory limit for you.'
];
}
// Check upload size.
try {
$upload_size_desired = 80;
$upload_max_filesize = wp_max_upload_size();
$upload_max_filesize_ok = $upload_max_filesize < 0 || $upload_max_filesize >= $upload_size_desired * 1024 * 1024;
$upload_max_filesize_in_mb = $upload_max_filesize < 0 ? 'Unlimited' : floor( $upload_max_filesize / ( 1024 * 1024 ) ) . 'M';
$limits['upload'] = [
'ok' => $upload_max_filesize_ok,
'title' => 'PHP Upload Limits',
'message' => $upload_max_filesize_ok ? "is ok at $upload_max_filesize_in_mb." : "$upload_max_filesize_in_mb may be too small. If you are having issues please set your PHP upload limits to at least {$upload_size_desired}M - or ask your hosting provider to do this if you're unsure.",
];
} catch ( \Exception $e ) {
$limits['upload'] = [
'title' => 'PHP Upload Limits',
'ok' => false,
'message' => 'Failed to check upload limit. If you are having issues please ask hosting provider to raise the upload limit for you.'
];
}
// Check max_input_vars.
try {
$max_input_vars = ini_get( 'max_input_vars' );
$max_input_vars_desired = 1000;
$max_input_vars_ok = $max_input_vars < 0 || $max_input_vars >= $max_input_vars_desired;
$limits['max_input_vars'] = [
'ok' => $max_input_vars_ok,
'title' => 'PHP Max Input Vars',
'message' => $max_input_vars_ok ? "is ok at $max_input_vars." : "$max_input_vars may be too small. If you are having issues please set your PHP max input vars to at least $max_input_vars_desired - or ask your hosting provider to do this if you're unsure.",
];
} catch ( \Exception $e ) {
$limits['max_input_vars'] = [
'title' => 'PHP Max Input Vars',
'ok' => false,
'message' => 'Failed to check input vars limit. If you are having issues please ask hosting provider to raise the input vars limit for you.'
];
}
// Check max_execution_time.
try {
$max_execution_time = ini_get( 'max_execution_time' );
$max_execution_time_desired = 60;
$max_execution_time_ok = $max_execution_time <= 0 || $max_execution_time >= $max_execution_time_desired;
$limits['max_execution_time'] = [
'ok' => $max_execution_time_ok,
'title' => 'PHP Execution Time',
'message' => $max_execution_time_ok ? "PHP execution time limit is ok at {$max_execution_time}." : "$max_execution_time is too small. Please set your PHP max execution time to at least $max_execution_time_desired - or ask your hosting provider to do this if you're unsure.",
];
} catch ( \Exception $e ) {
$limits['max_execution_time'] = [
'title' => 'PHP Execution Time',
'ok' => false,
'message' => 'Failed to check PHP execution time limit. Please ask hosting provider to raise this limit for you.'
];
}
// Check various hostname connectivity.
$hosts_to_check = array(
array(
'hostname' => 'envato.github.io',
'url' => 'https://envato.github.io/wp-envato-market/dist/update-check.json',
'title' => 'Plugin Update API',
),
array(
'hostname' => 'api.envato.com',
'url' => 'https://api.envato.com/ping',
'title' => 'Envato Market API',
),
array(
'hostname' => 'marketplace.envato.com',
'url' => 'https://marketplace.envato.com/robots.txt',
'title' => 'Download API',
),
);
foreach ( $hosts_to_check as $host ) {
try {
$response = wp_remote_get( $host['url'], [
'user-agent' => 'WordPress - Envato Market ' . envato_market()->get_version(),
'timeout' => 5,
] );
$response_code = wp_remote_retrieve_response_code( $response );
if ( $response && ! is_wp_error( $response ) && $response_code === 200 ) {
$limits[ $host['hostname'] ] = [
'ok' => true,
'title' => $host['title'],
'message' => 'Connected ok.',
];
} else {
$limits[ $host['hostname'] ] = [
'ok' => false,
'title' => $host['title'],
'message' => "Connection failed. Status '$response_code'. Please ensure PHP is allowed to connect to the host '" . $host['hostname'] . "' - or ask your hosting provider to do this if you’re unsure. " . ( is_wp_error( $response ) ? $response->get_error_message() : '' ),
];
}
} catch ( \Exception $e ) {
$limits[ $host['hostname'] ] = [
'ok' => true,
'title' => $host['title'],
'message' => "Connection failed. Please contact the hosting provider and ensure PHP is allowed to connect to the host '" . $host['hostname'] . "'. " . $e->getMessage(),
];
}
}
// Check authenticated API request
if ( !defined('ENVATO_LOCAL_DEVELOPMENT') ) {
$response = envato_market()->api()->request( 'https://api.envato.com/whoami' );
if ( is_wp_error( $response ) ) {
$limits['authentication'] = [
'ok' => false,
'title' => 'Envato API Authentication',
'message' => "Not currently authenticated with the Envato API. Please add your API token. " . $response->get_error_message(),
];
} elseif ( ! isset( $response['scopes'] ) ) {
$limits['authentication'] = [
'ok' => false,
'title' => 'Envato API Authentication',
'message' => "Missing API permissions. Please re-create your Envato API token with the correct permissions. ",
];
} else {
$minimum_scopes = $this->get_required_permissions();
$maximum_scopes = array( 'default' => 'Default' ) + $minimum_scopes;
$missing_scopes = array();
$additional_scopes = array();
foreach ( $minimum_scopes as $required_scope => $required_scope_name ) {
if ( ! in_array( $required_scope, $response['scopes'] ) ) {
// The scope minimum required scope doesn't exist.
$missing_scopes [] = $required_scope;
}
}
foreach ( $response['scopes'] as $scope ) {
if ( ! isset( $maximum_scopes[ $scope ] ) ) {
// The available scope is outside our maximum bounds.
$additional_scopes [] = $scope;
}
}
$limits['authentication'] = [
'ok' => true,
'title' => 'Envato API Authentication',
'message' => "Authenticated successfully with correct scopes: " . implode( ', ', $response['scopes'] ),
];
}
}
$debug_enabled = defined( 'WP_DEBUG' ) && WP_DEBUG;
$limits['wp_debug'] = [
'ok' => ! $debug_enabled,
'title' => 'WP Debug',
'message' => $debug_enabled ? 'If you’re on a production website, it’s best to set WP_DEBUG to false, please ask your hosting provider to do this if you’re unsure.' : 'WP Debug is disabled, all ok.',
];
$zip_archive_installed = class_exists( '\ZipArchive' );
$limits['zip_archive'] = [
'ok' => $zip_archive_installed,
'title' => 'ZipArchive Support',
'message' => $zip_archive_installed ? 'ZipArchive is available.' : 'ZipArchive is not available. If you have issues installing or updating items please ask your hosting provider to enable ZipArchive.',
];
$php_version_ok = version_compare( PHP_VERSION, '7.0', '>=' );
$limits['php_version'] = [
'ok' => $php_version_ok,
'title' => 'PHP Version',
'message' => $php_version_ok ? 'PHP version is ok at ' . PHP_VERSION . '.' : 'Please ask the hosting provider to upgrade your PHP version to at least 7.0 or above.',
];
require_once( ABSPATH . 'wp-admin/includes/file.php' );
$current_filesystem_method = get_filesystem_method();
if ( $current_filesystem_method !== 'direct' ) {
$limits['filesystem_method'] = [
'ok' => false,
'title' => 'WordPress Filesystem',
'message' => 'Please enable WordPress FS_METHOD direct - or ask your hosting provider to do this if you’re unsure.',
];
}
$wp_upload_dir = wp_upload_dir();
$upload_base_dir = $wp_upload_dir['basedir'];
$upload_base_dir_writable = is_writable( $upload_base_dir );
$limits['wp_content_writable'] = [
'ok' => $upload_base_dir_writable,
'title' => 'WordPress File Permissions',
'message' => $upload_base_dir_writable ? 'is ok.' : 'Please set correct WordPress PHP write permissions for the wp-content directory - or ask your hosting provider to do this if you’re unsure.',
];
$active_plugins = get_option( 'active_plugins' );
$active_plugins_ok = count( $active_plugins ) < 15;
if ( ! $active_plugins_ok ) {
$limits['active_plugins'] = [
'ok' => false,
'title' => 'Active Plugins',
'message' => 'Please try to reduce the number of active plugins on your WordPress site, as this will slow things down.',
];
}
return $limits;
}
/**
* Admin page callback.
*
* @since 1.0.0
*/
public function render_admin_callback() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/callback/admin.php' );
}
/**
* OAuth section callback.
*
* @since 1.0.0
*/
public function render_oauth_section_callback() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/callback/section/oauth.php' );
}
/**
* Items section callback.
*
* @since 1.0.0
*/
public function render_items_section_callback() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/callback/section/items.php' );
}
/**
* Token setting callback.
*
* @since 1.0.0
*/
public function render_token_setting_callback() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/callback/setting/token.php' );
}
/**
* Items setting callback.
*
* @since 1.0.0
*/
public function render_items_setting_callback() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/callback/setting/items.php' );
}
/**
* Intro
*
* @since 1.0.0
*/
public function render_intro_partial() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/partials/intro.php' );
}
/**
* Tabs
*
* @since 1.0.0
*/
public function render_tabs_partial() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/partials/tabs.php' );
}
/**
* Settings panel
*
* @since 1.0.0
*/
public function render_settings_panel_partial() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/partials/settings.php' );
}
/**
* Help panel
*
* @since 2.0.1
*/
public function render_help_panel_partial() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/partials/help.php' );
}
/**
* Themes panel
*
* @since 1.0.0
*/
public function render_themes_panel_partial() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/partials/themes.php' );
}
/**
* Plugins panel
*
* @since 1.0.0
*/
public function render_plugins_panel_partial() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/partials/plugins.php' );
}
/**
* Success notice.
*
* @since 1.0.0
*/
public function render_success_notice() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/notice/success.php' );
}
/**
* Success no-items notice.
*
* @since 1.0.0
*/
public function render_success_no_items_notice() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/notice/success-no-items.php' );
}
/**
* Success single-use notice.
*
* @since 1.0.0
*/
public function render_success_single_use_notice() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/notice/success-single-use.php' );
}
/**
* Error details.
*
* @since 2.0.2
*/
public function render_additional_error_details() {
$error_details = get_site_transient( envato_market()->get_option_name() . '_error_information' );
if ( $error_details && ! empty( $error_details['title'] ) ) {
extract( $error_details );
require( envato_market()->get_plugin_path() . 'inc/admin/view/notice/error-details.php' );
}
}
/**
* Error notice.
*
* @since 1.0.0
*/
public function render_error_notice() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/notice/error.php' );
$this->render_additional_error_details();
}
/**
* Permission error notice.
*
* @since 2.0.1
*/
public function render_error_permissions() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/notice/error-permissions.php' );
$this->render_additional_error_details();
}
/**
* Error single-use notice.
*
* @since 1.0.0
*/
public function render_error_single_use_notice() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/notice/error-single-use.php' );
$this->render_additional_error_details();
}
/**
* Error missing zip.
*
* @since 2.0.1
*/
public function render_error_missing_zip() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/notice/error-missing-zip.php' );
$this->render_additional_error_details();
}
/**
* Error http
*
* @since 2.0.1
*/
public function render_error_http() {
require( envato_market()->get_plugin_path() . 'inc/admin/view/notice/error-http.php' );
$this->render_additional_error_details();
}
/**
* Use the Settings API when in network mode.
*
* This allows us to make use of the same WordPress Settings API when displaying the menu item in network mode.
*
* @since 2.0.0
*/
public function save_network_settings() {
check_admin_referer( envato_market()->get_slug() . '-options' );
global $new_whitelist_options;
$options = $new_whitelist_options[ envato_market()->get_slug() ];
foreach ( $options as $option ) {
if ( isset( $_POST[ $option ] ) ) {
update_site_option( $option, $_POST[ $option ] );
} else {
delete_site_option( $option );
}
}
wp_redirect( envato_market()->get_page_url() );
exit;
}
/**
* Store additional error information in transient so users can self debug.
*
* @since 2.0.2
*/
public function store_additional_error_debug_information( $title, $message = '', $data = [] ) {
set_site_transient(
envato_market()->get_option_name() . '_error_information',
[
'title' => $title,
'message' => $message,
'data' => $data,
],
120
);
}
}
endif;
admin/functions.php 0000644 00000040477 14720702445 0010376 0 ustar 00 items()->themes( $group );
if ( empty( $premium ) ) {
return;
}
foreach ( $premium as $slug => $theme ) :
$name = $theme['name'];
$author = $theme['author'];
$version = $theme['version'];
$description = $theme['description'];
$url = $theme['url'];
$author_url = $theme['author_url'];
$theme['hasUpdate'] = false;
if ( 'active' === $group || 'installed' === $group ) {
$get_theme = wp_get_theme( $slug );
if ( $get_theme->exists() ) {
$name = $get_theme->get( 'Name' );
$author = $get_theme->get( 'Author' );
$version = $get_theme->get( 'Version' );
$description = $get_theme->get( 'Description' );
$author_url = $get_theme->get( 'AuthorURI' );
if ( version_compare( $version, $theme['version'], '<' ) ) {
$theme['hasUpdate'] = true;
}
}
}
// Setup the column CSS classes.
$classes = array( 'envato-card', 'theme' );
if ( 'active' === $group ) {
$classes[] = 'active';
}
// Setup the update action links.
$update_actions = array();
if ( true === $theme['hasUpdate'] ) {
$classes[] = 'update';
$classes[] = 'envato-card-' . esc_attr( $slug );
if ( current_user_can( 'update_themes' ) ) {
// Upgrade link.
$upgrade_link = add_query_arg(
array(
'action' => 'upgrade-theme',
'theme' => esc_attr( $slug ),
),
self_admin_url( 'update.php' )
);
$update_actions['update'] = sprintf(
'%6$s ',
wp_nonce_url( $upgrade_link, 'upgrade-theme_' . $slug ),
esc_attr__( 'Update %s now', 'envato-market' ),
esc_attr( $name ),
esc_attr( $slug ),
esc_attr( $theme['version'] ),
esc_html__( 'Update Available', 'envato-market' )
);
$update_actions['details'] = sprintf(
'%3$s ',
esc_url( $url ),
esc_attr( $name ),
sprintf(
__( 'View version %1$s details.', 'envato-market' ),
$theme['version']
)
);
}
}
// Setup the action links.
$actions = array();
if ( 'active' === $group && current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
// Customize theme.
$customize_url = admin_url( 'customize.php' );
$customize_url .= '?theme=' . urlencode( $slug );
$customize_url .= '&return=' . urlencode( envato_market()->get_page_url() . '#themes' );
$actions['customize'] = '' . __( 'Customize', 'envato-market' ) . ' ' . sprintf( __( 'Customize “%s”', 'envato-market' ), $name ) . ' ';
} elseif ( 'installed' === $group ) {
$can_activate = true;
// @codeCoverageIgnoreStart
// Multisite needs special attention.
if ( is_multisite() && ! $get_theme->is_allowed( 'both' ) && current_user_can( 'manage_sites' ) ) {
$can_activate = false;
if ( current_user_can( 'manage_network_themes' ) ) {
$actions['network_enable'] = '' . __( 'Network Enable', 'envato-market' ) . ' ' . sprintf( __( 'Network Enable “%s”', 'envato-market' ), $name ) . ' ';
}
}
// @codeCoverageIgnoreEnd
// Can activate theme.
if ( $can_activate && current_user_can( 'switch_themes' ) ) {
$activate_link = add_query_arg(
array(
'action' => 'activate',
'stylesheet' => urlencode( $slug ),
),
admin_url( 'themes.php' )
);
$activate_link = wp_nonce_url( $activate_link, 'switch-theme_' . $slug );
// Activate link.
$actions['activate'] = '' . __( 'Activate', 'envato-market' ) . ' ' . sprintf( __( 'Activate “%s”', 'envato-market' ), $name ) . ' ';
// Preview theme.
if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
$preview_url = admin_url( 'customize.php' );
$preview_url .= '?theme=' . urlencode( $slug );
$preview_url .= '&return=' . urlencode( envato_market()->get_page_url() . '#themes' );
$actions['customize_preview'] = '' . __( 'Live Preview', 'envato-market' ) . ' ' . sprintf( __( 'Live Preview “%s”', 'envato-market' ), $name ) . ' ';
}
}
} elseif ( 'install' === $group && current_user_can( 'install_themes' ) ) {
// Install link.
$install_link = add_query_arg(
array(
'page' => envato_market()->get_slug(),
'action' => 'install-theme',
'id' => $theme['id'],
),
self_admin_url( 'admin.php' )
);
$actions['install'] = '
' . __( 'Install', 'envato-market' ) . '
' . sprintf( __( 'Install %s', 'envato-market' ), $name ) . '
';
}
if ( 0 === strrpos( html_entity_decode( $author ), '' . esc_html( $author ) . ' ';
}
?>
$count > 0 ? ( $rating / 5 * 100 ) : 0,
'type' => 'percent',
'number' => $count,
)
);
} else {
wp_star_rating(
array(
'rating' => $theme['rating'] > 0 ? ( $theme['rating'] / 5 * 100 ) : 0,
'type' => 'percent',
)
);
}
}
?>
items()->plugins( $group );
if ( empty( $premium ) ) {
return;
}
$plugins = envato_market()->items()->wp_plugins();
foreach ( $premium as $slug => $plugin ) :
$name = $plugin['name'];
$author = $plugin['author'];
$version = $plugin['version'];
$description = $plugin['description'];
$url = $plugin['url'];
$author_url = $plugin['author_url'];
$plugin['hasUpdate'] = false;
// Setup the column CSS classes.
$classes = array( 'envato-card', 'plugin' );
if ( 'active' === $group ) {
$classes[] = 'active';
}
// Setup the update action links.
$update_actions = array();
// Check for an update.
if ( isset( $plugins[ $slug ] ) && version_compare( $plugins[ $slug ]['Version'], $plugin['version'], '<' ) ) {
$plugin['hasUpdate'] = true;
$classes[] = 'update';
$classes[] = 'envato-card-' . sanitize_key( dirname( $slug ) );
if ( current_user_can( 'update_plugins' ) ) {
// Upgrade link.
$upgrade_link = add_query_arg(
array(
'action' => 'upgrade-plugin',
'plugin' => $slug,
),
self_admin_url( 'update.php' )
);
// Details link.
$details_link = add_query_arg(
array(
'action' => 'upgrade-plugin',
'tab' => 'plugin-information',
'plugin' => dirname( $slug ),
'section' => 'changelog',
'TB_iframe' => 'true',
'width' => 640,
'height' => 662,
),
self_admin_url( 'plugin-install.php' )
);
$update_actions['update'] = sprintf(
'%7$s ',
wp_nonce_url( $upgrade_link, 'upgrade-plugin_' . $slug ),
esc_attr__( 'Update %s now', 'envato-market' ),
esc_attr( $name ),
esc_attr( $slug ),
sanitize_key( dirname( $slug ) ),
esc_attr( $version ),
esc_html__( 'Update Available', 'envato-market' )
);
$update_actions['details'] = sprintf(
'%3$s ',
esc_url( $details_link ),
esc_attr( $name ),
sprintf(
__( 'View version %1$s details.', 'envato-market' ),
$version
)
);
}
}
// Setup the action links.
$actions = array();
if ( 'active' === $group ) {
// Deactivate link.
$deactivate_link = add_query_arg(
array(
'action' => 'deactivate',
'plugin' => $slug,
),
self_admin_url( 'plugins.php' )
);
$actions['deactivate'] = '
' . __( 'Deactivate', 'envato-market' ) . '
' . sprintf( __( 'Deactivate %s', 'envato-market' ), $name ) . '
';
} elseif ( 'installed' === $group ) {
if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) {
// Delete link.
$delete_link = add_query_arg(
array(
'action' => 'delete-selected',
'checked[]' => $slug,
),
self_admin_url( 'plugins.php' )
);
$actions['delete'] = '
' . __( 'Delete', 'envato-market' ) . '
' . sprintf( __( 'Delete %s', 'envato-market' ), $name ) . '
';
}
if ( ! is_multisite() && current_user_can( 'activate_plugins' ) ) {
// Activate link.
$activate_link = add_query_arg(
array(
'action' => 'activate',
'plugin' => $slug,
),
self_admin_url( 'plugins.php' )
);
$actions['activate'] = '
' . __( 'Activate', 'envato-market' ) . '
' . sprintf( __( 'Activate %s', 'envato-market' ), $name ) . '
';
}
// @codeCoverageIgnoreStart
// Multisite needs special attention.
if ( is_multisite() ) {
if ( current_user_can( 'manage_network_plugins' ) ) {
$actions['network_activate'] = '
' . __( 'Network Activate', 'envato-market' ) . '
' . sprintf( __( 'Network Activate %s', 'envato-market' ), $name ) . '
';
}
}
// @codeCoverageIgnoreEnd
} elseif ( 'install' === $group && current_user_can( 'install_plugins' ) ) {
// Install link.
$install_link = add_query_arg(
array(
'page' => envato_market()->get_slug(),
'action' => 'install-plugin',
'id' => $plugin['id'],
),
self_admin_url( 'admin.php' )
);
$actions['install'] = '
' . __( 'Install', 'envato-market' ) . '
' . sprintf( __( 'Install %s', 'envato-market' ), $name ) . '
';
}
if ( 0 === strrpos( html_entity_decode( $author ), '' . esc_html( $author ) . ' ';
}
?>
$plugin['rating']['rating'] > 0 ? ( $plugin['rating']['rating'] / 5 * 100 ) : 0,
'type' => 'percent',
'number' => $plugin['rating']['count'],
)
);
} else {
wp_star_rating(
array(
'rating' => $plugin['rating'] > 0 ? ( $plugin['rating'] / 5 * 100 ) : 0,
'type' => 'percent',
)
);
}
}
?>
init_globals();
}
return self::$_instance;
}
/**
* A dummy constructor to prevent this class from being loaded more than once.
*
* @see Envato_Market_API::instance()
*
* @since 1.0.0
* @access private
* @codeCoverageIgnore
*/
private function __construct() {
/* We do nothing here! */
}
/**
* You cannot clone this class.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function __clone() {
_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'envato-market' ), '1.0.0' );
}
/**
* You cannot unserialize instances of this class.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function __wakeup() {
_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'envato-market' ), '1.0.0' );
}
/**
* Setup the class globals.
*
* @since 1.0.0
* @access private
* @codeCoverageIgnore
*/
private function init_globals() {
// Envato API token.
$this->token = envato_market()->get_option( 'token' );
}
/**
* Query the Envato API.
*
* @uses wp_remote_get() To perform an HTTP request.
*
* @since 1.0.0
*
* @param string $url API request URL, including the request method, parameters, & file type.
* @param array $args The arguments passed to `wp_remote_get`.
* @return array|WP_Error The HTTP response.
*/
public function request( $url, $args = array() ) {
$defaults = array(
'sslverify' => !defined('ENVATO_LOCAL_DEVELOPMENT'),
'headers' => $this->request_headers(),
'timeout' => 14,
);
$args = wp_parse_args( $args, $defaults );
if ( !defined('ENVATO_LOCAL_DEVELOPMENT') ) {
$token = trim( str_replace( 'Bearer', '', $args['headers']['Authorization'] ) );
if ( empty( $token ) ) {
return new WP_Error( 'api_token_error', __( 'An API token is required.', 'envato-market' ) );
}
}
$debugging_information = [
'request_url' => $url,
];
// Make an API request.
$response = wp_remote_get( esc_url_raw( $url ), $args );
// Check the response code.
$response_code = wp_remote_retrieve_response_code( $response );
$response_message = wp_remote_retrieve_response_message( $response );
$debugging_information['response_code'] = $response_code;
$debugging_information['response_cf_ray'] = wp_remote_retrieve_header( $response, 'cf-ray' );
$debugging_information['response_server'] = wp_remote_retrieve_header( $response, 'server' );
if ( ! empty( $response->errors ) && isset( $response->errors['http_request_failed'] ) ) {
// API connectivity issue, inject notice into transient with more details.
$option = envato_market()->get_options();
if ( empty( $option['notices'] ) ) {
$option['notices'] = [];
}
$option['notices']['http_error'] = current( $response->errors['http_request_failed'] );
envato_market()->set_options( $option );
return new WP_Error( 'http_error', esc_html( current( $response->errors['http_request_failed'] ) ), $debugging_information );
}
if ( 200 !== $response_code && ! empty( $response_message ) ) {
return new WP_Error( $response_code, $response_message, $debugging_information );
} elseif ( 200 !== $response_code ) {
return new WP_Error( $response_code, __( 'An unknown API error occurred.', 'envato-market' ), $debugging_information );
} else {
$return = json_decode( wp_remote_retrieve_body( $response ), true );
if ( null === $return ) {
return new WP_Error( 'api_error', __( 'An unknown API error occurred.', 'envato-market' ), $debugging_information );
}
return $return;
}
}
/**
* Deferred item download URL.
*
* @since 1.0.0
*
* @param int $id The item ID.
* @return string.
*/
public function deferred_download( $id ) {
if ( empty( $id ) ) {
return '';
}
$args = array(
'deferred_download' => true,
'item_id' => $id,
);
return add_query_arg( $args, esc_url( envato_market()->get_page_url() ) );
}
/**
* Get the item download.
*
* @since 1.0.0
*
* @param int $id The item ID.
* @param array $args The arguments passed to `wp_remote_get`.
* @return bool|array The HTTP response.
*/
public function download( $id, $args = array() ) {
if ( empty( $id ) ) {
return false;
}
$domain = envato_market()->get_envato_api_domain();
$path = $this->api_path_for('download');
$url = $domain . $path . '?item_id=' . $id . '&shorten_url=true';
$response = $this->request( $url, $args );
// @todo Find out which errors could be returned & handle them in the UI.
if ( is_wp_error( $response ) || empty( $response ) || ! empty( $response['error'] ) ) {
return false;
}
if ( ! empty( $response['wordpress_theme'] ) ) {
return $response['wordpress_theme'];
}
if ( ! empty( $response['wordpress_plugin'] ) ) {
return $response['wordpress_plugin'];
}
// Missing a WordPress theme and plugin, report an error.
$option = envato_market()->get_options();
if ( ! isset( $option['notices'] ) ) {
$option['notices'] = [];
}
$option['notices']['missing-package-zip'] = true;
envato_market()->set_options( $option );
return false;
}
/**
* Get an item by ID and type.
*
* @since 1.0.0
*
* @param int $id The item ID.
* @param array $args The arguments passed to `wp_remote_get`.
* @return array The HTTP response.
*/
public function item( $id, $args = array() ) {
$domain = envato_market()->get_envato_api_domain();
$path = $this->api_path_for('catalog-item');
$url = $domain . $path . '?id=' . $id;
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) || empty( $response ) ) {
return false;
}
if ( ! empty( $response['wordpress_theme_metadata'] ) ) {
return $this->normalize_theme( $response );
}
if ( ! empty( $response['wordpress_plugin_metadata'] ) ) {
return $this->normalize_plugin( $response );
}
return false;
}
/**
* Get the list of available themes.
*
* @since 1.0.0
*
* @param array $args The arguments passed to `wp_remote_get`.
* @return array The HTTP response.
*/
public function themes( $args = array() ) {
$themes = array();
$domain = envato_market()->get_envato_api_domain();
$path = $this->api_path_for('list-purchases');
$url = $domain . $path . '?filter_by=wordpress-themes';
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) || empty( $response ) || empty( $response['results'] ) ) {
return $themes;
}
foreach ( $response['results'] as $theme ) {
$themes[] = $this->normalize_theme( $theme['item'] );
}
return $themes;
}
/**
* Normalize a theme.
*
* @since 1.0.0
*
* @param array $theme An array of API request values.
* @return array A normalized array of values.
*/
public function normalize_theme( $theme ) {
$normalized_theme = array(
'id' => $theme['id'],
'name' => ( ! empty( $theme['wordpress_theme_metadata']['theme_name'] ) ? $theme['wordpress_theme_metadata']['theme_name'] : '' ),
'author' => ( ! empty( $theme['wordpress_theme_metadata']['author_name'] ) ? $theme['wordpress_theme_metadata']['author_name'] : '' ),
'version' => ( ! empty( $theme['wordpress_theme_metadata']['version'] ) ? $theme['wordpress_theme_metadata']['version'] : '' ),
'description' => self::remove_non_unicode( strip_tags( $theme['wordpress_theme_metadata']['description'] ) ),
'url' => ( ! empty( $theme['url'] ) ? $theme['url'] : '' ),
'author_url' => ( ! empty( $theme['author_url'] ) ? $theme['author_url'] : '' ),
'thumbnail_url' => ( ! empty( $theme['thumbnail_url'] ) ? $theme['thumbnail_url'] : '' ),
'rating' => ( ! empty( $theme['rating'] ) ? $theme['rating'] : '' ),
'landscape_url' => '',
);
// No main thumbnail in API response, so we grab it from the preview array.
if ( empty( $normalized_theme['thumbnail_url'] ) && ! empty( $theme['previews'] ) && is_array( $theme['previews'] ) ) {
foreach ( $theme['previews'] as $possible_preview ) {
if ( ! empty( $possible_preview['landscape_url'] ) ) {
$normalized_theme['landscape_url'] = $possible_preview['landscape_url'];
break;
}
}
}
if ( empty( $normalized_theme['thumbnail_url'] ) && ! empty( $theme['previews'] ) && is_array( $theme['previews'] ) ) {
foreach ( $theme['previews'] as $possible_preview ) {
if ( ! empty( $possible_preview['icon_url'] ) ) {
$normalized_theme['thumbnail_url'] = $possible_preview['icon_url'];
break;
}
}
}
return $normalized_theme;
}
/**
* Get the list of available plugins.
*
* @since 1.0.0
*
* @param array $args The arguments passed to `wp_remote_get`.
* @return array The HTTP response.
*/
public function plugins( $args = array() ) {
$plugins = array();
$domain = envato_market()->get_envato_api_domain();
$path = $this->api_path_for('list-purchases');
$url = $domain . $path . '?filter_by=wordpress-plugins';
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) || empty( $response ) || empty( $response['results'] ) ) {
return $plugins;
}
foreach ( $response['results'] as $plugin ) {
$plugins[] = $this->normalize_plugin( $plugin['item'] );
}
return $plugins;
}
/**
* Normalize a plugin.
*
* @since 1.0.0
*
* @param array $plugin An array of API request values.
* @return array A normalized array of values.
*/
public function normalize_plugin( $plugin ) {
$requires = null;
$tested = null;
$versions = array();
// Set the required and tested WordPress version numbers.
foreach ( $plugin['attributes'] as $k => $v ) {
if ( ! empty( $v['name'] ) && 'compatible-software' === $v['name'] && ! empty( $v['value'] ) && is_array( $v['value'] ) ) {
foreach ( $v['value'] as $version ) {
$versions[] = str_replace( 'WordPress ', '', trim( $version ) );
}
if ( ! empty( $versions ) ) {
$requires = $versions[ count( $versions ) - 1 ];
$tested = $versions[0];
}
break;
}
}
$plugin_normalized = array(
'id' => $plugin['id'],
'name' => ( ! empty( $plugin['wordpress_plugin_metadata']['plugin_name'] ) ? $plugin['wordpress_plugin_metadata']['plugin_name'] : '' ),
'author' => ( ! empty( $plugin['wordpress_plugin_metadata']['author'] ) ? $plugin['wordpress_plugin_metadata']['author'] : '' ),
'version' => ( ! empty( $plugin['wordpress_plugin_metadata']['version'] ) ? $plugin['wordpress_plugin_metadata']['version'] : '' ),
'description' => self::remove_non_unicode( strip_tags( $plugin['wordpress_plugin_metadata']['description'] ) ),
'url' => ( ! empty( $plugin['url'] ) ? $plugin['url'] : '' ),
'author_url' => ( ! empty( $plugin['author_url'] ) ? $plugin['author_url'] : '' ),
'thumbnail_url' => ( ! empty( $plugin['thumbnail_url'] ) ? $plugin['thumbnail_url'] : '' ),
'landscape_url' => ( ! empty( $plugin['previews']['landscape_preview']['landscape_url'] ) ? $plugin['previews']['landscape_preview']['landscape_url'] : '' ),
'requires' => $requires,
'tested' => $tested,
'number_of_sales' => ( ! empty( $plugin['number_of_sales'] ) ? $plugin['number_of_sales'] : '' ),
'updated_at' => ( ! empty( $plugin['updated_at'] ) ? $plugin['updated_at'] : '' ),
'rating' => ( ! empty( $plugin['rating'] ) ? $plugin['rating'] : '' ),
);
// No main thumbnail in API response, so we grab it from the preview array.
if ( empty( $plugin_normalized['landscape_url'] ) && ! empty( $plugin['previews'] ) && is_array( $plugin['previews'] ) ) {
foreach ( $plugin['previews'] as $possible_preview ) {
if ( ! empty( $possible_preview['landscape_url'] ) ) {
$plugin_normalized['landscape_url'] = $possible_preview['landscape_url'];
break;
}
}
}
if ( empty( $plugin_normalized['thumbnail_url'] ) && ! empty( $plugin['previews'] ) && is_array( $plugin['previews'] ) ) {
foreach ( $plugin['previews'] as $possible_preview ) {
if ( ! empty( $possible_preview['icon_url'] ) ) {
$plugin_normalized['thumbnail_url'] = $possible_preview['icon_url'];
break;
}
}
}
return $plugin_normalized;
}
public function api_path_for( $path ) {
if ( defined('ENVATO_LOCAL_DEVELOPMENT') ) {
$paths = MONOLITH_API_PATHS;
} else {
$paths = array(
'download' => '/v2/market/buyer/download',
'catalog-item' => '/v2/market/catalog/item',
'list-purchases' => '/v2/market/buyer/list-purchases',
'total-items' => '/v1/market/total-items.json'
);
}
return $paths[$path];
}
/**
* Remove all non unicode characters in a string
*
* @since 1.0.0
*
* @param string $retval The string to fix.
* @return string
*/
static private function remove_non_unicode( $retval ) {
return preg_replace( '/[\x00-\x1F\x80-\xFF]/', '', $retval );
}
private function request_headers() {
$user_agent = array('User-Agent' => 'WordPress - Envato Market ' . envato_market()->get_version());
$headers = array_merge($user_agent, envato_market()->get_envato_api_headers());
return $headers;
}
}
endif;
patterns/page-sidebar-poster.php 0000644 00000006543 14720703302 0012760 0 ustar 00 __( 'Poster with right sidebar', 'twentytwentytwo' ),
'categories' => array( 'twentytwentytwo_pages' ),
'content' => '
' . wp_kses_post( __( 'Flutter , a collection of bird-related ephemera', 'twentytwentytwo' ) ) . '
' . esc_html__( 'Date', 'twentytwentytwo' ) . '
' . esc_html__( 'February, 12 2021', 'twentytwentytwo' ) . '
' . esc_html__( 'Location', 'twentytwentytwo' ) . '
' . wp_kses_post( __( 'The Grand Theater 154 Eastern Avenue Maryland NY, 12345', 'twentytwentytwo' ) ) . '
',
);
patterns/header-centered-logo-black-background.php 0000644 00000002463 14720703302 0016264 0 ustar 00 __( 'Header with centered logo and background', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/footer-query-title-citation.php 0000644 00000004200 14720703302 0014477 0 ustar 00 __( 'Footer with query, title, and citation', 'twentytwentytwo' ),
'categories' => array( 'footer' ),
'blockTypes' => array( 'core/template-part/footer' ),
'content' => '
' .
sprintf(
/* Translators: WordPress link. */
esc_html__( 'Proudly powered by %s', 'twentytwentytwo' ),
'WordPress '
) . '
',
);
patterns/footer-navigation-copyright.php 0000644 00000002327 14720703302 0014560 0 ustar 00 __( 'Footer with navigation and copyright', 'twentytwentytwo' ),
'categories' => array( 'footer' ),
'blockTypes' => array( 'core/template-part/footer' ),
'content' => '
' . esc_html__( '© Site Title', 'twentytwentytwo' ) . '
',
);
patterns/header-logo-navigation-offset-tagline.php 0000644 00000003333 14720703302 0016345 0 ustar 00 __( 'Logo, navigation, and offset tagline Header', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/page-sidebar-blog-posts-right.php 0000644 00000012123 14720703302 0014637 0 ustar 00 __( 'Blog posts with right sidebar', 'twentytwentytwo' ),
'categories' => array( 'twentytwentytwo_pages' ),
'content' => '
' . esc_html__( 'Categories', 'twentytwentytwo' ) . '
' . esc_html__( 'Tags', 'twentytwentytwo' ) . '
',
);
patterns/header-stacked.php 0000644 00000002721 14720703302 0011761 0 ustar 00 __( 'Logo and navigation header', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/header-default.php 0000644 00000002401 14720703302 0011762 0 ustar 00 __( 'Default header', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/general-list-events.php 0000644 00000017625 14720703302 0013016 0 ustar 00 __( 'List of events', 'twentytwentytwo' ),
'categories' => array( 'featured', 'text' ),
'content' => '
' . esc_html__( 'Speaker Series', 'twentytwentytwo' ) . '
' . esc_html__( 'May 14th, 2022, 6 PM', 'twentytwentytwo' ) . '
' . esc_html__( 'Jesús Rodriguez', 'twentytwentytwo' ) . '
' . wp_kses_post( __( 'The Vintagé Theater 245 Arden Rd. Gardenville, NH', 'twentytwentytwo' ) ) . '
' . esc_html__( 'May 16th, 2022, 6 PM', 'twentytwentytwo' ) . '
' . esc_html__( 'Doug Stilton', 'twentytwentytwo' ) . '
' . wp_kses_post( __( 'The Swell Theater 120 River Rd. Rainfall, NH', 'twentytwentytwo' ) ) . '
' . esc_html__( 'May 18th, 2022, 7 PM', 'twentytwentytwo' ) . '
' . esc_html__( 'Amy Jensen', 'twentytwentytwo' ) . '
' . wp_kses_post( __( 'The Vintagé Theater 245 Arden Rd. Gardenville, NH', 'twentytwentytwo' ) ) . '
' . esc_html__( 'May 20th, 2022, 6 PM', 'twentytwentytwo' ) . '
' . esc_html__( 'Emery Driscoll', 'twentytwentytwo' ) . '
' . wp_kses_post( __( 'The Swell Theater 120 River Rd. Rainfall, NH', 'twentytwentytwo' ) ) . '
',
);
patterns/query-grid.php 0000644 00000002556 14720703302 0011213 0 ustar 00 __( 'Grid of posts', 'twentytwentytwo' ),
'categories' => array( 'query' ),
'blockTypes' => array( 'core/query' ),
'content' => '
',
);
patterns/page-layout-two-columns.php 0000644 00000007667 14720703302 0013647 0 ustar 00 __( 'Page layout with two columns', 'twentytwentytwo' ),
'categories' => array( 'twentytwentytwo_pages' ),
'content' => '
' . wp_kses_post( __( 'Goldfinch & Sparrow ', 'twentytwentytwo' ) ) . '
' . esc_html__( 'WELCOME', 'twentytwentytwo' ) . '
' . wp_kses_post( __( 'Oh hello. My name’s Angelo, and I operate this blog. I was born in Portland, but I currently live in upstate New York. You may recognize me from publications with names like Eagle Beagle and Mourning Dive . I write for a living. I usually use this blog to catalog extensive lists of birds and other things that I find interesting. If you find an error with one of my lists, please keep it to yourself. If that’s not your cup of tea, I definitely recommend this tea . It’s my favorite.', 'twentytwentytwo' ) ) . '
' . esc_html__( 'POSTS', 'twentytwentytwo' ) . '
',
);
patterns/query-simple-blog.php 0000644 00000003534 14720703302 0012475 0 ustar 00 __( 'Simple blog posts', 'twentytwentytwo' ),
'categories' => array( 'query' ),
'blockTypes' => array( 'core/query' ),
'content' => '
',
);
patterns/header-centered-title-navigation-social.php 0000644 00000004267 14720703302 0016667 0 ustar 00 __( 'Centered header with navigation, social links, and background', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/query-irregular-grid.php 0000644 00000020546 14720703302 0013204 0 ustar 00 __( 'Irregular grid of posts', 'twentytwentytwo' ),
'categories' => array( 'query' ),
'blockTypes' => array( 'core/query' ),
'content' => '
',
);
patterns/header-text-only-green-background.php 0000644 00000003116 14720703302 0015520 0 ustar 00 __( 'Text-only header with background', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/hidden-404.php 0000644 00000001741 14720703302 0010656 0 ustar 00 __( '404 content', 'twentytwentytwo' ),
'inserter' => false,
'content' => '
' . esc_html( _x( '404', 'Error code for a webpage that is not found.', 'twentytwentytwo' ) ) . '
' . esc_html__( 'This page could not be found. Maybe try a search?', 'twentytwentytwo' ) . '
',
);
patterns/page-about-media-right.php 0000644 00000005551 14720703302 0013335 0 ustar 00 __( 'About page with media on the right', 'twentytwentytwo' ),
'categories' => array( 'twentytwentytwo_pages' ),
'content' => '
' . wp_kses_post( __( 'Emery Driscoll', 'twentytwentytwo' ) ) . '
' . esc_html__( 'Oh hello. My name’s Emery, and you’ve found your way to my website. I’m an avid bird watcher, and I also broadcast my own radio show on Tuesday evenings at 11PM EDT.', 'twentytwentytwo' ) . '
',
);
patterns/page-about-links-dark.php 0000644 00000007131 14720703302 0013176 0 ustar 00 __( 'About page links (dark)', 'twentytwentytwo' ),
'categories' => array( 'twentytwentytwo_pages', 'buttons' ),
'content' => '
' . esc_html__( 'A trouble of hummingbirds', 'twentytwentytwo' ) . '
',
);
patterns/general-subscribe.php 0000644 00000002715 14720703302 0012514 0 ustar 00 __( 'Subscribe callout', 'twentytwentytwo' ),
'categories' => array( 'featured', 'buttons' ),
'content' => '
' . wp_kses_post( __( 'Watch birds from your inbox', 'twentytwentytwo' ) ) . '
',
);
patterns/general-wide-image-intro-buttons.php 0000644 00000004625 14720703302 0015372 0 ustar 00 __( 'Wide image with introduction and buttons', 'twentytwentytwo' ),
'categories' => array( 'featured', 'columns' ),
'content' => '
' . wp_kses_post( __( 'Welcome to the Aviary', 'twentytwentytwo' ) ) . '
' . esc_html__( 'A film about hobbyist bird watchers, a catalog of different birds, paired with the noises they make. Each bird is listed by their scientific name so things seem more official.', 'twentytwentytwo' ) . '
',
);
patterns/header-text-only-salmon-background.php 0000644 00000002645 14720703302 0015717 0 ustar 00 __( 'Text-only header with background', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/header-centered-logo.php 0000644 00000003505 14720703302 0013073 0 ustar 00 __( 'Header with centered logo', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/footer-social-copyright.php 0000644 00000003034 14720703302 0013667 0 ustar 00 __( 'Footer with social links and copyright', 'twentytwentytwo' ),
'categories' => array( 'footer' ),
'blockTypes' => array( 'core/template-part/footer' ),
'content' => '
' . esc_html__( '© Site Title', 'twentytwentytwo' ) . '
',
);
patterns/footer-title-tagline-social.php 0000644 00000003427 14720703302 0014427 0 ustar 00 __( 'Footer with title, tagline, and social links on a dark background', 'twentytwentytwo' ),
'categories' => array( 'footer' ),
'blockTypes' => array( 'core/template-part/footer' ),
'content' => '
',
);
patterns/page-sidebar-grid-posts.php 0000644 00000010137 14720703302 0013531 0 ustar 00 __( 'Grid of posts with left sidebar', 'twentytwentytwo' ),
'categories' => array( 'twentytwentytwo_pages' ),
'content' => '
',
);
patterns/query-image-grid.php 0000644 00000003573 14720703302 0012273 0 ustar 00 __( 'Grid of image posts', 'twentytwentytwo' ),
'categories' => array( 'query' ),
'blockTypes' => array( 'core/query' ),
'content' => '
',
);
patterns/header-large-dark.php 0000644 00000005367 14720703302 0012365 0 ustar 00 __( 'Large header with dark background', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
' . wp_kses_post( __( 'The Hatchery : a blog about my adventures in bird watching', 'twentytwentytwo' ) ) . '
',
);
patterns/header-image-background.php 0000644 00000004562 14720703302 0013547 0 ustar 00 __( 'Header with image background', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/header-logo-navigation-gray-background.php 0000644 00000002630 14720703302 0016514 0 ustar 00 __( 'Logo and navigation header with background', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/page-about-simple-dark.php 0000644 00000006417 14720703302 0013355 0 ustar 00 __( 'Simple dark about page', 'twentytwentytwo' ),
'categories' => array( 'twentytwentytwo_pages' ),
'content' => '
' . wp_kses_post( __( 'Jesús Rodriguez', 'twentytwentytwo' ) ) . '
' . esc_html__( 'Oh hello. My name’s Jesús, and you’ve found your way to my website. I’m an avid bird watcher, and I also broadcast my own radio show on Tuesday evenings at 11PM EDT.', 'twentytwentytwo' ) . '
',
);
patterns/general-featured-posts.php 0000644 00000002162 14720703302 0013474 0 ustar 00 __( 'Featured posts', 'twentytwentytwo' ),
'categories' => array( 'featured', 'query' ),
'content' => '
' . esc_html__( 'Latest posts', 'twentytwentytwo' ) . '
',
);
patterns/header-image-background-overlay.php 0000644 00000004514 14720703302 0015223 0 ustar 00 __( 'Header with image background and overlay', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/footer-logo.php 0000644 00000002035 14720703302 0011347 0 ustar 00 __( 'Footer with logo and citation', 'twentytwentytwo' ),
'categories' => array( 'footer' ),
'blockTypes' => array( 'core/template-part/footer' ),
'content' => '
' .
sprintf(
/* Translators: WordPress link. */
esc_html__( 'Proudly powered by %s', 'twentytwentytwo' ),
'WordPress '
) . '
',
);
patterns/header-title-and-button.php 0000644 00000002300 14720703302 0013526 0 ustar 00 __( 'Title and button header', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/page-about-links.php 0000644 00000010344 14720703302 0012257 0 ustar 00 __( 'About page links', 'twentytwentytwo' ),
'categories' => array( 'twentytwentytwo_pages', 'buttons' ),
'content' => '
' . esc_html__( 'Swoop', 'twentytwentytwo' ) . '
' . esc_html__( 'A podcast about birds', 'twentytwentytwo' ) . '
',
);
patterns/general-layered-images-with-duotone.php 0000644 00000002764 14720703302 0016053 0 ustar 00 __( 'Layered images with duotone', 'twentytwentytwo' ),
'categories' => array( 'featured', 'gallery' ),
'content' => '
',
);
patterns/footer-default.php 0000644 00000002004 14720703302 0012027 0 ustar 00 __( 'Default footer', 'twentytwentytwo' ),
'categories' => array( 'footer' ),
'blockTypes' => array( 'core/template-part/footer' ),
'content' => '
' .
sprintf(
/* Translators: WordPress link. */
esc_html__( 'Proudly powered by %s', 'twentytwentytwo' ),
'WordPress '
) . '
',
);
patterns/header-small-dark.php 0000644 00000004501 14720703302 0012370 0 ustar 00 __( 'Small header with dark background', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/footer-blog.php 0000644 00000005306 14720703302 0011336 0 ustar 00 __( 'Blog footer', 'twentytwentytwo' ),
'categories' => array( 'footer' ),
'blockTypes' => array( 'core/template-part/footer' ),
'content' => '
' . esc_html__( 'About us', 'twentytwentytwo' ) . '
' . esc_html__( 'We are a rogue collective of bird watchers. We’ve been known to sneak through fences, climb perimeter walls, and generally trespass in order to observe the rarest of birds.', 'twentytwentytwo' ) . '
' . esc_html__( 'Latest posts', 'twentytwentytwo' ) . '
' . esc_html__( 'Categories', 'twentytwentytwo' ) . '
' .
sprintf(
/* Translators: WordPress link. */
esc_html__( 'Proudly powered by %s', 'twentytwentytwo' ),
'WordPress '
) . '
',
);
patterns/general-divider-light.php 0000644 00000001622 14720703302 0013262 0 ustar 00 __( 'Divider with image and color (light)', 'twentytwentytwo' ),
'categories' => array( 'featured' ),
'content' => '
',
);
patterns/footer-query-images-title-citation.php 0000644 00000004444 14720703302 0015754 0 ustar 00 __( 'Footer with query, featured images, title, and citation', 'twentytwentytwo' ),
'categories' => array( 'footer' ),
'blockTypes' => array( 'core/template-part/footer' ),
'content' => '
' .
sprintf(
/* Translators: WordPress link. */
esc_html__( 'Proudly powered by %s', 'twentytwentytwo' ),
'WordPress '
) . '
',
);
patterns/general-video-header-details.php 0000644 00000005272 14720703302 0014513 0 ustar 00 __( 'Video with header and details', 'twentytwentytwo' ),
'categories' => array( 'featured', 'columns' ),
'content' => '
' . wp_kses_post( __( 'Warble , a film about hobbyist bird watchers.', 'twentytwentytwo' ) ) . '
' . esc_html__( 'Featuring', 'twentytwentytwo' ) . '
' . wp_kses_post( __( 'Jesús Rodriguez Doug Stilton Emery Driscoll Megan Perry Rowan Price', 'twentytwentytwo' ) ) . '
' . wp_kses_post( __( 'Angelo Tso Edward Stilton Amy Jensen Boston Bell Shay Ford', 'twentytwentytwo' ) ) . '
',
);
patterns/page-about-media-left.php 0000644 00000005735 14720703302 0013156 0 ustar 00 __( 'About page with media on the left', 'twentytwentytwo' ),
'categories' => array( 'twentytwentytwo_pages' ),
'content' => '
' . esc_html__( 'Doug', 'twentytwentytwo' ) . ' ' . esc_html__( 'Stilton', 'twentytwentytwo' ) . '
' . esc_html__( 'Oh hello. My name’s Doug, and you’ve found your way to my website. I’m an avid bird watcher, and I also broadcast my own radio show on Tuesday evenings at 11PM EDT.', 'twentytwentytwo' ) . '
',
);
patterns/footer-dark.php 0000644 00000002645 14720703302 0011337 0 ustar 00 __( 'Dark footer with title and citation', 'twentytwentytwo' ),
'categories' => array( 'footer' ),
'blockTypes' => array( 'core/template-part/footer' ),
'content' => '
' .
sprintf(
/* Translators: WordPress link. */
esc_html__( 'Proudly powered by %s', 'twentytwentytwo' ),
'WordPress '
) . '
',
);
patterns/header-logo-navigation-social-black-background.php 0000644 00000003623 14720703302 0020101 0 ustar 00 __( 'Logo, navigation, and social links header with background', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/general-video-trailer.php 0000644 00000003227 14720703302 0013300 0 ustar 00 __( 'Video trailer', 'twentytwentytwo' ),
'categories' => array( 'featured', 'columns' ),
'content' => '
' . esc_html__( 'Extended Trailer', 'twentytwentytwo' ) . '
' . esc_html__( 'A film about hobbyist bird watchers, a catalog of different birds, paired with the noises they make. Each bird is listed by their scientific name so things seem more official.', 'twentytwentytwo' ) . '
',
);
patterns/query-text-grid.php 0000644 00000002456 14720703302 0012174 0 ustar 00 __( 'Text-based grid of posts', 'twentytwentytwo' ),
'categories' => array( 'query' ),
'blockTypes' => array( 'core/query' ),
'content' => '
',
);
patterns/hidden-heading-and-bird.php 0000644 00000002620 14720703302 0013421 0 ustar 00 __( 'Heading and bird image', 'twentytwentytwo' ),
'inserter' => false,
'content' => '
' . wp_kses_post( __( 'The Hatchery : a blog about my adventures in bird watching', 'twentytwentytwo' ) ) . '
',
);
patterns/hidden-bird.php 0000644 00000001242 14720703302 0011263 0 ustar 00 __( 'Heading and bird image', 'twentytwentytwo' ),
'inserter' => false,
'content' => '
',
);
patterns/general-image-with-caption.php 0000644 00000003106 14720703302 0014214 0 ustar 00 __( 'Image with caption', 'twentytwentytwo' ),
'categories' => array( 'featured', 'columns', 'gallery' ),
'content' => '
' . esc_html__( 'Hummingbird', 'twentytwentytwo' ) . '
' . esc_html__( 'A beautiful bird featuring a surprising set of color feathers.', 'twentytwentytwo' ) . '
',
);
patterns/page-layout-image-text-and-video.php 0000644 00000007650 14720703302 0015260 0 ustar 00 __( 'Page layout with image, text and video', 'twentytwentytwo' ),
'categories' => array( 'twentytwentytwo_pages' ),
'content' => '
' . wp_kses_post( __( 'Warble , a film about hobbyist bird watchers.', 'twentytwentytwo' ) ) . '
' . esc_html__( 'Screening', 'twentytwentytwo' ) . '
' . wp_kses_post( __( 'May 14th, 2022 @ 7:00PM The Vintagé Theater, 245 Arden Rd. Gardenville, NH', 'twentytwentytwo' ) ) . '
' . esc_html__( 'Extended Trailer', 'twentytwentytwo' ) . '
' . esc_html__( 'Oh hello. My name’s Angelo, and you’ve found your way to my blog. I write about a range of topics, but lately I’ve been sharing my hopes for next year.', 'twentytwentytwo' ) . '
',
);
patterns/query-default.php 0000644 00000004425 14720703302 0011707 0 ustar 00 __( 'Default posts', 'twentytwentytwo' ),
'categories' => array( 'query' ),
'blockTypes' => array( 'core/query' ),
'content' => '
',
);
patterns/header-title-navigation-social.php 0000644 00000003031 14720703302 0015064 0 ustar 00 __( 'Title, navigation, and social links header', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/page-sidebar-blog-posts.php 0000644 00000010704 14720703302 0013527 0 ustar 00 __( 'Blog posts with left sidebar', 'twentytwentytwo' ),
'categories' => array( 'twentytwentytwo_pages' ),
'content' => '
',
);
patterns/query-large-titles.php 0000644 00000002517 14720703302 0012657 0 ustar 00 __( 'Large post titles', 'twentytwentytwo' ),
'categories' => array( 'query' ),
'blockTypes' => array( 'core/query' ),
'content' => '
',
);
patterns/general-pricing-table.php 0000644 00000011754 14720703302 0013256 0 ustar 00 __( 'Pricing table', 'twentytwentytwo' ),
'categories' => array( 'featured', 'columns', 'buttons' ),
'content' => '
' . esc_html( _x( '1', 'First item in a numbered list.', 'twentytwentytwo' ) ) . '
' . esc_html__( 'Pigeon', 'twentytwentytwo' ) . '
' . esc_html__( 'Help support our growing community by joining at the Pigeon level. Your support will help pay our writers, and you’ll get access to our exclusive newsletter.', 'twentytwentytwo' ) . '
' . esc_html( _x( '2', 'Second item in a numbered list.', 'twentytwentytwo' ) ) . '
' . esc_html__( 'Sparrow', 'twentytwentytwo' ) . '
' . esc_html__( 'Join at the Sparrow level and become a member of our flock! You’ll receive our newsletter, plus a bird pin that you can wear with pride when you’re out in nature.', 'twentytwentytwo' ) . '
' . esc_html( _x( '3', 'Third item in a numbered list.', 'twentytwentytwo' ) ) . '
' . esc_html__( 'Falcon', 'twentytwentytwo' ) . '
' . esc_html__( 'Play a leading role for our community by joining at the Falcon level. This level earns you a seat on our board, where you can help plan future birdwatching expeditions.', 'twentytwentytwo' ) . '
',
);
patterns/header-text-only-with-tagline-black-background.php 0000644 00000003335 14720703302 0020071 0 ustar 00 __( 'Text-only header with tagline and background', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/footer-about-title-logo.php 0000644 00000003433 14720703302 0013601 0 ustar 00 __( 'Footer with text, title, and logo', 'twentytwentytwo' ),
'categories' => array( 'footer' ),
'blockTypes' => array( 'core/template-part/footer' ),
'content' => '
' . esc_html__( 'About us', 'twentytwentytwo' ) . '
' . esc_html__( 'We are a rogue collective of bird watchers. We’ve been known to sneak through fences, climb perimeter walls, and generally trespass in order to observe the rarest of birds.', 'twentytwentytwo' ) . '
',
);
patterns/general-large-list-names.php 0000644 00000004573 14720703302 0013703 0 ustar 00 __( 'Large list of names', 'twentytwentytwo' ),
'categories' => array( 'featured', 'text' ),
'content' => '
' . esc_html__( 'Jesús Rodriguez, Doug Stilton, Emery Driscoll, Megan Perry, Rowan Price, Angelo Tso, Edward Stilton, Amy Jensen, Boston Bell, Shay Ford, Lee Cunningham, Evelynn Ray, Landen Reese, Ewan Hart, Jenna Chan, Phoenix Murray, Mel Saunders, Aldo Davidson, Zain Hall.', 'twentytwentytwo' ) . '
',
);
patterns/header-with-tagline.php 0000644 00000003063 14720703302 0012737 0 ustar 00 __( 'Header with tagline', 'twentytwentytwo' ),
'categories' => array( 'header' ),
'blockTypes' => array( 'core/template-part/header' ),
'content' => '
',
);
patterns/footer-navigation.php 0000644 00000002250 14720703302 0012545 0 ustar 00 __( 'Footer with navigation and citation', 'twentytwentytwo' ),
'categories' => array( 'footer' ),
'blockTypes' => array( 'core/template-part/footer' ),
'content' => '
' .
sprintf(
/* Translators: WordPress link. */
esc_html__( 'Proudly powered by %s', 'twentytwentytwo' ),
'WordPress '
) . '
',
);
patterns/general-divider-dark.php 0000644 00000001614 14720703302 0013075 0 ustar 00 __( 'Divider with image and color (dark)', 'twentytwentytwo' ),
'categories' => array( 'featured' ),
'content' => '
',
);
patterns/page-about-solid-color.php 0000644 00000005340 14720703302 0013365 0 ustar 00 __( 'About page on solid color background', 'twentytwentytwo' ),
'categories' => array( 'twentytwentytwo_pages' ),
'content' => '
' . wp_kses_post( __( 'Edvard Smith', 'twentytwentytwo' ) ) . '
' . esc_html__( 'Oh hello. My name’s Edvard, and you’ve found your way to my website. I’m an avid bird watcher, and I also broadcast my own radio show every Tuesday evening at 11PM EDT. Listen in sometime!', 'twentytwentytwo' ) . '
',
);
patterns/page-layout-image-and-text.php 0000644 00000005366 14720703302 0014156 0 ustar 00 __( 'Page layout with image and text', 'twentytwentytwo' ),
'categories' => array( 'twentytwentytwo_pages' ),
'content' => '
' . wp_kses_post( __( 'Watching Birds in the Garden ', 'twentytwentytwo' ) ) . '
' . wp_kses_post( __( 'Oh hello. My name’s Angelo, and I operate this blog. I was born in Portland, but I currently live in upstate New York. You may recognize me from publications with names like Eagle Beagle and Mourning Dive . I write for a living. I usually use this blog to catalog extensive lists of birds and other things that I find interesting. If you find an error with one of my lists, please keep it to yourself. If that’s not your cup of tea, I definitely recommend this tea . It’s my favorite.', 'twentytwentytwo' ) ) . '
',
);
patterns/general-two-images-text.php 0000644 00000005275 14720703302 0013575 0 ustar 00 __( 'Two images with text', 'twentytwentytwo' ),
'categories' => array( 'featured', 'columns', 'gallery' ),
'content' => '
' . esc_html__( 'SCREENING', 'twentytwentytwo' ) . '
' . wp_kses_post( __( 'May 14th, 2022 @ 7:00PM The Vintagé Theater, 245 Arden Rd. Gardenville, NH', 'twentytwentytwo' ) ) . '
',
);
patterns/page-about-large-image-and-buttons.php 0000644 00000010461 14720703302 0015545 0 ustar 00 __( 'About page with large image and buttons', 'twentytwentytwo' ),
'categories' => array( 'twentytwentytwo_pages', 'buttons' ),
'content' => '
',
);