labels->singular_name) ? (string) $object->labels->singular_name : ''; if (trim($label) === '') return __('post', 'wpbr-bulk-replace'); return wpbr_lowercase_label($label); } /** * The plural label for a post type, lowercased for use inside a sentence. * * @return string e.g. "products", "employees", or "posts" */ function wpbr_post_type_label_plural($post_type = '') { $object = wpbr_post_type_object($post_type); if (!$object) return __('posts', 'wpbr-bulk-replace'); $label = isset($object->labels->name) ? (string) $object->labels->name : ''; if (trim($label) === '') return __('posts', 'wpbr-bulk-replace'); return wpbr_lowercase_label($label); } /** * Title-case for a column header or the start of a sentence. * * @return string e.g. "Product", "Employee", or "Post" */ function wpbr_post_type_label_title($post_type = '') { $object = wpbr_post_type_object($post_type); if (!$object || !isset($object->labels->singular_name) || trim((string) $object->labels->singular_name) === '') { return __('Post', 'wpbr-bulk-replace'); } return (string) $object->labels->singular_name; } /** * How to name a configured post type in a settings or listing column. * * Returns the registered label when the type exists, and the raw slug when it * does not. That fallback matters: a batch configured against a post type whose * plugin has since been deactivated would otherwise display as "Post", quietly * replacing the real configuration with a plausible-looking wrong answer. The * slug is less friendly and it is true. * * @param string $post_type * @return string Empty string when nothing is configured. */ function wpbr_post_type_display($post_type) { $post_type = trim((string) $post_type); if ($post_type === '') return ''; $object = wpbr_post_type_object($post_type); if (!$object || !isset($object->labels->singular_name) || trim((string) $object->labels->singular_name) === '') { return $post_type; } return (string) $object->labels->singular_name; } /** * Lowercase a label unless it looks like a proper noun or an acronym. * * "Product" reads better as "product" mid-sentence. "FAQ" lowercased reads as * a typo, and "Case Study" or "the Gazette" lowercased reads as a different * thing from the name the site chose. * * The signal is a capital *after the first word*. A label's first word is * capitalised by WordPress convention whatever kind of word it is, so it * carries no information; a capital anywhere later was a deliberate choice, * which means a name. */ function wpbr_lowercase_label($label) { $label = trim($label); if ($label === '') return $label; $words = preg_split('/\s+/', $label); // An all-caps word of two or more letters is an acronym. Leave it alone. foreach ($words as $word) { if (wpbr_label_word_length($word) > 1 && $word === wpbr_label_upper($word) && preg_match('/\p{Lu}/u', $word)) { return $label; } } // A capital after the first word means the label is a name. foreach (array_slice($words, 1) as $word) { if ($word !== '' && preg_match('/^\p{Lu}/u', $word)) return $label; } return wpbr_label_lower($label); } /** Multibyte-aware helpers, degrading to the byte versions where ext/mbstring is absent. */ function wpbr_label_lower($s) { return function_exists('mb_strtolower') ? mb_strtolower($s, 'UTF-8') : strtolower($s); } function wpbr_label_upper($s) { return function_exists('mb_strtoupper') ? mb_strtoupper($s, 'UTF-8') : strtoupper($s); } function wpbr_label_word_length($s) { return function_exists('mb_strlen') ? mb_strlen($s, 'UTF-8') : strlen($s); } /** * The post type object, or null when there is nothing specific to speak about. */ function wpbr_post_type_object($post_type) { $post_type = trim((string) $post_type); if ($post_type === '' || $post_type === 'any') return null; if (!function_exists('get_post_type_object')) return null; $object = get_post_type_object($post_type); return $object ? $object : null; } /** * The site's own date-and-time format. * * Timestamps sit next to dates WordPress itself renders, so they follow the * reader's Settings > General choice rather than a format hardcoded here. * mysql2date() then also runs the result through the active locale, which a * literal like 'M j, Y' would leave in English. */ function wpbr_datetime_format() { return get_option('date_format', 'M j, Y') . ' ' . get_option('time_format', 'g:i a'); }