I have created a script that posts to my website when I run it (see code below) and everything works as it should, except I cannot seem to set the template for pages that I create.
from wordpress_xmlrpc import Client
from wordpress_xmlrpc.methods import posts, pages
from wordpress_xmlrpc import WordPressPage
client = Client(...)
page = WordPressPage()
page.template = 'template_name.php'
page.parent_id = '206'
page.title = 'Test'
page.slug = 'rrr'
page.content = 'Some text goes here'
page.post_status = 'publish'
page.id = client.call(posts.NewPost(page))
I found this issue posted at the repository (https://github.com/maxcutler/python-wordpress-xmlrpc/issues/44), and I tried using the alternative method:
page.wp_page_template = 'template_name.php'
I've also tried the names of the templates and other variations. I also find that my template(s) when I use the GetPageTemplates code:
templates = client.call(pages.GetPageTemplates())
All of my templates gets shown here.
Anyone had any success using this setting?
Seems a bug of wordpress_xmlrpc.
wordpress_xmlrpc converts field 'template' -> 'wp_page_tempalte' but its wrong.
Should be converted to 'page_template' (without wp_ prefix).
"class-wp-xmlrpc-server.php" then converts field of post data from 'page_template' to 'wp_page_template'.
So wordpress_xmlrpc should send page_template not wp_page_template.
wordpress_xmlrpc converts template to wp_page_template before post, so:
use 'template'
page.template = 'template_name.php'
patch wordpress.py like:
*** wordpress.py
--- wordpress.py.orig
***************
*** 126,132 ****
class WordPressPage(WordPressPost):
definition = dict(WordPressPost.definition, **{
! 'template': 'page_template',
'post_type': FieldMap('post_type', default='page'),
})
--- 126,132 ----
class WordPressPage(WordPressPost):
definition = dict(WordPressPost.definition, **{
! 'template': 'wp_page_template',
'post_type': FieldMap('post_type', default='page'),
})
It worked.
Related
so I'm fetching data for a mini-blog from an endpoint and each post in the JSON bin has an image property and in it is a corresponding link to a background image from Unsplash.
As in:
[
{
"id": 1,
"title": "The Life of Cactus",
"body": "Nori grape silver...",
"date": "31-08-2022",
"author": "Bakes Parker",
"image": "https://images.unsplash.com/photo-1544674644-c8c919e3cfbf?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=755&q=80"
},
Inside my Flask application, I get respective posts and render them with Flask and use dynamic values with Jinja. Here's the function that gets the posts:
#app.route("/post<int:num>")
def return_post(num):
API_ENDPOINT = "https://api.npoint.io/xxx"
blog_stories = requests.get(API_ENDPOINT).json()
requested_story = None
for blog_post in blog_stories:
if blog_post['id'] == num:
requested_story = blog_post
return render_template("post.html", requested_post=requested_story)
Inside post.html, I try to make the background of the respective post with this line
<style>
header {
background-image: url("{{requested_post['image']}}");
}
</style>
but it doesn't show as it shows the default #cccc background-img color.
I also try to make it inline but it's not possible because of CSS curly brace restrains.
As in:
<header class="masthead" style="background-image:{{requested_post['image']}} ;">
I can't do the above.
So I found out that the images from the endpoint were actually rendering but they were overridden by properties from the stylesheet which is quite odd because, I defined the style inside the style tag.
Developer Tools shows that the image is there
Sorry for any inconvenience.
Nothing jumps out as wrong. Try importing current_app from flask, then printing out your json to debug. Perhaps you are not getting the data you are expecting.
from flask import current_app
#app.route("/post<int:num>")
def return_post(num):
API_ENDPOINT = "https://api.npoint.io/xxx"
blog_stories = requests.get(API_ENDPOINT).json()
for requested_post in blog_stories:
if requested_post.get('id') == num:
current_app.logger.debug(requested_post)
return render_template("post.html", requested_post=requested_post)
return render_template("error.html")
I suggest you think about redirecting to an error template or route here.
Can you post your complete template? There may be clues there.
I am trying to use the gitlab projects api to edit multiple project MR templates. The problem is, that it only sends the first line of the markdown template.
While messing around with the script, I was toying with converting it to html when I found that it sent the whole template when converted to html.
I am probably missing something super simple but for the life of me, I cant figure out why it would be able to send the entire template in html but only send the first line of it natively in markdown.
I have been searching for a solution for a bit now so I apologize if my googlefu missed an obvious answer here.
Here is the script...
#! /usr/bin/env python3
import argparse
import requests
gitlab_addr = "https://gitlab.com/api/v4"
# Insert your project IDs into the array below.
project_IDs = [xxxx, yyyy, zzzz]
# Insert your MR template info below.
with open('/.gitlab/merge_request_templates/DefaultMRTemplate.md', 'r') as file:
MR_template = file.read()
#print(MR_template)
def getArgs():
parser = argparse.ArgumentParser(
description='This tool updates the default template for a single '
'or multiple program\'s MRs. \n\nYou will need to edit '
'the script to input your MR template and projects IDs.'
'\nYou will also need to pass in your API Token via '
' command line.\n\nYou want to see "200 OK" on the '
' command line as confirmation.',
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument("token", type=str,
help="API Token. Create one at User Settings / Access Tokens")
return parser.parse_args()
def ChangeTemplate():
token = getArgs().token
headers = {"PRIVATE-TOKEN": token, }
for x in project_IDs:
addr = f"{gitlab_addr}/projects/{x}/?merge_requests_template={MR_template}"
response = requests.put(addr, headers=headers)
# You want to see "200 OK" on the command line.
print(response.status_code, response.reason)
def main():
ChangeTemplate()
if __name__ == '__main__':
main()
Here is a sample template...
See guidance here: https://example.com/Gitlab+MR+Guide
## Description
%% Put a description here %%
%% Add an issue link here %%
## Tests
%% Include test listing here %%
## Checklists
**Author Checklist**
- [ ] A: Did you fill out the description, add an issue link (in title or desc) and fill out the test section?
- [ ] A: Add a peer to the MR
**Assignee 1 Checklist:**
- [ ] P: Verify the description field is filled out, issue link is included (in title or desc) and the test section is filled out
- [ ] P: Add a code owner to the MR
**Assignee 2 (Code Owner) Checklist:**
- [ ] O: Verify the description field is filled out, issue link is included (in title or desc) and the test section is filled out
- [ ] O: Verify unit test coverage is at least 40% line coverage with a goal of 90%
problem output...
See guidance here: https://example.com/Gitlab MR Guide
Your data needs to be properly encoded in the request. Trying to format the literal contents of the file into the query string won't work here.
Use the data keyword argument to requests.put, which will pass the data in the request body (or use params to set query params). requests will handle the proper encoding of the data.
addr = f"{gitlab_addr}/projects/{x}/"
payload = {'merge_requests_template': MR_template}
response = requests.put(addr, headers=headers, data=payload)
# or params=payload to use query string
I'm developing a webapp using Google App Engine and Python.
I'm facing a strange problem and i don't know how to solve it and what causes it.
When I fill a form I send the data for checking them. If they aren't complete and some fields are missed the server send the form back with an advice "FILL ALL THE FIELDS!".
That's work pretty well.
What I'm trying to do is sending the form back with the "description" and "title" fields filled with what the user has written before submitting the form, so he must to fill only the unfilled fields (and he doesn't need to rewrite everything from the beginning).
That's the code:
class SaleAnnCheck(BaseHandler):
def post(self):
title = self.request.POST.get('title')
cat = self.request.POST.get('cat')
description = self.request.POST.get('description')
AcqOpt = self.request.POST.get('AcqOpt')
lat = self.request.POST.get('lat')
lng = self.request.POST.get('lng')
image1 = self.request.POST.get("file1", None)
image2 = self.request.POST.get("file2", None)
image3 = self.request.POST.get("file3", None)
logging.info("info sale announcment")
logging.info(title)
logging.info(cat)
logging.info(description)
logging.info(AcqOpt)
logging.info(lat)
logging.info(lng)
logging.info(image1)
logging.info(image2)
logging.info(image3)
self.session["ECommerceUser"]["description"]=description
self.session["ECommerceUser"]["title"]=title
logging.info('session')
logging.info(self.session["ECommerceUser"])
if title == '' or cat == None or description == '' or AcqOpt == None or lat == '' or lng == '':
error = 'empty'
urlR='/CreateSaleAnn?'+urllib.urlencode({'error':'empty'})
self.redirect(urlR)
class Create(BaseHandler):
def get(self):
error = self.request.get('error')
if error == 'empty':
logging.info('sbagliato')
logging.info(self.session["ECommerceUser"])
template = JINJA_ENVIRONMENT.get_template('templates/CreateAnnouncement.html')
w = self.response.write
w(template.render({'error':'FILL ALL THE MANDATORY FIELDS!', 'description': self.session["ECommerceUser"]["description"], 'title': self.session["ECommerceUser"]["title"]}))
else:
logging.info('giusto')
logging.info(self.session["ECommerceUser"])
template = JINJA_ENVIRONMENT.get_template('templates/CreateAnnouncement.html')
w = self.response.write
w(template.render({'description': self.session["ECommerceUser"]["description"], 'title': self.session["ECommerceUser"]["title"]}))
When I submit the form the content is checked by making an HTTP post request to a certain URL, handled by SaleAnnCheck.
Description and Title are saved in the session correctly (i checked it by printing the content of self.session["ECommerceUser"] in the logs). Then, if a field isn't filled, the server redirect again to the form page, by a GET request to a related URL.
The requests to that URL is handled by Create. But when i try to render the HTML template of the form (using jinja2) with the previous typed values of Description and Title the related text areas are not filled with that values.
It happens because self.session["ECommerceUser"]["description"] and self.session["ECommerceUser"]["title"] are empty, but they weren't when i checked them before (in SaleAnnCheck).
Why it happens? Any explanation? It's a weird problem and there aren't any tips or suggestion about on internet
This is because 'self.session' is not a Session, it's just a class variable and will not be readable outside the class. If you really want to use persistent sessions for storing variables, try something like this:
From the docs:
http://docs.python-requests.org/en/master/user/advanced/
s = requests.Session()
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get('http://httpbin.org/cookies')
I am trying to create a script for myself to use on a few classified sites and starting with cl, I am using flask web framework and robobrowser but not going so well.
The Goal It will take my preset values and put them in the fields from that classifieds websites. Doesnt seem like a difficult concept however after 5 hours of reading online different code and trial and error I remembered the best developers are on stack...
I should inform you I am new to Python and still have alot to learn so any help would be greatly appreciated.
The error I get is:
assert isinstance(form, 'str')
TypeError: isinstance() arg 2 must be a type or tuple of types
but I dont see how to fix this and completely lost. HELP!!!
thanks in advance
# autosubmit to site
from flask import Flask
from robobrowser import RoboBrowser
app = Flask(__name__)
#app.route('/', methods = ['GET', 'POST'])
class My_RoboBrowser(RoboBrowser):
def __init__(self, auth=None, parser=None, headers=None, user_agent=None, history=True):
RoboBrowser.__init__(self, parser=None, user_agent=None, history=True)
def Open(self, vURL, vVerify=True):
response = self.session.get(vURL, verify=vVerify)
self._update_state(response)
browser = My_RoboBrowser(RoboBrowser, "html.parser");
urlL = 'https://accounts.craigslist.org/login'
browser.Open(urlL)
form = browser.get_form(id='login')
assert isinstance(form, 'str')
form['username'] = 'username'
form['password'] = 'password'
browser.submit_form(form)
urlQ = 'https://post.craigslist.org/k/qGDv7K4q5RGD0B5ZEBgXOQ/GLzgd?s=edit'
browser.open(urlQ)
#Question_Tag = browser.find_all(class_="not_answered")[0]
#ID = Question_Tag.get('data-qid')
#Get the form to fill out
Form = browser.get_form(id='formpost')
Form['PostingTitle'].value = 'Create this advertise ment in py'
Form['Postal_code'].value = ['10543']
Form['PostingBody'].value = 'TOGETHER WE INNOVATE Stress free communication with developers that are in the United States. We pride ourselves in bringing your web and app ideas to life and keeping your data secured'
browser.submit_form(Form)
if __name__ == "__main__":
app.run()
isinstance returns true if the first argument is an instance (or subclass) of the second argument otherwise false. In your assertion the form variable is of type robobrowser.forms.form.Form. You can see this with the following code:
print(type(form)) # should print <class 'robobrowser.forms.form.Form'>
Your particular assertion will pass if you update the second argument to indicate this robobrowser Form class:
# Add the following to your imports
import robobrowser
# ... existing code below imports
# The following should be true if form is valid
assert isinstance(form, robobrowser.forms.form.Form)
You can also import the Form class directly but you'll have to update the assertion accordingly:
from robobrowser.forms.form import Form
# ... existing code below imports
assert isinstance(form, Form)
Edit:
Below is the code to properly get the form from that page. There are no forms with an id of 'login' but you can select it by using its action or grabbing the first form on the page.
# ... previous code ...
form = browser.get_form(action='https://accounts.craigslist.org/login')
# you can also use: form = browser.get_form(0)
# It looks like you aren't selecting the fields by their proper names either.
form['inputEmailHandle'] = 'fill in username here'
form['inputPassword'] = 'fill in password here'
browser.submit_form(form)
See if the added code above helps.
i am developing one of my site with the python django where i have been using angularjs in one of my page where i have given the user option to search (specific request). Here is my model..
class Request(models.Model):
description = models.TextField(blank=True,null=True)
category = models.ForeignKey(Category)
sub_category = models.ForeignKey(SubCategory)
In my views I am returning through the following code:
def some(code, x):
exec code
return x
def search_request(request):
page = request.GET.get('page')
term = request.GET.get('term')
i = 0
terms = "x = Request.objects.filter("
for t in term.split(" "):
i=i+1
if(len(term.split(" "))>i):
terms = terms +"Q(name__icontains='"+t+"')|"
else:
terms = terms +"Q(name__icontains='"+t+"'))"
junk = compile(terms,'<string>', 'exec')
spit = Request.objects.filter(name__icontains=term)
requests = some(junk,spit)
output = HttpResponse()
output['values']=[{'requests':r,'category':r.category,'subcategory':r.sub_category} for r in requests]
return JSONResponse(output['values'])
In my HTML code when I return using AngularJS:
$scope.search = function(){
$scope.results = $http.get("{% url 'search-requests-show' %}?term="+$scope.term).then(
function(result){
return result.data;
}
);
}
The result on the HTML Output comes as in {[{results}]}:
"[{'category': <Category: The New Category>, 'requests': <Request: Need a Table>, 'subcategory': <SubCategory: Testsdfsdfsad>}]"
The problem is that I am not being able to access using results.category because the output is in "string", so the ng-repeat="result in results" brings the result as
[ { ' c a .....
I am probably doing something wrong in view. If anybody has any suggestion then please answer.
JSONResponse is probably using standard python json encoder, which doesn't really encode the object for you, instead it outputs a string representation (repr) of it, hence the <Category: The New Category> output.
You might need to use some external serializer class to handle django objects, like:
http://web.archive.org/web/20120414135953/http://www.traddicts.org/webdevelopment/flexible-and-simple-json-serialization-for-django
If not, you should then normalize object into simple python types inside the view (dict, list, string.., the kind that json module has no problem encoding). So instead doing:
'category':r.category
you could do:
'category': {'name': r.category.name}
Also as a sidenote: using exec is super bad idea. Don't use it in production!
You should return json strings for Angular:
import json
def resource_view(request):
# something to do here
return HttpResponse(json.dumps(your_dictionary))
for better usage i recommend djangorestframework.
Off Topic:
$http.get("{% url 'search-requests-show' %}?term="+$scope.term);
you can pass 'param' object:
$http.get("{% url 'search-requests-show' %}", {param : {term:$scope.term}});