基础代码
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
"plugin:@wordpress/eslint-plugin/esnext"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"browser": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
"stylelint-config-wordpress/scss"
|
||||||
|
],
|
||||||
|
"ignoreFiles": [
|
||||||
|
"sass/_normalize.scss"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"font-family-no-missing-generic-family-keyword": null,
|
||||||
|
"no-descending-specificity": null,
|
||||||
|
"block-no-empty": null,
|
||||||
|
"no-duplicate-selectors": null,
|
||||||
|
"font-family-no-duplicate-names": null,
|
||||||
|
"selector-class-pattern": null
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The template for displaying 404 pages (not found)
|
||||||
|
*
|
||||||
|
* @link https://codex.wordpress.org/Creating_an_Error_404_Page
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
get_header();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<main id="primary" class="site-main">
|
||||||
|
|
||||||
|
<section class="error-404 not-found">
|
||||||
|
<header class="page-header">
|
||||||
|
<h1 class="page-title"><?php esc_html_e( 'Oops! That page can’t be found.', 'cyywordpress' ); ?></h1>
|
||||||
|
</header><!-- .page-header -->
|
||||||
|
|
||||||
|
<div class="page-content">
|
||||||
|
<p><?php esc_html_e( 'It looks like nothing was found at this location. Maybe try one of the links below or a search?', 'cyywordpress' ); ?></p>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
get_search_form();
|
||||||
|
|
||||||
|
the_widget( 'WP_Widget_Recent_Posts' );
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="widget widget_categories">
|
||||||
|
<h2 class="widget-title"><?php esc_html_e( 'Most Used Categories', 'cyywordpress' ); ?></h2>
|
||||||
|
<ul>
|
||||||
|
<?php
|
||||||
|
wp_list_categories(
|
||||||
|
array(
|
||||||
|
'orderby' => 'count',
|
||||||
|
'order' => 'DESC',
|
||||||
|
'show_count' => 1,
|
||||||
|
'title_li' => '',
|
||||||
|
'number' => 10,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</ul>
|
||||||
|
</div><!-- .widget -->
|
||||||
|
|
||||||
|
<?php
|
||||||
|
/* translators: %1$s: smiley */
|
||||||
|
$cyywordpress_archive_content = '<p>' . sprintf( esc_html__( 'Try looking in the monthly archives. %1$s', 'cyywordpress' ), convert_smilies( ':)' ) ) . '</p>';
|
||||||
|
the_widget( 'WP_Widget_Archives', 'dropdown=1', "after_title=</h2>$cyywordpress_archive_content" );
|
||||||
|
|
||||||
|
the_widget( 'WP_Widget_Tag_Cloud' );
|
||||||
|
?>
|
||||||
|
|
||||||
|
</div><!-- .page-content -->
|
||||||
|
</section><!-- .error-404 -->
|
||||||
|
|
||||||
|
</main><!-- #main -->
|
||||||
|
|
||||||
|
<?php
|
||||||
|
get_footer();
|
||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The template for displaying archive pages
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
get_header();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<main id="primary" class="site-main">
|
||||||
|
|
||||||
|
<?php if ( have_posts() ) : ?>
|
||||||
|
|
||||||
|
<header class="page-header">
|
||||||
|
<?php
|
||||||
|
the_archive_title( '<h1 class="page-title">', '</h1>' );
|
||||||
|
the_archive_description( '<div class="archive-description">', '</div>' );
|
||||||
|
?>
|
||||||
|
</header><!-- .page-header -->
|
||||||
|
|
||||||
|
<?php
|
||||||
|
/* Start the Loop */
|
||||||
|
while ( have_posts() ) :
|
||||||
|
the_post();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Include the Post-Type-specific template for the content.
|
||||||
|
* If you want to override this in a child theme, then include a file
|
||||||
|
* called content-___.php (where ___ is the Post Type name) and that will be used instead.
|
||||||
|
*/
|
||||||
|
get_template_part( 'template-parts/content', get_post_type() );
|
||||||
|
|
||||||
|
endwhile;
|
||||||
|
|
||||||
|
the_posts_navigation();
|
||||||
|
|
||||||
|
else :
|
||||||
|
|
||||||
|
get_template_part( 'template-parts/content', 'none' );
|
||||||
|
|
||||||
|
endif;
|
||||||
|
?>
|
||||||
|
|
||||||
|
</main><!-- #main -->
|
||||||
|
|
||||||
|
<?php
|
||||||
|
get_sidebar();
|
||||||
|
get_footer();
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The template for displaying comments
|
||||||
|
*
|
||||||
|
* This is the template that displays the area of the page that contains both the current comments
|
||||||
|
* and the comment form.
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the current post is protected by a password and
|
||||||
|
* the visitor has not yet entered the password we will
|
||||||
|
* return early without loading the comments.
|
||||||
|
*/
|
||||||
|
if ( post_password_required() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div id="comments" class="comments-area">
|
||||||
|
|
||||||
|
<?php
|
||||||
|
// You can start editing here -- including this comment!
|
||||||
|
if ( have_comments() ) :
|
||||||
|
?>
|
||||||
|
<h2 class="comments-title">
|
||||||
|
<?php
|
||||||
|
$cyywordpress_comment_count = get_comments_number();
|
||||||
|
if ( '1' === $cyywordpress_comment_count ) {
|
||||||
|
printf(
|
||||||
|
/* translators: 1: title. */
|
||||||
|
esc_html__( 'One thought on “%1$s”', 'cyywordpress' ),
|
||||||
|
'<span>' . wp_kses_post( get_the_title() ) . '</span>'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
printf(
|
||||||
|
/* translators: 1: comment count number, 2: title. */
|
||||||
|
esc_html( _nx( '%1$s thought on “%2$s”', '%1$s thoughts on “%2$s”', $cyywordpress_comment_count, 'comments title', 'cyywordpress' ) ),
|
||||||
|
number_format_i18n( $cyywordpress_comment_count ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||||
|
'<span>' . wp_kses_post( get_the_title() ) . '</span>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</h2><!-- .comments-title -->
|
||||||
|
|
||||||
|
<?php the_comments_navigation(); ?>
|
||||||
|
|
||||||
|
<ol class="comment-list">
|
||||||
|
<?php
|
||||||
|
wp_list_comments(
|
||||||
|
array(
|
||||||
|
'style' => 'ol',
|
||||||
|
'short_ping' => true,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</ol><!-- .comment-list -->
|
||||||
|
|
||||||
|
<?php
|
||||||
|
the_comments_navigation();
|
||||||
|
|
||||||
|
// If comments are closed and there are comments, let's leave a little note, shall we?
|
||||||
|
if ( ! comments_open() ) :
|
||||||
|
?>
|
||||||
|
<p class="no-comments"><?php esc_html_e( 'Comments are closed.', 'cyywordpress' ); ?></p>
|
||||||
|
<?php
|
||||||
|
endif;
|
||||||
|
|
||||||
|
endif; // Check for have_comments().
|
||||||
|
|
||||||
|
comment_form();
|
||||||
|
?>
|
||||||
|
|
||||||
|
</div><!-- #comments -->
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "automattic/underscores",
|
||||||
|
"type": "wordpress-theme",
|
||||||
|
"description": "Hi. I'm a starter theme called _s, or underscores, if you like. I'm a theme meant for hacking so don't use me as a Parent Theme. Instead try turning me into the next, most awesome, WordPress theme out there. That's what I'm here for.",
|
||||||
|
"keywords": [
|
||||||
|
"WordPress",
|
||||||
|
"Themes"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/Automattic/_s",
|
||||||
|
"license": "GPL-2.0-or-later",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Contributors",
|
||||||
|
"homepage": "https://github.com/Automattic/_s/graphs/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.6"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
|
||||||
|
"wptrt/wpthemereview": "^0.2.1",
|
||||||
|
"php-parallel-lint/php-parallel-lint": "^1.2.0",
|
||||||
|
"wp-cli/i18n-command": "^2.2.5"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"lint:wpcs": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs",
|
||||||
|
"lint:php": "@php ./vendor/bin/parallel-lint --exclude .git --exclude vendor .",
|
||||||
|
"make-pot": "wp i18n make-pot . languages/_s.pot"
|
||||||
|
},
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/Automattic/_s/issues",
|
||||||
|
"source": "https://github.com/Automattic/_s"
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+1079
File diff suppressed because it is too large
Load Diff
+34
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The template for displaying the footer
|
||||||
|
*
|
||||||
|
* Contains the closing of the #content div and all content after.
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/basics/template-files/#template-partials
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<footer id="colophon" class="site-footer">
|
||||||
|
<div class="site-info">
|
||||||
|
<a href="<?php echo esc_url( __( 'https://wordpress.org/', 'cyywordpress' ) ); ?>">
|
||||||
|
<?php
|
||||||
|
/* translators: %s: CMS name, i.e. WordPress. */
|
||||||
|
printf( esc_html__( 'Proudly powered by %s', 'cyywordpress' ), 'WordPress' );
|
||||||
|
?>
|
||||||
|
</a>
|
||||||
|
<span class="sep"> | </span>
|
||||||
|
<?php
|
||||||
|
/* translators: 1: Theme name, 2: Theme author. */
|
||||||
|
printf( esc_html__( 'Theme: %1$s by %2$s.', 'cyywordpress' ), 'cyywordpress', '<a href="http://underscores.me/">Underscores.me</a>' );
|
||||||
|
?>
|
||||||
|
</div><!-- .site-info -->
|
||||||
|
</footer><!-- #colophon -->
|
||||||
|
</div><!-- #page -->
|
||||||
|
|
||||||
|
<?php wp_footer(); ?>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+180
@@ -0,0 +1,180 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* CyyWordpress functions and definitions
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/basics/theme-functions/
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ! defined( '_S_VERSION' ) ) {
|
||||||
|
// Replace the version number of the theme on each release.
|
||||||
|
define( '_S_VERSION', '1.0.0' );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! function_exists( 'cyywordpress_setup' ) ) :
|
||||||
|
/**
|
||||||
|
* Sets up theme defaults and registers support for various WordPress features.
|
||||||
|
*
|
||||||
|
* Note that this function is hooked into the after_setup_theme hook, which
|
||||||
|
* runs before the init hook. The init hook is too late for some features, such
|
||||||
|
* as indicating support for post thumbnails.
|
||||||
|
*/
|
||||||
|
function cyywordpress_setup() {
|
||||||
|
/*
|
||||||
|
* Make theme available for translation.
|
||||||
|
* Translations can be filed in the /languages/ directory.
|
||||||
|
* If you're building a theme based on CyyWordpress, use a find and replace
|
||||||
|
* to change 'cyywordpress' to the name of your theme in all the template files.
|
||||||
|
*/
|
||||||
|
load_theme_textdomain( 'cyywordpress', get_template_directory() . '/languages' );
|
||||||
|
|
||||||
|
// Add default posts and comments RSS feed links to head.
|
||||||
|
add_theme_support( 'automatic-feed-links' );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Let WordPress manage the document title.
|
||||||
|
* By adding theme support, we declare that this theme does not use a
|
||||||
|
* hard-coded <title> tag in the document head, and expect WordPress to
|
||||||
|
* provide it for us.
|
||||||
|
*/
|
||||||
|
add_theme_support( 'title-tag' );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable support for Post Thumbnails on posts and pages.
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/functionality/featured-images-post-thumbnails/
|
||||||
|
*/
|
||||||
|
add_theme_support( 'post-thumbnails' );
|
||||||
|
|
||||||
|
// This theme uses wp_nav_menu() in one location.
|
||||||
|
register_nav_menus(
|
||||||
|
array(
|
||||||
|
'menu-1' => esc_html__( 'Primary', 'cyywordpress' ),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Switch default core markup for search form, comment form, and comments
|
||||||
|
* to output valid HTML5.
|
||||||
|
*/
|
||||||
|
add_theme_support(
|
||||||
|
'html5',
|
||||||
|
array(
|
||||||
|
'search-form',
|
||||||
|
'comment-form',
|
||||||
|
'comment-list',
|
||||||
|
'gallery',
|
||||||
|
'caption',
|
||||||
|
'style',
|
||||||
|
'script',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set up the WordPress core custom background feature.
|
||||||
|
add_theme_support(
|
||||||
|
'custom-background',
|
||||||
|
apply_filters(
|
||||||
|
'cyywordpress_custom_background_args',
|
||||||
|
array(
|
||||||
|
'default-color' => 'ffffff',
|
||||||
|
'default-image' => '',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add theme support for selective refresh for widgets.
|
||||||
|
add_theme_support( 'customize-selective-refresh-widgets' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add support for core custom logo.
|
||||||
|
*
|
||||||
|
* @link https://codex.wordpress.org/Theme_Logo
|
||||||
|
*/
|
||||||
|
add_theme_support(
|
||||||
|
'custom-logo',
|
||||||
|
array(
|
||||||
|
'height' => 250,
|
||||||
|
'width' => 250,
|
||||||
|
'flex-width' => true,
|
||||||
|
'flex-height' => true,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
endif;
|
||||||
|
add_action( 'after_setup_theme', 'cyywordpress_setup' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the content width in pixels, based on the theme's design and stylesheet.
|
||||||
|
*
|
||||||
|
* Priority 0 to make it available to lower priority callbacks.
|
||||||
|
*
|
||||||
|
* @global int $content_width
|
||||||
|
*/
|
||||||
|
function cyywordpress_content_width() {
|
||||||
|
$GLOBALS['content_width'] = apply_filters( 'cyywordpress_content_width', 640 );
|
||||||
|
}
|
||||||
|
add_action( 'after_setup_theme', 'cyywordpress_content_width', 0 );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register widget area.
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/functionality/sidebars/#registering-a-sidebar
|
||||||
|
*/
|
||||||
|
function cyywordpress_widgets_init() {
|
||||||
|
register_sidebar(
|
||||||
|
array(
|
||||||
|
'name' => esc_html__( 'Sidebar', 'cyywordpress' ),
|
||||||
|
'id' => 'sidebar-1',
|
||||||
|
'description' => esc_html__( 'Add widgets here.', 'cyywordpress' ),
|
||||||
|
'before_widget' => '<section id="%1$s" class="widget %2$s">',
|
||||||
|
'after_widget' => '</section>',
|
||||||
|
'before_title' => '<h2 class="widget-title">',
|
||||||
|
'after_title' => '</h2>',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
add_action( 'widgets_init', 'cyywordpress_widgets_init' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue scripts and styles.
|
||||||
|
*/
|
||||||
|
function cyywordpress_scripts() {
|
||||||
|
wp_enqueue_style( 'cyywordpress-style', get_stylesheet_uri(), array(), _S_VERSION );
|
||||||
|
wp_style_add_data( 'cyywordpress-style', 'rtl', 'replace' );
|
||||||
|
|
||||||
|
wp_enqueue_script( 'cyywordpress-navigation', get_template_directory_uri() . '/js/navigation.js', array(), _S_VERSION, true );
|
||||||
|
|
||||||
|
if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) {
|
||||||
|
wp_enqueue_script( 'comment-reply' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'wp_enqueue_scripts', 'cyywordpress_scripts' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement the Custom Header feature.
|
||||||
|
*/
|
||||||
|
require get_template_directory() . '/inc/custom-header.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom template tags for this theme.
|
||||||
|
*/
|
||||||
|
require get_template_directory() . '/inc/template-tags.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functions which enhance the theme by hooking into WordPress.
|
||||||
|
*/
|
||||||
|
require get_template_directory() . '/inc/template-functions.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customizer additions.
|
||||||
|
*/
|
||||||
|
require get_template_directory() . '/inc/customizer.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load Jetpack compatibility file.
|
||||||
|
*/
|
||||||
|
if ( defined( 'JETPACK__VERSION' ) ) {
|
||||||
|
require get_template_directory() . '/inc/jetpack.php';
|
||||||
|
}
|
||||||
|
|
||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The header for our theme
|
||||||
|
*
|
||||||
|
* This is the template that displays all of the <head> section and everything up until <div id="content">
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/basics/template-files/#template-partials
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!doctype html>
|
||||||
|
<html <?php language_attributes(); ?>>
|
||||||
|
<head>
|
||||||
|
<meta charset="<?php bloginfo( 'charset' ); ?>">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="profile" href="https://gmpg.org/xfn/11">
|
||||||
|
|
||||||
|
<?php wp_head(); ?>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body <?php body_class(); ?>>
|
||||||
|
<?php wp_body_open(); ?>
|
||||||
|
<div id="page" class="site">
|
||||||
|
<a class="skip-link screen-reader-text" href="#primary"><?php esc_html_e( 'Skip to content', 'cyywordpress' ); ?></a>
|
||||||
|
|
||||||
|
<header id="masthead" class="site-header">
|
||||||
|
<div class="site-branding">
|
||||||
|
<?php
|
||||||
|
the_custom_logo();
|
||||||
|
if ( is_front_page() && is_home() ) :
|
||||||
|
?>
|
||||||
|
<h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
|
||||||
|
<?php
|
||||||
|
else :
|
||||||
|
?>
|
||||||
|
<p class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></p>
|
||||||
|
<?php
|
||||||
|
endif;
|
||||||
|
$cyywordpress_description = get_bloginfo( 'description', 'display' );
|
||||||
|
if ( $cyywordpress_description || is_customize_preview() ) :
|
||||||
|
?>
|
||||||
|
<p class="site-description"><?php echo $cyywordpress_description; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div><!-- .site-branding -->
|
||||||
|
|
||||||
|
<nav id="site-navigation" class="main-navigation">
|
||||||
|
<button class="menu-toggle" aria-controls="primary-menu" aria-expanded="false"><?php esc_html_e( 'Primary Menu', 'cyywordpress' ); ?></button>
|
||||||
|
<?php
|
||||||
|
wp_nav_menu(
|
||||||
|
array(
|
||||||
|
'theme_location' => 'menu-1',
|
||||||
|
'menu_id' => 'primary-menu',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</nav><!-- #site-navigation -->
|
||||||
|
</header><!-- #masthead -->
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Sample implementation of the Custom Header feature
|
||||||
|
*
|
||||||
|
* You can add an optional custom header image to header.php like so ...
|
||||||
|
*
|
||||||
|
<?php the_header_image_tag(); ?>
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/functionality/custom-headers/
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the WordPress core custom header feature.
|
||||||
|
*
|
||||||
|
* @uses cyywordpress_header_style()
|
||||||
|
*/
|
||||||
|
function cyywordpress_custom_header_setup() {
|
||||||
|
add_theme_support(
|
||||||
|
'custom-header',
|
||||||
|
apply_filters(
|
||||||
|
'cyywordpress_custom_header_args',
|
||||||
|
array(
|
||||||
|
'default-image' => '',
|
||||||
|
'default-text-color' => '000000',
|
||||||
|
'width' => 1000,
|
||||||
|
'height' => 250,
|
||||||
|
'flex-height' => true,
|
||||||
|
'wp-head-callback' => 'cyywordpress_header_style',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
add_action( 'after_setup_theme', 'cyywordpress_custom_header_setup' );
|
||||||
|
|
||||||
|
if ( ! function_exists( 'cyywordpress_header_style' ) ) :
|
||||||
|
/**
|
||||||
|
* Styles the header image and text displayed on the blog.
|
||||||
|
*
|
||||||
|
* @see cyywordpress_custom_header_setup().
|
||||||
|
*/
|
||||||
|
function cyywordpress_header_style() {
|
||||||
|
$header_text_color = get_header_textcolor();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If no custom options for text are set, let's bail.
|
||||||
|
* get_header_textcolor() options: Any hex value, 'blank' to hide text. Default: add_theme_support( 'custom-header' ).
|
||||||
|
*/
|
||||||
|
if ( get_theme_support( 'custom-header', 'default-text-color' ) === $header_text_color ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get this far, we have custom styles. Let's do this.
|
||||||
|
?>
|
||||||
|
<style type="text/css">
|
||||||
|
<?php
|
||||||
|
// Has the text been hidden?
|
||||||
|
if ( ! display_header_text() ) :
|
||||||
|
?>
|
||||||
|
.site-title,
|
||||||
|
.site-description {
|
||||||
|
position: absolute;
|
||||||
|
clip: rect(1px, 1px, 1px, 1px);
|
||||||
|
}
|
||||||
|
<?php
|
||||||
|
// If the user has set a custom color for the text use that.
|
||||||
|
else :
|
||||||
|
?>
|
||||||
|
.site-title a,
|
||||||
|
.site-description {
|
||||||
|
color: #<?php echo esc_attr( $header_text_color ); ?>;
|
||||||
|
}
|
||||||
|
<?php endif; ?>
|
||||||
|
</style>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
endif;
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* CyyWordpress Theme Customizer
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add postMessage support for site title and description for the Theme Customizer.
|
||||||
|
*
|
||||||
|
* @param WP_Customize_Manager $wp_customize Theme Customizer object.
|
||||||
|
*/
|
||||||
|
function cyywordpress_customize_register( $wp_customize ) {
|
||||||
|
$wp_customize->get_setting( 'blogname' )->transport = 'postMessage';
|
||||||
|
$wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage';
|
||||||
|
$wp_customize->get_setting( 'header_textcolor' )->transport = 'postMessage';
|
||||||
|
|
||||||
|
if ( isset( $wp_customize->selective_refresh ) ) {
|
||||||
|
$wp_customize->selective_refresh->add_partial(
|
||||||
|
'blogname',
|
||||||
|
array(
|
||||||
|
'selector' => '.site-title a',
|
||||||
|
'render_callback' => 'cyywordpress_customize_partial_blogname',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$wp_customize->selective_refresh->add_partial(
|
||||||
|
'blogdescription',
|
||||||
|
array(
|
||||||
|
'selector' => '.site-description',
|
||||||
|
'render_callback' => 'cyywordpress_customize_partial_blogdescription',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'customize_register', 'cyywordpress_customize_register' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the site title for the selective refresh partial.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function cyywordpress_customize_partial_blogname() {
|
||||||
|
bloginfo( 'name' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the site tagline for the selective refresh partial.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function cyywordpress_customize_partial_blogdescription() {
|
||||||
|
bloginfo( 'description' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds JS handlers to make Theme Customizer preview reload changes asynchronously.
|
||||||
|
*/
|
||||||
|
function cyywordpress_customize_preview_js() {
|
||||||
|
wp_enqueue_script( 'cyywordpress-customizer', get_template_directory_uri() . '/js/customizer.js', array( 'customize-preview' ), _S_VERSION, true );
|
||||||
|
}
|
||||||
|
add_action( 'customize_preview_init', 'cyywordpress_customize_preview_js' );
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Jetpack Compatibility File
|
||||||
|
*
|
||||||
|
* @link https://jetpack.com/
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jetpack setup function.
|
||||||
|
*
|
||||||
|
* See: https://jetpack.com/support/infinite-scroll/
|
||||||
|
* See: https://jetpack.com/support/responsive-videos/
|
||||||
|
* See: https://jetpack.com/support/content-options/
|
||||||
|
*/
|
||||||
|
function cyywordpress_jetpack_setup() {
|
||||||
|
// Add theme support for Infinite Scroll.
|
||||||
|
add_theme_support(
|
||||||
|
'infinite-scroll',
|
||||||
|
array(
|
||||||
|
'container' => 'main',
|
||||||
|
'render' => 'cyywordpress_infinite_scroll_render',
|
||||||
|
'footer' => 'page',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add theme support for Responsive Videos.
|
||||||
|
add_theme_support( 'jetpack-responsive-videos' );
|
||||||
|
|
||||||
|
// Add theme support for Content Options.
|
||||||
|
add_theme_support(
|
||||||
|
'jetpack-content-options',
|
||||||
|
array(
|
||||||
|
'post-details' => array(
|
||||||
|
'stylesheet' => 'cyywordpress-style',
|
||||||
|
'date' => '.posted-on',
|
||||||
|
'categories' => '.cat-links',
|
||||||
|
'tags' => '.tags-links',
|
||||||
|
'author' => '.byline',
|
||||||
|
'comment' => '.comments-link',
|
||||||
|
),
|
||||||
|
'featured-images' => array(
|
||||||
|
'archive' => true,
|
||||||
|
'post' => true,
|
||||||
|
'page' => true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
add_action( 'after_setup_theme', 'cyywordpress_jetpack_setup' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom render function for Infinite Scroll.
|
||||||
|
*/
|
||||||
|
function cyywordpress_infinite_scroll_render() {
|
||||||
|
while ( have_posts() ) {
|
||||||
|
the_post();
|
||||||
|
if ( is_search() ) :
|
||||||
|
get_template_part( 'template-parts/content', 'search' );
|
||||||
|
else :
|
||||||
|
get_template_part( 'template-parts/content', get_post_type() );
|
||||||
|
endif;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Functions which enhance the theme by hooking into WordPress
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds custom classes to the array of body classes.
|
||||||
|
*
|
||||||
|
* @param array $classes Classes for the body element.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function cyywordpress_body_classes( $classes ) {
|
||||||
|
// Adds a class of hfeed to non-singular pages.
|
||||||
|
if ( ! is_singular() ) {
|
||||||
|
$classes[] = 'hfeed';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a class of no-sidebar when there is no sidebar present.
|
||||||
|
if ( ! is_active_sidebar( 'sidebar-1' ) ) {
|
||||||
|
$classes[] = 'no-sidebar';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $classes;
|
||||||
|
}
|
||||||
|
add_filter( 'body_class', 'cyywordpress_body_classes' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a pingback url auto-discovery header for single posts, pages, or attachments.
|
||||||
|
*/
|
||||||
|
function cyywordpress_pingback_header() {
|
||||||
|
if ( is_singular() && pings_open() ) {
|
||||||
|
printf( '<link rel="pingback" href="%s">', esc_url( get_bloginfo( 'pingback_url' ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'wp_head', 'cyywordpress_pingback_header' );
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Custom template tags for this theme
|
||||||
|
*
|
||||||
|
* Eventually, some of the functionality here could be replaced by core features.
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ! function_exists( 'cyywordpress_posted_on' ) ) :
|
||||||
|
/**
|
||||||
|
* Prints HTML with meta information for the current post-date/time.
|
||||||
|
*/
|
||||||
|
function cyywordpress_posted_on() {
|
||||||
|
$time_string = '<time class="entry-date published updated" datetime="%1$s">%2$s</time>';
|
||||||
|
if ( get_the_time( 'U' ) !== get_the_modified_time( 'U' ) ) {
|
||||||
|
$time_string = '<time class="entry-date published" datetime="%1$s">%2$s</time><time class="updated" datetime="%3$s">%4$s</time>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$time_string = sprintf(
|
||||||
|
$time_string,
|
||||||
|
esc_attr( get_the_date( DATE_W3C ) ),
|
||||||
|
esc_html( get_the_date() ),
|
||||||
|
esc_attr( get_the_modified_date( DATE_W3C ) ),
|
||||||
|
esc_html( get_the_modified_date() )
|
||||||
|
);
|
||||||
|
|
||||||
|
$posted_on = sprintf(
|
||||||
|
/* translators: %s: post date. */
|
||||||
|
esc_html_x( 'Posted on %s', 'post date', 'cyywordpress' ),
|
||||||
|
'<a href="' . esc_url( get_permalink() ) . '" rel="bookmark">' . $time_string . '</a>'
|
||||||
|
);
|
||||||
|
|
||||||
|
echo '<span class="posted-on">' . $posted_on . '</span>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||||
|
|
||||||
|
}
|
||||||
|
endif;
|
||||||
|
|
||||||
|
if ( ! function_exists( 'cyywordpress_posted_by' ) ) :
|
||||||
|
/**
|
||||||
|
* Prints HTML with meta information for the current author.
|
||||||
|
*/
|
||||||
|
function cyywordpress_posted_by() {
|
||||||
|
$byline = sprintf(
|
||||||
|
/* translators: %s: post author. */
|
||||||
|
esc_html_x( 'by %s', 'post author', 'cyywordpress' ),
|
||||||
|
'<span class="author vcard"><a class="url fn n" href="' . esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ) . '">' . esc_html( get_the_author() ) . '</a></span>'
|
||||||
|
);
|
||||||
|
|
||||||
|
echo '<span class="byline"> ' . $byline . '</span>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||||
|
|
||||||
|
}
|
||||||
|
endif;
|
||||||
|
|
||||||
|
if ( ! function_exists( 'cyywordpress_entry_footer' ) ) :
|
||||||
|
/**
|
||||||
|
* Prints HTML with meta information for the categories, tags and comments.
|
||||||
|
*/
|
||||||
|
function cyywordpress_entry_footer() {
|
||||||
|
// Hide category and tag text for pages.
|
||||||
|
if ( 'post' === get_post_type() ) {
|
||||||
|
/* translators: used between list items, there is a space after the comma */
|
||||||
|
$categories_list = get_the_category_list( esc_html__( ', ', 'cyywordpress' ) );
|
||||||
|
if ( $categories_list ) {
|
||||||
|
/* translators: 1: list of categories. */
|
||||||
|
printf( '<span class="cat-links">' . esc_html__( 'Posted in %1$s', 'cyywordpress' ) . '</span>', $categories_list ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||||
|
}
|
||||||
|
|
||||||
|
/* translators: used between list items, there is a space after the comma */
|
||||||
|
$tags_list = get_the_tag_list( '', esc_html_x( ', ', 'list item separator', 'cyywordpress' ) );
|
||||||
|
if ( $tags_list ) {
|
||||||
|
/* translators: 1: list of tags. */
|
||||||
|
printf( '<span class="tags-links">' . esc_html__( 'Tagged %1$s', 'cyywordpress' ) . '</span>', $tags_list ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! is_single() && ! post_password_required() && ( comments_open() || get_comments_number() ) ) {
|
||||||
|
echo '<span class="comments-link">';
|
||||||
|
comments_popup_link(
|
||||||
|
sprintf(
|
||||||
|
wp_kses(
|
||||||
|
/* translators: %s: post title */
|
||||||
|
__( 'Leave a Comment<span class="screen-reader-text"> on %s</span>', 'cyywordpress' ),
|
||||||
|
array(
|
||||||
|
'span' => array(
|
||||||
|
'class' => array(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
wp_kses_post( get_the_title() )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
echo '</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
edit_post_link(
|
||||||
|
sprintf(
|
||||||
|
wp_kses(
|
||||||
|
/* translators: %s: Name of current post. Only visible to screen readers */
|
||||||
|
__( 'Edit <span class="screen-reader-text">%s</span>', 'cyywordpress' ),
|
||||||
|
array(
|
||||||
|
'span' => array(
|
||||||
|
'class' => array(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
wp_kses_post( get_the_title() )
|
||||||
|
),
|
||||||
|
'<span class="edit-link">',
|
||||||
|
'</span>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
endif;
|
||||||
|
|
||||||
|
if ( ! function_exists( 'cyywordpress_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.
|
||||||
|
*/
|
||||||
|
function cyywordpress_post_thumbnail() {
|
||||||
|
if ( post_password_required() || is_attachment() || ! has_post_thumbnail() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( is_singular() ) :
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="post-thumbnail">
|
||||||
|
<?php the_post_thumbnail(); ?>
|
||||||
|
</div><!-- .post-thumbnail -->
|
||||||
|
|
||||||
|
<?php else : ?>
|
||||||
|
|
||||||
|
<a class="post-thumbnail" href="<?php the_permalink(); ?>" aria-hidden="true" tabindex="-1">
|
||||||
|
<?php
|
||||||
|
the_post_thumbnail(
|
||||||
|
'post-thumbnail',
|
||||||
|
array(
|
||||||
|
'alt' => the_title_attribute(
|
||||||
|
array(
|
||||||
|
'echo' => false,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
endif; // End is_singular().
|
||||||
|
}
|
||||||
|
endif;
|
||||||
|
|
||||||
|
if ( ! function_exists( 'wp_body_open' ) ) :
|
||||||
|
/**
|
||||||
|
* Shim for sites older than 5.2.
|
||||||
|
*
|
||||||
|
* @link https://core.trac.wordpress.org/ticket/12563
|
||||||
|
*/
|
||||||
|
function wp_body_open() {
|
||||||
|
do_action( 'wp_body_open' );
|
||||||
|
}
|
||||||
|
endif;
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The main template file
|
||||||
|
*
|
||||||
|
* This is the most generic template file in a WordPress theme
|
||||||
|
* and one of the two required files for a theme (the other being style.css).
|
||||||
|
* It is used to display a page when nothing more specific matches a query.
|
||||||
|
* E.g., it puts together the home page when no home.php file exists.
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
get_header();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<main id="primary" class="site-main">
|
||||||
|
|
||||||
|
<?php
|
||||||
|
if ( have_posts() ) :
|
||||||
|
|
||||||
|
if ( is_home() && ! is_front_page() ) :
|
||||||
|
?>
|
||||||
|
<header>
|
||||||
|
<h1 class="page-title screen-reader-text"><?php single_post_title(); ?></h1>
|
||||||
|
</header>
|
||||||
|
<?php
|
||||||
|
endif;
|
||||||
|
|
||||||
|
/* Start the Loop */
|
||||||
|
while ( have_posts() ) :
|
||||||
|
the_post();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Include the Post-Type-specific template for the content.
|
||||||
|
* If you want to override this in a child theme, then include a file
|
||||||
|
* called content-___.php (where ___ is the Post Type name) and that will be used instead.
|
||||||
|
*/
|
||||||
|
get_template_part( 'template-parts/content', get_post_type() );
|
||||||
|
|
||||||
|
endwhile;
|
||||||
|
|
||||||
|
the_posts_navigation();
|
||||||
|
|
||||||
|
else :
|
||||||
|
|
||||||
|
get_template_part( 'template-parts/content', 'none' );
|
||||||
|
|
||||||
|
endif;
|
||||||
|
?>
|
||||||
|
|
||||||
|
</main><!-- #main -->
|
||||||
|
|
||||||
|
<?php
|
||||||
|
get_sidebar();
|
||||||
|
get_footer();
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/* global wp, jQuery */
|
||||||
|
/**
|
||||||
|
* File customizer.js.
|
||||||
|
*
|
||||||
|
* Theme Customizer enhancements for a better user experience.
|
||||||
|
*
|
||||||
|
* Contains handlers to make Theme Customizer preview reload changes asynchronously.
|
||||||
|
*/
|
||||||
|
|
||||||
|
( function( $ ) {
|
||||||
|
// Site title and description.
|
||||||
|
wp.customize( 'blogname', function( value ) {
|
||||||
|
value.bind( function( to ) {
|
||||||
|
$( '.site-title a' ).text( to );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
wp.customize( 'blogdescription', function( value ) {
|
||||||
|
value.bind( function( to ) {
|
||||||
|
$( '.site-description' ).text( to );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
// Header text color.
|
||||||
|
wp.customize( 'header_textcolor', function( value ) {
|
||||||
|
value.bind( function( to ) {
|
||||||
|
if ( 'blank' === to ) {
|
||||||
|
$( '.site-title, .site-description' ).css( {
|
||||||
|
clip: 'rect(1px, 1px, 1px, 1px)',
|
||||||
|
position: 'absolute',
|
||||||
|
} );
|
||||||
|
} else {
|
||||||
|
$( '.site-title, .site-description' ).css( {
|
||||||
|
clip: 'auto',
|
||||||
|
position: 'relative',
|
||||||
|
} );
|
||||||
|
$( '.site-title a, .site-description' ).css( {
|
||||||
|
color: to,
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}( jQuery ) );
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
/**
|
||||||
|
* File navigation.js.
|
||||||
|
*
|
||||||
|
* Handles toggling the navigation menu for small screens and enables TAB key
|
||||||
|
* navigation support for dropdown menus.
|
||||||
|
*/
|
||||||
|
( function() {
|
||||||
|
const siteNavigation = document.getElementById( 'site-navigation' );
|
||||||
|
|
||||||
|
// Return early if the navigation don't exist.
|
||||||
|
if ( ! siteNavigation ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const button = siteNavigation.getElementsByTagName( 'button' )[ 0 ];
|
||||||
|
|
||||||
|
// Return early if the button don't exist.
|
||||||
|
if ( 'undefined' === typeof button ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const menu = siteNavigation.getElementsByTagName( 'ul' )[ 0 ];
|
||||||
|
|
||||||
|
// Hide menu toggle button if menu is empty and return early.
|
||||||
|
if ( 'undefined' === typeof menu ) {
|
||||||
|
button.style.display = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! menu.classList.contains( 'nav-menu' ) ) {
|
||||||
|
menu.classList.add( 'nav-menu' );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle the .toggled class and the aria-expanded value each time the button is clicked.
|
||||||
|
button.addEventListener( 'click', function() {
|
||||||
|
siteNavigation.classList.toggle( 'toggled' );
|
||||||
|
|
||||||
|
if ( button.getAttribute( 'aria-expanded' ) === 'true' ) {
|
||||||
|
button.setAttribute( 'aria-expanded', 'false' );
|
||||||
|
} else {
|
||||||
|
button.setAttribute( 'aria-expanded', 'true' );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
// Remove the .toggled class and set aria-expanded to false when the user clicks outside the navigation.
|
||||||
|
document.addEventListener( 'click', function( event ) {
|
||||||
|
const isClickInside = siteNavigation.contains( event.target );
|
||||||
|
|
||||||
|
if ( ! isClickInside ) {
|
||||||
|
siteNavigation.classList.remove( 'toggled' );
|
||||||
|
button.setAttribute( 'aria-expanded', 'false' );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
// Get all the link elements within the menu.
|
||||||
|
const links = menu.getElementsByTagName( 'a' );
|
||||||
|
|
||||||
|
// Get all the link elements with children within the menu.
|
||||||
|
const linksWithChildren = menu.querySelectorAll( '.menu-item-has-children > a, .page_item_has_children > a' );
|
||||||
|
|
||||||
|
// Toggle focus each time a menu link is focused or blurred.
|
||||||
|
for ( const link of links ) {
|
||||||
|
link.addEventListener( 'focus', toggleFocus, true );
|
||||||
|
link.addEventListener( 'blur', toggleFocus, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle focus each time a menu link with children receive a touch event.
|
||||||
|
for ( const link of linksWithChildren ) {
|
||||||
|
link.addEventListener( 'touchstart', toggleFocus, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets or removes .focus class on an element.
|
||||||
|
*/
|
||||||
|
function toggleFocus() {
|
||||||
|
if ( event.type === 'focus' || event.type === 'blur' ) {
|
||||||
|
let self = this;
|
||||||
|
// Move up through the ancestors of the current link until we hit .nav-menu.
|
||||||
|
while ( ! self.classList.contains( 'nav-menu' ) ) {
|
||||||
|
// On li elements toggle the class .focus.
|
||||||
|
if ( 'li' === self.tagName.toLowerCase() ) {
|
||||||
|
self.classList.toggle( 'focus' );
|
||||||
|
}
|
||||||
|
self = self.parentNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( event.type === 'touchstart' ) {
|
||||||
|
const menuItem = this.parentNode;
|
||||||
|
event.preventDefault();
|
||||||
|
for ( const link of menuItem.parentNode.children ) {
|
||||||
|
if ( menuItem !== link ) {
|
||||||
|
link.classList.remove( 'focus' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menuItem.classList.toggle( 'focus' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}() );
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
# Copyright (C) 2020 Automattic
|
||||||
|
# This file is distributed under the GNU General Public License v2 or later.
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: _s 1.0.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: https://wordpress.org/support/theme/_s\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"POT-Creation-Date: 2020-04-17T21:03:15+00:00\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"X-Generator: WP-CLI 2.4.0\n"
|
||||||
|
"X-Domain: _s\n"
|
||||||
|
|
||||||
|
#. Theme Name of the theme
|
||||||
|
msgid "_s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Theme URI of the theme
|
||||||
|
msgid "https://underscores.me/"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Description of the theme
|
||||||
|
msgid "Hi. I'm a starter theme called <code>_s</code>, or <em>underscores</em>, if you like. I'm a theme meant for hacking so don't use me as a <em>Parent Theme</em>. Instead try turning me into the next, most awesome, WordPress theme out there. That's what I'm here for."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Author of the theme
|
||||||
|
msgid "Automattic"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Author URI of the theme
|
||||||
|
msgid "https://automattic.com/"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: 404.php:18
|
||||||
|
msgid "Oops! That page can’t be found."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: 404.php:22
|
||||||
|
msgid "It looks like nothing was found at this location. Maybe try one of the links below or a search?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: 404.php:31
|
||||||
|
msgid "Most Used Categories"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: %1$s: smiley
|
||||||
|
#: 404.php:49
|
||||||
|
msgid "Try looking in the monthly archives. %1$s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: 1: title.
|
||||||
|
#: comments.php:35
|
||||||
|
msgid "One thought on “%1$s”"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: 1: comment count number, 2: title.
|
||||||
|
#: comments.php:41
|
||||||
|
msgctxt "comments title"
|
||||||
|
msgid "%1$s thought on “%2$s”"
|
||||||
|
msgid_plural "%1$s thoughts on “%2$s”"
|
||||||
|
msgstr[0] ""
|
||||||
|
msgstr[1] ""
|
||||||
|
|
||||||
|
#: comments.php:68
|
||||||
|
msgid "Comments are closed."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: footer.php:18
|
||||||
|
msgid "https://wordpress.org/"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: %s: CMS name, i.e. WordPress.
|
||||||
|
#: footer.php:21
|
||||||
|
msgid "Proudly powered by %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: 1: Theme name, 2: Theme author.
|
||||||
|
#: footer.php:27
|
||||||
|
msgid "Theme: %1$s by %2$s."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: functions.php:53
|
||||||
|
msgid "Primary"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: functions.php:130
|
||||||
|
msgid "Sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: functions.php:132
|
||||||
|
msgid "Add widgets here."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: header.php:26
|
||||||
|
msgid "Skip to content"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: header.php:49
|
||||||
|
msgid "Primary Menu"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: %s: post date.
|
||||||
|
#: inc/template-tags.php:30
|
||||||
|
msgctxt "post date"
|
||||||
|
msgid "Posted on %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: %s: post author.
|
||||||
|
#: inc/template-tags.php:46
|
||||||
|
msgctxt "post author"
|
||||||
|
msgid "by %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: used between list items, there is a space after the comma
|
||||||
|
#: inc/template-tags.php:63
|
||||||
|
msgid ", "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: 1: list of categories.
|
||||||
|
#: inc/template-tags.php:66
|
||||||
|
msgid "Posted in %1$s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: used between list items, there is a space after the comma
|
||||||
|
#: inc/template-tags.php:70
|
||||||
|
msgctxt "list item separator"
|
||||||
|
msgid ", "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: 1: list of tags.
|
||||||
|
#: inc/template-tags.php:73
|
||||||
|
msgid "Tagged %1$s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: %s: post title
|
||||||
|
#: inc/template-tags.php:83
|
||||||
|
msgid "Leave a Comment<span class=\"screen-reader-text\"> on %s</span>"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: %s: Name of current post. Only visible to screen readers
|
||||||
|
#: inc/template-tags.php:100
|
||||||
|
#: template-parts/content-page.php:39
|
||||||
|
msgid "Edit <span class=\"screen-reader-text\">%s</span>"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: inc/woocommerce.php:186
|
||||||
|
msgid "View your shopping cart"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: number of items in the mini cart.
|
||||||
|
#: inc/woocommerce.php:190
|
||||||
|
msgid "%d item"
|
||||||
|
msgid_plural "%d items"
|
||||||
|
msgstr[0] ""
|
||||||
|
msgstr[1] ""
|
||||||
|
|
||||||
|
#. translators: %s: search query.
|
||||||
|
#: search.php:22
|
||||||
|
msgid "Search Results for: %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: single.php:23
|
||||||
|
msgid "Previous:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: single.php:24
|
||||||
|
msgid "Next:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: template-parts/content-none.php:14
|
||||||
|
msgid "Nothing Found"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: 1: link to WP admin new post page.
|
||||||
|
#: template-parts/content-none.php:24
|
||||||
|
msgid "Ready to publish your first post? <a href=\"%1$s\">Get started here</a>."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: template-parts/content-none.php:37
|
||||||
|
msgid "Sorry, but nothing matched your search terms. Please try again with some different keywords."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: template-parts/content-none.php:44
|
||||||
|
msgid "It seems we can’t find what you’re looking for. Perhaps searching can help."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: template-parts/content-page.php:25
|
||||||
|
#: template-parts/content.php:53
|
||||||
|
msgid "Pages:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: %s: Name of current post. Only visible to screen readers
|
||||||
|
#: template-parts/content.php:40
|
||||||
|
msgid "Continue reading<span class=\"screen-reader-text\"> \"%s\"</span>"
|
||||||
|
msgstr ""
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
Place your theme language files in this directory.
|
||||||
|
|
||||||
|
Please visit the following links to learn more about translating WordPress themes:
|
||||||
|
|
||||||
|
https://make.wordpress.org/polyglots/teams/
|
||||||
|
https://developer.wordpress.org/themes/functionality/localization/
|
||||||
|
https://developer.wordpress.org/reference/functions/load_theme_textdomain/
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"name": "underscores",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Hi. I'm a starter theme called _s, or underscores, if you like. I'm a theme meant for hacking so don't use me as a Parent Theme. Instead try turning me into the next, most awesome, WordPress theme out there. That's what I'm here for.",
|
||||||
|
"author": "Automattic Theme Team",
|
||||||
|
"license": "GPL-2.0-or-later",
|
||||||
|
"keywords": [
|
||||||
|
"WordPress",
|
||||||
|
"Theme"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/Automattic/_s#readme",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/Automattic/_s.git"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/Automattic/_s/issues"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@wordpress/scripts": "^12.1.0",
|
||||||
|
"dir-archiver": "^1.1.1",
|
||||||
|
"node-sass": "^4.14.1",
|
||||||
|
"rtlcss": "^2.5.0"
|
||||||
|
},
|
||||||
|
"rtlcssConfig": {
|
||||||
|
"options": {
|
||||||
|
"autoRename": false,
|
||||||
|
"autoRenameStrict": false,
|
||||||
|
"blacklist": {},
|
||||||
|
"clean": true,
|
||||||
|
"greedy": false,
|
||||||
|
"processUrls": false,
|
||||||
|
"stringMap": []
|
||||||
|
},
|
||||||
|
"plugins": [],
|
||||||
|
"map": false
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"watch": "node-sass sass/ -o ./ --source-map true --output-style expanded --indent-type tab --indent-width 1 -w",
|
||||||
|
"compile:css": "node-sass sass/ -o ./ && stylelint '*.css' --fix || true && stylelint '*.css' --fix",
|
||||||
|
"compile:rtl": "rtlcss style.css style-rtl.css",
|
||||||
|
"lint:scss": "wp-scripts lint-style 'sass/**/*.scss'",
|
||||||
|
"lint:js": "wp-scripts lint-js 'js/*.js'",
|
||||||
|
"bundle": "dir-archiver --src . --dest ../_s.zip --exclude .DS_Store .stylelintrc.json .eslintrc .git .gitattributes .github .gitignore README.md composer.json composer.lock node_modules vendor package-lock.json package.json .travis.yml phpcs.xml.dist sass style.css.map"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The template for displaying all pages
|
||||||
|
*
|
||||||
|
* This is the template that displays all pages by default.
|
||||||
|
* Please note that this is the WordPress construct of pages
|
||||||
|
* and that other 'pages' on your WordPress site may use a
|
||||||
|
* different template.
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
get_header();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<main id="primary" class="site-main">
|
||||||
|
|
||||||
|
<?php
|
||||||
|
while ( have_posts() ) :
|
||||||
|
the_post();
|
||||||
|
|
||||||
|
get_template_part( 'template-parts/content', 'page' );
|
||||||
|
|
||||||
|
// If comments are open or we have at least one comment, load up the comment template.
|
||||||
|
if ( comments_open() || get_comments_number() ) :
|
||||||
|
comments_template();
|
||||||
|
endif;
|
||||||
|
|
||||||
|
endwhile; // End of the loop.
|
||||||
|
?>
|
||||||
|
|
||||||
|
</main><!-- #main -->
|
||||||
|
|
||||||
|
<?php
|
||||||
|
get_sidebar();
|
||||||
|
get_footer();
|
||||||
+110
@@ -0,0 +1,110 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<ruleset name="WordPress Theme Coding Standards">
|
||||||
|
<!-- See https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-ruleset.xml -->
|
||||||
|
<!-- See https://github.com/WordPress/WordPress-Coding-Standards -->
|
||||||
|
<!-- See https://github.com/WPTRT/WPThemeReview -->
|
||||||
|
<!-- See https://github.com/PHPCompatibility/PHPCompatibilityWP -->
|
||||||
|
|
||||||
|
<!-- Set a description for this ruleset. -->
|
||||||
|
<description>A custom set of code standard rules to check for WordPress themes.</description>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
#############################################################################
|
||||||
|
COMMAND LINE ARGUMENTS
|
||||||
|
https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-ruleset.xml
|
||||||
|
#############################################################################
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Pass some flags to PHPCS:
|
||||||
|
p flag: Show progress of the run.
|
||||||
|
s flag: Show sniff codes in all reports.
|
||||||
|
-->
|
||||||
|
<arg value="ps"/>
|
||||||
|
|
||||||
|
<!-- Strip the filepaths down to the relevant bit. -->
|
||||||
|
<arg name="basepath" value="./"/>
|
||||||
|
|
||||||
|
<!-- Check up to 8 files simultaneously. -->
|
||||||
|
<arg name="parallel" value="8"/>
|
||||||
|
|
||||||
|
<!-- Check PHP files only. JavaScript and CSS files are checked separately using the @wordpress/scripts package. -->
|
||||||
|
<arg name="extensions" value="php"/>
|
||||||
|
|
||||||
|
<!-- Check all files in this directory and the directories below it. -->
|
||||||
|
<file>.</file>
|
||||||
|
|
||||||
|
<!-- Exclude patterns. -->
|
||||||
|
<exclude-pattern>/vendor/*</exclude-pattern>
|
||||||
|
<exclude-pattern>/node_modules/*</exclude-pattern>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
#############################################################################
|
||||||
|
USE THE WordPress AND THE Theme Review RULESET
|
||||||
|
#############################################################################
|
||||||
|
-->
|
||||||
|
|
||||||
|
<rule ref="WordPress">
|
||||||
|
<!-- This rule does not apply here since the _s prefix should be changed by the theme author. -->
|
||||||
|
<exclude name="WordPress.NamingConventions.PrefixAllGlobals.ShortPrefixPassed"/>
|
||||||
|
</rule>
|
||||||
|
<rule ref="WPThemeReview"/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
#############################################################################
|
||||||
|
SNIFF SPECIFIC CONFIGURATION
|
||||||
|
#############################################################################
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Verify that the text_domain is set to the desired text-domain.
|
||||||
|
Multiple valid text domains can be provided as a comma-delimited list. -->
|
||||||
|
<rule ref="WordPress.WP.I18n">
|
||||||
|
<properties>
|
||||||
|
<property name="text_domain" type="array" value="_s"/>
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- Allow for theme specific exceptions to the file name rules based
|
||||||
|
on the theme hierarchy. -->
|
||||||
|
<rule ref="WordPress.Files.FileName">
|
||||||
|
<properties>
|
||||||
|
<property name="is_theme" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- Set the minimum supported WP version. This is used by several sniffs.
|
||||||
|
The minimum version set here should be in line with the minimum WP version
|
||||||
|
as set in the "Requires at least" tag in the readme.txt file. -->
|
||||||
|
<config name="minimum_supported_wp_version" value="4.5"/>
|
||||||
|
|
||||||
|
<rule ref="WordPress.Arrays.MultipleStatementAlignment">
|
||||||
|
<properties>
|
||||||
|
<!-- No need to adjust alignment of large arrays when the item with the largest key is removed. -->
|
||||||
|
<property name="exact" value="false"/>
|
||||||
|
<!-- Don't align multi-line items if ALL items in the array are multi-line. -->
|
||||||
|
<property name="alignMultilineItems" value="!=100"/>
|
||||||
|
<!-- Array assignment operator should always be on the same line as the array key. -->
|
||||||
|
<property name="ignoreNewlines" value="false"/>
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- Verify that everything in the global namespace is prefixed with a theme specific prefix.
|
||||||
|
Multiple valid prefixes can be provided as a comma-delimited list. -->
|
||||||
|
<rule ref="WordPress.NamingConventions.PrefixAllGlobals">
|
||||||
|
<properties>
|
||||||
|
<property name="prefixes" type="array" value="_s" />
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
#############################################################################
|
||||||
|
USE THE PHPCompatibility RULESET
|
||||||
|
#############################################################################
|
||||||
|
-->
|
||||||
|
|
||||||
|
<config name="testVersion" value="5.6-"/>
|
||||||
|
<rule ref="PHPCompatibilityWP"/>
|
||||||
|
|
||||||
|
</ruleset>
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
=== CyyWordpress ===
|
||||||
|
|
||||||
|
Contributors: automattic
|
||||||
|
Tags: custom-background, custom-logo, custom-menu, featured-images, threaded-comments, translation-ready
|
||||||
|
|
||||||
|
Requires at least: 4.5
|
||||||
|
Tested up to: 5.4
|
||||||
|
Requires PHP: 5.6
|
||||||
|
Stable tag: 1.0.0
|
||||||
|
License: GNU General Public License v2 or later
|
||||||
|
License URI: LICENSE
|
||||||
|
|
||||||
|
A starter theme called CyyWordpress.
|
||||||
|
|
||||||
|
== Description ==
|
||||||
|
|
||||||
|
Description
|
||||||
|
|
||||||
|
== Installation ==
|
||||||
|
|
||||||
|
1. In your admin panel, go to Appearance > Themes and click the Add New button.
|
||||||
|
2. Click Upload Theme and Choose File, then select the theme's .zip file. Click Install Now.
|
||||||
|
3. Click Activate to use your new theme right away.
|
||||||
|
|
||||||
|
== Frequently Asked Questions ==
|
||||||
|
|
||||||
|
= Does this theme support any plugins? =
|
||||||
|
|
||||||
|
CyyWordpress includes support for WooCommerce and for Infinite Scroll in Jetpack.
|
||||||
|
|
||||||
|
== Changelog ==
|
||||||
|
|
||||||
|
= 1.0 - May 12 2015 =
|
||||||
|
* Initial release
|
||||||
|
|
||||||
|
== Credits ==
|
||||||
|
|
||||||
|
* Based on Underscores https://underscores.me/, (C) 2012-2020 Automattic, Inc., [GPLv2 or later](https://www.gnu.org/licenses/gpl-2.0.html)
|
||||||
|
* normalize.css https://necolas.github.io/normalize.css/, (C) 2012-2018 Nicolas Gallagher and Jonathan Neal, [MIT](https://opensource.org/licenses/MIT)
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 264 B |
+53
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The template for displaying search results pages
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/#search-result
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
get_header();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<main id="primary" class="site-main">
|
||||||
|
|
||||||
|
<?php if ( have_posts() ) : ?>
|
||||||
|
|
||||||
|
<header class="page-header">
|
||||||
|
<h1 class="page-title">
|
||||||
|
<?php
|
||||||
|
/* translators: %s: search query. */
|
||||||
|
printf( esc_html__( 'Search Results for: %s', 'cyywordpress' ), '<span>' . get_search_query() . '</span>' );
|
||||||
|
?>
|
||||||
|
</h1>
|
||||||
|
</header><!-- .page-header -->
|
||||||
|
|
||||||
|
<?php
|
||||||
|
/* Start the Loop */
|
||||||
|
while ( have_posts() ) :
|
||||||
|
the_post();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the loop for the search to output the results.
|
||||||
|
* If you want to overload this in a child theme then include a file
|
||||||
|
* called content-search.php and that will be used instead.
|
||||||
|
*/
|
||||||
|
get_template_part( 'template-parts/content', 'search' );
|
||||||
|
|
||||||
|
endwhile;
|
||||||
|
|
||||||
|
the_posts_navigation();
|
||||||
|
|
||||||
|
else :
|
||||||
|
|
||||||
|
get_template_part( 'template-parts/content', 'none' );
|
||||||
|
|
||||||
|
endif;
|
||||||
|
?>
|
||||||
|
|
||||||
|
</main><!-- #main -->
|
||||||
|
|
||||||
|
<?php
|
||||||
|
get_sidebar();
|
||||||
|
get_footer();
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The sidebar containing the main widget area
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/basics/template-files/#template-partials
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ! is_active_sidebar( 'sidebar-1' ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<aside id="secondary" class="widget-area">
|
||||||
|
<?php dynamic_sidebar( 'sidebar-1' ); ?>
|
||||||
|
</aside><!-- #secondary -->
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The template for displaying all single posts
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/#single-post
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
get_header();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<main id="primary" class="site-main">
|
||||||
|
|
||||||
|
<?php
|
||||||
|
while ( have_posts() ) :
|
||||||
|
the_post();
|
||||||
|
|
||||||
|
get_template_part( 'template-parts/content', get_post_type() );
|
||||||
|
|
||||||
|
the_post_navigation(
|
||||||
|
array(
|
||||||
|
'prev_text' => '<span class="nav-subtitle">' . esc_html__( 'Previous:', 'cyywordpress' ) . '</span> <span class="nav-title">%title</span>',
|
||||||
|
'next_text' => '<span class="nav-subtitle">' . esc_html__( 'Next:', 'cyywordpress' ) . '</span> <span class="nav-title">%title</span>',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// If comments are open or we have at least one comment, load up the comment template.
|
||||||
|
if ( comments_open() || get_comments_number() ) :
|
||||||
|
comments_template();
|
||||||
|
endif;
|
||||||
|
|
||||||
|
endwhile; // End of the loop.
|
||||||
|
?>
|
||||||
|
|
||||||
|
</main><!-- #main -->
|
||||||
|
|
||||||
|
<?php
|
||||||
|
get_sidebar();
|
||||||
|
get_footer();
|
||||||
+961
@@ -0,0 +1,961 @@
|
|||||||
|
/*!
|
||||||
|
Theme Name: CyyWordpress
|
||||||
|
Theme URI: https://underscores.me/
|
||||||
|
Author: Automattic
|
||||||
|
Author URI: https://automattic.com/
|
||||||
|
Description: Hi. I'm a starter theme called <code>CyyWordpress</code>, or <em>underscores</em>, if you like. I'm a theme meant for hacking so don't use me as a <em>Parent Theme</em>. Instead try turning me into the next, most awesome, WordPress theme out there. That's what I'm here for.
|
||||||
|
Version: 1.0.0
|
||||||
|
Tested up to: 5.4
|
||||||
|
Requires PHP: 5.6
|
||||||
|
License: GNU General Public License v2 or later
|
||||||
|
License URI: LICENSE
|
||||||
|
Text Domain: CyyWordpress
|
||||||
|
Tags: custom-background, custom-logo, custom-menu, featured-images, threaded-comments, translation-ready
|
||||||
|
|
||||||
|
This theme, like WordPress, is licensed under the GPL.
|
||||||
|
Use it to make something cool, have fun, and share what you've learned.
|
||||||
|
|
||||||
|
CyyWordpress is based on Underscores https://underscores.me/, (C) 2012-2020 Automattic, Inc.
|
||||||
|
Underscores is distributed under the terms of the GNU GPL v2 or later.
|
||||||
|
|
||||||
|
Normalizing styles have been helped along thanks to the fine work of
|
||||||
|
Nicolas Gallagher and Jonathan Neal https://necolas.github.io/normalize.css/
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
>>> TABLE OF CONTENTS:
|
||||||
|
----------------------------------------------------------------
|
||||||
|
# Generic
|
||||||
|
- Normalize
|
||||||
|
- Box sizing
|
||||||
|
# Base
|
||||||
|
- Typography
|
||||||
|
- Elements
|
||||||
|
- Links
|
||||||
|
- Forms
|
||||||
|
## Layouts
|
||||||
|
# Components
|
||||||
|
- Navigation
|
||||||
|
- Posts and pages
|
||||||
|
- Comments
|
||||||
|
- Widgets
|
||||||
|
- Media
|
||||||
|
- Captions
|
||||||
|
- Galleries
|
||||||
|
# plugins
|
||||||
|
- Jetpack infinite scroll
|
||||||
|
# Utilities
|
||||||
|
- Accessibility
|
||||||
|
- Alignments
|
||||||
|
|
||||||
|
--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
# Generic
|
||||||
|
--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Normalize
|
||||||
|
--------------------------------------------- */
|
||||||
|
|
||||||
|
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
|
||||||
|
|
||||||
|
/* Document
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the line height in all browsers.
|
||||||
|
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
||||||
|
*/
|
||||||
|
html {
|
||||||
|
line-height: 1.15;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the margin in all browsers.
|
||||||
|
*/
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the `main` element consistently in IE.
|
||||||
|
*/
|
||||||
|
main {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the font size and margin on `h1` elements within `section` and
|
||||||
|
* `article` contexts in Chrome, Firefox, and Safari.
|
||||||
|
*/
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: 0.67em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grouping content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in Firefox.
|
||||||
|
* 2. Show the overflow in Edge and IE.
|
||||||
|
*/
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box;
|
||||||
|
height: 0;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
pre {
|
||||||
|
font-family: monospace, monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text-level semantics
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the gray background on active links in IE 10.
|
||||||
|
*/
|
||||||
|
a {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Remove the bottom border in Chrome 57-
|
||||||
|
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||||
|
*/
|
||||||
|
abbr[title] {
|
||||||
|
border-bottom: none;
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration: underline dotted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||||
|
*/
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: monospace, monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font size in all browsers.
|
||||||
|
*/
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||||
|
* all browsers.
|
||||||
|
*/
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Embedded content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the border on images inside links in IE 10.
|
||||||
|
*/
|
||||||
|
img {
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forms
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Change the font styles in all browsers.
|
||||||
|
* 2. Remove the margin in Firefox and Safari.
|
||||||
|
*/
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
optgroup,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: 100%;
|
||||||
|
line-height: 1.15;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the overflow in IE.
|
||||||
|
* 1. Show the overflow in Edge.
|
||||||
|
*/
|
||||||
|
button,
|
||||||
|
input {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||||
|
* 1. Remove the inheritance of text transform in Firefox.
|
||||||
|
*/
|
||||||
|
button,
|
||||||
|
select {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
*/
|
||||||
|
button,
|
||||||
|
[type="button"],
|
||||||
|
[type="reset"],
|
||||||
|
[type="submit"] {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner border and padding in Firefox.
|
||||||
|
*/
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
[type="button"]::-moz-focus-inner,
|
||||||
|
[type="reset"]::-moz-focus-inner,
|
||||||
|
[type="submit"]::-moz-focus-inner {
|
||||||
|
border-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the focus styles unset by the previous rule.
|
||||||
|
*/
|
||||||
|
button:-moz-focusring,
|
||||||
|
[type="button"]:-moz-focusring,
|
||||||
|
[type="reset"]:-moz-focusring,
|
||||||
|
[type="submit"]:-moz-focusring {
|
||||||
|
outline: 1px dotted ButtonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the padding in Firefox.
|
||||||
|
*/
|
||||||
|
fieldset {
|
||||||
|
padding: 0.35em 0.75em 0.625em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the text wrapping in Edge and IE.
|
||||||
|
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||||
|
* 3. Remove the padding so developers are not caught out when they zero out
|
||||||
|
* `fieldset` elements in all browsers.
|
||||||
|
*/
|
||||||
|
legend {
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: inherit;
|
||||||
|
display: table;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||||
|
*/
|
||||||
|
progress {
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the default vertical scrollbar in IE 10+.
|
||||||
|
*/
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in IE 10.
|
||||||
|
* 2. Remove the padding in IE 10.
|
||||||
|
*/
|
||||||
|
[type="checkbox"],
|
||||||
|
[type="radio"] {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||||
|
*/
|
||||||
|
[type="number"]::-webkit-inner-spin-button,
|
||||||
|
[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the odd appearance in Chrome and Safari.
|
||||||
|
* 2. Correct the outline style in Safari.
|
||||||
|
*/
|
||||||
|
[type="search"] {
|
||||||
|
-webkit-appearance: textfield;
|
||||||
|
outline-offset: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner padding in Chrome and Safari on macOS.
|
||||||
|
*/
|
||||||
|
[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
* 2. Change font properties to `inherit` in Safari.
|
||||||
|
*/
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interactive
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in Edge, IE 10+, and Firefox.
|
||||||
|
*/
|
||||||
|
details {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in all browsers.
|
||||||
|
*/
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Misc
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 10+.
|
||||||
|
*/
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 10.
|
||||||
|
*/
|
||||||
|
[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Box sizing
|
||||||
|
--------------------------------------------- */
|
||||||
|
|
||||||
|
/* Inherit box-sizing to more easily change it's value on a component level.
|
||||||
|
@link http://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/ */
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
# Base
|
||||||
|
--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Typography
|
||||||
|
--------------------------------------------- */
|
||||||
|
body,
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
optgroup,
|
||||||
|
textarea {
|
||||||
|
color: #404040;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
dfn,
|
||||||
|
cite,
|
||||||
|
em,
|
||||||
|
i {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin: 0 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
address {
|
||||||
|
margin: 0 0 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
background: #eee;
|
||||||
|
font-family: "Courier 10 Pitch", courier, monospace;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: 1.6em;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 1.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
tt,
|
||||||
|
var {
|
||||||
|
font-family: monaco, consolas, "Andale Mono", "DejaVu Sans Mono", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
abbr,
|
||||||
|
acronym {
|
||||||
|
border-bottom: 1px dotted #666;
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
|
||||||
|
mark,
|
||||||
|
ins {
|
||||||
|
background: #fff9c0;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
big {
|
||||||
|
font-size: 125%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Elements
|
||||||
|
--------------------------------------------- */
|
||||||
|
body {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
background-color: #ccc;
|
||||||
|
border: 0;
|
||||||
|
height: 1px;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
margin: 0 3em 1.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: disc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol {
|
||||||
|
list-style: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
li > ul,
|
||||||
|
li > ol {
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-right: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd {
|
||||||
|
margin: 0 1.5em 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure embeds and iframes fit their containers. */
|
||||||
|
embed,
|
||||||
|
iframe,
|
||||||
|
object {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
margin: 0 0 1.5em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Links
|
||||||
|
--------------------------------------------- */
|
||||||
|
a {
|
||||||
|
color: #4169e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
color: #800080;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover,
|
||||||
|
a:focus,
|
||||||
|
a:active {
|
||||||
|
color: #191970;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:focus {
|
||||||
|
outline: thin dotted;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover,
|
||||||
|
a:active {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forms
|
||||||
|
--------------------------------------------- */
|
||||||
|
button,
|
||||||
|
input[type="button"],
|
||||||
|
input[type="reset"],
|
||||||
|
input[type="submit"] {
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: #ccc #ccc #bbb;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: #e6e6e6;
|
||||||
|
color: rgba(0, 0, 0, 0.8);
|
||||||
|
line-height: 1;
|
||||||
|
padding: 0.6em 1em 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover,
|
||||||
|
input[type="button"]:hover,
|
||||||
|
input[type="reset"]:hover,
|
||||||
|
input[type="submit"]:hover {
|
||||||
|
border-color: #ccc #bbb #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:active,
|
||||||
|
button:focus,
|
||||||
|
input[type="button"]:active,
|
||||||
|
input[type="button"]:focus,
|
||||||
|
input[type="reset"]:active,
|
||||||
|
input[type="reset"]:focus,
|
||||||
|
input[type="submit"]:active,
|
||||||
|
input[type="submit"]:focus {
|
||||||
|
border-color: #aaa #bbb #bbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"],
|
||||||
|
input[type="email"],
|
||||||
|
input[type="url"],
|
||||||
|
input[type="password"],
|
||||||
|
input[type="search"],
|
||||||
|
input[type="number"],
|
||||||
|
input[type="tel"],
|
||||||
|
input[type="range"],
|
||||||
|
input[type="date"],
|
||||||
|
input[type="month"],
|
||||||
|
input[type="week"],
|
||||||
|
input[type="time"],
|
||||||
|
input[type="datetime"],
|
||||||
|
input[type="datetime-local"],
|
||||||
|
input[type="color"],
|
||||||
|
textarea {
|
||||||
|
color: #666;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"]:focus,
|
||||||
|
input[type="email"]:focus,
|
||||||
|
input[type="url"]:focus,
|
||||||
|
input[type="password"]:focus,
|
||||||
|
input[type="search"]:focus,
|
||||||
|
input[type="number"]:focus,
|
||||||
|
input[type="tel"]:focus,
|
||||||
|
input[type="range"]:focus,
|
||||||
|
input[type="date"]:focus,
|
||||||
|
input[type="month"]:focus,
|
||||||
|
input[type="week"]:focus,
|
||||||
|
input[type="time"]:focus,
|
||||||
|
input[type="datetime"]:focus,
|
||||||
|
input[type="datetime-local"]:focus,
|
||||||
|
input[type="color"]:focus,
|
||||||
|
textarea:focus {
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
# Layouts
|
||||||
|
--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
# Components
|
||||||
|
--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Navigation
|
||||||
|
--------------------------------------------- */
|
||||||
|
.main-navigation {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation ul {
|
||||||
|
display: none;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation ul ul {
|
||||||
|
box-shadow: 0 3px 3px rgba(0, 0, 0, 0.2);
|
||||||
|
float: right;
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
right: -999em;
|
||||||
|
z-index: 99999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation ul ul ul {
|
||||||
|
right: -999em;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation ul ul li:hover > ul,
|
||||||
|
.main-navigation ul ul li.focus > ul {
|
||||||
|
display: block;
|
||||||
|
right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation ul ul a {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation ul li:hover > ul,
|
||||||
|
.main-navigation ul li.focus > ul {
|
||||||
|
right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation li {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation a {
|
||||||
|
display: block;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small menu. */
|
||||||
|
.menu-toggle,
|
||||||
|
.main-navigation.toggled ul {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 37.5em) {
|
||||||
|
|
||||||
|
.menu-toggle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation ul {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-main .comment-navigation,
|
||||||
|
.site-main
|
||||||
|
.posts-navigation,
|
||||||
|
.site-main
|
||||||
|
.post-navigation {
|
||||||
|
margin: 0 0 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-navigation .nav-links,
|
||||||
|
.posts-navigation .nav-links,
|
||||||
|
.post-navigation .nav-links {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-navigation .nav-previous,
|
||||||
|
.posts-navigation .nav-previous,
|
||||||
|
.post-navigation .nav-previous {
|
||||||
|
flex: 1 0 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-navigation .nav-next,
|
||||||
|
.posts-navigation .nav-next,
|
||||||
|
.post-navigation .nav-next {
|
||||||
|
text-align: end;
|
||||||
|
flex: 1 0 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Posts and pages
|
||||||
|
--------------------------------------------- */
|
||||||
|
.sticky {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post,
|
||||||
|
.page {
|
||||||
|
margin: 0 0 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.updated:not(.published) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content,
|
||||||
|
.entry-content,
|
||||||
|
.entry-summary {
|
||||||
|
margin: 1.5em 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-links {
|
||||||
|
clear: both;
|
||||||
|
margin: 0 0 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Comments
|
||||||
|
--------------------------------------------- */
|
||||||
|
.comment-content a {
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bypostauthor {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Widgets
|
||||||
|
--------------------------------------------- */
|
||||||
|
.widget {
|
||||||
|
margin: 0 0 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget select {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Media
|
||||||
|
--------------------------------------------- */
|
||||||
|
.page-content .wp-smiley,
|
||||||
|
.entry-content .wp-smiley,
|
||||||
|
.comment-content .wp-smiley {
|
||||||
|
border: none;
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure logo link wraps around logo image. */
|
||||||
|
.custom-logo-link {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Captions
|
||||||
|
--------------------------------------------- */
|
||||||
|
.wp-caption {
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-caption img[class*="wp-image-"] {
|
||||||
|
display: block;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-caption .wp-caption-text {
|
||||||
|
margin: 0.8075em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-caption-text {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Galleries
|
||||||
|
--------------------------------------------- */
|
||||||
|
.gallery {
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-item {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-2 {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-3 {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-4 {
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-5 {
|
||||||
|
grid-template-columns: repeat(5, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-6 {
|
||||||
|
grid-template-columns: repeat(6, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-7 {
|
||||||
|
grid-template-columns: repeat(7, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-8 {
|
||||||
|
grid-template-columns: repeat(8, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-9 {
|
||||||
|
grid-template-columns: repeat(9, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-caption {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
# Plugins
|
||||||
|
--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Jetpack infinite scroll
|
||||||
|
--------------------------------------------- */
|
||||||
|
|
||||||
|
/* Hide the Posts Navigation and the Footer when Infinite Scroll is in use. */
|
||||||
|
.infinite-scroll .posts-navigation,
|
||||||
|
.infinite-scroll.neverending .site-footer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Re-display the Theme Footer when Infinite Scroll has reached its end. */
|
||||||
|
.infinity-end.neverending .site-footer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
# Utilities
|
||||||
|
--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Accessibility
|
||||||
|
--------------------------------------------- */
|
||||||
|
|
||||||
|
/* Text meant only for screen readers. */
|
||||||
|
.screen-reader-text {
|
||||||
|
border: 0;
|
||||||
|
clip: rect(1px, 1px, 1px, 1px);
|
||||||
|
clip-path: inset(50%);
|
||||||
|
height: 1px;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
position: absolute !important;
|
||||||
|
width: 1px;
|
||||||
|
word-wrap: normal !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen-reader-text:focus {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.6);
|
||||||
|
clip: auto !important;
|
||||||
|
clip-path: none;
|
||||||
|
color: #21759b;
|
||||||
|
display: block;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 700;
|
||||||
|
height: auto;
|
||||||
|
right: 5px;
|
||||||
|
line-height: normal;
|
||||||
|
padding: 15px 23px 14px;
|
||||||
|
text-decoration: none;
|
||||||
|
top: 5px;
|
||||||
|
width: auto;
|
||||||
|
z-index: 100000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do not show the outline on the skip link target. */
|
||||||
|
#primary[tabindex="-1"]:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alignments
|
||||||
|
--------------------------------------------- */
|
||||||
|
.alignleft {
|
||||||
|
float: left;
|
||||||
|
margin-right: 1.5em;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alignright {
|
||||||
|
float: right;
|
||||||
|
margin-left: 1.5em;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aligncenter {
|
||||||
|
clear: both;
|
||||||
|
display: block;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
@@ -0,0 +1,969 @@
|
|||||||
|
/*!
|
||||||
|
Theme Name: CyyWordpress
|
||||||
|
Theme URI: http://underscores.me/
|
||||||
|
Author: Underscores.me
|
||||||
|
Author URI: http://underscores.me/
|
||||||
|
Description: Description
|
||||||
|
Version: 1.0.0
|
||||||
|
Tested up to: 5.4
|
||||||
|
Requires PHP: 5.6
|
||||||
|
License: GNU General Public License v2 or later
|
||||||
|
License URI: LICENSE
|
||||||
|
Text Domain: cyywordpress
|
||||||
|
Tags: custom-background, custom-logo, custom-menu, featured-images, threaded-comments, translation-ready
|
||||||
|
|
||||||
|
This theme, like WordPress, is licensed under the GPL.
|
||||||
|
Use it to make something cool, have fun, and share what you've learned.
|
||||||
|
|
||||||
|
CyyWordpress is based on Underscores https://underscores.me/, (C) 2012-2020 Automattic, Inc.
|
||||||
|
Underscores is distributed under the terms of the GNU GPL v2 or later.
|
||||||
|
|
||||||
|
Normalizing styles have been helped along thanks to the fine work of
|
||||||
|
Nicolas Gallagher and Jonathan Neal https://necolas.github.io/normalize.css/
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
>>> TABLE OF CONTENTS:
|
||||||
|
----------------------------------------------------------------
|
||||||
|
# Generic
|
||||||
|
- Normalize
|
||||||
|
- Box sizing
|
||||||
|
# Base
|
||||||
|
- Typography
|
||||||
|
- Elements
|
||||||
|
- Links
|
||||||
|
- Forms
|
||||||
|
## Layouts
|
||||||
|
# Components
|
||||||
|
- Navigation
|
||||||
|
- Posts and pages
|
||||||
|
- Comments
|
||||||
|
- Widgets
|
||||||
|
- Media
|
||||||
|
- Captions
|
||||||
|
- Galleries
|
||||||
|
# plugins
|
||||||
|
- Jetpack infinite scroll
|
||||||
|
# Utilities
|
||||||
|
- Accessibility
|
||||||
|
- Alignments
|
||||||
|
|
||||||
|
--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
# Generic
|
||||||
|
--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Normalize
|
||||||
|
--------------------------------------------- */
|
||||||
|
|
||||||
|
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
|
||||||
|
|
||||||
|
/* Document
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the line height in all browsers.
|
||||||
|
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
||||||
|
*/
|
||||||
|
html {
|
||||||
|
line-height: 1.15;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the margin in all browsers.
|
||||||
|
*/
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the `main` element consistently in IE.
|
||||||
|
*/
|
||||||
|
main {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the font size and margin on `h1` elements within `section` and
|
||||||
|
* `article` contexts in Chrome, Firefox, and Safari.
|
||||||
|
*/
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: 0.67em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grouping content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in Firefox.
|
||||||
|
* 2. Show the overflow in Edge and IE.
|
||||||
|
*/
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box;
|
||||||
|
height: 0;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
pre {
|
||||||
|
font-family: monospace, monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text-level semantics
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the gray background on active links in IE 10.
|
||||||
|
*/
|
||||||
|
a {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Remove the bottom border in Chrome 57-
|
||||||
|
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||||
|
*/
|
||||||
|
abbr[title] {
|
||||||
|
border-bottom: none;
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration: underline dotted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||||
|
*/
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: monospace, monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font size in all browsers.
|
||||||
|
*/
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||||
|
* all browsers.
|
||||||
|
*/
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Embedded content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the border on images inside links in IE 10.
|
||||||
|
*/
|
||||||
|
img {
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forms
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Change the font styles in all browsers.
|
||||||
|
* 2. Remove the margin in Firefox and Safari.
|
||||||
|
*/
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
optgroup,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: 100%;
|
||||||
|
line-height: 1.15;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the overflow in IE.
|
||||||
|
* 1. Show the overflow in Edge.
|
||||||
|
*/
|
||||||
|
button,
|
||||||
|
input {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||||
|
* 1. Remove the inheritance of text transform in Firefox.
|
||||||
|
*/
|
||||||
|
button,
|
||||||
|
select {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
*/
|
||||||
|
button,
|
||||||
|
[type="button"],
|
||||||
|
[type="reset"],
|
||||||
|
[type="submit"] {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner border and padding in Firefox.
|
||||||
|
*/
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
[type="button"]::-moz-focus-inner,
|
||||||
|
[type="reset"]::-moz-focus-inner,
|
||||||
|
[type="submit"]::-moz-focus-inner {
|
||||||
|
border-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the focus styles unset by the previous rule.
|
||||||
|
*/
|
||||||
|
button:-moz-focusring,
|
||||||
|
[type="button"]:-moz-focusring,
|
||||||
|
[type="reset"]:-moz-focusring,
|
||||||
|
[type="submit"]:-moz-focusring {
|
||||||
|
outline: 1px dotted ButtonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the padding in Firefox.
|
||||||
|
*/
|
||||||
|
fieldset {
|
||||||
|
padding: 0.35em 0.75em 0.625em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the text wrapping in Edge and IE.
|
||||||
|
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||||
|
* 3. Remove the padding so developers are not caught out when they zero out
|
||||||
|
* `fieldset` elements in all browsers.
|
||||||
|
*/
|
||||||
|
legend {
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: inherit;
|
||||||
|
display: table;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||||
|
*/
|
||||||
|
progress {
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the default vertical scrollbar in IE 10+.
|
||||||
|
*/
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in IE 10.
|
||||||
|
* 2. Remove the padding in IE 10.
|
||||||
|
*/
|
||||||
|
[type="checkbox"],
|
||||||
|
[type="radio"] {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||||
|
*/
|
||||||
|
[type="number"]::-webkit-inner-spin-button,
|
||||||
|
[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the odd appearance in Chrome and Safari.
|
||||||
|
* 2. Correct the outline style in Safari.
|
||||||
|
*/
|
||||||
|
[type="search"] {
|
||||||
|
-webkit-appearance: textfield;
|
||||||
|
outline-offset: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner padding in Chrome and Safari on macOS.
|
||||||
|
*/
|
||||||
|
[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
* 2. Change font properties to `inherit` in Safari.
|
||||||
|
*/
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interactive
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in Edge, IE 10+, and Firefox.
|
||||||
|
*/
|
||||||
|
details {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in all browsers.
|
||||||
|
*/
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Misc
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 10+.
|
||||||
|
*/
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 10.
|
||||||
|
*/
|
||||||
|
[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Box sizing
|
||||||
|
--------------------------------------------- */
|
||||||
|
|
||||||
|
/* Inherit box-sizing to more easily change it's value on a component level.
|
||||||
|
@link http://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/ */
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
# Base
|
||||||
|
--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Typography
|
||||||
|
--------------------------------------------- */
|
||||||
|
body,
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
optgroup,
|
||||||
|
textarea {
|
||||||
|
color: #404040;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
dfn,
|
||||||
|
cite,
|
||||||
|
em,
|
||||||
|
i {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin: 0 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
address {
|
||||||
|
margin: 0 0 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
background: #eee;
|
||||||
|
font-family: "Courier 10 Pitch", courier, monospace;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: 1.6em;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 1.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
tt,
|
||||||
|
var {
|
||||||
|
font-family: monaco, consolas, "Andale Mono", "DejaVu Sans Mono", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
abbr,
|
||||||
|
acronym {
|
||||||
|
border-bottom: 1px dotted #666;
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
|
||||||
|
mark,
|
||||||
|
ins {
|
||||||
|
background: #fff9c0;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
big {
|
||||||
|
font-size: 125%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Elements
|
||||||
|
--------------------------------------------- */
|
||||||
|
body {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
background-color: #ccc;
|
||||||
|
border: 0;
|
||||||
|
height: 1px;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
margin: 0 0 1.5em 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: disc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol {
|
||||||
|
list-style: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
li > ul,
|
||||||
|
li > ol {
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-left: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd {
|
||||||
|
margin: 0 1.5em 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure embeds and iframes fit their containers. */
|
||||||
|
embed,
|
||||||
|
iframe,
|
||||||
|
object {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
margin: 0 0 1.5em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Links
|
||||||
|
--------------------------------------------- */
|
||||||
|
a {
|
||||||
|
color: #4169e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
color: #800080;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover,
|
||||||
|
a:focus,
|
||||||
|
a:active {
|
||||||
|
color: #191970;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:focus {
|
||||||
|
outline: thin dotted;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover,
|
||||||
|
a:active {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forms
|
||||||
|
--------------------------------------------- */
|
||||||
|
button,
|
||||||
|
input[type="button"],
|
||||||
|
input[type="reset"],
|
||||||
|
input[type="submit"] {
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: #ccc #ccc #bbb;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: #e6e6e6;
|
||||||
|
color: rgba(0, 0, 0, 0.8);
|
||||||
|
line-height: 1;
|
||||||
|
padding: 0.6em 1em 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover,
|
||||||
|
input[type="button"]:hover,
|
||||||
|
input[type="reset"]:hover,
|
||||||
|
input[type="submit"]:hover {
|
||||||
|
border-color: #ccc #bbb #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:active,
|
||||||
|
button:focus,
|
||||||
|
input[type="button"]:active,
|
||||||
|
input[type="button"]:focus,
|
||||||
|
input[type="reset"]:active,
|
||||||
|
input[type="reset"]:focus,
|
||||||
|
input[type="submit"]:active,
|
||||||
|
input[type="submit"]:focus {
|
||||||
|
border-color: #aaa #bbb #bbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"],
|
||||||
|
input[type="email"],
|
||||||
|
input[type="url"],
|
||||||
|
input[type="password"],
|
||||||
|
input[type="search"],
|
||||||
|
input[type="number"],
|
||||||
|
input[type="tel"],
|
||||||
|
input[type="range"],
|
||||||
|
input[type="date"],
|
||||||
|
input[type="month"],
|
||||||
|
input[type="week"],
|
||||||
|
input[type="time"],
|
||||||
|
input[type="datetime"],
|
||||||
|
input[type="datetime-local"],
|
||||||
|
input[type="color"],
|
||||||
|
textarea {
|
||||||
|
color: #666;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"]:focus,
|
||||||
|
input[type="email"]:focus,
|
||||||
|
input[type="url"]:focus,
|
||||||
|
input[type="password"]:focus,
|
||||||
|
input[type="search"]:focus,
|
||||||
|
input[type="number"]:focus,
|
||||||
|
input[type="tel"]:focus,
|
||||||
|
input[type="range"]:focus,
|
||||||
|
input[type="date"]:focus,
|
||||||
|
input[type="month"]:focus,
|
||||||
|
input[type="week"]:focus,
|
||||||
|
input[type="time"]:focus,
|
||||||
|
input[type="datetime"]:focus,
|
||||||
|
input[type="datetime-local"]:focus,
|
||||||
|
input[type="color"]:focus,
|
||||||
|
textarea:focus {
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
# Layouts
|
||||||
|
--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
# Components
|
||||||
|
--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Navigation
|
||||||
|
--------------------------------------------- */
|
||||||
|
.main-navigation {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation ul {
|
||||||
|
display: none;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation ul ul {
|
||||||
|
box-shadow: 0 3px 3px rgba(0, 0, 0, 0.2);
|
||||||
|
float: left;
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: -999em;
|
||||||
|
z-index: 99999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation ul ul ul {
|
||||||
|
left: -999em;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation ul ul li:hover > ul,
|
||||||
|
.main-navigation ul ul li.focus > ul {
|
||||||
|
display: block;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation ul ul a {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation ul li:hover > ul,
|
||||||
|
.main-navigation ul li.focus > ul {
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation li {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation a {
|
||||||
|
display: block;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small menu. */
|
||||||
|
.menu-toggle,
|
||||||
|
.main-navigation.toggled ul {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 37.5em) {
|
||||||
|
|
||||||
|
.menu-toggle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-navigation ul {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-main .comment-navigation,
|
||||||
|
.site-main
|
||||||
|
.posts-navigation,
|
||||||
|
.site-main
|
||||||
|
.post-navigation {
|
||||||
|
margin: 0 0 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-navigation .nav-links,
|
||||||
|
.posts-navigation .nav-links,
|
||||||
|
.post-navigation .nav-links {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-navigation .nav-previous,
|
||||||
|
.posts-navigation .nav-previous,
|
||||||
|
.post-navigation .nav-previous {
|
||||||
|
flex: 1 0 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-navigation .nav-next,
|
||||||
|
.posts-navigation .nav-next,
|
||||||
|
.post-navigation .nav-next {
|
||||||
|
text-align: end;
|
||||||
|
flex: 1 0 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Posts and pages
|
||||||
|
--------------------------------------------- */
|
||||||
|
.sticky {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post,
|
||||||
|
.page {
|
||||||
|
margin: 0 0 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.updated:not(.published) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content,
|
||||||
|
.entry-content,
|
||||||
|
.entry-summary {
|
||||||
|
margin: 1.5em 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-links {
|
||||||
|
clear: both;
|
||||||
|
margin: 0 0 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Comments
|
||||||
|
--------------------------------------------- */
|
||||||
|
.comment-content a {
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bypostauthor {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Widgets
|
||||||
|
--------------------------------------------- */
|
||||||
|
.widget {
|
||||||
|
margin: 0 0 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget select {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Media
|
||||||
|
--------------------------------------------- */
|
||||||
|
.page-content .wp-smiley,
|
||||||
|
.entry-content .wp-smiley,
|
||||||
|
.comment-content .wp-smiley {
|
||||||
|
border: none;
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure logo link wraps around logo image. */
|
||||||
|
.custom-logo-link {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Captions
|
||||||
|
--------------------------------------------- */
|
||||||
|
.wp-caption {
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-caption img[class*="wp-image-"] {
|
||||||
|
display: block;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-caption .wp-caption-text {
|
||||||
|
margin: 0.8075em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-caption-text {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Galleries
|
||||||
|
--------------------------------------------- */
|
||||||
|
.gallery {
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-item {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-2 {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-3 {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-4 {
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-5 {
|
||||||
|
grid-template-columns: repeat(5, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-6 {
|
||||||
|
grid-template-columns: repeat(6, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-7 {
|
||||||
|
grid-template-columns: repeat(7, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-8 {
|
||||||
|
grid-template-columns: repeat(8, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-columns-9 {
|
||||||
|
grid-template-columns: repeat(9, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-caption {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
# Plugins
|
||||||
|
--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Jetpack infinite scroll
|
||||||
|
--------------------------------------------- */
|
||||||
|
|
||||||
|
/* Hide the Posts Navigation and the Footer when Infinite Scroll is in use. */
|
||||||
|
.infinite-scroll .posts-navigation,
|
||||||
|
.infinite-scroll.neverending .site-footer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Re-display the Theme Footer when Infinite Scroll has reached its end. */
|
||||||
|
.infinity-end.neverending .site-footer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
# Utilities
|
||||||
|
--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Accessibility
|
||||||
|
--------------------------------------------- */
|
||||||
|
|
||||||
|
/* Text meant only for screen readers. */
|
||||||
|
.screen-reader-text {
|
||||||
|
border: 0;
|
||||||
|
clip: rect(1px, 1px, 1px, 1px);
|
||||||
|
clip-path: inset(50%);
|
||||||
|
height: 1px;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
position: absolute !important;
|
||||||
|
width: 1px;
|
||||||
|
word-wrap: normal !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen-reader-text:focus {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.6);
|
||||||
|
clip: auto !important;
|
||||||
|
clip-path: none;
|
||||||
|
color: #21759b;
|
||||||
|
display: block;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 700;
|
||||||
|
height: auto;
|
||||||
|
left: 5px;
|
||||||
|
line-height: normal;
|
||||||
|
padding: 15px 23px 14px;
|
||||||
|
text-decoration: none;
|
||||||
|
top: 5px;
|
||||||
|
width: auto;
|
||||||
|
z-index: 100000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do not show the outline on the skip link target. */
|
||||||
|
#primary[tabindex="-1"]:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alignments
|
||||||
|
--------------------------------------------- */
|
||||||
|
.alignleft {
|
||||||
|
|
||||||
|
/*rtl:ignore*/
|
||||||
|
float: left;
|
||||||
|
|
||||||
|
/*rtl:ignore*/
|
||||||
|
margin-right: 1.5em;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alignright {
|
||||||
|
|
||||||
|
/*rtl:ignore*/
|
||||||
|
float: right;
|
||||||
|
|
||||||
|
/*rtl:ignore*/
|
||||||
|
margin-left: 1.5em;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aligncenter {
|
||||||
|
clear: both;
|
||||||
|
display: block;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Template part for displaying a message that posts cannot be found
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<section class="no-results not-found">
|
||||||
|
<header class="page-header">
|
||||||
|
<h1 class="page-title"><?php esc_html_e( 'Nothing Found', 'cyywordpress' ); ?></h1>
|
||||||
|
</header><!-- .page-header -->
|
||||||
|
|
||||||
|
<div class="page-content">
|
||||||
|
<?php
|
||||||
|
if ( is_home() && current_user_can( 'publish_posts' ) ) :
|
||||||
|
|
||||||
|
printf(
|
||||||
|
'<p>' . wp_kses(
|
||||||
|
/* translators: 1: link to WP admin new post page. */
|
||||||
|
__( 'Ready to publish your first post? <a href="%1$s">Get started here</a>.', 'cyywordpress' ),
|
||||||
|
array(
|
||||||
|
'a' => array(
|
||||||
|
'href' => array(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
) . '</p>',
|
||||||
|
esc_url( admin_url( 'post-new.php' ) )
|
||||||
|
);
|
||||||
|
|
||||||
|
elseif ( is_search() ) :
|
||||||
|
?>
|
||||||
|
|
||||||
|
<p><?php esc_html_e( 'Sorry, but nothing matched your search terms. Please try again with some different keywords.', 'cyywordpress' ); ?></p>
|
||||||
|
<?php
|
||||||
|
get_search_form();
|
||||||
|
|
||||||
|
else :
|
||||||
|
?>
|
||||||
|
|
||||||
|
<p><?php esc_html_e( 'It seems we can’t find what you’re looking for. Perhaps searching can help.', 'cyywordpress' ); ?></p>
|
||||||
|
<?php
|
||||||
|
get_search_form();
|
||||||
|
|
||||||
|
endif;
|
||||||
|
?>
|
||||||
|
</div><!-- .page-content -->
|
||||||
|
</section><!-- .no-results -->
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Template part for displaying page content in page.php
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
|
||||||
|
<header class="entry-header">
|
||||||
|
<?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
|
||||||
|
</header><!-- .entry-header -->
|
||||||
|
|
||||||
|
<?php cyywordpress_post_thumbnail(); ?>
|
||||||
|
|
||||||
|
<div class="entry-content">
|
||||||
|
<?php
|
||||||
|
the_content();
|
||||||
|
|
||||||
|
wp_link_pages(
|
||||||
|
array(
|
||||||
|
'before' => '<div class="page-links">' . esc_html__( 'Pages:', 'cyywordpress' ),
|
||||||
|
'after' => '</div>',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</div><!-- .entry-content -->
|
||||||
|
|
||||||
|
<?php if ( get_edit_post_link() ) : ?>
|
||||||
|
<footer class="entry-footer">
|
||||||
|
<?php
|
||||||
|
edit_post_link(
|
||||||
|
sprintf(
|
||||||
|
wp_kses(
|
||||||
|
/* translators: %s: Name of current post. Only visible to screen readers */
|
||||||
|
__( 'Edit <span class="screen-reader-text">%s</span>', 'cyywordpress' ),
|
||||||
|
array(
|
||||||
|
'span' => array(
|
||||||
|
'class' => array(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
wp_kses_post( get_the_title() )
|
||||||
|
),
|
||||||
|
'<span class="edit-link">',
|
||||||
|
'</span>'
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</footer><!-- .entry-footer -->
|
||||||
|
<?php endif; ?>
|
||||||
|
</article><!-- #post-<?php the_ID(); ?> -->
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Template part for displaying results in search pages
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
|
||||||
|
<header class="entry-header">
|
||||||
|
<?php the_title( sprintf( '<h2 class="entry-title"><a href="%s" rel="bookmark">', esc_url( get_permalink() ) ), '</a></h2>' ); ?>
|
||||||
|
|
||||||
|
<?php if ( 'post' === get_post_type() ) : ?>
|
||||||
|
<div class="entry-meta">
|
||||||
|
<?php
|
||||||
|
cyywordpress_posted_on();
|
||||||
|
cyywordpress_posted_by();
|
||||||
|
?>
|
||||||
|
</div><!-- .entry-meta -->
|
||||||
|
<?php endif; ?>
|
||||||
|
</header><!-- .entry-header -->
|
||||||
|
|
||||||
|
<?php cyywordpress_post_thumbnail(); ?>
|
||||||
|
|
||||||
|
<div class="entry-summary">
|
||||||
|
<?php the_excerpt(); ?>
|
||||||
|
</div><!-- .entry-summary -->
|
||||||
|
|
||||||
|
<footer class="entry-footer">
|
||||||
|
<?php cyywordpress_entry_footer(); ?>
|
||||||
|
</footer><!-- .entry-footer -->
|
||||||
|
</article><!-- #post-<?php the_ID(); ?> -->
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Template part for displaying posts
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
|
||||||
|
*
|
||||||
|
* @package CyyWordpress
|
||||||
|
*/
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
|
||||||
|
<header class="entry-header">
|
||||||
|
<?php
|
||||||
|
if ( is_singular() ) :
|
||||||
|
the_title( '<h1 class="entry-title">', '</h1>' );
|
||||||
|
else :
|
||||||
|
the_title( '<h2 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' );
|
||||||
|
endif;
|
||||||
|
|
||||||
|
if ( 'post' === get_post_type() ) :
|
||||||
|
?>
|
||||||
|
<div class="entry-meta">
|
||||||
|
<?php
|
||||||
|
cyywordpress_posted_on();
|
||||||
|
cyywordpress_posted_by();
|
||||||
|
?>
|
||||||
|
</div><!-- .entry-meta -->
|
||||||
|
<?php endif; ?>
|
||||||
|
</header><!-- .entry-header -->
|
||||||
|
|
||||||
|
<?php cyywordpress_post_thumbnail(); ?>
|
||||||
|
|
||||||
|
<div class="entry-content">
|
||||||
|
<?php
|
||||||
|
the_content(
|
||||||
|
sprintf(
|
||||||
|
wp_kses(
|
||||||
|
/* translators: %s: Name of current post. Only visible to screen readers */
|
||||||
|
__( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'cyywordpress' ),
|
||||||
|
array(
|
||||||
|
'span' => array(
|
||||||
|
'class' => array(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
wp_kses_post( get_the_title() )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
wp_link_pages(
|
||||||
|
array(
|
||||||
|
'before' => '<div class="page-links">' . esc_html__( 'Pages:', 'cyywordpress' ),
|
||||||
|
'after' => '</div>',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</div><!-- .entry-content -->
|
||||||
|
|
||||||
|
<footer class="entry-footer">
|
||||||
|
<?php cyywordpress_entry_footer(); ?>
|
||||||
|
</footer><!-- .entry-footer -->
|
||||||
|
</article><!-- #post-<?php the_ID(); ?> -->
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload.php @generated by Composer
|
||||||
|
|
||||||
|
require_once __DIR__ . '/composer/autoload_real.php';
|
||||||
|
|
||||||
|
return ComposerAutoloaderInit4def2de59a6f8d56a69341afa83adef3::getLoader();
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
dir=$(cd "${0%[/\\]*}" > /dev/null; cd "../gettext/languages/bin" && pwd)
|
||||||
|
|
||||||
|
if [ -d /proc/cygdrive ]; then
|
||||||
|
case $(which php) in
|
||||||
|
$(readlink -n /proc/cygdrive)/*)
|
||||||
|
# We are in Cygwin using Windows php, so the path must be translated
|
||||||
|
dir=$(cygpath -m "$dir");
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
"${dir}/export-plural-rules" "$@"
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
setlocal DISABLEDELAYEDEXPANSION
|
||||||
|
SET BIN_TARGET=%~dp0/../gettext/languages/bin/export-plural-rules
|
||||||
|
php "%BIN_TARGET%" %*
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
dir=$(cd "${0%[/\\]*}" > /dev/null; cd "../php-parallel-lint/php-parallel-lint" && pwd)
|
||||||
|
|
||||||
|
if [ -d /proc/cygdrive ]; then
|
||||||
|
case $(which php) in
|
||||||
|
$(readlink -n /proc/cygdrive)/*)
|
||||||
|
# We are in Cygwin using Windows php, so the path must be translated
|
||||||
|
dir=$(cygpath -m "$dir");
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
"${dir}/parallel-lint" "$@"
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
setlocal DISABLEDELAYEDEXPANSION
|
||||||
|
SET BIN_TARGET=%~dp0/../php-parallel-lint/php-parallel-lint/parallel-lint
|
||||||
|
php "%BIN_TARGET%" %*
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
dir=$(cd "${0%[/\\]*}" > /dev/null; cd "../squizlabs/php_codesniffer/bin" && pwd)
|
||||||
|
|
||||||
|
if [ -d /proc/cygdrive ]; then
|
||||||
|
case $(which php) in
|
||||||
|
$(readlink -n /proc/cygdrive)/*)
|
||||||
|
# We are in Cygwin using Windows php, so the path must be translated
|
||||||
|
dir=$(cygpath -m "$dir");
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
"${dir}/phpcbf" "$@"
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
setlocal DISABLEDELAYEDEXPANSION
|
||||||
|
SET BIN_TARGET=%~dp0/../squizlabs/php_codesniffer/bin/phpcbf
|
||||||
|
php "%BIN_TARGET%" %*
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
dir=$(cd "${0%[/\\]*}" > /dev/null; cd "../squizlabs/php_codesniffer/bin" && pwd)
|
||||||
|
|
||||||
|
if [ -d /proc/cygdrive ]; then
|
||||||
|
case $(which php) in
|
||||||
|
$(readlink -n /proc/cygdrive)/*)
|
||||||
|
# We are in Cygwin using Windows php, so the path must be translated
|
||||||
|
dir=$(cygpath -m "$dir");
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
"${dir}/phpcs" "$@"
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
setlocal DISABLEDELAYEDEXPANSION
|
||||||
|
SET BIN_TARGET=%~dp0/../squizlabs/php_codesniffer/bin/phpcs
|
||||||
|
php "%BIN_TARGET%" %*
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
dir=$(cd "${0%[/\\]*}" > /dev/null; cd "../wp-cli/wp-cli/bin" && pwd)
|
||||||
|
|
||||||
|
if [ -d /proc/cygdrive ]; then
|
||||||
|
case $(which php) in
|
||||||
|
$(readlink -n /proc/cygdrive)/*)
|
||||||
|
# We are in Cygwin using Windows php, so the path must be translated
|
||||||
|
dir=$(cygpath -m "$dir");
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
"${dir}/wp" "$@"
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
setlocal DISABLEDELAYEDEXPANSION
|
||||||
|
SET BIN_TARGET=%~dp0/../wp-cli/wp-cli/bin/wp
|
||||||
|
sh "%BIN_TARGET%" %*
|
||||||
Vendored
+477
@@ -0,0 +1,477 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||||
|
*
|
||||||
|
* $loader = new \Composer\Autoload\ClassLoader();
|
||||||
|
*
|
||||||
|
* // register classes with namespaces
|
||||||
|
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||||
|
* $loader->add('Symfony', __DIR__.'/framework');
|
||||||
|
*
|
||||||
|
* // activate the autoloader
|
||||||
|
* $loader->register();
|
||||||
|
*
|
||||||
|
* // to enable searching the include path (eg. for PEAR packages)
|
||||||
|
* $loader->setUseIncludePath(true);
|
||||||
|
*
|
||||||
|
* In this example, if you try to use a class in the Symfony\Component
|
||||||
|
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||||
|
* the autoloader will first look for the class under the component/
|
||||||
|
* directory, and it will then fallback to the framework/ directory if not
|
||||||
|
* found before giving up.
|
||||||
|
*
|
||||||
|
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
* @see https://www.php-fig.org/psr/psr-0/
|
||||||
|
* @see https://www.php-fig.org/psr/psr-4/
|
||||||
|
*/
|
||||||
|
class ClassLoader
|
||||||
|
{
|
||||||
|
private $vendorDir;
|
||||||
|
|
||||||
|
// PSR-4
|
||||||
|
private $prefixLengthsPsr4 = array();
|
||||||
|
private $prefixDirsPsr4 = array();
|
||||||
|
private $fallbackDirsPsr4 = array();
|
||||||
|
|
||||||
|
// PSR-0
|
||||||
|
private $prefixesPsr0 = array();
|
||||||
|
private $fallbackDirsPsr0 = array();
|
||||||
|
|
||||||
|
private $useIncludePath = false;
|
||||||
|
private $classMap = array();
|
||||||
|
private $classMapAuthoritative = false;
|
||||||
|
private $missingClasses = array();
|
||||||
|
private $apcuPrefix;
|
||||||
|
|
||||||
|
private static $registeredLoaders = array();
|
||||||
|
|
||||||
|
public function __construct($vendorDir = null)
|
||||||
|
{
|
||||||
|
$this->vendorDir = $vendorDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPrefixes()
|
||||||
|
{
|
||||||
|
if (!empty($this->prefixesPsr0)) {
|
||||||
|
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPrefixesPsr4()
|
||||||
|
{
|
||||||
|
return $this->prefixDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFallbackDirs()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFallbackDirsPsr4()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClassMap()
|
||||||
|
{
|
||||||
|
return $this->classMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $classMap Class to filename map
|
||||||
|
*/
|
||||||
|
public function addClassMap(array $classMap)
|
||||||
|
{
|
||||||
|
if ($this->classMap) {
|
||||||
|
$this->classMap = array_merge($this->classMap, $classMap);
|
||||||
|
} else {
|
||||||
|
$this->classMap = $classMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix, either
|
||||||
|
* appending or prepending to the ones previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param array|string $paths The PSR-0 root directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*/
|
||||||
|
public function add($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->fallbackDirsPsr0
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
$this->fallbackDirsPsr0,
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$first = $prefix[0];
|
||||||
|
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($prepend) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->prefixesPsr0[$first][$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
$this->prefixesPsr0[$first][$prefix],
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace, either
|
||||||
|
* appending or prepending to the ones previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param array|string $paths The PSR-4 base directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function addPsr4($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
// Register directories for the root namespace.
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->fallbackDirsPsr4
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
$this->fallbackDirsPsr4,
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||||
|
// Register directories for a new namespace.
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||||
|
} elseif ($prepend) {
|
||||||
|
// Prepend directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->prefixDirsPsr4[$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Append directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
$this->prefixDirsPsr4[$prefix],
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix,
|
||||||
|
* replacing any others previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param array|string $paths The PSR-0 base directories
|
||||||
|
*/
|
||||||
|
public function set($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr0 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace,
|
||||||
|
* replacing any others previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param array|string $paths The PSR-4 base directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setPsr4($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr4 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns on searching the include path for class files.
|
||||||
|
*
|
||||||
|
* @param bool $useIncludePath
|
||||||
|
*/
|
||||||
|
public function setUseIncludePath($useIncludePath)
|
||||||
|
{
|
||||||
|
$this->useIncludePath = $useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used to check if the autoloader uses the include path to check
|
||||||
|
* for classes.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getUseIncludePath()
|
||||||
|
{
|
||||||
|
return $this->useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns off searching the prefix and fallback directories for classes
|
||||||
|
* that have not been registered with the class map.
|
||||||
|
*
|
||||||
|
* @param bool $classMapAuthoritative
|
||||||
|
*/
|
||||||
|
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||||
|
{
|
||||||
|
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should class lookup fail if not found in the current class map?
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isClassMapAuthoritative()
|
||||||
|
{
|
||||||
|
return $this->classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||||
|
*
|
||||||
|
* @param string|null $apcuPrefix
|
||||||
|
*/
|
||||||
|
public function setApcuPrefix($apcuPrefix)
|
||||||
|
{
|
||||||
|
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getApcuPrefix()
|
||||||
|
{
|
||||||
|
return $this->apcuPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @param bool $prepend Whether to prepend the autoloader or not
|
||||||
|
*/
|
||||||
|
public function register($prepend = false)
|
||||||
|
{
|
||||||
|
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||||
|
|
||||||
|
if (null === $this->vendorDir) {
|
||||||
|
//no-op
|
||||||
|
} elseif ($prepend) {
|
||||||
|
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||||
|
} else {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters this instance as an autoloader.
|
||||||
|
*/
|
||||||
|
public function unregister()
|
||||||
|
{
|
||||||
|
spl_autoload_unregister(array($this, 'loadClass'));
|
||||||
|
|
||||||
|
if (null !== $this->vendorDir) {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the given class or interface.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
* @return bool|null True if loaded, null otherwise
|
||||||
|
*/
|
||||||
|
public function loadClass($class)
|
||||||
|
{
|
||||||
|
if ($file = $this->findFile($class)) {
|
||||||
|
includeFile($file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the path to the file where the class is defined.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
*
|
||||||
|
* @return string|false The path if found, false otherwise
|
||||||
|
*/
|
||||||
|
public function findFile($class)
|
||||||
|
{
|
||||||
|
// class map lookup
|
||||||
|
if (isset($this->classMap[$class])) {
|
||||||
|
return $this->classMap[$class];
|
||||||
|
}
|
||||||
|
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||||
|
if ($hit) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $this->findFileWithExtension($class, '.php');
|
||||||
|
|
||||||
|
// Search for Hack files if we are running on HHVM
|
||||||
|
if (false === $file && defined('HHVM_VERSION')) {
|
||||||
|
$file = $this->findFileWithExtension($class, '.hh');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
apcu_add($this->apcuPrefix.$class, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $file) {
|
||||||
|
// Remember that this class does not exist.
|
||||||
|
$this->missingClasses[$class] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently registered loaders indexed by their corresponding vendor directories.
|
||||||
|
*
|
||||||
|
* @return self[]
|
||||||
|
*/
|
||||||
|
public static function getRegisteredLoaders()
|
||||||
|
{
|
||||||
|
return self::$registeredLoaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function findFileWithExtension($class, $ext)
|
||||||
|
{
|
||||||
|
// PSR-4 lookup
|
||||||
|
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
|
||||||
|
$first = $class[0];
|
||||||
|
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||||
|
$subPath = $class;
|
||||||
|
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||||
|
$subPath = substr($subPath, 0, $lastPos);
|
||||||
|
$search = $subPath . '\\';
|
||||||
|
if (isset($this->prefixDirsPsr4[$search])) {
|
||||||
|
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||||
|
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||||
|
if (file_exists($file = $dir . $pathEnd)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-4 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 lookup
|
||||||
|
if (false !== $pos = strrpos($class, '\\')) {
|
||||||
|
// namespaced class name
|
||||||
|
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||||
|
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||||
|
} else {
|
||||||
|
// PEAR-like class name
|
||||||
|
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->prefixesPsr0[$first])) {
|
||||||
|
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||||
|
if (0 === strpos($class, $prefix)) {
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 include paths.
|
||||||
|
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope isolated include.
|
||||||
|
*
|
||||||
|
* Prevents access to $this/self from included files.
|
||||||
|
*/
|
||||||
|
function includeFile($file)
|
||||||
|
{
|
||||||
|
include $file;
|
||||||
|
}
|
||||||
+460
@@ -0,0 +1,460 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace Composer;
|
||||||
|
|
||||||
|
use Composer\Autoload\ClassLoader;
|
||||||
|
use Composer\Semver\VersionParser;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class InstalledVersions
|
||||||
|
{
|
||||||
|
private static $installed = array (
|
||||||
|
'root' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '1.0.0+no-version-set',
|
||||||
|
'version' => '1.0.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => NULL,
|
||||||
|
'name' => 'automattic/underscores',
|
||||||
|
),
|
||||||
|
'versions' =>
|
||||||
|
array (
|
||||||
|
'automattic/underscores' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '1.0.0+no-version-set',
|
||||||
|
'version' => '1.0.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => NULL,
|
||||||
|
),
|
||||||
|
'dealerdirect/phpcodesniffer-composer-installer' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v0.7.1',
|
||||||
|
'version' => '0.7.1.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => 'fe390591e0241955f22eb9ba327d137e501c771c',
|
||||||
|
),
|
||||||
|
'gettext/gettext' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v4.8.3',
|
||||||
|
'version' => '4.8.3.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '57ff4fb16647e78e80a5909fe3c190f1c3110321',
|
||||||
|
),
|
||||||
|
'gettext/languages' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '2.6.0',
|
||||||
|
'version' => '2.6.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '38ea0482f649e0802e475f0ed19fa993bcb7a618',
|
||||||
|
),
|
||||||
|
'grogy/php-parallel-lint' =>
|
||||||
|
array (
|
||||||
|
'replaced' =>
|
||||||
|
array (
|
||||||
|
0 => '*',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'jakub-onderka/php-parallel-lint' =>
|
||||||
|
array (
|
||||||
|
'replaced' =>
|
||||||
|
array (
|
||||||
|
0 => '*',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'mck89/peast' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v1.12.0',
|
||||||
|
'version' => '1.12.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '833be7a294627a8c5b1c482cbf489f73bf9b8086',
|
||||||
|
),
|
||||||
|
'mustache/mustache' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v2.13.0',
|
||||||
|
'version' => '2.13.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => 'e95c5a008c23d3151d59ea72484d4f72049ab7f4',
|
||||||
|
),
|
||||||
|
'php-parallel-lint/php-parallel-lint' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v1.2.0',
|
||||||
|
'version' => '1.2.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '474f18bc6cc6aca61ca40bfab55139de614e51ca',
|
||||||
|
),
|
||||||
|
'phpcompatibility/php-compatibility' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '9.3.5',
|
||||||
|
'version' => '9.3.5.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '9fb324479acf6f39452e0655d2429cc0d3914243',
|
||||||
|
),
|
||||||
|
'phpcompatibility/phpcompatibility-paragonie' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '1.3.1',
|
||||||
|
'version' => '1.3.1.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => 'ddabec839cc003651f2ce695c938686d1086cf43',
|
||||||
|
),
|
||||||
|
'phpcompatibility/phpcompatibility-wp' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '2.1.1',
|
||||||
|
'version' => '2.1.1.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => 'b7dc0cd7a8f767ccac5e7637550ea1c50a67b09e',
|
||||||
|
),
|
||||||
|
'rmccue/requests' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v1.7.0',
|
||||||
|
'version' => '1.7.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '87932f52ffad70504d93f04f15690cf16a089546',
|
||||||
|
),
|
||||||
|
'squizlabs/php_codesniffer' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '3.5.8',
|
||||||
|
'version' => '3.5.8.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '9d583721a7157ee997f235f327de038e7ea6dac4',
|
||||||
|
),
|
||||||
|
'symfony/finder' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v5.2.3',
|
||||||
|
'version' => '5.2.3.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '4adc8d172d602008c204c2e16956f99257248e03',
|
||||||
|
),
|
||||||
|
'wp-cli/i18n-command' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v2.2.6',
|
||||||
|
'version' => '2.2.6.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => 'a66da3f09f6a728832381012848c3074bf1635c8',
|
||||||
|
),
|
||||||
|
'wp-cli/mustangostang-spyc' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '0.6.3',
|
||||||
|
'version' => '0.6.3.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '6aa0b4da69ce9e9a2c8402dab8d43cf32c581cc7',
|
||||||
|
),
|
||||||
|
'wp-cli/php-cli-tools' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v0.11.11',
|
||||||
|
'version' => '0.11.11.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => 'fe9c7c44a9e1bf2196ec51dc38da0593dbf2993f',
|
||||||
|
),
|
||||||
|
'wp-cli/wp-cli' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v2.4.1',
|
||||||
|
'version' => '2.4.1.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => 'ceb18598e79befa9b2a37a51efbb34910628988b',
|
||||||
|
),
|
||||||
|
'wp-coding-standards/wpcs' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '2.3.0',
|
||||||
|
'version' => '2.3.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '7da1894633f168fe244afc6de00d141f27517b62',
|
||||||
|
),
|
||||||
|
'wptrt/wpthemereview' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '0.2.1',
|
||||||
|
'version' => '0.2.1.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '462e59020dad9399ed2fe8e61f2a21b5e206e420',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
private static $canGetVendors;
|
||||||
|
private static $installedByVendor = array();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static function getInstalledPackages()
|
||||||
|
{
|
||||||
|
$packages = array();
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
$packages[] = array_keys($installed['versions']);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (1 === \count($packages)) {
|
||||||
|
return $packages[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static function isInstalled($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (isset($installed['versions'][$packageName])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||||
|
{
|
||||||
|
$constraint = $parser->parseConstraints($constraint);
|
||||||
|
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||||
|
|
||||||
|
return $provided->matches($constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static function getVersionRanges($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ranges = array();
|
||||||
|
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
|
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(' || ', $ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static function getVersion($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static function getPrettyVersion($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['pretty_version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static function getReference($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['reference'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static function getRootPackage()
|
||||||
|
{
|
||||||
|
$installed = self::getInstalled();
|
||||||
|
|
||||||
|
return $installed[0]['root'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static function getRawData()
|
||||||
|
{
|
||||||
|
return self::$installed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static function reload($data)
|
||||||
|
{
|
||||||
|
self::$installed = $data;
|
||||||
|
self::$installedByVendor = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static function getInstalled()
|
||||||
|
{
|
||||||
|
if (null === self::$canGetVendors) {
|
||||||
|
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||||
|
}
|
||||||
|
|
||||||
|
$installed = array();
|
||||||
|
|
||||||
|
if (self::$canGetVendors) {
|
||||||
|
|
||||||
|
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||||
|
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir];
|
||||||
|
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$installed[] = self::$installed;
|
||||||
|
|
||||||
|
return $installed;
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+21
@@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_classmap.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(dirname(__FILE__));
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Application' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Application.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\ArrayIterator' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Settings.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Blame' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Error.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\CheckstyleOutput' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\ConsoleWriter' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Error' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Error.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\ErrorFormatter' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/ErrorFormatter.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Exception' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/exceptions.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\FileWriter' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\IWriter' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\InvalidArgumentException' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/exceptions.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\JsonOutput' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Manager' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Manager.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\MultipleWriter' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\NotExistsPathException' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/exceptions.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\NullWriter' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Output' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\ParallelLint' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/ParallelLint.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Process\\GitBlameProcess' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Process/GitBlameProcess.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Process\\LintProcess' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Process/LintProcess.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Process\\PhpExecutable' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Process/PhpExecutable.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Process\\PhpProcess' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Process/PhpProcess.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Process\\Process' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Process/Process.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Process\\SkipLintProcess' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Process/SkipLintProcess.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\RecursiveDirectoryFilterIterator' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Manager.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Result' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Result.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\RunTimeException' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/exceptions.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Settings' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Settings.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\SyntaxError' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Error.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\TextOutput' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\TextOutputColored' => $vendorDir . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
);
|
||||||
Vendored
+12
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_files.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(dirname(__FILE__));
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'be01b9b16925dcb22165c40b46681ac6' => $vendorDir . '/wp-cli/php-cli-tools/lib/cli/cli.php',
|
||||||
|
'3937806105cc8e221b8fa8db5b70d2f2' => $vendorDir . '/wp-cli/mustangostang-spyc/includes/functions.php',
|
||||||
|
'ffb465a494c3101218c4417180c2c9a2' => $vendorDir . '/wp-cli/i18n-command/i18n-command.php',
|
||||||
|
);
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_namespaces.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(dirname(__FILE__));
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'cli' => array($vendorDir . '/wp-cli/php-cli-tools/lib'),
|
||||||
|
'WP_CLI' => array($vendorDir . '/wp-cli/wp-cli/php'),
|
||||||
|
'Requests' => array($vendorDir . '/rmccue/requests/library'),
|
||||||
|
'Mustache' => array($vendorDir . '/mustache/mustache/src'),
|
||||||
|
);
|
||||||
Vendored
+17
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_psr4.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(dirname(__FILE__));
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'WP_CLI\\I18n\\' => array($vendorDir . '/wp-cli/i18n-command/src'),
|
||||||
|
'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
|
||||||
|
'Peast\\test\\' => array($vendorDir . '/mck89/peast/test/Peast'),
|
||||||
|
'Peast\\' => array($vendorDir . '/mck89/peast/lib/Peast'),
|
||||||
|
'Mustangostang\\' => array($vendorDir . '/wp-cli/mustangostang-spyc/src'),
|
||||||
|
'Gettext\\Languages\\' => array($vendorDir . '/gettext/languages/src'),
|
||||||
|
'Gettext\\' => array($vendorDir . '/gettext/gettext/src'),
|
||||||
|
'Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\' => array($vendorDir . '/dealerdirect/phpcodesniffer-composer-installer/src'),
|
||||||
|
);
|
||||||
Vendored
+75
@@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_real.php @generated by Composer
|
||||||
|
|
||||||
|
class ComposerAutoloaderInit4def2de59a6f8d56a69341afa83adef3
|
||||||
|
{
|
||||||
|
private static $loader;
|
||||||
|
|
||||||
|
public static function loadClassLoader($class)
|
||||||
|
{
|
||||||
|
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||||
|
require __DIR__ . '/ClassLoader.php';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Composer\Autoload\ClassLoader
|
||||||
|
*/
|
||||||
|
public static function getLoader()
|
||||||
|
{
|
||||||
|
if (null !== self::$loader) {
|
||||||
|
return self::$loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
require __DIR__ . '/platform_check.php';
|
||||||
|
|
||||||
|
spl_autoload_register(array('ComposerAutoloaderInit4def2de59a6f8d56a69341afa83adef3', 'loadClassLoader'), true, true);
|
||||||
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
|
||||||
|
spl_autoload_unregister(array('ComposerAutoloaderInit4def2de59a6f8d56a69341afa83adef3', 'loadClassLoader'));
|
||||||
|
|
||||||
|
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||||
|
if ($useStaticLoader) {
|
||||||
|
require __DIR__ . '/autoload_static.php';
|
||||||
|
|
||||||
|
call_user_func(\Composer\Autoload\ComposerStaticInit4def2de59a6f8d56a69341afa83adef3::getInitializer($loader));
|
||||||
|
} else {
|
||||||
|
$map = require __DIR__ . '/autoload_namespaces.php';
|
||||||
|
foreach ($map as $namespace => $path) {
|
||||||
|
$loader->set($namespace, $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$map = require __DIR__ . '/autoload_psr4.php';
|
||||||
|
foreach ($map as $namespace => $path) {
|
||||||
|
$loader->setPsr4($namespace, $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$classMap = require __DIR__ . '/autoload_classmap.php';
|
||||||
|
if ($classMap) {
|
||||||
|
$loader->addClassMap($classMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$loader->register(true);
|
||||||
|
|
||||||
|
if ($useStaticLoader) {
|
||||||
|
$includeFiles = Composer\Autoload\ComposerStaticInit4def2de59a6f8d56a69341afa83adef3::$files;
|
||||||
|
} else {
|
||||||
|
$includeFiles = require __DIR__ . '/autoload_files.php';
|
||||||
|
}
|
||||||
|
foreach ($includeFiles as $fileIdentifier => $file) {
|
||||||
|
composerRequire4def2de59a6f8d56a69341afa83adef3($fileIdentifier, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $loader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function composerRequire4def2de59a6f8d56a69341afa83adef3($fileIdentifier, $file)
|
||||||
|
{
|
||||||
|
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||||
|
require $file;
|
||||||
|
|
||||||
|
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+155
@@ -0,0 +1,155 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_static.php @generated by Composer
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
class ComposerStaticInit4def2de59a6f8d56a69341afa83adef3
|
||||||
|
{
|
||||||
|
public static $files = array (
|
||||||
|
'be01b9b16925dcb22165c40b46681ac6' => __DIR__ . '/..' . '/wp-cli/php-cli-tools/lib/cli/cli.php',
|
||||||
|
'3937806105cc8e221b8fa8db5b70d2f2' => __DIR__ . '/..' . '/wp-cli/mustangostang-spyc/includes/functions.php',
|
||||||
|
'ffb465a494c3101218c4417180c2c9a2' => __DIR__ . '/..' . '/wp-cli/i18n-command/i18n-command.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixLengthsPsr4 = array (
|
||||||
|
'W' =>
|
||||||
|
array (
|
||||||
|
'WP_CLI\\I18n\\' => 12,
|
||||||
|
),
|
||||||
|
'S' =>
|
||||||
|
array (
|
||||||
|
'Symfony\\Component\\Finder\\' => 25,
|
||||||
|
),
|
||||||
|
'P' =>
|
||||||
|
array (
|
||||||
|
'Peast\\test\\' => 11,
|
||||||
|
'Peast\\' => 6,
|
||||||
|
),
|
||||||
|
'M' =>
|
||||||
|
array (
|
||||||
|
'Mustangostang\\' => 14,
|
||||||
|
),
|
||||||
|
'G' =>
|
||||||
|
array (
|
||||||
|
'Gettext\\Languages\\' => 18,
|
||||||
|
'Gettext\\' => 8,
|
||||||
|
),
|
||||||
|
'D' =>
|
||||||
|
array (
|
||||||
|
'Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\' => 55,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixDirsPsr4 = array (
|
||||||
|
'WP_CLI\\I18n\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/wp-cli/i18n-command/src',
|
||||||
|
),
|
||||||
|
'Symfony\\Component\\Finder\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/symfony/finder',
|
||||||
|
),
|
||||||
|
'Peast\\test\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/mck89/peast/test/Peast',
|
||||||
|
),
|
||||||
|
'Peast\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/mck89/peast/lib/Peast',
|
||||||
|
),
|
||||||
|
'Mustangostang\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/wp-cli/mustangostang-spyc/src',
|
||||||
|
),
|
||||||
|
'Gettext\\Languages\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/gettext/languages/src',
|
||||||
|
),
|
||||||
|
'Gettext\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/gettext/gettext/src',
|
||||||
|
),
|
||||||
|
'Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/dealerdirect/phpcodesniffer-composer-installer/src',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixesPsr0 = array (
|
||||||
|
'c' =>
|
||||||
|
array (
|
||||||
|
'cli' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/wp-cli/php-cli-tools/lib',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'W' =>
|
||||||
|
array (
|
||||||
|
'WP_CLI' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/wp-cli/wp-cli/php',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'R' =>
|
||||||
|
array (
|
||||||
|
'Requests' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/rmccue/requests/library',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'M' =>
|
||||||
|
array (
|
||||||
|
'Mustache' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/mustache/mustache/src',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $classMap = array (
|
||||||
|
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Application' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Application.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\ArrayIterator' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Settings.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Blame' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Error.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\CheckstyleOutput' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\ConsoleWriter' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Error' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Error.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\ErrorFormatter' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/ErrorFormatter.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Exception' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/exceptions.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\FileWriter' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\IWriter' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\InvalidArgumentException' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/exceptions.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\JsonOutput' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Manager' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Manager.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\MultipleWriter' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\NotExistsPathException' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/exceptions.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\NullWriter' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Output' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\ParallelLint' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/ParallelLint.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Process\\GitBlameProcess' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Process/GitBlameProcess.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Process\\LintProcess' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Process/LintProcess.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Process\\PhpExecutable' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Process/PhpExecutable.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Process\\PhpProcess' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Process/PhpProcess.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Process\\Process' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Process/Process.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Process\\SkipLintProcess' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Process/SkipLintProcess.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\RecursiveDirectoryFilterIterator' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Manager.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Result' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Result.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\RunTimeException' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/exceptions.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\Settings' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Settings.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\SyntaxError' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Error.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\TextOutput' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
'JakubOnderka\\PhpParallelLint\\TextOutputColored' => __DIR__ . '/..' . '/php-parallel-lint/php-parallel-lint/src/Output.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static function getInitializer(ClassLoader $loader)
|
||||||
|
{
|
||||||
|
return \Closure::bind(function () use ($loader) {
|
||||||
|
$loader->prefixLengthsPsr4 = ComposerStaticInit4def2de59a6f8d56a69341afa83adef3::$prefixLengthsPsr4;
|
||||||
|
$loader->prefixDirsPsr4 = ComposerStaticInit4def2de59a6f8d56a69341afa83adef3::$prefixDirsPsr4;
|
||||||
|
$loader->prefixesPsr0 = ComposerStaticInit4def2de59a6f8d56a69341afa83adef3::$prefixesPsr0;
|
||||||
|
$loader->classMap = ComposerStaticInit4def2de59a6f8d56a69341afa83adef3::$classMap;
|
||||||
|
|
||||||
|
}, null, ClassLoader::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+1137
File diff suppressed because it is too large
Load Diff
Vendored
+200
@@ -0,0 +1,200 @@
|
|||||||
|
<?php return array (
|
||||||
|
'root' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '1.0.0+no-version-set',
|
||||||
|
'version' => '1.0.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => NULL,
|
||||||
|
'name' => 'automattic/underscores',
|
||||||
|
),
|
||||||
|
'versions' =>
|
||||||
|
array (
|
||||||
|
'automattic/underscores' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '1.0.0+no-version-set',
|
||||||
|
'version' => '1.0.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => NULL,
|
||||||
|
),
|
||||||
|
'dealerdirect/phpcodesniffer-composer-installer' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v0.7.1',
|
||||||
|
'version' => '0.7.1.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => 'fe390591e0241955f22eb9ba327d137e501c771c',
|
||||||
|
),
|
||||||
|
'gettext/gettext' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v4.8.3',
|
||||||
|
'version' => '4.8.3.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '57ff4fb16647e78e80a5909fe3c190f1c3110321',
|
||||||
|
),
|
||||||
|
'gettext/languages' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '2.6.0',
|
||||||
|
'version' => '2.6.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '38ea0482f649e0802e475f0ed19fa993bcb7a618',
|
||||||
|
),
|
||||||
|
'grogy/php-parallel-lint' =>
|
||||||
|
array (
|
||||||
|
'replaced' =>
|
||||||
|
array (
|
||||||
|
0 => '*',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'jakub-onderka/php-parallel-lint' =>
|
||||||
|
array (
|
||||||
|
'replaced' =>
|
||||||
|
array (
|
||||||
|
0 => '*',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'mck89/peast' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v1.12.0',
|
||||||
|
'version' => '1.12.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '833be7a294627a8c5b1c482cbf489f73bf9b8086',
|
||||||
|
),
|
||||||
|
'mustache/mustache' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v2.13.0',
|
||||||
|
'version' => '2.13.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => 'e95c5a008c23d3151d59ea72484d4f72049ab7f4',
|
||||||
|
),
|
||||||
|
'php-parallel-lint/php-parallel-lint' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v1.2.0',
|
||||||
|
'version' => '1.2.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '474f18bc6cc6aca61ca40bfab55139de614e51ca',
|
||||||
|
),
|
||||||
|
'phpcompatibility/php-compatibility' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '9.3.5',
|
||||||
|
'version' => '9.3.5.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '9fb324479acf6f39452e0655d2429cc0d3914243',
|
||||||
|
),
|
||||||
|
'phpcompatibility/phpcompatibility-paragonie' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '1.3.1',
|
||||||
|
'version' => '1.3.1.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => 'ddabec839cc003651f2ce695c938686d1086cf43',
|
||||||
|
),
|
||||||
|
'phpcompatibility/phpcompatibility-wp' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '2.1.1',
|
||||||
|
'version' => '2.1.1.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => 'b7dc0cd7a8f767ccac5e7637550ea1c50a67b09e',
|
||||||
|
),
|
||||||
|
'rmccue/requests' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v1.7.0',
|
||||||
|
'version' => '1.7.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '87932f52ffad70504d93f04f15690cf16a089546',
|
||||||
|
),
|
||||||
|
'squizlabs/php_codesniffer' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '3.5.8',
|
||||||
|
'version' => '3.5.8.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '9d583721a7157ee997f235f327de038e7ea6dac4',
|
||||||
|
),
|
||||||
|
'symfony/finder' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v5.2.3',
|
||||||
|
'version' => '5.2.3.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '4adc8d172d602008c204c2e16956f99257248e03',
|
||||||
|
),
|
||||||
|
'wp-cli/i18n-command' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v2.2.6',
|
||||||
|
'version' => '2.2.6.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => 'a66da3f09f6a728832381012848c3074bf1635c8',
|
||||||
|
),
|
||||||
|
'wp-cli/mustangostang-spyc' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '0.6.3',
|
||||||
|
'version' => '0.6.3.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '6aa0b4da69ce9e9a2c8402dab8d43cf32c581cc7',
|
||||||
|
),
|
||||||
|
'wp-cli/php-cli-tools' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v0.11.11',
|
||||||
|
'version' => '0.11.11.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => 'fe9c7c44a9e1bf2196ec51dc38da0593dbf2993f',
|
||||||
|
),
|
||||||
|
'wp-cli/wp-cli' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => 'v2.4.1',
|
||||||
|
'version' => '2.4.1.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => 'ceb18598e79befa9b2a37a51efbb34910628988b',
|
||||||
|
),
|
||||||
|
'wp-coding-standards/wpcs' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '2.3.0',
|
||||||
|
'version' => '2.3.0.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '7da1894633f168fe244afc6de00d141f27517b62',
|
||||||
|
),
|
||||||
|
'wptrt/wpthemereview' =>
|
||||||
|
array (
|
||||||
|
'pretty_version' => '0.2.1',
|
||||||
|
'version' => '0.2.1.0',
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'reference' => '462e59020dad9399ed2fe8e61f2a21b5e206e420',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
Vendored
+26
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// platform_check.php @generated by Composer
|
||||||
|
|
||||||
|
$issues = array();
|
||||||
|
|
||||||
|
if (!(PHP_VERSION_ID >= 50600)) {
|
||||||
|
$issues[] = 'Your Composer dependencies require a PHP version ">= 5.6.0". You are running ' . PHP_VERSION . '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($issues) {
|
||||||
|
if (!headers_sent()) {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
}
|
||||||
|
if (!ini_get('display_errors')) {
|
||||||
|
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||||
|
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||||
|
} elseif (!headers_sent()) {
|
||||||
|
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trigger_error(
|
||||||
|
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||||
|
E_USER_ERROR
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
"remark-preset-lint-recommended",
|
||||||
|
["remark-lint-list-item-indent", "space"]
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
extends: default
|
||||||
|
rules:
|
||||||
|
line-length:
|
||||||
|
level: warning
|
||||||
|
max: 120
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
|
||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
We as members, contributors, and leaders pledge to make participation in our
|
||||||
|
community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||||
|
identity and expression, level of experience, education, socio-economic status,
|
||||||
|
nationality, personal appearance, race, religion, or sexual identity
|
||||||
|
and orientation.
|
||||||
|
|
||||||
|
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||||
|
diverse, inclusive, and healthy community.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to a positive environment for our
|
||||||
|
community include:
|
||||||
|
|
||||||
|
* Demonstrating empathy and kindness toward other people
|
||||||
|
* Being respectful of differing opinions, viewpoints, and experiences
|
||||||
|
* Giving and gracefully accepting constructive feedback
|
||||||
|
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||||
|
and learning from the experience
|
||||||
|
* Focusing on what is best not just for us as individuals, but for the
|
||||||
|
overall community
|
||||||
|
|
||||||
|
Examples of unacceptable behavior include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery, and sexual attention or
|
||||||
|
advances of any kind
|
||||||
|
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or email
|
||||||
|
address, without their explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Enforcement Responsibilities
|
||||||
|
|
||||||
|
Community leaders are responsible for clarifying and enforcing our standards of
|
||||||
|
acceptable behavior and will take appropriate and fair corrective action in
|
||||||
|
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||||
|
or harmful.
|
||||||
|
|
||||||
|
Community leaders have the right and responsibility to remove, edit, or reject
|
||||||
|
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||||
|
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||||
|
decisions when appropriate.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies within all community spaces, and also applies when
|
||||||
|
an individual is officially representing the community in public spaces.
|
||||||
|
Examples of representing our community include using an official e-mail address,
|
||||||
|
posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported to the community leaders responsible for enforcement at
|
||||||
|
<potherca@gmail.com>.
|
||||||
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
reporter of any incident.
|
||||||
|
|
||||||
|
## Enforcement Guidelines
|
||||||
|
|
||||||
|
Community leaders will follow these Community Impact Guidelines in determining
|
||||||
|
the consequences for any action they deem in violation of this Code of Conduct:
|
||||||
|
|
||||||
|
### 1. Correction
|
||||||
|
|
||||||
|
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||||
|
unprofessional or unwelcome in the community.
|
||||||
|
|
||||||
|
**Consequence**: A private, written warning from community leaders, providing
|
||||||
|
clarity around the nature of the violation and an explanation of why the
|
||||||
|
behavior was inappropriate. A public apology may be requested.
|
||||||
|
|
||||||
|
### 2. Warning
|
||||||
|
|
||||||
|
**Community Impact**: A violation through a single incident or series
|
||||||
|
of actions.
|
||||||
|
|
||||||
|
**Consequence**: A warning with consequences for continued behavior. No
|
||||||
|
interaction with the people involved, including unsolicited interaction with
|
||||||
|
those enforcing the Code of Conduct, for a specified period of time. This
|
||||||
|
includes avoiding interactions in community spaces as well as external channels
|
||||||
|
like social media. Violating these terms may lead to a temporary or
|
||||||
|
permanent ban.
|
||||||
|
|
||||||
|
### 3. Temporary Ban
|
||||||
|
|
||||||
|
**Community Impact**: A serious violation of community standards, including
|
||||||
|
sustained inappropriate behavior.
|
||||||
|
|
||||||
|
**Consequence**: A temporary ban from any sort of interaction or public
|
||||||
|
communication with the community for a specified period of time. No public or
|
||||||
|
private interaction with the people involved, including unsolicited interaction
|
||||||
|
with those enforcing the Code of Conduct, is allowed during this period.
|
||||||
|
Violating these terms may lead to a permanent ban.
|
||||||
|
|
||||||
|
### 4. Permanent Ban
|
||||||
|
|
||||||
|
**Community Impact**: Demonstrating a pattern of violation of community
|
||||||
|
standards, including sustained inappropriate behavior, harassment of an
|
||||||
|
individual, or aggression toward or disparagement of classes of individuals.
|
||||||
|
|
||||||
|
**Consequence**: A permanent ban from any sort of public interaction within
|
||||||
|
the community.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||||
|
version 2.0, available at
|
||||||
|
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||||
|
|
||||||
|
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||||
|
enforcement ladder](https://github.com/mozilla/diversity).
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
|
For answers to common questions about this code of conduct, see the FAQ at
|
||||||
|
https://www.contributor-covenant.org/faq. Translations are available at
|
||||||
|
https://www.contributor-covenant.org/translations.
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2016-2020 Dealerdirect B.V.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,251 @@
|
|||||||
|
# PHP_CodeSniffer Standards Composer Installer Plugin
|
||||||
|
|
||||||
|
![Project Stage][project-stage-shield]
|
||||||
|
![Last Commit][last-updated-shield]
|
||||||
|
![Awesome][awesome-shield]
|
||||||
|
[![License][license-shield]](LICENSE.md)
|
||||||
|
|
||||||
|
[![Travis][travis-shield]][travis]
|
||||||
|
[![Scrutinizer][scrutinizer-shield]][scrutinizer]
|
||||||
|
[![Latest Version on Packagist][packagist-version-shield]][packagist-version]
|
||||||
|
[![Packagist][packagist-shield]][packagist]
|
||||||
|
|
||||||
|
[![Contributor Covenant][code-of-conduct-shield]][code-of-conduct]
|
||||||
|
|
||||||
|
This composer installer plugin allows for easy installation of [PHP_CodeSniffer][codesniffer] coding standards (rulesets).
|
||||||
|
|
||||||
|
No more symbolic linking of directories, checking out repositories on specific locations or changing
|
||||||
|
the `phpcs` configuration.
|
||||||
|
|
||||||
|
_Note: This plugin is compatible with both version 2.x and 3.x of_ [PHP_CodeSniffer][codesniffer]
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Installation can be done with [Composer][composer], by requiring this package as a development dependency:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer require --dev dealerdirect/phpcodesniffer-composer-installer
|
||||||
|
```
|
||||||
|
|
||||||
|
That's it.
|
||||||
|
|
||||||
|
### How it works
|
||||||
|
|
||||||
|
Basically, this plugin executes the following steps:
|
||||||
|
|
||||||
|
- This plugin searches for `phpcodesniffer-standard` packages in all of your currently installed Composer packages.
|
||||||
|
- Matching packages and the project itself are scanned for PHP_CodeSniffer rulesets.
|
||||||
|
- The plugin will call PHP_CodeSniffer and configure the `installed_paths` option.
|
||||||
|
|
||||||
|
### Example project
|
||||||
|
|
||||||
|
The following is an example Composer project and has included
|
||||||
|
multiple `phpcodesniffer-standard` packages.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "dealerdirect/example-project",
|
||||||
|
"description": "Just an example project",
|
||||||
|
"type": "project",
|
||||||
|
"require": {},
|
||||||
|
"require-dev": {
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": "*",
|
||||||
|
"object-calisthenics/phpcs-calisthenics-rules": "*",
|
||||||
|
"phpcompatibility/php-compatibility": "*",
|
||||||
|
"wp-coding-standards/wpcs": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
After running `composer install` PHP_CodeSniffer just works:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ ./vendor/bin/phpcs -i
|
||||||
|
The installed coding standards are MySource, PEAR, PSR1, PSR2, Squiz, Zend, PHPCompatibility, WordPress,
|
||||||
|
WordPress-Core, WordPress-Docs, WordPress-Extra and WordPress-VIP
|
||||||
|
```
|
||||||
|
|
||||||
|
### Calling the plugin directly
|
||||||
|
|
||||||
|
In some circumstances, it is desirable to call this plugin's functionality
|
||||||
|
directly. For instance, during development or in [CI][definition-ci] environments.
|
||||||
|
|
||||||
|
As the plugin requires Composer to work, direct calls need to be wired through a
|
||||||
|
project's `composer.json`.
|
||||||
|
|
||||||
|
This is done by adding a call to the `Plugin::run` function in the `script`
|
||||||
|
section of the `composer.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"install-codestandards": [
|
||||||
|
"Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
The command can then be called using `composer run-script install-codestandards` or
|
||||||
|
referenced from other script configurations, as follows:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"install-codestandards": [
|
||||||
|
"Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run"
|
||||||
|
],
|
||||||
|
"post-install-cmd": [
|
||||||
|
"@install-codestandards"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
For more details about Composer scripts, please refer to [the section on scripts
|
||||||
|
in the Composer manual][composer-manual-scripts].
|
||||||
|
|
||||||
|
### Changing the Coding Standards search depth
|
||||||
|
|
||||||
|
By default, this plugin searches up for Coding Standards up to three directories
|
||||||
|
deep. In most cases, this should be sufficient. However, this plugin allows
|
||||||
|
you to customize the search depth setting if needed.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"extra": {
|
||||||
|
"phpcodesniffer-search-depth": 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Caveats
|
||||||
|
|
||||||
|
When this plugin is installed globally, composer will load the _global_ plugin rather
|
||||||
|
than the one from the local repository. Despite [this behavior being documented
|
||||||
|
in the composer manual][using-composer-plugins], it could potentially confuse
|
||||||
|
as another version of the plugin could be run and not the one specified by the project.
|
||||||
|
|
||||||
|
## Developing Coding Standards
|
||||||
|
|
||||||
|
Coding standard can be developed normally, as documented by [PHP_CodeSniffer][codesniffer], in the [Coding Standard Tutorial][tutorial].
|
||||||
|
|
||||||
|
Create a composer package of your coding standard by adding a `composer.json` file.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name" : "acme/phpcodesniffer-our-standards",
|
||||||
|
"description" : "Package contains all coding standards of the Acme company",
|
||||||
|
"require" : {
|
||||||
|
"php" : ">=5.4.0,<8.0.0-dev",
|
||||||
|
"squizlabs/php_codesniffer" : "^3.0"
|
||||||
|
},
|
||||||
|
"type" : "phpcodesniffer-standard"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
* The repository may contain one or more standards.
|
||||||
|
* Each standard can have a separate directory no deeper than 3 levels from the repository root.
|
||||||
|
* The package `type` must be `phpcodesniffer-standard`. Without this, the plugin will not trigger.
|
||||||
|
|
||||||
|
### Requiring the plugin from within your coding standard
|
||||||
|
|
||||||
|
If your coding standard itself depends on additional external PHPCS standards, this plugin can
|
||||||
|
make life easier on your end-users by taking care of the installation of all standards - yours
|
||||||
|
and your dependencies - for them.
|
||||||
|
|
||||||
|
This can help reduce the number of support questions about setting the `installed_paths`, as well
|
||||||
|
as simplify your standard's installation instructions.
|
||||||
|
|
||||||
|
For this to work, make sure your external standard adds this plugin to the `composer.json` config
|
||||||
|
via `require`, **not** `require-dev`.
|
||||||
|
|
||||||
|
> :warning: Your end-user may already `require-dev` this plugin and/or other external standards used
|
||||||
|
> by your end-users may require this plugin as well.
|
||||||
|
>
|
||||||
|
> To prevent your end-users getting into "_dependency hell_", make sure to make the version requirement
|
||||||
|
> for this plugin flexible.
|
||||||
|
>
|
||||||
|
> As, for now, this plugin is still regarded as "unstable" (version < 1.0), remember that Composer
|
||||||
|
> treats unstable minors as majors and will not be able to resolve one config requiring this plugin
|
||||||
|
> at version `^0.5`, while another requires it at version `^0.6`.
|
||||||
|
> Either allow multiple minors or use `*` as the version requirement.
|
||||||
|
>
|
||||||
|
> Some examples of flexible requirements which can be used:
|
||||||
|
> ```bash
|
||||||
|
> composer require dealerdirect/phpcodesniffer-composer-installer:"*"
|
||||||
|
> composer require dealerdirect/phpcodesniffer-composer-installer:"0.*"
|
||||||
|
> composer require dealerdirect/phpcodesniffer-composer-installer:"^0.4 || ^0.5 || ^0.6"
|
||||||
|
> ```
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
This repository does not contain a `CHANGELOG.md` file, however, we do publish a changelog on each release
|
||||||
|
using the [GitHub releases][changelog] functionality.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
This is an active open-source project. We are always open to people who want to
|
||||||
|
use the code or contribute to it.
|
||||||
|
|
||||||
|
We've set up a separate document for our [contribution guidelines][contributing-guidelines].
|
||||||
|
|
||||||
|
Thank you for being involved! :heart_eyes:
|
||||||
|
|
||||||
|
## Authors & contributors
|
||||||
|
|
||||||
|
The original idea and setup of this repository is by [Franck Nijhof][frenck], employee @ Dealerdirect.
|
||||||
|
|
||||||
|
For a full list of all author and/or contributors, check [the contributors page][contributors].
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016-2020 Dealerdirect B.V.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
[awesome-shield]: https://img.shields.io/badge/awesome%3F-yes-brightgreen.svg
|
||||||
|
[changelog]: https://github.com/Dealerdirect/phpcodesniffer-composer-installer/releases
|
||||||
|
[code-of-conduct-shield]: https://img.shields.io/badge/Contributor%20Covenant-v2.0-ff69b4.svg
|
||||||
|
[code-of-conduct]: CODE_OF_CONDUCT.md
|
||||||
|
[codesniffer]: https://github.com/squizlabs/PHP_CodeSniffer
|
||||||
|
[composer-manual-scripts]: https://getcomposer.org/doc/articles/scripts.md
|
||||||
|
[composer]: https://getcomposer.org/
|
||||||
|
[contributing-guidelines]: CONTRIBUTING.md
|
||||||
|
[contributors]: https://github.com/Dealerdirect/phpcodesniffer-composer-installer/graphs/contributors
|
||||||
|
[definition-ci]: https://en.wikipedia.org/wiki/Continuous_integration
|
||||||
|
[frenck]: https://github.com/frenck
|
||||||
|
[last-updated-shield]: https://img.shields.io/github/last-commit/Dealerdirect/phpcodesniffer-composer-installer.svg
|
||||||
|
[license-shield]: https://img.shields.io/github/license/dealerdirect/phpcodesniffer-composer-installer.svg
|
||||||
|
[packagist-shield]: https://img.shields.io/packagist/dt/dealerdirect/phpcodesniffer-composer-installer.svg
|
||||||
|
[packagist-version-shield]: https://img.shields.io/packagist/v/dealerdirect/phpcodesniffer-composer-installer.svg
|
||||||
|
[packagist-version]: https://packagist.org/packages/dealerdirect/phpcodesniffer-composer-installer
|
||||||
|
[packagist]: https://packagist.org/packages/dealerdirect/phpcodesniffer-composer-installer
|
||||||
|
[project-stage-shield]: https://img.shields.io/badge/Project%20Stage-Development-yellowgreen.svg
|
||||||
|
[scrutinizer-shield]: https://img.shields.io/scrutinizer/g/dealerdirect/phpcodesniffer-composer-installer.svg
|
||||||
|
[scrutinizer]: https://scrutinizer-ci.com/g/dealerdirect/phpcodesniffer-composer-installer/
|
||||||
|
[travis-shield]: https://img.shields.io/travis/Dealerdirect/phpcodesniffer-composer-installer.svg
|
||||||
|
[travis]: https://travis-ci.org/Dealerdirect/phpcodesniffer-composer-installer
|
||||||
|
[tutorial]: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Coding-Standard-Tutorial
|
||||||
|
[using-composer-plugins]: https://getcomposer.org/doc/articles/plugins.md#using-plugins
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"name": "dealerdirect/phpcodesniffer-composer-installer",
|
||||||
|
"description": "PHP_CodeSniffer Standards Composer Installer Plugin",
|
||||||
|
"type": "composer-plugin",
|
||||||
|
"keywords": [
|
||||||
|
"composer", "installer", "plugin",
|
||||||
|
"phpcs", "codesniffer", "phpcodesniffer", "php_codesniffer",
|
||||||
|
"standard", "standards", "style guide", "stylecheck",
|
||||||
|
"qa", "quality", "code quality", "tests"
|
||||||
|
],
|
||||||
|
"homepage": "http://www.dealerdirect.com",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Franck Nijhof",
|
||||||
|
"email": "franck.nijhof@dealerdirect.com",
|
||||||
|
"homepage": "http://www.frenck.nl",
|
||||||
|
"role": "Developer / IT Manager"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues",
|
||||||
|
"source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3",
|
||||||
|
"composer-plugin-api": "^1.0 || ^2.0",
|
||||||
|
"squizlabs/php_codesniffer": "^2.0 || ^3.0 || ^4.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"composer/composer": "*",
|
||||||
|
"sensiolabs/security-checker": "^4.1.0",
|
||||||
|
"phpcompatibility/php-compatibility": "^9.0"
|
||||||
|
},
|
||||||
|
"minimum-stability": "dev",
|
||||||
|
"prefer-stable": true,
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"install-codestandards": [
|
||||||
|
"Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,620 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Dealerdirect PHP_CodeSniffer Standards
|
||||||
|
* Composer Installer Plugin package.
|
||||||
|
*
|
||||||
|
* @copyright 2016-2020 Dealerdirect B.V.
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Dealerdirect\Composer\Plugin\Installers\PHPCodeSniffer;
|
||||||
|
|
||||||
|
use Composer\Composer;
|
||||||
|
use Composer\EventDispatcher\EventSubscriberInterface;
|
||||||
|
use Composer\IO\IOInterface;
|
||||||
|
use Composer\Package\AliasPackage;
|
||||||
|
use Composer\Package\PackageInterface;
|
||||||
|
use Composer\Package\RootPackageInterface;
|
||||||
|
use Composer\Plugin\PluginInterface;
|
||||||
|
use Composer\Script\Event;
|
||||||
|
use Composer\Script\ScriptEvents;
|
||||||
|
use Composer\Util\Filesystem;
|
||||||
|
use Composer\Util\ProcessExecutor;
|
||||||
|
use Symfony\Component\Finder\Finder;
|
||||||
|
use Symfony\Component\Process\Exception\LogicException;
|
||||||
|
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||||
|
use Symfony\Component\Process\Exception\RuntimeException;
|
||||||
|
use Symfony\Component\Process\PhpExecutableFinder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHP_CodeSniffer standard installation manager.
|
||||||
|
*
|
||||||
|
* @author Franck Nijhof <franck.nijhof@dealerdirect.com>
|
||||||
|
*/
|
||||||
|
class Plugin implements PluginInterface, EventSubscriberInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
const KEY_MAX_DEPTH = 'phpcodesniffer-search-depth';
|
||||||
|
|
||||||
|
const MESSAGE_ERROR_WRONG_MAX_DEPTH =
|
||||||
|
'The value of "%s" (in the composer.json "extra".section) must be an integer larger then %d, %s given.';
|
||||||
|
const MESSAGE_NOT_INSTALLED = 'PHPCodeSniffer is not installed';
|
||||||
|
const MESSAGE_NOTHING_TO_INSTALL = 'Nothing to install or update';
|
||||||
|
const MESSAGE_PLUGIN_UNINSTALLED = 'PHPCodeSniffer Composer Installer is uninstalled';
|
||||||
|
const MESSAGE_RUNNING_INSTALLER = 'Running PHPCodeSniffer Composer Installer';
|
||||||
|
|
||||||
|
const PACKAGE_NAME = 'squizlabs/php_codesniffer';
|
||||||
|
const PACKAGE_TYPE = 'phpcodesniffer-standard';
|
||||||
|
|
||||||
|
const PHPCS_CONFIG_REGEX = '`%s:[^\r\n]+`';
|
||||||
|
const PHPCS_CONFIG_KEY = 'installed_paths';
|
||||||
|
|
||||||
|
const PLUGIN_NAME = 'dealerdirect/phpcodesniffer-composer-installer';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Composer
|
||||||
|
*/
|
||||||
|
private $composer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $cwd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Filesystem
|
||||||
|
*/
|
||||||
|
private $filesystem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $installedPaths;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var IOInterface
|
||||||
|
*/
|
||||||
|
private $io;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ProcessExecutor
|
||||||
|
*/
|
||||||
|
private $processExecutor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers the plugin's main functionality.
|
||||||
|
*
|
||||||
|
* Makes it possible to run the plugin as a custom command.
|
||||||
|
*
|
||||||
|
* @param Event $event
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
* @throws \RuntimeException
|
||||||
|
* @throws LogicException
|
||||||
|
* @throws ProcessFailedException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public static function run(Event $event)
|
||||||
|
{
|
||||||
|
$io = $event->getIO();
|
||||||
|
$composer = $event->getComposer();
|
||||||
|
|
||||||
|
$instance = new static();
|
||||||
|
|
||||||
|
$instance->io = $io;
|
||||||
|
$instance->composer = $composer;
|
||||||
|
$instance->init();
|
||||||
|
$instance->onDependenciesChangedEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException
|
||||||
|
* @throws LogicException
|
||||||
|
* @throws ProcessFailedException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public function activate(Composer $composer, IOInterface $io)
|
||||||
|
{
|
||||||
|
$this->composer = $composer;
|
||||||
|
$this->io = $io;
|
||||||
|
|
||||||
|
$this->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function deactivate(Composer $composer, IOInterface $io)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function uninstall(Composer $composer, IOInterface $io)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares the plugin so it's main functionality can be run.
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException
|
||||||
|
* @throws LogicException
|
||||||
|
* @throws ProcessFailedException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
private function init()
|
||||||
|
{
|
||||||
|
$this->cwd = getcwd();
|
||||||
|
$this->installedPaths = array();
|
||||||
|
|
||||||
|
$this->processExecutor = new ProcessExecutor($this->io);
|
||||||
|
$this->filesystem = new Filesystem($this->processExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public static function getSubscribedEvents()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
ScriptEvents::POST_INSTALL_CMD => array(
|
||||||
|
array('onDependenciesChangedEvent', 0),
|
||||||
|
),
|
||||||
|
ScriptEvents::POST_UPDATE_CMD => array(
|
||||||
|
array('onDependenciesChangedEvent', 0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry point for post install and post update events.
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
* @throws LogicException
|
||||||
|
* @throws ProcessFailedException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public function onDependenciesChangedEvent()
|
||||||
|
{
|
||||||
|
$io = $this->io;
|
||||||
|
$isVerbose = $io->isVerbose();
|
||||||
|
$exitCode = 0;
|
||||||
|
|
||||||
|
if ($isVerbose) {
|
||||||
|
$io->write(sprintf('<info>%s</info>', self::MESSAGE_RUNNING_INSTALLER));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isPHPCodeSnifferInstalled() === true) {
|
||||||
|
$this->loadInstalledPaths();
|
||||||
|
$installPathCleaned = $this->cleanInstalledPaths();
|
||||||
|
$installPathUpdated = $this->updateInstalledPaths();
|
||||||
|
|
||||||
|
if ($installPathCleaned === true || $installPathUpdated === true) {
|
||||||
|
$exitCode = $this->saveInstalledPaths();
|
||||||
|
} elseif ($isVerbose) {
|
||||||
|
$io->write(sprintf('<info>%s</info>', self::MESSAGE_NOTHING_TO_INSTALL));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$pluginPackage = $this
|
||||||
|
->composer
|
||||||
|
->getRepositoryManager()
|
||||||
|
->getLocalRepository()
|
||||||
|
->findPackages(self::PLUGIN_NAME)
|
||||||
|
;
|
||||||
|
|
||||||
|
$isPluginUninstalled = count($pluginPackage) === 0;
|
||||||
|
|
||||||
|
if ($isPluginUninstalled) {
|
||||||
|
if ($isVerbose) {
|
||||||
|
$io->write(sprintf('<info>%s</info>', self::MESSAGE_PLUGIN_UNINSTALLED));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$exitCode = 1;
|
||||||
|
if ($isVerbose) {
|
||||||
|
$io->write(sprintf('<error>%s</error>', self::MESSAGE_NOT_INSTALLED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all paths from PHP_CodeSniffer into an array.
|
||||||
|
*
|
||||||
|
* @throws LogicException
|
||||||
|
* @throws ProcessFailedException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
private function loadInstalledPaths()
|
||||||
|
{
|
||||||
|
if ($this->isPHPCodeSnifferInstalled() === true) {
|
||||||
|
$this->processExecutor->execute(
|
||||||
|
sprintf(
|
||||||
|
'phpcs --config-show %s',
|
||||||
|
self::PHPCS_CONFIG_KEY
|
||||||
|
),
|
||||||
|
$output,
|
||||||
|
$this->composer->getConfig()->get('bin-dir')
|
||||||
|
);
|
||||||
|
|
||||||
|
$regex = sprintf(self::PHPCS_CONFIG_REGEX, self::PHPCS_CONFIG_KEY);
|
||||||
|
if (preg_match($regex, $output, $match) === 1) {
|
||||||
|
$phpcsInstalledPaths = str_replace(self::PHPCS_CONFIG_KEY . ': ', '', $match[0]);
|
||||||
|
$phpcsInstalledPaths = trim($phpcsInstalledPaths);
|
||||||
|
|
||||||
|
if ($phpcsInstalledPaths !== '') {
|
||||||
|
$this->installedPaths = explode(',', $phpcsInstalledPaths);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save all coding standard paths back into PHP_CodeSniffer
|
||||||
|
*
|
||||||
|
* @throws LogicException
|
||||||
|
* @throws ProcessFailedException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*
|
||||||
|
* @return int Exit code. 0 for success, 1 or higher for failure.
|
||||||
|
*/
|
||||||
|
private function saveInstalledPaths()
|
||||||
|
{
|
||||||
|
// Check if we found installed paths to set.
|
||||||
|
if (count($this->installedPaths) !== 0) {
|
||||||
|
sort($this->installedPaths);
|
||||||
|
$paths = implode(',', $this->installedPaths);
|
||||||
|
$arguments = array('--config-set', self::PHPCS_CONFIG_KEY, $paths);
|
||||||
|
$configMessage = sprintf(
|
||||||
|
'PHP CodeSniffer Config <info>%s</info> <comment>set to</comment> <info>%s</info>',
|
||||||
|
self::PHPCS_CONFIG_KEY,
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Delete the installed paths if none were found.
|
||||||
|
$arguments = array('--config-delete', self::PHPCS_CONFIG_KEY);
|
||||||
|
$configMessage = sprintf(
|
||||||
|
'PHP CodeSniffer Config <info>%s</info> <comment>delete</comment>',
|
||||||
|
self::PHPCS_CONFIG_KEY
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare message in case of failure
|
||||||
|
$failMessage = sprintf(
|
||||||
|
'Failed to set PHP CodeSniffer <info>%s</info> Config',
|
||||||
|
self::PHPCS_CONFIG_KEY
|
||||||
|
);
|
||||||
|
|
||||||
|
// Determine the path to the main PHPCS file.
|
||||||
|
$phpcsPath = $this->getPHPCodeSnifferInstallPath();
|
||||||
|
if (file_exists($phpcsPath . '/bin/phpcs') === true) {
|
||||||
|
// PHPCS 3.x.
|
||||||
|
$phpcsExecutable = './bin/phpcs';
|
||||||
|
} else {
|
||||||
|
// PHPCS 2.x.
|
||||||
|
$phpcsExecutable = './scripts/phpcs';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Okay, lets rock!
|
||||||
|
$command = vsprintf(
|
||||||
|
'%s %s %s',
|
||||||
|
array(
|
||||||
|
'php executable' => $this->getPhpExecCommand(),
|
||||||
|
'phpcs executable' => $phpcsExecutable,
|
||||||
|
'arguments' => implode(' ', $arguments)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$exitCode = $this->processExecutor->execute($command, $configResult, $phpcsPath);
|
||||||
|
if ($exitCode === 0) {
|
||||||
|
$exitCode = $this->verifySaveSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($exitCode === 0) {
|
||||||
|
$this->io->write($configMessage);
|
||||||
|
} else {
|
||||||
|
$this->io->write($failMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->io->isVerbose() && !empty($configResult)) {
|
||||||
|
$this->io->write(sprintf('<info>%s</info>', $configResult));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that the paths which were expected to be saved, have been.
|
||||||
|
*
|
||||||
|
* @return int Exit code. 0 for success, 1 for failure.
|
||||||
|
*/
|
||||||
|
private function verifySaveSuccess()
|
||||||
|
{
|
||||||
|
$exitCode = 1;
|
||||||
|
$expectedPaths = $this->installedPaths;
|
||||||
|
|
||||||
|
// Request the currently set installed paths after the save.
|
||||||
|
$this->loadInstalledPaths();
|
||||||
|
|
||||||
|
$registeredPaths = array_intersect($this->installedPaths, $expectedPaths);
|
||||||
|
$registeredCount = count($registeredPaths);
|
||||||
|
$expectedCount = count($expectedPaths);
|
||||||
|
|
||||||
|
if ($expectedCount === $registeredCount) {
|
||||||
|
$exitCode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($exitCode === 1 && $this->io->isVerbose()) {
|
||||||
|
$verificationMessage = sprintf(
|
||||||
|
"Paths to external standards found by the plugin: <info>%s</info>\n"
|
||||||
|
. 'Actual paths registered with PHPCS: <info>%s</info>',
|
||||||
|
implode(', ', $expectedPaths),
|
||||||
|
implode(', ', $this->installedPaths)
|
||||||
|
);
|
||||||
|
$this->io->write($verificationMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path to the current PHP version being used.
|
||||||
|
*
|
||||||
|
* Duplicate of the same in the EventDispatcher class in Composer itself.
|
||||||
|
*/
|
||||||
|
protected function getPhpExecCommand()
|
||||||
|
{
|
||||||
|
$finder = new PhpExecutableFinder();
|
||||||
|
|
||||||
|
$phpPath = $finder->find(false);
|
||||||
|
|
||||||
|
if ($phpPath === false) {
|
||||||
|
throw new \RuntimeException('Failed to locate PHP binary to execute ' . $phpPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
$phpArgs = $finder->findArguments();
|
||||||
|
$phpArgs = $phpArgs
|
||||||
|
? ' ' . implode(' ', $phpArgs)
|
||||||
|
: ''
|
||||||
|
;
|
||||||
|
|
||||||
|
$command = ProcessExecutor::escape($phpPath) .
|
||||||
|
$phpArgs .
|
||||||
|
' -d allow_url_fopen=' . ProcessExecutor::escape(ini_get('allow_url_fopen')) .
|
||||||
|
' -d disable_functions=' . ProcessExecutor::escape(ini_get('disable_functions')) .
|
||||||
|
' -d memory_limit=' . ProcessExecutor::escape(ini_get('memory_limit'))
|
||||||
|
;
|
||||||
|
|
||||||
|
return $command;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate trough all known paths and check if they are still valid.
|
||||||
|
*
|
||||||
|
* If path does not exists, is not an directory or isn't readable, the path
|
||||||
|
* is removed from the list.
|
||||||
|
*
|
||||||
|
* @return bool True if changes where made, false otherwise
|
||||||
|
*/
|
||||||
|
private function cleanInstalledPaths()
|
||||||
|
{
|
||||||
|
$changes = false;
|
||||||
|
foreach ($this->installedPaths as $key => $path) {
|
||||||
|
// This might be a relative path as well
|
||||||
|
$alternativePath = realpath($this->getPHPCodeSnifferInstallPath() . DIRECTORY_SEPARATOR . $path);
|
||||||
|
|
||||||
|
if (
|
||||||
|
(is_dir($path) === false || is_readable($path) === false) &&
|
||||||
|
(is_dir($alternativePath) === false || is_readable($alternativePath) === false)
|
||||||
|
) {
|
||||||
|
unset($this->installedPaths[$key]);
|
||||||
|
$changes = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check all installed packages (including the root package) against
|
||||||
|
* the installed paths from PHP_CodeSniffer and add the missing ones.
|
||||||
|
*
|
||||||
|
* @return bool True if changes where made, false otherwise
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
* @throws \RuntimeException
|
||||||
|
*/
|
||||||
|
private function updateInstalledPaths()
|
||||||
|
{
|
||||||
|
$changes = false;
|
||||||
|
|
||||||
|
$searchPaths = array($this->cwd);
|
||||||
|
$codingStandardPackages = $this->getPHPCodingStandardPackages();
|
||||||
|
foreach ($codingStandardPackages as $package) {
|
||||||
|
$installPath = $this->composer->getInstallationManager()->getInstallPath($package);
|
||||||
|
if ($this->filesystem->isAbsolutePath($installPath) === false) {
|
||||||
|
$installPath = $this->filesystem->normalizePath(
|
||||||
|
$this->cwd . DIRECTORY_SEPARATOR . $installPath
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$searchPaths[] = $installPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
$finder = new Finder();
|
||||||
|
$finder->files()
|
||||||
|
->depth('<= ' . $this->getMaxDepth())
|
||||||
|
->depth('>= ' . $this->getMinDepth())
|
||||||
|
->ignoreUnreadableDirs()
|
||||||
|
->ignoreVCS(true)
|
||||||
|
->in($searchPaths)
|
||||||
|
->name('ruleset.xml');
|
||||||
|
|
||||||
|
// Process each found possible ruleset.
|
||||||
|
foreach ($finder as $ruleset) {
|
||||||
|
$standardsPath = $ruleset->getPath();
|
||||||
|
|
||||||
|
// Pick the directory above the directory containing the standard, unless this is the project root.
|
||||||
|
if ($standardsPath !== $this->cwd) {
|
||||||
|
$standardsPath = dirname($standardsPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use relative paths for local project repositories.
|
||||||
|
if ($this->isRunningGlobally() === false) {
|
||||||
|
$standardsPath = $this->filesystem->findShortestPath(
|
||||||
|
$this->getPHPCodeSnifferInstallPath(),
|
||||||
|
$standardsPath,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// De-duplicate and add when directory is not configured.
|
||||||
|
if (in_array($standardsPath, $this->installedPaths, true) === false) {
|
||||||
|
$this->installedPaths[] = $standardsPath;
|
||||||
|
$changes = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates through Composers' local repository looking for valid Coding
|
||||||
|
* Standard packages.
|
||||||
|
*
|
||||||
|
* If the package is the RootPackage (the one the plugin is installed into),
|
||||||
|
* the package is ignored for now since it needs a different install path logic.
|
||||||
|
*
|
||||||
|
* @return array Composer packages containing coding standard(s)
|
||||||
|
*/
|
||||||
|
private function getPHPCodingStandardPackages()
|
||||||
|
{
|
||||||
|
$codingStandardPackages = array_filter(
|
||||||
|
$this->composer->getRepositoryManager()->getLocalRepository()->getPackages(),
|
||||||
|
function (PackageInterface $package) {
|
||||||
|
if ($package instanceof AliasPackage) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $package->getType() === Plugin::PACKAGE_TYPE;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
! $this->composer->getPackage() instanceof RootPackageInterface
|
||||||
|
&& $this->composer->getPackage()->getType() === self::PACKAGE_TYPE
|
||||||
|
) {
|
||||||
|
$codingStandardPackages[] = $this->composer->getPackage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $codingStandardPackages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for the installed PHP_CodeSniffer Composer package
|
||||||
|
*
|
||||||
|
* @param null|string|\Composer\Semver\Constraint\ConstraintInterface $versionConstraint to match against
|
||||||
|
*
|
||||||
|
* @return PackageInterface|null
|
||||||
|
*/
|
||||||
|
private function getPHPCodeSnifferPackage($versionConstraint = null)
|
||||||
|
{
|
||||||
|
$packages = $this
|
||||||
|
->composer
|
||||||
|
->getRepositoryManager()
|
||||||
|
->getLocalRepository()
|
||||||
|
->findPackages(self::PACKAGE_NAME, $versionConstraint);
|
||||||
|
|
||||||
|
return array_shift($packages);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the path to the PHP_CodeSniffer package installation location
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getPHPCodeSnifferInstallPath()
|
||||||
|
{
|
||||||
|
return $this->composer->getInstallationManager()->getInstallPath($this->getPHPCodeSnifferPackage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple check if PHP_CodeSniffer is installed.
|
||||||
|
*
|
||||||
|
* @param null|string|\Composer\Semver\Constraint\ConstraintInterface $versionConstraint to match against
|
||||||
|
*
|
||||||
|
* @return bool Whether PHP_CodeSniffer is installed
|
||||||
|
*/
|
||||||
|
private function isPHPCodeSnifferInstalled($versionConstraint = null)
|
||||||
|
{
|
||||||
|
return ($this->getPHPCodeSnifferPackage($versionConstraint) !== null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if composer is running "global"
|
||||||
|
* This check kinda dirty, but it is the "Composer Way"
|
||||||
|
*
|
||||||
|
* @return bool Whether Composer is running "globally"
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException
|
||||||
|
*/
|
||||||
|
private function isRunningGlobally()
|
||||||
|
{
|
||||||
|
return ($this->composer->getConfig()->get('home') === $this->cwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the maximum search depth when searching for Coding Standards.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
private function getMaxDepth()
|
||||||
|
{
|
||||||
|
$maxDepth = 3;
|
||||||
|
|
||||||
|
$extra = $this->composer->getPackage()->getExtra();
|
||||||
|
|
||||||
|
if (array_key_exists(self::KEY_MAX_DEPTH, $extra)) {
|
||||||
|
$maxDepth = $extra[self::KEY_MAX_DEPTH];
|
||||||
|
$minDepth = $this->getMinDepth();
|
||||||
|
|
||||||
|
if (
|
||||||
|
(string) (int) $maxDepth !== (string) $maxDepth /* Must be an integer or cleanly castable to one */
|
||||||
|
|| $maxDepth <= $minDepth /* Larger than the minimum */
|
||||||
|
|| is_float($maxDepth) === true /* Within the boundaries of integer */
|
||||||
|
) {
|
||||||
|
$message = vsprintf(
|
||||||
|
self::MESSAGE_ERROR_WRONG_MAX_DEPTH,
|
||||||
|
array(
|
||||||
|
'key' => self::KEY_MAX_DEPTH,
|
||||||
|
'min' => $minDepth,
|
||||||
|
'given' => var_export($maxDepth, true),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
throw new \InvalidArgumentException($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) $maxDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minimal search depth for Coding Standard packages.
|
||||||
|
*
|
||||||
|
* Usually this is 0, unless PHP_CodeSniffer >= 3 is used.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private function getMinDepth()
|
||||||
|
{
|
||||||
|
if ($this->isPHPCodeSnifferInstalled('>= 3.0.0') !== true) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+178
@@ -0,0 +1,178 @@
|
|||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||||
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
Previous releases are documented in [github releases](https://github.com/oscarotero/Gettext/releases)
|
||||||
|
|
||||||
|
## [4.8.3] - 2020-11-18
|
||||||
|
### Fixed
|
||||||
|
- Blade extractor for Laravel8/Jetstream [#261]
|
||||||
|
|
||||||
|
## [4.8.2] - 2019-12-02
|
||||||
|
### Fixed
|
||||||
|
- UTF-8 handling for VueJs extractor [#242]
|
||||||
|
|
||||||
|
## [4.8.1] - 2019-11-15
|
||||||
|
### Fixed
|
||||||
|
- Php error when scanning for a single domain but other string found [#238]
|
||||||
|
|
||||||
|
## [4.8.0] - 2019-11-04
|
||||||
|
### Changed
|
||||||
|
- Many `private` properties and methods were changed to `protected` in order to improve the extensibility [#231]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- PHP 7.4 support [#230]
|
||||||
|
|
||||||
|
## [4.7.0] - 2019-10-07
|
||||||
|
### Added
|
||||||
|
- Support for UnitID in Xliff [#221] [#224] [#225]
|
||||||
|
- Support for scan multiple domains at the same time [#223]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- New lines in windows [#218] [#226]
|
||||||
|
|
||||||
|
## [4.6.3] - 2019-07-15
|
||||||
|
### Added
|
||||||
|
- Some VueJs extraction improvements and additions [#205], [#213]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Multiline extractions in jsCode [#200]
|
||||||
|
- Support for js template literals [#214]
|
||||||
|
- Fixed tabs in PHP comments [#215]
|
||||||
|
|
||||||
|
## [4.6.2] - 2019-01-12
|
||||||
|
### Added
|
||||||
|
- New option `facade` in blade extractor to use a facade instead create a blade compiler [#197], [#198]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Added php-7.3 to travis
|
||||||
|
- Added VueJS extractor method docblocks for IDEs [#191]
|
||||||
|
|
||||||
|
## [4.6.1] - 2018-08-27
|
||||||
|
### Fixed
|
||||||
|
- VueJS DOM parsing [#188]
|
||||||
|
- Javascript parser was unable to extract some functions [#187]
|
||||||
|
|
||||||
|
## [4.6.0] - 2018-06-26
|
||||||
|
### Added
|
||||||
|
- New extractor for VueJs [#178]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Do not include empty translations containing the headers in the translator [#182]
|
||||||
|
- Test enhancement [#177]
|
||||||
|
|
||||||
|
## [4.5.0] - 2018-04-23
|
||||||
|
### Added
|
||||||
|
- Support for disabled translations
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Added php-7.2 to travis
|
||||||
|
- Fixed po tests on bigendian [#159]
|
||||||
|
- Improved comment estraction [#166]
|
||||||
|
- Fixed incorrect docs to dn__ function [#170]
|
||||||
|
- Ignored phpcs.xml file on export [#168]
|
||||||
|
- Improved `@method` docs in `Translations` [#175]
|
||||||
|
|
||||||
|
## [4.4.4] - 2018-02-21
|
||||||
|
### Fixed
|
||||||
|
- Changed the comment extraction to be compatible with gettext behaviour: the comment must be placed in the line preceding the function [#161]
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Validate eval input from plural forms [#156]
|
||||||
|
|
||||||
|
## [4.4.3] - 2017-08-09
|
||||||
|
### Fixed
|
||||||
|
- Handle `NULL` arguments on extract entries in php. For example `dn__(null, 'singular', 'plural')`.
|
||||||
|
- Fixed the `PhpCode` and `JsCode` extractors that didn't extract `dn__` and `dngettext` entries [#155].
|
||||||
|
- Fixed the `PhpCode` and `JsCode` extractors that didn't extract `dnpgettext` correctly.
|
||||||
|
|
||||||
|
## [4.4.2] - 2017-07-27
|
||||||
|
### Fixed
|
||||||
|
- Clone the translations in `Translations::mergeWith` to prevent that the translation is referenced in both places. [#152]
|
||||||
|
- Fixed escaped quotes in the javascript extractor [#154]
|
||||||
|
|
||||||
|
## [4.4.1] - 2017-05-20
|
||||||
|
### Fixed
|
||||||
|
- Fixed a bug where the options was not passed correctly to the merging Translations object [#147]
|
||||||
|
- Unified the plural behaviours between PHP gettext and Translator when the plural translation is unknown [#148]
|
||||||
|
- Removed the deprecated function `create_function()` and use `eval()` instead
|
||||||
|
|
||||||
|
## [4.4.0] - 2017-05-10
|
||||||
|
### Added
|
||||||
|
- New option `noLocation` to po generator, to omit the references [#143]
|
||||||
|
- New options `delimiter`, `enclosure` and `escape_char` to Csv and CsvDictionary extractors and generators [#145]
|
||||||
|
- Added the missing `dn__()` function [#146]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Improved the code style including php_codesniffer in development
|
||||||
|
|
||||||
|
## 4.3.0 - 2017-03-04
|
||||||
|
### Added
|
||||||
|
- Added support for named placeholders (using `strtr`). For example:
|
||||||
|
```php
|
||||||
|
__('Hello :name', [':name' => 'World']);
|
||||||
|
```
|
||||||
|
- Added support for Twig v2
|
||||||
|
- New function `BaseTranslator::includeFunctions()` to include the functions file without register any translator
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed a bug related with the javascript source extraction with single quotes
|
||||||
|
|
||||||
|
[#143]: https://github.com/oscarotero/Gettext/issues/143
|
||||||
|
[#145]: https://github.com/oscarotero/Gettext/issues/145
|
||||||
|
[#146]: https://github.com/oscarotero/Gettext/issues/146
|
||||||
|
[#147]: https://github.com/oscarotero/Gettext/issues/147
|
||||||
|
[#148]: https://github.com/oscarotero/Gettext/issues/148
|
||||||
|
[#152]: https://github.com/oscarotero/Gettext/issues/152
|
||||||
|
[#154]: https://github.com/oscarotero/Gettext/issues/154
|
||||||
|
[#155]: https://github.com/oscarotero/Gettext/issues/155
|
||||||
|
[#156]: https://github.com/oscarotero/Gettext/issues/156
|
||||||
|
[#159]: https://github.com/oscarotero/Gettext/issues/159
|
||||||
|
[#161]: https://github.com/oscarotero/Gettext/issues/161
|
||||||
|
[#166]: https://github.com/oscarotero/Gettext/issues/166
|
||||||
|
[#168]: https://github.com/oscarotero/Gettext/issues/168
|
||||||
|
[#170]: https://github.com/oscarotero/Gettext/issues/170
|
||||||
|
[#175]: https://github.com/oscarotero/Gettext/issues/175
|
||||||
|
[#177]: https://github.com/oscarotero/Gettext/issues/177
|
||||||
|
[#178]: https://github.com/oscarotero/Gettext/issues/178
|
||||||
|
[#182]: https://github.com/oscarotero/Gettext/issues/182
|
||||||
|
[#187]: https://github.com/oscarotero/Gettext/issues/187
|
||||||
|
[#188]: https://github.com/oscarotero/Gettext/issues/188
|
||||||
|
[#191]: https://github.com/oscarotero/Gettext/issues/191
|
||||||
|
[#197]: https://github.com/oscarotero/Gettext/issues/197
|
||||||
|
[#198]: https://github.com/oscarotero/Gettext/issues/198
|
||||||
|
[#200]: https://github.com/oscarotero/Gettext/issues/200
|
||||||
|
[#205]: https://github.com/oscarotero/Gettext/issues/205
|
||||||
|
[#213]: https://github.com/oscarotero/Gettext/issues/213
|
||||||
|
[#214]: https://github.com/oscarotero/Gettext/issues/214
|
||||||
|
[#215]: https://github.com/oscarotero/Gettext/issues/215
|
||||||
|
[#218]: https://github.com/oscarotero/Gettext/issues/218
|
||||||
|
[#221]: https://github.com/oscarotero/Gettext/issues/221
|
||||||
|
[#223]: https://github.com/oscarotero/Gettext/issues/223
|
||||||
|
[#224]: https://github.com/oscarotero/Gettext/issues/224
|
||||||
|
[#225]: https://github.com/oscarotero/Gettext/issues/225
|
||||||
|
[#226]: https://github.com/oscarotero/Gettext/issues/226
|
||||||
|
[#230]: https://github.com/oscarotero/Gettext/issues/230
|
||||||
|
[#231]: https://github.com/oscarotero/Gettext/issues/231
|
||||||
|
[#238]: https://github.com/oscarotero/Gettext/issues/238
|
||||||
|
[#242]: https://github.com/oscarotero/Gettext/issues/242
|
||||||
|
[#261]: https://github.com/oscarotero/Gettext/issues/261
|
||||||
|
|
||||||
|
[4.8.3]: https://github.com/oscarotero/Gettext/compare/v4.8.2...v4.8.3
|
||||||
|
[4.8.2]: https://github.com/oscarotero/Gettext/compare/v4.8.1...v4.8.2
|
||||||
|
[4.8.1]: https://github.com/oscarotero/Gettext/compare/v4.8.0...v4.8.1
|
||||||
|
[4.8.0]: https://github.com/oscarotero/Gettext/compare/v4.7.0...v4.8.0
|
||||||
|
[4.7.0]: https://github.com/oscarotero/Gettext/compare/v4.6.3...v4.7.0
|
||||||
|
[4.6.3]: https://github.com/oscarotero/Gettext/compare/v4.6.2...v4.6.3
|
||||||
|
[4.6.2]: https://github.com/oscarotero/Gettext/compare/v4.6.1...v4.6.2
|
||||||
|
[4.6.1]: https://github.com/oscarotero/Gettext/compare/v4.6.0...v4.6.1
|
||||||
|
[4.6.0]: https://github.com/oscarotero/Gettext/compare/v4.5.0...v4.6.0
|
||||||
|
[4.5.0]: https://github.com/oscarotero/Gettext/compare/v4.4.4...v4.5.0
|
||||||
|
[4.4.4]: https://github.com/oscarotero/Gettext/compare/v4.4.3...v4.4.4
|
||||||
|
[4.4.3]: https://github.com/oscarotero/Gettext/compare/v4.4.2...v4.4.3
|
||||||
|
[4.4.2]: https://github.com/oscarotero/Gettext/compare/v4.4.1...v4.4.2
|
||||||
|
[4.4.1]: https://github.com/oscarotero/Gettext/compare/v4.4.0...v4.4.1
|
||||||
|
[4.4.0]: https://github.com/oscarotero/Gettext/compare/v4.3.0...v4.4.0
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
Contributing to Gettext
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Looking to contribute something to this library? Here's how you can help.
|
||||||
|
|
||||||
|
## Bugs
|
||||||
|
|
||||||
|
A bug is a demonstrable problem that is caused by the code in the repository. Good bug reports are extremely helpful – thank you!
|
||||||
|
|
||||||
|
Please try to be as detailed as possible in your report. Include specific information about the environment – version of PHP, version of gettext, etc, and steps required to reproduce the issue.
|
||||||
|
|
||||||
|
## Pull Requests
|
||||||
|
|
||||||
|
Good pull requests – patches, improvements, new features – are a fantastic help. New extractors or generator are welcome. Before create a pull request, please follow these instructions:
|
||||||
|
|
||||||
|
* The code must be PSR-2 compliant
|
||||||
|
* Write some tests
|
||||||
Vendored
+21
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2017 Oscar Otero Marzoa
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
Vendored
+425
@@ -0,0 +1,425 @@
|
|||||||
|
Gettext
|
||||||
|
=======
|
||||||
|
|
||||||
|
[](https://travis-ci.org/oscarotero/Gettext)
|
||||||
|
[](https://scrutinizer-ci.com/g/oscarotero/Gettext/?branch=master)
|
||||||
|
[](https://packagist.org/packages/gettext/gettext)
|
||||||
|
[](https://packagist.org/packages/gettext/gettext)
|
||||||
|
[](https://packagist.org/packages/gettext/gettext)
|
||||||
|
[](https://packagist.org/packages/gettext/gettext)
|
||||||
|
|
||||||
|
[](https://insight.sensiolabs.com/projects/496dc2a6-43be-4046-a283-f8370239dd47)
|
||||||
|
|
||||||
|
Created by Oscar Otero <http://oscarotero.com> <oom@oscarotero.com> (MIT License)
|
||||||
|
|
||||||
|
Gettext is a PHP (>=5.4) library to import/export/edit gettext from PO, MO, PHP, JS files, etc.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
With composer (recomended):
|
||||||
|
|
||||||
|
```
|
||||||
|
composer require gettext/gettext
|
||||||
|
```
|
||||||
|
|
||||||
|
If you don't use composer in your project, you have to download and place this package in a directory of your project. You need to install also [gettext/languages](https://github.com/mlocati/cldr-to-gettext-plural-rules). Then, include the autoloaders of both projects in any place of your php code:
|
||||||
|
|
||||||
|
```php
|
||||||
|
include_once "libs/gettext/src/autoloader.php";
|
||||||
|
include_once "libs/cldr-to-gettext-plural-rules/src/autoloader.php";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Classes and functions
|
||||||
|
|
||||||
|
This package contains the following classes:
|
||||||
|
|
||||||
|
* `Gettext\Translation` - A translation definition
|
||||||
|
* `Gettext\Translations` - A collection of translations
|
||||||
|
* `Gettext\Extractors\*` - Import translations from various sources (po, mo, php, js, etc)
|
||||||
|
* `Gettext\Generators\*` - Export translations to various formats (po, mo, php, json, etc)
|
||||||
|
* `Gettext\Translator` - To use the translations in your php templates instead the [gettext extension](http://php.net/gettext)
|
||||||
|
* `Gettext\GettextTranslator` - To use the [gettext extension](http://php.net/gettext)
|
||||||
|
|
||||||
|
## Usage example
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Gettext\Translations;
|
||||||
|
|
||||||
|
//import from a .po file:
|
||||||
|
$translations = Translations::fromPoFile('locales/gl.po');
|
||||||
|
|
||||||
|
//edit some translations:
|
||||||
|
$translation = $translations->find(null, 'apple');
|
||||||
|
|
||||||
|
if ($translation) {
|
||||||
|
$translation->setTranslation('Mazá');
|
||||||
|
}
|
||||||
|
|
||||||
|
//export to a php array:
|
||||||
|
$translations->toPhpArrayFile('locales/gl.php');
|
||||||
|
|
||||||
|
//and to a .mo file
|
||||||
|
$translations->toMoFile('Locale/gl/LC_MESSAGES/messages.mo');
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want use this translations in your php templates without using the gettext extension:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Gettext\Translator;
|
||||||
|
|
||||||
|
//Create the translator instance
|
||||||
|
$t = new Translator();
|
||||||
|
|
||||||
|
//Load your translations (exported as PhpArray):
|
||||||
|
$t->loadTranslations('locales/gl.php');
|
||||||
|
|
||||||
|
//Use it:
|
||||||
|
echo $t->gettext('apple'); // "Mazá"
|
||||||
|
|
||||||
|
//If you want use global functions:
|
||||||
|
$t->register();
|
||||||
|
|
||||||
|
echo __('apple'); // "Mazá"
|
||||||
|
```
|
||||||
|
|
||||||
|
To use this translations with the gettext extension:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Gettext\GettextTranslator;
|
||||||
|
|
||||||
|
//Create the translator instance
|
||||||
|
$t = new GettextTranslator();
|
||||||
|
|
||||||
|
//Set the language and load the domain
|
||||||
|
$t->setLanguage('gl');
|
||||||
|
$t->loadDomain('messages', 'Locale');
|
||||||
|
|
||||||
|
//Use it:
|
||||||
|
echo $t->gettext('apple'); // "Mazá"
|
||||||
|
|
||||||
|
//Or use the gettext functions
|
||||||
|
echo gettext('apple'); // "Mazá"
|
||||||
|
|
||||||
|
//If you want use the global functions
|
||||||
|
$t->register();
|
||||||
|
|
||||||
|
echo __('apple'); // "Mazá"
|
||||||
|
|
||||||
|
//And use sprintf/strtr placeholders
|
||||||
|
echo __('Hello %s', 'world'); //Hello world
|
||||||
|
echo __('Hello {name}', ['{name}' => 'world']); //Hello world
|
||||||
|
```
|
||||||
|
|
||||||
|
The benefits of using the functions provided by this library (`__()` instead `_()` or `gettext()`) are:
|
||||||
|
|
||||||
|
* You are using the same functions, no matter whether the translations are provided by gettext extension or any other method.
|
||||||
|
* You can use variables easier because `sprintf` functionality is included. For example: `__('Hello %s', 'world')` instead `sprintf(_('Hello %s'), 'world')`.
|
||||||
|
* You can also use named placeholders if the second argument is an array. For example: `__('Hello %name%', ['%name%' => 'world'])` instead of `strtr(_('Hello %name%'), ['%name%' => 'world'])`.
|
||||||
|
|
||||||
|
## Translation
|
||||||
|
|
||||||
|
The `Gettext\Translation` class stores all information about a translation: the original text, the translated text, source references, comments, etc.
|
||||||
|
|
||||||
|
```php
|
||||||
|
// __construct($context, $original, $plural)
|
||||||
|
$translation = new Gettext\Translation('comments', 'One comment', '%s comments');
|
||||||
|
|
||||||
|
$translation->setTranslation('Un comentario');
|
||||||
|
$translation->setPluralTranslation('%s comentarios');
|
||||||
|
|
||||||
|
$translation->addReference('templates/comments/comment.php', 34);
|
||||||
|
$translation->addComment('To display the amount of comments in a post');
|
||||||
|
|
||||||
|
echo $translation->getContext(); // comments
|
||||||
|
echo $translation->getOriginal(); // One comment
|
||||||
|
echo $translation->getTranslation(); // Un comentario
|
||||||
|
|
||||||
|
// etc...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Translations
|
||||||
|
|
||||||
|
The `Gettext\Translations` class stores a collection of translations:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$translations = new Gettext\Translations();
|
||||||
|
|
||||||
|
//You can add new translations using the array syntax
|
||||||
|
$translations[] = new Gettext\Translation('comments', 'One comment', '%s comments');
|
||||||
|
|
||||||
|
//Or using the "insert" method
|
||||||
|
$insertedTranslation = $translations->insert('comments', 'One comment', '%s comments');
|
||||||
|
|
||||||
|
//Find a specific translation
|
||||||
|
$translation = $translations->find('comments', 'One comment');
|
||||||
|
|
||||||
|
//Edit headers, domain, etc
|
||||||
|
$translations->setHeader('Last-Translator', 'Oscar Otero');
|
||||||
|
$translations->setDomain('my-blog');
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extractors
|
||||||
|
|
||||||
|
The extrators allows to fetch gettext values from any source. For example, to scan a .po file:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$translations = new Gettext\Translations();
|
||||||
|
|
||||||
|
//From a file
|
||||||
|
Gettext\Extractors\Po::fromFile('locales/en.po', $translations);
|
||||||
|
|
||||||
|
//From a string
|
||||||
|
$string = file_get_contents('locales2/en.po');
|
||||||
|
Gettext\Extractors\Po::fromString($string, $translations);
|
||||||
|
```
|
||||||
|
|
||||||
|
The better way to use extractors is using the magic methods of `Gettext\Translations`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
//Create a Translations instance using a po file
|
||||||
|
$translations = Gettext\Translations::fromPoFile('locales/en.po');
|
||||||
|
|
||||||
|
//Add more messages from other files
|
||||||
|
$translations->addFromPoFile('locales2/en.po');
|
||||||
|
```
|
||||||
|
|
||||||
|
The available extractors are the following:
|
||||||
|
|
||||||
|
Name | Description | Example
|
||||||
|
---- | ----------- | --------
|
||||||
|
**Blade** | Scans a Blade template (For laravel users). | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/blade/input.php)
|
||||||
|
**Csv** | Gets the messages from csv. | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/Csv.csv)
|
||||||
|
**CsvDictionary** | Gets the messages from csv (without plurals and context). | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/CsvDictionary.csv)
|
||||||
|
**Jed** | Gets the messages from a json compatible with [Jed](http://slexaxton.github.com/Jed/). | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/Jed.json)
|
||||||
|
**JsCode** | Scans javascript code looking for all gettext functions (the same than PhpCode but for javascript). You can use [the javascript gettext-translator library](https://github.com/oscarotero/gettext-translator) | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/jscode/input.js)
|
||||||
|
**Json** | Gets the messages from json compatible with [gettext-translator](https://github.com/oscarotero/gettext-translator). | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/Json.json)
|
||||||
|
**JsonDictionary** | Gets the messages from a json (without plurals and context). | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/JsonDictionary.json)
|
||||||
|
**Mo** | Gets the messages from MO. | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/Mo.mo)
|
||||||
|
**PhpArray** | Gets the messages from a php file that returns an array. | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/PhpArray.php)
|
||||||
|
**PhpCode** | Scans php code looking for all gettext functions (see `translator_functions.php`). | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/phpcode/input.php)
|
||||||
|
**Po** | Gets the messages from PO. | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/Po.po)
|
||||||
|
**Twig** | To scan a Twig template. | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/twig/input.php)
|
||||||
|
**Xliff** | Gets the messages from [xliff (2.0)](http://docs.oasis-open.org/xliff/xliff-core/v2.0/os/xliff-core-v2.0-os.html). | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/Xliff.xlf)
|
||||||
|
**Yaml** | Gets the messages from yaml. | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/Yaml.yml)
|
||||||
|
**YamlDictionary** | Gets the messages from a yaml (without plurals and context). | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/YamlDictionary.yml)
|
||||||
|
**VueJs** | Gets the messages from a VueJs template. | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/vuejs/input.vue)
|
||||||
|
|
||||||
|
## Generators
|
||||||
|
|
||||||
|
The generators export a `Gettext\Translations` instance to any format (po, mo, array, etc).
|
||||||
|
|
||||||
|
```php
|
||||||
|
//Save to a file
|
||||||
|
Gettext\Generators\Po::toFile($translations, 'locales/en.po');
|
||||||
|
|
||||||
|
//Return as a string
|
||||||
|
$content = Gettext\Generators\Po::toString($translations);
|
||||||
|
file_put_contents('locales/en.po', $content);
|
||||||
|
```
|
||||||
|
|
||||||
|
Like extractors, the better way to use generators is using the magic methods of `Gettext\Translations`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
//Extract messages from a php code file
|
||||||
|
$translations = Gettext\Translations::fromPhpCodeFile('templates/index.php');
|
||||||
|
|
||||||
|
//Export to a po file
|
||||||
|
$translations->toPoFile('locales/en.po');
|
||||||
|
|
||||||
|
//Export to a po string
|
||||||
|
$content = $translations->toPoString();
|
||||||
|
file_put_contents('locales/en.po', $content);
|
||||||
|
```
|
||||||
|
|
||||||
|
The available generators are the following:
|
||||||
|
|
||||||
|
Name | Description | Example
|
||||||
|
---- | ----------- | --------
|
||||||
|
**Csv** | Exports to csv. | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/Csv.csv)
|
||||||
|
**CsvDictionary** | Exports to csv (without plurals and context). | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/CsvDictionary.csv)
|
||||||
|
**Json** | Exports to json, compatible with [gettext-translator](https://github.com/oscarotero/gettext-translator). | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/Json.json)
|
||||||
|
**JsonDictionary** | Exports to json (without plurals and context). | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/JsonDictionary.json)
|
||||||
|
**Mo** | Exports to Mo. | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/Mo.mo)
|
||||||
|
**PhpArray** | Exports to php code that returns an array. | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/PhpArray.php)
|
||||||
|
**Po** | Exports to Po. | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/Po.po)
|
||||||
|
**Jed** | Exports to json format compatible with [Jed](http://slexaxton.github.com/Jed/). | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/Jed.json)
|
||||||
|
**Xliff** | Exports to [xliff (2.0)](http://docs.oasis-open.org/xliff/xliff-core/v2.0/os/xliff-core-v2.0-os.html). | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/Xliff.xlf)
|
||||||
|
**Yaml** | Exports to yaml. | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/Yaml.yml)
|
||||||
|
**YamlDictionary** | Exports to yaml (without plurals and context). | [example](https://github.com/oscarotero/Gettext/blob/master/tests/assets/po/YamlDictionary.yml)
|
||||||
|
|
||||||
|
## Translator
|
||||||
|
|
||||||
|
The class `Gettext\Translator` implements the gettext functions in php. Useful if you don't have the native gettext extension for php or want to avoid problems with it. You can load the translations from a php array file or using a `Gettext\Translations` instance:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Gettext\Translator;
|
||||||
|
|
||||||
|
//Create a new instance of the translator
|
||||||
|
$t = new Translator();
|
||||||
|
|
||||||
|
//Load the translations using any of the following ways:
|
||||||
|
|
||||||
|
// 1. from php files (generated by Gettext\Extractors\PhpArray)
|
||||||
|
$t->loadTranslations('locales/gl.php');
|
||||||
|
|
||||||
|
// 2. using the array directly
|
||||||
|
$array = include 'locales/gl.php';
|
||||||
|
$t->loadTranslations($array);
|
||||||
|
|
||||||
|
// 3. using a Gettext\Translations instance (slower)
|
||||||
|
$translations = Gettext\Translations::fromPoFile('locales/gl.po');
|
||||||
|
$t->loadTranslations($translations);
|
||||||
|
|
||||||
|
//Now you can use it in your templates
|
||||||
|
echo $t->gettext('apple');
|
||||||
|
```
|
||||||
|
|
||||||
|
## GettextTranslator
|
||||||
|
|
||||||
|
The class `Gettext\GettextTranslator` uses the gettext extension. It's useful because combines the performance of using real gettext functions but with the same API than `Translator` class, so you can switch to one or other translator deppending of the environment without change code of your app.
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Gettext\GettextTranslator;
|
||||||
|
|
||||||
|
//Create a new instance
|
||||||
|
$t = new GettextTranslator();
|
||||||
|
|
||||||
|
//It detects the environment variables to set the locale, but you can change it:
|
||||||
|
$t->setLanguage('gl');
|
||||||
|
|
||||||
|
//Load the domains:
|
||||||
|
$t->loadDomain('messages', 'project/Locale');
|
||||||
|
//this means you have the file "project/Locale/gl/LC_MESSAGES/messages.po"
|
||||||
|
|
||||||
|
//Now you can use it in your templates
|
||||||
|
echo $t->gettext('apple');
|
||||||
|
```
|
||||||
|
|
||||||
|
## Global functions
|
||||||
|
|
||||||
|
To ease the use of translations in your php templates, you can use the provided functions:
|
||||||
|
|
||||||
|
```php
|
||||||
|
//Register the translator to use the global functions
|
||||||
|
$t->register();
|
||||||
|
|
||||||
|
echo __('apple'); // it's the same than $t->gettext('apple');
|
||||||
|
```
|
||||||
|
|
||||||
|
You can scan the php files containing these functions and extract the values with the PhpCode extractor:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- index.php -->
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<?= __('Hello world'); ?>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Merge translations
|
||||||
|
|
||||||
|
To work with different translations you may want merge them in an unique file. There are two ways to do this:
|
||||||
|
|
||||||
|
The simplest way is adding new translations:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Gettext\Translations;
|
||||||
|
|
||||||
|
$translations = Translations::fromPoFile('my-file1.po');
|
||||||
|
$translations->addFromPoFile('my-file2.po');
|
||||||
|
```
|
||||||
|
|
||||||
|
A more advanced way is merge two `Translations` instances:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Gettext\Translations;
|
||||||
|
|
||||||
|
//Create a new Translations instances with our translations.
|
||||||
|
|
||||||
|
$translations1 = Translations::fromPoFile('my-file1.po');
|
||||||
|
$translations2 = Translations::fromPoFile('my-file2.po');
|
||||||
|
|
||||||
|
//Merge one inside other:
|
||||||
|
$translations1->mergeWith($translations2);
|
||||||
|
|
||||||
|
//Now translations1 has all values
|
||||||
|
```
|
||||||
|
|
||||||
|
The second argument of `mergeWith` defines how the merge will be done. Use the `Gettext\Merge` constants to configure the merging:
|
||||||
|
|
||||||
|
Constant | Description
|
||||||
|
--------- | -----------
|
||||||
|
`Merge::ADD` | Adds the translations from `$translations2` that are missing
|
||||||
|
`Merge::REMOVE` | Removes the translations missing in `$translations2`
|
||||||
|
`Merge::HEADERS_ADD` | Adds the headers from `$translations2` that are missing
|
||||||
|
`Merge::HEADERS_REMOVE` | Removes the headers missing in `$translations2`
|
||||||
|
`Merge::HEADERS_OVERRIDE` | Overrides the headers with the values of `$translations2`
|
||||||
|
`Merge::LANGUAGE_OVERRIDE` | Set the language defined in `$translations2`
|
||||||
|
`Merge::DOMAIN_OVERRIDE` | Set the domain defined in `$translations2`
|
||||||
|
`Merge::TRANSLATION_OVERRIDE` | Override the translation and plural translations with the value of `$translation2`
|
||||||
|
`Merge::COMMENTS_OURS` | Use only the comments of `$translation1`
|
||||||
|
`Merge::COMMENTS_THEIRS` | Use only the comments of `$translation2`
|
||||||
|
`Merge::EXTRACTED_COMMENTS_OURS` | Use only the extracted comments of `$translation1`
|
||||||
|
`Merge::EXTRACTED_COMMENTS_THEIRS` | Use only the extracted comments of `$translation2`
|
||||||
|
`Merge::FLAGS_OURS` | Use only the flags of `$translation1`
|
||||||
|
`Merge::FLAGS_THEIRS` | Use only the flags of `$translation2`
|
||||||
|
`Merge::REFERENCES_OURS` | Use only the references of `$translation1`
|
||||||
|
`Merge::REFERENCES_THEIRS` | Use only the references of `$translation2`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Merge;
|
||||||
|
|
||||||
|
//Scan the php code to find the latest gettext translations
|
||||||
|
$phpTranslations = Translations::fromPhpCodeFile('my-templates.php');
|
||||||
|
|
||||||
|
//Get the translations of the code that are stored in a po file
|
||||||
|
$poTranslations = Translations::fromPoFile('locale.po');
|
||||||
|
|
||||||
|
//Merge the translations from the po file using the references from `$phpTranslations`:
|
||||||
|
$translations->mergeWith($poTranslations, Merge::REFERENCES_OURS);
|
||||||
|
|
||||||
|
//Now save a po file with the result
|
||||||
|
$translations->toPoFile('locale.po');
|
||||||
|
```
|
||||||
|
|
||||||
|
Note, if the second argument is not defined, the default value is `Merge::DEFAULTS` that's equivalent to `Merge::ADD | Merge::HEADERS_ADD`.
|
||||||
|
|
||||||
|
## Use from CLI
|
||||||
|
|
||||||
|
There's a Robo task to use this library from the command line interface: https://github.com/oscarotero/GettextRobo
|
||||||
|
|
||||||
|
## Use in the browser
|
||||||
|
|
||||||
|
If you want to use your translations in the browser, there's a javascript translator: https://github.com/oscarotero/gettext-translator
|
||||||
|
|
||||||
|
## Third party packages
|
||||||
|
|
||||||
|
Twig integration:
|
||||||
|
|
||||||
|
* [jaimeperez/twig-configurable-i18n](https://packagist.org/packages/jaimeperez/twig-configurable-i18n)
|
||||||
|
* [cemerson/translator-twig-extension](https://packagist.org/packages/cemerson/translator-twig-extension)
|
||||||
|
|
||||||
|
Framework integration:
|
||||||
|
|
||||||
|
* [Laravel 5](https://packagist.org/packages/eusonlito/laravel-gettext)
|
||||||
|
* [CakePHP 3](https://packagist.org/packages/k1low/po)
|
||||||
|
* [Symfony 2](https://packagist.org/packages/mablae/gettext-bundle)
|
||||||
|
|
||||||
|
[add your package](https://github.com/oscarotero/Gettext/issues/new)
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
Thanks to all [contributors](https://github.com/oscarotero/Gettext/graphs/contributors) specially to [@mlocati](https://github.com/mlocati).
|
||||||
|
|
||||||
|
## Donations
|
||||||
|
|
||||||
|
If this library is useful for you, consider to donate to the author.
|
||||||
|
|
||||||
|
[Buy me a beer :beer:](https://www.paypal.me/oscarotero)
|
||||||
|
|
||||||
|
Thanks in advance!
|
||||||
Vendored
+54
@@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"name": "gettext/gettext",
|
||||||
|
"type": "library",
|
||||||
|
"description": "PHP gettext manager",
|
||||||
|
"keywords": ["js", "gettext", "i18n", "translation", "po", "mo"],
|
||||||
|
"homepage": "https://github.com/oscarotero/Gettext",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Oscar Otero",
|
||||||
|
"email": "oom@oscarotero.com",
|
||||||
|
"homepage": "http://oscarotero.com",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"email": "oom@oscarotero.com",
|
||||||
|
"issues": "https://github.com/oscarotero/Gettext/issues"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.4.0",
|
||||||
|
"gettext/languages": "^2.3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"illuminate/view": "*",
|
||||||
|
"twig/twig": "^1.31|^2.0",
|
||||||
|
"twig/extensions": "*",
|
||||||
|
"symfony/yaml": "~2",
|
||||||
|
"phpunit/phpunit": "^4.8|^5.7|^6.5",
|
||||||
|
"squizlabs/php_codesniffer": "^3.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"illuminate/view": "Is necessary if you want to use the Blade extractor",
|
||||||
|
"twig/twig": "Is necessary if you want to use the Twig extractor",
|
||||||
|
"twig/extensions": "Is necessary if you want to use the Twig extractor",
|
||||||
|
"symfony/yaml": "Is necessary if you want to use the Yaml extractor/generator"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Gettext\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"Gettext\\Tests\\": "tests"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": [
|
||||||
|
"phpunit",
|
||||||
|
"phpcs"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext;
|
||||||
|
|
||||||
|
abstract class BaseTranslator implements TranslatorInterface
|
||||||
|
{
|
||||||
|
/** @var TranslatorInterface */
|
||||||
|
public static $current;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TranslatorInterface
|
||||||
|
*/
|
||||||
|
public function noop($original)
|
||||||
|
{
|
||||||
|
return $original;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TranslatorInterface
|
||||||
|
*/
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
$previous = static::$current;
|
||||||
|
|
||||||
|
static::$current = $this;
|
||||||
|
|
||||||
|
static::includeFunctions();
|
||||||
|
|
||||||
|
return $previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Include the gettext functions
|
||||||
|
*/
|
||||||
|
public static function includeFunctions()
|
||||||
|
{
|
||||||
|
include_once __DIR__.'/translator_functions.php';
|
||||||
|
}
|
||||||
|
}
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Illuminate\Filesystem\Filesystem;
|
||||||
|
use Illuminate\View\Compilers\BladeCompiler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from blade.php files returning arrays.
|
||||||
|
*/
|
||||||
|
class Blade extends Extractor implements ExtractorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
if (empty($options['facade'])) {
|
||||||
|
$cachePath = empty($options['cachePath']) ? sys_get_temp_dir() : $options['cachePath'];
|
||||||
|
$bladeCompiler = new BladeCompiler(new Filesystem(), $cachePath);
|
||||||
|
|
||||||
|
if (method_exists($bladeCompiler, 'withoutComponentTags')) {
|
||||||
|
$bladeCompiler->withoutComponentTags();
|
||||||
|
}
|
||||||
|
|
||||||
|
$string = $bladeCompiler->compileString($string);
|
||||||
|
} else {
|
||||||
|
$string = $options['facade']::compileString($string);
|
||||||
|
}
|
||||||
|
|
||||||
|
PhpCode::fromString($string, $translations, $options);
|
||||||
|
}
|
||||||
|
}
|
||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\HeadersExtractorTrait;
|
||||||
|
use Gettext\Utils\CsvTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from csv.
|
||||||
|
*/
|
||||||
|
class Csv extends Extractor implements ExtractorInterface
|
||||||
|
{
|
||||||
|
use HeadersExtractorTrait;
|
||||||
|
use CsvTrait;
|
||||||
|
|
||||||
|
public static $options = [
|
||||||
|
'delimiter' => ",",
|
||||||
|
'enclosure' => '"',
|
||||||
|
'escape_char' => "\\"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$options += static::$options;
|
||||||
|
$handle = fopen('php://memory', 'w');
|
||||||
|
|
||||||
|
fputs($handle, $string);
|
||||||
|
rewind($handle);
|
||||||
|
|
||||||
|
while ($row = static::fgetcsv($handle, $options)) {
|
||||||
|
$context = array_shift($row);
|
||||||
|
$original = array_shift($row);
|
||||||
|
|
||||||
|
if ($context === '' && $original === '') {
|
||||||
|
static::extractHeaders(array_shift($row), $translations);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$translation = $translations->insert($context, $original);
|
||||||
|
|
||||||
|
if (!empty($row)) {
|
||||||
|
$translation->setTranslation(array_shift($row));
|
||||||
|
$translation->setPluralTranslations($row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\HeadersExtractorTrait;
|
||||||
|
use Gettext\Utils\CsvTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from csv.
|
||||||
|
*/
|
||||||
|
class CsvDictionary extends Extractor implements ExtractorInterface
|
||||||
|
{
|
||||||
|
use HeadersExtractorTrait;
|
||||||
|
use CsvTrait;
|
||||||
|
|
||||||
|
public static $options = [
|
||||||
|
'delimiter' => ",",
|
||||||
|
'enclosure' => '"',
|
||||||
|
'escape_char' => "\\"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$options += static::$options;
|
||||||
|
$handle = fopen('php://memory', 'w');
|
||||||
|
|
||||||
|
fputs($handle, $string);
|
||||||
|
rewind($handle);
|
||||||
|
|
||||||
|
while ($row = static::fgetcsv($handle, $options)) {
|
||||||
|
list($original, $translation) = $row + ['', ''];
|
||||||
|
|
||||||
|
if ($original === '') {
|
||||||
|
static::extractHeaders($translation, $translations);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$translations->insert(null, $original)->setTranslation($translation);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use Gettext\Translations;
|
||||||
|
|
||||||
|
abstract class Extractor implements ExtractorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function fromFile($file, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
foreach (static::getFiles($file) as $file) {
|
||||||
|
$options['file'] = $file;
|
||||||
|
static::fromString(static::readFile($file), $translations, $options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks and returns all files.
|
||||||
|
*
|
||||||
|
* @param string|array $file The file/s
|
||||||
|
*
|
||||||
|
* @return array The file paths
|
||||||
|
*/
|
||||||
|
protected static function getFiles($file)
|
||||||
|
{
|
||||||
|
if (empty($file)) {
|
||||||
|
throw new InvalidArgumentException('There is not any file defined');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string($file)) {
|
||||||
|
if (!is_file($file)) {
|
||||||
|
throw new InvalidArgumentException("'$file' is not a valid file");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_readable($file)) {
|
||||||
|
throw new InvalidArgumentException("'$file' is not a readable file");
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$file];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($file)) {
|
||||||
|
$files = [];
|
||||||
|
|
||||||
|
foreach ($file as $f) {
|
||||||
|
$files = array_merge($files, static::getFiles($f));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidArgumentException('The first argument must be string or array');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads and returns the content of a file.
|
||||||
|
*
|
||||||
|
* @param string $file
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected static function readFile($file)
|
||||||
|
{
|
||||||
|
$length = filesize($file);
|
||||||
|
|
||||||
|
if (!($fd = fopen($file, 'rb'))) {
|
||||||
|
throw new Exception("Cannot read the file '$file', probably permissions");
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = $length ? fread($fd, $length) : '';
|
||||||
|
fclose($fd);
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
|
||||||
|
interface ExtractorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Extract the translations from a file.
|
||||||
|
*
|
||||||
|
* @param array|string $file A path of a file or files
|
||||||
|
* @param Translations $translations The translations instance to append the new translations.
|
||||||
|
* @param array $options
|
||||||
|
*/
|
||||||
|
public static function fromFile($file, Translations $translations, array $options = []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a string and append the translations found in the Translations instance.
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
* @param Translations $translations
|
||||||
|
* @param array $options
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = []);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
|
||||||
|
interface ExtractorMultiInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Parses a string and append the translations found in the Translations instance.
|
||||||
|
* Allows scanning for multiple domains at a time (each Translation has to have a different domain)
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
* @param Translations[] $translations
|
||||||
|
* @param array $options
|
||||||
|
*/
|
||||||
|
public static function fromStringMultiple($string, array $translations, array $options = []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a string and append the translations found in the Translations instance.
|
||||||
|
* Allows scanning for multiple domains at a time (each Translation has to have a different domain)
|
||||||
|
*
|
||||||
|
* @param $file
|
||||||
|
* @param Translations[] $translations
|
||||||
|
* @param array $options
|
||||||
|
*/
|
||||||
|
public static function fromFileMultiple($file, array $translations, array $options = []);
|
||||||
|
}
|
||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from json files.
|
||||||
|
*/
|
||||||
|
class Jed extends Extractor implements ExtractorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
static::extract(json_decode($string, true), $translations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an array of translations and append to the Translations instance.
|
||||||
|
*
|
||||||
|
* @param array $content
|
||||||
|
* @param Translations $translations
|
||||||
|
*/
|
||||||
|
public static function extract(array $content, Translations $translations)
|
||||||
|
{
|
||||||
|
$messages = current($content);
|
||||||
|
$headers = isset($messages['']) ? $messages[''] : null;
|
||||||
|
unset($messages['']);
|
||||||
|
|
||||||
|
if (!empty($headers['domain'])) {
|
||||||
|
$translations->setDomain($headers['domain']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($headers['lang'])) {
|
||||||
|
$translations->setLanguage($headers['lang']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($headers['plural-forms'])) {
|
||||||
|
$translations->setHeader(Translations::HEADER_PLURAL, $headers['plural-forms']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$context_glue = '\u0004';
|
||||||
|
|
||||||
|
foreach ($messages as $key => $translation) {
|
||||||
|
$key = explode($context_glue, $key);
|
||||||
|
$context = isset($key[1]) ? array_shift($key) : '';
|
||||||
|
|
||||||
|
$translations->insert($context, array_shift($key))
|
||||||
|
->setTranslation(array_shift($translation))
|
||||||
|
->setPluralTranslations($translation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\FunctionsScanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from javascript files.
|
||||||
|
*/
|
||||||
|
class JsCode extends Extractor implements ExtractorInterface, ExtractorMultiInterface
|
||||||
|
{
|
||||||
|
public static $options = [
|
||||||
|
'constants' => [],
|
||||||
|
|
||||||
|
'functions' => [
|
||||||
|
'gettext' => 'gettext',
|
||||||
|
'__' => 'gettext',
|
||||||
|
'ngettext' => 'ngettext',
|
||||||
|
'n__' => 'ngettext',
|
||||||
|
'pgettext' => 'pgettext',
|
||||||
|
'p__' => 'pgettext',
|
||||||
|
'dgettext' => 'dgettext',
|
||||||
|
'd__' => 'dgettext',
|
||||||
|
'dngettext' => 'dngettext',
|
||||||
|
'dn__' => 'dngettext',
|
||||||
|
'dpgettext' => 'dpgettext',
|
||||||
|
'dp__' => 'dpgettext',
|
||||||
|
'npgettext' => 'npgettext',
|
||||||
|
'np__' => 'npgettext',
|
||||||
|
'dnpgettext' => 'dnpgettext',
|
||||||
|
'dnp__' => 'dnpgettext',
|
||||||
|
'noop' => 'noop',
|
||||||
|
'noop__' => 'noop',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
protected static $functionsScannerClass = 'Gettext\Utils\JsFunctionsScanner';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
static::fromStringMultiple($string, [$translations], $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function fromStringMultiple($string, array $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$options += static::$options;
|
||||||
|
|
||||||
|
/** @var FunctionsScanner $functions */
|
||||||
|
$functions = new static::$functionsScannerClass($string);
|
||||||
|
$functions->saveGettextFunctions($translations, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function fromFileMultiple($file, array $translations, array $options = [])
|
||||||
|
{
|
||||||
|
foreach (static::getFiles($file) as $file) {
|
||||||
|
$options['file'] = $file;
|
||||||
|
static::fromStringMultiple(static::readFile($file), $translations, $options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\MultidimensionalArrayTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from json.
|
||||||
|
*/
|
||||||
|
class Json extends Extractor implements ExtractorInterface
|
||||||
|
{
|
||||||
|
use MultidimensionalArrayTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$messages = json_decode($string, true);
|
||||||
|
|
||||||
|
if (is_array($messages)) {
|
||||||
|
static::fromArray($messages, $translations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\DictionaryTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from plain json.
|
||||||
|
*/
|
||||||
|
class JsonDictionary extends Extractor implements ExtractorInterface
|
||||||
|
{
|
||||||
|
use DictionaryTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$messages = json_decode($string, true);
|
||||||
|
|
||||||
|
if (is_array($messages)) {
|
||||||
|
static::fromArray($messages, $translations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+131
@@ -0,0 +1,131 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\StringReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from .mo files.
|
||||||
|
*/
|
||||||
|
class Mo extends Extractor implements ExtractorInterface
|
||||||
|
{
|
||||||
|
const MAGIC1 = -1794895138;
|
||||||
|
const MAGIC2 = -569244523;
|
||||||
|
const MAGIC3 = 2500072158;
|
||||||
|
|
||||||
|
protected static $stringReaderClass = 'Gettext\Utils\StringReader';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
/** @var StringReader $stream */
|
||||||
|
$stream = new static::$stringReaderClass($string);
|
||||||
|
$magic = static::readInt($stream, 'V');
|
||||||
|
|
||||||
|
if (($magic === static::MAGIC1) || ($magic === static::MAGIC3)) { //to make sure it works for 64-bit platforms
|
||||||
|
$byteOrder = 'V'; //low endian
|
||||||
|
} elseif ($magic === (static::MAGIC2 & 0xFFFFFFFF)) {
|
||||||
|
$byteOrder = 'N'; //big endian
|
||||||
|
} else {
|
||||||
|
throw new Exception('Not MO file');
|
||||||
|
}
|
||||||
|
|
||||||
|
static::readInt($stream, $byteOrder);
|
||||||
|
|
||||||
|
$total = static::readInt($stream, $byteOrder); //total string count
|
||||||
|
$originals = static::readInt($stream, $byteOrder); //offset of original table
|
||||||
|
$tran = static::readInt($stream, $byteOrder); //offset of translation table
|
||||||
|
|
||||||
|
$stream->seekto($originals);
|
||||||
|
$table_originals = static::readIntArray($stream, $byteOrder, $total * 2);
|
||||||
|
|
||||||
|
$stream->seekto($tran);
|
||||||
|
$table_translations = static::readIntArray($stream, $byteOrder, $total * 2);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $total; ++$i) {
|
||||||
|
$next = $i * 2;
|
||||||
|
|
||||||
|
$stream->seekto($table_originals[$next + 2]);
|
||||||
|
$original = $stream->read($table_originals[$next + 1]);
|
||||||
|
|
||||||
|
$stream->seekto($table_translations[$next + 2]);
|
||||||
|
$translated = $stream->read($table_translations[$next + 1]);
|
||||||
|
|
||||||
|
if ($original === '') {
|
||||||
|
// Headers
|
||||||
|
foreach (explode("\n", $translated) as $headerLine) {
|
||||||
|
if ($headerLine === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$headerChunks = preg_split('/:\s*/', $headerLine, 2);
|
||||||
|
$translations->setHeader($headerChunks[0], isset($headerChunks[1]) ? $headerChunks[1] : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$chunks = explode("\x04", $original, 2);
|
||||||
|
|
||||||
|
if (isset($chunks[1])) {
|
||||||
|
$context = $chunks[0];
|
||||||
|
$original = $chunks[1];
|
||||||
|
} else {
|
||||||
|
$context = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$chunks = explode("\x00", $original, 2);
|
||||||
|
|
||||||
|
if (isset($chunks[1])) {
|
||||||
|
$original = $chunks[0];
|
||||||
|
$plural = $chunks[1];
|
||||||
|
} else {
|
||||||
|
$plural = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$translation = $translations->insert($context, $original, $plural);
|
||||||
|
|
||||||
|
if ($translated === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($plural === '') {
|
||||||
|
$translation->setTranslation($translated);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$v = explode("\x00", $translated);
|
||||||
|
$translation->setTranslation(array_shift($v));
|
||||||
|
$translation->setPluralTranslations($v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param StringReader $stream
|
||||||
|
* @param string $byteOrder
|
||||||
|
*/
|
||||||
|
protected static function readInt(StringReader $stream, $byteOrder)
|
||||||
|
{
|
||||||
|
if (($read = $stream->read(4)) === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$read = unpack($byteOrder, $read);
|
||||||
|
|
||||||
|
return array_shift($read);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param StringReader $stream
|
||||||
|
* @param string $byteOrder
|
||||||
|
* @param int $count
|
||||||
|
*/
|
||||||
|
protected static function readIntArray(StringReader $stream, $byteOrder, $count)
|
||||||
|
{
|
||||||
|
return unpack($byteOrder.$count, $stream->read(4 * $count));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use BadMethodCallException;
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\MultidimensionalArrayTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from php files returning arrays.
|
||||||
|
*/
|
||||||
|
class PhpArray extends Extractor implements ExtractorInterface
|
||||||
|
{
|
||||||
|
use MultidimensionalArrayTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function fromFile($file, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
foreach (static::getFiles($file) as $file) {
|
||||||
|
static::fromArray(include($file), $translations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('PhpArray::fromString() cannot be called. Use PhpArray::fromFile()');
|
||||||
|
}
|
||||||
|
}
|
||||||
+170
@@ -0,0 +1,170 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\FunctionsScanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from php files returning arrays.
|
||||||
|
*/
|
||||||
|
class PhpCode extends Extractor implements ExtractorInterface, ExtractorMultiInterface
|
||||||
|
{
|
||||||
|
public static $options = [
|
||||||
|
// - false: to not extract comments
|
||||||
|
// - empty string: to extract all comments
|
||||||
|
// - non-empty string: to extract comments that start with that string
|
||||||
|
// - array with strings to extract comments format.
|
||||||
|
'extractComments' => false,
|
||||||
|
|
||||||
|
'constants' => [],
|
||||||
|
|
||||||
|
'functions' => [
|
||||||
|
'gettext' => 'gettext',
|
||||||
|
'__' => 'gettext',
|
||||||
|
'ngettext' => 'ngettext',
|
||||||
|
'n__' => 'ngettext',
|
||||||
|
'pgettext' => 'pgettext',
|
||||||
|
'p__' => 'pgettext',
|
||||||
|
'dgettext' => 'dgettext',
|
||||||
|
'd__' => 'dgettext',
|
||||||
|
'dngettext' => 'dngettext',
|
||||||
|
'dn__' => 'dngettext',
|
||||||
|
'dpgettext' => 'dpgettext',
|
||||||
|
'dp__' => 'dpgettext',
|
||||||
|
'npgettext' => 'npgettext',
|
||||||
|
'np__' => 'npgettext',
|
||||||
|
'dnpgettext' => 'dnpgettext',
|
||||||
|
'dnp__' => 'dnpgettext',
|
||||||
|
'noop' => 'noop',
|
||||||
|
'noop__' => 'noop',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
protected static $functionsScannerClass = 'Gettext\Utils\PhpFunctionsScanner';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
static::fromStringMultiple($string, [$translations], $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function fromStringMultiple($string, array $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$options += static::$options;
|
||||||
|
|
||||||
|
/** @var FunctionsScanner $functions */
|
||||||
|
$functions = new static::$functionsScannerClass($string);
|
||||||
|
|
||||||
|
if ($options['extractComments'] !== false) {
|
||||||
|
$functions->enableCommentsExtraction($options['extractComments']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$functions->saveGettextFunctions($translations, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public static function fromFileMultiple($file, array $translations, array $options = [])
|
||||||
|
{
|
||||||
|
foreach (static::getFiles($file) as $file) {
|
||||||
|
$options['file'] = $file;
|
||||||
|
static::fromStringMultiple(static::readFile($file), $translations, $options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a T_CONSTANT_ENCAPSED_STRING string.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function convertString($value)
|
||||||
|
{
|
||||||
|
if (strpos($value, '\\') === false) {
|
||||||
|
return substr($value, 1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value[0] === "'") {
|
||||||
|
return strtr(substr($value, 1, -1), ['\\\\' => '\\', '\\\'' => '\'']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = substr($value, 1, -1);
|
||||||
|
|
||||||
|
return preg_replace_callback(
|
||||||
|
'/\\\(n|r|t|v|e|f|\$|"|\\\|x[0-9A-Fa-f]{1,2}|u{[0-9a-f]{1,6}}|[0-7]{1,3})/',
|
||||||
|
function ($match) {
|
||||||
|
switch ($match[1][0]) {
|
||||||
|
case 'n':
|
||||||
|
return "\n";
|
||||||
|
case 'r':
|
||||||
|
return "\r";
|
||||||
|
case 't':
|
||||||
|
return "\t";
|
||||||
|
case 'v':
|
||||||
|
return "\v";
|
||||||
|
case 'e':
|
||||||
|
return "\e";
|
||||||
|
case 'f':
|
||||||
|
return "\f";
|
||||||
|
case '$':
|
||||||
|
return '$';
|
||||||
|
case '"':
|
||||||
|
return '"';
|
||||||
|
case '\\':
|
||||||
|
return '\\';
|
||||||
|
case 'x':
|
||||||
|
return chr(hexdec(substr($match[1], 1)));
|
||||||
|
case 'u':
|
||||||
|
return static::unicodeChar(hexdec(substr($match[1], 1)));
|
||||||
|
default:
|
||||||
|
return chr(octdec($match[1]));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
$value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $dec
|
||||||
|
* @return string|null
|
||||||
|
* @see http://php.net/manual/en/function.chr.php#118804
|
||||||
|
*/
|
||||||
|
protected static function unicodeChar($dec)
|
||||||
|
{
|
||||||
|
if ($dec < 0x80) {
|
||||||
|
return chr($dec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($dec < 0x0800) {
|
||||||
|
return chr(0xC0 + ($dec >> 6))
|
||||||
|
. chr(0x80 + ($dec & 0x3f));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($dec < 0x010000) {
|
||||||
|
return chr(0xE0 + ($dec >> 12))
|
||||||
|
. chr(0x80 + (($dec >> 6) & 0x3f))
|
||||||
|
. chr(0x80 + ($dec & 0x3f));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($dec < 0x200000) {
|
||||||
|
return chr(0xF0 + ($dec >> 18))
|
||||||
|
. chr(0x80 + (($dec >> 12) & 0x3f))
|
||||||
|
. chr(0x80 + (($dec >> 6) & 0x3f))
|
||||||
|
. chr(0x80 + ($dec & 0x3f));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
+211
@@ -0,0 +1,211 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Translation;
|
||||||
|
use Gettext\Utils\HeadersExtractorTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from php files returning arrays.
|
||||||
|
*/
|
||||||
|
class Po extends Extractor implements ExtractorInterface
|
||||||
|
{
|
||||||
|
use HeadersExtractorTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a .po file and append the translations found in the Translations instance.
|
||||||
|
*
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$lines = explode("\n", $string);
|
||||||
|
$i = 0;
|
||||||
|
|
||||||
|
$translation = $translations->createNewTranslation('', '');
|
||||||
|
|
||||||
|
for ($n = count($lines); $i < $n; ++$i) {
|
||||||
|
$line = trim($lines[$i]);
|
||||||
|
$line = static::fixMultiLines($line, $lines, $i);
|
||||||
|
|
||||||
|
if ($line === '') {
|
||||||
|
if ($translation->is('', '')) {
|
||||||
|
static::extractHeaders($translation->getTranslation(), $translations);
|
||||||
|
} elseif ($translation->hasOriginal()) {
|
||||||
|
$translations[] = $translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
$translation = $translations->createNewTranslation('', '');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$splitLine = preg_split('/\s+/', $line, 2);
|
||||||
|
$key = $splitLine[0];
|
||||||
|
$data = isset($splitLine[1]) ? $splitLine[1] : '';
|
||||||
|
|
||||||
|
if ($key === '#~') {
|
||||||
|
$translation->setDisabled(true);
|
||||||
|
|
||||||
|
$splitLine = preg_split('/\s+/', $data, 2);
|
||||||
|
$key = $splitLine[0];
|
||||||
|
$data = isset($splitLine[1]) ? $splitLine[1] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($key) {
|
||||||
|
case '#':
|
||||||
|
$translation->addComment($data);
|
||||||
|
$append = null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '#.':
|
||||||
|
$translation->addExtractedComment($data);
|
||||||
|
$append = null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '#,':
|
||||||
|
foreach (array_map('trim', explode(',', trim($data))) as $value) {
|
||||||
|
$translation->addFlag($value);
|
||||||
|
}
|
||||||
|
$append = null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '#:':
|
||||||
|
foreach (preg_split('/\s+/', trim($data)) as $value) {
|
||||||
|
if (preg_match('/^(.+)(:(\d*))?$/U', $value, $matches)) {
|
||||||
|
$translation->addReference($matches[1], isset($matches[3]) ? $matches[3] : null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$append = null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'msgctxt':
|
||||||
|
$translation = $translation->getClone(static::convertString($data));
|
||||||
|
$append = 'Context';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'msgid':
|
||||||
|
$translation = $translation->getClone(null, static::convertString($data));
|
||||||
|
$append = 'Original';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'msgid_plural':
|
||||||
|
$translation->setPlural(static::convertString($data));
|
||||||
|
$append = 'Plural';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'msgstr':
|
||||||
|
case 'msgstr[0]':
|
||||||
|
$translation->setTranslation(static::convertString($data));
|
||||||
|
$append = 'Translation';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'msgstr[1]':
|
||||||
|
$translation->setPluralTranslations([static::convertString($data)]);
|
||||||
|
$append = 'PluralTranslation';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (strpos($key, 'msgstr[') === 0) {
|
||||||
|
$p = $translation->getPluralTranslations();
|
||||||
|
$p[] = static::convertString($data);
|
||||||
|
|
||||||
|
$translation->setPluralTranslations($p);
|
||||||
|
$append = 'PluralTranslation';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($append)) {
|
||||||
|
if ($append === 'Context') {
|
||||||
|
$translation = $translation->getClone($translation->getContext()
|
||||||
|
."\n"
|
||||||
|
.static::convertString($data));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($append === 'Original') {
|
||||||
|
$translation = $translation->getClone(null, $translation->getOriginal()
|
||||||
|
."\n"
|
||||||
|
.static::convertString($data));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($append === 'PluralTranslation') {
|
||||||
|
$p = $translation->getPluralTranslations();
|
||||||
|
$p[] = array_pop($p)."\n".static::convertString($data);
|
||||||
|
$translation->setPluralTranslations($p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$getMethod = 'get'.$append;
|
||||||
|
$setMethod = 'set'.$append;
|
||||||
|
$translation->$setMethod($translation->$getMethod()."\n".static::convertString($data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($translation->hasOriginal() && !in_array($translation, iterator_to_array($translations))) {
|
||||||
|
$translations[] = $translation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets one string from multiline strings.
|
||||||
|
*
|
||||||
|
* @param string $line
|
||||||
|
* @param array $lines
|
||||||
|
* @param int &$i
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected static function fixMultiLines($line, array $lines, &$i)
|
||||||
|
{
|
||||||
|
for ($j = $i, $t = count($lines); $j < $t; ++$j) {
|
||||||
|
if (substr($line, -1, 1) == '"'
|
||||||
|
&& isset($lines[$j + 1])
|
||||||
|
&& substr(trim($lines[$j + 1]), 0, 1) == '"'
|
||||||
|
) {
|
||||||
|
$line = substr($line, 0, -1).substr(trim($lines[$j + 1]), 1);
|
||||||
|
} else {
|
||||||
|
$i = $j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a string from its PO representation.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function convertString($value)
|
||||||
|
{
|
||||||
|
if (!$value) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value[0] === '"') {
|
||||||
|
$value = substr($value, 1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return strtr(
|
||||||
|
$value,
|
||||||
|
[
|
||||||
|
'\\\\' => '\\',
|
||||||
|
'\\a' => "\x07",
|
||||||
|
'\\b' => "\x08",
|
||||||
|
'\\t' => "\t",
|
||||||
|
'\\n' => "\n",
|
||||||
|
'\\v' => "\x0b",
|
||||||
|
'\\f' => "\x0c",
|
||||||
|
'\\r' => "\r",
|
||||||
|
'\\"' => '"',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Twig_Loader_Array;
|
||||||
|
use Twig_Environment;
|
||||||
|
use Twig_Source;
|
||||||
|
use Twig_Extensions_Extension_I18n;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from twig files returning arrays.
|
||||||
|
*/
|
||||||
|
class Twig extends Extractor implements ExtractorInterface
|
||||||
|
{
|
||||||
|
public static $options = [
|
||||||
|
'extractComments' => 'notes:',
|
||||||
|
'twig' => null,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$options += static::$options;
|
||||||
|
|
||||||
|
$twig = $options['twig'] ?: static::createTwig();
|
||||||
|
|
||||||
|
PhpCode::fromString($twig->compileSource(new Twig_Source($string, '')), $translations, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Twig instance.
|
||||||
|
*
|
||||||
|
* @return Twig_Environment
|
||||||
|
*/
|
||||||
|
protected static function createTwig()
|
||||||
|
{
|
||||||
|
$twig = new Twig_Environment(new Twig_Loader_Array(['' => '']));
|
||||||
|
$twig->addExtension(new Twig_Extensions_Extension_I18n());
|
||||||
|
|
||||||
|
return static::$options['twig'] = $twig;
|
||||||
|
}
|
||||||
|
}
|
||||||
+423
@@ -0,0 +1,423 @@
|
|||||||
|
<?php
|
||||||
|
/** @noinspection PhpComposerExtensionStubsInspection */
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use DOMAttr;
|
||||||
|
use DOMDocument;
|
||||||
|
use DOMElement;
|
||||||
|
use DOMNode;
|
||||||
|
use Exception;
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\FunctionsScanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from VueJS template files.
|
||||||
|
*/
|
||||||
|
class VueJs extends Extractor implements ExtractorInterface, ExtractorMultiInterface
|
||||||
|
{
|
||||||
|
public static $options = [
|
||||||
|
'constants' => [],
|
||||||
|
|
||||||
|
'functions' => [
|
||||||
|
'gettext' => 'gettext',
|
||||||
|
'__' => 'gettext',
|
||||||
|
'ngettext' => 'ngettext',
|
||||||
|
'n__' => 'ngettext',
|
||||||
|
'pgettext' => 'pgettext',
|
||||||
|
'p__' => 'pgettext',
|
||||||
|
'dgettext' => 'dgettext',
|
||||||
|
'd__' => 'dgettext',
|
||||||
|
'dngettext' => 'dngettext',
|
||||||
|
'dn__' => 'dngettext',
|
||||||
|
'dpgettext' => 'dpgettext',
|
||||||
|
'dp__' => 'dpgettext',
|
||||||
|
'npgettext' => 'npgettext',
|
||||||
|
'np__' => 'npgettext',
|
||||||
|
'dnpgettext' => 'dnpgettext',
|
||||||
|
'dnp__' => 'dnpgettext',
|
||||||
|
'noop' => 'noop',
|
||||||
|
'noop__' => 'noop',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
protected static $functionsScannerClass = 'Gettext\Utils\JsFunctionsScanner';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function fromFileMultiple($file, array $translations, array $options = [])
|
||||||
|
{
|
||||||
|
foreach (static::getFiles($file) as $file) {
|
||||||
|
$options['file'] = $file;
|
||||||
|
static::fromStringMultiple(static::readFile($file), $translations, $options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
static::fromStringMultiple($string, [$translations], $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function fromStringMultiple($string, array $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$options += static::$options;
|
||||||
|
$options += [
|
||||||
|
// HTML attribute prefixes we parse as JS which could contain translations (are JS expressions)
|
||||||
|
'attributePrefixes' => [
|
||||||
|
':',
|
||||||
|
'v-bind:',
|
||||||
|
'v-on:',
|
||||||
|
'v-text',
|
||||||
|
],
|
||||||
|
// HTML Tags to parse
|
||||||
|
'tagNames' => [
|
||||||
|
'translate',
|
||||||
|
],
|
||||||
|
// HTML tags to parse when attribute exists
|
||||||
|
'tagAttributes' => [
|
||||||
|
'v-translate',
|
||||||
|
],
|
||||||
|
// Comments
|
||||||
|
'commentAttributes' => [
|
||||||
|
'translate-comment',
|
||||||
|
],
|
||||||
|
'contextAttributes' => [
|
||||||
|
'translate-context',
|
||||||
|
],
|
||||||
|
// Attribute with plural content
|
||||||
|
'pluralAttributes' => [
|
||||||
|
'translate-plural',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Ok, this is the weirdest hack, but let me explain:
|
||||||
|
// On Linux (Mac is fine), when converting HTML to DOM, new lines get trimmed after the first tag.
|
||||||
|
// So if there are new lines between <template> and next element, they are lost
|
||||||
|
// So we insert a "." which is a text node, and it will prevent that newlines are stripped between elements.
|
||||||
|
// Same thing happens between template and script tag.
|
||||||
|
$string = str_replace('<template>', '<template>.', $string);
|
||||||
|
$string = str_replace('</template>', '</template>.', $string);
|
||||||
|
|
||||||
|
// Normalize newlines
|
||||||
|
$string = str_replace(["\r\n", "\n\r", "\r"], "\n", $string);
|
||||||
|
|
||||||
|
// VueJS files are valid HTML files, we will operate with the DOM here
|
||||||
|
$dom = static::convertHtmlToDom($string);
|
||||||
|
|
||||||
|
$script = static::extractScriptTag($string);
|
||||||
|
|
||||||
|
// Parse the script part as a regular JS code
|
||||||
|
if ($script) {
|
||||||
|
$scriptLineNumber = $dom->getElementsByTagName('script')->item(0)->getLineNo();
|
||||||
|
static::getScriptTranslationsFromString(
|
||||||
|
$script,
|
||||||
|
$translations,
|
||||||
|
$options,
|
||||||
|
$scriptLineNumber - 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Template part is parsed separately, all variables will be extracted
|
||||||
|
// and handled as a regular JS code
|
||||||
|
$template = $dom->getElementsByTagName('template')->item(0);
|
||||||
|
if ($template) {
|
||||||
|
static::getTemplateTranslations(
|
||||||
|
$template,
|
||||||
|
$translations,
|
||||||
|
$options,
|
||||||
|
$template->getLineNo() - 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts script tag contents using regex instead of DOM operations.
|
||||||
|
* If we parse using DOM, some contents may change, for example, tags within strings will be stripped
|
||||||
|
*
|
||||||
|
* @param $string
|
||||||
|
* @return bool|string
|
||||||
|
*/
|
||||||
|
protected static function extractScriptTag($string)
|
||||||
|
{
|
||||||
|
if (preg_match('#<\s*?script\b[^>]*>(.*?)</script\b[^>]*>#s', $string, $matches)) {
|
||||||
|
return $matches[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $html
|
||||||
|
* @return DOMDocument
|
||||||
|
*/
|
||||||
|
protected static function convertHtmlToDom($html)
|
||||||
|
{
|
||||||
|
$dom = new DOMDocument;
|
||||||
|
|
||||||
|
libxml_use_internal_errors(true);
|
||||||
|
|
||||||
|
// Prepend xml encoding so DOMDocument document handles UTF8 correctly.
|
||||||
|
// Assuming that vue template files will not have any xml encoding tags, because duplicate tags may be ignored.
|
||||||
|
$dom->loadHTML('<?xml encoding="utf-8"?>' . $html);
|
||||||
|
|
||||||
|
libxml_clear_errors();
|
||||||
|
|
||||||
|
return $dom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract translations from script part
|
||||||
|
*
|
||||||
|
* @param string $scriptContents Only script tag contents, not the whole template
|
||||||
|
* @param Translations|Translations[] $translations One or multiple domain Translation objects
|
||||||
|
* @param array $options
|
||||||
|
* @param int $lineOffset Number of lines the script is offset in the vue template file
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected static function getScriptTranslationsFromString(
|
||||||
|
$scriptContents,
|
||||||
|
$translations,
|
||||||
|
array $options = [],
|
||||||
|
$lineOffset = 0
|
||||||
|
) {
|
||||||
|
/** @var FunctionsScanner $functions */
|
||||||
|
$functions = new static::$functionsScannerClass($scriptContents);
|
||||||
|
$options['lineOffset'] = $lineOffset;
|
||||||
|
$functions->saveGettextFunctions($translations, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse template to extract all translations (element content and dynamic element attributes)
|
||||||
|
*
|
||||||
|
* @param DOMNode $dom
|
||||||
|
* @param Translations|Translations[] $translations One or multiple domain Translation objects
|
||||||
|
* @param array $options
|
||||||
|
* @param int $lineOffset Line number where the template part starts in the vue file
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected static function getTemplateTranslations(
|
||||||
|
DOMNode $dom,
|
||||||
|
$translations,
|
||||||
|
array $options,
|
||||||
|
$lineOffset = 0
|
||||||
|
) {
|
||||||
|
// Build a JS string from all template attribute expressions
|
||||||
|
$fakeAttributeJs = static::getTemplateAttributeFakeJs($options, $dom);
|
||||||
|
|
||||||
|
// 1 line offset is necessary because parent template element was ignored when converting to DOM
|
||||||
|
static::getScriptTranslationsFromString($fakeAttributeJs, $translations, $options, $lineOffset);
|
||||||
|
|
||||||
|
// Build a JS string from template element content expressions
|
||||||
|
$fakeTemplateJs = static::getTemplateFakeJs($dom);
|
||||||
|
static::getScriptTranslationsFromString($fakeTemplateJs, $translations, $options, $lineOffset);
|
||||||
|
|
||||||
|
static::getTagTranslations($options, $dom, $translations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $options
|
||||||
|
* @param DOMNode $dom
|
||||||
|
* @param Translations|Translations[] $translations
|
||||||
|
*/
|
||||||
|
protected static function getTagTranslations(array $options, DOMNode $dom, $translations)
|
||||||
|
{
|
||||||
|
// Since tag scanning does not support domains, we always use the first translation given
|
||||||
|
$translations = is_array($translations) ? reset($translations) : $translations;
|
||||||
|
|
||||||
|
$children = $dom->childNodes;
|
||||||
|
for ($i = 0; $i < $children->length; $i++) {
|
||||||
|
$node = $children->item($i);
|
||||||
|
|
||||||
|
if (!($node instanceof DOMElement)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$translatable = false;
|
||||||
|
|
||||||
|
if (in_array($node->tagName, $options['tagNames'], true)) {
|
||||||
|
$translatable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$attrList = $node->attributes;
|
||||||
|
$context = null;
|
||||||
|
$plural = "";
|
||||||
|
$comment = null;
|
||||||
|
|
||||||
|
for ($j = 0; $j < $attrList->length; $j++) {
|
||||||
|
/** @var DOMAttr $domAttr */
|
||||||
|
$domAttr = $attrList->item($j);
|
||||||
|
// Check if this is a dynamic vue attribute
|
||||||
|
if (in_array($domAttr->name, $options['tagAttributes'])) {
|
||||||
|
$translatable = true;
|
||||||
|
}
|
||||||
|
if (in_array($domAttr->name, $options['contextAttributes'])) {
|
||||||
|
$context = $domAttr->value;
|
||||||
|
}
|
||||||
|
if (in_array($domAttr->name, $options['pluralAttributes'])) {
|
||||||
|
$plural = $domAttr->value;
|
||||||
|
}
|
||||||
|
if (in_array($domAttr->name, $options['commentAttributes'])) {
|
||||||
|
$comment = $domAttr->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($translatable) {
|
||||||
|
$translation = $translations->insert($context, trim($node->textContent), $plural);
|
||||||
|
$translation->addReference($options['file'], $node->getLineNo());
|
||||||
|
if ($comment) {
|
||||||
|
$translation->addExtractedComment($comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($node->hasChildNodes()) {
|
||||||
|
static::getTagTranslations($options, $node, $translations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract JS expressions from element attribute bindings (excluding text within elements)
|
||||||
|
* For example: <span :title="__('extract this')"> skip element content </span>
|
||||||
|
*
|
||||||
|
* @param array $options
|
||||||
|
* @param DOMNode $dom
|
||||||
|
* @return string JS code
|
||||||
|
*/
|
||||||
|
protected static function getTemplateAttributeFakeJs(array $options, DOMNode $dom)
|
||||||
|
{
|
||||||
|
$expressionsByLine = static::getVueAttributeExpressions($options['attributePrefixes'], $dom);
|
||||||
|
|
||||||
|
if (empty($expressionsByLine)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$maxLines = max(array_keys($expressionsByLine));
|
||||||
|
$fakeJs = '';
|
||||||
|
|
||||||
|
for ($line = 1; $line <= $maxLines; $line++) {
|
||||||
|
if (isset($expressionsByLine[$line])) {
|
||||||
|
$fakeJs .= implode("; ", $expressionsByLine[$line]);
|
||||||
|
}
|
||||||
|
$fakeJs .= "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fakeJs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop DOM element recursively and parse out all dynamic vue attributes which are basically JS expressions
|
||||||
|
*
|
||||||
|
* @param array $attributePrefixes List of attribute prefixes we parse as JS (may contain translations)
|
||||||
|
* @param DOMNode $dom
|
||||||
|
* @param array $expressionByLine [lineNumber => [jsExpression, ..], ..]
|
||||||
|
* @return array [lineNumber => [jsExpression, ..], ..]
|
||||||
|
*/
|
||||||
|
protected static function getVueAttributeExpressions(
|
||||||
|
array $attributePrefixes,
|
||||||
|
DOMNode $dom,
|
||||||
|
array &$expressionByLine = []
|
||||||
|
) {
|
||||||
|
$children = $dom->childNodes;
|
||||||
|
|
||||||
|
for ($i = 0; $i < $children->length; $i++) {
|
||||||
|
$node = $children->item($i);
|
||||||
|
|
||||||
|
if (!($node instanceof DOMElement)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$attrList = $node->attributes;
|
||||||
|
|
||||||
|
for ($j = 0; $j < $attrList->length; $j++) {
|
||||||
|
/** @var DOMAttr $domAttr */
|
||||||
|
$domAttr = $attrList->item($j);
|
||||||
|
|
||||||
|
// Check if this is a dynamic vue attribute
|
||||||
|
if (static::isAttributeMatching($domAttr->name, $attributePrefixes)) {
|
||||||
|
$line = $domAttr->getLineNo();
|
||||||
|
$expressionByLine += [$line => []];
|
||||||
|
$expressionByLine[$line][] = $domAttr->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($node->hasChildNodes()) {
|
||||||
|
$expressionByLine = static::getVueAttributeExpressions($attributePrefixes, $node, $expressionByLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $expressionByLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this attribute name should be parsed for translations
|
||||||
|
*
|
||||||
|
* @param string $attributeName
|
||||||
|
* @param string[] $attributePrefixes
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected static function isAttributeMatching($attributeName, $attributePrefixes)
|
||||||
|
{
|
||||||
|
foreach ($attributePrefixes as $prefix) {
|
||||||
|
if (strpos($attributeName, $prefix) === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract JS expressions from within template elements (excluding attributes)
|
||||||
|
* For example: <span :title="skip attributes"> {{__("extract element content")}} </span>
|
||||||
|
*
|
||||||
|
* @param DOMNode $dom
|
||||||
|
* @return string JS code
|
||||||
|
*/
|
||||||
|
protected static function getTemplateFakeJs(DOMNode $dom)
|
||||||
|
{
|
||||||
|
$fakeJs = '';
|
||||||
|
$lines = explode("\n", $dom->textContent);
|
||||||
|
|
||||||
|
// Build a fake JS file from template by extracting JS expressions within each template line
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
$expressionMatched = static::parseOneTemplateLine($line);
|
||||||
|
|
||||||
|
$fakeJs .= implode("; ", $expressionMatched) . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fakeJs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match JS expressions in a template line
|
||||||
|
*
|
||||||
|
* @param string $line
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
protected static function parseOneTemplateLine($line)
|
||||||
|
{
|
||||||
|
$line = trim($line);
|
||||||
|
|
||||||
|
if (!$line) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$regex = '#\{\{(.*?)\}\}#';
|
||||||
|
|
||||||
|
preg_match_all($regex, $line, $matches);
|
||||||
|
|
||||||
|
$matched = array_map(function ($v) {
|
||||||
|
return trim($v, '\'"{}');
|
||||||
|
}, $matches[1]);
|
||||||
|
|
||||||
|
return $matched;
|
||||||
|
}
|
||||||
|
}
|
||||||
+86
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Translation;
|
||||||
|
use SimpleXMLElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from xliff format.
|
||||||
|
*/
|
||||||
|
class Xliff extends Extractor implements ExtractorInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public static $options = [
|
||||||
|
'unitid_as_id' => false
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$options += static::$options;
|
||||||
|
|
||||||
|
$xml = new SimpleXMLElement($string, null, false);
|
||||||
|
|
||||||
|
foreach ($xml->file as $file) {
|
||||||
|
if (isset($file->notes)) {
|
||||||
|
foreach ($file->notes->note as $note) {
|
||||||
|
$translations->setHeader($note['id'], (string) $note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($file->unit as $unit) {
|
||||||
|
foreach ($unit->segment as $segment) {
|
||||||
|
$targets = [];
|
||||||
|
|
||||||
|
foreach ($segment->target as $target) {
|
||||||
|
$targets[] = (string) $target;
|
||||||
|
}
|
||||||
|
|
||||||
|
$translation = $translations->createNewTranslation(null, (string) $segment->source);
|
||||||
|
if (isset($unit['id'])) {
|
||||||
|
$unitId = (string) $unit['id'];
|
||||||
|
$translation->addComment("XLIFF_UNIT_ID: $unitId");
|
||||||
|
if ($options['unitid_as_id']) {
|
||||||
|
$translation->setId($unitId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$translation->setTranslation(array_shift($targets));
|
||||||
|
$translation->setPluralTranslations($targets);
|
||||||
|
|
||||||
|
if (isset($unit->notes)) {
|
||||||
|
foreach ($unit->notes->note as $note) {
|
||||||
|
switch ($note['category']) {
|
||||||
|
case 'context':
|
||||||
|
$translation = $translation->getClone((string) $note);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'extracted-comment':
|
||||||
|
$translation->addExtractedComment((string) $note);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'flag':
|
||||||
|
$translation->addFlag((string) $note);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'reference':
|
||||||
|
$ref = explode(':', (string) $note, 2);
|
||||||
|
$translation->addReference($ref[0], isset($ref[1]) ? $ref[1] : null);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$translation->addComment((string) $note);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$translations[] = $translation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\MultidimensionalArrayTrait;
|
||||||
|
use Symfony\Component\Yaml\Yaml as YamlParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from yaml.
|
||||||
|
*/
|
||||||
|
class Yaml extends Extractor implements ExtractorInterface
|
||||||
|
{
|
||||||
|
use MultidimensionalArrayTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$messages = YamlParser::parse($string);
|
||||||
|
|
||||||
|
if (is_array($messages)) {
|
||||||
|
static::fromArray($messages, $translations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Extractors;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\DictionaryTrait;
|
||||||
|
use Symfony\Component\Yaml\Yaml as YamlParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get gettext strings from yaml.
|
||||||
|
*/
|
||||||
|
class YamlDictionary extends Extractor implements ExtractorInterface
|
||||||
|
{
|
||||||
|
use DictionaryTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function fromString($string, Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$messages = YamlParser::parse($string);
|
||||||
|
|
||||||
|
if (is_array($messages)) {
|
||||||
|
static::fromArray($messages, $translations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Generators;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\HeadersGeneratorTrait;
|
||||||
|
use Gettext\Utils\CsvTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to export translations to csv.
|
||||||
|
*/
|
||||||
|
class Csv extends Generator implements GeneratorInterface
|
||||||
|
{
|
||||||
|
use HeadersGeneratorTrait;
|
||||||
|
use CsvTrait;
|
||||||
|
|
||||||
|
public static $options = [
|
||||||
|
'includeHeaders' => false,
|
||||||
|
'delimiter' => ",",
|
||||||
|
'enclosure' => '"',
|
||||||
|
'escape_char' => "\\"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@parentDoc}.
|
||||||
|
*/
|
||||||
|
public static function toString(Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$options += static::$options;
|
||||||
|
$handle = fopen('php://memory', 'w');
|
||||||
|
|
||||||
|
if ($options['includeHeaders']) {
|
||||||
|
static::fputcsv($handle, ['', '', static::generateHeaders($translations)], $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($translations as $translation) {
|
||||||
|
if ($translation->isDisabled()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$line = [$translation->getContext(), $translation->getOriginal(), $translation->getTranslation()];
|
||||||
|
|
||||||
|
if ($translation->hasPluralTranslations(true)) {
|
||||||
|
$line = array_merge($line, $translation->getPluralTranslations());
|
||||||
|
}
|
||||||
|
|
||||||
|
static::fputcsv($handle, $line, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
rewind($handle);
|
||||||
|
$csv = stream_get_contents($handle);
|
||||||
|
fclose($handle);
|
||||||
|
|
||||||
|
return $csv;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Generators;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\DictionaryTrait;
|
||||||
|
use Gettext\Utils\CsvTrait;
|
||||||
|
|
||||||
|
class CsvDictionary extends Generator implements GeneratorInterface
|
||||||
|
{
|
||||||
|
use DictionaryTrait;
|
||||||
|
use CsvTrait;
|
||||||
|
|
||||||
|
public static $options = [
|
||||||
|
'includeHeaders' => false,
|
||||||
|
'delimiter' => ",",
|
||||||
|
'enclosure' => '"',
|
||||||
|
'escape_char' => "\\"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@parentDoc}.
|
||||||
|
*/
|
||||||
|
public static function toString(Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$options += static::$options;
|
||||||
|
$handle = fopen('php://memory', 'w');
|
||||||
|
|
||||||
|
foreach (static::toArray($translations, $options['includeHeaders']) as $original => $translation) {
|
||||||
|
static::fputcsv($handle, [$original, $translation], $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
rewind($handle);
|
||||||
|
$csv = stream_get_contents($handle);
|
||||||
|
fclose($handle);
|
||||||
|
|
||||||
|
return $csv;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Generators;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
|
||||||
|
abstract class Generator implements GeneratorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function toFile(Translations $translations, $file, array $options = [])
|
||||||
|
{
|
||||||
|
$content = static::toString($translations, $options);
|
||||||
|
|
||||||
|
if (file_put_contents($file, $content) === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Generators;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
|
||||||
|
interface GeneratorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Saves the translations in a file.
|
||||||
|
*
|
||||||
|
* @param Translations $translations
|
||||||
|
* @param string $file
|
||||||
|
* @param array $options
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function toFile(Translations $translations, $file, array $options = []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a string with the translations ready to save in a file.
|
||||||
|
*
|
||||||
|
* @param Translations $translations
|
||||||
|
* @param array $options
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function toString(Translations $translations, array $options = []);
|
||||||
|
}
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Generators;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
|
||||||
|
class Jed extends Generator implements GeneratorInterface
|
||||||
|
{
|
||||||
|
public static $options = [
|
||||||
|
'json' => 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@parentDoc}.
|
||||||
|
*/
|
||||||
|
public static function toString(Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$domain = $translations->getDomain() ?: 'messages';
|
||||||
|
$options += static::$options;
|
||||||
|
|
||||||
|
return json_encode([
|
||||||
|
$domain => [
|
||||||
|
'' => [
|
||||||
|
'domain' => $domain,
|
||||||
|
'lang' => $translations->getLanguage() ?: 'en',
|
||||||
|
'plural-forms' => $translations->getHeader('Plural-Forms') ?: 'nplurals=2; plural=(n != 1);',
|
||||||
|
],
|
||||||
|
] + static::buildMessages($translations),
|
||||||
|
], $options['json']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an array with all translations.
|
||||||
|
*
|
||||||
|
* @param Translations $translations
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected static function buildMessages(Translations $translations)
|
||||||
|
{
|
||||||
|
$pluralForm = $translations->getPluralForms();
|
||||||
|
$pluralSize = is_array($pluralForm) ? ($pluralForm[0] - 1) : null;
|
||||||
|
$messages = [];
|
||||||
|
$context_glue = '\u0004';
|
||||||
|
|
||||||
|
foreach ($translations as $translation) {
|
||||||
|
if ($translation->isDisabled()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = ($translation->hasContext() ? $translation->getContext().$context_glue : '')
|
||||||
|
.$translation->getOriginal();
|
||||||
|
|
||||||
|
if ($translation->hasPluralTranslations(true)) {
|
||||||
|
$message = $translation->getPluralTranslations($pluralSize);
|
||||||
|
array_unshift($message, $translation->getTranslation());
|
||||||
|
} else {
|
||||||
|
$message = [$translation->getTranslation()];
|
||||||
|
}
|
||||||
|
|
||||||
|
$messages[$key] = $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $messages;
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Generators;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\MultidimensionalArrayTrait;
|
||||||
|
|
||||||
|
class Json extends Generator implements GeneratorInterface
|
||||||
|
{
|
||||||
|
use MultidimensionalArrayTrait;
|
||||||
|
|
||||||
|
public static $options = [
|
||||||
|
'json' => 0,
|
||||||
|
'includeHeaders' => false,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function toString(Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$options += static::$options;
|
||||||
|
|
||||||
|
return json_encode(static::toArray($translations, $options['includeHeaders'], true), $options['json']);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Generators;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\DictionaryTrait;
|
||||||
|
|
||||||
|
class JsonDictionary extends Generator implements GeneratorInterface
|
||||||
|
{
|
||||||
|
use DictionaryTrait;
|
||||||
|
|
||||||
|
public static $options = [
|
||||||
|
'json' => 0,
|
||||||
|
'includeHeaders' => false,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@parentDoc}.
|
||||||
|
*/
|
||||||
|
public static function toString(Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$options += static::$options;
|
||||||
|
|
||||||
|
return json_encode(static::toArray($translations, $options['includeHeaders']), $options['json']);
|
||||||
|
}
|
||||||
|
}
|
||||||
+140
@@ -0,0 +1,140 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Generators;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\HeadersGeneratorTrait;
|
||||||
|
|
||||||
|
class Mo extends Generator implements GeneratorInterface
|
||||||
|
{
|
||||||
|
use HeadersGeneratorTrait;
|
||||||
|
|
||||||
|
public static $options = [
|
||||||
|
'includeHeaders' => true,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@parentDoc}.
|
||||||
|
*/
|
||||||
|
public static function toString(Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$options += static::$options;
|
||||||
|
$messages = [];
|
||||||
|
|
||||||
|
if ($options['includeHeaders']) {
|
||||||
|
$messages[''] = static::generateHeaders($translations);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($translations as $translation) {
|
||||||
|
if (!$translation->hasTranslation() || $translation->isDisabled()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($translation->hasContext()) {
|
||||||
|
$originalString = $translation->getContext()."\x04".$translation->getOriginal();
|
||||||
|
} else {
|
||||||
|
$originalString = $translation->getOriginal();
|
||||||
|
}
|
||||||
|
|
||||||
|
$messages[$originalString] = $translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($messages);
|
||||||
|
$numEntries = count($messages);
|
||||||
|
$originalsTable = '';
|
||||||
|
$translationsTable = '';
|
||||||
|
$originalsIndex = [];
|
||||||
|
$translationsIndex = [];
|
||||||
|
$pluralForm = $translations->getPluralForms();
|
||||||
|
$pluralSize = is_array($pluralForm) ? ($pluralForm[0] - 1) : null;
|
||||||
|
|
||||||
|
foreach ($messages as $originalString => $translation) {
|
||||||
|
if (is_string($translation)) {
|
||||||
|
// Headers
|
||||||
|
$translationString = $translation;
|
||||||
|
} else {
|
||||||
|
/* @var $translation \Gettext\Translation */
|
||||||
|
if ($translation->hasPlural() && $translation->hasPluralTranslations(true)) {
|
||||||
|
$originalString .= "\x00".$translation->getPlural();
|
||||||
|
$translationString = $translation->getTranslation();
|
||||||
|
$translationString .= "\x00".implode("\x00", $translation->getPluralTranslations($pluralSize));
|
||||||
|
} else {
|
||||||
|
$translationString = $translation->getTranslation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$originalsIndex[] = [
|
||||||
|
'relativeOffset' => strlen($originalsTable),
|
||||||
|
'length' => strlen($originalString)
|
||||||
|
];
|
||||||
|
$originalsTable .= $originalString."\x00";
|
||||||
|
$translationsIndex[] = [
|
||||||
|
'relativeOffset' => strlen($translationsTable),
|
||||||
|
'length' => strlen($translationString)
|
||||||
|
];
|
||||||
|
$translationsTable .= $translationString."\x00";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offset of table with the original strings index: right after the header (which is 7 words)
|
||||||
|
$originalsIndexOffset = 7 * 4;
|
||||||
|
|
||||||
|
// Size of table with the original strings index
|
||||||
|
$originalsIndexSize = $numEntries * (4 + 4);
|
||||||
|
|
||||||
|
// Offset of table with the translation strings index: right after the original strings index table
|
||||||
|
$translationsIndexOffset = $originalsIndexOffset + $originalsIndexSize;
|
||||||
|
|
||||||
|
// Size of table with the translation strings index
|
||||||
|
$translationsIndexSize = $numEntries * (4 + 4);
|
||||||
|
|
||||||
|
// Hashing table starts after the header and after the index table
|
||||||
|
$originalsStringsOffset = $translationsIndexOffset + $translationsIndexSize;
|
||||||
|
|
||||||
|
// Translations start after the keys
|
||||||
|
$translationsStringsOffset = $originalsStringsOffset + strlen($originalsTable);
|
||||||
|
|
||||||
|
// Let's generate the .mo file binary data
|
||||||
|
$mo = '';
|
||||||
|
|
||||||
|
// Magic number
|
||||||
|
$mo .= pack('L', 0x950412de);
|
||||||
|
|
||||||
|
// File format revision
|
||||||
|
$mo .= pack('L', 0);
|
||||||
|
|
||||||
|
// Number of strings
|
||||||
|
$mo .= pack('L', $numEntries);
|
||||||
|
|
||||||
|
// Offset of table with original strings
|
||||||
|
$mo .= pack('L', $originalsIndexOffset);
|
||||||
|
|
||||||
|
// Offset of table with translation strings
|
||||||
|
$mo .= pack('L', $translationsIndexOffset);
|
||||||
|
|
||||||
|
// Size of hashing table: we don't use it.
|
||||||
|
$mo .= pack('L', 0);
|
||||||
|
|
||||||
|
// Offset of hashing table: it would start right after the translations index table
|
||||||
|
$mo .= pack('L', $translationsIndexOffset + $translationsIndexSize);
|
||||||
|
|
||||||
|
// Write the lengths & offsets of the original strings
|
||||||
|
foreach ($originalsIndex as $info) {
|
||||||
|
$mo .= pack('L', $info['length']);
|
||||||
|
$mo .= pack('L', $originalsStringsOffset + $info['relativeOffset']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the lengths & offsets of the translated strings
|
||||||
|
foreach ($translationsIndex as $info) {
|
||||||
|
$mo .= pack('L', $info['length']);
|
||||||
|
$mo .= pack('L', $translationsStringsOffset + $info['relativeOffset']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write original strings
|
||||||
|
$mo .= $originalsTable;
|
||||||
|
|
||||||
|
// Write translation strings
|
||||||
|
$mo .= $translationsTable;
|
||||||
|
|
||||||
|
return $mo;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Generators;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
use Gettext\Utils\MultidimensionalArrayTrait;
|
||||||
|
|
||||||
|
class PhpArray extends Generator implements GeneratorInterface
|
||||||
|
{
|
||||||
|
use MultidimensionalArrayTrait;
|
||||||
|
|
||||||
|
public static $options = [
|
||||||
|
'includeHeaders' => true,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function toString(Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$array = static::generate($translations, $options);
|
||||||
|
|
||||||
|
return '<?php return '.var_export($array, true).';';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an array with the translations.
|
||||||
|
*
|
||||||
|
* @param Translations $translations
|
||||||
|
* @param array $options
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function generate(Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$options += static::$options;
|
||||||
|
|
||||||
|
return static::toArray($translations, $options['includeHeaders'], true);
|
||||||
|
}
|
||||||
|
}
|
||||||
+145
@@ -0,0 +1,145 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Generators;
|
||||||
|
|
||||||
|
use Gettext\Translations;
|
||||||
|
|
||||||
|
class Po extends Generator implements GeneratorInterface
|
||||||
|
{
|
||||||
|
public static $options = [
|
||||||
|
'noLocation' => false,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@parentDoc}.
|
||||||
|
*/
|
||||||
|
public static function toString(Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$options += static::$options;
|
||||||
|
|
||||||
|
$pluralForm = $translations->getPluralForms();
|
||||||
|
$pluralSize = is_array($pluralForm) ? ($pluralForm[0] - 1) : null;
|
||||||
|
$lines = ['msgid ""', 'msgstr ""'];
|
||||||
|
|
||||||
|
foreach ($translations->getHeaders() as $name => $value) {
|
||||||
|
$lines[] = sprintf('"%s: %s\\n"', $name, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$lines[] = '';
|
||||||
|
|
||||||
|
//Translations
|
||||||
|
foreach ($translations as $translation) {
|
||||||
|
if ($translation->hasComments()) {
|
||||||
|
foreach ($translation->getComments() as $comment) {
|
||||||
|
$lines[] = '# '.$comment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($translation->hasExtractedComments()) {
|
||||||
|
foreach ($translation->getExtractedComments() as $comment) {
|
||||||
|
$lines[] = '#. '.$comment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$options['noLocation'] && $translation->hasReferences()) {
|
||||||
|
foreach ($translation->getReferences() as $reference) {
|
||||||
|
$lines[] = '#: '.$reference[0].(!is_null($reference[1]) ? ':'.$reference[1] : null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($translation->hasFlags()) {
|
||||||
|
$lines[] = '#, '.implode(',', $translation->getFlags());
|
||||||
|
}
|
||||||
|
|
||||||
|
$prefix = $translation->isDisabled() ? '#~ ' : '';
|
||||||
|
|
||||||
|
if ($translation->hasContext()) {
|
||||||
|
$lines[] = $prefix.'msgctxt '.static::convertString($translation->getContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
static::addLines($lines, $prefix.'msgid', $translation->getOriginal());
|
||||||
|
|
||||||
|
if ($translation->hasPlural()) {
|
||||||
|
static::addLines($lines, $prefix.'msgid_plural', $translation->getPlural());
|
||||||
|
static::addLines($lines, $prefix.'msgstr[0]', $translation->getTranslation());
|
||||||
|
|
||||||
|
foreach ($translation->getPluralTranslations($pluralSize) as $k => $v) {
|
||||||
|
static::addLines($lines, $prefix.'msgstr['.($k + 1).']', $v);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
static::addLines($lines, $prefix.'msgstr', $translation->getTranslation());
|
||||||
|
}
|
||||||
|
|
||||||
|
$lines[] = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode("\n", $lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escapes and adds double quotes to a string.
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected static function multilineQuote($string)
|
||||||
|
{
|
||||||
|
$lines = explode("\n", $string);
|
||||||
|
$last = count($lines) - 1;
|
||||||
|
|
||||||
|
foreach ($lines as $k => $line) {
|
||||||
|
if ($k === $last) {
|
||||||
|
$lines[$k] = static::convertString($line);
|
||||||
|
} else {
|
||||||
|
$lines[$k] = static::convertString($line."\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add one or more lines depending whether the string is multiline or not.
|
||||||
|
*
|
||||||
|
* @param array &$lines
|
||||||
|
* @param string $name
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
protected static function addLines(array &$lines, $name, $value)
|
||||||
|
{
|
||||||
|
$newLines = static::multilineQuote($value);
|
||||||
|
|
||||||
|
if (count($newLines) === 1) {
|
||||||
|
$lines[] = $name.' '.$newLines[0];
|
||||||
|
} else {
|
||||||
|
$lines[] = $name.' ""';
|
||||||
|
|
||||||
|
foreach ($newLines as $line) {
|
||||||
|
$lines[] = $line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a string to its PO representation.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function convertString($value)
|
||||||
|
{
|
||||||
|
return '"'.strtr(
|
||||||
|
$value,
|
||||||
|
[
|
||||||
|
"\x00" => '',
|
||||||
|
'\\' => '\\\\',
|
||||||
|
"\t" => '\t',
|
||||||
|
"\r" => '\r',
|
||||||
|
"\n" => '\n',
|
||||||
|
'"' => '\\"',
|
||||||
|
]
|
||||||
|
).'"';
|
||||||
|
}
|
||||||
|
}
|
||||||
+122
@@ -0,0 +1,122 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gettext\Generators;
|
||||||
|
|
||||||
|
use Gettext\Translation;
|
||||||
|
use Gettext\Translations;
|
||||||
|
use DOMDocument;
|
||||||
|
|
||||||
|
class Xliff extends Generator implements GeneratorInterface
|
||||||
|
{
|
||||||
|
const UNIT_ID_REGEXP = '/^XLIFF_UNIT_ID: (.*)$/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function toString(Translations $translations, array $options = [])
|
||||||
|
{
|
||||||
|
$dom = new DOMDocument('1.0', 'utf-8');
|
||||||
|
$dom->formatOutput = true;
|
||||||
|
$xliff = $dom->appendChild($dom->createElement('xliff'));
|
||||||
|
$xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:2.0');
|
||||||
|
$xliff->setAttribute('version', '2.0');
|
||||||
|
$xliff->setAttribute('srcLang', $translations->getLanguage());
|
||||||
|
$xliff->setAttribute('trgLang', $translations->getLanguage());
|
||||||
|
$file = $xliff->appendChild($dom->createElement('file'));
|
||||||
|
$file->setAttribute('id', $translations->getDomain().'.'.$translations->getLanguage());
|
||||||
|
|
||||||
|
//Save headers as notes
|
||||||
|
$notes = $dom->createElement('notes');
|
||||||
|
|
||||||
|
foreach ($translations->getHeaders() as $name => $value) {
|
||||||
|
$notes->appendChild(static::createTextNode($dom, 'note', $value))->setAttribute('id', $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($notes->hasChildNodes()) {
|
||||||
|
$file->appendChild($notes);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($translations as $translation) {
|
||||||
|
//Find an XLIFF unit ID, if one is available; otherwise generate
|
||||||
|
$unitId = static::getUnitID($translation)?:md5($translation->getContext().$translation->getOriginal());
|
||||||
|
|
||||||
|
$unit = $dom->createElement('unit');
|
||||||
|
$unit->setAttribute('id', $unitId);
|
||||||
|
|
||||||
|
//Save comments as notes
|
||||||
|
$notes = $dom->createElement('notes');
|
||||||
|
|
||||||
|
$notes->appendChild(static::createTextNode($dom, 'note', $translation->getContext()))
|
||||||
|
->setAttribute('category', 'context');
|
||||||
|
|
||||||
|
foreach ($translation->getComments() as $comment) {
|
||||||
|
//Skip XLIFF unit ID comments.
|
||||||
|
if (preg_match(static::UNIT_ID_REGEXP, $comment)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$notes->appendChild(static::createTextNode($dom, 'note', $comment))
|
||||||
|
->setAttribute('category', 'comment');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($translation->getExtractedComments() as $comment) {
|
||||||
|
$notes->appendChild(static::createTextNode($dom, 'note', $comment))
|
||||||
|
->setAttribute('category', 'extracted-comment');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($translation->getFlags() as $flag) {
|
||||||
|
$notes->appendChild(static::createTextNode($dom, 'note', $flag))
|
||||||
|
->setAttribute('category', 'flag');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($translation->getReferences() as $reference) {
|
||||||
|
$notes->appendChild(static::createTextNode($dom, 'note', $reference[0].':'.$reference[1]))
|
||||||
|
->setAttribute('category', 'reference');
|
||||||
|
}
|
||||||
|
|
||||||
|
$unit->appendChild($notes);
|
||||||
|
|
||||||
|
$segment = $unit->appendChild($dom->createElement('segment'));
|
||||||
|
$segment->appendChild(static::createTextNode($dom, 'source', $translation->getOriginal()));
|
||||||
|
$segment->appendChild(static::createTextNode($dom, 'target', $translation->getTranslation()));
|
||||||
|
|
||||||
|
foreach ($translation->getPluralTranslations() as $plural) {
|
||||||
|
if ($plural !== '') {
|
||||||
|
$segment->appendChild(static::createTextNode($dom, 'target', $plural));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$file->appendChild($unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dom->saveXML();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function createTextNode(DOMDocument $dom, $name, $string)
|
||||||
|
{
|
||||||
|
$node = $dom->createElement($name);
|
||||||
|
$text = (preg_match('/[&<>]/', $string) === 1)
|
||||||
|
? $dom->createCDATASection($string)
|
||||||
|
: $dom->createTextNode($string);
|
||||||
|
$node->appendChild($text);
|
||||||
|
|
||||||
|
return $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the translation's unit ID, if one is available.
|
||||||
|
*
|
||||||
|
* @param Translation $translation
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public static function getUnitID(Translation $translation)
|
||||||
|
{
|
||||||
|
foreach ($translation->getComments() as $comment) {
|
||||||
|
if (preg_match(static::UNIT_ID_REGEXP, $comment, $matches)) {
|
||||||
|
return $matches[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user