<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[6599] sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins: WordCamp Helpers: Break `wordcamp` post type helpers into separate file.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="http://meta.trac.wordpress.org/changeset/6599">6599</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"http://meta.trac.wordpress.org/changeset/6599","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>iandunn</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2018-02-12 17:35:19 +0000 (Mon, 12 Feb 2018)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>WordCamp Helpers: Break `wordcamp` post type helpers into separate file.</pre>

<h3>Added Paths</h3>
<ul>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentmupluginshelpersmiscphp">sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/helpers-misc.php</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentmupluginshelperswcptphp">sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/helpers-wcpt.php</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentmupluginshelperfunctionsphp">sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/helper-functions.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentmupluginshelperfunctionsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/helper-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/helper-functions.php   2018-02-12 17:35:15 UTC (rev 6598)
+++ sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/helper-functions.php     2018-02-12 17:35:19 UTC (rev 6599)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,316 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-
-use WordCamp\Logger;
-
-/**
- * Retrieves the `wordcamp` post and postmeta associated with the current site.
- *
- * `Site ID` is the most reliable way to associate a site with it's corresponding `wordcamp` post,
- * but wasn't historically assigned when new sites are created. For older sites, we fallback to
- * using the `URL` to associate them. That will only work if the site's site_url() exactly
- * matches the `wordcamp` post's `URL` meta field, though. It could also fail if we ever migrate
- * to a different URL structure.
- *
- * @return false|WP_Post
- */
-function get_wordcamp_post() {
-       $current_site_id  = get_current_blog_id();
-       $current_site_url = site_url();
-
-       switch_to_blog( BLOG_ID_CURRENT_SITE ); // central.wordcamp.org
-
-       $wordcamp = get_posts( array(
-               'post_type'   => 'wordcamp',
-               'post_status' => 'any',
-
-               'meta_query' => array(
-                       'relation'  => 'OR',
-
-                       array(
-                               'key'   => '_site_id',
-                               'value' => $current_site_id,
-                       ),
-
-                       array(
-                               'key'   => 'URL',
-                               'value' => $current_site_url,
-                       ),
-               ),
-       ) );
-
-       if ( isset( $wordcamp[0]->ID ) ) {
-               $wordcamp = $wordcamp[0];
-               $wordcamp->meta = get_post_custom( $wordcamp->ID );
-       } else {
-               $wordcamp = false;
-       }
-
-       restore_current_blog();
-
-       return $wordcamp;
-}
-
-/**
- * Find the site that corresponds to the given `wordcamp` post
- *
- * @param WP_Post $wordcamp_post
- *
- * @return mixed An integer if successful, or boolean false if failed
- */
-function get_wordcamp_site_id( $wordcamp_post ) {
-       switch_to_blog( BLOG_ID_CURRENT_SITE ); // central.wordcamp.org
-
-       if ( ! $site_id = get_post_meta( $wordcamp_post->ID, '_site_id', true ) ) {
-               $url = parse_url( get_post_meta( $wordcamp_post->ID, 'URL', true ) );
-
-               if ( isset( $url['host'] ) && isset( $url['path'] ) ) {
-                       if ( $site = get_site_by_path( $url['host'], $url['path'] ) ) {
-                               $site_id = $site->blog_id;
-                       }
-               }
-       }
-
-       restore_current_blog();
-
-       return $site_id;
-}
-
-/**
- * Get a consistent WordCamp name in the 'WordCamp [Location] [Year]' format.
- *
- * The results of bloginfo( 'name' ) don't always contain the year, but the title of the site's corresponding
- * `wordcamp` post is usually named 'WordCamp [Location]', so we can get a consistent name most of the time
- * by using that and adding the year (if available).
- *
- * @param int $site_id Optionally, get the name for a site other than the current one.
- *
- * @return string
- */
-function get_wordcamp_name( $site_id = 0 ) {
-       $name = false;
-
-       switch_to_blog( $site_id );
-
-       if ( $wordcamp = get_wordcamp_post() ) {
-               if ( ! empty( $wordcamp->meta['Start Date (YYYY-mm-dd)'][0] ) ) {
-                       $name = $wordcamp->post_title .' '. date( 'Y', $wordcamp->meta['Start Date (YYYY-mm-dd)'][0] );
-               }
-       }
-
-       if ( ! $name ) {
-               $name = get_bloginfo( 'name' );
-       }
-
-       restore_current_blog();
-
-       return $name;
-}
-
-/**
- * Determine if a specific feature should be skipped on the current site
- *
- * Often times we want to add new functionality to plugins and themes, but can't let it run on older sites
- * because that would break backwards compatibility. To get around that, we set a flag on older sites to
- * indicate that they should not have the new feature, and then setup the feature to run on sites that
- * don't have the flag, i.e., to run by default.
- *
- * Doing it this way means that local development environments like the Meta Environment don't to have add any
- * new filters in order to start using the new functionality.
- *
- * See WordCamp_CLI_Miscellaneous::set_skip_feature_flag() for how to set the flags.
- *
- * @param string $flag
- *
- * @return bool
- */
-function wcorg_skip_feature( $flag ) {
-       $flags = get_option( 'wordcamp_skip_features', array() );
-
-       return isset( $flags[ $flag ] );
-}
-
-/**
- * Get a user by the username or nicename
- *
- * Note: This intentionally doesn't lookup users by the display name or nickname, because those can be set by the
- * user, which could result in false-positive matches.
- *
- * @param string $name
- *
- * @return false|WP_User
- */
-function wcorg_get_user_by_canonical_names( $name ) {
-       if ( ! $user = get_user_by( 'login', $name ) ) {    // user_login
-               $user = get_user_by( 'slug', $name );           // user_nicename
-       }
-
-       return $user;
-}
-
-/**
- * Extract pieces from a WordCamp.org URL
- *
- * @todo find other code that's doing this same task in an ad-hoc manner, and convert it to use this instead
- *
- * @param string $url
- * @param string $part 'city', 'city-domain' (without the year, e.g. seattle.wordcamp.org), 'year'
- *
- * @return false|string|int False on errors; an integer for years; a string for city and city-domain
- */
-function wcorg_get_url_part( $url, $part ) {
-       $url_parts = explode( '.', parse_url( $url, PHP_URL_HOST ) );
-       $result    = false;
-
-       // Make sure it matches the typical year.city.wordcamp.org structure
-       if ( 4 !== count( $url_parts ) ) {
-               return $result;
-       }
-
-       switch( $part ) {
-               case 'city':
-                       $result = $url_parts[1];
-                       break;
-
-               case 'city-domain':
-                       $result = ltrim( strstr( $url, '.' ), '.' );
-                       break;
-
-               case 'year':
-                       $result = absint( $url_parts[0] );
-                       break;
-       }
-
-       return $result;
-}
-
-/**
- * Get ISO-3166 country names and codes
- *
- * @todo move the real functionality from get_valid_countries_iso3166() to here, then have the Budgets plugin,
- * QBO, etc call this.
- *
- * @return array
- */
-function wcorg_get_countries() {
-       require_once( WP_PLUGIN_DIR . '/wordcamp-payments/includes/wordcamp-budgets.php' );
-
-       return WordCamp_Budgets::get_valid_countries_iso3166();
-}
-
-/**
- * Make a remote HTTP request, and retry if it fails
- *
- * Sometimes the HTTP request times out, or there's a temporary server-side error, etc. Some use cases require a
- * successful request, like stats scripts, where the resulting data would be distorted by a failed response.
- *
- * @todo Add support for wp_remote_post() too
- * @todo Remove this if https://github.com/rmccue/Requests/issues/222 is implemented
- * @todo maybe `set_time_limit( absint( ini_get( 'max_execution_time' ) ) + $retry_after );` before sleep()'ing to
- *       avoid php timeout
- *
- * @param string $request_url
- * @param array  $request_args
- *
- * @return array|WP_Error
- */
-function wcorg_redundant_remote_get( $request_url, $request_args = array() ) {
-       $attempt_count = 1;
-
-       while ( true ) {
-               $response    = wp_remote_get( $request_url, $request_args );
-               $status_code = wp_remote_retrieve_response_code( $response );
-               $body        = wp_remote_retrieve_body( $response );
-               $retry_after = wp_remote_retrieve_header( $response, 'retry-after' ) ?: 5;
-               $retry_after = min( $retry_after * $attempt_count, 30 );
-
-               if ( ! is_wp_error( $response ) && 200 === $status_code && $body ) {
-                       break;
-               }
-
-               if ( $attempt_count < 3 ) {
-                       Logger\log( 'request_failed_temporarily', compact( 'request_url', 'request_args', 'response', 'attempt_count', 'retry_after' ) );
-                       sleep( $retry_after );
-               } else {
-                       Logger\log( 'request_failed_permenantly', compact( 'request_url', 'request_args', 'response' ) );
-                       break;
-               }
-
-               $attempt_count++;
-       }
-
-       return $response;
-}
-
-/**
- * Take the start and end dates for a WordCamp and calculate how many days it lasts.
- *
- * @param WP_Post $wordcamp
- *
- * @return int
- */
-function wcord_get_wordcamp_duration( WP_Post $wordcamp ) {
-       // @todo Make sure $wordcamp is the correct post type
-
-       $start = get_post_meta( $wordcamp->ID, 'Start Date (YYYY-mm-dd)', true );
-       $end   = get_post_meta( $wordcamp->ID, 'End Date (YYYY-mm-dd)', true );
-
-       // Assume 1 day duration if there is no end date
-       if ( ! $end ) {
-               return 1;
-       }
-
-       $duration_raw = $end - $start;
-
-       // Add one second and round up to ensure the end date counts as a day as well
-       $duration_days = ceil( ( $duration_raw + 1 ) / DAY_IN_SECONDS );
-
-       return absint( $duration_days );
-}
-
-/**
- * Register post meta so that it only appears on a specific REST API endpoint
- *
- * As of WordPress 4.7, there's no way to register a meta field for a specific post type. Registering a
- * field registers it for all post types, and registering it with `show_in_rest => true` exposes it in all
- * API endpoints. Doing that could lead to unintentional privacy leaks. There's no officially-supported
- * way to avoid that, other than using `register_rest_field()`.
- *
- * See https://core.trac.wordpress.org/ticket/38323
- *
- * `register_rest_field()` isn't an ideal solution for post meta, though, because it's logically
- * inconsistent; i.e., meta fields would not show up in the `meta` tree of the response, where other meta
- * fields are located, and where a client would expect to find them. Instead, meta fields would show up as
- * top-level fields in the response, as if they were first-class `post` object fields, or as if they were
- * arbitrary fields (which is what `register_rest_field()` is really intended for).
- *
- * Having meta fields at the top-level also clutters the post item, making it harder to read, and annoying
- * the crap out of grumpy, old, anal-retentive developers like @iandunn.
- *
- * So, in order to safely add meta fields in the `meta` tree where they belong, but without exposing them
- * on endpoints where they don't belong, an ugly workaround is used. `register_meta()` is only called
- * for `wcb_session` meta fields during API requests for the `sessions` endpoint. During all other API
- * and non-API requests, it is not called.
- *
- * This only works if you don't need the meta registered in non-API contexts, but that's usually true.
- *
- * @todo Once #38323 is resolved, this can be removed and the calling functions can be updated to use
- *       whatever the officially supported solution turns out to be.
- *
- * @param string $meta_type   Type of object this meta is registered to. 'post', 'user', 'term', etc
- * @param array  $meta_fields An array index by the field slug, with values to be passed to `register_meta()` as
- *                            `$args`. For example, `array( '_wcpt_session_slides' => array( 'single' => true ) )`
- * @param string $endpoint    The partial path of the endpoint. For example, '/wp-json/wp/v2/sessions'.
- */
-function wcorg_register_meta_only_on_endpoint( $meta_type, $meta_fields, $endpoint ) {
-       $is_correct_endpoint_request = false !== strpos( $_SERVER['REQUEST_URI'], untrailingslashit( $endpoint ) );
-
-       if ( ! $is_correct_endpoint_request ) {
-               return;
-       }
-
-       foreach ( $meta_fields as $field_key => $arguments ) {
-               $arguments = array_merge( $arguments, array( 'show_in_rest' => true ) );
-
-               register_meta( $meta_type, $field_key, $arguments );
-       }
-}
</del></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentmupluginshelpersmiscphpfromrev6598sitestrunkwordcamporgpublic_htmlwpcontentmupluginshelperfunctionsphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/helpers-misc.php (from rev 6598, sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/helper-functions.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/helpers-misc.php                               (rev 0)
+++ sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/helpers-misc.php 2018-02-12 17:35:19 UTC (rev 6599)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,156 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+defined( 'WPINC' ) or die();
+use WordCamp\Logger;
+
+/*
+ * Miscellaneous helper functions.
+ */
+
+
+/**
+ * Determine if a specific feature should be skipped on the current site
+ *
+ * Often times we want to add new functionality to plugins and themes, but can't let it run on older sites
+ * because that would break backwards compatibility. To get around that, we set a flag on older sites to
+ * indicate that they should not have the new feature, and then setup the feature to run on sites that
+ * don't have the flag, i.e., to run by default.
+ *
+ * Doing it this way means that local development environments like the Meta Environment don't to have add any
+ * new filters in order to start using the new functionality.
+ *
+ * See WordCamp_CLI_Miscellaneous::set_skip_feature_flag() for how to set the flags.
+ *
+ * @param string $flag
+ *
+ * @return bool
+ */
+function wcorg_skip_feature( $flag ) {
+       $flags = get_option( 'wordcamp_skip_features', array() );
+
+       return isset( $flags[ $flag ] );
+}
+
+/**
+ * Get a user by the username or nicename
+ *
+ * Note: This intentionally doesn't lookup users by the display name or nickname, because those can be set by the
+ * user, which could result in false-positive matches.
+ *
+ * @param string $name
+ *
+ * @return false|WP_User
+ */
+function wcorg_get_user_by_canonical_names( $name ) {
+       if ( ! $user = get_user_by( 'login', $name ) ) {    // user_login
+               $user = get_user_by( 'slug', $name );           // user_nicename
+       }
+
+       return $user;
+}
+
+/**
+ * Get ISO-3166 country names and codes
+ *
+ * @todo move the real functionality from get_valid_countries_iso3166() to here, then have the Budgets plugin,
+ * QBO, etc call this.
+ *
+ * @return array
+ */
+function wcorg_get_countries() {
+       require_once( WP_PLUGIN_DIR . '/wordcamp-payments/includes/wordcamp-budgets.php' );
+
+       return WordCamp_Budgets::get_valid_countries_iso3166();
+}
+
+/**
+ * Make a remote HTTP request, and retry if it fails
+ *
+ * Sometimes the HTTP request times out, or there's a temporary server-side error, etc. Some use cases require a
+ * successful request, like stats scripts, where the resulting data would be distorted by a failed response.
+ *
+ * @todo Add support for wp_remote_post() too
+ * @todo Remove this if https://github.com/rmccue/Requests/issues/222 is implemented
+ * @todo maybe `set_time_limit( absint( ini_get( 'max_execution_time' ) ) + $retry_after );` before sleep()'ing to
+ *       avoid php timeout
+ *
+ * @param string $request_url
+ * @param array  $request_args
+ *
+ * @return array|WP_Error
+ */
+function wcorg_redundant_remote_get( $request_url, $request_args = array() ) {
+       $attempt_count = 1;
+
+       while ( true ) {
+               $response    = wp_remote_get( $request_url, $request_args );
+               $status_code = wp_remote_retrieve_response_code( $response );
+               $body        = wp_remote_retrieve_body( $response );
+               $retry_after = wp_remote_retrieve_header( $response, 'retry-after' ) ?: 5;
+               $retry_after = min( $retry_after * $attempt_count, 30 );
+
+               if ( ! is_wp_error( $response ) && 200 === $status_code && $body ) {
+                       break;
+               }
+
+               if ( $attempt_count < 3 ) {
+                       Logger\log( 'request_failed_temporarily', compact( 'request_url', 'request_args', 'response', 'attempt_count', 'retry_after' ) );
+                       sleep( $retry_after );
+               } else {
+                       Logger\log( 'request_failed_permenantly', compact( 'request_url', 'request_args', 'response' ) );
+                       break;
+               }
+
+               $attempt_count++;
+       }
+
+       return $response;
+}
+
+/**
+ * Register post meta so that it only appears on a specific REST API endpoint
+ *
+ * As of WordPress 4.7, there's no way to register a meta field for a specific post type. Registering a
+ * field registers it for all post types, and registering it with `show_in_rest => true` exposes it in all
+ * API endpoints. Doing that could lead to unintentional privacy leaks. There's no officially-supported
+ * way to avoid that, other than using `register_rest_field()`.
+ *
+ * See https://core.trac.wordpress.org/ticket/38323
+ *
+ * `register_rest_field()` isn't an ideal solution for post meta, though, because it's logically
+ * inconsistent; i.e., meta fields would not show up in the `meta` tree of the response, where other meta
+ * fields are located, and where a client would expect to find them. Instead, meta fields would show up as
+ * top-level fields in the response, as if they were first-class `post` object fields, or as if they were
+ * arbitrary fields (which is what `register_rest_field()` is really intended for).
+ *
+ * Having meta fields at the top-level also clutters the post item, making it harder to read, and annoying
+ * the crap out of grumpy, old, anal-retentive developers like @iandunn.
+ *
+ * So, in order to safely add meta fields in the `meta` tree where they belong, but without exposing them
+ * on endpoints where they don't belong, an ugly workaround is used. `register_meta()` is only called
+ * for `wcb_session` meta fields during API requests for the `sessions` endpoint. During all other API
+ * and non-API requests, it is not called.
+ *
+ * This only works if you don't need the meta registered in non-API contexts, but that's usually true.
+ *
+ * @todo Once #38323 is resolved, this can be removed and the calling functions can be updated to use
+ *       whatever the officially supported solution turns out to be.
+ *
+ * @param string $meta_type   Type of object this meta is registered to. 'post', 'user', 'term', etc
+ * @param array  $meta_fields An array index by the field slug, with values to be passed to `register_meta()` as
+ *                            `$args`. For example, `array( '_wcpt_session_slides' => array( 'single' => true ) )`
+ * @param string $endpoint    The partial path of the endpoint. For example, '/wp-json/wp/v2/sessions'.
+ */
+function wcorg_register_meta_only_on_endpoint( $meta_type, $meta_fields, $endpoint ) {
+       $is_correct_endpoint_request = false !== strpos( $_SERVER['REQUEST_URI'], untrailingslashit( $endpoint ) );
+
+       if ( ! $is_correct_endpoint_request ) {
+               return;
+       }
+
+       foreach ( $meta_fields as $field_key => $arguments ) {
+               $arguments = array_merge( $arguments, array( 'show_in_rest' => true ) );
+
+               register_meta( $meta_type, $field_key, $arguments );
+       }
+}
</ins></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentmupluginshelperswcptphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/helpers-wcpt.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/helpers-wcpt.php                               (rev 0)
+++ sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/helpers-wcpt.php 2018-02-12 17:35:19 UTC (rev 6599)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,176 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+defined( 'WPINC' ) or die();
+
+/*
+ * Helper functions related to the `wordcamp` post type.
+ */
+
+
+/**
+ * Retrieves the `wordcamp` post and postmeta associated with the current site.
+ *
+ * `Site ID` is the most reliable way to associate a site with it's corresponding `wordcamp` post,
+ * but wasn't historically assigned when new sites are created. For older sites, we fallback to
+ * using the `URL` to associate them. That will only work if the site's site_url() exactly
+ * matches the `wordcamp` post's `URL` meta field, though. It could also fail if we ever migrate
+ * to a different URL structure.
+ *
+ * @return false|WP_Post
+ */
+function get_wordcamp_post() {
+       $current_site_id  = get_current_blog_id();
+       $current_site_url = site_url();
+
+       switch_to_blog( BLOG_ID_CURRENT_SITE ); // central.wordcamp.org
+
+       $wordcamp = get_posts( array(
+               'post_type'   => 'wordcamp',
+               'post_status' => 'any',
+
+               'meta_query' => array(
+                       'relation' => 'OR',
+
+                       array(
+                               'key'   => '_site_id',
+                               'value' => $current_site_id,
+                       ),
+
+                       array(
+                               'key'   => 'URL',
+                               'value' => $current_site_url,
+                       ),
+               ),
+       ) );
+
+       if ( isset( $wordcamp[0]->ID ) ) {
+               $wordcamp       = $wordcamp[0];
+               $wordcamp->meta = get_post_custom( $wordcamp->ID );
+       } else {
+               $wordcamp = false;
+       }
+
+       restore_current_blog();
+
+       return $wordcamp;
+}
+
+/**
+ * Find the site that corresponds to the given `wordcamp` post
+ *
+ * @param WP_Post $wordcamp_post
+ *
+ * @return mixed An integer if successful, or boolean false if failed
+ */
+function get_wordcamp_site_id( $wordcamp_post ) {
+       switch_to_blog( BLOG_ID_CURRENT_SITE ); // central.wordcamp.org
+
+       if ( ! $site_id = get_post_meta( $wordcamp_post->ID, '_site_id', true ) ) {
+               $url = parse_url( get_post_meta( $wordcamp_post->ID, 'URL', true ) );
+
+               if ( isset( $url['host'] ) && isset( $url['path'] ) ) {
+                       if ( $site = get_site_by_path( $url['host'], $url['path'] ) ) {
+                               $site_id = $site->blog_id;
+                       }
+               }
+       }
+
+       restore_current_blog();
+
+       return $site_id;
+}
+
+/**
+ * Get a consistent WordCamp name in the 'WordCamp [Location] [Year]' format.
+ *
+ * The results of bloginfo( 'name' ) don't always contain the year, but the title of the site's corresponding
+ * `wordcamp` post is usually named 'WordCamp [Location]', so we can get a consistent name most of the time
+ * by using that and adding the year (if available).
+ *
+ * @param int $site_id Optionally, get the name for a site other than the current one.
+ *
+ * @return string
+ */
+function get_wordcamp_name( $site_id = 0 ) {
+       $name = false;
+
+       switch_to_blog( $site_id );
+
+       if ( $wordcamp = get_wordcamp_post() ) {
+               if ( ! empty( $wordcamp->meta['Start Date (YYYY-mm-dd)'][0] ) ) {
+                       $name = $wordcamp->post_title . ' ' . date( 'Y', $wordcamp->meta['Start Date (YYYY-mm-dd)'][0] );
+               }
+       }
+
+       if ( ! $name ) {
+               $name = get_bloginfo( 'name' );
+       }
+
+       restore_current_blog();
+
+       return $name;
+}
+
+
+/**
+ * Extract pieces from a WordCamp.org URL
+ *
+ * @todo find other code that's doing this same task in an ad-hoc manner, and convert it to use this instead
+ *
+ * @param string $url
+ * @param string $part 'city', 'city-domain' (without the year, e.g. seattle.wordcamp.org), 'year'
+ *
+ * @return false|string|int False on errors; an integer for years; a string for city and city-domain
+ */
+function wcorg_get_url_part( $url, $part ) {
+       $url_parts = explode( '.', parse_url( $url, PHP_URL_HOST ) );
+       $result    = false;
+
+       // Make sure it matches the typical year.city.wordcamp.org structure
+       if ( 4 !== count( $url_parts ) ) {
+               return $result;
+       }
+
+       switch ( $part ) {
+               case 'city':
+                       $result = $url_parts[1];
+                       break;
+
+               case 'city-domain':
+                       $result = ltrim( strstr( $url, '.' ), '.' );
+                       break;
+
+               case 'year':
+                       $result = absint( $url_parts[0] );
+                       break;
+       }
+
+       return $result;
+}
+
+
+/**
+ * Take the start and end dates for a WordCamp and calculate how many days it lasts.
+ *
+ * @param WP_Post $wordcamp
+ *
+ * @return int
+ */
+function wcorg_get_wordcamp_duration( WP_Post $wordcamp ) {
+       // @todo Make sure $wordcamp is the correct post type
+
+       $start = get_post_meta( $wordcamp->ID, 'Start Date (YYYY-mm-dd)', true );
+       $end   = get_post_meta( $wordcamp->ID, 'End Date (YYYY-mm-dd)', true );
+
+       // Assume 1 day duration if there is no end date
+       if ( ! $end ) {
+               return 1;
+       }
+
+       $duration_raw = $end - $start;
+
+       // Add one second and round up to ensure the end date counts as a day as well
+       $duration_days = ceil( ( $duration_raw + 1 ) / DAY_IN_SECONDS );
+
+       return absint( $duration_days );
+}
</ins></span></pre>
</div>
</div>

</body>
</html>