Buddypress new profile tabs and sub tabs: How to set up url slug properly? - menu

First of all, I’ve seen alot of people trying to do a similar task, which is simply to create a new tab, with sub tabs in the user profile menu. I’ve managed to do this, but I can’t seem to get the url slug to work properly. When I click on the first sub tab, it simply takes me back to the main page for the user profile, and when I click on any additional sub tabs I get 404 errors. I have a feeling I’m missing something pretty simple, and I’ve been trying to learn over the last couple weeks how to make this work without any luck. If someone could help guide me on how to get this working properly, I would very grateful, and I imagine many others would find this post useful in the future.
For the record the main profile tab works properly, but the sub-tabs do not.
Here is the code I currently have in my bp-custom.php file
// My Membership Profile Tab
function profile_new_nav_item() {
global $bp;
bp_core_new_nav_item(
array(
'name' => 'My Membership',
'slug' => 'my-membership',
'default_subnav_slug' => 'extra_sub_tab', // We add this submenu item below
'screen_function' => 'view_manage_tab_main'
)
);
}
add_action( 'bp_setup_nav', 'profile_new_nav_item', 10 );
function view_manage_tab_main() {
add_action( 'bp_template_content', 'bp_template_content_main_function' );
bp_core_load_template( 'template_content' );
}
function bp_template_content_main_function() {
if ( ! is_user_logged_in() ) {
wp_login_form( array( 'echo' => true ) );
}
}
function profile_new_subnav_item() {
global $bp;
bp_core_new_subnav_item( array(
'name' => 'Membership Level',
'slug' => 'extra_sub_tab',
'parent_url' => $bp->loggedin_user->domain . $bp->bp_nav[ 'extra_tab' ][ 'slug' ] . '/',
'parent_slug' => $bp->bp_nav[ 'my-membership' ][ 'slug' ],
'position' => 10,
'screen_function' => 'view_manage_sub_tab_main'
) );
}
add_action( 'bp_setup_nav', 'profile_new_subnav_item', 10 );
function view_manage_sub_tab_main() {
add_action( 'bp_template_content', 'bp_template_content_sub_function' );
bp_core_load_template( 'template_content' );
}
function bp_template_content_sub_function() {
if ( is_user_logged_in() ) {
//Add shortcode to display content in sub tab
echo do_shortcode( '[membership]' );
} else {
wp_login_form( array( 'echo' => true ) );
}
}
// My Billing Profile Tab
function profile_new_subnav_item_billing() {
global $bp;
bp_core_new_subnav_item( array(
'name' => 'Billing',
'slug' => 'extra_sub_tab_billing',
'parent_url' => $bp->loggedin_user->domain . $bp->bp_nav[ 'extra_tab' ][ 'slug' ] . '/',
'parent_slug' => $bp->bp_nav[ 'my-membership' ][ 'slug' ],
'position' => 20,
'screen_function' => 'view_manage_sub_tab_billing'
) );
}
add_action( 'bp_setup_nav', 'profile_new_subnav_item_billing', 20 );
function view_manage_sub_tab_billing() {
add_action( 'bp_template_content', 'bp_template_content_sub_function_billing' );
bp_core_load_template( 'template_content' );
}
function bp_template_content_sub_function_billing() {
if ( is_user_logged_in() ) {
//Add shortcode to display content in sub tab
echo do_shortcode( '[billing]' );
} else {
wp_login_form( array( 'echo' => true ) );
}
}

You may use this:
// define your parent slug
$parent_slug = 'activity';
bp_core_new_subnav_item( array( .........
'parent_url' => $bp->loggedin_user->domain . $parent_slug.'/',
'parent_slug' => $parent_slug,
It works for me.

Related

How to show primary menu of main site throughout multi-site network

I have managed to switch the primiary navigation menu of my subsites to show the main site primary navigation.
However, it renders above the site-header instead of in the menu location dictated in the code.
Here is the code I currently have:
function wp_multisite_nav_menu() {
global $blog_id;
}
if ( ! is_multisite() || 2 == $blog_id ) {
switch_to_blog( 1 );
wp_nav_menu( array(
'menu' => 2,
'fallback_cb' => false,
'menu_class' => 'genesis-nav-menu',
'theme_location' => 'Primary Navigation Menu',
));
restore_current_blog();
}
I was expecting the menu to be placed in the 'Primary Navigation Menu' location.
What have I missed?
Any clarity is appreciated.
UPDATE
I managed to figure it out for my primary and secondary menus however how do get the site title to change to the main site title and hyperlink?
Here is the code I currently have minus the site title switch
//*Multisite global menus
//*Primary global menu
add_action('genesis_after_header', 'primary_menu_switch');
function primary_menu_switch() {
global $blog_id;
if ( ! is_multisite() || 2 == $blog_id ) {
switch_to_blog( 1 );
wp_nav_menu( array(
'menu' => 2,
'fallback_cb' => false,
'menu_class' => 'genesis-nav-menu',
'theme_location' => 'primary'
) );
restore_current_blog();
}
}
//*Secondary global menu
add_action('genesis_header_right', 'secondary_menu_switch');
function secondary_menu_switch() {
global $blog_id;
if ( ! is_multisite() || 2 == $blog_id ) {
switch_to_blog( 1 );
wp_nav_menu( array(
'menu' => 17,
'fallback_cb' => false,
'menu_class' => 'genesis-nav-menu menu-primary responsive-menu',
'theme_location' => 'primary'
));
restore_current_blog();
}
}
//*Use main site title
function site_title_switch() {
global $blog_id;
if ( ! is_multisite() || 2 == $blog_id ) {
switch_to_blog( 1 );
restore_current_blog();
}
}
I am a complete novice so please excuse the hack job.
Your insights are appreciated.
This is an answer to the updated question, not the one in the title.
This should do the trick, if you put it in a network activated plugin. Read the comments to see what it does exactly. It might not work depending on how your theme is made. I made it for the Twenty Eleven theme.
Keep in mind that it will change the home URL everywhere where it is called with a path '/', not only in the header.
add_filter( 'option_blogname', 'function_to_filter_the_blogname' );
// Changes the blog name of all sites that are not the main one to the name of the main one, only outside of the admin panel
function function_to_filter_the_blogname( $name ) {
$main_site_id = get_main_site_id();
if ( get_current_blog_id() != $main_site_id && ! is_admin() ) {
return get_blog_option( $main_site_id, 'blogname' );
}
return $name;
}
add_filter( 'home_url', 'function_to_filter_the_home_url', 10, 4 );
// Changes the home URL of all sites that are not the main one to the home URL of the main one, only outside of the admin panel and only when the path is '/'
function function_to_filter_the_home_url( $url, $path, $orig_scheme, $blog_id ) {
$main_site_id = get_main_site_id();
if ( $blog_id != $main_site_id && ! is_admin() && '/' == $path ) {
return get_blog_option( $main_site_id, 'home' );
}
return $url;
}

How to implement a pagination for a search module in Zend Framework 2?

I have a module Search in my ZF2 application. The user fills in a search form out and gets a list of courses.
Now I'm adding the pagination to the module. The paginator is basically working: I can retrieve data over it and the pagination is displayed correctly (pagelinks 1-7 for 70 found courses with the dafault setting 10 items per page).
But it's still not usable. When I click on a pagelink, the form POST data is lost. I know -- it cannot work the way, how I implemented it (see the code below). But I have no idea, how to do it correctly, in order to eep checking the form data and nonetheless be able to use pagination.
That is my code:
Table class Search\Model\CourseTable
class CourseTable {
...
// without pagination
// public function findAllByCriteria(CourseSearchInput $input) {
// with pagination
public function findAllByCriteria(CourseSearchInput $input, $pageNumber) {
...
$select = new Select();
$where = new Where();
$having = new Having();
...
// without pagination
// $resultSet = $this->tableGateway->selectWith($select);
// return $resultSet;
// with pagination
$adapter = new \MyNamespqce\Paginator\Adapter\DbSelect($select, $this->tableGateway->getAdapter());
$paginator = new \Zend\Paginator\Paginator($adapter);
$paginator->setCurrentPageNumber($pageNumber);
return $paginator;
}
...
}
Search\Controller\SearchController
class SearchController extends AbstractActionController {
public function searchCoursesAction() {
$form = $this->getServiceLocator()->get('Search\Form\CourseSearchForm');
$request = $this->getRequest();
if ($request->isPost()) {
$courseSearchInput = new CourseSearchInput();
$form->setInputFilter($courseSearchInput->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$courseSearchInput->exchangeArray($form->getData());
// without pagination
// $courses = $this->getCourseTable()->findAllByCriteria($courseSearchInput);
// with pagination
$page = $this->params()->fromRoute('page');
$paginator = $this->getCourseTable()->findAllByCriteria($courseSearchInput, $page);
} else {
$paginator = null;
}
} else {
$paginator = null;
}
return new ViewModel(array(
'form' => $form,
// without pagination
// 'courses' => $courses,
// with pagination
'paginator' => $paginator,
'cities' => ...
));
}
...
}
How to get it working?
I also have the same problem, and I have solved it. But this is not good way. May be the idea will help you.
I solved it as follow: (Search pagination for Zend tutorial album module)
I build two action in controller named "search" and "index".
Whenever the search form submitted, it always post the value to search action. Search action build the url with search parameters, and redirect to index to disply search result.
And when the pagination links clicked, then posted values are passed through url. So whenever index action ask for search parameters, it always get the values in same format.
I defined route as follows:
'album' => array(
'type' => 'segment',
'options' => array(
'route' => '/album[/:action][/:id][/page/:page][/order_by/:order_by][/:order][/search_by/:search_by]',
'constraints' => array(
'action' => '(?!\bpage\b)(?!\border_by\b)(?!\bsearch_by\b)[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
'page' => '[0-9]+',
'order_by' => '[a-zA-Z][a-zA-Z0-9_-]*',
'order' => 'ASC|DESC',
),
'defaults' => array(
'controller' => 'Album\Controller\Album',
'action' => 'index',
),
),
),
There is a parameter named "search_by", which will keep all search parameters as a json string. This is the point, which is not good I know, but have not find any other way yet.
"Search" action build this string as -
public function searchAction()
{
$request = $this->getRequest();
$url = 'index';
if ($request->isPost()) {
$formdata = (array) $request->getPost();
$search_data = array();
foreach ($formdata as $key => $value) {
if ($key != 'submit') {
if (!empty($value)) {
$search_data[$key] = $value;
}
}
}
if (!empty($search_data)) {
$search_by = json_encode($search_data);
$url .= '/search_by/' . $search_by;
}
}
$this->redirect()->toUrl($url);
}
And next index action decode the string, do necessary action, and also send the json string to view.
public function indexAction() {
$searchform = new AlbumSearchForm();
$searchform->get('submit')->setValue('Search');
$select = new Select();
$order_by = $this->params()->fromRoute('order_by') ?
$this->params()->fromRoute('order_by') : 'id';
$order = $this->params()->fromRoute('order') ?
$this->params()->fromRoute('order') : Select::ORDER_ASCENDING;
$page = $this->params()->fromRoute('page') ? (int) $this->params()->fromRoute('page') : 1;
$select->order($order_by . ' ' . $order);
$search_by = $this->params()->fromRoute('search_by') ?
$this->params()->fromRoute('search_by') : '';
$where = new \Zend\Db\Sql\Where();
$formdata = array();
if (!empty($search_by)) {
$formdata = (array) json_decode($search_by);
if (!empty($formdata['artist'])) {
$where->addPredicate(
new \Zend\Db\Sql\Predicate\Like('artist', '%' . $formdata['artist'] . '%')
);
}
if (!empty($formdata['title'])) {
$where->addPredicate(
new \Zend\Db\Sql\Predicate\Like('title', '%' . $formdata['title'] . '%')
);
}
}
if (!empty($where)) {
$select->where($where);
}
$album = $this->getAlbumTable()->fetchAll($select);
$totalRecord = $album->count();
$itemsPerPage = 2;
$album->current();
$paginator = new Paginator(new paginatorIterator($album));
$paginator->setCurrentPageNumber($page)
->setItemCountPerPage($itemsPerPage)
->setPageRange(7);
$searchform->setData($formdata);
return new ViewModel(array(
'search_by' => $search_by,
'order_by' => $order_by,
'order' => $order,
'page' => $page,
'paginator' => $paginator,
'pageAction' => 'album',
'form' => $searchform,
'totalRecord' => $totalRecord
));
}
All the sorting and paging url contain that string.
If you know all the searching paarameters before, then you can define that at route, and pass like the same way without json string. As I have to build a common search, I have build a single string.
Source code for "Album search" is available in git hub at https://github.com/tahmina8765/zf2_search_with_pagination_example.
Live Demo: http://zf2pagination.lifencolor.com/public/album
#Sam & #automatix in the question comments are both right. My suggestion (though I'm looking for a simpler alternative) is to construct a segment route, which covers all of the options that you're likely to need and start with a standard form POST request.
Then, after the request is validated, pass the form data to the paginationControl helper as follows:
$resultsView = new ViewModel(array(
'paginator' => $paginator,
'routeParams' => array_filter($form->getData())
));
Then, in your view template, set the route parameters in the paginationControl view helper:
<?php echo $this->paginationControl($paginator, 'Sliding', 'paginator/default',
array('routeParams' => $routeParams)
) ?>
I've used array_filter here because it's a really simple way of removing any element from the form data that's null, empty or so on. That way you don't pass in extra data that you don't need.

Infinitescroll to finish after a certain number of posts

I am using Paul Irish's infinitescroll with masonry js on a wordpress site. It is a site with a lot of content. I want infintescroll to stop adding new content when it reaches post number 40 and to give the "No additional items" message at that point. I tried to customize the wordpress loop to only return 40 posts but that did not seem to work.
I thought that maybe one of the options in infinitecroll might do the trick but the infintescroll documentation is very sparse. For example, there is an infinitescroll option in the "loading" init section called "finished: undefined" Is it possible to change that parameter to stop the scrolling after a certain number of content items?
Is there some other obvious way to control when infinitescroll stops loading new content?
Any assistance would be greatly appreciated.
In the Administration -> Settings -> Reading you can set Blog pages show at most to 40.
With code:
Two ways I've done Masonry by numbers like your question I've had success with the following:
limit posts_per_page in your query arguments
$args = array(
'posts_per_page' => 40,
'offset' => 5,
'orderby' => 'post_date',
'order' => 'DESC',
'exclude' => 'none',
'post_type' => 'post',
'post_status' => 'publish',
'suppress_filters' => true
);
$posts = new WP_Query( $args );
if ( $posts -> have_posts()) {
while ( $posts -> have_posts() ) : $posts->the_post(); {
//do stuff with the posts returned here
}
}
or by incrementing:
$counts = 0 ;
$posts = new WP_Query( $args );
if ( $posts -> have_posts()) {
while ( $posts -> have_posts() ) : $posts->the_post(); {
//do stuff with the posts returned here
$counts = ++;
if($counts == 40) { return }
}
}

Custom error message for validation rules in Kohana 3.2

I have a controller=product.php,a model=category.php, and a custom error message file category.php. When I am submitting the empty form , I am getting error messages for rule "not_empty, but I am not getting error message for rule "unique_categoryname"
Please help!
class Controller_Product extends Controller_Application
{
public function action_addcategory()
{
$errors='';
$cat = new Model_Category();
$validation=Validation::factory($this->request->post())
->rule('cat_name',array($cat,'unique_categoryname'));
if ($validation->check())
{
if (HTTP_Request::POST == $this->request->method())
{
try
{
$cat_name=$_POST['cat_name'];
$cat_description=$_POST['cat_description'];
if (isset($_FILES['cat_image']))
{
$filename = $cat->upload_photo($_FILES['cat_image']);
}
$cat->InsertCategory($cat_name,$cat_description,$filename);
Request::current()->redirect('product/listcategory');
}
catch (ORM_Validation_Exception $ex)
{
$errors = $ex->errors('models');
}
}
}
$view = new View('product/addcategory');
$view->set("categories",$cat);
$view->set('errors',$errors);
$this->template->content=$view;
}
}
class Model_Category extends ORM
{
public function rules()
{
return array(
'cat_name' => array(
array('not_empty'),
array('min_length', array(':value', 4)),
array('max_length', array(':value', 32)),
),
'cat_description' => array(
array('not_empty'),
array('min_length', array(':value', 10)),
),
);
}
}
//Custom error messages page : messages/models/category.php
return array(
'cat_name' => array(
'not_empty' => 'You must provide a category name.',
'min_length' => 'The category name must be at least :param2 characters long.',
'max_length' => 'The category name must be less than :param2 characters long.',
'unique_categoryname'=> 'Category Name already exists, please change',
),
'cat_description' => array(
'not_empty' => 'You must provide category description .',
'min_length' => 'The category description must be at least :param2 characters long.',
),
);
You need to pass your $validation to the ORM save/update method.
Assuming InsertCategory is a wrapper for saving, you should pass it there:
$cat->InsertCategory($cat_name, $cat_description, $filename, $validation);
Then in InsertCategory method:
public function InsertCategory(....)
{
// .....
$this->save($validation);
}
Be aware that there is a bug in Kohana 3.2 and external validation messages go to _external.php file.
You can find more information here: http://kohanaframework.org/3.2/guide/orm/validation#external-validation

Extending Drupal 7 search

I want to extend default Drupal 7 node search with one additional field.
I alter search form with the following new field:
function mymodule_form_search_form_alter(&$form, &$form_state, $form_id) {
$form['basic']['site'] = array(
'#type' => 'select',
'#options' => array(
'KEY1' => 'TITLE1',
'KEY2' => 'TITLE2',
'KEY3' => 'TITLE3'
)
);
}
I have a field called field_data_field_site.field_site_value which i need to use as a filter in this search.
I've tried to read about hook_search_* functions but didn't get the idea.
My question is the following. How can I extend search form? Anyone have live examples?
The following is the best way I solve this problem.
First of all I need to alter Drupal's search block and search form with my field and define new submit function.
/**
* Implements hook_form_FORM_ID_alter().
*/
function mymodule_form_search_block_form_alter(&$form, &$form_state, $form_id) {
$form['#submit'][] = 'search_form_alter_submit';
$form['site'] = array(
'#type' => 'select',
'#options' => _options(),
'#default_value' => (($_GET['site']) ? $_GET['site'] : '')
);
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function mymodule_form_search_form_alter(&$form, &$form_state, $form_id) {
$form['#submit'][] = 'search_form_alter_submit';
$form['basic']['site'] = array(
'#type' => 'select',
'#options' => _options(),
'#default_value' => (($_GET['site']) ? $_GET['site'] : '')
);
}
function _options() {
return array(
'' => 'Select site',
'site-1' => 'Site 1',
'site-2' => 'Site 2'
);
}
Submit function will forward us to default search/node page but with our query. Page would look like search/node/Our-query-string?site=Our-option-selected.
function search_form_alter_submit($form, &$form_state) {
$path = $form_state['redirect'];
$options = array(
'query' => array(
'site' => $form_state['values']['site']
)
);
drupal_goto($path, $options);
}
Next step is to use hook_search_info (Don't forget to turn it on and set as default on admin/config/search/settings page).
/**
* Implements hook_search_info().
*/
function mymodule_search_info() {
return array(
'title' => 'Content',
'path' => 'node',
'conditions_callback' => '_conditions_callback',
);
}
Conditions callback function defined in hook_search_info. We need to provide additional queries to our search.
function _conditions_callback($keys) {
$conditions = array();
if (!empty($_REQUEST['site'])) {
$conditions['site'] = $_REQUEST['site'];
}
return $conditions;
}
Finally, hook_search_execute will filter our content by our query. I used default code from this hook with modifications I need.
/**
* Implements hook_search_execute().
*/
function mymodule_search_execute($keys = NULL, $conditions = NULL) {
// Build matching conditions
$query = db_select('search_index', 'i', array('target' => 'slave'))
->extend('SearchQuery')
->extend('PagerDefault');
$query->join('node', 'n', 'n.nid = i.sid');
// Here goes my filter where I joined another table and
// filter by required field
$site = (isset($conditions['site'])) ? $conditions['site'] : NULL;
if ($site) {
$query->leftJoin('field_data_field_site', 's', 's.entity_id = i.sid');
$query->condition('s.field_site_value', $site);
}
// End of my filter
$query
->condition('n.status', 1)
->addTag('node_access')
->searchExpression($keys, 'node');
// Insert special keywords.
$query->setOption('type', 'n.type');
$query->setOption('language', 'n.language');
if ($query->setOption('term', 'ti.tid')) {
$query->join('taxonomy_index', 'ti', 'n.nid = ti.nid');
}
// Only continue if the first pass query matches.
if (!$query->executeFirstPass()) {
return array();
}
// Add the ranking expressions.
_node_rankings($query);
// Load results.
$find = $query
->limit(10)
->execute();
$results = array();
foreach ($find as $item) {
// Build the node body.
$node = node_load($item->sid);
node_build_content($node, 'search_result');
$node->body = drupal_render($node->content);
// Fetch comments for snippet.
$node->rendered .= ' ' . module_invoke('comment', 'node_update_index', $node);
// Fetch terms for snippet.
$node->rendered .= ' ' . module_invoke('taxonomy', 'node_update_index', $node);
$extra = module_invoke_all('node_search_result', $node);
$results[] = array(
'link' => url("node/{$item->sid}", array('absolute' => TRUE)),
'type' => check_plain(node_type_get_name($node)),
'title' => $node->title,
'user' => theme('username', array('account' => $node)),
'date' => $node->changed,
'node' => $node,
'extra' => $extra,
'score' => $item->calculated_score,
'snippet' => search_excerpt($keys, $node->body)
);
}
return $results;
}
I'd be happy if anyone would give me a better answer.

Resources