We found – 4 articles for query model

Upcoming changes to the Date Time system

This post is intended to be the more technical complement to the post on our main website blog.

Background

We recently discovered the following within our automated unit tests against our date and time system:

  1. Although we test gmt offset conversion to a timezone string via EEH_DTT_Helper_Test::test_get_timezone_string_from_gmt_offset, the primary purpose of that test is just to verify that there are no fatals. Primarily that list of offsets includes what were determined to be invalid offsets within php. However, this list is a hardcoded list of invalid offsets that are not necessarily invalid for every system environment.
  2. There is no where in our unit tests where we test setting the WordPress gmt_offset option to an offset, set the timezone_string option to an empty string, and then test the EE generated dates and times in the model system against what WP returns for it’s date methods.

As I began going about correcting the above issues, I started discovering other flaws within our code.

Before getting into the issues uncovered below, keep in mind that one of the reasons EE works with timezone strings as opposed to offsets is because that is primarily how PHP is oriented for its DateTime system. If you want to work with DateTime objects accurately in PHP, then you need to work with timezone strings not offsets.

The fact that WordPress allows users to set a GMT offset for times in their system may be fine for a general blog, but its a huge pain for an application around events because offsets have no location awareness and do not inherently track any DST that might exist for that location. This problem is magnified with software like Event Espresso.

Issue One: DST

EEH_DTT_Helper::get_timezone_string_from_gmt_offset was not considering that a set timezone_string in the database could be in DST.

In WordPress, when a call is made to get_option(‘gmt_offset’) there is actually a default hook added by WordPress core on the pre_get_option_gmt_offset which checks get_option('timezone_string') first and if that’s present, returns the offset for that timezone_string. So even if both gmt_offset and timezone_string are set on a WP install (which is possible, just not via the ui), then the offset on timezone_string gets returned.

Where this is problematic is that offsets are timezone agnostic, however, the offset for a timezone_string could vary depending on whether that timezone is currently in DST or not. So if this method was called with NO offset supplied, and the current set timezone_string on the site was in DST, then the resulting offset used for the initial search in timezone_name_from_abbr could result in an INCORRECT match.

I fixed this so that in this scenario if there is a timezone_string set in the db, we just return that instead of deriving it from what gets returned by WP as the offset.

Issue Two: Offset of +0

EEH_DTT_Helper::get_timezone_string_from_gmt_offset was not properly handling scenarios where an offset of 0 was supplied. For all purposes 0 === UTC so there is no need to go through all the logic that could return something that is 0 but currently only because the site is in DST. If client code is supplying an offset to get a timezone_string, then we assume not DST information.

So this was fixed so that now if this method explicitly receives an offset, the assumption is explicit that the given value has no DST information.

Issue Three: Historical Timezones

EEH_DTT_Helper:;get_timezone_string_from_gmt_offset was returning matches against historical timezones.

The PHP methods timezone_name_from_abbr and timezone_abbreviations_list contain not only current timezone data, but also historical timezone data. I discovered this when running some new unit tests we have setup in the working branch. For the offset -12, that would get flipped by the EE usage of these php methods to +12!!! The reason for this is because although -12 matched a timezone_string using the php methods, the current actual offset in real life for the matched timezone_string (when using that matched timezone_string) to instantiate a DateTimeZone object is +12. So the timezone_string matched historically had an offset of -12 but in current day no longer has that offset.

To fix this, I added some further checks on matched timezone strings to make sure that the current offset for that matched timezone_string equals the incoming offset. If they don’t match then that timezone_string match is rejected.

Doing this in turn revealed a number of offsets that are settable via the WordPress UI that have no equivalent currenttimezone_string matches in PHP! To complicate things, that list of invalid offsets is dynamic and depends on whether the server the site is on has up to date timezone offset maps which in turn is influenced by the server OS and/or PHP version installed. The fixes implemented account for this.

Issue Four: Inability to do certain tests.

I added some comments to the Model_Data_Translator_Test::test_prepare_conditions_query_params_for_models__gmt_datetimes that explains why certain offsets were removed from the list that gets tested. This was done intentionally, because the offsets that get adjusted by EE in the EEH_DTT_Helper::adjust_invalid_gmt_offset with the implemented fixes, are changed to the closest offset with a corresponding current (historically) timezone_string. This means that sometimes, the values for “now” saved to the db will NOT match the value for “now” that is generated by the WordPress current_time function because that function works with offsets directly and does not rely on php’s timezones at all (when the only time information on the WP site is gmt_offset which is what this test working against). So this means its pretty much impossible to reliably test comparisons for offsets we convert against the offset WP uses because this could vary between server environments.

Practically speaking, the tests that matter are still covering critical functionality.

What this means

If you are using any code that interacts directly (or indirectly) with our EEH_DTT_Helper::get_timezone_string_from_offset method (or any of the public methods it calls), you need to be aware of how this could change when things are released (as described above).

This also means that for sites using a GMT offset (as opposed to a timezone_string), the resulting values for saved dates and times in the database (when displayed) may not be as expected because the database values were converted using an incorrect offset to begin with.

To fix the above scenario on affected sites, there are a couple options:

  1. You can use the bundled tool that provides a UI for fixing the offset on all saved EE date and time values in the database.
  2. You can manually fix things for affected sites via using a variation of the query found here (note this query only affects datetime offsets, there are other values in the database that use EE_Datetime values which are affected that you’ll want to run the query against as well): https://github.com/eventespresso/ee-code-snippet-library/blob/master/mysql-queries/update-offset-on-all-datetimes.sql

The good news is that if you have sites that are not using UTC offsets but are using timezone_strings then they will not be affected by any of this.



To OOP or not to OOP ?

While performing a code review for some work I had done, I was asked the following question by Darren regarding a new method I had added to EEM_Registration called event_reg_count_for_statuses() :

 I wonder if it’d be better to have the first argument be an $Event ID instead of a full event object?

The method in question type hinted for an Event object:

then used that event object to populate part of a query’s where conditions like :

in which we would substitute ### for the Event ID using

Now normally it’s advisable to try and type hint for objects as much as possible, but keeping in mind that this method was basically a query helper on the EEM_Registration model used for retrieving information from the database, Darren’s suggestion was actually a better approach.

But why?

Function Parameters : Primitives or Objects ?

As stated above, it’s normally advisable to try and type hint for objects as much as possible because there are many benefits to be gained from passing an object instead of any other alternative. The following are some musings on why this is usually the case, written using the method discussed above as a point of reference.

Guaranteed Identity

If a function accepts a value that we can not type hint for, then we really don’t know what we are getting. Even if an int is received (as opposed to some other value)… how do we know that it is a valid Event ID ? It could be any random number, and no amount of validation logic ensuring that we receive an int can change that it could still be a random number. But by simply type hinting for an EE_Event, we have guaranteed that the value we pass along to the query is not only an int, but a valid Event ID. No further validation logic beyond the type hint is necessary but the method gains a lot of stability.

Efficiency and Memory Usage

In PHP all objects are passed by reference, whereas passing an int would require a new local variable to be created to hold a copy of an already existing variable, so more memory is required as there will be more entries on PHP’s memory stack. This isn’t a big deal if there are only two methods involved, and the one receiving the Event ID to perform the query isn’t passing that ID along anywhere else (other than the model). But if the chain of methods involved was bigger, and the Event ID was getting passed around a lot, then the memory usage for that one bit of data can grow quickly. Change your variable to an array of data and the inefficiency goes way way up. When I first started with EE working on EE3, the methods involved in the registration process would all pass IDs amongst themselves. This was horrifically inefficient because you would have a method receive an Event ID, then query for the Event object so that it could get other data for the Event, then pass the ID along to the next method, that would also query for the Event object so that it too could get other data for the Event. This sometimes happened 4-5-6 times in a row, meaning 4-5-6 queries for an Event object that was already in the system. And many of these methods would also save their changes to the Event object before passing its ID along, so a series of function calls could result in dozens of unnecessary additional queries (we can thank the previous lead dev Abel for that bit of amazing code /sarcasm). This is the worst case scenario and the main thing that I want to avoid, so if you are writing a method that requires an object, you should type hint for that object instead of simply requesting an ID. Then any other methods that require the use of your method can handle obtaining the object based on what data they have, assuming they don’t already have it.

Fail Early at the Source

So when a function type hints for an object, then it can only receive a valid instance of that object. Where the object was originally instantiated is inconsequential because PHP is only passing pointers around instead of the actual object, and if a valid object could not be created, the error would likely be discovered immediately. But when you pass primitive data types around, it can sometimes be difficult to determine where the data originated from.

If a function requires a valid valid Event ID but some invalid value is received instead, then we are farther away from the original source of the invalid data. By forcing the code that first obtained the int to retrieve an Event, any errors can be thrown at the source of the problem. I know I have experienced difficulties in finding the source of a problem because some variable was passed around through some filters and/or actions, and by the time the variable was discovered to be invalid, the source no longer appeared in the stack trace. This kind of follows the fail early philosophy. In an ideal application, the request data would be validated immediately and any invalid data would produce errors immediately. By passing an integer through the system, we can not do this. Of course it’s not always ideal to convert an int to an object just so that you can retrieve that same int again from the object (especially if a query was required to build the object).

Domain Driven Design

In articles discussing Domain Driven Design, you will often see images of a system represented by a series of rings or hexagons that surround each other. The innermost ring represents the domain where all of the business logic resides. The domain should be completely ignorant of the request as that interaction should be handled by one of the outer rings. Imagine the stability of a domain that ONLY type hints for objects as opposed to one that allows primitive data types to be passed around. The second would require significantly more validation and processing to ensure that the methods were receiving the data that they require. Whereas the domain that exclusively type hints for objects would be much much more stable, since the range of data its methods could accept would be greatly reduced. In this kind of system, your outer ring that interacts with the incoming request would be responsible for validating all of the incoming data before passing it to the domain. So your controller type classes that receive the user input or request data, would also need to have access to a model or repository that they could pull the appropriate object from before passing things along to the inner domain. In this situation, since event_reg_count_for_statuses() is a query helper method on the model, it’s appropriate for it to receive an ID instead of an object. So in this case, we decided not to OOP.

 



Important changes to EE Datetime System coming to EE

This post is to highlight some changes coming to the EE Datetime system that we want to highlight to developers who might be building things using EE. There is potential that interactions with the current EE Datetime system will break when these changes are rolled out.

[notification type=”alert-info” close=”false” ]The datetime changes mentioned in this post are currently available on this branch of the EE repository.  Currently there is no set release date for these changes but they are coming soon.[/notification]

In most cases, modifying code to work with the old system will only need some minor updates to enable it to work with the new system so it shouldn’t take long to update any of your custom code and/or plugins implementing EE Datetime system methods and logic (we’ve already done that for any of our official add-ons).

Our Goals

Since Event Espresso is a product that is primarily concerned with events, it is assumed then that dates and times are a critical component of our product.  Therefore, one of the important considerations when designing EE4 is having a robust date and time (or datetime) system. There are a few end goals we have with this system:

1. Simple

Dates and times become a complex subject when you throw timezones and all the different formats they can have into the mix.

  • Developers need a simple way to interact with dates and times.
  • End Users need a simple way to modify how dates and times are displayed on their site.

2. Clear and Consistent

It should be easy to point to a date and/or time and know what timezone it is in, and what format it is in.

  • Developers need to have a clear understanding of what timezone a given date and time string is in, what format it is in, and have a clear way to interact with the system where things are not ambiguous.
  • End users shouldn’t require the date and time interface be explained to them.  They should also be able to have the dates and times in their language and display to their site visitors in their language.

3. Flexible

Dates and Times can be displayed in many different formats, timezones and languages (both human and machine).

  • Developers should be able to interact with our system using a variety of formats, and timezones and via different machine languages (php, js, mysql, json etc).
  • Users should be able change the way dates and times are displayed on the front end of their site and in their administrative pages. End users should have flexibility in displaying dates and times in creative ways (i.e. calendar type boxes)  The visitor to users sites, should (eventually, still on the roadmap) be able to control how dates and times are formatted and modify them so they are in their own timezone.

How Dates and Times Work in WordPress

Most WordPress developers will be familiar with how dates and times work in WordPress, however it is worthwhile summarizing this for the purpose of this document:

1. WordPress sets the offset for all php date related processing to UTC +0 (or GMT).

This means that when you use a php related date function like date() it returns the result in UTC+0.

2. In the General Settings page for WordPress, users are able to set the format for how dates and times are displayed on their site.

This means whenever dates and times are displayed on their WordPress site, they will be in the given format and given timezone.

Very important: WordPress makes the assumption that once people set their timezone on this page, they will never be changing it (even though you CAN change it).  How do we know this assumption is made? See the next point…

3. WordPress saves dates in the database for posts in four columns.

Two for the date in the current timezone (post_date, post_modified_date) and two for the date in gmt (utc+0) (post_date_gmt, post_modified_date_gmt).

In BOTH cases, the date is saved in the mysql timestamp format (Y-m-d H:i:s).

When post dates are retrieved by default from the WP database using their date functions. The default date retrieved on the frontend is post_date or post_modified_date, unless wp is doing internal date and time calculations in which case it uses the gmt values (eg publishing a post that was set on a schedule for being published) or unless the others are explicitly requested.

The advantages to doing things this way, is because wp can then use php date functions to just transform and display the save “post_date” and it will always be in the correct set timezone for the end user. Then they still have GMT for falling back on when doing date and time calculations.

However remember WP is assuming people will never change their timezone (which in reality is actually a fairly safe assumption to make in most cases for simple blogs). Why is this a gotcha? Because IF someone changes their timezone then all of their existing posts will have the date displayed for those posts as originally saved (which is for the date in the old timezone). Which for all intents and purposes is accurate, but to the end user it may appear incorrect because its not displaying it in the date and time for the current timezone. If the end user wants to update things, then they need to go into each post and modify the publish date (or write a script to automatically convert existing post_date and post_modified_date to the current timezone values using the saved gmt values.

My guess is that WP did this because it saves a having to convert things to and from GMT time and thus makes things efficient (while still being able to query against that gmt time). The huge downside to this approach in my opinion, is the assumption that people will rarely change the timezone for their website.

Frankly, I don’t think that’s an assumption we can make with Event Espresso, especially if we are ever going to offer the feature where people can list event dates and times for specific timezones (separate from the set site timezone).

4. current_time().

current_time() is a function in WordPress that is intended to make it easier to quickly get a correct date and time string for NOW on this website, without having to worry about timezone stuff.

It returns two possible formats mysql and unixtimestamp. It has a flag that allows you to indicate you want the date returned in.

Here’s the incredible gotcha with WordPress.

If you do current_time( 'timestamp' ), WordPress will return a unixtimestamp. But its actually NOT equivalent to what you’d get with time(). In fact, what WordPress does, is they ADD the offset for the set timezone on the site TO that unixtimestamp. The reason they do this, is so if you do something like date( 'Y-m-d H:i:s', current_time('timestamp' ) ), it will just output the date as is because remember internally, WP has set all php date functions to UTC. Since UTC+0 has no offset, it will take an incoming unixtimestamp and not apply any offset. So WordPress APPLIES the offset ahead of time. If one was to do date( 'Y-m-d H:i:s', time() ) that returns the date for UTC+0. This is a HUGE gotcha, because developers not familiar with what WP is doing here will think it is returning an actual unixtimestamp, its not.

You CAN get the actual unixtimestamp by doing current_time( 'timestamp', true ).

5. Localization.

WordPress has a neat system in place for localizing Date and time display via the functiondate_i18n(). The way it works is you send it a format you want the result in a “unixtimestamp”, and whether it should be in GMT (UTC+0) or not, then it spits out that format localized in the set language for the site.

Here’s the gotcha, when you send it a “unixtimestamp” (regardless of what you set the gmt flag to), WordPress considers that unixtimestamp to be their specially computed timestamp with the offset applied NOT an actual unixtimestamp. The GMT flag just indicates whether you want the returned string to be converted to GMT before returning. However, if you send in an actual unixtimestamp, then that will get “converted” to GMT and thus will be returned with what appears to be a double offset from the actual time in the set timezone for the current site.

6. Summary

There’s more, but the reason I wanted to very briefly go over how Dates and Times work in WordPress is to illustrate that as long as you operate on the assumptions WordPress makes, and are aware of how things work internally, everything works out great.

However, the way WordPress does things, conflicts with the needs of EE.

The Initial Implementation of the Datetime System

Keep in mind, in the initial implementation of the datetime system, we still supported PHP5.2 . This meant a lot of useful php date functions that would have made our lives easier at that time were not available to us because they required PHP5.3.  In the early development of EE4, we did not think that was a big deal and we thought we’d be able to work around most deficiencies with PHP5.2.

1. In effort to keep it simple.

Users:

  • Allow them to use a familiar interface for setting how their dates and times display (the WordPress general settings) and the timezone for how everything displays. So really for users with existing sites this would “just work”.

Developers:

  • EE_Datetime_Field handles the complex conversions necessary to make sure data gets to and from the database as expected. Throw any format at it for incoming dates and it should “just work”.

The problems

  • we discovered that we couldn’t just let people set the format to whatever they wanted (even one of the suggested default formats d/m/Y  provided by WordPress), because for our internal conversions, we had to use strtotime(), and strtotime() has a limited number of formats it can convert correctly. So as a “fix” we didn’t allow people to set their date/time formats to something that EE could not convert.
  • the ticking BOMB with this, is that our “preventative” measures does not catch users who install EE on a pre-existing WordPress site that is using one of those formats. They may have had their site up for a while using one of those formats with no problems and all of a sudden they install EE and it doesn’t work correctly. The user could file an issue about this our response to them would be, “Sorry, you can’t use that format”.
  • we also discovered that WordPress allows users to set their sites to a UTC offset that PHP doesn’t recognize as valid. Our workaround was to behind the scenes set that offset to the closest valid one and use it instead (this doesn’t change even with the refactor).

2. Keep things Clear and Consistent

Users:

  • for the most part, the format for all our date-pickers in the backend was fairly consistent (although users are not able to change that format).
  • For the most part anywhere dates and times were just displayed (and not interacted with), they followed the format that was set by them in their WordPress settings, and in the timezone they expected.

Developers:

  • For the most part, what was made accessible to developers was useful. They had a clear set of methods to get dates and times from the database, and a clear set of methods to send dates and time into the database.
  • Clear zones describing how dates and times “live” in those zones.
    • DB – mysql timestamp UTC+0
    • Models – unixtimestamp (no offset applied).
    • Client Code – whatever WordPress was set at.

the problems

  • localization? What localization? In the initial iteration of the datetime system I completely forgot about setting things up so dates and times would be localized when displayed.
  • As fixes were implemented to make localization possible, all the gotchas I mentioned above regarding how WordPress does “unixtimestamp” came into play.
  • Date calculations by client code were not easy to do and a lot of conversions became necessary to accommodate the flexibility we wanted to retain.
  • EE_Datetime_Field had a TON of code handling conversions to cover different scenarios that would get thrown at it and to account for the deficiencies with PHP5.2. Flaws in these conversions were found and bandaid fixes applied. There started to be a multitude of different functions and methods for developers to use as a result of fixing some of these deficiencies. It became ambigous to the user not familiar with the system how queries should be setup in the different zones for datetime related items… should I use current_time('timestamp', true)? Should I use current_time('timestamp')? Should I use date('Y-m-d H:i:s', strtotime( $date_string ) )? Will this query still work when we build a feature for people to change the timezone for how things are displayed? Or when they can have events saved in multiple timezones?
  • things have become increasingly unclear and inconsistent.

3. Flexibility

Users

  • Set a format, and it works. (well actually, only certain formats work…)
  • Can I change how the datepicker’s display time and dates? No ( see this feature request in our support forums )

Developers

  • Still some flexibility if you are willing to ignore using our system and just build your own tools for interacting with dates and times (which also applies to any add-ons we build that use dates and times)
  • Be very careful what you send via queries otherwise you will get unintended results.

Enter the Refactor

Over time we realized, that there were a number of problems with the current date time system that were increasingly creating headaches in terms of unintended bugs and in the long run not supporting our goals for this critical system.

Keep in mind that while we wanted to try to preserve backward compatibility as much as possible with existing code that might be in the wild, we realized that to ‘do things properly’ would require some breakage.  However, we were able to keep the breakage limited to the querying and display of date and time information in cases where old code is not updated to use the new paradigms of the refactored date time system.

High Level overview of changes

1. Dates continue to be saved as mysql timestamps ( Y-m-d H:i:s ) in the database in UTC +0.

This is something that has not changed from the original system.  This is why there is no data destruction with this update.

2. Dates live within the models and model objects as PHP DateTime objects.

When dates are retrieved from the database they are stored as PHP DateTime objects in the timezone set internally on the EE_Base_Class object for the values of EE_Datetime_Fields.  This allows for less conversion related code.

3.  Any unix timestamps coming into EE_Datetime_Field::prepare_for_set() methods are considered to have no offset on them.

This is a big change from the previous system.  In the previous system incoming unixtimestamps were considered to have an offset already applied to them via current_time().  We felt that it was much clearer to treat unixtimestamps as actual timestamps.

4. Formats are now required for when instantiating EE_Base_Class objects with date time strings that are not a unixtimestamp.

The method signature for EE_Base_Class::new_instance() has changed so it now not only allows for passing the properties and their values as an array, the timezone string for any dates and times included in the first argument, but also now a third argument for date formats.

The date formats argument is expected to be an array where the first value is the date format and the second value is the time format.

The reason for this change is so that developers now can use any date and time strings they want in instantiating a EE_Base_Class that has date string values. However, to make sure there is no ambiguity regarding the format sent in ( d/m/Y vs m/d/Y for example ), the format is sent in.

If developers don’t want to be bothered with a format, you can instantiate just using a unixtimestamp (with no offset applied) and EE will convert it to the appropriate DateTime object internally. However if you do not send in a unixtimestamp you must send in the formats to ensure the date string is converted properly internally.

5. New helpers are available for setting up strings for date related queries.

We’ve added some helpers accessible to EEM_Base child classes that make it easier to setup queries using the EE Models system involving date and time strings.

6. New EE_Base_Class helper for displaying localized date.

EE_Base_Class::get_i18n_datetime( $field, $format ) is available for easily retrieving the localized date.

7. Extensive unit test coverage

We have covered the new system fairly extensively with unit tests to ensure that any future modifications do not break functionality.

Basic Examples

More extensive examples/documentation of usage will be provided in the code documentation on this site (and will be linked to from this post as it becomes available).

Example EE_Datetime instantiation:

Example model query helper method usages:



PHP Coding Standards

[notification type=”alert-warning” close=”false” ]Keep in mind that we are fully aware there is still code in Event Espresso 4 that does not conform to these standards.  They are a target for improvement over time![/notification]

[notification type=”alert-info” close=”false” ]Generally speaking, our php coding standards closely mirror the WordPress PHP Coding Standards.  We won’t repeat all those here but emphasis, modifications, and additions are listed below.[/notification]

General Code Guidelines

Yoda Conditionals.

See the WordPress handbook for an example and info on what this is.  We have decided to not adopt the use of yoda conditionals in our code.

DRY (Don’t Repeat Yourself)

Most developers will be familiar with this principle.  If you find yourself writing code repeatedly consider whether its something that can be abstracted for reusability.

Consider the following bad example.

Notice how these two methods increment_foo() and increment_bar() are basically doing the same thing – take an incoming variable and increment it by one.  The DRY way to do this is simply:

Now this is probably an overtly obvious example of the DRY principle but it does illustrate what we mean.  The less code you write the less there is to maintain.  In this example we have one function that does incrementation and thus we only have to maintain that one function going forward.  DRY also leads to more bug free code, however when there are bugs, they are generally easier to fix because instead of fixing a bug in multiple places, you are more likely to only need to fix in one.  (more reading on DRY here)

Favor OOP over procedural

One of the major decisions made early in the development of Event Espresso 4, was to use general OOP (Object Oriented Programming) principles in the refactor.   What this means is that when designing and implementing systems, we favoured  using classes and objects over global scope functions and global variables.   This allows for clear separation of concerns and more testable and reusable code.

Naming Conventions

Function Naming

Any functions not found in a class should be prefixed with espresso_.  An example of this in use is the espresso_version() function.

Class Naming

All classes for Event Espresso should be prefixed with EE_.  An example of this in use is the EE_Base_Class.  Note, there are some other important naming schemas related to classes:

Type of ClassNaming SchemaDescriptionExample
RegularEE_{class_name}This is a class that is not a part of any system or library OR a core class. EE_Registry
DB ModelEEM_{class_name}These are part of the EE model systemEEM_Event
DB Model ObjectEE_{class_name}These are part of the EE Model system. You can differentiate these from Regular classes in that Model Objects always extend the `EE_Base_Class`EE_Event
HelperEEH_{class_name}Helper Classes. These classes usually contain static methods and are typically used for "helper" type methods.EEH_Template
Admin{class_name}_Admin_Page
{class_name}_Admin_Page_Init
These classes are a part of the EE Admin systemEvent_Admin_Page
Event_Admin_Page_Init
CPT StrategyEE_CPT_{class_name}_StrategyAny class related to CPT's and Custom TaxonomiesEE_CPT_Event_Strategy
Data MigrationEE_DMS_{version_migration}Classes used for Data MigrationEE_DMS_4_1_0
Messages Data HandlerEE_Messages_{data_source}_incoming_dataThese are the data handler classes for the Messages system.EE_Messages_Gateways_incoming_data
Messages Template DefaultsEE_Messages_{messenger}_{message_type}_DefaultsTheses classes define the defaults for the message templatesEE_Messages_Email_Cancelled_Registration_Defaults
Messages Message TypeEE_{message_type}_message_typeThese classes represent message types.EE_Cancelled_Registration_message_type
Messages MessengerEE_{messenger}_messengerThese classes represent a messages system messengerEE_Email_messenger
Messages ValidatorsEE_Messages_{messenger}_{message_type}_ValidatorThese classes represent the messages system validators (validate fields and shortcodes in templates)EE_Email_Cancelled_Registration_Validator
ModulesEED_{Module_Name}These classes are part of the EE Module systemEED_Event_Single
General ShortcodesEES_{Shortcode_Name}These classes define and handle the various EE shortcodes.EES_Espresso_Cancelled
WidgetsEEW_{Widget_Name}These classes define and implement various EE Widgets for the WordPress widget system.EEW_Upcoming_Events

Class Property Method and Property Schema

All private or protected properties or methods are prefixed with an underscore.  Example Property: $this->_property.  Example method: function _method().

All public properties or methods are not prefixed with an underscore.  Example property: $this->property.  Example method: function method() {}.

File Naming Schema

File TypeSchemaDescriptionExample
Regular.phpAs with normal php rules. All php files end with the `.php` extensionespresso.php
Core.core.phpCore classes (usually parent or "main" classes)EE_Error.core.php
Template.template.phpAny template related code goes into a file with this extensionwhats_new.template.php
Help Tabs.help_tab.phpFiles containing classes for the EE Help Tab system.event_editor.help_tab.php
Non Specified Class.class.phpAnything with a "class" extension contains a class (or classes).Events_Admin_List_Table.class.php
Library.lib.phpUses for classes that are a part of a library.EE_Event_Editor_Decaf_Tips.lib.php
Migration Scripts.dms.phpContains a data migration script class.EE_DMS_4_1_0.dms.php
Model.model.phpContains a model class.EEM_Answer.model.php
Helper.helper.phpContains a helper class.EEH_DTT_Helper.helper.php
Modele.module.phpContains a module class.EED_Event_Single.module.php
Shortcodes.shortcode.phpContains a EE Shortcode classEES_Espresso_Cancelled.shortcode.php
Widgets.widget.phpContains a Widget ClassEEW_Upcoming_Events.widget.php

White Space

Indentation

Your indentation should always reflect logical structure. Use real tabs (1 tab = 4 spaces) and not spaces, as this allows the most flexibility across clients.

Remove Trailing Spaces

[notification type=”alert-danger” close=”false” ]Make sure you remove trailing whitespace after closing PHP tags.[/notification]

Also remove trailing spaces at the end of each line of code.

Space between functions/methods

For readability, put 5 lines of white space between functions/methods.

Inline Spaces

Always put spaces after commas and on both sides of logical and assignment operators.

Put spaces on both sides of the opening and closing parenthesis of if, else if, foreach, for, and switch blocks:

foreach ( $foo as $bar ) { ...

When defining a function, do it like so:

function myfunction( $param1, $param2 = 'bar'  ) { ... }

When calling a function, do it like so:

myfunction( $param1, funcparam( $param2 ) );

When performing logical comparisons:

if ( ! $foo ) { ... }

When type casting:

foreach ( (array) $foo as $bar { ... }

PHP In Templates

In general, try to restrict usage of PHP code in templates to only using: if, else, foreach, echo.  Generally there should be no assigning of variables (except maybe an iteration counter).  There should definitely be no SQL queries, requires, or definition of any functions.  Also, define all the variables in the template requires at the beginning of the file and briefly explain what they are expected to contain.

 Database Queries

In Event Espresso 4 we spent a significant amount of time planning and building a model system for all db interactions.  The intent is that only the EEM_ model singletons are used to interact with the database.  If a query you want doesn’t exist, then generally, it should be added to the appropriate model (or improvement to the model to support that query).