diff --git a/README.md b/README.md index 02975fb1c..e74d84f37 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ Contributors: batmoo, danielbachhuber, sbressler, automattic Donate link: http://editflow.org/contribute/ Tags: edit flow, workflow, editorial, newsroom, management, journalism, post status, custom status, notifications, email, comments, editorial comments, usergroups, calendars, editorial calendar, story budget Requires at least: 4.5 -Tested up to: 4.6.1 -Stable tag: 0.8.2 +Tested up to: 4.9.6 +Stable tag: 0.8.3 Redefining your editorial workflow. @@ -56,6 +56,9 @@ For support questions, feedback and ideas, please use the [WordPress.org forums] ## Upgrade Notice +**0.8.3** +Improvements and bugfixes. + **0.8.2** Minor enhancements and bug fixes, translation updates. @@ -80,10 +83,10 @@ Contributors and other users without the 'publish_posts' capability can access c **0.7.1** Enhancements and bug fixes, including defaulting to the proper date in the calendar and an Italian localization. -**0.7** +**0.7** Complete rewrite into a modular architecture. Lots of polish added. Important note: If upgrading from pre-v0.6, please upgrade to v0.6.5 first -**0.6.5** +**0.6.5** Fixes an issue where the post timestamp would be set as soon as a custom status was used. **0.6.4** @@ -103,6 +106,18 @@ New features, including story budget and editorial metadata, a completely rewrit ## Changelog +**0.8.3 (June 14, 2018)** +* UI Improvement: Made primary buttons on Settings screen consistent with WordPress UI. Props [cojennin](https://github.com/cojennin). +* UI Improvement: Display who particularly was notified about an editorial comment. Props [goodguyry](https://github.com/goodguyry), [WPprodigy](https://github.com/WPprodigy) +* Improvement: Updated Russian translation and documentation. Props [achumakov](https://github.com/achumakov). +* Improvement: Eliminate a few cases of raw SQL queries in favor of `date_query`. Props [justnorris](https://github.com/justnorris). +* Improvement: Cache calendar items for each user individually to prevent potential cache pollution. Props [justnorris](https://github.com/justnorris). +* Improvement: various i18n updates. +* Improvement: Move ef_story_budget_posts_query_args filter down to allow overriding the date query in Story Budget module. +* Improvement: Limit results in Calendar to 200 per page, potentially saving from trouble on websites with large amount of content. +* Improvement: Don’t generate rewrite rules for notepad as they're unused. +* Improvement: Support modifying HTML output of a Calendar day via ef_pre_calendar_single_date_item_html filter. Props [cklosowski](https://github.com/cklosowski). + **0.8.2 (Sept. 16, 2016)** * Improvement: Updated Spanish localization thanks to [moucho](https://github.com/moucho) * Improvement: New Swedish localization thanks to [Warpsmith](https://github.com/Warpsmith) @@ -306,13 +321,13 @@ The following folks did some tremendous work helping with the release of Edit Fl * Added option to globally disable QuickPitch widget * Bug fix: Custom Status names cannot be longer than 20 chars * Bug fix: Deleted users are removed as subscribers from posts -* Bug fix: Blank menu items should now be sorta hidden +* Bug fix: Blank menu items should now be sorta hidden **0.2** * Custom Statuses are now supported for pages * Editorial Comments (with threading) * Email Notifications (on post status change and editorial comment) -* Additional Post metadata +* Additional Post metadata * Quick Pitch Dashboard widget * Bug fix: sorting issue on Manage Posts page (Mad props to David Smith from Columbia U.) * Other bug fixes diff --git a/common/php/class-module-with-view.php b/common/php/class-module-with-view.php new file mode 100644 index 000000000..5e14d2a9b --- /dev/null +++ b/common/php/class-module-with-view.php @@ -0,0 +1,181 @@ +modules as $mod_name => $mod_data ) { + if ( isset( $mod_data->options->enabled ) && $mod_data->options->enabled == 'on' && $mod_data->configure_page_cb ) + $settings_view_slugs[] = $mod_data->settings_slug; + } + + // The current page better be in the array of registered settings view slugs + if ( empty( $settings_view_slugs ) || ! in_array( $_GET['page'], $settings_view_slugs ) ) { + return false; + } + + if ( $slug && $edit_flow->modules->{$slug}->settings_slug !== $_GET['page'] ) { + return false; + } + + return true; + } + + /** + * Check whether if we're at module settings view + * for the current module based on `is_module_settings_view` method + * + * @return bool + */ + public function is_current_module_settings_view() { + return $this->is_module_settings_view( $this->module->name ); + } + + + /** + * Check for admin page and whether the current post type is supported + * @param array $allowed_pages + * + * @return bool + */ + function is_active_view( $allowed_pages = array( 'edit.php', 'post.php', 'post-new.php' ) ) { + return ( $this->is_admin_page( $allowed_pages ) && $this->is_supported_post_type() ); + } + + + /** + * Check whether the current post type is supported for $this module + * + * @return bool + */ + public function is_supported_post_type() { + $post_type = $this->get_current_post_type(); + + return ( + $post_type + && + in_array( $post_type, $this->get_post_types_for_module( $this->module ), true ) + ); + } + + /** + * Checks for the current post type + * + * @since 0.7 + * @return string|null $post_type The post type we've found, or null if no post type + */ + function get_current_post_type() { + global $post, $typenow, $pagenow, $current_screen; + //get_post() needs a variable + $post_id = isset( $_REQUEST['post'] ) ? (int) $_REQUEST['post'] : false; + + if ( $post && $post->post_type ) { + $post_type = $post->post_type; + } elseif ( $typenow ) { + $post_type = $typenow; + } elseif ( $current_screen && ! empty( $current_screen->post_type ) ) { + $post_type = $current_screen->post_type; + } elseif ( isset( $_REQUEST['post_type'] ) ) { + $post_type = sanitize_key( $_REQUEST['post_type'] ); + } elseif ( 'post.php' == $pagenow + && $post_id + && ! empty( get_post( $post_id )->post_type ) ) { + $post_type = get_post( $post_id )->post_type; + } elseif ( in_array( $pagenow, array('edit.php', 'post-new.php' ) ) && empty( $_REQUEST['post_type'] ) ) { + $post_type = 'post'; + } else { + $post_type = null; + } + + return $post_type; + } + + /** + * Check whether currently viewing the desired admin page + * + * @param array $allowed_pages + * + * @return bool + */ + public function is_admin_page( $allowed_pages = array( 'edit.php', 'post.php', 'post-new.php' ) ) { + global $pagenow; + + return ( $pagenow && in_array( $pagenow, $allowed_pages, true ) ); + } + + + /** + * Shorthand for `is_active_view` to check for list type views ( list of posts pages, custom post types ) + * + * @see is_active_view + * @return bool + */ + public function is_active_list_view() { + return $this->is_active_view( array( 'edit.php' ) ); + } + + /** + * Shorthand for `is_active_view` to check for editor mode + * + * @see is_active_view + * @return bool + */ + public function is_active_editor_view() { + return $this->is_active_view( array( 'post.php', 'posts-new.php' ) ); + } + + + /** + * This method was supposed to check whether or not the current page is a user-facing Edit Flow View + * But it was never implemented + * + * It is now deprecated in favor of `$this->is_active_view` + * @see EF_Module::is_active_view() + * @since 0.7 + * @deprecated 0.8.3 + * + * @param string $module_name (Optional) Module name to check against + */ + public function is_whitelisted_functional_view( $module_name = null ) { + _deprecated_function( __FUNCTION__, '0.8.3', 'is_active_view' ); + + return true; + } + + /** + * Whether or not the current page is an Edit Flow settings view (either main or module) + * Determination is based on $pagenow, $_GET['page'], and the module's $settings_slug + * If there's no module name specified, it will return true against all Edit Flow settings views + * + * @since 0.7 + * @deprecated 0.8.3 + * + * @param string $module_name (Optional) Module name to check against + * @return bool $is_settings_view Return true if it is + */ + public function is_whitelisted_settings_view( $module_name = null ) { + _deprecated_function( 'is_whitelisted_settings_view', '0.8.3', 'is_module_settings_view' ); + + return $this->is_module_settings_view( $module_name ); + } + +} \ No newline at end of file diff --git a/common/php/class-module.php b/common/php/class-module.php index c19034913..7824f7ff9 100755 --- a/common/php/class-module.php +++ b/common/php/class-module.php @@ -186,42 +186,7 @@ function filter_posts_link( $slug, $post_type = 'post' ) { $filter_link = add_query_arg( 'post_type', $post_type, $filter_link ); return $filter_link; } - - /** - * Returns the friendly name for a given status - * - * @since 0.7 - * - * @param string $status The status slug - * @return string $status_friendly_name The friendly name for the status - */ - function get_post_status_friendly_name( $status ) { - global $edit_flow; - - $status_friendly_name = ''; - - $builtin_stati = array( - 'publish' => __( 'Published', 'edit-flow' ), - 'draft' => __( 'Draft', 'edit-flow' ), - 'future' => __( 'Scheduled', 'edit-flow' ), - 'private' => __( 'Private', 'edit-flow' ), - 'pending' => __( 'Pending Review', 'edit-flow' ), - 'trash' => __( 'Trash', 'edit-flow' ), - ); - - // Custom statuses only handles workflow statuses - if ( $this->module_enabled( 'custom_status' ) - && !in_array( $status, array( 'publish', 'future', 'private', 'trash' ) ) ) { - $status_object = $edit_flow->custom_status->get_custom_status_by( 'slug', $status ); - if( $status_object && !is_wp_error( $status_object ) ) { - $status_friendly_name = $status_object->name; - } - } else if ( array_key_exists( $status, $builtin_stati ) ) { - $status_friendly_name = $builtin_stati[$status]; - } - return $status_friendly_name; - } - + /** * Enqueue any resources (CSS or JS) associated with datepicker functionality * @@ -243,38 +208,7 @@ function enqueue_datepicker_resources() { wp_enqueue_style( 'jquery-ui-theme', EDIT_FLOW_URL . 'common/css/jquery.ui.theme.css', false, EDIT_FLOW_VERSION, 'screen' ); } - /** - * Checks for the current post type - * - * @since 0.7 - * @return string|null $post_type The post type we've found, or null if no post type - */ - function get_current_post_type() { - global $post, $typenow, $pagenow, $current_screen; - //get_post() needs a variable - $post_id = isset( $_REQUEST['post'] ) ? (int)$_REQUEST['post'] : false; - - if ( $post && $post->post_type ) { - $post_type = $post->post_type; - } elseif ( $typenow ) { - $post_type = $typenow; - } elseif ( $current_screen && !empty( $current_screen->post_type ) ) { - $post_type = $current_screen->post_type; - } elseif ( isset( $_REQUEST['post_type'] ) ) { - $post_type = sanitize_key( $_REQUEST['post_type'] ); - } elseif ( 'post.php' == $pagenow - && $post_id - && !empty( get_post( $post_id )->post_type ) ) { - $post_type = get_post( $post_id )->post_type; - } elseif ( 'edit.php' == $pagenow && empty( $_REQUEST['post_type'] ) ) { - $post_type = 'post'; - } else { - $post_type = null; - } - return $post_type; - } - /** * Wrapper for the get_user_meta() function so we can replace it if we need to * @@ -331,55 +265,6 @@ function print_ajax_response( $status, $message = '' ) { exit; } - /** - * Whether or not the current page is a user-facing Edit Flow View - * @todo Think of a creative way to make this work - * - * @since 0.7 - * - * @param string $module_name (Optional) Module name to check against - */ - function is_whitelisted_functional_view( $module_name = null ) { - - // @todo complete this method - - return true; - } - - /** - * Whether or not the current page is an Edit Flow settings view (either main or module) - * Determination is based on $pagenow, $_GET['page'], and the module's $settings_slug - * If there's no module name specified, it will return true against all Edit Flow settings views - * - * @since 0.7 - * - * @param string $module_name (Optional) Module name to check against - * @return bool $is_settings_view Return true if it is - */ - function is_whitelisted_settings_view( $module_name = null ) { - global $pagenow, $edit_flow; - - // All of the settings views are based on admin.php and a $_GET['page'] parameter - if ( $pagenow != 'admin.php' || !isset( $_GET['page'] ) ) - return false; - - // Load all of the modules that have a settings slug/ callback for the settings page - foreach ( $edit_flow->modules as $mod_name => $mod_data ) { - if ( isset( $mod_data->options->enabled ) && $mod_data->options->enabled == 'on' && $mod_data->configure_page_cb ) - $settings_view_slugs[] = $mod_data->settings_slug; - } - - // The current page better be in the array of registered settings view slugs - if ( !in_array( $_GET['page'], $settings_view_slugs ) ) - return false; - - if ( $module_name && $edit_flow->modules->$module_name->settings_slug != $_GET['page'] ) - return false; - - return true; - } - - /** * This is a hack, Hack, HACK!!! * Encode all of the given arguments as a serialized array, and then base64_encode @@ -507,7 +392,11 @@ function users_select_form( $selected = null, $args = null ) { ID, $selected) ) ? 'checked="checked"' : ''; ?>
  • @@ -604,6 +493,7 @@ function upgrade_074_term_descriptions( $taxonomy ) { wp_update_term( $term->term_id, $taxonomy, array( 'description' => $new_description ) ); } } - + + } } diff --git a/edit_flow.php b/edit_flow.php index 57eb5639f..d8ed8c996 100644 --- a/edit_flow.php +++ b/edit_flow.php @@ -4,7 +4,7 @@ Plugin URI: http://editflow.org/ Description: Remixing the WordPress admin for better editorial workflow options. Author: Daniel Bachhuber, Scott Bressler, Mohammad Jangda, Automattic, and others -Version: 0.8.2 +Version: 0.8.3 Author URI: http://editflow.org/ Copyright 2009-2016 Mohammad Jangda, Daniel Bachhuber, et al. @@ -28,7 +28,7 @@ */ // Define contants -define( 'EDIT_FLOW_VERSION' , '0.8.3-alpha' ); +define( 'EDIT_FLOW_VERSION' , '0.8.3' ); define( 'EDIT_FLOW_ROOT' , dirname(__FILE__) ); define( 'EDIT_FLOW_FILE_PATH' , EDIT_FLOW_ROOT . '/' . basename(__FILE__) ); define( 'EDIT_FLOW_URL' , plugins_url( '/', __FILE__ ) ); @@ -93,7 +93,14 @@ private function load_modules() { // Edit Flow base module require_once( EDIT_FLOW_ROOT . '/common/php/class-module.php' ); - + + /* + * Include interfaces: + */ + require_once( EDIT_FLOW_ROOT . '/interfaces/EF_Script_Interface.php' ); + require_once( EDIT_FLOW_ROOT . '/interfaces/EF_Style_Interface.php' ); + require_once( EDIT_FLOW_ROOT . '/common/php/class-module-with-view.php' ); + // Scan the modules directory and include any modules that exist there $module_dirs = scandir( EDIT_FLOW_ROOT . '/modules/' ); $class_names = array(); @@ -128,8 +135,12 @@ private function load_modules() { } } - // Supplementary plugins can hook into this, include their own modules - // and add them to the $edit_flow object + /** + * Fires after edit_flow has loaded all Edit Flow internal modules. + * + * Plugin authors can hook into this action, include their own modules add them to the $edit_flow object + * + */ do_action( 'ef_modules_loaded' ); } @@ -147,6 +158,13 @@ private function setup_actions() { add_action( 'admin_init', array( $this, 'action_admin_init' ) ); + /** + * Fires after setup of all edit_flow actions. + * + * Plugin authors can hook into this action to manipulate the edit_flow class after initial actions have been registered. + * + * @param edit_flow $this The core edit flow class + */ do_action_ref_array( 'editflow_after_setup_actions', array( &$this ) ); } @@ -169,6 +187,12 @@ function action_init() { if ( isset( $mod_data->options->enabled ) && $mod_data->options->enabled == 'on' ) $this->$mod_name->init(); + /** + * Fires after edit_flow has loaded all modules and module options. + * + * Plugin authors can hook into this action to trigger functionaltiy after all Edit Flow module's have been loaded. + * + */ do_action( 'ef_init' ); } @@ -248,6 +272,14 @@ public function register_module( $name, $args = array() ) { add_action( 'load-edit-flow_page_' . $args['settings_slug'], array( &$this->$name, 'action_settings_help_menu' ) ); $this->modules->$name = (object) $args; + + /** + * Fires after edit_flow has registered a module. + * + * Plugin authors can hook into this action to trigger functionaltiy after a module has been loaded. + * + * @param string $name The name of the registered module + */ do_action( 'ef_module_registered', $name ); return $this->modules->$name; } @@ -268,6 +300,13 @@ function load_module_options() { $this->$mod_name->module = $this->modules->$mod_name; } + + /** + * Fires after edit_flow has loaded all of the module options from the database. + * + * Plugin authors can hook into this action to read and manipulate module settings. + * + */ do_action( 'ef_module_options_loaded' ); } @@ -288,6 +327,9 @@ function action_init_after() { /** * Get a module by one of its descriptive values + * + * @param string $key The property to use for searching a module (ex: 'name') + * @param string|int|array $value The value to compare (using ==) */ function get_module_by( $key, $value ) { $module = false; diff --git a/interfaces/EF_Script_Interface.php b/interfaces/EF_Script_Interface.php new file mode 100644 index 000000000..0f9218be4 --- /dev/null +++ b/interfaces/EF_Script_Interface.php @@ -0,0 +1,9 @@ +create_post_cap = apply_filters( 'ef_calendar_create_post_cap', 'edit_posts' ); - - require_once( EDIT_FLOW_ROOT . '/common/php/' . 'screen-options.php' ); - add_screen_options_panel( self::usermeta_key_prefix . 'screen_options', __( 'Calendar Options', 'edit-flow' ), array( $this, 'generate_screen_options' ), self::screen_id, false, true ); + + add_action( 'admin_init', array( $this, 'add_screen_options_panel' ) ); add_action( 'admin_init', array( $this, 'handle_save_screen_options' ) ); add_action( 'admin_init', array( $this, 'register_settings' ) ); - add_action( 'admin_menu', array( $this, 'action_admin_menu' ) ); - add_action( 'admin_print_styles', array( $this, 'add_admin_styles' ) ); + add_action( 'admin_menu', array( $this, 'action_admin_menu' ) ); + add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_styles' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) ); // Ajax manipulation for the calendar @@ -174,10 +173,11 @@ function action_admin_menu() { * * @uses wp_enqueue_style() */ - function add_admin_styles() { - global $pagenow; - // Only load calendar styles on the calendar page - if ( $pagenow == 'index.php' && isset( $_GET['page'] ) && $_GET['page'] == 'calendar' ) + public function enqueue_admin_styles() { + if ( ! $this->is_calendar_view() ) { + return; + } + wp_enqueue_style( 'edit-flow-calendar-css', $this->module_url . 'lib/calendar.css', false, EDIT_FLOW_VERSION ); } @@ -189,9 +189,12 @@ function add_admin_styles() { */ function enqueue_admin_scripts() { + if ( ! $this->is_calendar_view() ) { + return; + } + $this->enqueue_datepicker_resources(); - if ( $this->is_whitelisted_functional_view() ) { $js_libraries = array( 'jquery', 'jquery-ui-core', @@ -199,6 +202,7 @@ function enqueue_admin_scripts() { 'jquery-ui-draggable', 'jquery-ui-droppable', ); + foreach( $js_libraries as $js_library ) { wp_enqueue_script( $js_library ); } @@ -206,7 +210,7 @@ function enqueue_admin_scripts() { $ef_cal_js_params = array( 'can_add_posts' => current_user_can( $this->create_post_cap ) ? 'true' : 'false' ); wp_localize_script( 'edit-flow-calendar-js', 'ef_calendar_params', $ef_cal_js_params ); - } + } @@ -244,6 +248,16 @@ function generate_screen_options() { return $output; } + /** + * Add module options to the screen panel + * + * @since 0.8.3 + */ + function add_screen_options_panel() { + require_once( EDIT_FLOW_ROOT . '/common/php/' . 'screen-options.php' ); + add_screen_options_panel( self::usermeta_key_prefix . 'screen_options', __( 'Calendar Options', 'edit-flow' ), array( $this, 'generate_screen_options' ), self::screen_id, false, true ); + } + /** * Handle the request to save the screen options * @@ -385,7 +399,7 @@ function handle_ics_subscription() { $start_date = self::ics_format_time( $post->post_date ); $end_date = self::ics_format_time( $post->post_date, 5 * MINUTE_IN_SECONDS ); $last_modified = self::ics_format_time( $post->post_modified ); - + $post_status_obj = get_post_status_object( get_post_status( $post->ID ) ); // Remove the convert chars and wptexturize filters from the title remove_filter( 'the_title', 'convert_chars' ); remove_filter( 'the_title', 'wptexturize' ); @@ -393,7 +407,7 @@ function handle_ics_subscription() { $formatted_post = array( 'BEGIN' => 'VEVENT', 'UID' => $post->guid, - 'SUMMARY' => $this->do_ics_escaping( apply_filters( 'the_title', $post->post_title ) ) . ' - ' . $this->get_post_status_friendly_name( get_post_status( $post->ID ) ), + 'SUMMARY' => $this->do_ics_escaping( apply_filters( 'the_title', $post->post_title ) ) . ' - ' . $post_status_obj->label, 'DTSTART' => $start_date, 'DTEND' => $end_date, 'LAST-MODIFIED' => $last_modified, @@ -782,10 +796,14 @@ function view_calendar() { $this->hidden = 0; if ( !empty( $week_posts[$week_single_date] ) ) { - $week_posts[$week_single_date] = apply_filters( 'ef_calendar_posts_for_week', $week_posts[$week_single_date] ); + $week_posts[$week_single_date] = apply_filters( 'ef_calendar_posts_for_week', $week_posts[$week_single_date], $week_single_date ); - foreach ( $week_posts[$week_single_date] as $num => $post ){ - echo $this->generate_post_li_html( $post, $week_single_date, $num ); + foreach ( $week_posts[$week_single_date] as $num => $post ) { + $output = apply_filters( 'ef_pre_calendar_single_date_item_html', '', $this, $num, $post, $week_single_date ); + if ( ! $output ) { + $output = $this->generate_post_li_html( $post, $week_single_date, $num ); + } + echo $output; } } @@ -856,6 +874,7 @@ function generate_post_li_html( $post, $post_date, $num = 0 ){ ob_start(); $post_id = $post->ID; $edit_post_link = get_edit_post_link( $post_id ); + $status_object = get_post_status_object( get_post_status( $post_id ) ); $post_classes = array( 'day-item', @@ -884,7 +903,7 @@ function generate_post_li_html( $post, $post_date, $num = 0 ){
    -
    get_post_status_friendly_name( get_post_status( $post_id ) ), 'edit-flow' ); ?>
    +
    label ); ?>
    ID ) ); ?>
    @@ -1213,17 +1232,17 @@ function get_calendar_posts_for_week( $args = array(), $context = 'dashboard' ) $args = array_merge( $defaults, $args ); - // Unpublished as a status is just an array of everything but 'publish' - if ( $args['post_status'] == 'unpublish' ) { + // Unpublished as a status is just an array of everything but 'publish'. + if ( 'unpublish' == $args['post_status'] ) { $args['post_status'] = ''; - $post_statuses = $this->get_post_statuses(); - foreach ( $post_statuses as $post_status ) { - $args['post_status'] .= $post_status->slug . ', '; + $post_stati = get_post_stati(); + unset($post_stati['inherit'], $post_stati['auto-draft'], $post_stati['trash'], $post_stati['publish'] ); + if ( ! apply_filters( 'ef_show_scheduled_as_unpublished', false ) ) { + unset( $post_stati['future'] ); + } + foreach ( $post_stati as $post_status ) { + $args['post_status'] .= $post_status . ', '; } - $args['post_status'] = rtrim( $args['post_status'], ', ' ); - // Optional filter to include scheduled content as unpublished - if ( apply_filters( 'ef_show_scheduled_as_unpublished', false ) ) - $args['post_status'] .= ', future'; } // The WP functions for printing the category and author assign a value of 0 to the default // options, but passing this to the query is bad (trashed and auto-draft posts appear!), so @@ -1296,23 +1315,23 @@ function get_pagination_link( $direction = 'next', $filters = array(), $weeks_of /** * Given a day in string format, returns the day at the beginning of that week, which can be the given date. - * The end of the week is determined by the blog option, 'start_of_week'. + * The beginning of the week is determined by the blog option, 'start_of_week'. * * @see http://www.php.net/manual/en/datetime.formats.date.php for valid date formats * * @param string $date String representing a date - * @param string $format Date format in which the end of the week should be returned + * @param string $format Date format in which the beginning of the week should be returned * @param int $week Number of weeks we're offsetting the range - * @return string $formatted_start_of_week End of the week + * @return string $formatted_start_of_week Beginning of the week */ function get_beginning_of_week( $date, $format = 'Y-m-d', $week = 1 ) { $date = strtotime( $date ); $start_of_week = get_option( 'start_of_week' ); $day_of_week = date( 'w', $date ); - $date += (( $start_of_week - $day_of_week - 7 ) % 7) * 60 * 60 * 24 * $week; - $additional = 3600 * 24 * 7 * ( $week - 1 ); - $formatted_start_of_week = date( $format, $date + $additional ); + $date += (( $start_of_week - $day_of_week - 7 ) % 7) * 60 * 60 * 24 ; + $date = strtotime ( '+' . ( $week - 1 ) . ' week', $date ) ; + $formatted_start_of_week = date( $format, $date ); return $formatted_start_of_week; } @@ -1334,8 +1353,8 @@ function get_ending_of_week( $date, $format = 'Y-m-d', $week = 1 ) { $end_of_week = get_option( 'start_of_week' ) - 1; $day_of_week = date( 'w', $date ); $date += (( $end_of_week - $day_of_week + 7 ) % 7) * 60 * 60 * 24; - $additional = 3600 * 24 * 7 * ( $week - 1 ); - $formatted_end_of_week = date( $format, $date + $additional ); + $date = strtotime ( '+' . ( $week - 1 ) . ' week', $date ) ; + $formatted_end_of_week = date( $format, $date ); return $formatted_end_of_week; } @@ -1683,10 +1702,9 @@ function sanitize_filter( $key, $dirty_value ) { switch( $key ) { case 'post_status': // Whitelist-based validation for this parameter - $valid_statuses = wp_list_pluck( $this->get_post_statuses(), 'slug' ); - $valid_statuses[] = 'future'; + $valid_statuses = get_post_stati(); $valid_statuses[] = 'unpublish'; - $valid_statuses[] = 'publish'; + unset( $valid_statuses['inherit'], $valid_statuses['auto-draft'], $valid_statuses['trash'] ); if ( in_array( $dirty_value, $valid_statuses ) ) return $dirty_value; else @@ -1716,18 +1734,19 @@ function sanitize_filter( $key, $dirty_value ) { function calendar_filter_options( $select_id, $select_name, $filters ) { switch( $select_id ){ case 'post_status': - $post_statuses = $this->get_post_statuses(); + $post_stati = get_post_stati(); + unset( $post_stati['inherit'], $post_stati['auto-draft'], $post_stati['trash'] ); ?> disable_custom_statuses_for_post_type() ) + if ( ! $this->is_custom_status_view() ) return; // Register new taxonomy so that we can store all our fancy new custom statuses (or is it stati?) @@ -254,70 +257,13 @@ function register_custom_statuses() { } } - /** - * Whether custom post statuses should be disabled for this post type. - * Used to stop custom statuses from being registered for post types that don't support them. - * - * @since 0.7.5 - * - * @return bool - */ - function disable_custom_statuses_for_post_type( $post_type = null ) { - global $pagenow; - - // Only allow deregistering on 'edit.php' and 'post.php' - if ( ! in_array( $pagenow, array( 'edit.php', 'post.php', 'post-new.php' ) ) ) - return false; - - if ( is_null( $post_type ) ) - $post_type = $this->get_current_post_type(); - - if ( $post_type && ! in_array( $post_type, $this->get_post_types_for_module( $this->module ) ) ) - return true; - - return false; - } - - /** - * Enqueue Javascript resources that we need in the admin: - * - Primary use of Javascript is to manipulate the post status dropdown on Edit Post and Manage Posts - * - jQuery Sortable plugin is used for drag and dropping custom statuses - * - We have other custom code for Quick Edit and JS niceties - */ - function action_admin_enqueue_scripts() { - global $pagenow; - - if ( $this->disable_custom_statuses_for_post_type() ) - return; - - // Load Javascript we need to use on the configuration views (jQuery Sortable and Quick Edit) - if ( $this->is_whitelisted_settings_view( $this->module->name ) ) { - wp_enqueue_script( 'jquery-ui-sortable' ); - wp_enqueue_script( 'edit-flow-custom-status-configure', $this->module_url . 'lib/custom-status-configure.js', array( 'jquery', 'jquery-ui-sortable', 'edit-flow-settings-js' ), EDIT_FLOW_VERSION, true ); - } - - // Custom javascript to modify the post status dropdown where it shows up - if ( $this->is_whitelisted_page() ) { - wp_enqueue_script( 'edit_flow-custom_status', $this->module_url . 'lib/custom-status.js', array( 'jquery','post' ), EDIT_FLOW_VERSION, true ); - wp_enqueue_style( 'edit_flow-custom_status', $this->module_url . 'lib/custom-status.css', false, EDIT_FLOW_VERSION, 'all' ); - wp_localize_script('edit_flow-custom_status', '__ef_localize_custom_status', array( - 'no_change' => esc_html__( "— No Change —", 'edit-flow' ), - 'published' => esc_html__( 'Published', 'edit-flow' ), - 'save_as' => esc_html__( 'Save as', 'edit-flow' ), - 'save' => esc_html__( 'Save', 'edit-flow' ), - 'edit' => esc_html__( 'Edit', 'edit-flow' ), - 'ok' => esc_html__( 'OK', 'edit-flow' ), - 'cancel' => esc_html__( 'Cancel', 'edit-flow' ), - )); - } - } /** * Displays a notice to users if they have JS disabled * Javascript is needed for custom statuses to be fully functional */ function no_js_notice() { - if( $this->is_whitelisted_page() ) : + if( $this->is_custom_status_view() ) : ?>
    get_post_statuses(); - foreach ( $post_statuses as $post_status ) { - $args['post_status'] .= $post_status->slug . ', '; + $post_stati = get_post_stati(); + unset( $post_stati['inherit'], $post_stati['auto-draft'], $post_stati['trash'], $post_stati['publish'] ); + if ( ! apply_filters( 'ef_show_scheduled_as_unpublished', false ) ) { + unset( $post_stati['future'] ); + } + foreach ( $post_stati as $post_status ) { + $args['post_status'] .= $post_status . ', '; } - $args['post_status'] = rtrim( $args['post_status'], ', ' ); - // Optional filter to include scheduled content as unpublished - if ( apply_filters( 'ef_show_scheduled_as_unpublished', false ) ) - $args['post_status'] .= ', future'; } - + // Filter by post_author if it's set if ( $args['author'] === '0' ) unset( $args['author'] ); @@ -497,8 +512,8 @@ function term_column_default( $post, $column_name, $parent_term ) { switch( $column_name ) { case 'status': - $status_name = $this->get_post_status_friendly_name( $post->post_status ); - return $status_name; + $status_name = get_post_status_object( $post->post_status ); + return $status_name->label; break; case 'author': $post_author = get_userdata( $post->post_author ); @@ -510,8 +525,7 @@ function term_column_default( $post, $column_name, $parent_term ) { return $output; break; case 'post_modified': - $modified_time_gmt = strtotime( $post->post_modified_gmt . " GMT" ); - return $this->timesince( $modified_time_gmt ); + return sprintf( esc_html__( '%s ago', 'edit-flow' ), human_time_diff( get_the_time( 'U', $post->ID ), current_time( 'timestamp' ) ) ); break; default: break; @@ -716,17 +730,18 @@ function story_budget_filters() { function story_budget_filter_options( $select_id, $select_name, $filters ) { switch( $select_id ) { case 'post_status': - $post_statuses = $this->get_post_statuses(); + $post_stati = get_post_stati(); + unset( $post_stati['inherit'], $post_stati['auto-draft'], $post_stati['trash'] ); ?> is_whitelisted_functional_view() || $this->is_whitelisted_settings_view( $this->module->name ) ) { + + if ( $this->is_current_module_settings_view() ) { wp_enqueue_script( 'jquery-listfilterizer' ); wp_enqueue_script( 'jquery-quicksearch' ); wp_enqueue_script( 'edit-flow-user-groups-js', $this->module_url . 'lib/user-groups.js', array( 'jquery', 'jquery-listfilterizer', 'jquery-quicksearch' ), EDIT_FLOW_VERSION, true ); - } - - if ( $this->is_whitelisted_settings_view( $this->module->name ) ) wp_enqueue_script( 'edit-flow-user-groups-configure-js', $this->module_url . 'lib/user-groups-configure.js', array( 'jquery' ), EDIT_FLOW_VERSION, true ); + } + } /** * Enqueue necessary admin styles, but only on the proper pages * * @since 0.7 + * @updated 0.8.3 * * @uses wp_enqueue_style() */ function enqueue_admin_styles() { - - if ( $this->is_whitelisted_functional_view() || $this->is_whitelisted_settings_view() ) { + if ( $this->is_current_module_settings_view() ) { wp_enqueue_style( 'jquery-listfilterizer' ); wp_enqueue_style( 'edit-flow-user-groups-css', $this->module_url . 'lib/user-groups.css', false, EDIT_FLOW_VERSION ); } @@ -844,6 +844,9 @@ function get_usergroup_by( $field, $value ) { $usergroup->$key = $value; } } + + $usergroup = apply_filters( 'ef_usergroup_object', $usergroup ); + return $usergroup; } @@ -1067,7 +1070,8 @@ function get_usergroups_for_user( $user_id_or_login, $ids_or_objects = 'ids' ) { return false; } } - + + } } diff --git a/readme.txt b/readme.txt index 26ab4367e..ee998ea72 100644 --- a/readme.txt +++ b/readme.txt @@ -3,8 +3,8 @@ Contributors: batmoo, danielbachhuber, sbressler, automattic Donate link: http://editflow.org/contribute/ Tags: edit flow, workflow, editorial, newsroom, management, journalism, post status, custom status, notifications, email, comments, editorial comments, usergroups, calendars, editorial calendar, story budget Requires at least: 4.5 -Tested up to: 4.8 -Stable tag: 0.8.2 +Tested up to: 4.9.6 +Stable tag: 0.8.3 Redefining your editorial workflow. @@ -56,6 +56,9 @@ For support questions, feedback and ideas, please use the [WordPress.org forums] == Upgrade Notice == += 0.8.3 = +Improvements and bugfixes. + = 0.8.2 = Minor enhancements and bug fixes, translation updates. @@ -103,6 +106,29 @@ New features, including story budget and editorial metadata, a completely rewrit == Changelog == += 0.8.3 (June 14, 2018) = +* UI Improvement: Made primary buttons on Settings screen consistent with WordPress UI. Props [cojennin](https://github.com/cojennin). +* UI Improvement: Display who particularly was notified about an editorial comment. Props [goodguyry](https://github.com/goodguyry), [WPprodigy](https://github.com/WPprodigy) +* Improvement: Updated Russian translation and documentation. Props [achumakov](https://github.com/achumakov). +* Improvement: Eliminate a few cases of raw SQL queries in favor of `date_query`. Props [justnorris](https://github.com/justnorris). +* Improvement: Cache calendar items for each user individually to prevent potential cache pollution. Props [justnorris](https://github.com/justnorris). +* Improvement: various i18n updates. +* Improvement: Move ef_story_budget_posts_query_args filter down to allow overriding the date query in Story Budget module. +* Improvement: Limit results in Calendar to 200 per page, potentially saving from trouble on websites with large amount of content. +* Improvement: Don’t generate rewrite rules for notepad as they're unused. +* Improvement: Support modifying HTML output of a Calendar day via ef_pre_calendar_single_date_item_html filter. Props [cklosowski](https://github.com/cklosowski). + +* Improvement: show custom post statuses in Calendar and Story Budget. Props [mikeyarce](https://github.com/mikeyarce) +* WordPress Coding Standards improvements and code cleanup by many unsung heroes (primarily [justnorris](https://github.com/justnorris)). +* Bug fix: Prevent user from removing "Draft" post status, breaking the auto-draft functionality. +* Bug fix: Fix ef_pre_insert_editorial_comment filter so that it actually has meaning. Props [sudar](https://github.com/sudar). +* Bug fix: Fix PHP Warning: array_map(): Argument #2 should be an array. Props Michael Auteri. +* Bug fix: Always offset post times to UTC+0 for Calendars to prevent incorrect times when adding to iCalendar/Google Calendar. Props [justnorris](https://github.com/justnorris). +* Bug fix: Use taxonomy when checking for term existence when trying to prevent term collision. Props [shadyvb](https://github.com/shadyvb). +* Bug fix: Correctly handle screen options update for Story Budget columns. Props [raduconst](https://github.com/raduconst) +* Bug fix: EF_Calendar::get_beginning_of_week and EF_Calendar::get_ending_of_week should respect DST now. Props [FewKinG](https://github.com/FewKinG) +* Bug fix: Build home_url() previews with trailing slash. Props [jeremyfelt](https://github.com/jeremyfelt) + = 0.8.2 (Sept 16, 2016) = * Improvement: Updated Spanish localization thanks to [moucho](https://github.com/moucho) * Improvement: New Swedish localization thanks to [Warpsmith](https://github.com/Warpsmith) diff --git a/vipgo-helper.php b/vipgo-helper.php index 77ad84fad..be0166473 100644 --- a/vipgo-helper.php +++ b/vipgo-helper.php @@ -4,6 +4,16 @@ */ add_action( 'after_setup_theme', 'EditFlow' ); +/** + * Caps don't get loaded on install on VIP Go. Instead, let's add + * them via filters. + */ +add_filter( 'ef_kill_add_caps_to_role', '__return_true' ); +add_filter( 'ef_view_calendar_cap', function() {return 'edit_posts'; } ); +add_filter( 'ef_view_story_budget_cap', function() { return 'edit_posts'; } ); +add_filter( 'ef_edit_post_subscriptions_cap', function() { return 'edit_others_posts'; } ); +add_filter( 'ef_manage_usergroups_cap', function() { return 'manage_options'; } ); + /** * Edit Flow loads modules after plugins_loaded, which has already been fired when loading via wpcom_vip_load_plugins * Let's run the method at after_setup_themes