#33161 closed task (blessed) (fixed)
Create a standard for defining and identifying site environment
Reported by: | krogsgard | Owned by: | SergeyBiryukov |
---|---|---|---|
Milestone: | 5.5 | Priority: | normal |
Severity: | normal | Version: | 4.2 |
Component: | Bootstrap/Load | Keywords: | has-patch has-dev-note |
Focuses: | Cc: |
Description
There are a number of reasons I can think of that would make a site environment identifier quite handy.
What I'm proposing: The ability to potentially define and/or identify a site environment, i.e., local
, development
, staging
, live
.
For instance, if it were a constant, then it could be defined:
define('SITE_ENVIRONMENT', 'live');
Third party solutions like Mark Jaquith's WP_LOCAL_DEV
are already popular, but this would be in core and include more environments.
I know that adding constants isn't popular, but this could also allow core as well as third party plugins and themes to remove code that attempts, often not that well, to determine the same kind of information. A definition in the site's config could help make that easier and more accurate.
I don't know if a constant is the best route for enabling the definition and identification of the site environment, but I'd like to start a conversation.
Attachments (2)
Change History (67)
#2
@
9 years ago
You mention that Core does attempt to find out in what environment the code is running, would you mind pointing me towards an example for this?
In my opinion, your code should not care where it runs. Local, preproduction, production, those are just deploys of the same code base. Meaning the behavior of the code base should not change depending on the environment.
The current way of handling connection details in wp-config.php
, and the workarounds like the one that Mark has written about are fine for use cases in which you do not want to put a deployment procedure into place.
However if you are at the point that you have a centralized development version, a staging environment, etc. then the time for poor workarounds like conditional handling of database connection information is gone.
There are solutions for all the problems that people encounter. There is software to automatically provision machines in the different environments to keep the stack the same. The config can be stored in environment variables. Differences in asset handling (unminified in development, minified in production) can be handled through build scripts.
There's a great site about best practices like this: http://12factor.net/
So in short I'm not in favor of this ticket. It encourages outdated development techniques and actually makes things more difficult for developers. Web development has moved on from these techniques, let's move along with it.
#3
@
8 years ago
What about incorporating dotenv?
https://github.com/vlucas/phpdotenv
This would avoid ever having to edit wp-config.php for configuration, like database credentials, as well as giving the ability to define enviroment variables for plugins, themes, etc. if desired. API keys spring to mind as an example. These things can then be kept out of the code base, out of version control, and even out of the document root if desired.
@Frank Klein - Item 3 of the 12 Factor app is specifically about storing config in the environment and not in the code base, so I'm confused why you reference it and then say you're not in favour?
Here is an article by Eric Barnes highlighting one way that dotenv could be incorporated in to WordPress to help manage environments.
https://dotdev.co/tutorials/secure-wordpress-config-dotenv/
#5
@
5 years ago
While @ocean90 just marked my issue as a duplicate, that doesn't bring all the nuance in that issue here. Especially that there's now prior art in three of the biggest plugins out there for doing this, Jetpack, Woo and Yoast. We need to address this.
This ticket was mentioned in Slack in #core-site-health by joostdevalk. View the logs.
5 years ago
#7
@
5 years ago
Moving the context from that duplicate ticket to here:
WooCommerce subscriptions solved this for themselves, as can be seen here. Jetpack has "staging mode". We at Yoast partly fixed it and will need to fix it even better soon. Others _must_ run into this problem, where you don't want to show certain notices on a staging site that you do want to show on a live site.
Would it be a good idea to set an option in the site settings, under Settings -> General, that toggles between three states:
- development
- staging
- live
Where "live" would obviously be the default.
This would allow hosts that create staging sites to switch this toggle when they move a site to a staging environment etc. This way, Yoast SEO for instance could automatically block indexing of development and staging sites, and instead open up indexing on live sites. Other plugins like the Woo Subscriptions case above could also be solved much more uniformly.
#8
@
5 years ago
- Milestone set to 5.5
- Owner set to SergeyBiryukov
- Status changed from new to accepted
Not sure this should be a UI option. Let's start with a filterable function, wp_get_environment_type()
or something like that. If someone has ideas for a better name, please share :)
#11
@
5 years ago
This would be very helpful for other areas of sites looking to use things like Elasticsearch as well (specifically on our Jetpack Search feature). Big benefit if you can see what state the site is in and not accidentally start indexing large amounts of data on a testing site.
#12
@
5 years ago
Yes, definitely in favor of something proper here.
Adding to the use cases: conditionally plugging wp_mail()
in non-production environments to as to not inadvertently send n
automated/transaction emails. I heard this happened to a friend once and it was a bad day for my friend.
#13
@
5 years ago
I've had this come up a couple times as well of late, and made some thoughts on the approach, heck, I've made a quick code-draft with my thoughts on how to approach it, I don't want it to be a dashboard setting, but I see the value in flexibility.
System environment variables are worht their weight in gold for those who have dedicated stage servers, while constants are fixed values that can be used to override this in one-off situations, or where system environment variables are not available for whatever reason.
And of course, filters, you may have a plugin to handle this in various cases.
It's also important to limit the outputs, or at least to an extent, to ensure the response is an expected one.
I'm not 100% sold on filtering the available approved environments or not, but I put it in as a thought to not disregard it straight away though.
<?php function get_environment() { $approved_environments = array( 'development', 'stage', 'production', ); /* * Filter specs for allowing other environment types for very unique setups. */ $approved_environments = apply_filters( 'wp_approved_environments', $approved_environments ); $current_env = ''; // Check if a environment variable has been set for max flexibility, if `getenv` is available on the system. if ( function_exists( 'getenv' ) ) { $has_env = getenv( 'WP_ENVIRONMENT' ); if ( false !== $has_env ) { $current_env = $has_env; } } // Fetch the environment from a constant, this overrides global system variables for consistency. if ( defined( 'WP_ENVIRONMENT' ) ) { $current_env = WP_ENVIRONMENT; } /* * Filter specs for setting the environment programatically. */ $current_env = apply_filters( 'wp_current_environment', $current_env ); // Make sure the environment is an allowed one, and not accidentalyl set to an invalid value to try and avoid breaking stuff relying on this. if ( ! in_array( $current_env, $approved_environments ) ) { $current_env = 'production'; } return $current_env; }
#14
follow-up:
↓ 15
@
5 years ago
To echo @nathanrice... I did a little checking with folks here at WP Engine / Genesis / Flywheel / Local WP and we can think of a good number of use cases where this would be helpful for our customers & products. As with other plugin authors, we have our home-brew ways of dealing with this today. Having a standard would be helpful.
#15
in reply to:
↑ 14
@
5 years ago
+1 we see this all the time. For example, Jetpack is crazy popular and doesn't run well on staging or local environments. Support for hosts is hard-coded into the plugin itself: https://github.com/Automattic/jetpack/blob/5faa321993c4ca955df871f5a77cd89fa411bca5/packages/status/src/class-status.php#L91
Local would benefit greatly from something like this!
Replying to davidvee:
To echo @nathanrice... I did a little checking with folks here at WP Engine / Genesis / Flywheel / Local WP and we can think of a good number of use cases where this would be helpful for our customers & products. As with other plugin authors, we have our home-brew ways of dealing with this today. Having a standard would be helpful.
#16
@
5 years ago
I'd like to hear a bit more about specific use cases so we can more clearly identify the problem before proposing solutions.
Assuming core implements functionality that allows the environment to be determined as one of development, staging, or production, what does this enable?
#17
follow-up:
↓ 21
@
5 years ago
The reason I'd like to hear specifics is because every time I encounter this problem, the logic that alters behaviour based on the environment happens really early, in wp-config.php
, meaning a filterable function will trigger too late for a lot of per-environment logic.
#18
@
5 years ago
We have this need too in WP Rocket since recently.
A use case is for example our RocketCDN service integration. Users are able to subscribe to the service from the plugin itself, but we don't want them to do that when it's a local or staging site.
Right now we have our own function to check for that https://github.com/wp-media/wp-rocket/blob/c7a020448d6639ca3cb4cddf72195f9d9c18fbec/inc/functions/api.php#L85 but a core solution would make it unnecessary, as we could rely on the hosts/local solutions to provide that information to WP for the most part instead.
#19
@
5 years ago
Something like the idea behind this little plugin of mine?
https://github.com/Nettvendt/wp-local-dev
#20
@
5 years ago
I'd love to walk through it (since I made a very tangible proposal).
Firstly, it's a function used for grabbing the current environment, this is to ensure everyone fetches the values the same way (to avoid using different terms and such).
As you mentioned, the function would need to be loaded fairly early, probably alongside the same time as the fatal error handler and similar things, to make it usable in most scenarios.
As for the filtering possibilities, although possible to circumvent by running code directly instead of through hooks, _most_ (based on my own experience at least) actions that fire would come from another hook or later down the call stack.
Some examples where diverting based on environment would be useful:
Outbound emails could be filtered, and if get_environment()
isn't set to production
then send them to the developer, allowing for legitimate email tests in stage setups without worrying about emails reaching end users.
API endpoints where you want to use a test endpoint when not in production to prevent data pollution.
Providing a wp-admin notice for non-production sites so it's much clearer that what you are doing now will/won't affect the site your business relies on.
All of those examples fire so late that plugins would have had a chance to kick in a filter.
As for why they might want to filter, you may use a "staging-plugin" to change environments on your site on the fly for testing purposes, or possibly conditionally set the environment "the core way" on a legacy project which has been doing it in some custom way without a good way to change that, but wanting to ensure compatibility with other plugins/themes moving forward.
#21
in reply to:
↑ 17
@
5 years ago
Replying to johnbillion:
The reason I'd like to hear specifics is because every time I encounter this problem, the logic that alters behaviour based on the environment happens really early, in
wp-config.php
, meaning a filterable function will trigger too late for a lot of per-environment logic.
I was actually looking to see if there were comments beyond the dev, staging, and live usage. For a specific use how about a temp site built on a local vm used for quick and dirty host/domain migrations? I’ve done this with a hacked site in the past as well for content restoration.
#22
@
5 years ago
@johnbillion with the patch proposed above you could set WP_ENVIRONMENT
before wp-config even loads and fix it.
#23
@
5 years ago
I really like @Clorith's excellent suggestion.
We are adding our own custom environment vars here at Pantheon so plugin authors have the option of doing this but it would be so nice to have this in core so plugin authors don't need to write host specific code.
The original proposal defined local as a possible option. Is there a need for a local definition or does using development for local give the same outcome for plugin authors?
#24
@
5 years ago
One suggestion on how to possibly make this a user-facing enhancement: different admin styling (colors or otherwise) for staging and local environments.
#25
@
5 years ago
One suggestion on how to possibly make this a user-facing enhancement: different admin styling (colors or otherwise) for staging and local environments.
I like that idea, would also prefer changing the favicon.
But: I don't want *anything* to block shipping the bare bones version of this ASAP :)
#26
@
5 years ago
Yeah there's a few options we can do there, one that I've done on WordPress.com VIP is to use an environment indicator in the admin toolbar but I don't think that's anything we should do for the first version in core.
This ticket was mentioned in Slack in #hosting-community by mike. View the logs.
5 years ago
#28
follow-ups:
↓ 29
↓ 31
@
5 years ago
This seems to have consensus, my only concern is that get_environment()
function name seems too general, I would think it returns something like phpinfo()
or Site Health info. I also think we'd want to add a wp_
prefix to avoid a potential clash with any custom functions.
How about:
wp_get_environment_type()
for the function and filter name.WP_ENVIRONMENT_TYPE
for the constant name?
#29
in reply to:
↑ 28
@
5 years ago
How about:
wp_get_environment_type()
for the function and filter name.WP_ENVIRONMENT_TYPE
for the constant name?
Sounds good to me.
This ticket was mentioned in Slack in #hosting-community by jadonn. View the logs.
5 years ago
#31
in reply to:
↑ 28
@
5 years ago
Replying to SergeyBiryukov:
How about:
wp_get_environment_type()
for the function and filter name.WP_ENVIRONMENT_TYPE
for the constant name?
Indeed, in this case I think it's really necessary to use wp_
prefix, as there may be a lot of existing implementations.
#33
@
5 years ago
Logical next step: Should the default value of WP_DEBUG
and friends be dependent on the environment? eg. should WP_DEBUG
be true by default for non-production environments?
#34
@
5 years ago
- Keywords needs-dev-note added; needs-patch removed
Note: @joostdevalk proposed to write the related dev note.
#35
@
4 years ago
In a future iteration of this patch, I wonder whether this comment above the wp_get_environment_type
filter could be clarified:
This filter runs before it can be used by plugins. It is designed for non-web runtimes.
Since nothing is yet invoking wp_get_environment_type()
, it's unclear why plugins are unable to use it.
Also, a plugin still could add a filter to it, and subsequent calls to wp_get_environment_type()
would honor the filter. It sounds as though something is going to have been defined before the plugin can act — it's just not clear what.
Secondarily, it would be great if there was a sanctioned way for all runtimes to be able to modify the list of allowed environments, perhaps through a constant similar to WP_ENVIRONMENT_TYPE
.
To take one example: As noted by @johnbillion's plugin, the VIP Go platform offers a develop
environment, which is not the same as our local development environments. In this case, it would be confusing, if nothing else, for our local environments to be development
, as would labeling VIP's develop
environment as stage
, since there can also be a stage
environment.
Using the example of one VIP Go project I'm familiar with, it would be much preferable to be able to list array( 'local', 'develop', 'preprod', 'production' )
, which mirrors the names given to the project's existing environments.
#36
follow-up:
↓ 38
@
4 years ago
@dlh looks like this:
Secondarily, it would be great if there was a sanctioned way for all runtimes to be able to modify the list of allowed environments, perhaps through a constant similar to WP_ENVIRONMENT_TYPE.
is already covered by the patch?
#37
@
4 years ago
I see the wp_approved_environment_types
filter, but it's documented as "for non-web runtimes." Am I misreading the patch?
#38
in reply to:
↑ 36
@
4 years ago
- Resolution fixed deleted
- Status changed from closed to reopened
Replying to joostdevalk:
looks like this:
Secondarily, it would be great if there was a sanctioned way for all runtimes to be able to modify the list of allowed environments, perhaps through a constant similar to WP_ENVIRONMENT_TYPE.
is already covered by the patch?
Apparently not, looks like it should read a WP_APPROVED_ENVIRONMENT_TYPES
system variable and constant.
#39
@
4 years ago
I'm not sure approved
is the correct phrasing that should be used here, perhaps it should be whitelist
or whitelisted
instead?
Or, the filter could just be renamed to wp_environment_types
too I guess?
#41
@
4 years ago
somehow related "Force users to set strong passwords" https://core.trac.wordpress.org/ticket/35817#comment:7
#42
@
4 years ago
- Keywords has-patch added
In 33161.diff:
- Rename
wp_approved_environment_types
to justwp_environment_types
. - Introduce
WP_ENVIRONMENT_TYPES
system variable and constant to complement the filter. - Correct the argument type for the
wp_environment_types
filter.
This ticket was mentioned in Slack in #core by jeffpaul. View the logs.
4 years ago
#44
@
4 years ago
I think it'd be valuable to make sure this value is the same throughout the entire request by caching it internally, perhaps with a static
variable. Having the environment change out from under you could lead to weirdness depending on how developers are utilizing the environment type.
#45
@
4 years ago
Agreed. I can imagine a plugin that adds a filter to wp_approved_environment_types
or wp_get_environment_type
after it initialises, causing the value to change.
#46
@
4 years ago
Is there a specific reason this using 'stage'
instead of the more typical 'staging'
?
Also, would there be any objection to also includinig 'qa'
and 'uat'
in the default list of environments?
#48
follow-up:
↓ 49
@
4 years ago
To summarize, some open questions left from comment:33 and comment:46:
- Should the default value of
WP_DEBUG
and friends be dependent on the environment? eg. shouldWP_DEBUG
be true by default for non-production environments? - Would there be any objection to also includinig
'qa'
and'uat'
in the default list of environments?
#49
in reply to:
↑ 48
;
follow-up:
↓ 50
@
4 years ago
Replying to SergeyBiryukov:
To summarize, some open questions left from comment:33 and comment:46:
- Should the default value of
WP_DEBUG
and friends be dependent on the environment? eg. shouldWP_DEBUG
be true by default for non-production environments?
That makes sense to me that defining the site environment sets reasonable defaults for WP_DEBUG, et al.
- Would there be any objection to also includinig
'qa'
and'uat'
in the default list of environments?
No objection per se, but I'd like in the dev notes (and ideally in inline documentation IMO) some explanation of what each is intended to mean.
For example, in Jetpack, we have a "development mode" that is intended for localhost where a site would not be connecting to WordPress.com. The original use case is for theme developers to be able to activate some features of Jetpack that would usually require a connection with a fair mockup of it so they can work on front-end theming. (I realize this mode isn't perfect, so let's not go down the rabbit hole if Jetpack is actually doing all that I'm claiming it does!). Major parts of Jetpack will not work in this mode and isn't foreseen as a new going-into-production-eventually site. [To note, Jetpack will likely deprecate and rename our "development" mode to be more precise as a "localhost mode".]
We have a "Staging Mode" which is meant for sites that may be a copy of a production database (which in our case includes the knowledge that a site is connected to WordPress.com), but isn't production — so don't do anything that would impact that. Don't send out new posts to Twitter, etc.
I think our use of "staging" matches what everyone else is using it, but I think we may have different definitions of a "development" environment in this instance. I'd reckon that "development" here means a version of a regular site that is early in the workflow toward production.
In short, when plugins are looking at the site environment and deciding what to do, let's make it really clear what the site owner's intention should be when they set that environmental value.
#50
in reply to:
↑ 49
@
4 years ago
Replying to kraftbj:
- Would there be any objection to also includinig
'qa'
and'uat'
in the default list of environments?No objection per se, but I'd like in the dev notes (and ideally in inline documentation IMO) some explanation of what each is intended to mean.
Since the suggestion for adding those came from me, let me explain what I mean by them (actually, the following is how they've been used by clients I've worked with):
qa
anduat
are distinct fromdevelopment
andstaging
in that- no code or content changes happen (other than pushes from some "other" environment)
- they never get pushed to production (like
staging
), tho they do get pushed tostaging
uat
(User Acceptance Testing) is for review/sign-off on both functionality and look-and-feel by stake holdersqa
(Quality Assurance) is for review/sign-off by parties that are not stake holders, e.g.,- the legal department approving final copy (e.g., changes to Privacy Policy text)
- outside auditors (e.g., accessibility audits, when there are legal requirements for Level A vs AA vs AAA WCAG compliance, and the expertise to do that review is not available in-house)
Maybe those environments (and the purposes they are used for) are peculiar to the clients I've worked with, in which case I have no problem with them not being included in core (since they can always be added via the wp_environment_types
filter).
Hope this helps.
#51
@
4 years ago
All these extra values, outside staging
, development
and production
feel like very user-specific cases to be, and I'd rather see them be added through other means in the cases where they are needed.
As for setting WP_DEBUG
based on the environment, I'm thinking it would be nice if development had WP_DEBUG
enabled by default (of course overruled by using the constant manually), and disabled on production
, which is already the default, so I guess really only the development
one would make sense.
#52
@
4 years ago
I concur, the intention isn't to cover every possible named environment, but rather the environment types. I won't be using this function to identify an environment, just to identify its type in order to toggle certain behaviour on or off.
UAT, QA, etc can be classified as development or staging as you see fit.
#53
@
4 years ago
I have no problem with limiting the types to development
, staging
, and production
. Consider my request to add qa
and uat
withdrawn.
#54
@
4 years ago
I think that only leaves the request to set WP_DEBUG
to true on development
environments, which makes all sorts of sense to me, so let's just do that?
#55
@
4 years ago
Assuming that wp_initial_constants()
would continue to be called when it is currently, then it looks to me like using wp_get_environment_type()
to determine the default value for WP_DEBUG
would mean the new static $current_env
would be set very early, even before MU plugins. That might not be a bad tradeoff for the consistency of knowing when the environment type will be set, but noting it just in case.
#58
@
4 years ago
- Resolution fixed deleted
- Status changed from closed to reopened
Since the function runs too early for plugins to hook into the wp_environment_types
or wp_get_environment_type
filters here, and the result is then cached in a static variable and cannot be changed later, it seems that the filters are not that useful.
Even having them documented as:
This filter runs before it can be used by plugins. It is designed for non-web runtimes.
it still might be confusing. At a glance, I don't recall any other filters in core that are not designed to be used by plugins in a "normal" way.
Any objections to removing the wp_environment_types
and wp_get_environment_type
filters? The environment variables and the constants seem enough for now. See 33161.2.diff.
#60
@
4 years ago
@SergeyBiryukov Go for it, you may be right and that may avoid some confusion down the line... since the filter _could_ be used by a plugin, but you may have different results depending on when the environment check is triggered if something does filter them.
@szepeviktor the WP_ENV
approach is something used by Bedrock as far as I know, and although that's a good boilerplate, it's not indicative of the wider WP world. Personally I favor constants that are spelled out for clarity sake (that's my own personal take on it of course), but if there's strong reasons for changing this, then there's still a few days to make amendments here, but there's not been a lot of issues surfaced by the chosen naming scheme.
Edit: Also by using a name not used by an existing boilerplate, we avoid unintended behavior for users who just download boilerplates without changing default values, so that may also be a benefit, and not a drawback.
#61
@
4 years ago
@Clorith We have WP_ENV×22000 on GitHub https://github.com/search?q=WP_ENV&type=Code
It is widespread including the roots people.
we avoid unintended behavior for users who just download boilerplates without changing default values, so that may also be a benefit, and not a drawback
I do agree with that.
To be fair upfront, one of the biggest downsides is that this would happen in
wp-config.php
and that's one of the ideal places to use this information.It'd be great to more easily define site config constants (like database details) based on what environment is. I don't know the way around that, and that's my biggest question as to whether a constant would be the right route, or if there is a more low lying issue that would need fixing to make this the most valuable.