I am using Commerce Kickstart to create an e-commerce marketplace and I am wondering how I can create a second login page that can be used by the merchants.
The standard login page is generated at http://website.com/user/login. How would I be able to create another login page at let's say http://website.com/user/merchant_login. The page itself will function exactly the same as the login, with slight changes in aesthetics, like taking off the register link, as we will generate the login information for the merchants.
I can see that the form is being generated at commerce_kickstart_user_form_alter through specified form_ids so I should be able to simply add the details for the merchant form there. My main question is how will the page/form be generated when they visit a url of my choosing?
You just need to create a custom page:
Assuming that your custom module is called custom_merchant the code should be something like this:
function custom_merchant_menu() {
$items = array();
$items['user/merchant_login'] = array(
'page callback' => 'custom_merchant_login_callback',
'page arguments' => array(true),
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
return $items;
}
function custom_merchant_login_menu_alter(&$items) {
$items['user']['page callback'] = 'custom_login_user_page';
}
function custom_merchant_login_callback($show = false) {
global $user;
if ($user->uid) {
menu_set_active_item('user/'. $user->uid);
return menu_execute_active_handler();
} else if ($show) {
return drupal_get_form('user_login');
}
drupal_not_found();
}
Related
I am trying to write my first Drupal custom module (using drupal 6). I got the basic module working but I would like to add another page to the project. For example, right now my module's path looks like this: www.mysite.com/my_custom_module. I would like to add another page like this: www.mysite.com/my_custom_module/my_sub_page. I've tried adding a new .module and .info file but this does not work. I've also tried adding new items to the menu hook, like this:
my_custom_module.module:
function my_custom_module_menu(){
$items = array();
$items['my_custom_module'] = array(
'title' => "My Custom Module",
'page callback' => "my_custom_module_info",
'access callback' => true,
'type' => MENU_NORMAL_ITEM,
);
$items['my_custom_module/my_sub_page'] = array(
'title' => "My Sub Page",
'page callback' => "my_custom_module_sub_page_info",
'access callback' => true,
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
function my_custom_module_info(){
$result = 'My Page URL was hit';
return $result;
}
function my_custom_module_sub_page_info(){
$result = 'My Sub Page URL was hit';
return $result;
}
In this example, if I go to .../my_custom_module it works fine. But, if I go to .../my_custom_module/my_sub_page, it still load, and displays my_custom_module. When I debug with a break point in each function, only my_custom_module_info is hit. Not the sub page. What am I doing wrong? I this even the correct way to create multi pages in a module? Just an FYI, each of these pages will have different audiences. The first page is to allow a user to submit some form data. The second is to allow an elevated user view the data.
Thanks
jason
In a custom module I want to have a page defined in hook_menu, that shows the add form for a specific content type, with some modifications to the form.
So far it's working, and even saving the new node, but only with the default values I'm setting in the code, i.e. it's not picking up anything the user types into the form. I checked and $form_state['input'] contains the inputted values, but $form_state['values'] doesn't, so the new node gets saved wrong.
Here's the relevant code:
function mymodule_menu() {
return array(
'admin/content/myadd/%' => array(
'title' => 'my custom add page',
'page callback' => 'mymodule_node_add',
'page arguments' => array(3),
'access callback' => TRUE,
'type' => MENU_CALLBACK,
),
);
}
function mymodule_node_add() {
module_load_include('inc', 'node', 'node.pages');
//I'm doing a print here instead of returning because I'm calling this page
//in an AJAX popup, so I don't want the whole page to output, only the form.
print render(drupal_get_form('mymodule_node_add_form'));
}
function mymodule_node_add_form($form, &$form_state) {
if (!isset($form_state['node']) {
global $user;
$node = (object) array(
'uid' => $user->uid,
'type' => 'mycontenttype',
'language' => LANGUAGE_NONE,
);
//this is setting a default value
$node->myfield = array(LANGUAGE_NONE => array(array('value' => arg(3))));
$form_state['build_info']['args'] = array($node);
$form = drupal_build_form('mycontenttype_node_form', $form_state);
$form['actions']['submit']['#submit'][0] = 'mymodule_node_add_form_submit';
//there's a lot more customization of the form here, like adding fields, etc.
}
return $form;
}
function mymodule_node_add_form_submit($form, &$form_state) {
//here's where $form_state['input'] is correct but $form_state['values'] isn't.
$node = node_form_submit_build_node($form, $form_state);
node_save($node);
$form_state['values']['nid'] = $node->nid;
$form_state['nid'] = $node->nid;
$form_state['redirect'] = 'some/other/page';
}
So, am I doing something wrong here? Should I be concerned about form ids being wrong? (my form's id is mymodule_node_add_form, but the actual form might output mycontenttype_node_form), would this affect me?
You want hook_form_alter() (see api.drupal.org). I would try to use the existing content type's form and simply alter it with hook_form_alter(). I would also try to first get it working as a standard, non-AJAX page, so you can get all the advantages of dpm() and other debugging techniques. When you have it down solid, then modify it to take advantage of the AJAX techniques.
mymodule_form_alter(&$form, &$form_state, $form_id) {
// use this with your devel module turned on to verify
// your $form_id and contents of all forms that load on a given page
dpm($form);
// once you verify your $form_id, you can begin accessing your form and altering it
switch( $form_id ) {
case 'my_target_form_id' :
// this part is just pseudocode, I haven't memorized the $form structure,
// you can get it from your dpm().
if( $form['node']->type == 'my_target_content_type' ) {
$form['actions']['submit']['#submit'][0] = 'mymodule_node_add_form_submit';
}
break;
}
}
I would like to use the node-menu (see image) on a page in Drupal.
Is this possible and, if yes, how?
If the page you are referring is a custom page output from your module, and "mymodule/page" is the path for that page, for which you want the tabs "View" and "Edit," then you should implement hook_menu() using code similar to the following one:
function mymodule_menu() {
$items = array();
$items['mymodule/page'] = array(
'page callback' => 'mymodule_page_view',
'access arguments' => array('view mymodule page'),
);
$items['mymodule/page/view'] = array(
'title' => 'View',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items['mymodule/page/edit'] = array(
'title' => 'Edit',
'page callback' => 'mymodule_page_edit',
'access arguments' => array('edit mymodule page'),
'weight' => 0,
'type' => MENU_LOCAL_TASK,
);
return $items;
}
If the page you are referring is a page that is shown at example.com/mymodule/page, and that should show what you see at example.com/node/7, then you can implement the following code, in Drupal 7:
function mymodule_url_inbound_alter(&$path, $original_path, $path_language) {
if (preg_match('|^mymodule/page|', $path)) {
$path = 'node/7';
}
}
The equivalent for Drupal 6 is writing the following code in the settings.php file:
function custom_url_rewrite_inbound(&$result, $path, $path_language) {
if (preg_match('|^mymodule/page|', $path)) {
$result = 'node/7';
}
}
I didn't write the symmetric code for hook_url_outbound_alter(), and custom_url_rewrite_outbound() as I suppose you are not interested in rewriting example.com/node/7 to make it appear as example.com/mymodule/page, but you are interested in making appear example.com/mymodule/page the same as example.com/node/7.
Okay; a node page usually has those View and Edit tabs. So my next question is to wonder why they aren't appearing on your node page already. Have you by chance created a custom page template for this node type and removed the code that prints the tabs? Or is there a chance you're logged in as a user that doesn't have permission to edit this type of node?
There must be a reason why you're not getting those tabs; they should be there, by default.
If you do have a custom page template for this node type, look for code that looks something like this:
<?php if ($tabs): ?>
<div class="tabs"><?php print $tabs; ?></div>
<?php endif; ?>
If you don't see code like that, try adding it.
If you DO see code like that, try to isolate what's different about this content type compared to other content types where you DO see those tabs.
which will be the best way to develop custom forms for drupal, for admin's part of the system?
thank you in advance!
First thing, you need a location to access your form from, preferably in the "admin/*" namespace if the form is only meant for administration.
If you're just showing a form, you could directly use drupal_get_form as page callback (but you could use any function to generate the HTML code, even mix with theme functions)
Also, you need to know which permission(s) is required to access the form.
By default, I used "access administration pages" but you probably should use something more specific, depending on what you intend the form for.
Let's say the path is "admin/build/something", you need to use hook_menu to register that path:
/**
* Implementation of hook_menu().
*/
function modulename_menu(){
return array(
'admin/build/something' => array(
'title' => 'Example Admin Form',
'description' => 'Admin form introduced by the MODULENAME module',
'type' => MENU_NORMAL_ITEM,
'page callback' => 'drupal_get_form',
'access arguments' => array('access administration pages'),
),
);
}
Now, to actually display a page: the value provided in "page arguments" was the name
of the function that drupal_get_form expects to provide the form structure
(which must be an associative array):
/**
* Form Structure
*/
function modulename_form_something(&$form_state){
$form = array();
$form['myfield'] = array(
'#title' => 'My Field',
'#description' => 'This is a basic text input field',
'#type' => 'textfield',
'#default_value' => $form_state['values']['myfield'],
);
//
// Here you can add more elements in the form
//
return $form;
}
Here is more informations about the Forms API, which you can use to make some pretty complex forms easily.
Now your form is displayed at "/admin/build/something", but you probably want to do soemthing with these data as well; by default, the validate and submit functions are named the same as the form structure function, with "_validate" and "_submit" respectively (however you can override this with #validate and #submit in the form structure).
For example, let's say the string "no" is not a valid value, everything else is accepted.
/**
* Form validation
*/
function modulename_form_something_validate($form, &$form_state){
if ($form_state['values']['myfield'] == 'no'){
form_set_error('myfield', '"<b>no</b>" is not a valid answer, try again.');
}
}
The validation is called first, however you should only check if data are alright in that function. If you need to perform actions when the form is received, do it in the "submit" handler instead because validate may be called several times while submit is called only once.
/**
* Form submission
*/
function modulename_form_something_submit(&$form, &$form_state){
//
// Here you can perform whatever action that form is made for.
//
drupal_set_message( 'The form has been sent. "myfield" has the following value: '.$form_state['values']['myfield'] );
}
Let's summarize, here's the whole modulename.module file:
<?php
/**
* Implementation of hook_menu().
*/
function modulename_menu(){
return array(
'admin/build/something' => array(
'title' => 'Example Admin Form',
'description' => 'Admin form introduced by the MODULENAME module',
'type' => MENU_NORMAL_ITEM,
'page callback' => 'drupal_get_form',
'page arguments' => 'modulename_form_something',
'access arguments' => array('access administration pages'),
),
);
}
/**
* Form Structure
*/
function modulename_form_something(&$form_state){
$form = array();
$form['myfield'] = array(
'#title' => 'My Field',
'#description' => 'This is a basic text input field',
'#type' => 'textfield',
'#default_value' => $form_state['values']['myfield'],
);
//
// Here you can add more elements in the form
//
return $form;
}
/**
* Form validation
*/
function modulename_form_something_validate($form, &$form_state){
if ($form_state['values']['myfield'] == 'no'){
form_set_error('myfield', '"<b>no</b>" is not a valid answer, try again.');
}
}
/**
* Form submission
*/
function modulename_form_something_submit(&$form, &$form_state){
//
// Here you can perform whatever action that form is made for.
//
drupal_set_message( 'The form has been sent. "myfield" has the following value: '.$form_state['values']['myfield'] );
}
Don't forget you also need a .info file for being able to install the module:
Source of modulename.info:
; $Id
name = Admin Form
description = This module adds an admin form
package = Example Module
core = "6.x"
version = "6.x-0.1-dev"
The Drupal form api system will help you make any form you need. If you need to store settings, system_settings_form is a nice shortcut.
The only difference when making admin forms, is to remember to set some sort of permission required, and to place the form somewhere in the /admin/ section of the site. There really isn't anything special about admin forms.
Unless I'm misunderstanding your question, I think you can avoid the hassle of Forms API by using the Webform module.
No code required, nice UI and built in statistics tools.
http://drupal.org/project/webform
Watch a couple tutorial videos and you'll be making just about any form in no time.
Is there anyway I can customize the paths to a node's tabs?
When using either pathauto or hook_menu_alter, I can change the path to the node view to from node/node_id to, well pretty much anything, but let's say xyz/node_title.
The node tabs, however, still stay with the path /node/node_id/tab_name
I'm trying to add a custom tab to the node, and keep the custom path as well (e.g.: xyz/node_title/tab_name instead of node/node_id/tab_name).
I manage to add the custom tab via hook_menu:
$items['node/%node/members'] = array(
'title' => 'Manage Membership',
'page callback' => 'mymodule_members',
'page arguments' => array(1),
'access callback' => 'mymembers_members_access',
'access arguments' => array(1),
'type' => MENU_LOCAL_TASK
);
but if I try to customize the path, either at hook_menu or at hook_menu_alter, the tab just disappears.
Any ideas?
PS, I've posted the same question on the Drupal forums, no answer so far. I'll cross-update.
You can add two functions in settings.php: custom_url_rewrite_inbound(), and custom_url_rewrite_outbound().
The examples in those pages should make clear how to use them.
function custom_url_rewrite_inbound(&$result, $path, $path_language) {
global $user;
// Change all article/x requests to node/x
if (preg_match('|^article(/.*)|', $path, $matches)) {
$result = 'node'. $matches[1];
}
// Redirect a path called 'e' to the user's profile edit page.
if ($path == 'e') {
$result = 'user/'. $user->uid .'/edit';
}
}
function custom_url_rewrite_outbound(&$path, &$options, $original_path) {
global $user;
// Change all 'node' to 'article'.
if (preg_match('|^node(/.*)|', $path, $matches)) {
$path = 'article'. $matches[1];
}
// Create a path called 'e' which lands the user on her profile edit page.
if ($path == 'user/'. $user->uid .'/edit') {
$path = 'e';
}
}
Drupal 7 uses two new hooks, instead of those functions: hook_url_inbound_alter() and hook_url_outbound_alter().
I think this module will help you form the tab path the way you want: Sub-path URL Aliases.