Forum Replies Created
-
AuthorPosts
-
chrisdavies71Participant
Hi Zac,
Looks like the way that you get the various sizes has changed again in Gutenberg and we now need to use the media_details object. Something like:
img.media_details.sizes.thumbnail.source_url
However i get this error:
Uncaught TypeError: can't access property "sizes", img.media_details is undefined
Any thoughts where I am going wrong?
Cheers
Chris
chrisdavies71ParticipantHi Zac,
I am still struggling with this.
I have now given up entirely on trying to do this dynamically and gone for a simple Inspector Controls way of adding it.
I still have the issue though that it works in the edit but not the save.
Chris
chrisdavies71ParticipantHi Zac,
Any thoughts on the above?
Opted for using the clientId instead which works in the edit but comes up as undefined when saved.
What am I doing wrong here?
Regards
Chris
chrisdavies71ParticipantHi Zac,
A native accordion option would be good – looks like it is being developed currently but probably a way off a shipped version.
As for the ID – In an ideal world I would get something like 1,2,3 but not essential. What I do need is for it to be the same in a couple of places in the code so that the show/hide works. I am building it based on Bootstrap styles.
Currently I have not started with this as Hooks are completely new to me so no idea where to start.
Chris
chrisdavies71ParticipantHi Zac,
I was not getting any error it was just not rendering the image.
Just starting out really with Gutenberg/JSX but I found this link 7-ways-to-implement-conditional-rendering-in-react-applications and used the Ternary Operators solution.
Code now looks like this and works
) : ( <Fragment> <p class="image-wrapper"> <img src={ imgURL } alt={ imgAlt } /> </p> { carouselControls ? <Fragment> <a className="carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev"> <span className="carousel-control-prev-icon" aria-hidden="true"></span> <span className="sr-only">Previous</span> </a> <a className="carousel-control-next" href="#carouselExampleControls" role="button" data-slide="next"> <span className="carousel-control-next-icon" aria-hidden="true"></span> <span className="sr-only">Next</span> </a> </Fragment> : '' } </Fragment> ) //end if has image
It could probably be tidied up in places. Thanks for the help though.
Chris
chrisdavies71ParticipantHi Zac,
If I take it back to basically what you have in the course examples it works – as in the image appears in the block as expected.
I can also add the HTML for the controls and when the image appears in the block so do the controls (expected behaviour)
When I try and add the conditional around the controls HTML the image no longer appears in the block. It seems this bit is what is tripping me up:
) : ( <Fragment> <p class="image-wrapper"> <img src={ imgURL } alt={ imgAlt } /> </p> </Fragment>, carouselControls && ( <-- THIS IS WHERE IT GOES WRONG <Fragment> <a className="carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev"> <span className="carousel-control-prev-icon" aria-hidden="true"></span> <span className="sr-only">Previous</span> </a> <a className="carousel-control-next" href="#carouselExampleControls" role="button" data-slide="next"> <span className="carousel-control-next-icon" aria-hidden="true"></span> <span className="sr-only">Next</span> </a> </Fragment> ) //end carousel controls check ) //end if has image
- This reply was modified 4 years, 6 months ago by chrisdavies71. Reason: Code tidy up
chrisdavies71ParticipantAnd finally the ajax.js file:
function ajax_load( query ) { jQuery('#productlist').load('../wp-content/plugins/current-rms-for-wordpress-gutenberg/dist/assets/ajax.php?postid=&'+query); } ajax_load('query=product_groups');
chrisdavies71ParticipantHere is the ajax.php file:
<?php require_once ( './class.php' ); define ('AJAX_URL', $_SERVER['PHP_SELF']); function render_breadcrumb( $links=array() ) { $html = '<div class="row mb-3">'; $html .= '<div class="col-md-11">'; $html .= '<nav aria-label="breadcrumb">'; $html .= '<ol class="breadcrumb">'; $html .= '<li class="breadcrumb-item"><a href="/">Home</a></li>'; $html .= '<li class="breadcrumb-item"><a href="#" onclick="ajax_load(\'query=product_groups\')">Hire & Sales</a></li>'; foreach ($links as $query=>$name) { $html .= '<li class="breadcrumb-item"><a href="#" onclick="ajax_load(\''.$query.'\')">'.$name.'</a></li>'; } //$html .= '<li class="breadcrumb-item active" aria-current="page">Data</li>'; $html .= '</ol>'; $html .= '</nav>'; $html .= '</div>'; $html .= '<div class="col-md-1">'; $html .= '<button type="button" class="btn btn-primary" onclick="window.history.go(-1);">Back</button>'; $html .= '</div>'; $html .= '</div>'; return $html; } switch( $_GET['query'] ) { // Product Groups (Categories) Page case 'product_groups': //$objCurrentRmsApi = new current_rms_api( $_GET['postid']); $objCurrentRmsApi = new current_rms_api(); $product_groups = $objCurrentRmsApi->getProductGroups(); $html = render_breadcrumb(); $html .= '<div class="row">'; foreach( $product_groups as $product_group ) { $html .= '<div id="productlist" class="col-md-4">'; $html .= '<div class="card">'; if (isset ($product_group->icon->url) ) { $html .= '<img class="card-img-top" style="padding:1.25rem" src="'. $product_group->icon->url . '">'; } $html .= '<div class="card-body">'; $html .= '<h5 class="card-title">' . $product_group->name . '</h5>'; $html .= '<p class="card-text">' . $product_group->description . '</p>'; $html .= '<a href="#" style="cursor:pointer" onclick="ajax_load(\'query=products&name=' . urlencode($product_group->name) . '\');" class="btn btn-primary">View Products</a>'; $html .= '</div>'; $html .= '</div>'; $html .= '</div>'; } $html .= '</div>'; echo $html; break; // Products in each Product Group (Category) case 'products': $objCurrentRmsApi = new current_rms_api(); $products = $objCurrentRmsApi->getProducts( $_GET['name'] ); //$tags = $objCurrentRmsApi->getTags(); $tags=array(); foreach ($products as $product) { foreach ($product->tag_list as $tag) { if (!in_array($tag, $tags)) { $tags[]=$tag; } } } sort($tags); $html = render_breadcrumb(array('query=products&name='.urlencode($_GET['name'])=>$_GET['name'])); $counter = 0; $html .= '<ul class="nav nav-tabs flex-column flex-sm-row nav-fill" id="myTab" role="tablist">'; foreach ($tags as $tag) { $html .= '<li class="flex-sm-fill text-center nav-item">'; $html .= '<a class="nav-link' . ($counter == 0 ? ' active' : '') . '" id="' . preg_replace('/\s+/', '_', $tag) . '_tab" data-toggle="tab" href="#' . preg_replace('/\s+/', '_', $tag) . '" role="tab" aria-controls"' . preg_replace('/\s+/', '_', $tag) . '" aria-selected="' . ($counter == 0 ? 'true' : 'false') .'">' . $tag . '</a>'; $html .= '</li>'; $counter++; } $html .= '</ul>'; $html .= '<div class="tab-content mt-4" id="myTabContent">'; $counter2 = 0; foreach ($tags as $tag) { $html .= '<div class="tab-pane fade' . ($counter2 == 0 ? ' show active' : '') . '" id="' . preg_replace('/\s+/', '_', $tag) . '" role="tabpanel" aria-labelledby="' . preg_replace('/\s+/', '_', $tag) . '_tab">'; $html .= '<div class="row">'; foreach( $products as $product ) { if (in_array($tag, $product->tag_list)) { $html .= '<div class="col-md-4">'; $html .= '<div class="card">'; if (isset ($product->icon->url) ) { $html .= '<img class="card-img-top p-3" src="'. $product->icon->url . '">'; } //end product icon isset $html .= '<div class="card-body">'; $html .= '<h5 class="card-title">' . $product->name . '</h5>'; $html .= '<a href="#" style="cursor:pointer" onclick="ajax_load(\'query=product&id=' . urlencode($product->id) . '\');" class="btn btn-primary">View Product</a>'; //$html .= $product_tag; $html .= '</div>'; //end card-body $html .= '</div>'; //end card $html .= '</div>'; //end col } //end product_tag foreach }// end product foreach $html .= '</div>'; //end row $html .= '</div>'; //end tab-pane $counter2++; }// end tags foreach $html .= '</div>'; //end tab-content echo $html; break; // Individual Product Page case 'product': $objCurrentRmsApi = new current_rms_api(); $product = $objCurrentRmsApi->getProduct( $_GET['id'] ); $accessories = $objCurrentRmsApi->getAccessories( $_GET['id'] ); $price = $objCurrentRmsApi->getProductPrice( $_GET['id'] ); $rates = $objCurrentRmsApi->getRates( $price->rate_definition_id ); $labels = array('1_day'=>'Daily', 'weekend'=>'Weekend', 'week'=>'Weekly', 'subs_day'=>'Additional Days'); $html = render_breadcrumb(array('query=products&name='.urlencode($product->product_group->name)=>$product->product_group->name,'query=product&id='.$_GET['id']=>$product->name)); $html .= '<div class="row">'; $html .= '<div class="col-md-6 item-photo">'; if (isset ($product->icon->url) ) { $html .= '<img style="max-width:100%;" src="' . $product->icon->url . '" />'; } $html .= '</div>'; $html .= '<div class="col-md-6" style="border:0px solid gray">'; $html .= '<h1>' . $product->name . '</h1>'; $html .= '<p>' . $product->description . '</p>'; $html .= 'Supplied with the following accessories:'; $html .= '<ul class="list-group list-group-flush mb-3">'; foreach( $accessories as $accessory ) { $html .= '<li class="list-group-item border-0">' . $accessory->related_name . '</li>'; } $html .= '</ul>'; $html .= '<table class="table">'; $html .= '<thead class="thead-light">'; $html .= '<tr>'; $html .= '<th scope="col">Hire Period</th>'; $html .= '<th scope="col">Cost</th>'; $html .= '</tr>'; $html .= '</thead>'; $html .= '<tbody>'; foreach ( $rates->rate_engine->rate_engine->config->charging_periods as $code=>$rate) { $html .= '<tr><th>' . $labels[$code] . '</th><td>£' . number_format($price->price * $rate->default_value / 100,2) .'</td></tr>'; } $html .= '</tbody>'; $html .= '</table>'; //$html .= '<!-- Hire and Sale Buttons -->'; //$html .= '<div class="section" style="padding-bottom:20px;">'; //$html .= '<button class="btn btn-success">Agregar al carro</button>'; //$html .= '<button class="btn btn-success">Agregar al carro</button>'; //$html .= '</div>'; $html .= '</div>'; echo $html; break; default: echo 'Invalid query'; } ?>
chrisdavies71ParticipantHi Zac,
Here is the block.js file:
/** * BLOCK: current-rms-for-wordpress-gutenberg * * Registering a basic block with Gutenberg. * Simple block, renders and saves the same content without any interactivity. */ // Import CSS. import './style.scss'; import './editor.scss'; import icon from './icon'; import logo from './current-rms-logo.png'; const { __ } = wp.i18n; // Import __() from wp.i18n const { registerBlockType } = wp.blocks; // Import registerBlockType() from wp.blocks const { InspectorControls, } = wp.editor; const { PanelBody, PanelRow, TextControl} = wp.components; /** * Register: aa Gutenberg Block. * * Registers a new block provided a unique name and an object defining its * behavior. Once registered, the block is made editor as an option to any * editor interface where blocks are implemented. * * @link https://wordpress.org/gutenberg/handbook/block-api/ * @param {string} name Block name. * @param {Object} settings Block settings. * @return {?WPBlock} The block, if it has been successfully * registered; otherwise <code>undefined</code>. */ registerBlockType( 'cgb/current-rms-for-wordpress-gutenberg', { // Block name. Block names must be string that contains a namespace prefix. Example: my-plugin/my-custom-block. title: __( 'Current RMS' ), // Block title. description: 'Show your Current RMS system on your WordPress website using the new Gutenberg editor', icon: icon.current_rms_icon, // Block icon. category: 'embed', // Block category — Group blocks together based on common traits E.g. common, formatting, layout widgets, embed. keywords: [ __( 'Hire' ), __( 'Sales' ), __( 'Store' ), ], attributes: { apikey: { type: 'string', source: 'meta', meta: 'current_rms_apikey' }, subdomain: { type: 'string', source: 'meta', meta: 'current_rms_subdomain' }, }, /** * The edit function describes the structure of your block in the context of the editor. * This represents what the editor will render when the block is used. * * The "edit" property must be a valid function. * * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/ */ edit: function( props ) { console.log ('output of props in edit:'); console.log ( props ); const { attributes, setAttributes } = props; const { apikey, subdomain } = props.attributes; const onChangeAPIKey = value => { props.setAttributes( { apikey: value } ) }; const onChangeSubDomain = value => { props.setAttributes( { subdomain: value } ) }; return ([ <InspectorControls> <PanelBody title={ __( 'API Settings' ) } > <PanelRow> <TextControl label={ __( 'API Key' ) } value={ apikey } onChange={ onChangeAPIKey } /> </PanelRow> <PanelRow> <TextControl label={ __( 'Subdomain' ) } value={ subdomain } onChange={ onChangeSubDomain } /> </PanelRow> </PanelBody> </InspectorControls>, // Creates a <p class='wp-block-cgb-block-cp-current-rms-plugin'></p>. <div className={ props.className }> <img className="currentlogo" src="../wp-content/plugins/current-rms-for-wordpress-gutenberg/dist/assets/current-rms-logo.png" /> {/*<img src={logo} className="currentlogo" alt="current-logo" />.*/} </div> ]); }, /** * The save function defines the way in which the different attributes should be combined * into the final markup, which is then serialized by Gutenberg into post_content. * * The "save" property must be specified and must be a valid function. * * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/ */ save: function( props ) { console.log ('output of props in save:'); console.log ( props ); return ( <div> <div id="productlist">Loading...</div> <script src="../wp-content/plugins/current-rms-for-wordpress-gutenberg/dist/assets/ajax.js"></script> </div> ); }, } );
chrisdavies71ParticipantHi Zac,
Here is the class.php file which is where i need to do the post ID stuff. If you need anything else let me know.
<?php include_once("../../../../../wp-load.php"); if ( ! defined( 'ABSPATH' ) ) { exit; } class current_rms_api { //TODO: Make the version selectable from a dropdown in InspectorControls - currently only v1. //NOTE: apikey ad subdomain are here for reference only remove later //private $apikey = 'JNxCt3e_mNa-M2v71qJF'; //private $subdomain = 'cpackham'; private $version = 'v1'; //public function __construct( $postid) { public function __construct() { //$settings = get_option( 'cp_currentrms_settings' ); //print_r ($settings); //$this->apikey = $settings['cp_currentrms_apikey']; //$this->subdomain = $settings['cp_currentrms_subdomain']; //$this->apikey = get_post_meta( $postid, 'current_rms_apikey', 'true' ); //$this->subdomain = get_post_meta( $postid, 'current_rms_subdomain', 'true' ); $this->apikey = get_post_meta( '869', 'current_rms_apikey', 'true' ); $this->subdomain = get_post_meta( '869', 'current_rms_subdomain', 'true' ); } private function query( $endpoint, $params=array()) { $params['subdomain']=$this->subdomain; $params['apikey']=$this->apikey; // Call API url $url = 'https://api.current-rms.com/api/'.$this->version.'/'.$endpoint.'?' . http_build_query($params); //echo $url; $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); $data = json_decode($response); return $data; } // Function gets a list of product groups (categories). public function getProductGroups() { $data = $this->query('product_groups'); return $data->product_groups; } // Function gets a list of products in a product group (category). // NOTE: You can not do this using the id of the product group. // TODO: See if we can get this to only show categories that have a product count / hide empty categories // TODO: See if we can get this to show only product with a specific tag (so that tab panel nav works. public function getProducts( $name ) { $data = $this->query('products', array('q[product_group_name_eq]'=>$name,'q[accessory_only_eq]'=>false,'per_page'=>100)); return $data->products; } // Function gets an individual product based on the product ID. public function getProduct( $id ) { $data = $this->query('products/' . $id); return $data->product; } // Function gets a list of accessories based on the product ID public function getAccessories( $id ) { $data = $this->query('products/' . $id . '/accessories'); return $data->accessories; } // Function gets the price based on the product ID public function getProductPrice( $id ) { $data = $this->query('products/' . $id . '/item_price'); return $data->data; } // Function gets the rate definitions for the products public function getRates( $id ) { $data = $this->query('rate_definitions/' . $id ); return $data->rate_definition; } // Function gets a list of tags public function getTags() { $data = $this->query('products/tag_cloud'); return $data->tag_cloud; } // Function gets products by tag public function getProductsbyTag( $tag ) { $data = $this->query('products', array('tags'=>'['.$tag.']')); return $data->products; } } ?>
Regards
CHRIS
-
AuthorPosts