├── css ├── style.css ├── map-after-fields.css ├── dashboard.css └── settings.css ├── languages ├── church-theme-content-af.mo ├── church-theme-content-da_DK.mo ├── church-theme-content-de_DE.mo ├── church-theme-content-es_ES.mo ├── church-theme-content-es_MX.mo ├── church-theme-content-fr_FR.mo ├── church-theme-content-nb_NO.mo ├── church-theme-content-nl_NL.mo ├── church-theme-content-nn_NO.mo ├── church-theme-content-pt_BR.mo ├── church-theme-content-sk_SK.mo ├── church-theme-content-sr_RS.mo ├── church-theme-content-sv_SE.mo └── important.txt ├── includes ├── admin │ ├── admin-posts.php │ ├── admin-enqueue-styles.php │ ├── admin-helpers.php │ ├── admin-enqueue-scripts.php │ ├── notices.php │ ├── dashboard.php │ ├── import.php │ ├── admin-support.php │ ├── upgrade.php │ ├── editor.php │ ├── admin-add-ons.php │ ├── admin-menu.php │ ├── admin-maps.php │ └── admin-person-fields.php ├── event-fields.php ├── mime-types.php ├── classes │ ├── CTC_Dashboard_News.php │ └── CTC_EDD_SL_Plugin_Updater.php ├── schedule.php ├── add-ons.php ├── podcast.php ├── helpers.php ├── support.php └── post-types.php ├── js ├── settings.js ├── map-after-fields.js └── lib │ └── clipboard.min.js ├── readme.txt └── church-theme-content.php /css/style.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Church Content General Styles 3 | */ 4 | 5 | -------------------------------------------------------------------------------- /languages/church-theme-content-af.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/churchthemes/church-theme-content/HEAD/languages/church-theme-content-af.mo -------------------------------------------------------------------------------- /languages/church-theme-content-da_DK.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/churchthemes/church-theme-content/HEAD/languages/church-theme-content-da_DK.mo -------------------------------------------------------------------------------- /languages/church-theme-content-de_DE.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/churchthemes/church-theme-content/HEAD/languages/church-theme-content-de_DE.mo -------------------------------------------------------------------------------- /languages/church-theme-content-es_ES.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/churchthemes/church-theme-content/HEAD/languages/church-theme-content-es_ES.mo -------------------------------------------------------------------------------- /languages/church-theme-content-es_MX.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/churchthemes/church-theme-content/HEAD/languages/church-theme-content-es_MX.mo -------------------------------------------------------------------------------- /languages/church-theme-content-fr_FR.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/churchthemes/church-theme-content/HEAD/languages/church-theme-content-fr_FR.mo -------------------------------------------------------------------------------- /languages/church-theme-content-nb_NO.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/churchthemes/church-theme-content/HEAD/languages/church-theme-content-nb_NO.mo -------------------------------------------------------------------------------- /languages/church-theme-content-nl_NL.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/churchthemes/church-theme-content/HEAD/languages/church-theme-content-nl_NL.mo -------------------------------------------------------------------------------- /languages/church-theme-content-nn_NO.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/churchthemes/church-theme-content/HEAD/languages/church-theme-content-nn_NO.mo -------------------------------------------------------------------------------- /languages/church-theme-content-pt_BR.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/churchthemes/church-theme-content/HEAD/languages/church-theme-content-pt_BR.mo -------------------------------------------------------------------------------- /languages/church-theme-content-sk_SK.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/churchthemes/church-theme-content/HEAD/languages/church-theme-content-sk_SK.mo -------------------------------------------------------------------------------- /languages/church-theme-content-sr_RS.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/churchthemes/church-theme-content/HEAD/languages/church-theme-content-sr_RS.mo -------------------------------------------------------------------------------- /languages/church-theme-content-sv_SE.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/churchthemes/church-theme-content/HEAD/languages/church-theme-content-sv_SE.mo -------------------------------------------------------------------------------- /languages/important.txt: -------------------------------------------------------------------------------- 1 | Do not add your own translations to this directory. They will be lost during plugin updates. The only .mo files that should be loaded from here are pre-made translations that come with the plugin (if any are included). 2 | 3 | Store your translations at wp-content/languages/plugins/church-theme-content-$locale.mo 4 | (e.g. church-theme-content-en_US.mo) to keep them safe from loss during updates. 5 | 6 | Read https://churchthemes.com/go/translate-plugin for more information and please contact us if you would like to contribute your translation for other churches to use. -------------------------------------------------------------------------------- /css/map-after-fields.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Map After Fields (Event / Location) 3 | */ 4 | 5 | /* Container for description and Google Map */ 6 | 7 | #ctc-map-after-fields-container { 8 | display: none; /* shown only when have data */ 9 | } 10 | 11 | /* Google Map element */ 12 | 13 | #ctc-map-after-fields { 14 | width: 100%; /* responsive */ 15 | height: 350px; 16 | max-width: 980px; /* not awkward on wide screen */ 17 | max-height: 65vh; /* not more than 2/3 of mobile screen */ 18 | } 19 | 20 | 21 | /* Description below map */ 22 | 23 | #ctc-map-after-fields-description { 24 | margin-top: 7px; 25 | } 26 | -------------------------------------------------------------------------------- /css/dashboard.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Dashboard 3 | */ 4 | 5 | /******************************************* 6 | * AT A GLANCE 7 | *******************************************/ 8 | 9 | /* Show custom post type icons */ 10 | 11 | #dashboard_right_now a.ctc_sermon-count:before, 12 | #dashboard_right_now span.ctc_sermon-count:before { 13 | content: "\f236"; 14 | } 15 | 16 | #dashboard_right_now a.ctc_event-count:before, 17 | #dashboard_right_now span.ctc_event-count:before { 18 | content: "\f145"; 19 | } 20 | 21 | #dashboard_right_now a.ctc_location-count:before, 22 | #dashboard_right_now span.ctc_location-count:before { 23 | content: "\f230"; 24 | } 25 | 26 | #dashboard_right_now a.ctc_person-count:before, 27 | #dashboard_right_now span.ctc_person-count:before { 28 | content: "\f110"; 29 | } 30 | -------------------------------------------------------------------------------- /includes/admin/admin-posts.php: -------------------------------------------------------------------------------- 1 | true 38 | ), 'objects' ); 39 | 40 | // Check if post slug matches a post type rewrite slug 41 | foreach ( $post_types as $post_type ) { 42 | if ( ! empty( $post_type->rewrite['slug'] ) && $post_type->rewrite['slug'] == $slug ) { 43 | return true; 44 | } 45 | } 46 | 47 | return $current_value; 48 | 49 | } 50 | 51 | add_filter( 'wp_unique_post_slug_is_bad_flat_slug', 'ctc_is_bad_post_slug', 10, 2 ); 52 | add_filter( 'wp_unique_post_slug_is_bad_hierarchical_slug', 'ctc_is_bad_post_slug', 10, 2 ); 53 | -------------------------------------------------------------------------------- /includes/admin/admin-enqueue-styles.php: -------------------------------------------------------------------------------- 1 | base ) { // only on Dashboard screen. 35 | wp_enqueue_style( 'ctc-dashboard', CTC_URL . '/' . CTC_CSS_DIR . '/dashboard.css', false, CTC_VERSION ); 36 | } 37 | 38 | // Plugin Settings. 39 | if ( $ctc_settings->is_settings_page() ) { // only on Plugin Settings page. 40 | wp_enqueue_style( 'ctc-settings', CTC_URL . '/' . CTC_CSS_DIR . '/settings.css', false, CTC_VERSION ); 41 | } 42 | 43 | // Styles for showing map after related fields on event/location screens. 44 | if ( ctc_has_lat_lng_fields() ) { // only if event/location screen with latitude and longitude fields supported. 45 | wp_enqueue_style( 'ctc-map-after-fields', CTC_URL . '/' . CTC_CSS_DIR . '/map-after-fields.css', false, CTC_VERSION ); 46 | } 47 | 48 | } 49 | 50 | add_action( 'admin_enqueue_scripts', 'ctc_admin_enqueue_styles' ); // admin-end only. 51 | -------------------------------------------------------------------------------- /includes/admin/admin-helpers.php: -------------------------------------------------------------------------------- 1 | slug . '&post_type=' . $post_type ) ) . '"> ' . $term->name . ''; 43 | } 44 | 45 | $list = implode( ', ', $terms_array ); 46 | 47 | } 48 | 49 | return apply_filters( 'ctc_admin_term_list', $list, $post_id, $taxonomy ); 50 | 51 | } 52 | 53 | /********************************* 54 | * CONDITIONS 55 | *********************************/ 56 | 57 | /** 58 | * Is this a Church Content plugin-provided custom post type add/edit screen? 59 | * 60 | * Example: Adding a sermon or editing an event. 61 | * 62 | * @since 2.0 63 | * @global bool $multipage 64 | * @return bool True if current post has multiple pages 65 | */ 66 | function ctc_is_cpt_add_edit() { 67 | 68 | // Default result. 69 | $result = false; 70 | 71 | // Get current screen. 72 | $screen = get_current_screen(); 73 | 74 | // Check of adding or editing a Church Content plugin-provided custom post type. 75 | if ( 'post' === $screen->base && preg_match( '/^ctc_.*$/', $screen->post_type ) ) { 76 | $result = true; 77 | } 78 | 79 | // Return filtered. 80 | return apply_filters( 'ctc_is_cpt_add_edit', $result ); 81 | 82 | } 83 | -------------------------------------------------------------------------------- /includes/event-fields.php: -------------------------------------------------------------------------------- 1 | is_settings_page() ) { // only on Plugin Settings page. 33 | 34 | // Settings script. 35 | wp_enqueue_script( 'ctc-settings', CTC_URL . '/' . CTC_JS_DIR . '/settings.js', array( 'jquery' ), CTC_VERSION ); // bust cache on update. 36 | 37 | // Clipboard.js 38 | wp_enqueue_script( 'clipboard-js', CTC_URL . '/' . CTC_JS_DIR . '/lib/clipboard.min.js', false, CTC_VERSION ); 39 | 40 | } 41 | 42 | // Scripts for showing map after related fields on event/location screens 43 | if ( ctc_has_lat_lng_fields() ) { // only if event/location screen with latitude and longitude fields supported. 44 | 45 | // Enqueue Google Maps JavaScript API. 46 | wp_enqueue_script( 'google-maps', '//maps.googleapis.com/maps/api/js?key=' . ctc_setting( 'google_maps_api_key' ), false, null ); // no version, generic name to share w/plugins. 47 | 48 | // Script for initializing and interacting with map. 49 | wp_enqueue_script( 'ctc-map-after-fields', CTC_URL . '/' . CTC_JS_DIR . '/map-after-fields.js', false, CTC_VERSION ); 50 | wp_localize_script( 'ctc-map-after-fields', 'ctc_map_after_fields_data', array( // data to use in JS. 51 | 'get_from_address_failed' => __( 'Address could not be converted. Check the address or enter your city then click the map to pinpoint your location.', 'church-theme-content' ), 52 | 'missing_address' => __( 'Please enter an Address above.', 'church-theme-content' ), 53 | 'missing_key_message' => __( 'Go to Settings > Church Content > Locations to set your Google Maps API Key to use this button.', 'church-theme-content' ), 54 | 'has_api_key' => ctc_setting( 'google_maps_api_key' ) ? true : false, 55 | ) ); 56 | 57 | } 58 | 59 | } 60 | 61 | add_action( 'admin_enqueue_scripts', 'ctc_admin_enqueue_scripts' ); // admin-end only. 62 | -------------------------------------------------------------------------------- /includes/mime-types.php: -------------------------------------------------------------------------------- 1 | (%s)', 'PDFs (%s)', 'church-theme-content' ) 78 | ); 79 | 80 | return $post_mime_types; 81 | 82 | } 83 | 84 | add_filter( 'post_mime_types', 'ctc_add_post_mime_types' ); 85 | -------------------------------------------------------------------------------- /js/settings.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Plugin Settings 3 | */ 4 | 5 | jQuery(document).ready(function ($) { 6 | 7 | /************************************** 8 | * PRO DISABLED 9 | **************************************/ 10 | 11 | // Add .ctc-pro-setting-inactive and .button-disabled to image button when image input readonly. 12 | if ($('#ctps-field-podcast_image').hasClass('ctc-setting-readonly')) { 13 | $('.ctps-upload-file', $('#ctps-field-podcast_image').parent('.ctps-section')).addClass('ctc-pro-setting-inactive button-disabled'); 14 | } 15 | 16 | // Show notice when user engages field requiring Pro while Pro is inactive. 17 | // The Pro fields have readonly attribute so cannot be changed, but will be saved. 18 | $('.ctc-pro-setting-inactive').on('focus, click', function (e) { 19 | 20 | // Prevent clicks on links from having effect. 21 | e.preventDefault(); 22 | 23 | // Remove previous instance of message before showing new. 24 | $('.ctc-pro-setting-inactive-message-inline').remove(); 25 | 26 | // Get parent cell. 27 | var $field_container = $(this).parents('td'); 28 | 29 | // Get message from section description. 30 | var $message = $('.ctc-pro-setting-inactive-message:visible').html(); 31 | 32 | // Have message. 33 | if ($message) { 34 | 35 | // Copy message below field. 36 | $field_container.append(''); 37 | 38 | // Fade it in. 39 | $('.ctc-pro-setting-inactive-message-inline').hide().fadeIn('fast'); 40 | 41 | } 42 | 43 | }); 44 | 45 | // Prevent checkbox/radio changes on inactive fields (due to missing theme support or Pro being required). 46 | // readonly attribute does not stop changes to checkbox states. 47 | $('input[type=checkbox].ctc-setting-readonly, input[type=radio].ctc-setting-readonly').on('click', function (e) { 48 | return false; 49 | }); 50 | 51 | /************************************** 52 | * PODCAST 53 | **************************************/ 54 | 55 | // Open Podcast section when "Podcast Settings" link clicked in Sermons section. 56 | $('.ctps-field-podcast_content a').on('click', function (e) { 57 | 58 | // Prevent regular click action. 59 | e.preventDefault(); 60 | 61 | // Switch to Podcast tab. 62 | ctps_switch_section('podcast'); 63 | 64 | }); 65 | 66 | // Copy Feed URL to clipboard. 67 | var clipboard = new ClipboardJS('#ctc-copy-podcast-url-button', { 68 | 69 | // Get URL. 70 | text: function (trigger) { 71 | return $('#ctc-settings-podcast-feed-link').attr('href'); 72 | } 73 | 74 | }).on('success', function (e) { 75 | 76 | // Show message. 77 | $('#ctc-podcast-url-copied').fadeIn('fast'); 78 | 79 | // Hide message. 80 | setTimeout(function () { 81 | $('#ctc-podcast-url-copied').fadeOut('fast'); 82 | }, 3000); 83 | 84 | // Stop click. 85 | return false; 86 | 87 | }); 88 | 89 | // Stop click to # on Copy button. 90 | $('#ctc-copy-podcast-url-button').on('click', function (e) { 91 | e.preventDefault(); 92 | }); 93 | 94 | }); 95 | -------------------------------------------------------------------------------- /includes/admin/notices.php: -------------------------------------------------------------------------------- 1 | php_is_old ) { 39 | $show = false; 40 | } 41 | 42 | // Show notice only if recurrence is enabled. 43 | if ( ! ctc_field_supported( 'events', '_ctc_event_recurrence' ) ) { 44 | $show = false; 45 | } 46 | 47 | // Show notice only on relevant screens. 48 | // Dashboard, events list and event add/edit. 49 | $screen = get_current_screen(); 50 | if ( 'dashboard' !== $screen->base && 'ctc_event' !== $screen->post_type ) { 51 | $show = false; 52 | } 53 | 54 | // Show notice. 55 | if ( $show ) { 56 | 57 | $content = sprintf( 58 | wp_kses( 59 | /* translators: %1$s is minimum required version of PHP, %2$s is URL with information on updating PHP. */ 60 | __( 'Event recurrence is disabled. PHP %1$s or newer is required for recurrence to work. Update PHP to resolve.', 'church-theme-content' ), 61 | array( 62 | 'strong' => array(), 63 | 'a' => array( 64 | 'href' => array(), 65 | 'target' => array(), 66 | ), 67 | ) 68 | ), 69 | esc_html( $ct_recurrence->php_min_version ), 70 | esc_url( ctc_ctcom_url( 'update-php', array( 'utm_content' => 'recurrence' ) ) ) 71 | ); 72 | 73 | } 74 | 75 | // Return. 76 | return apply_filters( '', $content ); 77 | 78 | } 79 | 80 | /** 81 | * Show PHP update notice when CT Recurrence class needs it. 82 | * 83 | * CT Recurrence methods return empty when PHP version not satisfied. 84 | * Recurring events are treated as non-recurring until PHP is updated. 85 | * 86 | * @since 2.0 87 | */ 88 | function ctc_recurrence_php_notice() { 89 | 90 | // Get notice if it is to be shown. 91 | $notice = ctc_recurrence_php_note(); 92 | 93 | // Have notice. 94 | if ( $notice ) { 95 | 96 | ?> 97 |
99 | 100 |
101 |41 | More Information', 'church-theme-content' ), 46 | array( 47 | 'b' => array(), 48 | 'a' => array( 49 | 'href' => array(), 50 | 'target' => array(), 51 | ) 52 | ) 53 | ), 54 | CTC_NAME, 55 | 'https://wordpress.org/plugins/church-theme-content/' 56 | ); 57 | ?> 58 |
59 |67 | %1$s theme does not support the %2$s plugin. More Information, Dismiss', 'church-theme-content' ), 71 | array( 72 | 'b' => array(), 73 | 'a' => array( 74 | 'href' => array(), 75 | 'target' => array(), 76 | ) 77 | ) 78 | ), 79 | wp_get_theme(), 80 | CTC_NAME, 81 | 'https://wordpress.org/plugins/church-theme-content/', 82 | esc_url( $dismiss_url ) 83 | ); 84 | ?> 85 |
86 |Church Content Pro to save time with recurring events.', 'church-theme-content' ), array( 'a' => array( 'href' => array(), 'target' => array(), ) ) ), esc_url( ctc_ctcom_url( 'church-content-pro', array( 'utm_content' => 'recurrence_field' ) ) ) ); ?>
Church Content Pro
to save time by selecting previously used locations.', 'church-theme-content' ), array( 'a' => array( 'href' => array(), 'target' => array(), ), ) ), esc_url( ctc_ctcom_url( 'church-content-pro', array( 'utm_content' => 'event_location_box' ) ) ) ); ?> Settings then Sermons > Podcast). 37 | $settings_page_uri = 'options-general.php?page=' . CTC_DIR . '&rand=' . $rand; 38 | 39 | // Capability. 40 | $capability = 'manage_options'; // role/capability with access. 41 | 42 | // Setting word for all post types. 43 | $settings_word = _x( 'Settings', 'custom post type menu', 'church-theme-content' ); 44 | 45 | // Sermons. 46 | $key = 'edit.php?post_type=ctc_sermon'; 47 | 48 | // Podcast. 49 | $submenu[ $key ][] = array( 50 | _x( 'Podcast', 'custom post type menu', 'church-theme-content' ), 51 | $capability, 52 | admin_url( $settings_page_uri . '#podcast' ), 53 | ); 54 | 55 | // Settings. 56 | $submenu[ $key ][] = array( 57 | $settings_word, 58 | $capability, 59 | admin_url( $settings_page_uri . '#sermons' ), 60 | ); 61 | 62 | // Events. 63 | $key = 'edit.php?post_type=ctc_event'; 64 | 65 | // Settings. 66 | $submenu[ $key ][] = array( 67 | $settings_word, 68 | $capability, 69 | admin_url( $settings_page_uri . '#events' ), 70 | ); 71 | 72 | // Locations. 73 | $key = 'edit.php?post_type=ctc_location'; 74 | 75 | // Settings. 76 | $submenu[ $key ][] = array( 77 | $settings_word, 78 | $capability, 79 | admin_url( $settings_page_uri . '#locations' ), 80 | ); 81 | 82 | // People. 83 | $key = 'edit.php?post_type=ctc_person'; 84 | 85 | // Settings. 86 | $submenu[ $key ][] = array( 87 | $settings_word, 88 | $capability, 89 | admin_url( $settings_page_uri . '#people' ), 90 | ); 91 | 92 | } 93 | 94 | add_action( 'admin_menu', 'ctc_add_settings_menu_links' ); 95 | 96 | /******************************************* 97 | * REORDERING 98 | *******************************************/ 99 | 100 | /** 101 | * Enable custom menu order 102 | * 103 | * Note ctc_reorder_admin_menu which does the actual ordering. 104 | * 105 | * @since 0.9 106 | */ 107 | function ctc_custom_menu_order() { 108 | return true; 109 | } 110 | 111 | add_filter( 'custom_menu_order', 'ctc_custom_menu_order' ); // enable custom menu order 112 | 113 | /** 114 | * Friendly admin menu order 115 | * 116 | * Move Pages to top followed by Posts then custom post types. 117 | * Show Comments and Media at bottom. 118 | * 119 | * @since 0.9 120 | * @param array $menu_ord Menu data 121 | * @return array Modified $menu_ord 122 | */ 123 | function ctc_reorder_admin_menu( $menu_ord ) { 124 | 125 | // Move Pages before Posts 126 | ctc_move_admin_menu_item( $menu_ord, 'edit.php?post_type=page', 'edit.php', 'before' ); 127 | 128 | // Move Comments and Media after the LAST CPT 129 | // This is in case some CPT's are not used or reordered 130 | $last_cpt = ''; 131 | foreach ( $menu_ord as $item ) { 132 | if ( preg_match( '/^edit\.php\?post_type=/', $item ) ) { 133 | $last_cpt = $item; 134 | } 135 | } 136 | ctc_move_admin_menu_item( $menu_ord, 'upload.php', $last_cpt ); // Media Library - last 137 | ctc_move_admin_menu_item( $menu_ord, 'edit-comments.php', $last_cpt ); // Comments - second to last 138 | 139 | // Return manipulated menu array 140 | return $menu_ord; 141 | 142 | } 143 | 144 | add_filter( 'menu_order', 'ctc_reorder_admin_menu' ); 145 | 146 | /** 147 | * Function to move admin menu item before or after another 148 | * 149 | * Use this with custom_menu_order and menu_order filters. 150 | * 151 | * @since 0.9 152 | * @param array $menu_ord The original menu from menu_order filter 153 | * @param string $move_item Value of item in array to move 154 | * @param string $target_item Value of item in array to move $move_item before or after 155 | * @param string $position Position 'after' (default) or 'before' in which to place $move_item in relation to $target_item 156 | * @return array Modified $menu_ord 157 | */ 158 | function ctc_move_admin_menu_item( &$menu_ord, $move_item, $target_item, $position = 'after' ) { 159 | 160 | // make sure items given are in array 161 | if ( in_array( $move_item, $menu_ord ) && in_array( $target_item, $menu_ord ) ) { 162 | 163 | // get position of each item 164 | $move_key = array_search( $move_item, $menu_ord ); 165 | $move_key_after = array_search( $target_item, $menu_ord ); 166 | 167 | // move item before instead of after 168 | if ( 'before' == $position ) { 169 | $move_key_after = ( $move_key_after - 1 ) >= 0 ? ( $move_key_after - 1 ) : 0; // move after item before item to move after (unless item to move after is at very top) 170 | } 171 | 172 | // move one item directly after the other 173 | if ( $move_key < $move_key_after ) { // item to move is currently before item to move after 174 | $menu_ord = array_merge( 175 | array_slice( $menu_ord, 0, $move_key ), // everything before item being moved 176 | array_slice( $menu_ord, $move_key + 1, $move_key_after - $move_key ), // everything after item being moved through item to move after 177 | array( $menu_ord[$move_key] ), // add item to move after item to move after 178 | array_slice( $menu_ord, $move_key_after + 1 ) // everything after item to move after 179 | ); 180 | } else if ( $move_key > $move_key_after ) { // item to move is currently after item to move directly after 181 | $menu_ord = array_merge( 182 | array_slice( $menu_ord, 0, $move_key_after + 1 ), // everything from item to move after and before 183 | array( $menu_ord[$move_key] ), // add item to move after item to move after 184 | array_slice( $menu_ord, $move_key_after + 1, $move_key - $move_key_after - 1 ), // everything after item to move after and before item to move 185 | array_slice( $menu_ord, $move_key + 1 ) // everything after item to move 186 | ); 187 | } 188 | 189 | // if moving item before very first item, run again but with $move_item and $target_item inverted 190 | // there was no higher item to move after so we ran as normal and now swap the new two top items 191 | if ( 'before' == $position && 0 == $move_key_after ) { 192 | ctc_move_admin_menu_item( $menu_ord, $target_item, $move_item ); // run again with item to move and item to move after swapped 193 | } 194 | 195 | } 196 | 197 | // return manipulated menu or original menu if no manipulation done 198 | return apply_filters( 'ctc_move_admin_menu_item', $menu_ord, $menu_ord, $move_item, $target_item, $position ); 199 | 200 | } 201 | 202 | /******************************************* 203 | * HIDING 204 | *******************************************/ 205 | 206 | /** 207 | * Hide sermons in admin area. 208 | * 209 | * Apply setting to hide post type in admin area. 210 | * Useful when not using a particular feature (e.g. using a third-party plugin. 211 | * 212 | * This filters post type registration arguments. 213 | * 214 | * @since 2.0 215 | * @param array $args Current post type arguments. 216 | * @return array Modified post type arguments. 217 | */ 218 | function ctc_admin_hide_sermons( $args ) { 219 | return ctc_admin_hide_post_type_args( 'sermons_admin_hide', $args ); 220 | } 221 | 222 | add_filter( 'ctc_post_type_sermon_args', 'ctc_admin_hide_sermons' ); 223 | 224 | /** 225 | * Hide events in admin area. 226 | * 227 | * @since 2.0 228 | * @param array $args Current post type arguments. 229 | * @return array Modified post type arguments. 230 | */ 231 | function ctc_admin_hide_events( $args ) { 232 | return ctc_admin_hide_post_type_args( 'events_admin_hide', $args ); 233 | } 234 | 235 | add_filter( 'ctc_post_type_event_args', 'ctc_admin_hide_events' ); 236 | 237 | /** 238 | * Hide locations in admin area. 239 | * 240 | * @since 2.0 241 | * @param array $args Current post type arguments. 242 | * @return array Modified post type arguments. 243 | */ 244 | function ctc_admin_hide_locations( $args ) { 245 | return ctc_admin_hide_post_type_args( 'locations_admin_hide', $args ); 246 | } 247 | 248 | add_filter( 'ctc_post_type_location_args', 'ctc_admin_hide_locations' ); 249 | 250 | /** 251 | * Hide people in admin area. 252 | * 253 | * @since 2.0 254 | * @param array $args Current post type arguments. 255 | * @return array Modified post type arguments. 256 | */ 257 | function ctc_admin_hide_people( $args ) { 258 | return ctc_admin_hide_post_type_args( 'people_admin_hide', $args ); 259 | } 260 | 261 | add_filter( 'ctc_post_type_person_args', 'ctc_admin_hide_people' ); 262 | 263 | /** 264 | * Update post type arguments array to hide in admin, when a setting is true. 265 | * 266 | * @since 2.0 267 | * @param string $setting Setting ID to check for true value on. 268 | * @param array $args Arguments to merge into. 269 | * @return array Modified post type arguments. 270 | */ 271 | function ctc_admin_hide_post_type_args( $setting, $args ) { 272 | 273 | // Setting is active. 274 | if ( ctc_setting( $setting ) ) { 275 | 276 | // Change post type registration arguments. 277 | $args['show_ui'] = false; 278 | $args['show_in_nav_menus'] = false; 279 | 280 | } 281 | 282 | return $args; 283 | 284 | } 285 | -------------------------------------------------------------------------------- /js/lib/clipboard.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * clipboard.js v2.0.0 3 | * https://zenorocha.github.io/clipboard.js 4 | * 5 | * Licensed MIT © Zeno Rocha 6 | */ 7 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return function(t){function e(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return t[o].call(r.exports,r,r.exports,e),r.l=!0,r.exports}var n={};return e.m=t,e.c=n,e.i=function(t){return t},e.d=function(t,n,o){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:o})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=3)}([function(t,e,n){var o,r,i;!function(a,c){r=[t,n(7)],o=c,void 0!==(i="function"==typeof o?o.apply(e,r):o)&&(t.exports=i)}(0,function(t,e){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var o=function(t){return t&&t.__esModule?t:{default:t}}(e),r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function t(t,e){for(var n=0;n200 | Google Maps API Key Not Set. You must set it in Church Content Settings for maps to work.', 'church-theme-content' ), 205 | array( 206 | 'strong' => array(), 207 | 'a' => array( 208 | 'href' => array(), 209 | 'target' => array(), 210 | ), 211 | ) 212 | ), 213 | esc_url( admin_url( 'options-general.php?page=' . CTC_DIR . '#locations' ) ) 214 | ); 215 | ?> 216 |
217 |339 | 340 |
341 | 342 |352 | 353 | Important: You must set your Google Maps API Key in Church Content Settings for maps to work.', 'church-theme-content' ), 358 | array( 359 | 'strong' => array(), 360 | 'a' => array( 361 | 'href' => array(), 362 | 'target' => array(), 363 | ), 364 | ) 365 | ), 366 | esc_url( admin_url( 'options-general.php?page=' . CTC_DIR . '#locations' ) ) 367 | ); 368 | ?> 369 | 370 | 371 | 372 |
373 | 374 | is same but with the button on end. 386 | * 387 | * @since 1.6 388 | */ 389 | function ctc_coordinate_field( $data ) { 390 | 391 | // Get current screen 392 | $screen = get_current_screen(); 393 | 394 | // Text input from CT Meta Box 395 | $input = ''; 396 | 397 | // Only if address field supported 398 | if ( 399 | ( 'ctc_event' == $screen->post_type && ! ctc_field_supported( 'events', '_ctc_event_address' ) ) 400 | || ( 'ctc_location' == $screen->post_type && ! ctc_field_supported( 'locations', '_ctc_location_address' ) ) 401 | ) { 402 | return $input; 403 | } 404 | 405 | // Only if latitude and longitude fields supported 406 | if ( ! ctc_has_lat_lng_fields() ) { 407 | return $input; 408 | } 409 | 410 | // Append aufofill button 411 | $input .= ' '; 412 | 413 | // Return input with button 414 | return $input; 415 | 416 | } 417 | -------------------------------------------------------------------------------- /includes/helpers.php: -------------------------------------------------------------------------------- 1 | '/' . $utm_base_query . '&utm_campaign=church-theme-content', 88 | 89 | // How to get a Google Maps API key. 90 | 'google-maps-api-key' => '/go/google-maps-api-key/', // no utm, messes up redirect. 91 | 92 | // Church Content product page. 93 | 'church-content' => '/plugins/church-content/' . $utm_base_query . '&utm_campaign=church-theme-content', 94 | 95 | // Church Content Pro product page. 96 | // Pro details are on same page as Church Content plugin. 97 | 'church-content-pro' => '/plugins/church-content-pro/' . $utm_base_query . '&utm_campaign=church_content_pro', 98 | 99 | // How to upgrade from Custom Recurring Events to Pro. 100 | 'cre-to-pro' => '/go/cre-to-pro/' . $utm_base_query . '&utm_campaign=church_content_pro', 101 | 102 | // What SEO Structured Data setting does. 103 | 'seo-setting' => '/go/seo-setting/' . $utm_base_query . '&utm_campaign=church_content_pro&utm_content=settings', 104 | 105 | // How to handle event registration. 106 | 'event-registration' => '/go/ctc-event-registration/' . $utm_base_query . '&utm_campaign=church-theme-content', 107 | 108 | // How to update PHP. 109 | 'update-php' => '/go/update-php/' . $utm_base_query . '&utm_campaign=church-theme-content', 110 | 111 | // URLs for sermon media field descriptions. 112 | 'sermon-video-sites' => '/go/ctc-sermon-video-sites/', // external. 113 | 'sermon-video-help' => '/go/ctc-sermon-video-help/' . $utm_base_query . '&utm_campaign=church-theme-content&utm_content=sermon', 114 | 'sermon-audio-sites' => '/go/ctc-sermon-audio-sites/', // external. 115 | 'sermon-audio-help' => '/go/ctc-sermon-audio-help/' . $utm_base_query . '&utm_campaign=church-theme-content&utm_content=sermon', 116 | 117 | // Podcasting guide. 118 | 'podcast-guide' => '/go/podcast-guide/' . $utm_base_query . '&utm_campaign=church-theme-content', 119 | 120 | // Podcasting submission. 121 | 'podcast-submit-apple' => '/go/apple-podcast-submit/', // no UTM, redirects. add ?url=https://feedurl argument 122 | 'podcast-submit-google' => '/go/google-podcast-submit/', // no UTM, redirects. 123 | 124 | // Agency mode guide. 125 | 'agency-mode' => '/go/agency-mode/', // no UTM, used by theme framework too. 126 | 127 | // Newsletter sign up. 128 | 'newsletter' => '/newsletter/', // no UTM, redirects to Mailchimp page. 129 | 130 | // Blog. 131 | 'blog' => '/blog/' . $utm_base_query . '&utm_campaign=church-theme-content&utm_content=settings', 132 | 133 | // Risen migration guide. 134 | 'migrate-risen' => '/go/switch-from-risen/' . $utm_base_query . '&utm_campaign=migrate-risen', 135 | 'migrate-risen-backup' => '/go/backups/', 136 | 137 | ); 138 | 139 | // Make URL. 140 | if ( isset( $paths[ $path_key ] ) ) { 141 | $url .= $paths[ $path_key ]; 142 | } 143 | 144 | // Add or replace params. 145 | if ( isset( $query_args ) && is_array( $query_args ) ) { 146 | $url = add_query_arg( $query_args, $url ); 147 | } 148 | 149 | // Return filtered. 150 | return apply_filters( 'ctc_ctcom_url', $url, $path_key, $query_args ); 151 | 152 | } 153 | 154 | /** 155 | * Make slug in URL bold. 156 | * 157 | * This is used by settings descriptions for URL slug change examples. 158 | * 159 | * Make https://yourname.com/slug/ into https://yourname.com/slug/ 160 | * 161 | * @since 2.0 162 | * @param string $slug Slug to append to home_url(). 163 | * @return string URL with slug made bold. 164 | */ 165 | function ctc_make_url_slug_bold( $slug ) { 166 | return preg_replace( '/(.*)(\/(.*)\/)$/', '$1/' . $slug . '/', trailingslashit( home_url( $slug ) ) ); 167 | } 168 | 169 | 170 | /** 171 | * Check if string is a URL 172 | * 173 | * @since 2.0 174 | * @param string $string String to check for URL format 175 | * @return bool True if string i=s URL 176 | */ 177 | function ctc_is_url( $string ) { 178 | 179 | $bool = false; 180 | 181 | $url_pattern = '/^(http(s*)):\/\//i'; 182 | 183 | if ( preg_match( $url_pattern, $string ) ) { // URL 184 | $bool = true; 185 | } 186 | 187 | return apply_filters( 'ctc_is_url', $bool, $string ); 188 | 189 | } 190 | 191 | /************************************************* 192 | * STRINGS 193 | *************************************************/ 194 | 195 | /** 196 | * Shorten a string 197 | * 198 | * @since 2.0 199 | * @param string $string String to shorten. 200 | * @param int $length Max length of string. 201 | * @return string Shortened string. 202 | */ 203 | function ctc_shorten( $string, $length ) { 204 | 205 | // Trim. 206 | $string = trim( $string ); 207 | 208 | // Shorten. 209 | $string = mb_substr( $string, 0, $length ); 210 | 211 | // Trim. 212 | $string = trim( $string ); 213 | 214 | // Return. 215 | return apply_filters( 'ctc_shorten', $string, $length ); 216 | 217 | } 218 | 219 | 220 | /** 221 | * Convert to one line 222 | * 223 | * It replaces line breaks with commas. 224 | * 225 | * @since 2.0 226 | * @param string $string Multi-line string. 227 | * @return string Single line string. 228 | */ 229 | function ctc_one_line( $string ) { 230 | 231 | $one_line = $string; 232 | 233 | if ( $string ) { 234 | $one_line = strip_tags( $string ); // remove HTML 235 | $one_line = preg_replace( '/\r\n|\n|\r/', ', ', $one_line ); // replace line breaks with commas 236 | $one_line = trim( $one_line ); // remove whitespace 237 | } 238 | 239 | return apply_filters( 'ctc_one_line', $one_line, $string ); 240 | 241 | } 242 | 243 | /************************************************* 244 | * ARRAYS 245 | *************************************************/ 246 | 247 | /** 248 | * Merge an array into another array after a specific key 249 | * 250 | * Meant for one dimensional associative arrays. 251 | * Used to insert post type overview columns. 252 | * 253 | * @since 0.9 254 | * @param array $original_array Array to merge another into 255 | * @param array $insert_array Array to merge into original 256 | * @param mixed $after_key Key in original array to merge second array after 257 | * @return array Modified array 258 | */ 259 | function ctc_array_merge_after_key( $original_array, $insert_array, $after_key ) { 260 | 261 | $modified_array = array(); 262 | 263 | // loop original array items 264 | foreach ( $original_array as $item_key => $item_value ) { 265 | 266 | // rebuild the array one item at a time 267 | $modified_array[$item_key] = $item_value; 268 | 269 | // insert array after specific key 270 | if ( $item_key == $after_key ) { 271 | $modified_array = array_merge( $modified_array, $insert_array ); 272 | } 273 | 274 | } 275 | 276 | return apply_filters( 'ctc_array_merge_after_key', $modified_array, $original_array, $insert_array, $after_key ); 277 | 278 | } 279 | 280 | /** 281 | * Show array as HTML 282 | * 283 | * This is helpful for development / debugging 284 | * 285 | * @since 1.2 286 | * @param array $array Array to format 287 | * @param bool $return Return or echo output 288 | */ 289 | function ctc_print_array( $array, $return = false ) { 290 | 291 | $result = '' . print_r( $array, true ) . ''; 292 | 293 | if ( empty($return) ) { 294 | echo $result; 295 | } else { 296 | return $result; 297 | } 298 | 299 | } 300 | 301 | /************************************************* 302 | * DATES 303 | *************************************************/ 304 | 305 | /** 306 | * Convert date and time to MySQL DATETIME format 307 | * 308 | * If no date, value will be 0000-00-00 00:00:00 309 | * If no time, value will be 2014-10-28 00:00:00 310 | * 311 | * @since 1.2 312 | * @param string $date Date in YYYY-mm-dd format (e.g. 2014-05-10 for May 5th, 2014) 313 | * @param string $time Time in 24-hour hh-mm format (e.g. 08:00 for 8 AM or 13:12 for 1:12 PM) 314 | * @return string Date and time in DATETIME format (e.g. 2014-05-10 13:12:00) 315 | */ 316 | function ctc_convert_to_datetime( $date, $time ) { 317 | 318 | if ( empty( $date ) ) { 319 | $date = '0000-00-00'; 320 | } 321 | if ( empty( $time ) ) { 322 | $time = '00:00'; 323 | } 324 | 325 | $datetime = $date . ' ' . $time . ':00'; 326 | 327 | return apply_filters( 'ctc_convert_to_datetime', $datetime, $date, $time ); 328 | 329 | } 330 | 331 | /** 332 | * Convert address to one line 333 | * 334 | * It replaces line breaks with commas. 335 | * 336 | * @since 2.0 337 | * @param string $address Multi-line address 338 | * @return string Single line address 339 | */ 340 | function ctc_address_one_line( $address ) { 341 | 342 | $address_one_line = ctc_one_line( $address ); 343 | 344 | return apply_filters( 'ctc_address_one_line', $address_one_line, $address ); 345 | 346 | } 347 | 348 | /************************************************* 349 | * FUNCTIONS 350 | *************************************************/ 351 | 352 | /** 353 | * Check if a function is available 354 | * 355 | * This is helpful: http://bit.ly/100BpPJ 356 | * 357 | * @since 1.2 358 | * @param string $function Name of function to check 359 | * @return bool True if function exists and is not disabled 360 | */ 361 | function ctc_function_available( $function ) { 362 | 363 | $available = false; 364 | 365 | // Function exists? 366 | if ( function_exists( $function ) ) { 367 | 368 | // Is it not disabled in php.ini? 369 | $disabled_functions = explode( ',', ini_get( 'disable_functions' ) ); 370 | if ( ! in_array( $function, $disabled_functions ) ) { 371 | $available = true; 372 | } 373 | 374 | } 375 | 376 | return apply_filters( 'ctc_function_available', $available, $function ); 377 | 378 | } 379 | 380 | /************************************************* 381 | * PLUGINS 382 | *************************************************/ 383 | 384 | /** 385 | * Check if Church Content Pro plugin active. 386 | * 387 | * @since 2.0 388 | * @return bool True if plugin installed and active. 389 | */ 390 | function ctc_pro_is_active() { 391 | 392 | $active = false; 393 | 394 | if ( defined( 'CCP_VERSION' ) ) { 395 | $active = true; 396 | } 397 | 398 | return $active; 399 | 400 | } 401 | 402 | /** 403 | * Check if Custom Recurring Events plugin is active. 404 | * 405 | * @since 2.0 406 | * @return bool True if plugin installed and active. 407 | */ 408 | function ctc_cre_is_active() { 409 | 410 | $active = false; 411 | 412 | if ( defined( 'CTC_CRE_VERSION' ) ) { 413 | $active = true; 414 | } 415 | 416 | return $active; 417 | 418 | } 419 | -------------------------------------------------------------------------------- /includes/support.php: -------------------------------------------------------------------------------- 1 | array( 38 | 'theme_support' => 'ctc-sermons', // theme support feature name 39 | 'post_type' => 'ctc_sermon', // post type feature requires 40 | ), 41 | 42 | 'events' => array( 43 | 'theme_support' => 'ctc-events', 44 | 'post_type' => 'ctc_event', 45 | ), 46 | 47 | 'people' => array( 48 | 'theme_support' => 'ctc-people', 49 | 'post_type' => 'ctc_person', 50 | ), 51 | 52 | 'locations' => array( 53 | 'theme_support' => 'ctc-locations', 54 | 'post_type' => 'ctc_location', 55 | ), 56 | 57 | ); 58 | 59 | // Add feature to array values for ease of use 60 | foreach ( $features as $feature_key => $feature_data ) { 61 | $features[$feature_key]['feature'] = $feature_key; 62 | } 63 | 64 | // Return specific feature 65 | if ( ! empty( $feature ) ) { 66 | if ( isset( $features[$feature] ) ) { // feature data exists 67 | return apply_filters( 'ctc_get_feature_data-' . $feature, $features[$feature] ); 68 | } 69 | } 70 | 71 | // Return all features 72 | else { 73 | return apply_filters( 'ctc_get_feature_data', $features ); 74 | } 75 | 76 | // In case feature given but not valid 77 | return false; 78 | 79 | } 80 | 81 | /** 82 | * Get feature data by post type 83 | * 84 | * @since 0.9 85 | * @param string $post_type Post type to get feature data for 86 | * @return array Feature data 87 | */ 88 | function ctc_get_feature_data_by_post_type( $post_type ) { 89 | 90 | $data = false; 91 | 92 | // Get all features 93 | $features = ctc_get_feature_data(); 94 | 95 | // Loop features to find post type and get feature data 96 | foreach ( $features as $feature_key => $feature_data ) { 97 | 98 | // Post type given used by this feature 99 | if ( $post_type == $feature_data['post_type'] ) { 100 | 101 | $data = $feature_data; 102 | 103 | break; 104 | 105 | } 106 | } 107 | 108 | // Return filterable 109 | return apply_filters( 'ctc_get_feature_data_by_post_type', $data, $post_type ); 110 | 111 | } 112 | 113 | /**************************************** 114 | * THEME SUPPORT 115 | **************************************** 116 | 117 | /** 118 | * Default features for unsupported themes 119 | * 120 | * If no add_theme_support( 'church-theme-content' ), add support for all features with no arguments. 121 | * This causes all content to be revealed in case admin switched to unsupported theme. 122 | * They can then develop the theme for the plugin or retrieve their content. 123 | * 124 | * @since 0.9 125 | */ 126 | function ctc_set_default_theme_support() { 127 | 128 | // Theme does not support plugin 129 | if ( ! current_theme_supports( 'church-theme-content' ) ) { 130 | 131 | // Loop features 132 | $features = ctc_get_feature_data(); 133 | foreach ( $features as $feature_key => $feature_data ) { 134 | 135 | // Add support with no arguments so defaults are used (everything) 136 | add_theme_support( $feature_data['theme_support'] ); 137 | 138 | } 139 | 140 | } 141 | 142 | } 143 | 144 | add_action( 'init', 'ctc_set_default_theme_support', 1 ); // init 1 is right after after_setup_theme when theme add support but earlier than normal plugin init at 10 145 | 146 | /** 147 | * Get theme support data for a feature 148 | * 149 | * Optionally specify an argument to get that data 150 | * 151 | * @since 0.9 152 | * @param string $feature Feature to get theme support data for 153 | * @return mixed Feature data if found 154 | */ 155 | function ctc_get_theme_support( $feature, $argument = null ) { 156 | 157 | $data = false; 158 | 159 | // Theme has support 160 | $support = get_theme_support( $feature ); 161 | if ( $support ) { 162 | 163 | // Get theme support data 164 | $support = isset( $support[0] ) ? $support[0] : false; 165 | 166 | // Use data for specific argument 167 | if ( isset( $argument ) ) { // argument given 168 | if ( is_array( $support ) && isset( $support[$argument] ) ) { // argument is set (even if empty) 169 | $data = $support[$argument]; 170 | } else { 171 | $data = null; // so return value will return false for isset() 172 | } 173 | } 174 | 175 | // Use all arguments 176 | else { 177 | $data = $support; 178 | } 179 | 180 | } 181 | 182 | // Return data 183 | return apply_filters( 'ctc_get_theme_support', $data, $feature, $argument ); 184 | 185 | } 186 | 187 | /** 188 | * Get theme support data based on post type 189 | * 190 | * Optionally specify an argument to get that data. 191 | * 192 | * @since 0.9 193 | * @param string $post_type Post type to get theme support data for. 194 | * @param string $argument Optional feature argument to get specific data for. 195 | * @return mixed Array of all feature data or specific argument 196 | */ 197 | function ctc_get_theme_support_by_post_type( $post_type, $argument = null ) { 198 | 199 | $data = false; 200 | 201 | // Get feature based on post type 202 | $feature_data = ctc_get_feature_data_by_post_type( $post_type ); 203 | if ( $feature_data ) { 204 | 205 | // Get data for feature/argument 206 | $data = ctc_get_theme_support( $feature_data['theme_support'], $argument ); 207 | 208 | } 209 | 210 | // Return data 211 | return apply_filters( 'ctc_get_theme_support_by_post_type', $data, $post_type, $argument ); 212 | 213 | } 214 | 215 | /********************************************* 216 | * FEATURE CHECKING 217 | *********************************************/ 218 | 219 | /** 220 | * Check if feature is supported 221 | * 222 | * @since 0.9 223 | * @param string $feature Feature to check support for 224 | * @return bool True if supported by theme 225 | */ 226 | function ctc_feature_supported( $feature ) { 227 | 228 | $supported = false; 229 | 230 | // Get feature data 231 | $feature_data = ctc_get_feature_data( $feature ); 232 | if ( $feature_data ) { // valid feature returns data 233 | 234 | // Does theme support feature? 235 | if ( current_theme_supports( $feature_data['theme_support'] ) ) { 236 | 237 | $supported = true; 238 | 239 | // (in future could override support via plugin settings here) 240 | 241 | } 242 | 243 | } 244 | 245 | // Return filtered 246 | return apply_filters( 'ctc_feature_supported', $supported, $feature ); 247 | 248 | } 249 | 250 | /** 251 | * Check if taxonomy is supported 252 | * 253 | * @since 0.9 254 | * @param string $feature Feature taxonomy relates to 255 | * @param string $taxonomy Taxonomy to check support for 256 | * @return bool True if feature supported 257 | */ 258 | function ctc_taxonomy_supported( $feature, $taxonomy ) { 259 | 260 | $supported = false; 261 | 262 | // Get feature data 263 | $feature_data = ctc_get_feature_data( $feature ); 264 | if ( $feature_data ) { // valid feature returns data 265 | 266 | // Theme taxonomies are specified 267 | $theme_taxonomies = ctc_get_theme_support( $feature_data['theme_support'], 'taxonomies' ); 268 | if ( isset( $theme_taxonomies ) ) { 269 | 270 | // Taxonomy is explicitly supported 271 | if ( in_array( $taxonomy, (array) $theme_taxonomies ) ) { 272 | $supported = true; 273 | } 274 | 275 | } 276 | 277 | // Theme taxonomies are not specified 278 | // Default is to use all taxonomies when support not explicit, so anything returns true 279 | else { 280 | $supported = true; 281 | } 282 | 283 | // (if true, could override with false using plugin settings here) 284 | // (checking if show_ui is true is not enough since this is used during taxonomy registration) 285 | 286 | } 287 | 288 | // Return filtered 289 | return apply_filters( 'ctc_taxonomy_supported', $supported, $feature, $taxonomy ); 290 | 291 | } 292 | 293 | /** 294 | * Check if field is supported 295 | * 296 | * @since 0.9 297 | * @param string $feature Feature field relates to 298 | * @param string $field Field to check support for 299 | * @return bool True if field supported 300 | */ 301 | function ctc_field_supported( $feature, $field ) { 302 | 303 | $supported = false; 304 | 305 | // Get feature data 306 | $feature_data = ctc_get_feature_data( $feature ); 307 | if ( $feature_data ) { // valid feature returns data 308 | 309 | // Theme fields are specified 310 | $theme_fields = ctc_get_theme_support( $feature_data['theme_support'], 'fields' ); 311 | if ( isset( $theme_fields ) ) { 312 | 313 | // Field is explicitly supported 314 | if ( in_array( $field, (array) $theme_fields ) ) { 315 | $supported = true; 316 | } 317 | 318 | } 319 | 320 | // Theme fields are not specified 321 | // Default is to use all fields when support not explicit, so anything returns true 322 | else { 323 | $supported = true; 324 | } 325 | 326 | // (if true, can override with false using plugin settings here) 327 | 328 | } 329 | 330 | // Return filtered 331 | return apply_filters( 'ctc_field_supported', $supported, $feature, $field ); 332 | 333 | } 334 | 335 | /********************************************* 336 | * FIELD FILTERING 337 | *********************************************/ 338 | 339 | /** 340 | * Filter Meta Box Fields 341 | * 342 | * Add filters for CT_Meta_Box to set visibility and override data on fields 343 | * based on theme support and possibly in future plugin settings. 344 | * 345 | * @since 0.9 346 | */ 347 | function ctc_filter_fields() { 348 | 349 | // Loop features to filter their fields 350 | $features = ctc_get_feature_data(); 351 | foreach ( $features as $feature_key => $feature_data ) { 352 | 353 | // Has post type, filter CT_Meta_Box configs 354 | if ( isset( $feature_data['post_type'] ) ) { 355 | 356 | // Set Visible Fields 357 | add_filter( 'ctmb_visible_fields-' . $feature_data['post_type'], 'ctc_set_visible_fields', 10, 2 ); 358 | 359 | // Set Field Overrides 360 | add_filter( 'ctmb_field_overrides-' . $feature_data['post_type'], 'ctc_set_field_overrides', 10, 2 ); 361 | 362 | } 363 | 364 | } 365 | 366 | } 367 | 368 | add_action( 'init', 'ctc_filter_fields' ); 369 | 370 | /** 371 | * Set visible fields 372 | * 373 | * Show or hide CT_Meta_Box fields for a post type based on add_theme_support. 374 | * Door is open for plugin settings to override in future. 375 | * 376 | * @since 0.9 377 | * @param array $visible_fields Current field visibility 378 | * @param string $post_type Post type this relates to 379 | * @return array Modified $visible_fields 380 | */ 381 | function ctc_set_visible_fields( $visible_fields, $post_type ) { 382 | 383 | // All fields 384 | $original_visible_fields = $visible_fields; 385 | 386 | // Filter visible fields based on theme support 387 | // If not set, all fields are used by default 388 | // If set and empty, all fields will be hidden 389 | $theme_fields = ctc_get_theme_support_by_post_type( $post_type, 'fields' ); 390 | if ( isset( $theme_fields ) ) { 391 | 392 | // Make new array out of fields theme supports 393 | $visible_fields = $theme_fields; 394 | 395 | // Add support for fields that are not from Church Content 396 | // (otherwise they would need to be in add_theme_support arguments) 397 | foreach ( $original_visible_fields as $field ) { 398 | if ( ! preg_match( '/^_ctc_.+$/', $field ) ) { // CTC fields are prefixed by "_ctc_" 399 | $visible_fields[] = $field; 400 | } 401 | } 402 | 403 | } 404 | 405 | // (here plugin settings could disable fields supported by theme) 406 | 407 | // Return default or filtered field list 408 | return $visible_fields; 409 | 410 | } 411 | 412 | /** 413 | * Set field overrides 414 | * 415 | * Override CT_Meta_Box field data for a post type based on add_theme_support. 416 | * 417 | * @since 0.9 418 | * @param array $field_overrides Field overrides to set 419 | * @param string $post_type Post type to set overrides on 420 | * @return mixed Theme support data 421 | */ 422 | function ctc_set_field_overrides( $field_overrides, $post_type ) { 423 | 424 | // Return field overrides, if any 425 | return ctc_get_theme_support_by_post_type( $post_type, 'field_overrides' ); 426 | 427 | } 428 | -------------------------------------------------------------------------------- /includes/post-types.php: -------------------------------------------------------------------------------- 1 | array( 46 | 'name' => esc_html( $plural ), 47 | 'singular_name' => esc_html( $singular ), 48 | 'add_new' => esc_html_x( 'Add New', 'sermon', 'church-theme-content' ), 49 | 'add_new_item' => esc_html( sprintf( 50 | /* translators: %s is singular word for "Sermon", possibly changed via settings. Always use %s and not "Sermon" directly. */ 51 | _x( 'Add %s', 'sermon', 'church-theme-content' ), 52 | $singular 53 | ) ), 54 | 'edit_item' => esc_html( sprintf( 55 | /* translators: %s is singular word for "Sermon", possibly changed via settings. Always use %s and not "Sermon" directly. */ 56 | _x( 'Edit %s', 'sermon', 'church-theme-content' ), 57 | $singular 58 | ) ), 59 | 'new_item' => esc_html( sprintf( 60 | /* translators: %s is singular word for "Sermon", possibly changed via settings. Always use %s and not "Sermon" directly. */ 61 | _x( 'New %s', 'sermon', 'church-theme-content' ), 62 | $singular 63 | ) ), 64 | 'all_items' => esc_html( sprintf( 65 | /* translators: %s is plural word for "Sermons", possibly changed via settings. Always use %s and not "Sermons" directly. */ 66 | _x( 'All %s', 'sermons', 'church-theme-content' ), 67 | $plural 68 | ) ), 69 | 'view_item' => esc_html( sprintf( 70 | /* translators: %s is singular word for "Sermon", possibly changed via settings. Always use %s and not "Sermon" directly. */ 71 | _x( 'View %s', 'sermon', 'church-theme-content' ), 72 | $singular 73 | ) ), 74 | 'view_items' => esc_html( sprintf( 75 | /* translators: %s is plural word for "Sermons", possibly changed via settings. Always use %s and not "Sermons" directly. */ 76 | _x( 'View %s', 'sermons', 'church-theme-content' ), 77 | $plural 78 | ) ), 79 | 'search_items' => esc_html( sprintf( 80 | /* translators: %s is plural word for "Sermons", possibly changed via settings. Always use %s and not "Sermons" directly. */ 81 | _x( 'Search %s', 'sermons', 'church-theme-content' ), 82 | $plural 83 | ) ), 84 | 'not_found' => esc_html( sprintf( 85 | /* translators: %s is lowercase plural word for "sermons", possibly changed via settings. Always use %s and not "sermons" directly. */ 86 | _x( 'No %s found', 'sermons', 'church-theme-content' ), 87 | $plural_lowercase 88 | ) ), 89 | 'not_found_in_trash' => esc_html( sprintf( 90 | /* translators: %s is lowercase plural word for "sermons", possibly changed via settings. Always use %s and not "sermons" directly. */ 91 | _x( 'No %s found in Trash', 'sermons', 'church-theme-content' ), 92 | $plural_lowercase 93 | ) ), 94 | // Note: WordPress now offers additional labels that may be worth defining: https://codex.wordpress.org/Function_Reference/register_post_type#Arguments. 95 | ), 96 | 'public' => ctc_feature_supported( 'sermons' ), 97 | 'has_archive' => ctc_feature_supported( 'sermons' ), 98 | 'rewrite' => array( 99 | 'slug' => 'sermons', 100 | 'with_front' => false, 101 | 'feeds' => ctc_feature_supported( 'sermons' ), 102 | ), 103 | 'supports' => array( 'title', 'editor', 'excerpt', 'publicize', 'thumbnail', 'comments', 'author', 'revisions' ), // 'editor' required for media upload button (see Meta Boxes note below about hiding) 104 | 'taxonomies' => array( 'ctc_sermon_topic', 'ctc_sermon_book', 'ctc_sermon_series', 'ctc_sermon_speaker', 'ctc_sermon_tag' ), 105 | 'menu_icon' => 'dashicons-video-alt3', 106 | 'show_in_rest' => true, 107 | ); 108 | 109 | // Filter arguments. 110 | if ( ! $unfiltered ) { 111 | $args = apply_filters( 'ctc_post_type_sermon_args', $args ); 112 | } 113 | 114 | return $args; 115 | 116 | } 117 | 118 | /** 119 | * Register sermon post type. 120 | * 121 | * @since 0.9 122 | */ 123 | function ctc_register_post_type_sermon() { 124 | 125 | // Arguments. 126 | $args = ctc_post_type_sermon_args(); 127 | 128 | // Registration. 129 | register_post_type( 130 | 'ctc_sermon', 131 | $args 132 | ); 133 | 134 | } 135 | 136 | add_action( 'init', 'ctc_register_post_type_sermon' ); // register post type. 137 | 138 | /** 139 | * "Sermon" singular label from post type. 140 | * 141 | * @since 2.0 142 | * @return string Default, translated or what is set in settings. 143 | */ 144 | function ctc_sermon_word_singular() { 145 | 146 | // Get post type label, possibly changed by Pro settings. 147 | $word = ctc_post_type_label( 'ctc_sermon', 'singular' ); 148 | 149 | // Get default word in case post type not registered yet. 150 | if ( ! $word ) { 151 | $word = _x( 'Sermon', 'post type singular', 'church-theme-content' ); 152 | } 153 | 154 | return $word; 155 | 156 | } 157 | 158 | /** 159 | * "Sermons" plural label from post type. 160 | * 161 | * @since 2.0 162 | * @return string Default, translated or what is set in settings. 163 | */ 164 | function ctc_sermon_word_plural() { 165 | 166 | // Get post type label, possibly changed by Pro settings. 167 | $word = ctc_post_type_label( 'ctc_sermon', 'plural' ); 168 | 169 | // Get default word in case post type not registered yet. 170 | if ( ! $word ) { 171 | $word = _x( 'Sermons', 'post type plural', 'church-theme-content' ); 172 | } 173 | 174 | return $word; 175 | 176 | } 177 | 178 | /********************************** 179 | * EVENT POST TYPE 180 | **********************************/ 181 | 182 | /** 183 | * Event post type arguments. 184 | * 185 | * @since 2.0 186 | * @param bool $unfiltered Set true to return arguments without being filtered. 187 | * @return array Post type registration arguments. 188 | */ 189 | function ctc_post_type_event_args( $unfiltered = false ) { 190 | 191 | // Arguments 192 | $args = array( 193 | 'labels' => array( 194 | 'name' => esc_html_x( 'Events', 'post type general name', 'church-theme-content' ), 195 | 'singular_name' => esc_html_x( 'Event', 'post type singular name', 'church-theme-content' ), 196 | 'add_new' => esc_html_x( 'Add New', 'event', 'church-theme-content' ), 197 | 'add_new_item' => esc_html__( 'Add Event', 'church-theme-content' ), 198 | 'edit_item' => esc_html__( 'Edit Event', 'church-theme-content' ), 199 | 'new_item' => esc_html__( 'New Event', 'church-theme-content' ), 200 | 'all_items' => esc_html__( 'All Events', 'church-theme-content' ), 201 | 'view_item' => esc_html__( 'View Event', 'church-theme-content' ), 202 | 'view_items' => esc_html__( 'View Events', 'church-theme-content' ), 203 | 'search_items' => esc_html__( 'Search Events', 'church-theme-content' ), 204 | 'not_found' => esc_html__( 'No events found', 'church-theme-content' ), 205 | 'not_found_in_trash' => esc_html__( 'No events found in Trash', 'church-theme-content' ) 206 | ), 207 | 'public' => ctc_feature_supported( 'events' ), 208 | 'has_archive' => ctc_feature_supported( 'events' ), 209 | 'rewrite' => array( 210 | 'slug' => 'events', 211 | 'with_front' => false, 212 | 'feeds' => ctc_feature_supported( 'events' ), 213 | ), 214 | 'supports' => array( 'title', 'editor', 'excerpt', 'publicize', 'thumbnail', 'comments', 'author', 'revisions' ), 215 | 'taxonomies' => array( 'ctc_event_category' ), 216 | 'menu_icon' => 'dashicons-calendar', 217 | 'show_in_rest' => true, 218 | ); 219 | 220 | // Filter arguments. 221 | if ( ! $unfiltered ) { 222 | $args = apply_filters( 'ctc_post_type_event_args', $args ); 223 | } 224 | 225 | return $args; 226 | 227 | } 228 | 229 | /** 230 | * Register event post type. 231 | * 232 | * @since 0.9 233 | */ 234 | function ctc_register_post_type_event() { 235 | 236 | // Arguments. 237 | $args = ctc_post_type_event_args(); 238 | 239 | // Registration. 240 | register_post_type( 241 | 'ctc_event', 242 | $args 243 | ); 244 | 245 | } 246 | 247 | add_action( 'init', 'ctc_register_post_type_event' ); // register post type. 248 | 249 | /********************************** 250 | * LOCATION POST TYPE 251 | **********************************/ 252 | 253 | /** 254 | * Location post type arguments. 255 | * 256 | * @since 2.0 257 | * @param bool $unfiltered Set true to return arguments without being filtered. 258 | * @return array Post type registration arguments. 259 | */ 260 | function ctc_post_type_location_args( $unfiltered = false ) { 261 | 262 | // Arguments 263 | $args = array( 264 | 'labels' => array( 265 | 'name' => esc_html_x( 'Locations', 'post type general name', 'church-theme-content' ), 266 | 'singular_name' => esc_html_x( 'Location', 'post type singular name', 'church-theme-content' ), 267 | 'add_new' => esc_html_x( 'Add New', 'location', 'church-theme-content' ), 268 | 'add_new_item' => esc_html__( 'Add Location', 'church-theme-content' ), 269 | 'edit_item' => esc_html__( 'Edit Location', 'church-theme-content' ), 270 | 'new_item' => esc_html__( 'New Location', 'church-theme-content' ), 271 | 'all_items' => esc_html__( 'All Locations', 'church-theme-content' ), 272 | 'view_item' => esc_html__( 'View Location', 'church-theme-content' ), 273 | 'view_items' => esc_html__( 'View Locations', 'church-theme-content' ), 274 | 'search_items' => esc_html__( 'Search Locations', 'church-theme-content' ), 275 | 'not_found' => esc_html__( 'No location found', 'church-theme-content' ), 276 | 'not_found_in_trash' => esc_html__( 'No location found in Trash', 'church-theme-content' ) 277 | ), 278 | 'public' => ctc_feature_supported( 'locations' ), 279 | 'has_archive' => ctc_feature_supported( 'locations' ), 280 | 'rewrite' => array( 281 | 'slug' => 'locations', 282 | 'with_front' => false, 283 | 'feeds' => ctc_feature_supported( 'locations' ), 284 | ), 285 | 'supports' => array( 'title', 'editor', 'excerpt', 'thumbnail', 'page-attributes' ), 286 | 'menu_icon' => 'dashicons-location', 287 | 'show_in_rest' => true, 288 | ); 289 | 290 | // Filter arguments. 291 | if ( ! $unfiltered ) { 292 | $args = apply_filters( 'ctc_post_type_location_args', $args ); 293 | } 294 | 295 | return $args; 296 | 297 | } 298 | 299 | /** 300 | * Register location post type. 301 | * 302 | * @since 0.9 303 | */ 304 | function ctc_register_location_post_type() { 305 | 306 | // Arguments. 307 | $args = ctc_post_type_location_args(); 308 | 309 | // Registration. 310 | register_post_type( 311 | 'ctc_location', 312 | $args 313 | ); 314 | 315 | } 316 | 317 | add_action( 'init', 'ctc_register_location_post_type' ); // register post type. 318 | 319 | /********************************** 320 | * PERSON POST TYPE 321 | **********************************/ 322 | 323 | /** 324 | * Person post type arguments. 325 | * 326 | * @since 2.0 327 | * @param bool $unfiltered Set true to return arguments without being filtered. 328 | * @return array Post type registration arguments. 329 | */ 330 | function ctc_post_type_person_args( $unfiltered = false ) { 331 | 332 | // Arguments 333 | $args = array( 334 | 'labels' => array( 335 | 'name' => esc_html_x( 'People', 'post type general name', 'church-theme-content' ), 336 | 'singular_name' => esc_html_x( 'Person', 'post type singular name', 'church-theme-content' ), 337 | 'add_new' => esc_html_x( 'Add New', 'person', 'church-theme-content' ), 338 | 'add_new_item' => esc_html__( 'Add Person', 'church-theme-content' ), 339 | 'edit_item' => esc_html__( 'Edit Person', 'church-theme-content' ), 340 | 'new_item' => esc_html__( 'New Person', 'church-theme-content' ), 341 | 'all_items' => esc_html__( 'All People', 'church-theme-content' ), 342 | 'view_item' => esc_html__( 'View Person', 'church-theme-content' ), 343 | 'view_items' => esc_html__( 'View People', 'church-theme-content' ), 344 | 'search_items' => esc_html__( 'Search People', 'church-theme-content' ), 345 | 'not_found' => esc_html__( 'No people found', 'church-theme-content' ), 346 | 'not_found_in_trash' => esc_html__( 'No people found in Trash', 'church-theme-content' ) 347 | ), 348 | 'public' => ctc_feature_supported( 'people' ), 349 | 'has_archive' => ctc_feature_supported( 'people' ), 350 | 'rewrite' => array( 351 | 'slug' => 'people', 352 | 'with_front' => false, 353 | 'feeds' => ctc_feature_supported( 'people' ), 354 | ), 355 | 'supports' => array( 'title', 'editor', 'page-attributes', 'thumbnail', 'excerpt' ), 356 | 'taxonomies' => array( 'ctc_person_group' ), 357 | 'menu_icon' => 'dashicons-admin-users', 358 | 'show_in_rest' => true, 359 | ); 360 | 361 | // Filter arguments. 362 | if ( ! $unfiltered ) { 363 | $args = apply_filters( 'ctc_post_type_person_args', $args ); 364 | } 365 | 366 | return $args; 367 | 368 | } 369 | 370 | /** 371 | * Register person post type. 372 | * 373 | * @since 0.9 374 | */ 375 | function ctc_register_post_type_person() { 376 | 377 | // Arguments. 378 | $args = ctc_post_type_person_args(); 379 | 380 | // Registration. 381 | register_post_type( 382 | 'ctc_person', 383 | $args 384 | ); 385 | 386 | } 387 | 388 | add_action( 'init', 'ctc_register_post_type_person' ); // register post type. 389 | 390 | /********************************** 391 | * POST TYPE HELPERS 392 | **********************************/ 393 | 394 | /** 395 | * Get post type label (plural or singular). 396 | * 397 | * This will get the label used when registering post type. 398 | * The value may be the default or what Pro settings provide. 399 | * 400 | * Will return empty if post type not yet registered. 401 | * 402 | * @since 2.0 403 | * @param string $post_type Post type to get label for. 404 | * @param string $form 'singular' or 'plural' (can also leave empty to get plural). 405 | * @return string Singular or plural label for post type. 406 | */ 407 | function ctc_post_type_label( $post_type, $form = false ) { 408 | 409 | // Empty if cannot get name. 410 | $name = ''; 411 | 412 | // Get post type object. 413 | $obj = get_post_type_object( $post_type ); 414 | 415 | // Have object. 416 | if ( ! empty( $obj ) ) { 417 | 418 | // Singular form. 419 | if ( 'singular' === $form && isset( $obj->labels->singular_name ) ) { 420 | $name = $obj->labels->singular_name; 421 | } 422 | 423 | // Plural form. 424 | // If not singular, assume plural. 425 | elseif ( isset( $obj->labels->name ) ) { 426 | $name = $obj->labels->name; 427 | } 428 | 429 | } 430 | 431 | // Return filtered. 432 | return apply_filters( 'ctc_post_type_label', $name ); 433 | 434 | } 435 | -------------------------------------------------------------------------------- /includes/admin/admin-person-fields.php: -------------------------------------------------------------------------------- 1 | 'ctc_person_details', // unique ID 39 | 'title' => _x( 'Person Details', 'meta box', 'church-theme-content' ), 40 | 'post_type' => 'ctc_person', 41 | 'context' => 'normal', // where the meta box appear: normal (left above standard meta boxes), advanced (left below standard boxes), side 42 | 'priority' => 'high', // high, core, default or low (see this: http://www.wproots.com/ultimate-guide-to-meta-boxes-in-wordpress/) 43 | 'callback_args' => array( 44 | '__block_editor_compatible_meta_box' => true, // meta box works in Gutenberg editor. 45 | ), 46 | 47 | // Fields 48 | 'fields' => array( 49 | 50 | // Example 51 | /* 52 | 'option_key' => array( 53 | 'name' => __( 'Field Name', 'church-theme-content' ), 54 | 'after_name' => '', // (Optional), (Required), etc. 55 | 'after_input' => '', // text to show to right of input (fields: text, select, number, range, upload, url, date, time) 56 | 'desc' => __( 'This is the description below the field.', 'church-theme-content' ), 57 | 'type' => 'text', // text, textarea, checkbox, checkbox_multiple, radio, select, number, range, upload, upload_textarea, url, date, time 58 | 'checkbox_label' => '', //show text after checkbox 59 | 'options' => array(), // array of keys/values for radio or select 60 | 'upload_button' => '', // text for button that opens media frame 61 | 'upload_title' => '', // title appearing at top of media frame 62 | 'upload_type' => '', // optional type of media to filter by (image, audio, video, application/pdf) 63 | 'date_multiple' => false, // whether or not to allow date field type to select multiple dates, to be saved as comma-separated list. 64 | 'date_button' => '', // text for button user clicks to open datepicker calendar. 65 | 'default' => '', // value to pre-populate option with (before first save or on reset) 66 | 'no_empty' => false, // if user empties value, force default to be saved instead 67 | 'allow_html' => false, // allow HTML to be used in the value (text, textarea) 68 | 'attributes' => array(), // attr => value array (e.g. set min/max for number or range type) 69 | 'class' => '', // class(es) to add to input (try ctmb-medium, ctmb-small, ctmb-tiny) 70 | 'field_attributes' => array(), // attr => value array for field container 71 | 'field_class' => '', // class(es) to add to field container 72 | 'custom_sanitize' => '', // function to do additional sanitization 73 | 'custom_field' => '', // function for custom display of field input 74 | 'visibility' => array( // show/hide this field based on other fields' values 75 | 'field1' => 'value', // and... 76 | 'field2' => array( 'value', '!=' ), // not having this value 77 | ), 78 | */ 79 | 80 | // Position 81 | '_ctc_person_position' => array( 82 | 'name' => _x( 'Position', 'person meta box', 'church-theme-content' ), 83 | 'after_name' => '', // (Optional), (Required), etc. 84 | 'after_input' => '', // text to show to right of input (fields: text, select, number, range, upload, url, date, time) 85 | 'desc' => __( "Enter the person's position or title (e.g. Senior Pastor, Deacon, etc.)", 'church-theme-content' ), 86 | 'type' => 'text', // text, textarea, checkbox, checkbox_multiple, radio, select, number, range, upload, upload_textarea, url, date, time 87 | 'checkbox_label' => '', //show text after checkbox 88 | 'options' => array(), // array of keys/values for radio or select 89 | 'upload_button' => '', // text for button that opens media frame 90 | 'upload_title' => '', // title appearing at top of media frame 91 | 'upload_type' => '', // optional type of media to filter by (image, audio, video, application/pdf) 92 | 'date_multiple' => false, // whether or not to allow date field type to select multiple dates, to be saved as comma-separated list. 93 | 'date_button' => '', // text for button user clicks to open datepicker calendar. 94 | 'default' => '', // value to pre-populate option with (before first save or on reset) 95 | 'no_empty' => false, // if user empties value, force default to be saved instead 96 | 'allow_html' => false, // allow HTML to be used in the value (text, textarea) 97 | 'attributes' => array(), // attr => value array (e.g. set min/max for number or range type) 98 | 'class' => 'ctmb-medium', // class(es) to add to input (try ctmb-medium, ctmb-small, ctmb-tiny) 99 | 'field_attributes' => array(), // attr => value array for field container 100 | 'field_class' => '', // class(es) to add to field container 101 | 'custom_sanitize' => '', // function to do additional sanitization 102 | 'custom_field' => '', // function for custom display of field input 103 | 'visibility' => array(), // show/hide based on other fields' values: array( array( 'field1' => 'value' ), array( 'field2' => array( 'value', '!=' ) ) 104 | ), 105 | 106 | // Phone 107 | '_ctc_person_phone' => array( 108 | 'name' => __( 'Phone', 'church-theme-content' ), 109 | 'after_name' => '', // (Optional), (Required), etc. 110 | 'after_input' => '', // text to show to right of input (fields: text, select, number, range, upload, url, date, time) 111 | 'desc' => '', 112 | 'type' => 'text', // text, textarea, checkbox, checkbox_multiple, radio, select, number, range, upload, upload_textarea, url, date, time 113 | 'checkbox_label' => '', //show text after checkbox 114 | 'options' => array(), // array of keys/values for radio or select 115 | 'upload_button' => '', // text for button that opens media frame 116 | 'upload_title' => '', // title appearing at top of media frame 117 | 'upload_type' => '', // optional type of media to filter by (image, audio, video, application/pdf) 118 | 'date_multiple' => false, // whether or not to allow date field type to select multiple dates, to be saved as comma-separated list. 119 | 'date_button' => '', // text for button user clicks to open datepicker calendar. 120 | 'default' => '', // value to pre-populate option with (before first save or on reset) 121 | 'no_empty' => false, // if user empties value, force default to be saved instead 122 | 'allow_html' => false, // allow HTML to be used in the value (text, textarea) 123 | 'attributes' => array(), // attr => value array (e.g. set min/max for number or range type) 124 | 'class' => 'ctmb-medium', // class(es) to add to input (try ctmb-medium, ctmb-small, ctmb-tiny) 125 | 'field_attributes' => array(), // attr => value array for field container 126 | 'field_class' => '', // class(es) to add to field container 127 | 'custom_sanitize' => '', // function to do additional sanitization 128 | 'custom_field' => '', // function for custom display of field input 129 | 'visibility' => array(), // show/hide based on other fields' values: array( array( 'field1' => 'value' ), array( 'field2' => array( 'value', '!=' ) ) 130 | ), 131 | 132 | // Email 133 | '_ctc_person_email' => array( 134 | 'name' => __( 'Email', 'church-theme-content' ), 135 | 'after_name' => '', // (Optional), (Required), etc. 136 | 'after_input' => '', // text to show to right of input (fields: text, select, number, range, upload, url, date, time) 137 | 'desc' => '', 138 | 'type' => 'text', // text, textarea, checkbox, checkbox_multiple, radio, select, number, range, upload, upload_textarea, url, date, time 139 | 'checkbox_label' => '', //show text after checkbox 140 | 'options' => array(), // array of keys/values for radio or select 141 | 'upload_button' => '', // text for button that opens media frame 142 | 'upload_title' => '', // title appearing at top of media frame 143 | 'upload_type' => '', // optional type of media to filter by (image, audio, video, application/pdf) 144 | 'date_multiple' => false, // whether or not to allow date field type to select multiple dates, to be saved as comma-separated list. 145 | 'date_button' => '', // text for button user clicks to open datepicker calendar. 146 | 'default' => '', // value to pre-populate option with (before first save or on reset) 147 | 'no_empty' => false, // if user empties value, force default to be saved instead 148 | 'allow_html' => false, // allow HTML to be used in the value (text, textarea) 149 | 'attributes' => array(), // attr => value array (e.g. set min/max for number or range type) 150 | 'class' => 'ctmb-medium', // class(es) to add to input (try ctmb-medium, ctmb-small, ctmb-tiny) 151 | 'field_attributes' => array(), // attr => value array for field container 152 | 'field_class' => '', // class(es) to add to field container 153 | 'custom_sanitize' => 'sanitize_email', // function to do additional sanitization 154 | 'custom_field' => '', // function for custom display of field input 155 | 'visibility' => array(), // show/hide based on other fields' values: array( array( 'field1' => 'value' ), array( 'field2' => array( 'value', '!=' ) ) 156 | ), 157 | 158 | // URLs 159 | '_ctc_person_urls' => array( 160 | 'name' => __( 'URLs', 'church-theme-content' ), 161 | 'after_name' => '', // (Optional), (Required), etc. 162 | 'after_input' => '', // text to show to right of input (fields: text, select, number, range, upload, url, date, time) 163 | 'desc' => '', 164 | 'type' => 'textarea', // text, textarea, checkbox, checkbox_multiple, radio, select, number, range, upload, upload_textarea, url, date, time 165 | 'checkbox_label' => '', //show text after checkbox 166 | 'options' => array(), // array of keys/values for radio or select 167 | 'upload_button' => '', // text for button that opens media frame 168 | 'upload_title' => '', // title appearing at top of media frame 169 | 'upload_type' => '', // optional type of media to filter by (image, audio, video, application/pdf) 170 | 'date_multiple' => false, // whether or not to allow date field type to select multiple dates, to be saved as comma-separated list. 171 | 'date_button' => '', // text for button user clicks to open datepicker calendar. 172 | 'default' => '', // value to pre-populate option with (before first save or on reset) 173 | 'no_empty' => false, // if user empties value, force default to be saved instead 174 | 'allow_html' => false, // allow HTML to be used in the value (text, textarea) 175 | 'attributes' => array(), // attr => value array (e.g. set min/max for number or range type) 176 | 'class' => '', // class(es) to add to input (try ctmb-medium, ctmb-small, ctmb-tiny) 177 | 'field_attributes' => array(), // attr => value array for field container 178 | 'field_class' => '', // class(es) to add to field container 179 | 'custom_sanitize' => '', // function to do additional sanitization 180 | 'custom_field' => '', // function for custom display of field input 181 | 'visibility' => array(), // show/hide based on other fields' values: array( array( 'field1' => 'value' ), array( 'field2' => array( 'value', '!=' ) ) 182 | ), 183 | 184 | ), 185 | 186 | ); 187 | 188 | // Add Meta Box 189 | new CT_Meta_Box( $meta_box ); 190 | 191 | } 192 | 193 | add_action( 'admin_init', 'ctc_add_meta_box_person_details' ); 194 | 195 | /********************************** 196 | * ADMIN COLUMNS 197 | **********************************/ 198 | 199 | /** 200 | * Add/remove list columns 201 | * 202 | * @since 0.9 203 | * @param array $columns Columns to manipulate 204 | * @return array Modified columns 205 | */ 206 | function ctc_person_columns( $columns ) { 207 | 208 | // insert thumbnail after checkbox (before title) 209 | $insert_array = array(); 210 | $insert_array['ctc_person_thumbnail'] = esc_html__( 'Thumbnail', 'church-theme-content' ); 211 | $columns = ctc_array_merge_after_key( $columns, $insert_array, 'cb' ); 212 | 213 | // insert columns after title 214 | $insert_array = array(); 215 | if ( ctc_field_supported( 'people', '_ctc_person_position' ) ) $insert_array['ctc_person_position'] = esc_html__( 'Position', 'church-theme-content' ); 216 | if ( ctc_taxonomy_supported( 'people', 'ctc_person_group' ) ) $insert_array['ctc_person_group'] = esc_html_x( 'Groups', 'people column', 'church-theme-content' ); 217 | $insert_array['ctc_person_order'] = esc_html_x( 'Order', 'sorting', 'church-theme-content' ); 218 | $columns = ctc_array_merge_after_key( $columns, $insert_array, 'title' ); 219 | 220 | //change "title" to "name" 221 | $columns['title'] = esc_html_x( 'Name', 'person', 'church-theme-content' ); 222 | 223 | return $columns; 224 | 225 | } 226 | 227 | add_filter( 'manage_ctc_person_posts_columns' , 'ctc_person_columns' ); // add columns 228 | 229 | /** 230 | * Change person list column content 231 | * 232 | * @since 0.9 233 | * @param string $column Column being worked on 234 | */ 235 | function ctc_person_columns_content( $column ) { 236 | 237 | global $post; 238 | 239 | switch ( $column ) { 240 | 241 | // Thumbnail 242 | case 'ctc_person_thumbnail' : 243 | 244 | if ( has_post_thumbnail() ) { 245 | echo '' . get_the_post_thumbnail( $post->ID, array( 60, 60 ) ) . ''; 246 | } 247 | 248 | break; 249 | 250 | // Position 251 | case 'ctc_person_position' : 252 | 253 | echo strip_tags( get_post_meta( $post->ID , '_ctc_person_position' , true ) ); 254 | 255 | break; 256 | 257 | // Group 258 | case 'ctc_person_group' : 259 | 260 | echo ctc_admin_term_list( $post->ID, 'ctc_person_group' ); 261 | 262 | break; 263 | 264 | // Order 265 | case 'ctc_person_order' : 266 | 267 | echo isset( $post->menu_order ) ? $post->menu_order : ''; 268 | 269 | break; 270 | 271 | } 272 | 273 | } 274 | 275 | add_action( 'manage_posts_custom_column' , 'ctc_person_columns_content' ); // add content for columns 276 | 277 | /** 278 | * Enable sorting for new columns 279 | * 280 | * @since 0.9 281 | * @param array $columns Columns being worked on 282 | * @return array Modified columns 283 | */ 284 | function ctc_person_columns_sorting( $columns ) { 285 | 286 | $columns['ctc_person_position'] = '_ctc_person_position'; 287 | $columns['ctc_person_order'] = 'menu_order'; 288 | 289 | return $columns; 290 | 291 | } 292 | 293 | add_filter( 'manage_edit-ctc_person_sortable_columns', 'ctc_person_columns_sorting' ); // make columns sortable 294 | 295 | /** 296 | * Set how to sort columns (default sorting, custom fields) 297 | * 298 | * @since 0.9 299 | * @param array $args Sorting arguments 300 | * @return array Modified arguments 301 | */ 302 | function ctc_person_columns_sorting_request( $args ) { 303 | 304 | // admin area only 305 | if ( is_admin() ) { 306 | 307 | // Don't run if something causing filter to run when would not normally. 308 | if ( ! function_exists( 'get_current_screen' ) ) { 309 | return; 310 | } 311 | 312 | $screen = get_current_screen(); 313 | 314 | // only on this post type's list 315 | if ( 'ctc_person' == $screen->post_type && 'edit' == $screen->base ) { 316 | 317 | // orderby has been set, tell how to order 318 | if ( isset( $args['orderby'] ) ) { 319 | 320 | switch ( $args['orderby'] ) { 321 | 322 | // Under Name 323 | case '_ctc_person_position' : 324 | 325 | $args['meta_key'] = '_ctc_person_position'; 326 | $args['orderby'] = 'meta_value'; // alphabetically (meta_value_num for numeric) 327 | 328 | break; 329 | 330 | } 331 | 332 | } 333 | 334 | // orderby not set, tell which column to sort by default 335 | else { 336 | $args['orderby'] = 'menu_order'; // sort by Order column by default 337 | $args['order'] = 'ASC'; 338 | } 339 | 340 | } 341 | 342 | } 343 | 344 | return $args; 345 | 346 | } 347 | 348 | add_filter( 'request', 'ctc_person_columns_sorting_request' ); // set how to sort columns 349 | -------------------------------------------------------------------------------- /includes/classes/CTC_EDD_SL_Plugin_Updater.php: -------------------------------------------------------------------------------- 1 | api_url = trailingslashit($_api_url); 52 | $this->api_data = $_api_data; 53 | $this->name = plugin_basename($_plugin_file); 54 | $this->slug = basename($_plugin_file, '.php'); 55 | $this->version = $_api_data['version']; 56 | $this->wp_override = isset($_api_data['wp_override']) ? (bool) $_api_data['wp_override'] : false; 57 | $this->beta = ! empty($this->api_data['beta']) ? true : false; 58 | $this->cache_key = md5(serialize($this->slug . $this->api_data['license'] . $this->beta)); 59 | 60 | $edd_plugin_data[$this->slug] = $this->api_data; 61 | 62 | // Set up hooks. 63 | $this->init(); 64 | } 65 | 66 | /** 67 | * Set up WordPress filters to hook into WP's update process. 68 | * 69 | * @uses add_filter() 70 | * 71 | * @return void 72 | */ 73 | public function init() 74 | { 75 | 76 | add_filter('pre_set_site_transient_update_plugins', array($this, 'check_update')); 77 | add_filter('plugins_api', array($this, 'plugins_api_filter'), 10, 3); 78 | remove_action('after_plugin_row_' . $this->name, 'wp_plugin_update_row', 10); 79 | add_action('after_plugin_row_' . $this->name, array($this, 'show_update_notification'), 10, 2); 80 | add_action('admin_init', array($this, 'show_changelog')); 81 | } 82 | 83 | /** 84 | * Check for Updates at the defined API endpoint and modify the update array. 85 | * 86 | * This function dives into the update API just when WordPress creates its update array, 87 | * then adds a custom API call and injects the custom plugin data retrieved from the API. 88 | * It is reassembled from parts of the native WordPress plugin update code. 89 | * See wp-includes/update.php line 121 for the original wp_update_plugins() function. 90 | * 91 | * @uses api_request() 92 | * 93 | * @param array $_transient_data Update array build by WordPress. 94 | * @return array Modified update array with custom plugin data. 95 | */ 96 | public function check_update($_transient_data) 97 | { 98 | 99 | global $pagenow; 100 | 101 | if (! is_object($_transient_data)) { 102 | $_transient_data = new stdClass; 103 | } 104 | 105 | if ('plugins.php' == $pagenow && is_multisite()) { 106 | return $_transient_data; 107 | } 108 | 109 | if (! empty($_transient_data->response) && ! empty($_transient_data->response[$this->name]) && false === $this->wp_override) { 110 | return $_transient_data; 111 | } 112 | 113 | $version_info = $this->get_cached_version_info(); 114 | 115 | if (false === $version_info) { 116 | $version_info = $this->api_request('plugin_latest_version', array('slug' => $this->slug, 'beta' => $this->beta)); 117 | 118 | $this->set_version_info_cache($version_info); 119 | } 120 | 121 | if (false !== $version_info && is_object($version_info) && isset($version_info->new_version)) { 122 | 123 | if (version_compare($this->version, $version_info->new_version, '<')) { 124 | 125 | $_transient_data->response[$this->name] = $version_info; 126 | } 127 | 128 | $_transient_data->last_checked = current_time('timestamp'); 129 | $_transient_data->checked[$this->name] = $this->version; 130 | } 131 | 132 | return $_transient_data; 133 | } 134 | 135 | /** 136 | * show update notification row -- needed for multisite subsites, because WP won't tell you otherwise! 137 | * 138 | * @param string $file 139 | * @param array $plugin 140 | */ 141 | public function show_update_notification($file, $plugin) 142 | { 143 | 144 | if (is_network_admin()) { 145 | return; 146 | } 147 | 148 | if (! current_user_can('update_plugins')) { 149 | return; 150 | } 151 | 152 | if (! is_multisite()) { 153 | return; 154 | } 155 | 156 | if ($this->name != $file) { 157 | return; 158 | } 159 | 160 | // Remove our filter on the site transient 161 | remove_filter('pre_set_site_transient_update_plugins', array($this, 'check_update'), 10); 162 | 163 | $update_cache = get_site_transient('update_plugins'); 164 | 165 | $update_cache = is_object($update_cache) ? $update_cache : new stdClass(); 166 | 167 | if (empty($update_cache->response) || empty($update_cache->response[$this->name])) { 168 | 169 | $version_info = $this->get_cached_version_info(); 170 | 171 | if (false === $version_info) { 172 | $version_info = $this->api_request('plugin_latest_version', array('slug' => $this->slug, 'beta' => $this->beta)); 173 | 174 | $this->set_version_info_cache($version_info); 175 | } 176 | 177 | if (! is_object($version_info)) { 178 | return; 179 | } 180 | 181 | if (version_compare($this->version, $version_info->new_version, '<')) { 182 | 183 | $update_cache->response[$this->name] = $version_info; 184 | } 185 | 186 | $update_cache->last_checked = current_time('timestamp'); 187 | $update_cache->checked[$this->name] = $this->version; 188 | 189 | set_site_transient('update_plugins', $update_cache); 190 | } else { 191 | 192 | $version_info = $update_cache->response[$this->name]; 193 | } 194 | 195 | // Restore our filter 196 | add_filter('pre_set_site_transient_update_plugins', array($this, 'check_update')); 197 | 198 | if (! empty($update_cache->response[$this->name]) && version_compare($this->version, $version_info->new_version, '<')) { 199 | 200 | // build a plugin list row, with update notification 201 | $wp_list_table = _get_list_table('WP_Plugins_List_Table'); 202 | #