/** * Respond to Javascript callbacks * The name of this method is action_ajax_ followed by what you passed to the context parameter above. */ public function action_ajax_auto_tags( $handler ) { $selected = array(); if( isset( $handler->handler_vars['selected'] ) ) { $selected = Utils::single_array( $handler->handler_vars['selected'] ); } if( isset( $handler->handler_vars['term'] ) && MultiByte::strlen( $handler->handler_vars['term'] ) ) { $search = $handler->handler_vars['term'] . '%'; $tags = new Terms( DB::get_results( "SELECT * FROM {terms} WHERE vocabulary_id = :vid and LOWER(term_display) LIKE LOWER(:crit) ORDER BY term_display ASC", array( 'vid' => Tags::vocabulary()->id, 'crit' => $search ), 'Term' ) ); } else { $tags = Tags::vocabulary()->get_tree( 'term_display ASC' ); } $resp = array(); foreach ( $tags as $tag ) { $resp[] = MultiByte::strpos( $tag->term_display, ',' ) === false ? $tag->term_display : $tag->tag_text_searchable; } if( count( $selected ) ) { $resp = array_diff($resp, $selected ); } // Send the response // $ar = new AjaxResponse(); // $ar->data = $resp; // $ar->out(); echo json_encode( $resp ); }
public function parse_htpasswd($passwdfile) { $lines = file($passwdfile); $users = array(); $i = 0; foreach ($lines as $line) { // if there is no :, assume this is a username with a newline if (MultiByte::strpos($line, ':') === false) { // append the next line to it $line = $line . $lines[$i + 1]; // unset the next line unset($lines[$i + 1]); } list($username, $password) = explode(':', $line); // trim the username and password $username = trim($username); $password = trim($password); if ($username == '' || $password == '') { continue; } $users[$username] = $password; $i++; } return $users; }
public function test_strpos() { // these are exact duplicates of test_strpos(), but the equality is now not_equal // there should probably be a better effort to come up with a meaningful test // make sure a simple strpos works $this->assert_not_equal(MultiByte::strpos($this->test_strings['lowercase'], $this->test_strings['strpos']), 2); $this->assert_equal(MultiByte::strpos($this->test_strings['international'], $this->test_strings['strpos2']), 2); // this one works because the characters before it are native! // make sure a strpos with an offset works $this->assert_not_equal(MultiByte::strpos($this->test_strings['lowercase'], $this->test_strings['strpos'], 1), 2); $this->assert_not_equal(MultiByte::strpos($this->test_strings['international'], $this->test_strings['strpos2'], 4), 12); // make sure a non-esistant strpos works - the character does not exist after the offset $this->assert_not_equal(MultiByte::strpos($this->test_strings['lowercase'], $this->test_strings['strpos'], 3), false); $this->assert_not_equal(MultiByte::strpos($this->test_strings['international'], $this->test_strings['strpos2'], 14), false); // and perform a single test with an ascii string for code coverage - this one should still work fine! $this->assert_equal(MultiByte::strpos('abcd', 'c', null, 'ascii'), 2); }
/** * Either just display the login form; or check a user's credentials, and * create a session for them; or handle a password reset request. */ public function act_login() { // If we're a reset password request, do that. if (isset($_POST['submit_button']) && $_POST['submit_button'] === _t('Reset password')) { Utils::check_request_method(array('POST')); $name = $this->handler_vars['habari_username']; if ($name !== NULL) { if (!is_numeric($name) && ($user = User::get($name))) { $hash = Utils::random_password(); $user->info->password_reset = md5($hash); $user->info->commit(); $message = _t('Please visit %1$s to reset your password.', array(URL::get('user', array('page' => 'password_reset', 'id' => $user->id, 'hash' => $hash)))); Utils::mail($user->email, _t('[%1$s] Password reset request for %2$s', array(Options::get('title'), $user->displayname)), $message); } // Moving this inside the check for user existence would allow attackers to test usernames, so don't Session::notice(_t('A password reset request has been sent to the user.')); } } else { Utils::check_request_method(array('GET', 'HEAD', 'POST')); $name = $_POST['habari_username']; $pass = $_POST['habari_password']; if (NULL != $name || NULL != $pass) { $user = User::authenticate($name, $pass); if ($user instanceof User && FALSE != $user) { /* Successfully authenticated. */ // Timestamp last login date and time. $user->info->authenticate_time = date('Y-m-d H:i:s'); $user->update(); // Remove left over expired session error message. if (Session::has_errors('expired_session')) { Session::remove_error('expired_session'); } $login_session = Session::get_set('login'); if (!empty($login_session)) { /* Now that we know we're dealing with the same user, transfer the form data so he does not lose his request */ if (!empty($login_session['post_data'])) { Session::add_to_set('last_form_data', $last_form_data['post'], 'post'); } if (!empty($login_session['get_data'])) { Session::add_to_set('last_form_data', $last_form_data['get'], 'get'); } /* Redirect to the correct admin page */ $dest = explode('/', MultiByte::substr($login_session['original'], MultiByte::strpos($login_session['original'], 'admin/'))); if ('' == $dest[0]) { $login_dest = Site::get_url('admin'); } else { // Replace '?' with '&' in $dest[1] before call URL::get() // Therefore calling URL::get() with a query string $dest[1] = str_replace('?', '&', $dest[1]); $login_dest = URL::get('admin', 'page=' . $dest[1]); } } else { $login_session = null; $login_dest = Site::get_url('admin'); } // filter the destination $login_dest = Plugins::filter('login_redirect_dest', $login_dest, $user, $login_session); // finally, redirect to the destination Utils::redirect($login_dest); return TRUE; } /* Authentication failed. */ // Remove submitted password, see, we're secure! $_POST['habari_password'] = ''; $this->handler_vars['error'] = _t('Bad credentials'); } } // Display the login form. $this->login_form($name); }
/** * get_dir returns a complete filesystem path to the requested item * 'config_file' returns the complete path to the config.php file, including the filename * 'config' returns the path of the directory containing config.php * 'user' returns the path of the user directory * 'theme' returns the path of the site's active theme * @param string the name of the path item to return * @param bool whether to include a trailing slash. Default: No * @return string Path */ public static function get_dir( $name, $trail = false ) { $path = ''; switch ( strtolower( $name ) ) { case 'config_file': $path = Site::get_dir( 'config' ) . '/config.php'; break; case 'config': if ( self::$config_path ) { return self::$config_path; } self::$config_path = HABARI_PATH; $config_dirs = preg_replace( '/^' . preg_quote( HABARI_PATH, '/' ) . '\/user\/sites\/(.*)\/config.php/', '$1', Utils::glob( HABARI_PATH . '/user/sites/*/config.php' ) ); if ( empty( $config_dirs ) ) { return self::$config_path; } $server = InputFilter::parse_url( Site::get_url( 'habari' ) ); $server = ( isset( $server['port'] ) ) ? $server['port'] . '.' . $server['host'] . '.' : $server['host'] . '.'; $request = explode( '/', trim( $_SERVER['REQUEST_URI'], '/' ) ); $match = trim( $server, '.' ); $x = count( $request ); do { if ( in_array( $match, $config_dirs ) ) { self::$config_dir = $match; self::$config_path = HABARI_PATH . '/user/sites/' . self::$config_dir; self::$config_type = ( $x > 0 ) ? Site::CONFIG_SUBDOMAIN : Site::CONFIG_SUBDIR; break; } $match = MultiByte::substr( $match, MultiByte::strpos( $match, '.' ) + 1 ); $x--; } while ( MultiByte::strpos( $match, '.' ) !== false ); $path = self::$config_path; break; case 'user': if ( Site::get_dir( 'config' ) == HABARI_PATH ) { $path = HABARI_PATH . '/user'; } else { $path = Site::get_dir( 'config' ); } break; case 'theme': $theme = Themes::get_theme_dir(); if ( file_exists( Site::get_dir( 'config' ) . '/themes/' . $theme ) ) { $path = Site::get_dir( 'user' ) . '/themes/' . $theme; } elseif ( file_exists( HABARI_PATH . '/user/themes/' . $theme ) ) { $path = HABARI_PATH . '/user/themes/' . $theme; } elseif ( file_exists( HABARI_PATH . '/3rdparty/themes/' . $theme ) ) { $url = Site::get_url( 'habari' ) . '/3rdparty/themes/' . $theme; } else { $path = HABARI_PATH . '/system/themes/' . $theme; } break; case 'admin_theme': $path = HABARI_PATH . '/system/admin'; break; case 'vendor': $path = HABARI_PATH . '/system/vendor'; break; } $path .= Utils::trail( $trail ); $path = Plugins::filter( 'site_dir_' . $name, $path ); return $path; }
/** * Returns a form for editing this post * @param string $context The context the form is being created in, most often 'admin' * @return FormUI A form appropriate for creating and updating this post. */ public function get_form($context) { $form = new FormUI('create-content'); $form->class[] = 'create'; $newpost = 0 === $this->id; // If the post has already been saved, add a link to its permalink if (!$newpost) { $post_links = $form->append('wrapper', 'post_links'); $permalink = $this->status != Post::status('published') ? $this->permalink . '?preview=1' : $this->permalink; $post_links->append('static', 'post_permalink', '<a href="' . $permalink . '" class="viewpost" >' . ($this->status != Post::status('published') ? _t('Preview Post') : _t('View Post')) . '</a>'); $post_links->class = 'container'; } // Store this post instance into a hidden field for later use when saving data $form->append('hidden', 'post', $this, _t('Title'), 'admincontrol_text'); // Create the Title field $form->append('text', 'title', 'null:null', _t('Title'), 'admincontrol_text'); $form->title->class[] = 'important'; $form->title->class[] = 'check-change'; $form->title->tabindex = 1; $form->title->value = $this->title_internal; // Create the silos if (count(Plugins::get_by_interface('MediaSilo'))) { $form->append('silos', 'silos'); $form->silos->silos = Media::dir(); } // Create the Content field $form->append('textarea', 'content', 'null:null', _t('Content'), 'admincontrol_textarea'); $form->content->class[] = 'resizable'; $form->content->class[] = 'check-change'; $form->content->tabindex = 2; $form->content->value = $this->content_internal; $form->content->raw = true; // Create the tags field $form->append('text', 'tags', 'null:null', _t('Tags, separated by, commas'), 'admincontrol_text'); $form->tags->class = 'check-change'; $form->tags->tabindex = 3; $tags = (array) $this->get_tags(); array_walk($tags, function (&$element, $key) { $element->term_display = MultiByte::strpos($element->term_display, ',') === false ? $element->term_display : $element->tag_text_searchable; }); $form->tags->value = implode(', ', $tags); // Create the splitter $publish_controls = $form->append('tabs', 'publish_controls'); // Create the publishing controls // pass "false" to list_post_statuses() so that we don't include internal post statuses $statuses = Post::list_post_statuses($this); unset($statuses[array_search('any', $statuses)]); $statuses = Plugins::filter('admin_publish_list_post_statuses', $statuses); $settings = $publish_controls->append('fieldset', 'settings', _t('Settings')); $settings->append('select', 'status', 'null:null', _t('Content State'), array_flip($statuses), 'tabcontrol_select'); $settings->status->value = $this->status; // hide the minor edit checkbox if the post is new if ($newpost) { $settings->append('hidden', 'minor_edit', 'null:null'); $settings->minor_edit->value = false; } else { $settings->append('checkbox', 'minor_edit', 'null:null', _t('Minor Edit'), 'tabcontrol_checkbox'); $settings->minor_edit->value = true; $form->append('hidden', 'modified', 'null:null')->value = $this->modified; } $settings->append('checkbox', 'comments_enabled', 'null:null', _t('Comments Allowed'), 'tabcontrol_checkbox'); $settings->comments_enabled->value = $this->info->comments_disabled ? false : true; $settings->append('text', 'pubdate', 'null:null', _t('Publication Time'), 'tabcontrol_text'); $settings->pubdate->value = $this->pubdate->format('Y-m-d H:i:s'); $settings->pubdate->helptext = _t('YYYY-MM-DD HH:MM:SS'); $settings->append('hidden', 'updated', 'null:null'); $settings->updated->value = $this->updated->int; $settings->append('text', 'newslug', 'null:null', _t('Content Address'), 'tabcontrol_text'); $settings->newslug->id = 'newslug'; $settings->newslug->value = $this->slug; // Create the button area $buttons = $form->append('fieldset', 'buttons'); $buttons->template = 'admincontrol_buttons'; $buttons->class[] = 'container'; $buttons->class[] = 'buttons'; $buttons->class[] = 'publish'; // Create the Save button $require_any = array('own_posts' => 'create', 'post_any' => 'create', 'post_' . Post::type_name($this->content_type) => 'create'); if ($newpost && User::identify()->can_any($require_any) || !$newpost && ACL::access_check($this->get_access(), 'edit')) { $buttons->append('submit', 'save', _t('Save'), 'admincontrol_submit'); $buttons->save->tabindex = 4; } // Add required hidden controls $form->append('hidden', 'content_type', 'null:null'); $form->content_type->id = 'content_type'; $form->content_type->value = $this->content_type; $form->append('hidden', 'post_id', 'null:null'); $form->post_id->id = 'id'; $form->post_id->value = $this->id; $form->append('hidden', 'slug', 'null:null'); $form->slug->value = $this->slug; $form->slug->id = 'originalslug'; $form->on_success(array($this, 'form_publish_success')); // Let plugins alter this form Plugins::act('form_publish', $form, $this, $context); $content_types = array_flip(Post::list_active_post_types()); Plugins::act('form_publish_' . Utils::slugify($content_types[$this->content_type], '_'), $form, $this, $context); // Return the form object return $form; }
/** * Handles AJAX requests from media silos. */ public function ajax_media($handler_vars) { Utils::check_request_method(array('POST')); $path = $handler_vars['path']; $rpath = $path; $silo = Media::get_silo($rpath, true); // get_silo sets $rpath by reference to the path inside the silo $assets = Media::dir($path); $output = array('ok' => 1, 'dirs' => array(), 'files' => array(), 'path' => $path); foreach ($assets as $asset) { if ($asset->is_dir) { $output['dirs'][$asset->basename] = $asset->get_props(); } else { $output['files'][$asset->basename] = $asset->get_props(); } } $rootpath = MultiByte::strpos($path, '/') !== false ? MultiByte::substr($path, 0, MultiByte::strpos($path, '/')) : $path; $controls = array('root' => '<a href="#" onclick="habari.media.fullReload();habari.media.showdir(\'' . $rootpath . '\');return false;">' . _t('Root') . '</a>'); $controls = Plugins::filter('media_controls', $controls, $silo, $rpath, ''); $controls_out = ''; foreach ($controls as $k => $v) { if (is_numeric($k)) { $controls_out .= "<li>{$v}</li>"; } else { $controls_out .= "<li class=\"{$k}\">{$v}</li>"; } } $output['controls'] = $controls_out; echo json_encode($output); }
/** * Grabs post data and inserts that data into the internal * handler_vars array, which eventually gets extracted into * the theme's ( and thereby the template_engine's ) local * symbol table for use in the theme's templates * * This is the default, generic function to grab posts. To * "filter" the posts retrieved, simply pass any filters to * the handler_vars variables associated with the post retrieval. * For instance, to filter by tag, ensure that handler_vars['tag'] * contains the tag to filter by. Simple as that. */ public function act_display($paramarray = array('user_filters' => array())) { Utils::check_request_method(array('GET', 'HEAD', 'POST')); // Get any full-query parameters $possible = array('user_filters', 'fallback', 'posts', 'post', 'content_type'); foreach ($possible as $varname) { if (isset($paramarray[$varname])) { ${$varname} = $paramarray[$varname]; } } /** * Since handler_vars no longer contains $_GET and $_POST, we have broken out our valid filters into * an array based upon where we should expect them to be. We then only merge those specific pieces together. * * These are ordered so that handler vars gets overwritten by POST, which gets overwritten by GET, should the * same key exist multiple places. This seemed logical to me at the time, but needs further thought. */ $where_filters = array(); $where_filters_hv = Controller::get_handler_vars()->filter_keys($this->valid_filters['handler_vars']); $where_filters_post = $_POST->filter_keys($this->valid_filters['POST']); $where_filters_get = $_GET->filter_keys($this->valid_filters['GET']); $where_filters = $where_filters_hv->merge($where_filters_post, $where_filters_get); $where_filters['vocabulary'] = array(); if (array_key_exists('tag', $where_filters)) { $tags = Tags::parse_url_tags($where_filters['tag']); $not_tag = $tags['exclude_tag']; $all_tag = $tags['include_tag']; if (count($not_tag) > 0) { $where_filters['vocabulary'] = array_merge($where_filters['vocabulary'], array(Tags::vocabulary()->name . ':not:term' => $not_tag)); } if (count($all_tag) > 0) { $where_filters['vocabulary'] = array_merge($where_filters['vocabulary'], array(Tags::vocabulary()->name . ':all:term' => $all_tag)); } $where_filters['tag_slug'] = Utils::slugify($where_filters['tag']); unset($where_filters['tag']); } if (!isset($_GET['preview'])) { $where_filters['status'] = Post::status('published'); } if (!isset($posts)) { $user_filters = Plugins::filter('template_user_filters', $user_filters); // Work around the tags parameters to Posts::get() being subsumed by the vocabulary parameter if (isset($user_filters['not:tag'])) { $user_filters['vocabulary'] = array(Tags::vocabulary()->name . ':not:term' => $user_filters['not:tag']); unset($user_filters['not:tag']); } if (isset($user_filters['tag'])) { $user_filters['vocabulary'] = array(Tags::vocabulary()->name . ':term_display' => $user_filters['tag']); unset($user_filters['tag']); } $where_filters = $where_filters->merge($user_filters); $where_filters = Plugins::filter('template_where_filters', $where_filters); $posts = Posts::get($where_filters); } $this->assign('posts', $posts); if ($posts !== false && count($posts) > 0) { if (count($posts) == 1) { $post = $posts instanceof Post ? $posts : reset($posts); Stack::add('body_class', Post::type_name($post->content_type) . '-' . $post->id); Stack::add('body_class', 'single'); } else { $post = reset($posts); Stack::add('body_class', 'multiple'); } $this->assign('post', $post); $type = Post::type_name($post->content_type); } elseif ($posts === false || isset($where_filters['page']) && $where_filters['page'] > 1 && count($posts) == 0) { if ($this->template_exists('404')) { $fallback = array('404'); // Replace template variables with the 404 rewrite rule $this->request->{URL::get_matched_rule()->name} = false; $this->request->{URL::set_404()->name} = true; $this->matched_rule = URL::get_matched_rule(); // 404 status header sent in act_display_404, but we're past // that, so send it now. header('HTTP/1.1 404 Not Found', true, 404); } else { $this->display('header'); echo '<h2>'; _e("Whoops! 404. The page you were trying to access is not really there. Please try again."); echo '</h2>'; header('HTTP/1.1 404 Not Found', true, 404); $this->display('footer'); die; } } $extract = $where_filters->filter_keys('page', 'type', 'id', 'slug', 'posttag', 'year', 'month', 'day', 'tag', 'tag_slug'); foreach ($extract as $key => $value) { ${$key} = $value; } $this->assign('page', isset($page) ? $page : 1); if (!isset($fallback)) { // Default fallbacks based on the number of posts $fallback = array('{$type}.{$id}', '{$type}.{$slug}', '{$type}.tag.{$posttag}'); if (count($posts) > 1) { $fallback[] = '{$type}.multiple'; $fallback[] = 'multiple'; } else { $fallback[] = '{$type}.single'; $fallback[] = 'single'; } } $searches = array('{$id}', '{$slug}', '{$year}', '{$month}', '{$day}', '{$type}', '{$tag}'); $replacements = array(isset($post) && $post instanceof Post ? $post->id : '-', isset($post) && $post instanceof Post ? $post->slug : '-', isset($year) ? $year : '-', isset($month) ? $month : '-', isset($day) ? $day : '-', isset($type) ? $type : '-', isset($tag_slug) ? $tag_slug : '-'); $fallback[] = 'home'; $fallback = Plugins::filter('template_fallback', $fallback, $posts, isset($post) ? $post : null); $fallback = array_values(array_unique(MultiByte::str_replace($searches, $replacements, $fallback))); for ($z = 0; $z < count($fallback); $z++) { if (MultiByte::strpos($fallback[$z], '{$posttag}') !== false && isset($post) && $post instanceof Post) { $replacements = array(); if ($alltags = $post->tags) { foreach ($alltags as $current_tag) { $replacements[] = MultiByte::str_replace('{$posttag}', $current_tag->term, $fallback[$z]); } array_splice($fallback, $z, 1, $replacements); } else { break; } } } return $this->display_fallback($fallback); }
public function testStrpos ( ) { // make sure a simple strpos works $this->assertEquals( MultiByte::strpos( $this->test_strings['lowercase'], $this->test_strings['strpos'] ), 2 ); $this->assertEquals( MultiByte::strpos( $this->test_strings['international'], $this->test_strings['strpos2'] ), 2 ); // make sure a strpos with an offset works $this->assertEquals( MultiByte::strpos( $this->test_strings['lowercase'], $this->test_strings['strpos'], 1 ), 2 ); $this->assertEquals( MultiByte::strpos( $this->test_strings['international'], $this->test_strings['strpos2'], 4 ), 12 ); // make sure a non-esistant strpos works - the character does not exist after the offset $this->assertEquals( MultiByte::strpos( $this->test_strings['lowercase'], $this->test_strings['strpos'], 3 ), false ); $this->assertEquals( MultiByte::strpos( $this->test_strings['international'], $this->test_strings['strpos2'], 14 ), false ); // and perform a single test with an ascii string for code coverage $this->assertEquals( MultiByte::strpos( 'abcd', 'c', null, 'ascii' ), 2 ); }
/** * Match a URL/URI against the rewrite rules stored in the DB. * This method is used by the Controller class for parsing * requests, and by other classes, such as Pingback, which * uses it to determine the post slug for a given URL. * * Returns the matched RewriteRule object, or false. * * @param string $from_url URL string to parse * @return \Habari\RewriteRule matched rule, or false */ public static function parse($from_url) { $base_url = Site::get_path('base', true); /* * Strip out the base URL from the requested URL * but only if the base URL isn't / */ if (strpos($from_url, $base_url) === 0) { $from_url = MultiByte::substr($from_url, MultiByte::strlen($base_url)); } /* Trim off any leading or trailing slashes */ $from_url = trim($from_url, '/'); /* Remove the querystring from the URL */ if (MultiByte::strpos($from_url, '?') !== false) { list($from_url, ) = explode('?', $from_url); } $url = URL::instance(); $url->load_rules(); // Cached in singleton /* * Run the stub through the regex matcher */ self::$stub = $from_url; /** @var RewriteRule $rule */ foreach ($url->rules as $rule) { if ($rule->match($from_url)) { $url->matched_rule = $rule; /* Stop processing at first matched rule... */ return $rule; } } return false; }
/** * Returns a form for editing this post * @param string $context The context the form is being created in, most often 'admin' * @return FormUI A form appropriate for creating and updating this post. */ public function get_form($context) { /** @var FormUI $form */ $form = new FormUI('create-content', null, array('class' => array('create'))); $form->set_wrap_each('<div class="container">%s</div>'); $newpost = 0 === $this->id; // If the post has already been saved, add a link to its permalink if (!$newpost) { /** @var FormControlWrapper $post_links */ $post_links = $form->append(FormControlWrapper::create('post_links', null, array('class' => 'container'))); $permalink = $this->status != Post::status('published') ? $this->permalink . '?preview=1' : $this->permalink; $post_links->append(FormControlStatic::create('post_permalink')->set_static('<a href="' . $permalink . '" class="viewpost" >' . ($this->status != Post::status('published') ? _t('Preview Post') : _t('View Post')) . '</a>')); } // Store this post instance into a hidden field for later use when saving data $form->append(FormControlData::create('post')->set_value($this)); // Create the Title field $form->append(FormControlLabel::wrap(_t('Title'), FormControlText::create('title', null, array('class' => array('check-change full-width')))->set_value($this->title_internal))); // Create the silos if (count(Plugins::get_by_interface('MediaSilo'))) { $silos = FormControlSilos::create('silos')->set_setting('wrap', '<div class="container silos">%s</div>'); $form->append($silos); } // Create the Content field $form->append(FormControlLabel::wrap(_t('Content'), FormControlTextArea::create('content', null, array('class' => array('resizable', 'check-change full-width rte')))->set_value($this->content_internal))); $form->content->raw = true; // @todo What does this do? // Create the tags field /** @var FormControlAutocomplete $tags_control */ $form->append(FormControlLabel::wrap(_t('Tags, separated by, commas'), $tags_control = FormControlAutocomplete::create('tags', null, array('style' => 'width:100%;margin:0px 0px 20px;', 'class' => 'check-change full-width'), array('allow_new' => true, 'init_selection' => true)))->set_properties(array('style' => 'width:100%;margin:0px 0px 20px;'))); $tags = (array) $this->get_tags(); array_walk($tags, function (&$element, $key) { $element->term_display = MultiByte::strpos($element->term_display, ',') === false ? $element->term_display : $element->tag_text_searchable; }); $tags_control->set_value(implode(',', $tags)); $tags_control->set_ajax(URL::auth_ajax('tag_list')); // Create the splitter /** @var FormControlTabs $publish_controls */ $publish_controls = $form->append(FormControlTabs::create('publish_controls')->set_setting('wrap', '%s')->set_setting('class_each', 'container')); // Create the publishing controls // pass "false" to list_post_statuses() so that we don't include internal post statuses $statuses = Post::list_post_statuses($this); unset($statuses[array_search('any', $statuses)]); $statuses = Plugins::filter('admin_publish_list_post_statuses', $statuses); /** @var FormControlFieldset $settings */ $settings = $publish_controls->append(FormControlFieldset::create('post_settings')->set_caption(_t('Settings'))); $settings->append(FormControlLabel::wrap(_t('Content State'), FormControlSelect::create('status')->set_options(array_flip($statuses))->set_value($this->status))); // hide the minor edit checkbox if the post is new if ($newpost) { $settings->append(FormControlData::create('minor_edit')->set_value(false)); } else { $settings->append(FormControlLabel::wrap(_t('Minor Edit'), FormControlCheckbox::create('minor_edit')->set_value(true))); $form->append(FormControlData::create('modified')->set_value($this->modified)); } $settings->append(FormControlLabel::wrap(_t('Comments Allowed'), FormControlCheckbox::create('comments_enabled')->set_value($this->info->comments_disabled ? false : true))); $settings->append(FormControlLabel::wrap(_t('Publication Time'), FormControlText::create('pubdate')->set_value($this->pubdate->format('Y-m-d H:i:s')))); $settings->pubdate->set_helptext(_t('YYYY-MM-DD HH:MM:SS')); $settings->append(FormControlData::create('updated')->set_value($this->updated->int)); $settings->append(FormControlLabel::wrap(_t('Content Address'), FormControlText::create('newslug')->set_value($this->slug))); // Create the button area $buttons = $form->append(FormControlFieldset::create('buttons', null, array('class' => array('container', 'buttons', 'publish')))); // What buttons should we have? $require_any = array('own_posts' => 'create', 'post_any' => 'create', 'post_' . Post::type_name($this->content_type) => 'create'); $show_buttons = array(); if ($newpost) { if (User::identify()->can_any($require_any)) { $show_buttons['save'] = true; $show_buttons['publish'] = true; } } else { if (ACL::access_check($this->get_access(), 'edit')) { if ($this->status == Post::status('draft')) { $show_buttons['publish'] = true; } $show_buttons['save'] = true; } if (ACL::access_check($this->get_access(), 'delete')) { $show_buttons['delete'] = true; } } $show_buttons = Plugins::filter('publish_form_buttons', $show_buttons, $this); if (isset($show_buttons['delete'])) { // Create the Delete button $buttons->append(FormControlSubmit::create('delete', null, array('class' => 'three columns'))->set_caption(_t('Delete'))->on_success(array($this, 'form_publish_delete'))); } if (isset($show_buttons['save'])) { // Create the Save button $buttons->append(FormControlSubmit::create('save', null, array('class' => 'three columns'))->set_caption(_t('Save'))); } if (isset($show_buttons['publish'])) { // Create the Publish button $buttons->append(FormControlSubmit::create('publish', null, array('class' => 'three columns'))->set_caption(_t('Publish'))->add_validator(function ($value, FormControlSubmit $control, FormUI $form) { $form->status->set_value(Post::status('published')); $allow = Plugins::filter('post_publish_allow', true, $this); if (!$allow) { return array('Publishing has been denied'); } return array(); })); } // Add required hidden controls $form->append(FormControlData::create('content_type', null, array('id' => 'content_type'))->set_value($this->content_type)); $form->append(FormControlData::create('post_id', null, array('id' => 'id'))->set_value($this->id)); $form->append(FormControlData::create('slug', null, array('id' => 'originalslug'))->set_value($this->slug)); $form->on_success(array($this, 'form_publish_success')); // Let plugins alter this form Plugins::act('form_publish', $form, $this, $context); $content_types = array_flip(Post::list_active_post_types()); Plugins::act('form_publish_' . Utils::slugify($content_types[$this->content_type], '_'), $form, $this, $context); // Return the form object return $form; }