Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
| 1 | <?php |
||
| 11 | class Theme_Options_Container extends Container { |
||
| 12 | |||
| 13 | /** |
||
| 14 | * Array of registered page slugs to verify uniqueness with |
||
| 15 | * |
||
| 16 | * @var array |
||
| 17 | */ |
||
| 18 | protected static $registered_pages = array(); |
||
| 19 | |||
| 20 | /** |
||
| 21 | * Array of container settings |
||
| 22 | * |
||
| 23 | * @var array |
||
| 24 | */ |
||
| 25 | public $settings = array( |
||
| 26 | 'parent' => '', |
||
| 27 | 'file' => '', |
||
| 28 | 'icon' => '', |
||
| 29 | 'position' => null, |
||
| 30 | ); |
||
| 31 | |||
| 32 | /** |
||
| 33 | * {@inheritDoc} |
||
| 34 | */ |
||
| 35 | View Code Duplication | public function __construct( $id, $title, $type, $condition_collection, $condition_translator ) { |
|
| 36 | parent::__construct( $id, $title, $type, $condition_collection, $condition_translator ); |
||
| 37 | |||
| 38 | if ( ! $this->get_datastore() ) { |
||
| 39 | $this->set_datastore( Datastore::make( 'theme_options' ), $this->has_default_datastore() ); |
||
| 40 | } |
||
| 41 | |||
| 42 | if ( apply_filters( 'carbon_fields_' . $type . '_container_admin_only_access', true, $title ) ) { |
||
| 43 | $this->where( 'current_user_capability', '=', 'manage_options' ); |
||
| 44 | } |
||
| 45 | } |
||
| 46 | |||
| 47 | /** |
||
| 48 | * Sanitize a title to a filename |
||
| 49 | * |
||
| 50 | * @param string $title |
||
| 51 | * @return string |
||
| 52 | */ |
||
| 53 | protected function title_to_filename( $title, $extension ) { |
||
| 54 | $title = sanitize_file_name( $title ); |
||
| 55 | $title = strtolower( $title ); |
||
| 56 | $title = remove_accents( $title ); |
||
| 57 | $title = preg_replace( array( |
||
| 58 | '~\s+~', |
||
| 59 | '~[^\w\d-]+~u', |
||
| 60 | '~-+~', |
||
| 61 | ), array( |
||
| 62 | '-', |
||
| 63 | '-', |
||
| 64 | '-', |
||
| 65 | ), $title ); |
||
| 66 | return $title . $extension; |
||
| 67 | } |
||
| 68 | |||
| 69 | /** |
||
| 70 | * Attach container as a theme options page/subpage. |
||
| 71 | */ |
||
| 72 | public function init() { |
||
| 73 | if ( ! $this->settings['file'] ) { |
||
| 74 | $this->settings['file'] = $this->title_to_filename( 'crb_' . $this->get_id(), '.php' ); |
||
| 75 | } |
||
| 76 | |||
| 77 | $registered = $this->register_page(); |
||
| 78 | if ( $registered ) { |
||
| 79 | add_action( 'admin_menu', array( $this, '_attach' ) ); |
||
| 80 | } |
||
| 81 | } |
||
| 82 | |||
| 83 | /** |
||
| 84 | * Checks whether the current save request is valid |
||
| 85 | * |
||
| 86 | * @return bool |
||
| 87 | */ |
||
| 88 | public function is_valid_save() { |
||
| 95 | |||
| 96 | /** |
||
| 97 | * Perform save operation after successful is_valid_save() check. |
||
| 98 | * The call is propagated to all fields in the container. |
||
| 99 | * |
||
| 100 | * @param mixed $user_data |
||
| 101 | */ |
||
| 102 | public function save( $user_data = null ) { |
||
| 103 | try { |
||
| 104 | parent::save( $user_data ); |
||
| 105 | } catch ( Incorrect_Syntax_Exception $e ) { |
||
| 106 | $this->errors[] = $e->getMessage(); |
||
| 107 | } |
||
| 108 | |||
| 109 | do_action( 'carbon_fields_theme_options_container_saved', $user_data, $this ); |
||
| 110 | |||
| 111 | if ( ! headers_sent() ) { |
||
| 112 | wp_redirect( add_query_arg( array( 'settings-updated' => 'true' ) ) ); |
||
| 113 | } |
||
| 114 | } |
||
| 115 | |||
| 116 | /** |
||
| 117 | * Get environment array for page request (in admin) |
||
| 118 | * |
||
| 119 | * @return array |
||
| 120 | */ |
||
| 121 | protected function get_environment_for_request() { |
||
| 124 | |||
| 125 | /** |
||
| 126 | * Perform checks whether the container should be attached during the current request |
||
| 127 | * |
||
| 128 | * @return bool True if the container is allowed to be attached |
||
| 129 | */ |
||
| 130 | public function is_valid_attach_for_request() { |
||
| 133 | |||
| 134 | /** |
||
| 135 | * Get environment array for object id |
||
| 136 | * |
||
| 137 | * @return array |
||
| 138 | */ |
||
| 139 | protected function get_environment_for_object( $object_id ) { |
||
| 142 | |||
| 143 | /** |
||
| 144 | * Check container attachment rules against object id |
||
| 145 | * |
||
| 146 | * @param int $object_id |
||
| 147 | * @return bool |
||
| 148 | */ |
||
| 149 | public function is_valid_attach_for_object( $object_id = null ) { |
||
| 152 | |||
| 153 | /** |
||
| 154 | * Add theme options container pages. |
||
| 155 | * Hook the container saving action. |
||
| 156 | */ |
||
| 157 | public function attach() { |
||
| 158 | // use the "read" capability because conditions will handle actual access and save capability checking |
||
| 159 | // before the attach() method is called |
||
| 160 | |||
| 161 | // Add menu page |
||
| 162 | if ( ! $this->settings['parent'] ) { |
||
| 163 | add_menu_page( |
||
| 164 | $this->title, |
||
| 165 | $this->title, |
||
| 166 | 'read', |
||
| 167 | $this->settings['file'], |
||
| 168 | array( $this, 'render' ), |
||
| 169 | $this->settings['icon'], |
||
| 170 | $this->settings['position'] |
||
| 171 | ); |
||
| 172 | } |
||
| 173 | |||
| 174 | add_submenu_page( |
||
| 175 | $this->settings['parent'], |
||
| 176 | $this->title, |
||
| 177 | $this->title, |
||
| 178 | 'read', |
||
| 179 | $this->settings['file'], |
||
| 180 | array( $this, 'render' ) |
||
| 181 | ); |
||
| 182 | |||
| 183 | $page_hook = get_plugin_page_hookname( $this->settings['file'], '' ); |
||
| 184 | add_action( 'load-' . $page_hook, array( $this, '_save' ) ); |
||
| 185 | } |
||
| 186 | |||
| 187 | /** |
||
| 188 | * Whether this container is currently viewed. |
||
| 189 | * |
||
| 190 | * @return boolean |
||
| 191 | */ |
||
| 192 | public function should_activate() { |
||
| 193 | $input = stripslashes_deep( $_GET ); |
||
| 194 | $request_page = isset( $input['page'] ) ? $input['page'] : ''; |
||
| 195 | if ( ! empty( $request_page ) && $request_page === $this->settings['file'] ) { |
||
| 196 | return true; |
||
| 197 | } |
||
| 198 | |||
| 199 | return false; |
||
| 200 | } |
||
| 201 | |||
| 202 | /** |
||
| 203 | * Output the container markup |
||
| 204 | */ |
||
| 205 | public function render() { |
||
| 214 | |||
| 215 | /** |
||
| 216 | * Register the page while making sure it is unique. |
||
| 217 | * |
||
| 218 | * @return boolean |
||
| 219 | */ |
||
| 220 | protected function register_page() { |
||
| 248 | |||
| 249 | /** |
||
| 250 | * Change the parent theme options page of this container |
||
| 251 | * |
||
| 252 | * @return Container $this |
||
| 253 | */ |
||
| 254 | public function set_page_parent( $parent ) { |
||
| 263 | |||
| 264 | /** |
||
| 265 | * Set the theme options file name of this container. |
||
| 266 | * |
||
| 267 | * @return Container $this |
||
| 268 | */ |
||
| 269 | public function set_page_file( $file ) { |
||
| 273 | |||
| 274 | /** |
||
| 275 | * Set the page position of this container in the administration menu. |
||
| 276 | * |
||
| 277 | * @return Container $this |
||
| 278 | */ |
||
| 279 | public function set_page_position( $position ) { |
||
| 283 | |||
| 284 | /** |
||
| 285 | * Set the icon of this theme options page. |
||
| 286 | * Applicable only for parent theme option pages. |
||
| 287 | * |
||
| 288 | * @return Container $this |
||
| 289 | */ |
||
| 290 | public function set_icon( $icon ) { |
||
| 294 | } |
||
| 295 |