wp-cli / wp-cli

⚙️ WP-CLI framework
https://wp-cli.org/
MIT License
4.87k stars 976 forks source link

wp doesn't fully populate $_SERVER array #1734

Closed theMikeD closed 9 years ago

theMikeD commented 9 years ago

UPDATE The actual issue is that $_SERVER is not being fully set up when wp-cli is run. If you put

error_log($_SERVER['SERVER_NAME']);

into wp-config.php and run any wp command, you'll get a blank line. For my setup, this sets WP_CONTENT_URL and WP_CONTENT_DIR to invalid results, and the command fails.

--- original report

According to the docs the taxonomy is supplied as the first option and the term is the second. When I do this using a custom taxonomy, the command fails.

Example: typetax is a properly declared and working custom taxonomy using (the full declaration is omitted for clarity)

register_taxonomy( 'typetax', 'stories', $args );

but when this is run

wp term create typetax 'Banana'

I get an error: Error: Invalid taxonomy

If I run

wp term create post_tag 'Banana'

it works. So the issue seems to be that WP-CLI doesn't understand Custom Taxonomies.

The CT is declared via an mu-plugin FTR.

WileESpaghetti commented 9 years ago

What plugin is creating the CT?

I was able to get register_taxonomy( 'typetax', 'stories', $args ); to work with WP-CLI 0.18.0, WordPress 4.1.1 with default theme (Twenty Fifteen 1.0).

I set up a fresh WordPress install and added the following to the end of the Twenty Fifteen functions.php to create the custom post type and taxonomy.

add_action( 'init', 'create_post_type' );
function create_post_type() {
  register_post_type( 'stories',
    array(
      'labels' => array(
        'name' => __( 'Stories' ),
        'singular_name' => __( 'Story' )
      ),
      'public' => true,
      'has_archive' => true,
    )
  );
}

add_action( 'init', 'create_book_tax' );
function create_book_tax() {
    register_taxonomy(
        'typetax',
        'stories',
        array(
            'label' => __( 'typetax' ),
            'rewrite' => array( 'slug' => 'typetax' ),
            'hierarchical' => false,
        )
    );
}
theMikeD commented 9 years ago
add_action( 'init', 'md_create_type_taxonomy', 0 );
function md_create_type_taxonomy()  {
    $labels = array(
        'name'                       => _x( 'Types', 'Taxonomy General Name', CF_TXT ),
        'singular_name'              => _x( 'Type', 'Taxonomy Singular Name', CF_TXT ),
        'menu_name'                  => __( 'Types', CF_TXT ),
        'all_items'                  => __( 'All Types', CF_TXT ),
        'parent_item'                => __( 'Parent Type', CF_TXT ),
        'parent_item_colon'          => __( 'Parent Type:', CF_TXT ),
        'new_item_name'              => __( 'New Type Name', CF_TXT ),
        'add_new_item'               => __( 'Add New Type', CF_TXT ),
        'edit_item'                  => __( 'Edit Type', CF_TXT ),
        'update_item'                => __( 'Update Type', CF_TXT ),
        'separate_items_with_commas' => __( 'Separate Types with commas', CF_TXT ),
        'search_items'               => __( 'Search Types', CF_TXT ),
        'add_or_remove_items'        => __( 'Add or remove Types', CF_TXT ),
        'choose_from_most_used'      => __( 'Choose from the most used Types', CF_TXT ),
        'popular_items'              => __( 'Popular Types', CF_TXT ),
        'not_found'                  => __( 'No Types found', CF_TXT ),
        'view_item'                  => __( 'View Type', CF_TXT ),
    );
    $rewrite = array(
        'slug'                       => 'story-types',
        'with_front'                 => false,
        'hierarchical'               => true,
    );
    $args = array(
        'labels'                     => $labels,
        'hierarchical'               => true,
        'public'                     => true,
        'show_ui'                    => true,
        'show_admin_column'          => true,
        'show_in_nav_menus'          => true,
        'show_tagcloud'              => false,
        'rewrite'                    => $rewrite,
        'query_var'                  => true,
        'args'                       => array( 'orderby' => 'term_order' ),
    );
    register_taxonomy( 'typetax', 'post', $args );
}

added to functions.php of clean 4.1.1 twentyfifteen with no plugins yields an error. Note that i made one change: that it applied to posts rather than a CPT for simplicity's sake.

theMikeD commented 9 years ago
31-Mar-2015 03:56:46 Europe/Berlin] PHP Notice:  Undefined index: HTTPS in phar:///usr/local/bin/wp/php/wp-cli.php(23) : eval()'d code on line 22
[31-Mar-2015 03:56:46 Europe/Berlin] PHP Notice:  Undefined index: SERVER_NAME in phar:///usr/local/bin/wp/php/wp-cli.php(23) : eval()'d code on line 23

From my console. Note that these lines also appear when a successful insertion is done using post_tag

theMikeD commented 9 years ago

wp-config.php in case it's relevant


// Note that $_SERVER['DOCUMENT_ROOT'] will return a string with a trailing slash on
//  some systems and not others, so we'll make sure it's gone in all cases where there
//  is ambiguity by using rtrim.
// Also note that this is above the loading of the wp-config-*.php files so that these can
//  be over-ridden as required.

$md_http = ($_SERVER['HTTPS']) ? 'https://': 'http://';
$md_server_name = rtrim($_SERVER['SERVER_NAME'],"/");
$md_document_root = rtrim($_SERVER['DOCUMENT_ROOT'],"/");

// The wordpress install is in its own folder, so we force that setting here
define('WP_SITEURL', $md_http . $md_server_name . '/wordpress');
define('WP_HOME',    $md_http . $md_server_name);

// The wordpress wp-content folder is outside of the git WordPress submodule so
//     tell WP where it is. These may have to be set manually in some cases
define('WP_CONTENT_URL', $md_http . $md_server_name . '/wp-content');
define('WP_CONTENT_DIR', $md_document_root . '/wp-content');

// Four stages
// local = local development on my workstation
// staging = site is on my staging server
// live = site is live and under my ongoing maintenance
// released = site is live and I play no role in maintenance. In this case, the logic 
//  block below is removed and everything reverts back to a single file, and all traces
//  of git are purged leaving a normal site. This is all done manually btw.

if ( file_exists( dirname( __FILE__ ) . '/wp-config-local.php' ) ) {
    define( 'MD_LOCAL_DEV', true );
    include( dirname( __FILE__ ) . '/wp-config-local.php' );

    // I don't need cron running, so turn it off
    define( 'DISABLE_WP_CRON', true );

} else if ( file_exists( dirname( __FILE__ ) . '/wp-config-staging.php' ) ) {
    define( 'MD_STAGING_DEV', true );
    include( dirname( __FILE__ ) . '/wp-config-staging.php' );

    // Disable all core updates, as they are handled on local machine and done via git
    define( 'WP_AUTO_UPDATE_CORE', false );
    define( 'DISALLOW_FILE_MODS', true );
    define( 'AUTOMATIC_UPDATER_DISABLED', true );

    // I Handle cron via system cron, so disable wp_cron
    define( 'DISABLE_WP_CRON', true );

} else if ( file_exists( dirname( __FILE__ ) . '/wp-config-live.php' ) ) {
    define( 'MD_LIVE', true );
    include( dirname( __FILE__ ) . '/wp-config-live.php' );

    //Disable all core updates, as they are handled on local machine and done via git
    define( 'WP_AUTO_UPDATE_CORE', false );
    define( 'DISALLOW_FILE_MODS', true );
    define( 'AUTOMATIC_UPDATER_DISABLED', true );

    // Disable all debugging
    define('WP_DEBUG', false);
}

// NOTE: If upgrading from an old installation and DB_CHARSET and DB_COLLATE do not exist 
//  in the wp-config.php file, DO NOT ADD THEM. Read more here
//  https://codex.wordpress.org/Editing_wp-config.php#Database_character_set
// Database Charset to use in creating database tables.
define('DB_CHARSET', 'utf8');

// The Database Collate type. Don't change this if in doubt.
define('DB_COLLATE', '');

/**
 * Authentication Unique Keys and Salts.
 *
 * Change these to different unique phrases!
 * You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}
 * You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again.
 *
 * @since 2.6.0
 */
// NOTE: This is a placeholder replaced with new salts via the site creation script
//  It will throw an error if not done correctly. This is by design.

define('AUTH_KEY',         '+/l:+c+^-RimCPsX7D]|[ G7>Yq2+lP T2[7/If2p-.${)((v-c<ubi*<8QOF.Q_');
define('SECURE_AUTH_KEY',  'FKgfL}M)DW6I5iQ-8pqF-op{6{o&d4KNHWxA|~jdR&kXO<(%AD`*i|RCp>S1>XDq');
define('LOGGED_IN_KEY',    ')|adOIXS>U(x 0UOV^.LhebLn_GUk,^x.I-0~R6<ig;q|e2X%ri`mG4S%cO2NYE|');
define('NONCE_KEY',        'G;tydGEsOy1`Wg9d%x{_+j~Z7@DI}^)fq$fNTu!82oVU!5S|y+lS[s~()&0fz&]-');
define('AUTH_SALT',        'Z1TvD2qp|ZJF.:uS3#P]%U/J&|ktGQe}HA@NQVXBFW?GM{?n.!h:aK!o-]hpU 5G');
define('SECURE_AUTH_SALT', ' 3NK2z#TK,X1FIv6#4C0iEQl$}ebQ{|-IHEm.wo;6/Fsp;8$xmb:]K?m,>6-`z.-');
define('LOGGED_IN_SALT',   'o+oy|<p/*m+>w}?n8!V^ybzDq*q-NiJ5NuQ0%FF/-I3w?zspN T!3C&b`_!YIADI');
define('NONCE_SALT',       '6lhg~>o:FBfm|j H<Nb++tqg$zyjp--?VWs$XAOa+T3{aN}dZq)4FBzo^54n)xz*');

/**
 * WordPress Localized Language, defaults to English.
 *
 * Change this to localize WordPress. A corresponding MO file for the chosen
 * language must be installed to wp-content/languages. For example, install
 * de_DE.mo to wp-content/languages and set WPLANG to 'de_DE' to enable German
 * language support.
 */
define('WPLANG', '');

/* That's all, stop editing! Happy blogging. */

/** Absolute path to the WordPress directory. */
if ( !defined('ABSPATH') )
    define('ABSPATH', dirname(__FILE__) . '/');

/** Sets up WordPress vars and included files. */
require_once(ABSPATH . 'wp-settings.php');
theMikeD commented 9 years ago

Note that the exact setup I'm using can be duplicated by going here https://github.com/theMikeD/wp-base-tools and using addwordpress.sh with no options.

theMikeD commented 9 years ago

A fresh install using only wp-cli works. Perhaps it's not parsing variables in wp-config.php properly

danielbachhuber commented 9 years ago

wp-config.php in case it's relevant

You'll want to reset your salts now that you've exposed them publicly.

Note that i made one change: that it applied to posts rather than a CPT for simplicity's sake.

Could it be that this one change is what fixes it? What priority is the CPT registered on?

theMikeD commented 9 years ago

This is a dev site never to see the light of day. This ain't my first rodeo :)

What it appears to be is that WP_CONTENT_DIR and/or WP_CONTENT_URL are being ignored.

theMikeD commented 9 years ago

UPDATE: The actual issue is that $_SERVER is not being set up when wp-cli is run. If you put

error_log($_SERVER['SERVER_NAME']);

into wp-config.php and run and wp command, you'll get a blank line. Is this an expected result?


Here is how to duplicate the bug. And yess, the numbering is off thanks to GH not recognizing a continuing list.

  1. Create an empty folder for testing. This will be referred to as "root"
  2. Install WP into root, but put it into its own folder called wordpress following these steps. After doing so, run the install process and verify that WP is working.
  3. in admin, activate the Twenty Fifteen theme.
  4. copy wordpress/wp-content to root, making it parallel with the wordpress/ folder.

At this point you will have two copies of wp-content/: one under root ( /wp-content/ ) and one under the WP install folder ( /wordpress/wp-content/ )

  1. Add the following code to wp-config.php
$md_http = ($_SERVER['HTTPS']) ? 'https://': 'http://';
$md_server_name = rtrim($_SERVER['SERVER_NAME'],"/");
$md_document_root = rtrim($_SERVER['DOCUMENT_ROOT'],"/");

define('WP_CONTENT_URL', $md_http . $md_server_name . '/wp-content');
define('WP_CONTENT_DIR', $md_document_root . '/wp-content');

This tells WP to use the wp-content/ folder in root. Verify that the admin is still working.

[UPDATE: This is the bug. Setting these two options manually doesn't reveal the bug, but setting them programmatically does. $_SERVER is not being set up bu wp-cli]

  1. Add the following custom taxonomy code to /wp-content/themes/twentyfifteen/functions.php

add_action( 'init', 'md_create_type_taxonomy', 0 );
function md_create_type_taxonomy()  {
    $labels = array(
        'name'                       => _x( 'Types', 'Taxonomy General Name', CF_TXT ),
        'singular_name'              => _x( 'Type', 'Taxonomy Singular Name', CF_TXT ),
        'menu_name'                  => __( 'Types', CF_TXT ),
        'all_items'                  => __( 'All Types', CF_TXT ),
        'parent_item'                => __( 'Parent Type', CF_TXT ),
        'parent_item_colon'          => __( 'Parent Type:', CF_TXT ),
        'new_item_name'              => __( 'New Type Name', CF_TXT ),
        'add_new_item'               => __( 'Add New Type', CF_TXT ),
        'edit_item'                  => __( 'Edit Type', CF_TXT ),
        'update_item'                => __( 'Update Type', CF_TXT ),
        'separate_items_with_commas' => __( 'Separate Types with commas', CF_TXT ),
        'search_items'               => __( 'Search Types', CF_TXT ),
        'add_or_remove_items'        => __( 'Add or remove Types', CF_TXT ),
        'choose_from_most_used'      => __( 'Choose from the most used Types', CF_TXT ),
        'popular_items'              => __( 'Popular Types', CF_TXT ),
        'not_found'                  => __( 'No Types found', CF_TXT ),
        'view_item'                  => __( 'View Type', CF_TXT ),
    );
    $rewrite = array(
        'slug'                       => 'story-types',
        'with_front'                 => false,
        'hierarchical'               => true,
    );
    $args = array(
        'labels'                     => $labels,
        'hierarchical'               => true,
        'public'                     => true,
        'show_ui'                    => true,
        'show_admin_column'          => true,
        'show_in_nav_menus'          => true,
        'show_tagcloud'              => false,
        'rewrite'                    => $rewrite,
        'query_var'                  => true,
        'args'                       => array( 'orderby' => 'term_order' ),
    );
    register_taxonomy( 'typetax', 'post', $args );
}
  1. Refresh the admin page to verify that the Type custom taxonomy is listed under Posts.
  2. run this command in the shell: wp term create typetax 'Banana' It will fail.
  3. Remove the custom taxonomy code just added and now add it to /wordpress/wp-content/themes/twentyfifteen/functions.php IOW the copy of Twenty Fifteen that WP would use by default, but is not actually using thanks to the wp-config.php mods.
  4. Refresh the admin page to verify that the custom taxonomy is NOT listed under Posts.
  5. run this command in the shell: wp term create typetax 'Banana' It will succeed.

Bug.

theMikeD commented 9 years ago

I'll add this last comment here to make sure the update is seen.

The actual issue is that $_SERVER is not being set up when wp-cli is run. If you put

error_log($_SERVER['SERVER_NAME']);

into wp-config.php and run any wp command, you'll get a blank line. For my setup, this sets WP_CONTENT_URL and WP_CONTENT_DIR to invalid results, and the command fails. Is this an expected result?

szepeviktor commented 9 years ago

wp-cli sets $_SERVER['DOCUMENT_ROOT'] to ABSPATH. See: https://github.com/wp-cli/wp-cli/search?utf8=%E2%9C%93&q=DOCUMENT_ROOT

danielbachhuber commented 9 years ago

Related https://github.com/wp-cli/wp-cli/issues/785#issuecomment-24915224

theMikeD commented 9 years ago

Maybe we should close this one and use #785 to track this instead? They are tracking the same issue.

danielbachhuber commented 9 years ago

Sure, #785 is fine.

chaoticbear commented 8 years ago

EDIT: Using a switch wasn't working for wp-admin URLs because the basename was outputting wp-admin. Using if and strstr to check if the cwd had a string in it works for both wp-admin and the live site. It feels clunky but it's an option.

In case anyone's looking for a workaround: getcwd() will get the current path and works in php cli php4+. Note that when accessing wp-admin it includes wp-admin because these requests aren't handled by the index.php in the wordpress root. That's why I'm using strstr to check if my path exists in the string.

Depending on your environment directory naming scheme this can work for multiple wp-config.php settings.

if(strstr(getcwd(),'/full/path/to/wp/dev')) { // DEV code / settings } elseif(strstr(getcwd(),'/full/path/to/wp/stage')) { // STAGE // STAGE code / settings } else { // PRODUCTION // PRODUCTION code / settings }

szabeszg commented 7 years ago

Thank you @joshfleming for the workaround!