Viewing 14 reply threads
  • Author
    Posts
    • #6056
      wpmusketeer
      Member

      Hi awesome Piklist peeps 😉

      I’m struggling with a frontend form. I have a CPT ‘job’.

      Within a template file I’m iterating over a WP_Query and creating a list of Jobs. In each Job’s li I have a div that needs to display a form for editing that Job (I’ve created the form in /parts/forms/job.php).

      The only way I’ve seen mentioned of outputting a Piklist form is via shortcode. I can use do_shortcode() to output the form on the template page as long as it is outside of the WP_Query loop. As soon as I use it inside the loop the page crashes completely. To the point where I have to close the Chrome tab because there’s nothing I can do with it!

      I have a couple of questions based off of this:

      1. Is do_shortcode() the best way to output a form in a template file?

      2. If so, why is it crashing when used inside a WP_Query loop?

      3. Once I’ve got the form to display, how do I get it to update the right Job? I’ve seen in the docs that you can pass the post ID to the page in a URL parameter, but that doesn’t help me inside the loop… Is there an ID parameter that can be passed to the shortcode?

      Thanks for your time.

      Dave

    • #6057
      wpmusketeer
      Member

      Hmm… Been playing around a bit more. It’s very difficult to debug because it completely crashes the browser tab in Chrome and Safari. On Firefox I’ve found it throws up an error dialogue saying “Unresponsive script: jQuery”.

      I take it Piklist is using some JavaScript on frontend forms? In the Firefox inspector I can see piklist.js in the JS resources so I guess something here is clashing with jQuery.

      The divs with the Piklist forms are hidden by default. I have some JS that shows them when an edit button is clicked but I’ve completely removed that JS and the problem persists.

    • #6058
      jrcreative
      Member

      What happens if you limit the result of the query to 1. Does it still blow up? It could cause all kinds of problems if the form is duplicated multiple times while duplicating field names.

      Ideally you could pass the post id into the shortcode and it would modify all of the field names and insure that they’re all unique.

    • #6064
      wpmusketeer
      Member

      Hi jrcreative,

      I think you’re on the right track. Limiting the query to a single Job lets the page load.

      I can’t see why multiple versions of the same form would cause a problem though, unless it’s something to do with the Piklist JavaScript on the page that is only expecting to see 1 instance of a form.

      There shouldn’t be anything wrong with having multiple instances of a form… after all, only 1 will ever be submitted at a time.

      The only field that should change is the ID it posts to. I’m still not sure how you’re supposed to pass the ID. In a hidden field perhaps? I don’t know what you mean when you say “pass the post id to the shortcode”.

      If the field names were made unique for each instance of the form as you suggest then all the forms would be attempting to update non-existant post meta!

      I’m guessing Piklist’s frontend forms can’t currently deal with this use-case, which is a shame because it’s likely to be a common one. I think I’ll give Caldera Forms a quick shot. They have an extension that lets you post meta to a CPT.

      Cheers,

      Dave

    • #6066
      jivedig
      Member

      Howdy Dave! I was hoping i’d spark some Piklist interest in you 😉
      You’ve got an interesting use case here, i’d be curious to test it out as well at some point.

      Here’s a quick tip, don’t use the shortcode in a template… do this:
      piklist::render('forms/job');

      The only way i’ve tested editing an existing post is adding a query var to the url e.g( example.com/my-form-page/?_post[ID]=123 )
      I was hoping to find a way to ‘load’ a form with post values where the ID comes from somewhere else. Naturally we could grab the values ourselves and put them in the field ‘value’ parameter, but that’s very manual (CMB2 style).

    • #6084
      wpmusketeer
      Member

      Geddon Mike! Traditional Cornish greeting that 😉

      You certainly fanned the flame of my interest in Piklist, so thanks.

      I think this is a very common use-case in the world of SPAs, so it would be great if Piklist supported it, since Piklist is aiming to turn WordPress into a better platform for developing web apps.

      Thanks for tipping me off to piklist::render( 'forms/job' ); – where did you find out about that? The disconnect between the Piklist docs and trunk is Piklist’s single greatest limiting factor in my opinion.

      Using that function does allow the page to load, so it’s getting closer. However, the forms still don’t work as you can’t submit them. Inspecting the page it’s pretty obvious why: the actual <form /> element is missing!

      Screenshot of Piklist function not generating a form element

      Is that expected behaviour for the function? Is there another function you’re supposed to call to produce the <form /> element?

    • #6088
      wpmusketeer
      Member

      Actually, the above behaviour may just be perfect for my use-case because I can output the <form> tag myself and make sure it POSTs to a URL that passes the ID as a URL parameter.

      Let me test…

    • #6089
      wpmusketeer
      Member

      No, that’s not going to work because of course the _post[ID]=123 URL param needs to be passed to the form as a GET as it’s rendered, not as a POST in the form action once it’s submitted.

    • #6091
      jivedig
      Member

      Dave, something is not right. Can you paste your code here? Or even DM it in our Genesis Slack group so I can test?

      You should absolutely have the <form> wrap. I never _not_ had it work.

    • #6092
      wpmusketeer
      Member

      Hi Mike,

      Thanks for the reply.

      I’m pretty sure Piklist can’t handle this situation with the way frontend forms currently work because it requires the ID of the post you want to edit to be passed to the form in the form of a GET URL param.

      I did a bit of sleuthing to see if Piklist generated a different <form> tag, or added an extra post_id field when the GET URL param was present but there wasn’t anything obvious I could see.

      With multiple forms on the page I don’t know how you can get the correct ID passed to the form as it is rendered to make sure it POSTs to the right CPT instance.

      I’ve tried adding a hidden field in the form PHP file for the ID of the post to update (populated with get_the_id()) but that doesn’t seem to work.

      Also, I found the fields aren’t correctly pre-populated with the DB values for the current instance of the CPT. However, I was surprised to discover that by using 'value' => get_post_meta( get_the_ID(), PREFIX . 'accounts_status', true ), in the form PHP file the fields were pre-populated correctly for each instance!

      Anyway, here’s the code:

      parts/forms/job-edit.php

      
      <?php
      /**
       Title: Job List Edit Form
       Method: post
       Message: Job updated
       */
      
      piklist( 'field', array(
      		'type'  => 'hidden',
      		'scope' => 'post',
      		'field' => 'post_type',
      		'value' => 'job',
      	)
      );
      
      piklist( 'field', array(
      		'type'  => 'select',
      		'field' => PREFIX . 'accounts_status',
      		'scope' => 'post_meta',
      		'value' => get_post_meta( get_the_id(), PREFIX . 'accounts_status', true ),
      		'label' => __( 'Accounts Status', 'core-functionality' ),
      		'choices' => array(
      			'accounts_quote'   => 'Quote',
      			'accounts_hold'    => 'Unpaid Hold',
      			'accounts_release' => 'Unpaid Release',
      			'accounts_paid'    => 'Paid',
      		),
      	)
      );
      
      piklist( 'field', array(
      		'type'  => 'select',
      		'field' => PREFIX . 'proof_status',
      		'scope' => 'post_meta',
      		'value' => get_post_meta( get_the_id(), PREFIX . 'proof_status', true ),
      		'label' => __( 'Proof Status', 'core-functionality' ),
      		'choices' => array(
      			'proof_needed'       => 'Needs Proof',
      			'proof_sent'         => 'Proof Sent',
      			'proof_not_required' => 'Not Required',
      			'proof_approved'     => 'Approved',
      		),
      	)
      );
      
      piklist( 'field', array(
      		'type'  => 'select',
      		'field' => PREFIX . 'print_status',
      		'scope' => 'post_meta',
      		'value' => get_post_meta( get_the_id(), PREFIX . 'print_status', true ),
      		'label' => __( 'Print Status', 'core-functionality' ),
      		'choices' => array(
      			'printed_no'      => 'Not Printed',
      			'printed_yes'     => 'Printed',
      			'printed_reprint' => 'Needs Reprint',
      		),
      	)
      );
      
      piklist( 'field', array(
      		'type'  => 'select',
      		'field' => PREFIX . 'shipping_status',
      		'scope' => 'post_meta',
      		'value' => get_post_meta( get_the_id(), PREFIX . 'shipping_status', true ),
      		'label' => __( 'Shipping Status', 'core-functionality' ),
      		'choices' => array(
      			'shipped_no'   => 'Not Shipped',
      			'shipped_yes'  => 'Shipped',
      			'shipped_part' => 'Part Shipped',
      		),
      	)
      );
      
      piklist( 'field', array(
      		'type'  => 'submit',
      		'field' => 'submit',
      		'value' => 'Update',
      	)
      );
      

      jobs-list.php (template part)

      
      <?php
      /**
       * Render a list of Jobs.
       *
       * @package    Musket
       * @author     WP Musketeer - Dave Dean
       * @link       http://www.wpmusketeer.com
       * @copyright  Dave Dean, Moortor Design Ltd.
       * @license    GPL-2.0+
       */
      
      $args = array(
      	'post_type'      => array( 'job' ),
      	'posts_per_page' => -1,
      	'post_status'    => array( 'processing' ),
      	'meta_key'       => PREFIX . 'job_priority',
      	'orderby'        => 'meta_value_num',
      	'order'          => 'ASC',
      );
      
      $jobs = new WP_Query( $args );
      ?>
      
      <?php //echo do_shortcode( '[piklist_form form="job-edit" add_on="core-functionality"]' ); ?>
      
      <div class="job-board">
      
      	<ul class="job-header-row" id="jobHeaderRow">
      		<li>↕</li>
      		<li>Contact</li>
      		<li>Account Status</li>
      		<li>Proof Status</li>
      		<li>Print Status</li>
      		<li>Shipping Status</li>
      		<li>Notes</li>
      		<li>Actions</li>
      	</ul>
      
      	<ul class="job-list" id="sortableJobList">
      
      		<?php
      		if ( $jobs->have_posts() ) {
      			while ( $jobs->have_posts() ) : $jobs->the_post();
      				$priority = get_post_meta( get_the_ID(), PREFIX . 'job_priority', true );
      				$accounts_status = get_post_meta( get_the_ID(), PREFIX . 'accounts_status', true );
      				$proof_status = get_post_meta( get_the_ID(), PREFIX . 'proof_status', true );
      				$print_status = get_post_meta( get_the_ID(), PREFIX . 'print_status', true );
      				$shipping_status = get_post_meta( get_the_ID(), PREFIX . 'shipping_status', true );
      				$contact = get_post( $post->{ PREFIX . 'related_contact' } );
      				?>
      				<li class="job" data-id="<?php echo esc_attr( get_the_ID() ); ?>">
      					<div class="job-priority"><?php echo esc_html( $priority ); ?></div>
      					<ul class="job-details">
      						<li class="job-contact">
      							<div class="contact-name"><?php echo esc_html( $contact->post_title ); ?></div>
      							<div class="order-number"><?php echo the_title(); ?></div>
      						</li>
      						<li class="job-accounts-status">
      							<?php
      							echo esc_html( wpm_get_status_map( $accounts_status ) );
      							echo wpm_get_tick_icon_map( $accounts_status );
      							?>
      
      						</li>
      						<li class="job-proof-status">
      							<?php
      							echo esc_html( wpm_get_status_map( $proof_status ) );
      							echo wpm_get_tick_icon_map( $proof_status );
      							?>
      						</li>
      						<li class="job-print-status">
      							<?php
      							echo esc_html( wpm_get_status_map( $print_status ) );
      							echo wpm_get_tick_icon_map( $print_status );
      							?>
      						</li>
      						<li class="job-shipping-status">
      							<?php
      							echo esc_html( wpm_get_status_map( $shipping_status ) );
      							echo wpm_get_tick_icon_map( $shipping_status );
      							?>
      						</li>
      						<li class="job-notes">
      							<?php echo the_excerpt(); ?>
      						</li>
      						<li class="job-actions">
      							<a class="job-edit-button button" data-id="<?php echo esc_attr( get_the_ID() ); ?>" href="javascript:;">Edit</a>
      						</li>
      					</ul>
      					<div class="job-edit-<?php echo esc_attr( get_the_ID() ); ?>">
      						<form method="post" action="<?php echo esc_attr( site_url() ); ?>?_post[ID]=<?php echo esc_attr( get_the_ID() ); ?>" enctype="multipart/form-data" id="core_functionality_job_edit" autocomplete="off" data-piklist-form="true" class="piklist-form ">
      							<?php piklist::render( 'forms/job-edit' ); ?>
      						</form>
      					</div>
      				</li>
      				<?php
      			endwhile;
      		} else {
      			wpm_frontend_notice( 'No jobs found.', 'notice-warning is-dismissable' );
      		}
      		?>
      	</ul>
      </div>
      
      <?php
      wp_reset_postdata();
      

      You can see I’m adding the <form> tag manually in that example. Without it, no <form> tag renders. I’ve tried different actions for the form but all to no avail.

    • #6093
      jivedig
      Member

      No time to test now, but I was going to suggest using the value parameter to preload values when you don’t want to use the query var.

    • #6094
      wpmusketeer
      Member

      That’s what I’ve done for the main fields, just need to find a way that does the same for the ID of the CPT to update!

    • #6095
      jivedig
      Member

      You may need to set a custom scope and manually update the CPT via the piklist action.

      'scope' => 'update_daves_cpt',

      Then:

      add_action( 'piklist_save_field-connect_resource_to_step', 'update_daves_cpt', 10, 1 );
      function update_daves_cpt( $fields ) {
      // Manually do some awesomeness
      }

      Note: add the same scope to all the fields you want for the CPT update

    • #6098
      wpmusketeer
      Member

      That looks like it’s worth investigating. I’ll let you know how I get on with manually updating some awesomeness 😉

      Thanks Mike!

    • #11164
      cdcorey
      Member

      Manually setting $_REQUEST[piklist::$prefix . 'post']['ID'] before calling do_shortcode() seems to be a perfectly workable (if slightly kludgey) solution.

Viewing 14 reply threads
  • You must be logged in to reply to this topic.